@@ -0,0 +1,140 @@
|
||||
/datum/component/fantasy
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
var/quality
|
||||
|
||||
var/canFail
|
||||
var/announce
|
||||
|
||||
var/originalName
|
||||
var/list/affixes
|
||||
var/list/appliedComponents
|
||||
|
||||
var/static/list/affixListing
|
||||
|
||||
/datum/component/fantasy/Initialize(quality, list/affixes = list(), canFail=FALSE, announce=FALSE)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.quality = quality || randomQuality()
|
||||
src.canFail = canFail
|
||||
src.announce = announce
|
||||
|
||||
src.affixes = affixes
|
||||
appliedComponents = list()
|
||||
randomAffixes()
|
||||
|
||||
/datum/component/fantasy/Destroy()
|
||||
unmodify()
|
||||
affixes = null
|
||||
return ..()
|
||||
|
||||
/datum/component/fantasy/RegisterWithParent()
|
||||
var/obj/item/master = parent
|
||||
originalName = master.name
|
||||
modify()
|
||||
|
||||
/datum/component/fantasy/UnregisterFromParent()
|
||||
unmodify()
|
||||
|
||||
/datum/component/fantasy/InheritComponent(datum/component/fantasy/newComp, original, list/arguments)
|
||||
unmodify()
|
||||
if(newComp)
|
||||
quality += newComp.quality
|
||||
canFail = newComp.canFail
|
||||
announce = newComp.announce
|
||||
else
|
||||
arguments.len = 5 // This is done to replicate what happens when an arglist smaller than the necessary arguments is given
|
||||
quality += arguments[1]
|
||||
canFail = arguments[4] || canFail
|
||||
announce = arguments[5] || announce
|
||||
modify()
|
||||
|
||||
/datum/component/fantasy/proc/randomQuality()
|
||||
var/quality = pick(1;15, 2;14, 2;13, 2;12, 3;11, 3;10, 3;9, 4;8, 4;7, 4;6, 5;5, 5;4, 5;3, 6;2, 6;1, 6;0)
|
||||
if(prob(50))
|
||||
quality = -quality
|
||||
return quality
|
||||
|
||||
/datum/component/fantasy/proc/randomAffixes(force)
|
||||
if(!affixListing)
|
||||
affixListing = list()
|
||||
for(var/T in subtypesof(/datum/fantasy_affix))
|
||||
var/datum/fantasy_affix/affix = new T
|
||||
affixListing[affix] = affix.weight
|
||||
|
||||
if(length(affixes))
|
||||
if(!force)
|
||||
return
|
||||
affixes = list()
|
||||
|
||||
var/alignment
|
||||
if(quality >= 0)
|
||||
alignment |= AFFIX_GOOD
|
||||
if(quality <= 0)
|
||||
alignment |= AFFIX_EVIL
|
||||
|
||||
var/usedSlots = NONE
|
||||
for(var/i in 1 to max(1, abs(quality))) // We want at least 1 affix applied
|
||||
var/datum/fantasy_affix/affix = pickweight(affixListing)
|
||||
if(affix.placement & usedSlots)
|
||||
continue
|
||||
if(!(affix.alignment & alignment))
|
||||
continue
|
||||
if(!affix.validate(src))
|
||||
continue
|
||||
affixes += affix
|
||||
usedSlots |= affix.placement
|
||||
|
||||
/datum/component/fantasy/proc/modify()
|
||||
var/obj/item/master = parent
|
||||
|
||||
master.force = max(0, master.force + quality)
|
||||
master.throwforce = max(0, master.throwforce + quality)
|
||||
master.armor = master.armor?.modifyAllRatings(quality)
|
||||
|
||||
var/newName = originalName
|
||||
for(var/i in affixes)
|
||||
var/datum/fantasy_affix/affix = i
|
||||
newName = affix.apply(src, newName)
|
||||
|
||||
if(quality != 0)
|
||||
newName = "[newName] [quality > 0 ? "+" : ""][quality]"
|
||||
|
||||
if(canFail && prob((quality - 9)*10))
|
||||
var/turf/place = get_turf(parent)
|
||||
place.visible_message("<span class='danger'>[parent] <span class='blue'>violently glows blue</span> for a while, then evaporates.</span>")
|
||||
master.burn()
|
||||
return
|
||||
else if(announce)
|
||||
announce()
|
||||
|
||||
master.name = newName
|
||||
|
||||
/datum/component/fantasy/proc/unmodify()
|
||||
var/obj/item/master = parent
|
||||
|
||||
for(var/i in affixes)
|
||||
var/datum/fantasy_affix/affix = i
|
||||
affix.remove(src)
|
||||
for(var/i in appliedComponents)
|
||||
qdel(i)
|
||||
|
||||
master.force = max(0, master.force - quality)
|
||||
master.throwforce = max(0, master.throwforce - quality)
|
||||
master.armor = master.armor?.modifyAllRatings(-quality)
|
||||
|
||||
master.name = originalName
|
||||
|
||||
/datum/component/fantasy/proc/announce()
|
||||
var/turf/location = get_turf(parent)
|
||||
var/span
|
||||
var/effect_description
|
||||
if(quality >= 0)
|
||||
span = "<span class='notice'>"
|
||||
effect_description = "<span class='heavy_brass'>shimmering golden glow</span>"
|
||||
else
|
||||
span = "<span class='danger'>"
|
||||
effect_description = "<span class='bold'>mottled black glow</span>"
|
||||
|
||||
location.visible_message("[span][originalName] is covered by a [effect_description] and then transforms into [parent]!</span>")
|
||||
@@ -0,0 +1,13 @@
|
||||
/datum/fantasy_affix
|
||||
var/placement // A bitflag of "slots" this affix takes up, for example pre/suffix
|
||||
var/alignment
|
||||
var/weight = 10
|
||||
|
||||
// For those occasional affixes which only make sense in certain circumstances
|
||||
/datum/fantasy_affix/proc/validate(datum/component/fantasy/comp)
|
||||
return TRUE
|
||||
|
||||
/datum/fantasy_affix/proc/apply(datum/component/fantasy/comp, newName)
|
||||
return newName
|
||||
|
||||
/datum/fantasy_affix/proc/remove(datum/component/fantasy/comp)
|
||||
@@ -0,0 +1,68 @@
|
||||
/datum/fantasy_affix/cosmetic_prefixes
|
||||
placement = AFFIX_PREFIX
|
||||
alignment = AFFIX_GOOD | AFFIX_EVIL
|
||||
|
||||
var/list/goodPrefixes
|
||||
var/list/badPrefixes
|
||||
|
||||
/datum/fantasy_affix/cosmetic_prefixes/New()
|
||||
goodPrefixes = list(
|
||||
"greater",
|
||||
"major",
|
||||
"blessed",
|
||||
"superior",
|
||||
"empowered",
|
||||
"honed",
|
||||
"true",
|
||||
"glorious",
|
||||
"robust",
|
||||
)
|
||||
badPrefixes = list(
|
||||
"lesser",
|
||||
"minor",
|
||||
"blighted",
|
||||
"inferior",
|
||||
"enfeebled",
|
||||
"rusted",
|
||||
"unsteady",
|
||||
"tragic",
|
||||
"gimped",
|
||||
"cursed",
|
||||
)
|
||||
|
||||
weight = (length(goodPrefixes) + length(badPrefixes)) * 10
|
||||
|
||||
/datum/fantasy_affix/cosmetic_prefixes/apply(datum/component/fantasy/comp, newName)
|
||||
if(comp.quality > 0 || (comp.quality == 0 && prob(50)))
|
||||
return "[pick(goodPrefixes)] [newName]"
|
||||
else
|
||||
return "[pick(badPrefixes)] [newName]"
|
||||
|
||||
/datum/fantasy_affix/tactical
|
||||
placement = AFFIX_PREFIX
|
||||
alignment = AFFIX_GOOD
|
||||
weight = 1 // Very powerful, no one should have such power
|
||||
|
||||
/datum/fantasy_affix/tactical/apply(datum/component/fantasy/comp, newName)
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/tactical)
|
||||
return "tactical [newName]"
|
||||
|
||||
/datum/fantasy_affix/pyromantic
|
||||
placement = AFFIX_PREFIX
|
||||
alignment = AFFIX_GOOD
|
||||
|
||||
/datum/fantasy_affix/pyromantic/apply(datum/component/fantasy/comp, newName)
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/igniter, CLAMP(comp.quality, 1, 10))
|
||||
return "pyromantic [newName]"
|
||||
|
||||
/datum/fantasy_affix/vampiric
|
||||
placement = AFFIX_PREFIX
|
||||
alignment = AFFIX_GOOD
|
||||
weight = 5
|
||||
|
||||
/datum/fantasy_affix/vampiric/apply(datum/component/fantasy/comp, newName)
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/lifesteal, comp.quality)
|
||||
return "vampiric [newName]"
|
||||
@@ -0,0 +1,170 @@
|
||||
/datum/fantasy_affix/cosmetic_suffixes
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_GOOD | AFFIX_EVIL
|
||||
|
||||
var/list/goodSuffixes
|
||||
var/list/badSuffixes
|
||||
|
||||
/datum/fantasy_affix/cosmetic_suffixes/New()
|
||||
goodSuffixes = list(
|
||||
"dexterity",
|
||||
"constitution",
|
||||
"intelligence",
|
||||
"wisdom",
|
||||
"charisma",
|
||||
"the forest",
|
||||
"the hills",
|
||||
"the plains",
|
||||
"the sea",
|
||||
"the sun",
|
||||
"the moon",
|
||||
"the void",
|
||||
"the world",
|
||||
"many secrets",
|
||||
"many tales",
|
||||
"many colors",
|
||||
"rending",
|
||||
"sundering",
|
||||
"the night",
|
||||
"the day",
|
||||
)
|
||||
badSuffixes = list(
|
||||
"draining",
|
||||
"burden",
|
||||
"discomfort",
|
||||
"awkwardness",
|
||||
"poor hygiene",
|
||||
"timidity",
|
||||
)
|
||||
|
||||
weight = (length(goodSuffixes) + length(badSuffixes)) * 10
|
||||
|
||||
/datum/fantasy_affix/cosmetic_suffixes/apply(datum/component/fantasy/comp, newName)
|
||||
if(comp.quality > 0 || (comp.quality == 0 && prob(50)))
|
||||
return "[newName] of [pick(goodSuffixes)]"
|
||||
else
|
||||
return "[newName] of [pick(badSuffixes)]"
|
||||
|
||||
//////////// Good suffixes
|
||||
/datum/fantasy_affix/bane
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_GOOD
|
||||
weight = 20
|
||||
|
||||
/datum/fantasy_affix/bane/apply(datum/component/fantasy/comp, newName)
|
||||
. = ..()
|
||||
// This is set up to be easy to add to these lists as I expect it will need modifications
|
||||
var/static/list/possible_mobtypes
|
||||
if(!possible_mobtypes)
|
||||
// The base list of allowed mob/species types
|
||||
possible_mobtypes = typecacheof(list(
|
||||
/mob/living/simple_animal,
|
||||
/mob/living/carbon,
|
||||
/datum/species,
|
||||
))
|
||||
// Some particular types to disallow if they're too broad/abstract
|
||||
possible_mobtypes -= list(
|
||||
/mob/living/simple_animal/hostile,
|
||||
)
|
||||
// Some types to remove them and their subtypes
|
||||
possible_mobtypes -= typecacheof(list(
|
||||
/mob/living/carbon/human/species,
|
||||
))
|
||||
|
||||
var/mob/picked_mobtype = pick(possible_mobtypes)
|
||||
// This works even with the species picks since we're only accessing the name
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/bane, picked_mobtype)
|
||||
return "[newName] of [initial(picked_mobtype.name)] slaying"
|
||||
|
||||
/datum/fantasy_affix/summoning
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_GOOD
|
||||
weight = 5
|
||||
|
||||
/datum/fantasy_affix/summoning/apply(datum/component/fantasy/comp, newName)
|
||||
. = ..()
|
||||
// This is set up to be easy to add to these lists as I expect it will need modifications
|
||||
var/static/list/possible_mobtypes
|
||||
if(!possible_mobtypes)
|
||||
// The base list of allowed mob/species types
|
||||
possible_mobtypes = typecacheof(list(
|
||||
/mob/living/simple_animal,
|
||||
/mob/living/carbon,
|
||||
/datum/species,
|
||||
))
|
||||
// Some particular types to disallow if they're too broad/abstract
|
||||
possible_mobtypes -= list(
|
||||
/mob/living/simple_animal/hostile,
|
||||
)
|
||||
// Some types to remove them and their subtypes
|
||||
possible_mobtypes -= typecacheof(list(
|
||||
/mob/living/carbon/human/species,
|
||||
/mob/living/simple_animal/hostile/megafauna,
|
||||
))
|
||||
|
||||
var/mob/picked_mobtype = pick(possible_mobtypes)
|
||||
// This works even with the species picks since we're only accessing the name
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
var/max_mobs = max(CEILING(comp.quality/2, 1), 1)
|
||||
var/spawn_delay = 300 - 30 * comp.quality
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/summoning, list(picked_mobtype), 100, max_mobs, spawn_delay)
|
||||
return "[newName] of [initial(picked_mobtype.name)] summoning"
|
||||
|
||||
/datum/fantasy_affix/shrapnel
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_GOOD
|
||||
|
||||
/datum/fantasy_affix/shrapnel/validate(datum/component/fantasy/comp)
|
||||
if(isgun(comp.parent))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/fantasy_affix/shrapnel/apply(datum/component/fantasy/comp, newName)
|
||||
. = ..()
|
||||
// higher means more likely
|
||||
var/list/weighted_projectile_types = list(/obj/item/projectile/meteor = 1,
|
||||
/obj/item/projectile/energy/nuclear_particle = 1,
|
||||
/obj/item/projectile/beam/pulse = 1,
|
||||
/obj/item/projectile/bullet/honker = 15,
|
||||
/obj/item/projectile/temp = 15,
|
||||
/obj/item/projectile/ion = 15,
|
||||
/obj/item/projectile/magic/door = 15,
|
||||
/obj/item/projectile/magic/locker = 15,
|
||||
// /obj/item/projectile/magic/fetch = 15,
|
||||
/obj/item/projectile/beam/emitter = 15,
|
||||
// /obj/item/projectile/magic/flying = 15,
|
||||
/obj/item/projectile/energy/net = 15,
|
||||
/obj/item/projectile/bullet/incendiary/c9mm = 15,
|
||||
/obj/item/projectile/temp/hot = 15,
|
||||
/obj/item/projectile/beam/disabler = 15)
|
||||
|
||||
var/obj/item/projectile/picked_projectiletype = pickweight(weighted_projectile_types)
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/shrapnel, picked_projectiletype)
|
||||
return "[newName] of [initial(picked_projectiletype.name)] shrapnel"
|
||||
|
||||
/datum/fantasy_affix/strength
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_GOOD
|
||||
|
||||
/datum/fantasy_affix/strength/apply(datum/component/fantasy/comp, newName)
|
||||
. = ..()
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/knockback, CEILING(comp.quality/2, 1), FLOOR(comp.quality/10, 1))
|
||||
return "[newName] of strength"
|
||||
|
||||
//////////// Bad suffixes
|
||||
|
||||
/datum/fantasy_affix/fool
|
||||
placement = AFFIX_SUFFIX
|
||||
alignment = AFFIX_EVIL
|
||||
|
||||
/datum/fantasy_affix/fool/apply(datum/component/fantasy/comp, newName)
|
||||
. = ..()
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
|
||||
return "[newName] of the fool"
|
||||
Reference in New Issue
Block a user