Merge pull request #9679 from Ghommie/Ghommie-cit302

Ports "Replaces the rpg loot datum with a component and makes some suffixes have real effects" & co
This commit is contained in:
kevinz000
2019-11-03 06:14:13 -07:00
committed by GitHub
26 changed files with 766 additions and 98 deletions

View File

@@ -157,6 +157,10 @@
// /mob/living/carbon signals // /mob/living/carbon signals
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity)) #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
// /mob/living/simple_animal/hostile signals
#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
#define COMPONENT_HOSTILE_NO_ATTACK 1
// /obj signals // /obj signals
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled) #define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag) #define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag)
@@ -206,6 +210,9 @@
// /obj/item/pen signals // /obj/item/pen signals
#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user) #define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
// /obj/item/projectile signals (sent to the firer)
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" // from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" // from base of /obj/item/projectile/proc/fire(): (obj/item/projectile, atom/original_target)
// /mob/living/carbon/human signals // /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target) #define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)

View File

@@ -0,0 +1,5 @@
#define AFFIX_PREFIX (1 << 0)
#define AFFIX_SUFFIX (1 << 1)
#define AFFIX_GOOD (1 << 0)
#define AFFIX_EVIL (1 << 1)

View File

@@ -219,6 +219,10 @@ GLOBAL_LIST_INIT(pointed_types, typecacheof(list(
#define isbodypart(A) (istype(A, /obj/item/bodypart)) #define isbodypart(A) (istype(A, /obj/item/bodypart))
#define isprojectile(A) (istype(A, /obj/item/projectile))
#define isgun(A) (istype(A, /obj/item/gun))
//Assemblies //Assemblies
#define isassembly(O) (istype(O, /obj/item/assembly)) #define isassembly(O) (istype(O, /obj/item/assembly))

View File

@@ -0,0 +1,45 @@
/datum/component/bane
dupe_mode = COMPONENT_DUPE_ALLOWED
var/mobtype
var/speciestype
var/damage_multiplier
/datum/component/bane/Initialize(mobtype, damage_multiplier=1)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
if(ispath(mobtype, /mob/living))
src.mobtype = mobtype
else if(ispath(mobtype, /datum/species))
speciestype = mobtype
else
return COMPONENT_INCOMPATIBLE
src.damage_multiplier = damage_multiplier
/datum/component/bane/RegisterWithParent()
if(speciestype)
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/speciesCheck)
else
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/mobCheck)
/datum/component/bane/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_ITEM_AFTERATTACK)
/datum/component/bane/proc/speciesCheck(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!is_species(target, speciestype))
return
activate(source, target, user)
/datum/component/bane/proc/mobCheck(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!istype(target, mobtype))
return
activate(source, target, user)
/datum/component/bane/proc/activate(obj/item/source, mob/living/target, mob/attacker)
if(attacker.a_intent != INTENT_HARM)
return
var/extra_damage = max(0, source.force * damage_multiplier)
target.apply_damage(extra_damage, source.damtype, attacker.zone_selected)

View File

@@ -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>")

View File

@@ -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)

View File

@@ -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]"

View File

@@ -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"

View File

@@ -0,0 +1,37 @@
/datum/component/igniter
var/fire_stacks
/datum/component/igniter/Initialize(fire_stacks=1)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.fire_stacks = fire_stacks
/datum/component/igniter/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/item_afterattack)
else if(ishostile(parent))
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/igniter/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/igniter/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_igniter(target)
/datum/component/igniter/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_igniter(target)
/datum/component/igniter/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_igniter(target)
/datum/component/igniter/proc/do_igniter(atom/target)
if(isliving(target))
var/mob/living/L = target
L.adjust_fire_stacks(fire_stacks)
L.IgniteMob()

View File

@@ -0,0 +1,44 @@
/datum/component/knockback
var/throw_distance
var/throw_anchored
/datum/component/knockback/Initialize(throw_distance=1)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.throw_distance = throw_distance
src.throw_anchored = throw_anchored
/datum/component/knockback/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/item_afterattack)
else if(ishostile(parent))
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/knockback/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_knockback(target, user, get_dir(source, target))
/datum/component/knockback/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_knockback(target, attacker, get_dir(attacker, target))
/datum/component/knockback/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_knockback(target, null, angle2dir(Angle))
/datum/component/knockback/proc/do_knockback(atom/target, mob/thrower, throw_dir)
if(!ismovableatom(target) || throw_dir == null)
return
var/atom/movable/throwee = target
if(throwee.anchored && !throw_anchored)
return
if(throw_distance < 0)
throw_dir = turn(throw_dir, 180)
throw_distance *= -1
var/atom/throw_target = get_edge_target_turf(throwee, throw_dir)
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower)

View File

@@ -0,0 +1,39 @@
/datum/component/lifesteal
var/flat_heal // heals a constant amount every time a hit occurs
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
/datum/component/lifesteal/Initialize(flat_heal=0)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent))
return COMPONENT_INCOMPATIBLE
src.flat_heal = flat_heal
/datum/component/lifesteal/RegisterWithParent()
if(isgun(parent))
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/item_afterattack)
else if(ishostile(parent))
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/lifesteal/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/lifesteal/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_lifesteal(user, target)
/datum/component/lifesteal/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_lifesteal(attacker, target)
/datum/component/lifesteal/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_lifesteal(firer, target)
/datum/component/lifesteal/proc/do_lifesteal(atom/heal_target, atom/damage_target)
if(isliving(heal_target) && isliving(damage_target))
var/mob/living/healing = heal_target
var/mob/living/damaging = damage_target
if(damaging.stat != DEAD)
healing.heal_ordered_damage(flat_heal, damage_heal_order)

View File

@@ -0,0 +1,39 @@
/datum/component/shrapnel
var/projectile_type
var/radius // shoots a projectile for every turf on this radius from the hit target
var/override_projectile_range
/datum/component/shrapnel/Initialize(projectile_type, radius=1, override_projectile_range)
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.projectile_type = projectile_type
src.radius = radius
src.override_projectile_range = override_projectile_range
/datum/component/shrapnel/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
/datum/component/shrapnel/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_PROJECTILE_ON_HIT))
/datum/component/shrapnel/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_shrapnel(firer, target)
/datum/component/shrapnel/proc/do_shrapnel(mob/firer, atom/target)
if(radius < 1)
return
var/turf/target_turf = get_turf(target)
for(var/turf/shootat_turf in RANGE_TURFS(radius, target) - RANGE_TURFS(radius-1, target))
var/obj/item/projectile/P = new projectile_type(target_turf)
//Shooting Code:
P.range = radius+1
if(override_projectile_range)
P.range = override_projectile_range
P.preparePixelProjectile(shootat_turf, target)
P.firer = firer // don't hit ourself that would be really annoying
P.permutated += target // don't hit the target we hit already with the flak
P.fire()

View File

@@ -0,0 +1,69 @@
/datum/component/summoning
var/list/mob_types = list()
var/spawn_chance // chance for the mob to spawn on hit in percent
var/max_mobs
var/spawn_delay // delay in spawning between mobs (deciseconds)
var/spawn_text
var/spawn_sound
var/list/faction
var/last_spawned_time = 0
var/list/spawned_mobs = list()
/datum/component/summoning/Initialize(mob_types, spawn_chance=100, max_mobs=3, spawn_delay=100, spawn_text="appears out of nowhere", spawn_sound='sound/magic/summon_magic.ogg', faction)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.mob_types = mob_types
src.spawn_chance = spawn_chance
src.max_mobs = max_mobs
src.spawn_delay = spawn_delay
src.spawn_text = spawn_text
src.spawn_sound = spawn_sound
src.faction = faction
/datum/component/summoning/RegisterWithParent()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/item_afterattack)
else if(ishostile(parent))
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/summoning/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/summoning/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_spawn_mob(get_turf(target), user)
/datum/component/summoning/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_spawn_mob(get_turf(target), attacker)
/datum/component/summoning/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_spawn_mob(get_turf(target), firer)
/datum/component/summoning/proc/do_spawn_mob(atom/spawn_location, summoner)
if(spawned_mobs.len >= max_mobs)
return 0
if(last_spawned_time > world.time)
return 0
if(!prob(spawn_chance))
return 0
last_spawned_time = world.time + spawn_delay
var/chosen_mob_type = pick(mob_types)
var/mob/living/simple_animal/L = new chosen_mob_type(spawn_location)
if(ishostile(L))
var/mob/living/simple_animal/hostile/H = L
H.friends += summoner // do not attack our summon boy
spawned_mobs += L
if(faction != null)
L.faction = faction
RegisterSignal(L, COMSIG_MOB_DEATH, .proc/on_spawned_death) // so we can remove them from the list, etc (for mobs with corpses)
playsound(spawn_location,spawn_sound, 50, 1)
spawn_location.visible_message("<span class='danger'>[L] [spawn_text].</span>")
/datum/component/summoning/proc/on_spawned_death(mob/killed, gibbed)
spawned_mobs -= killed

View File

@@ -0,0 +1,42 @@
/datum/component/tactical
var/allowed_slot
/datum/component/tactical/Initialize(allowed_slot)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
src.allowed_slot = allowed_slot
/datum/component/tactical/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/modify)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/unmodify)
/datum/component/tactical/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
unmodify()
/datum/component/fantasy/Destroy()
unmodify()
return ..()
/datum/component/tactical/proc/modify(obj/item/source, mob/user, slot)
if(allowed_slot && slot != allowed_slot)
unmodify()
return
var/obj/item/master = parent
var/image/I = image(icon = master.icon, icon_state = master.icon_state, loc = user)
I.copy_overlays(master)
I.override = TRUE
source.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission", I)
I.layer = ABOVE_MOB_LAYER
/datum/component/tactical/proc/unmodify(obj/item/source, mob/user)
var/obj/item/master = source || parent
if(!user)
if(!ismob(master.loc))
return
user = master.loc
user.remove_alt_appearance("sneaking_mission")

View File

@@ -562,6 +562,7 @@
//Shooting Code: //Shooting Code:
A.preparePixelProjectile(target, T) A.preparePixelProjectile(target, T)
A.firer = src A.firer = src
A.fired_from = src
A.fire() A.fire()
return A return A

View File

@@ -97,9 +97,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// non-clothing items // non-clothing items
var/datum/dog_fashion/dog_fashion = null var/datum/dog_fashion/dog_fashion = null
var/datum/rpg_loot/rpg_loot = null
//Tooltip vars //Tooltip vars
var/force_string //string form of an item's force. Edit this var only to set a custom force string var/force_string //string form of an item's force. Edit this var only to set a custom force string
var/last_force_string_check = 0 var/last_force_string_check = 0
@@ -124,7 +121,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
actions_types = null actions_types = null
if(GLOB.rpg_loot_items) if(GLOB.rpg_loot_items)
rpg_loot = new(src) AddComponent(/datum/component/fantasy)
if(force_string) if(force_string)
item_flags |= FORCE_STRING_OVERRIDE item_flags |= FORCE_STRING_OVERRIDE
@@ -149,7 +146,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
m.temporarilyRemoveItemFromInventory(src, TRUE) m.temporarilyRemoveItemFromInventory(src, TRUE)
for(var/X in actions) for(var/X in actions)
qdel(X) qdel(X)
QDEL_NULL(rpg_loot)
return ..() return ..()
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self) /obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)

View File

@@ -430,7 +430,7 @@
A.BB.nodamage = FALSE A.BB.nodamage = FALSE
A.BB.speed = 0.5 A.BB.speed = 0.5
playsound(src.loc, 'sound/machines/click.ogg', 50, 1) playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
A.fire_casing(target, user, params, 0, 0, null, 0) A.fire_casing(target, user, params, 0, 0, null, 0, src)
user.visible_message("<span class='warning'>[user] blasts a flying lollipop at [target]!</span>") user.visible_message("<span class='warning'>[user] blasts a flying lollipop at [target]!</span>")
check_amount() check_amount()
@@ -446,7 +446,7 @@
A.BB.speed = 0.5 A.BB.speed = 0.5
A.BB.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) A.BB.color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
playsound(src.loc, 'sound/weapons/bulletflyby3.ogg', 50, 1) playsound(src.loc, 'sound/weapons/bulletflyby3.ogg', 50, 1)
A.fire_casing(target, user, params, 0, 0, null, 0) A.fire_casing(target, user, params, 0, 0, null, 0, src)
user.visible_message("<span class='warning'>[user] shoots a high-velocity gumball at [target]!</span>") user.visible_message("<span class='warning'>[user] shoots a high-velocity gumball at [target]!</span>")
check_amount() check_amount()

View File

@@ -300,18 +300,9 @@
throw_speed = 2 throw_speed = 2
throw_range = 4 throw_range = 4
/obj/item/twohanded/required/kirbyplants/Initialize()
/obj/item/twohanded/required/kirbyplants/equipped(mob/living/user) . = ..()
var/image/I = image(icon = 'icons/obj/flora/plants.dmi' , icon_state = src.icon_state, loc = user) AddComponent(/datum/component/tactical)
I.copy_overlays(src)
I.override = 1
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission", I)
I.layer = ABOVE_MOB_LAYER
..()
/obj/item/twohanded/required/kirbyplants/dropped(mob/living/user)
..()
user.remove_alt_appearance("sneaking_mission")
/obj/item/twohanded/required/kirbyplants/random /obj/item/twohanded/required/kirbyplants/random
icon = 'icons/obj/flora/_flora.dmi' icon = 'icons/obj/flora/_flora.dmi'

View File

@@ -8,8 +8,11 @@
/datum/round_event/wizard/rpgloot/start() /datum/round_event/wizard/rpgloot/start()
var/upgrade_scroll_chance = 0 var/upgrade_scroll_chance = 0
for(var/obj/item/I in world) for(var/obj/item/I in world)
if(!istype(I.rpg_loot)) CHECK_TICK
I.rpg_loot = new(I) if(!(I.flags_1 & INITIALIZED_1))
continue
I.AddComponent(/datum/component/fantasy)
if(istype(I, /obj/item/storage)) if(istype(I, /obj/item/storage))
var/obj/item/storage/S = I var/obj/item/storage/S = I
@@ -31,86 +34,20 @@
var/upgrade_amount = 1 var/upgrade_amount = 1
var/can_backfire = TRUE var/can_backfire = TRUE
var/one_use = TRUE var/uses = 1
/obj/item/upgradescroll/afterattack(obj/item/target, mob/user , proximity) /obj/item/upgradescroll/afterattack(obj/item/target, mob/user , proximity)
. = ..() . = ..()
if(!proximity || !istype(target)) if(!proximity || !istype(target))
return return
var/datum/rpg_loot/rpg_loot_datum = target.rpg_loot target.AddComponent(/datum/component/fantasy, upgrade_amount, null, null, can_backfire, TRUE)
if(!istype(rpg_loot_datum))
target.rpg_loot = rpg_loot_datum = new /datum/rpg_loot(target)
var/quality = rpg_loot_datum.quality if(--uses <= 0)
if(can_backfire && (quality > 9 && prob((quality - 9)*10)))
to_chat(user, "<span class='danger'>[target] violently glows blue for a while, then evaporates.</span>")
target.burn()
else
to_chat(user, "<span class='notice'>[target] glows blue and seems vaguely \"better\"!</span>")
rpg_loot_datum.modify(upgrade_amount)
if(one_use)
qdel(src) qdel(src)
/obj/item/upgradescroll/unlimited /obj/item/upgradescroll/unlimited
name = "unlimited foolproof item fortification scroll" name = "unlimited foolproof item fortification scroll"
desc = "Somehow, this piece of paper can be applied to items to make them \"better\". This scroll is made from the tongues of dead paper wizards, and can be used an unlimited number of times, with no drawbacks." desc = "Somehow, this piece of paper can be applied to items to make them \"better\". This scroll is made from the tongues of dead paper wizards, and can be used an unlimited number of times, with no drawbacks."
one_use = FALSE uses = INFINITY
can_backfire = FALSE can_backfire = FALSE
/datum/rpg_loot
var/positive_prefix = "okay"
var/negative_prefix = "weak"
var/suffix = "something profound"
var/quality = 0
var/obj/item/attached
var/original_name
/datum/rpg_loot/New(attached_item=null)
attached = attached_item
randomise()
/datum/rpg_loot/Destroy()
attached = null
/datum/rpg_loot/proc/randomise()
var/static/list/prefixespositive = list("greater", "major", "blessed", "superior", "empowered", "honed", "true", "glorious", "robust")
var/static/list/prefixesnegative = list("lesser", "minor", "blighted", "inferior", "enfeebled", "rusted", "unsteady", "tragic", "gimped")
var/static/list/suffixes = list("orc slaying", "elf slaying", "corgi slaying", "strength", "dexterity", "constitution", "intelligence", "wisdom", "charisma", "the forest", "the hills", "the plains", "the sea", "the sun", "the moon", "the void", "the world", "the fool", "many secrets", "many tales", "many colors", "rending", "sundering", "the night", "the day")
var/new_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)
suffix = pick(suffixes)
positive_prefix = pick(prefixespositive)
negative_prefix = pick(prefixesnegative)
if(prob(50))
new_quality = -new_quality
modify(new_quality)
/datum/rpg_loot/proc/rename()
var/obj/item/I = attached
if(!original_name)
original_name = I.name
if(quality < 0)
I.name = "[negative_prefix] [original_name] of [suffix] [quality]"
else if(quality == 0)
I.name = "[original_name] of [suffix]"
else if(quality > 0)
I.name = "[positive_prefix] [original_name] of [suffix] +[quality]"
/datum/rpg_loot/proc/modify(quality_mod)
var/obj/item/I = attached
quality += quality_mod
I.force = max(0,I.force + quality_mod)
I.throwforce = max(0,I.throwforce + quality_mod)
I.armor = I.armor.modifyAllRatings(quality)
rename()

View File

@@ -344,6 +344,7 @@
/mob/living/simple_animal/hostile/proc/AttackingTarget() /mob/living/simple_animal/hostile/proc/AttackingTarget()
SEND_SIGNAL(src, COMSIG_HOSTILE_ATTACKINGTARGET, target)
in_melee = TRUE in_melee = TRUE
if(vore_active) if(vore_active)
if(isliving(target)) if(isliving(target))
@@ -426,12 +427,13 @@
if(casingtype) if(casingtype)
var/obj/item/ammo_casing/casing = new casingtype(startloc) var/obj/item/ammo_casing/casing = new casingtype(startloc)
playsound(src, projectilesound, 100, 1) playsound(src, projectilesound, 100, 1)
casing.fire_casing(targeted_atom, src, null, null, null, ran_zone()) casing.fire_casing(targeted_atom, src, null, null, null, ran_zone(), src)
else if(projectiletype) else if(projectiletype)
var/obj/item/projectile/P = new projectiletype(startloc) var/obj/item/projectile/P = new projectiletype(startloc)
playsound(src, projectilesound, 100, 1) playsound(src, projectilesound, 100, 1)
P.starting = startloc P.starting = startloc
P.firer = src P.firer = src
P.fired_from = src
P.yo = targeted_atom.y - startloc.y P.yo = targeted_atom.y - startloc.y
P.xo = targeted_atom.x - startloc.x P.xo = targeted_atom.x - startloc.x
if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space

View File

@@ -199,6 +199,7 @@
if(prob(35)) if(prob(35))
sparks.start() sparks.start()
P.firer = user ? user : src P.firer = user ? user : src
P.fired_from = src
if(last_projectile_params) if(last_projectile_params)
P.p_x = last_projectile_params[2] P.p_x = last_projectile_params[2]
P.p_y = last_projectile_params[3] P.p_y = last_projectile_params[3]

View File

@@ -1,8 +1,8 @@
/obj/item/ammo_casing/proc/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread) /obj/item/ammo_casing/proc/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
distro += variance distro += variance
for (var/i = max(1, pellets), i > 0, i--) for (var/i = max(1, pellets), i > 0, i--)
var/targloc = get_turf(target) var/targloc = get_turf(target)
ready_proj(target, user, quiet, zone_override) ready_proj(target, user, quiet, zone_override, fired_from)
if(distro) //We have to spread a pixel-precision bullet. throw_proj was called before so angles should exist by now... if(distro) //We have to spread a pixel-precision bullet. throw_proj was called before so angles should exist by now...
if(randomspread) if(randomspread)
spread = round((rand() - 0.5) * distro) spread = round((rand() - 0.5) * distro)
@@ -20,11 +20,12 @@
update_icon() update_icon()
return 1 return 1
/obj/item/ammo_casing/proc/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") /obj/item/ammo_casing/proc/ready_proj(atom/target, mob/living/user, quiet, zone_override = "", fired_from)
if (!BB) if (!BB)
return return
BB.original = target BB.original = target
BB.firer = user BB.firer = user
BB.fired_from = fired_from
if (zone_override) if (zone_override)
BB.def_zone = zone_override BB.def_zone = zone_override
else else

View File

@@ -3,7 +3,7 @@
firing_effect_type = null firing_effect_type = null
heavy_metal = FALSE heavy_metal = FALSE
/obj/item/ammo_casing/caseless/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread) /obj/item/ammo_casing/caseless/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
if (..()) //successfully firing if (..()) //successfully firing
moveToNullspace() moveToNullspace()
QDEL_NULL(src) QDEL_NULL(src)

View File

@@ -233,7 +233,7 @@
else //Smart spread else //Smart spread
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1) sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd)) if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user) shoot_with_empty_chamber(user)
firing_burst = FALSE firing_burst = FALSE
return FALSE return FALSE
@@ -280,7 +280,7 @@
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>") to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return return
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread)) sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
if(!chambered.fire_casing(target, user, params, , suppressed, zone_override, sprd)) if(!chambered.fire_casing(target, user, params, , suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user) shoot_with_empty_chamber(user)
return return
else else

View File

@@ -17,6 +17,7 @@
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/def_zone = "" //Aiming at var/def_zone = "" //Aiming at
var/atom/movable/firer = null//Who shot it var/atom/movable/firer = null//Who shot it
var/atom/fired_from = null // the atom that the projectile was fired from (gun, turret)
var/suppressed = FALSE //Attack message var/suppressed = FALSE //Attack message
var/candink = FALSE //Can this projectile play the dink sound when hitting the head? var/candink = FALSE //Can this projectile play the dink sound when hitting the head?
var/yo = null var/yo = null
@@ -131,6 +132,8 @@
return TRUE return TRUE
/obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE) /obj/item/projectile/proc/on_hit(atom/target, blocked = FALSE)
if(fired_from)
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle)
var/turf/target_loca = get_turf(target) var/turf/target_loca = get_turf(target)
var/hitx var/hitx
@@ -356,6 +359,8 @@
pixel_move(1, FALSE) pixel_move(1, FALSE)
/obj/item/projectile/proc/fire(angle, atom/direct_target) /obj/item/projectile/proc/fire(angle, atom/direct_target)
if(fired_from)
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original)
//If no angle needs to resolve it from xo/yo! //If no angle needs to resolve it from xo/yo!
if(!log_override && firer && original) if(!log_override && firer && original)
log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]") log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")

View File

@@ -45,6 +45,7 @@
#include "code\__DEFINES\donator_groupings.dm" #include "code\__DEFINES\donator_groupings.dm"
#include "code\__DEFINES\events.dm" #include "code\__DEFINES\events.dm"
#include "code\__DEFINES\exports.dm" #include "code\__DEFINES\exports.dm"
#include "code\__DEFINES\fantasy_affixes.dm"
#include "code\__DEFINES\flags.dm" #include "code\__DEFINES\flags.dm"
#include "code\__DEFINES\food.dm" #include "code\__DEFINES\food.dm"
#include "code\__DEFINES\footsteps.dm" #include "code\__DEFINES\footsteps.dm"
@@ -344,6 +345,7 @@
#include "code\datums\components\_component.dm" #include "code\datums\components\_component.dm"
#include "code\datums\components\anti_magic.dm" #include "code\datums\components\anti_magic.dm"
#include "code\datums\components\armor_plate.dm" #include "code\datums\components\armor_plate.dm"
#include "code\datums\components\bane.dm"
#include "code\datums\components\bouncy.dm" #include "code\datums\components\bouncy.dm"
#include "code\datums\components\butchering.dm" #include "code\datums\components\butchering.dm"
#include "code\datums\components\caltrop.dm" #include "code\datums\components\caltrop.dm"
@@ -357,9 +359,12 @@
#include "code\datums\components\empprotection.dm" #include "code\datums\components\empprotection.dm"
#include "code\datums\components\footstep.dm" #include "code\datums\components\footstep.dm"
#include "code\datums\components\forced_gravity.dm" #include "code\datums\components\forced_gravity.dm"
#include "code\datums\components\igniter.dm"
#include "code\datums\components\infective.dm" #include "code\datums\components\infective.dm"
#include "code\datums\components\jousting.dm" #include "code\datums\components\jousting.dm"
#include "code\datums\components\knockback.dm"
#include "code\datums\components\knockoff.dm" #include "code\datums\components\knockoff.dm"
#include "code\datums\components\lifesteal.dm"
#include "code\datums\components\lockon_aiming.dm" #include "code\datums\components\lockon_aiming.dm"
#include "code\datums\components\magnetic_catch.dm" #include "code\datums\components\magnetic_catch.dm"
#include "code\datums\components\material_container.dm" #include "code\datums\components\material_container.dm"
@@ -375,16 +380,23 @@
#include "code\datums\components\remote_materials.dm" #include "code\datums\components\remote_materials.dm"
#include "code\datums\components\riding.dm" #include "code\datums\components\riding.dm"
#include "code\datums\components\rotation.dm" #include "code\datums\components\rotation.dm"
#include "code\datums\components\shrapnel.dm"
#include "code\datums\components\slippery.dm" #include "code\datums\components\slippery.dm"
#include "code\datums\components\spooky.dm" #include "code\datums\components\spooky.dm"
#include "code\datums\components\squeak.dm" #include "code\datums\components\squeak.dm"
#include "code\datums\components\stationloving.dm" #include "code\datums\components\stationloving.dm"
#include "code\datums\components\summoning.dm"
#include "code\datums\components\swarming.dm" #include "code\datums\components\swarming.dm"
#include "code\datums\components\tactical.dm"
#include "code\datums\components\thermite.dm" #include "code\datums\components\thermite.dm"
#include "code\datums\components\uplink.dm" #include "code\datums\components\uplink.dm"
#include "code\datums\components\virtual_reality.dm" #include "code\datums\components\virtual_reality.dm"
#include "code\datums\components\wearertargeting.dm" #include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm" #include "code\datums\components\wet_floor.dm"
#include "code\datums\components\fantasy\_fantasy.dm"
#include "code\datums\components\fantasy\affix.dm"
#include "code\datums\components\fantasy\prefixes.dm"
#include "code\datums\components\fantasy\suffixes.dm"
#include "code\datums\components\storage\storage.dm" #include "code\datums\components\storage\storage.dm"
#include "code\datums\components\storage\concrete\_concrete.dm" #include "code\datums\components\storage\concrete\_concrete.dm"
#include "code\datums\components\storage\concrete\bag_of_holding.dm" #include "code\datums\components\storage\concrete\bag_of_holding.dm"