diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index dacbda950e..4fa3547fa3 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -83,6 +83,7 @@ GLOBAL_VAR_INIT(refid_filter, TYPEID(filter(type="angular_blur"))) #define issimulatedturf(A) istype(A, /turf/simulated) #define isopenspace(A) istype(A, /turf/simulated/open) #define isspace(A) istype(A, /turf/space) +#define islava(A) istype(A, /turf/simulated/floor/lava) #define isopenturf(A) (istype(A, /turf/simulated/open) || istype(A, /turf/space)) #define isnonsolidturf(A) (istype(A, /turf/simulated/open) || istype(A, /turf/space) || istype(A, /turf/simulated/floor/water) || istype(A, /turf/simulated/floor/lava)) #define ismineralturf(A) istype(A, /turf/simulated/mineral) diff --git a/code/__defines/traits/declarations.dm b/code/__defines/traits/declarations.dm index 3f2fe08481..b305044f2a 100644 --- a/code/__defines/traits/declarations.dm +++ b/code/__defines/traits/declarations.dm @@ -59,8 +59,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_SLOBBER "slobber" // Owner will be considered a tiny mob for some interactions, such as airlocks not opening unless they have a client, or being vacuumed up by the vacpack #define TRAIT_AMBIENT_PEST_MOB "ambient_pest_mob" +///Trait given by /datum/component/germ_sensitive +#define TRAIT_GERM_SENSITIVE "germ_sensitive" +#define TRAIT_STRONG_STOMACH "strong_stomach" /// Marks that this object is irradiated -#define TRAIT_IRRADIATED "iraddiated" +#define TRAIT_IRRADIATED "irradiated" /// Whether or not this item will allow the radiation SS to go through standard /// radiation processing as if this wasn't already irradiated. /// Basically, without this, COMSIG_IN_RANGE_OF_IRRADIATION won't fire once the object is irradiated. diff --git a/code/_global_vars/typecache.dm b/code/_global_vars/typecache.dm index 21c2656608..14f3d36b10 100644 --- a/code/_global_vars/typecache.dm +++ b/code/_global_vars/typecache.dm @@ -4,3 +4,28 @@ //Note: typecache can only replace istype if you know for sure the thing is at least a datum. GLOBAL_LIST_INIT(typecache_stack, typecacheof(/obj/item/stack)) + +/// A typecache listing structures that are considered to have surfaces that you can place items on that are higher than the floor. This, of course, should be restricted to /atom/movables. This is primarily used for food decomposition code. +GLOBAL_LIST_INIT(typecache_elevated_structures, typecacheof(list( + /obj/machinery, + /obj/structure, + /obj/structure/table, + //Kitchen + /obj/machinery/smartfridge, + /obj/structure/bonfire, + /obj/structure/fireplace, + /obj/machinery/appliance/cooker/grill, +// /obj/machinery/griddle, + /obj/machinery/appliance/cooker/fryer, + /obj/machinery/processor, + /obj/machinery/microwave, + /obj/machinery/appliance/cooker/oven, + /obj/machinery/gibber, + /obj/machinery/icecream_vat, + //Botany + /obj/machinery/biogenerator, + /obj/machinery/portable_atmospherics/hydroponics, // So that harvest doesn't catch germs or decompose (includes dirt piles) + //Medbay + /obj/machinery/atmospherics/unary/cryo_cell, + /obj/machinery/chem_master, // Pills may catch germs +))) diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index a70f7f4144..cd53e54dca 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -637,3 +637,26 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH, var/list/l = i return l.Copy() return i + +/proc/slot2body_zone(slot) + switch(slot) + if(SLOT_BACK, SLOT_OCLOTHING, SLOT_ICLOTHING, SLOT_BELT, SLOT_ID) + return BP_TORSO + + if(SLOT_GLOVES) + return pick(BP_L_HAND, BP_R_HAND) + + if(SLOT_HEAD, SLOT_TWOEARS, SLOT_TIE, SLOT_EARS) + return BP_HEAD + + if(SLOT_MASK) + return BP_HEAD + + if(SLOT_EYES) + return BP_HEAD + + if(SLOT_FEET) + return pick(BP_R_FOOT, BP_L_FOOT) + +// if(SLOT_LEGCUFFED) +// return pick(BP_L_LEG, BODY_ZONE_R_LEG) diff --git a/code/datums/components/food/germ_sensitive.dm b/code/datums/components/food/germ_sensitive.dm new file mode 100644 index 0000000000..2452d0d8c4 --- /dev/null +++ b/code/datums/components/food/germ_sensitive.dm @@ -0,0 +1,132 @@ +// Don't eat off the floor or hold parent object with dirty hands, you'll get sick + +/// Time needed for bacteria to infect the parent object +#define GERM_EXPOSURE_DELAY (5 SECONDS) // Five-second rule + +/// Possible diseases +GLOBAL_LIST_INIT(floor_diseases, list( + /datum/disease/cold = 2, + /datum/disease/food_poisoning = 7, + /datum/disease/lycan = 1, +)) + +/// Makes items infective if left on floor, also sending corresponding signals to parent +/datum/component/germ_sensitive + /// Timer for counting delay before becoming infective + var/timer_id + /// Whether it is already infective + var/infective = FALSE + +/datum/component/germ_sensitive/Initialize(mapload) + if(!isobj(parent)) + return COMPONENT_INCOMPATIBLE + + ADD_TRAIT(parent, TRAIT_GERM_SENSITIVE, REF(src)) + + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examine)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_movement)) + RegisterSignals(parent, list(COMSIG_COMPONENT_CLEAN_ACT, COMSIG_ITEM_FRIED, COMSIG_ITEM_BARBEQUE_GRILLED, COMSIG_ATOM_FIRE_ACT), PROC_REF(delete_germs)) + + RegisterSignals(parent, list( + COMSIG_ITEM_DROPPED, //Dropped into the world + COMSIG_ATOM_EXITED, //Object exits a storage object (tables, boxes, etc) + ), + PROC_REF(dropped)) + + RegisterSignals(parent, list( + COMSIG_ITEM_PICKUP, //Picked up by mob + COMSIG_ATOM_ENTERED, //Object enters a storage object (tables, boxes, etc.) + ), + PROC_REF(picked_up)) + + // Map spawned items are protected until moved + if(!mapload) + handle_movement() + +/datum/component/germ_sensitive/UnregisterFromParent() + REMOVE_TRAIT(parent, TRAIT_GERM_SENSITIVE, REF(src)) + UnregisterSignal(parent, list( + COMSIG_ATOM_ENTERED, + COMSIG_ATOM_EXAMINE, + COMSIG_ATOM_EXITED, + COMSIG_COMPONENT_CLEAN_ACT, + COMSIG_ITEM_FRIED, + COMSIG_ITEM_BARBEQUE_GRILLED, + COMSIG_ATOM_FIRE_ACT, + COMSIG_ITEM_DROPPED, + COMSIG_ITEM_PICKUP, + COMSIG_MOVABLE_MOVED, + )) + +/datum/component/germ_sensitive/Destroy() + remove_timer() + return ..() + +/datum/component/germ_sensitive/proc/remove_timer() + if(!timer_id) + return + deltimer(timer_id) + timer_id = null + +/datum/component/germ_sensitive/proc/handle_movement() + SIGNAL_HANDLER + + var/obj/parent_object = parent + var/turf/simulated/open_turf = parent_object.loc + + // Is parent on simulated valid turf that is safe? Or held/in a pocket/in a closet/etc? + if(!istype(open_turf) || islava(open_turf) || ismineralturf(open_turf) || !parent_object.get_gravity()) + remove_timer() + SEND_SIGNAL(parent, COMSIG_ATOM_GERM_UNEXPOSED, src) + return + + // Is parent on an elevated structure? + for(var/atom/movable/content as anything in open_turf.contents) + if(GLOB.typecache_elevated_structures[content.type]) + remove_timer() + SEND_SIGNAL(parent, COMSIG_ATOM_GERM_UNEXPOSED, src) + return + + // Exposed to bacteria, start countdown until becoming infected + timer_id = addtimer(CALLBACK(src, PROC_REF(expose_to_germs)), GERM_EXPOSURE_DELAY, TIMER_STOPPABLE | TIMER_UNIQUE) + +/datum/component/germ_sensitive/proc/picked_up() + SIGNAL_HANDLER + SEND_SIGNAL(parent, COMSIG_ATOM_GERM_UNEXPOSED, src) + remove_timer() + +/datum/component/germ_sensitive/proc/dropped() + SIGNAL_HANDLER + handle_movement() + +/datum/component/germ_sensitive/proc/examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + if(infective) + examine_list += span_warning("[parent] looks dirty and not safe to consume.") + +/datum/component/germ_sensitive/proc/expose_to_germs() + // Admin spawned items are never exposed NYI +// var/atom/parent_atom = parent +// if(parent_atom.flags_1 & ADMIN_SPAWNED_1) +// return + + SEND_SIGNAL(parent, COMSIG_ATOM_GERM_EXPOSED, src) + + if(infective) + return + infective = TRUE + + var/random_disease = pick_weight(GLOB.floor_diseases) + parent.AddComponent(/datum/component/infective, new random_disease, weak = TRUE) + +/datum/component/germ_sensitive/proc/delete_germs() + SIGNAL_HANDLER + + . = NONE + + if(infective) + infective = FALSE + qdel(parent.GetComponent(/datum/component/infective)) + return COMPONENT_CLEANED + +#undef GERM_EXPOSURE_DELAY diff --git a/code/datums/components/infective.dm b/code/datums/components/infective.dm index bd5ceea9b5..019d8bd7ca 100644 --- a/code/datums/components/infective.dm +++ b/code/datums/components/infective.dm @@ -1,43 +1,203 @@ /datum/component/infective - dupe_mode = COMPONENT_DUPE_ALLOWED - var/list/datum/disease/diseases + var/list/datum/disease/diseases //make sure these are the static, non-processing versions! var/expire_time var/required_clean_types = CLEAN_TYPE_DISEASE + /// The infection is weak and can only infect on consumption with small chance + var/is_weak = FALSE + /// Chance of weak infection on consumption + var/weak_infection_chance = 10 -/datum/component/infective/Initialize(list/datum/disease/_diseases, expire_in) - if(islist(_diseases)) - diseases = _diseases - else - diseases = list(_diseases) - if(!diseases.len || isnull(diseases[1])) - stack_trace("Infective component initialized without any diseases!") - qdel(src) - if(expire_in) - expire_time = world.time + expire_in - QDEL_IN(src, expire_in) + +/datum/component/infective/Initialize(list/datum/disease/diseases, expire_in, weak = FALSE, weak_infection_chance = 10) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE + if(!islist(diseases)) + diseases = list(diseases) + + ///Make sure the diseases list is populated with instances of diseases so that it doesn't have to be for each AddComponent call. + for(var/datum/disease/disease as anything in diseases) + if(!disease) //empty entry, remove. + diseases -= disease + if(ispath(disease, /datum/disease)) + var/datum/disease/instance = new disease + diseases -= disease + diseases += instance + else if(!istype(disease)) + stack_trace("found [isdatum(disease) ? "an instance of [disease.type]" : disease] inside the diseases list argument for [type]") + diseases -= disease + + src.diseases = diseases + + if(expire_in) + expire_time = world.time + expire_in + QDEL_IN(src, expire_in) + + is_weak = weak + src.weak_infection_chance = weak_infection_chance + +/datum/component/infective/Destroy() + QDEL_LIST(diseases) + return ..() + +/datum/component/infective/RegisterWithParent() + if(is_weak && isitem(parent)) + RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(try_infect_eat)) + RegisterSignal(parent, COMSIG_PILL_CONSUMED, PROC_REF(try_infect_eat)) + return var/static/list/disease_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(try_infect_crossed), ) AddComponent(/datum/component/connect_loc_behalf, parent, disease_connections) RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean)) + RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, PROC_REF(try_infect_buckle)) RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(try_infect_collide)) - + RegisterSignal(parent, COMSIG_MOVABLE_IMPACT_ZONE, PROC_REF(try_infect_impact_zone)) RegisterSignal(parent, COMSIG_ATOM_EXTRAPOLATOR_ACT, PROC_REF(extrapolation)) if(isitem(parent)) RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(try_infect_attack)) - // RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(try_infect_eat)) - TODO: Send signal when eating + if(isitem(parent)) + RegisterSignal(parent, COMSIG_ITEM_ATTACK_ZONE, PROC_REF(try_infect_attack_zone)) + RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(try_infect_attack)) + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(try_infect_equipped)) + RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(try_infect_eat)) + RegisterSignal(parent, COMSIG_PILL_CONSUMED, PROC_REF(try_infect_eat)) + if(istype(parent, /obj/item/reagent_containers/glass)) + RegisterSignal(parent, COMSIG_GLASS_DRANK, PROC_REF(try_infect_drink)) + if(isorgan(parent)) + RegisterSignal(parent, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_organ_insertion)) + +/datum/component/infective/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list( + COMSIG_FOOD_EATEN, + COMSIG_PILL_CONSUMED, + COMSIG_COMPONENT_CLEAN_ACT, + COMSIG_MOVABLE_BUMP, + COMSIG_MOVABLE_IMPACT_ZONE, + COMSIG_ITEM_ATTACK_ZONE, + COMSIG_ITEM_ATTACK, + COMSIG_ITEM_EQUIPPED, + COMSIG_GLASS_DRANK, + COMSIG_ORGAN_IMPLANTED, + COMSIG_ATOM_EXTRAPOLATOR_ACT + )) + qdel(GetComponent(/datum/component/connect_loc_behalf)) + +/datum/component/infective/proc/on_organ_insertion(obj/item/organ/target, mob/living/carbon/receiver) + SIGNAL_HANDLER + + for(var/datum/disease/disease in diseases) + receiver.ForceContractDisease(disease) + + qdel(src) // once organ is implanted delete the infective component + +/datum/component/infective/proc/try_infect_eat(datum/source, mob/living/eater, mob/living/feeder) + SIGNAL_HANDLER + + if(HAS_TRAIT(eater, TRAIT_STRONG_STOMACH)) + return + +// eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food) + + for(var/datum/disease/disease as anything in diseases) + if(is_weak && !prob(weak_infection_chance)) + continue +// if(!disease.has_required_infectious_organ(eater, ORGAN_SLOT_STOMACH)) +// continue + + eater.ForceContractDisease(disease) + + if(!is_weak) + try_infect(feeder, BP_L_ARM) + +/datum/component/infective/proc/try_infect_drink(datum/source, mob/living/drinker, mob/living/feeder) + SIGNAL_HANDLER + + if(HAS_TRAIT(drinker, TRAIT_STRONG_STOMACH)) + return + + if(!is_weak) + var/bodypart_type + if(feeder.l_hand == source) + bodypart_type = BP_R_ARM + else if(feeder.r_hand == source) + bodypart_type = BP_L_ARM + else + bodypart_type = BP_TORSO + try_infect(feeder, bodypart_type) + + for(var/datum/disease/disease as anything in diseases) + if(is_weak && !prob(weak_infection_chance)) + continue +// if(!disease.has_required_infectious_organ(drinker, ORGAN_SLOT_STOMACH)) +// continue + + drinker.ForceContractDisease(disease) /datum/component/infective/proc/clean(datum/source, clean_types) SIGNAL_HANDLER + . = NONE if(clean_types & required_clean_types) qdel(src) - return TRUE + return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP + +/datum/component/infective/proc/try_infect_buckle(datum/source, mob/M, force) + SIGNAL_HANDLER + + if(isliving(M)) + try_infect(M) + +/datum/component/infective/proc/try_infect_collide(datum/source, atom/A) + SIGNAL_HANDLER + + var/atom/movable/P = parent + if(P.throwing) + //this will be handled by try_infect_impact_zone() + return + if(isliving(A)) + try_infect(A) + +/datum/component/infective/proc/try_infect_impact_zone(datum/source, mob/living/target, hit_zone) + SIGNAL_HANDLER + + try_infect(target, hit_zone) + +/datum/component/infective/proc/try_infect_attack_zone(obj/item/source, mob/living/carbon/target, mob/living/user, hit_zone) + SIGNAL_HANDLER + + try_infect(target, hit_zone) + +/datum/component/infective/proc/try_infect_attack(obj/item/source, mob/living/target, mob/living/user) + SIGNAL_HANDLER + if(source.loc == user) + var/obj/item/organ/external/hand = user.get_active_hand() + if(!istype(hand)) //Some fuckery is going on here. + return + + if(hand.body_part == HAND_LEFT) + try_infect(user, BP_L_HAND) + else + try_infect(user, BP_R_HAND) + +/datum/component/infective/proc/try_infect_equipped(datum/source, mob/living/L, slot) + SIGNAL_HANDLER + + var/old_bio_armor + if(isitem(parent)) + //if you are putting an infective item on, it obviously will not protect you, so set its bio armor low enough that it will never block ContactContractDisease() + var/obj/item/equipped_item = parent + old_bio_armor = equipped_item.armor["bio"] + equipped_item.armor["bio"] = 0 + + try_infect(L, slot2body_zone(slot)) + + if(isitem(parent)) + var/obj/item/equipped_item = parent + equipped_item.armor["bio"] = old_bio_armor /datum/component/infective/proc/try_infect_crossed(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER @@ -45,35 +205,18 @@ if(isliving(arrived)) try_infect(arrived, BP_L_FOOT) -/* -/datum/component/proc/try_infect_eat(datum/source, mob/living/eater, mob/living/feeder) +/datum/component/infective/proc/try_infect_streak(datum/source, list/directions, list/output_diseases) SIGNAL_HANDLER - for(var/datum/disease/D in diseases) - eater.ForceContractDisease(D) - try_infect(feeder, BP_L_ARM) -*/ - -/datum/component/infective/proc/try_infect_collide(datum/source, atom/A) - SIGNAL_HANDLER - - var/atom/movable/P = parent - if(P.throwing) - // This will be handled by COMSIG_MOVABLE_IMPACT_ZONE, whenever we get that. + // This blood is not infectable / does not have a diseases list + if(!islist(output_diseases)) return - if(isliving(A)) - try_infect(A) -/datum/component/infective/proc/try_infect_attack(datum/source, mob/living/target, mob/living/user) - SIGNAL_HANDLER - - if(!iscarbon(target)) - try_infect(target) - try_infect(user, BP_L_ARM) + output_diseases |= diseases /datum/component/infective/proc/try_infect(mob/living/L, target_zone) - for(var/datum/disease/D in diseases) - L.ContractDisease(D) + for(var/V in diseases) + L.ContractDisease(V, target_zone) /datum/component/infective/proc/extrapolation(datum/source, mob/user, obj/item/extrapolator/extrapolator, dry_run = FALSE, list/result) SIGNAL_HANDLER diff --git a/code/modules/food/compile_recipies.dm b/code/modules/food/compile_recipes.dm similarity index 100% rename from code/modules/food/compile_recipies.dm rename to code/modules/food/compile_recipes.dm diff --git a/code/modules/food/kitchen/cooking_machines/fryer.dm b/code/modules/food/kitchen/cooking_machines/fryer.dm index 0ff19a40a4..9be58af6a6 100644 --- a/code/modules/food/kitchen/cooking_machines/fryer.dm +++ b/code/modules/food/kitchen/cooking_machines/fryer.dm @@ -168,6 +168,7 @@ I.reagents.remove_reagent(R.id, R.volume) else total_our_oil += R.volume + SEND_SIGNAL(I, COMSIG_ITEM_FRIED) if (total_removed > 0 || total_oil != CI.max_oil) diff --git a/code/modules/food/kitchen/cooking_machines/grill.dm b/code/modules/food/kitchen/cooking_machines/grill.dm index 62a9717456..ce150c7f39 100644 --- a/code/modules/food/kitchen/cooking_machines/grill.dm +++ b/code/modules/food/kitchen/cooking_machines/grill.dm @@ -49,3 +49,8 @@ icon_state = off_icon if(grill_loop) grill_loop.stop(src) + +/obj/machinery/appliance/cooker/grill/finish_cooking(var/datum/cooking_item/CI) + ..() + for(var/obj/item/I in CI.container) + SEND_SIGNAL(I, COMSIG_ITEM_BARBEQUE_GRILLED) diff --git a/code/modules/mob/living/carbon/human/species/station/traits/positive.dm b/code/modules/mob/living/carbon/human/species/station/traits/positive.dm index 1d17dd83d0..9331901883 100644 --- a/code/modules/mob/living/carbon/human/species/station/traits/positive.dm +++ b/code/modules/mob/living/carbon/human/species/station/traits/positive.dm @@ -847,13 +847,14 @@ /datum/trait/positive/toxin_gut name ="Robust Gut" - desc = "You are immune to most ingested toxins. Does not protect from possible harm caused by other drugs, meds, allergens etc." + desc = "You are immune to most ingested toxins and raw food. Does not protect from possible harm caused by other drugs, meds, allergens etc." cost = 1 custom_only = FALSE /datum/trait/positive/toxin_gut/apply(var/datum/species/S,var/mob/living/carbon/human/H) ..() ADD_TRAIT(H, INGESTED_TOXIN_IMMUNE, ROUNDSTART_TRAIT) + ADD_TRAIT(H, TRAIT_STRONG_STOMACH, ROUNDSTART_TRAIT) /datum/trait/positive/nobreathe name = "Breathless" diff --git a/code/modules/mob/living/carbon/human/species/station/traits/weaver_recipies.dm b/code/modules/mob/living/carbon/human/species/station/traits/weaver_recipes.dm similarity index 100% rename from code/modules/mob/living/carbon/human/species/station/traits/weaver_recipies.dm rename to code/modules/mob/living/carbon/human/species/station/traits/weaver_recipes.dm diff --git a/vorestation.dme b/vorestation.dme index d5d8088ce7..8838607a3b 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -771,6 +771,7 @@ #include "code\datums\components\disabilities\pollen.dm" #include "code\datums\components\disabilities\rotting.dm" #include "code\datums\components\disabilities\tourettes.dm" +#include "code\datums\components\food\germ_sensitive.dm" #include "code\datums\components\machinery\disposal_connection.dm" #include "code\datums\components\materials\machine_shim.dm" #include "code\datums\components\materials\material_container.dm" @@ -2893,7 +2894,7 @@ #include "code\modules\flufftext\hallucination_events.dm" #include "code\modules\flufftext\look_up.dm" #include "code\modules\flufftext\TextFilters.dm" -#include "code\modules\food\compile_recipies.dm" +#include "code\modules\food\compile_recipes.dm" #include "code\modules\food\food.dm" #include "code\modules\food\recipe.dm" #include "code\modules\food\recipe_dump.dm" @@ -3559,7 +3560,7 @@ #include "code\modules\mob\living\carbon\human\species\station\traits\trait.dm" #include "code\modules\mob\living\carbon\human\species\station\traits\traits_tutorial.dm" #include "code\modules\mob\living\carbon\human\species\station\traits\weaver_objs.dm" -#include "code\modules\mob\living\carbon\human\species\station\traits\weaver_recipies.dm" +#include "code\modules\mob\living\carbon\human\species\station\traits\weaver_recipes.dm" #include "code\modules\mob\living\carbon\human\species\virtual_reality\avatar.dm" #include "code\modules\mob\living\carbon\human\species\virtual_reality\opaque_form.dm" #include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_powers.dm"