diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index cc14178268e..942a3a60034 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -52156,7 +52156,7 @@ }, /obj/structure/window/spawner/directional/east, /obj/structure/window/spawner/directional/north, -/mob/living/simple_animal/chick{ +/mob/living/basic/chick/permanent{ name = "Morgan" }, /turf/open/floor/grass, diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm index 98750ef5e7b..9e625a5f3b7 100644 --- a/code/__DEFINES/dcs/signals/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -7,6 +7,7 @@ #define COMSIG_COMPONENT_ADDED "component_added" /// before a component is removed from a datum because of ClearFromParent: (/datum/component) #define COMSIG_COMPONENT_REMOVING "component_removing" + /// before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation /// you should only be using this if you want to block deletion /// that's the only functional difference between it and COMSIG_PARENT_QDELETING, outside setting QDELETING to detect diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index 618caf1ccf2..d9adb3c8bff 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -57,8 +57,8 @@ GLOBAL_LIST_INIT(phobia_mobs, list( )), "anime" = typecacheof(list(/mob/living/simple_animal/hostile/guardian)), "birds" = typecacheof(list( + /mob/living/basic/chick, /mob/living/basic/chicken, - /mob/living/simple_animal/chick, /mob/living/simple_animal/parrot, /mob/living/simple_animal/pet/penguin, )), diff --git a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm index 05b09c53fb9..9c60f2f4164 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm @@ -96,6 +96,12 @@ emote_hear = list("clucks.", "croons.") emote_see = list("pecks at the ground.","flaps her wings viciously.") +/datum/ai_planning_subtree/random_speech/chick + speech_chance = 4 + speak = list("Cherp.", "Cherp?", "Chirrup.", "Cheep!") + emote_hear = list("cheeps.") + emote_see = list("pecks at the ground.","flaps her tiny wings.") + /datum/ai_planning_subtree/random_speech/cow speech_chance = 1 speak = list("moo?","moo","MOOOOOO") diff --git a/code/datums/components/growth_and_differentiation.dm b/code/datums/components/growth_and_differentiation.dm index 8dd659bad81..e326c4f4a77 100644 --- a/code/datums/components/growth_and_differentiation.dm +++ b/code/datums/components/growth_and_differentiation.dm @@ -2,10 +2,7 @@ * ### Growth and Differentiation Component: Used to randomly "grow" a creature into a new entity over its lifespan. * * If we are passed a typepath, we will 100% grow into that type. However, if we are not passed a typepath, we will pick one from a subtype of the parent we were applied to! - * - * Used for spiderlings to turn them into giant spiders. */ - /datum/component/growth_and_differentiation /// What this mob turns into when fully grown. var/growth_path @@ -18,6 +15,8 @@ var/lower_growth_value /// Integer - The upper bound for the percentage we have to grow before we can differentiate. var/upper_growth_value + /// List of signals we kill on ourselves when we grow. + var/list/signals_to_kill_on /// Optional callback for checks to see if we're okay to grow. var/datum/callback/optional_checks /// Optional callback in case we wish to override the default grow() behavior. Assume we supersede the change_mob_type() call if we have this set. @@ -32,7 +31,16 @@ /// and will actively try to grow the mob (only barred by optional checks). var/ready_to_grow = FALSE -/datum/component/growth_and_differentiation/Initialize(growth_time, growth_path, growth_probability, lower_growth_value, upper_growth_value, optional_checks, optional_grow_behavior) +/datum/component/growth_and_differentiation/Initialize( + growth_time, + growth_path, + growth_probability, + lower_growth_value, + upper_growth_value, + list/signals_to_kill_on, + datum/callback/optional_checks, + datum/callback/optional_grow_behavior, +) if(!isliving(parent)) return COMPONENT_INCOMPATIBLE @@ -44,6 +52,10 @@ src.optional_checks = optional_checks src.optional_grow_behavior = optional_grow_behavior + if(islist(signals_to_kill_on)) + src.signals_to_kill_on = signals_to_kill_on + RegisterSignals(parent, src.signals_to_kill_on, PROC_REF(stop_component_processing_entirely)) + // If we haven't started the round, we can't do timer stuff. Let's wait in case we're mapped in or something. if(!SSticker.HasRoundStarted() && !isnull(growth_time)) RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, PROC_REF(comp_on_round_start)) @@ -52,11 +64,14 @@ return setup_growth_tracking() /datum/component/growth_and_differentiation/Destroy(force, silent) - . = ..() + STOP_PROCESSING(SSdcs, src) deltimer(timer_id) + return ..() -/datum/component/growth_and_differentiation/UnregisterFromParent() - UnregisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING) +/// Wrapper for qdel() so we can pass it in RegisterSignals(). I hate it here too. +/datum/component/growth_and_differentiation/proc/stop_component_processing_entirely() + SIGNAL_HANDLER + qdel(src) /// What we invoke when the round starts so we can set up our timer. /datum/component/growth_and_differentiation/proc/comp_on_round_start() @@ -64,7 +79,7 @@ setup_growth_tracking() UnregisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING) -/// Sets up the failover timer for certain growth. +/// Sets up the two different systems for growth: the timer and the probability based one. Both can coexist. Return COMPONENT_INCOMPATIBLE if we fail to set up either. /datum/component/growth_and_differentiation/proc/setup_growth_tracking() var/did_we_add_at_least_one_thing = FALSE @@ -113,10 +128,11 @@ optional_grow_behavior.Invoke() return - var/mob/living/new_mob = growth_path - if(!istype(new_mob)) + if(!ispath(growth_path, /mob/living)) CRASH("Growth and Differentiation Component: Growth path was not a mob type! If you wanted to do something special, please put it in the optional_grow_behavior callback instead!") + var/mob/living/new_mob = growth_path + var/new_mob_name = initial(new_mob.name) if(!silent) diff --git a/code/datums/memory/_memory.dm b/code/datums/memory/_memory.dm index c0bf77fafd5..e9dfa19d469 100644 --- a/code/datums/memory/_memory.dm +++ b/code/datums/memory/_memory.dm @@ -249,6 +249,7 @@ /mob/living/basic/carp, /mob/living/basic/carp/magic, /mob/living/basic/carp/magic/chaos, + /mob/living/basic/chick, /mob/living/basic/chicken, /mob/living/basic/cow, /mob/living/basic/cow/wisdom, @@ -263,7 +264,6 @@ /mob/living/basic/statue, /mob/living/basic/stickman, /mob/living/basic/stickman/dog, - /mob/living/simple_animal/chick, /mob/living/simple_animal/crab, /mob/living/simple_animal/hostile/asteroid/basilisk/watcher, /mob/living/simple_animal/hostile/asteroid/goliath/beast, diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index 174f893a9f7..a93ba6e3cd1 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -67,14 +67,14 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) var/chance = rand(0, 255) switch(chance) if(0 to 30) - new /mob/living/simple_animal/chick(hit_turf) + new /mob/living/basic/chick(hit_turf) GLOB.chicks_from_eggs++ visible_message(span_notice("A chick comes out of the cracked egg!")) if(31) var/spawned_chickens = min(4, MAX_CHICKENS - GLOB.chicks_from_eggs) // We don't want to go over the limit visible_message(span_notice("[spawned_chickens] chicks come out of the egg! Jackpot!")) for(var/i in 1 to spawned_chickens) - new /mob/living/simple_animal/chick(hit_turf) + new /mob/living/basic/chick(hit_turf) GLOB.chicks_from_eggs++ reagents.expose(hit_atom, TOUCH) @@ -171,7 +171,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) . = ..() AddComponent(/datum/component/fertile_egg,\ - embryo_type = /mob/living/simple_animal/chick,\ + embryo_type = /mob/living/basic/chick,\ minimum_growth_rate = 1,\ maximum_growth_rate = 2,\ total_growth_required = 200,\ diff --git a/code/modules/cargo/packs/livestock.dm b/code/modules/cargo/packs/livestock.dm index 333ead4bc1a..bd58abd984f 100644 --- a/code/modules/cargo/packs/livestock.dm +++ b/code/modules/cargo/packs/livestock.dm @@ -52,7 +52,7 @@ desc = "The chicken goes bwaak!" cost = CARGO_CRATE_VALUE * 4 access_view = ACCESS_KITCHEN - contains = list( /mob/living/simple_animal/chick) + contains = list(/mob/living/basic/chick) crate_name = "chicken crate" /datum/supply_pack/critter/corgi diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm index 5b2de971ce1..f97a7f2a139 100644 --- a/code/modules/holodeck/holo_effect.dm +++ b/code/modules/holodeck/holo_effect.dm @@ -83,8 +83,8 @@ . = ..() mobtype = list( /mob/living/basic/butterfly, + /mob/living/basic/chick/permanent, /mob/living/basic/rabbit, - /mob/living/simple_animal/chick/holo, /mob/living/simple_animal/pet/fox, ) mobtype += pick( diff --git a/code/modules/mob/living/basic/farm_animals/chicken/chick.dm b/code/modules/mob/living/basic/farm_animals/chicken/chick.dm new file mode 100644 index 00000000000..339b2c5e7f5 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/chicken/chick.dm @@ -0,0 +1,64 @@ +/** + * ## Chicks + * + * Baby birds that grow into big chickens. + */ +/mob/living/basic/chick + name = "\improper chick" + desc = "Adorable! They make such a racket though." + icon_state = "chick" + icon_living = "chick" + icon_dead = "chick_dead" + icon_gib = "chick_gib" + gender = FEMALE + mob_biotypes = MOB_ORGANIC|MOB_BEAST + speak_emote = list("cheeps") + density = FALSE + butcher_results = list(/obj/item/food/meat/slab/chicken = 1) + response_help_continuous = "pets" + response_help_simple = "pet" + response_disarm_continuous = "gently pushes aside" + response_disarm_simple = "gently push aside" + response_harm_continuous = "kicks" + response_harm_simple = "kick" + attack_verb_continuous = "kicks" + attack_verb_simple = "kick" + health = 3 + maxHealth = 3 + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + mob_size = MOB_SIZE_TINY + gold_core_spawnable = FRIENDLY_SPAWN + + /// What we grow into. + var/grow_as = /mob/living/basic/chicken + +/mob/living/basic/chick/Initialize(mapload) + . = ..() + pixel_x = base_pixel_x + rand(-6, 6) + pixel_y = base_pixel_y + rand(0, 10) + + ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + + AddElement(/datum/element/pet_bonus, "chirps!") + AddElement(/datum/element/swabable, CELL_LINE_TABLE_CHICKEN, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) + AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) + + if(!isnull(grow_as)) // we don't have a set time to grow up beyond whatever RNG dictates, and if we somehow get a client, all growth halts. + AddComponent(\ + /datum/component/growth_and_differentiation,\ + growth_time = null,\ + growth_path = grow_as,\ + growth_probability = 100,\ + lower_growth_value = 0.5,\ + upper_growth_value = 1,\ + signals_to_kill_on = list(COMSIG_MOB_CLIENT_LOGIN),\ + optional_checks = CALLBACK(src, PROC_REF(ready_to_grow)),\ + ) + +/// We don't grow into a chicken if we're not conscious. +/mob/living/basic/chick/proc/ready_to_grow() + return (stat == CONSCIOUS) + +/// Variant of chick that just spawns in the holodeck so you can pet it. Doesn't grow up. +/mob/living/basic/chick/permanent + grow_as = null diff --git a/code/modules/mob/living/basic/farm_animals/chicken.dm b/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm similarity index 98% rename from code/modules/mob/living/basic/farm_animals/chicken.dm rename to code/modules/mob/living/basic/farm_animals/chicken/chicken.dm index 6d39d483c0a..b3eb18e0cd4 100644 --- a/code/modules/mob/living/basic/farm_animals/chicken.dm +++ b/code/modules/mob/living/basic/farm_animals/chicken/chicken.dm @@ -6,8 +6,6 @@ GLOBAL_VAR_INIT(chicken_count, 0) * * Not-entirely-flightless domesticated birds that lay eggs, which are then consumed by humans and other animals. */ - - /mob/living/basic/chicken name = "\improper chicken" desc = "Hopefully the eggs are good this season." @@ -69,7 +67,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) if(GLOB.chicken_count <= MAX_CHICKENS && fertile && prob(25)) egg.AddComponent(\ /datum/component/fertile_egg,\ - embryo_type = /mob/living/simple_animal/chick,\ + embryo_type = /mob/living/basic/chick,\ minimum_growth_rate = 1,\ maximum_growth_rate = 2,\ total_growth_required = 200,\ @@ -94,3 +92,4 @@ GLOBAL_VAR_INIT(chicken_count, 0) /datum/ai_planning_subtree/basic_melee_attack_subtree, /datum/ai_planning_subtree/random_speech/chicken, ) + diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4db1bc36496..f9c7ab40abd 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1380,6 +1380,7 @@ /mob/living/basic/carp, /mob/living/basic/carp/magic, /mob/living/basic/carp/magic/chaos, + /mob/living/basic/chick, /mob/living/basic/chicken, /mob/living/basic/cow, /mob/living/basic/giant_spider, @@ -1393,7 +1394,6 @@ /mob/living/basic/statue, /mob/living/basic/stickman, /mob/living/basic/stickman/dog, - /mob/living/simple_animal/chick, /mob/living/simple_animal/crab, /mob/living/simple_animal/hostile/asteroid/basilisk/watcher, /mob/living/simple_animal/hostile/asteroid/goliath/beast, diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm index a1556d2f684..04d7ac56023 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -118,63 +118,3 @@ plant_target.visible_message(span_warning("[src] takes a big chomp out of [plant_target]!"), \ span_userdanger("[src] takes a big chomp out of your [edible_bodypart || "body"]!")) - - -/mob/living/simple_animal/chick - name = "\improper chick" - desc = "Adorable! They make such a racket though." - icon_state = "chick" - icon_living = "chick" - icon_dead = "chick_dead" - icon_gib = "chick_gib" - gender = FEMALE - mob_biotypes = MOB_ORGANIC|MOB_BEAST - speak = list("Cherp.","Cherp?","Chirrup.","Cheep!") - speak_emote = list("cheeps") - emote_hear = list("cheeps.") - emote_see = list("pecks at the ground.","flaps her tiny wings.") - density = FALSE - speak_chance = 2 - turns_per_move = 2 - butcher_results = list(/obj/item/food/meat/slab/chicken = 1) - response_help_continuous = "pets" - response_help_simple = "pet" - response_disarm_continuous = "gently pushes aside" - response_disarm_simple = "gently push aside" - response_harm_continuous = "kicks" - response_harm_simple = "kick" - attack_verb_continuous = "kicks" - attack_verb_simple = "kick" - health = 3 - maxHealth = 3 - var/amount_grown = 0 - pass_flags = PASSTABLE | PASSGRILLE | PASSMOB - mob_size = MOB_SIZE_TINY - gold_core_spawnable = FRIENDLY_SPAWN - - footstep_type = FOOTSTEP_MOB_CLAW - -/mob/living/simple_animal/chick/Initialize(mapload) - . = ..() - AddElement(/datum/element/pet_bonus, "chirps!") - pixel_x = base_pixel_x + rand(-6, 6) - pixel_y = base_pixel_y + rand(0, 10) - add_cell_sample() - ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) - -/mob/living/simple_animal/chick/add_cell_sample() - AddElement(/datum/element/swabable, CELL_LINE_TABLE_CHICKEN, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - -/mob/living/simple_animal/chick/Life(seconds_per_tick = SSMOBS_DT, times_fired) - . =..() - if(!.) - return - if(!stat && !ckey) - amount_grown += rand(0.5 * seconds_per_tick, 1 * seconds_per_tick) - if(amount_grown >= 100) - new /mob/living/basic/chicken(src.loc) - qdel(src) - -/mob/living/simple_animal/chick/holo/Life(seconds_per_tick = SSMOBS_DT, times_fired) - ..() - amount_grown = 0 diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 1d6823dc1ba..00a07a29850 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -32,8 +32,6 @@ /mob/living/simple_animal/bot/secbot/honkbot, /mob/living/simple_animal/bot/secbot/pingsky, /mob/living/simple_animal/bot/vibebot, - /mob/living/simple_animal/chick, - /mob/living/simple_animal/chick/holo, /mob/living/simple_animal/crab, /mob/living/simple_animal/crab/coffee, /mob/living/simple_animal/crab/evil, diff --git a/tgstation.dme b/tgstation.dme index 6622a0b9b10..19256d0c56f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3942,11 +3942,12 @@ #include "code\modules\mob\living\basic\festivus_pole.dm" #include "code\modules\mob\living\basic\health_adjustment.dm" #include "code\modules\mob\living\basic\tree.dm" -#include "code\modules\mob\living\basic\farm_animals\chicken.dm" #include "code\modules\mob\living\basic\farm_animals\deer.dm" #include "code\modules\mob\living\basic\farm_animals\pig.dm" #include "code\modules\mob\living\basic\farm_animals\rabbit.dm" #include "code\modules\mob\living\basic\farm_animals\sheep.dm" +#include "code\modules\mob\living\basic\farm_animals\chicken\chick.dm" +#include "code\modules\mob\living\basic\farm_animals\chicken\chicken.dm" #include "code\modules\mob\living\basic\farm_animals\cow\_cow.dm" #include "code\modules\mob\living\basic\farm_animals\cow\cow_ai.dm" #include "code\modules\mob\living\basic\farm_animals\cow\cow_moonicorn.dm" diff --git a/tools/UpdatePaths/Scripts/75592_simple_to_basic_chickens.txt b/tools/UpdatePaths/Scripts/75592_simple_to_basic_chickens.txt index 1b2f6ee1d19..c2eaf98dc58 100644 --- a/tools/UpdatePaths/Scripts/75592_simple_to_basic_chickens.txt +++ b/tools/UpdatePaths/Scripts/75592_simple_to_basic_chickens.txt @@ -1 +1,5 @@ /mob/living/simple_animal/chicken : /mob/living/basic/chicken{@OLD} + +## Updated in #75663 +/mob/living/simple_animal/chick : /mob/living/basic/chick{@OLD} +/mob/living/simple_animal/chick/holo : /mob/living/basic/chick/permanent{@OLD}