diff --git a/_maps/map_files/Basketball/greytide_worldwide.dmm b/_maps/map_files/Basketball/greytide_worldwide.dmm index 77c5f30af4c..6711c66743d 100644 --- a/_maps/map_files/Basketball/greytide_worldwide.dmm +++ b/_maps/map_files/Basketball/greytide_worldwide.dmm @@ -704,7 +704,7 @@ /obj/effect/turf_decal/box/red/corners{ dir = 1 }, -/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/mob/living/basic/goose/vomit, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/centcom/basketball) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index c1e1b7aaf48..e11938e405d 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -36288,7 +36288,7 @@ dir = 8 }, /obj/effect/turf_decal/tile/neutral/fourcorners, -/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/mob/living/basic/goose/vomit, /turf/open/floor/iron/dark, /area/station/service/abandoned_gambling_den) "jap" = ( diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index ecda43c7556..07594b2b8d4 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -38588,7 +38588,7 @@ /area/mine/laborcamp) "kYF" = ( /obj/structure/light_construct/directional/west, -/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/mob/living/basic/goose/vomit, /turf/open/floor/wood, /area/station/maintenance/port/aft) "kYI" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index c69694b8f48..4a78966445f 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -14361,7 +14361,7 @@ /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) "fgn" = ( -/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/mob/living/basic/goose/vomit, /turf/open/floor/wood, /area/station/maintenance/port/aft) "fgu" = ( diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 64cad41bbeb..feae642f8b1 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -39018,7 +39018,7 @@ "nMj" = ( /obj/effect/turf_decal/sand/plating, /obj/effect/mapping_helpers/broken_floor, -/mob/living/simple_animal/hostile/retaliate/goose/vomit, +/mob/living/basic/goose/vomit, /turf/open/floor/plating, /area/station/maintenance/central/greater) "nMk" = ( diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index f7f77a7169e..161f9973b36 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -49,6 +49,11 @@ #define BB_BANE_BATMAN "BB_bane_batman" //yep that's it +/// Are we a panicking goose? +#define BB_GOOSE_PANICKED "BB_goose_panicked" +/// Are we a panicking goose? +#define BB_GOOSE_VOMIT_CHANCE "BB_goose_vomit_chance" + //Hunting BB keys ///key that holds our current hunting target #define BB_CURRENT_HUNTING_TARGET "BB_current_hunting_target" @@ -140,6 +145,9 @@ /// Blackboard key for a held item #define BB_SIMPLE_CARRY_ITEM "BB_SIMPLE_CARRY_ITEM" +///key holding a range to look for stuff in +#define BB_SEARCH_RANGE "BB_search_range" + ///Mob the MOD is trying to attach to #define BB_MOD_TARGET "BB_mod_target" ///The implant the AI was created from diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 6024f799138..73c75fec3ba 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -30,7 +30,6 @@ GLOBAL_LIST_INIT(abstract_mob_types, list( /mob/living/simple_animal/hostile/asteroid, /mob/living/simple_animal/hostile/megafauna, /mob/living/basic/mimic, // Cannot exist if spawned without being passed an item reference - /mob/living/simple_animal/hostile/retaliate, /mob/living/simple_animal/hostile, /mob/living/simple_animal/soulscythe, // As mimic, can't exist if spawned outside an item /mob/living/simple_animal, diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm index c482722fbf9..699e9b4de01 100644 --- a/code/_globalvars/phobias.dm +++ b/code/_globalvars/phobias.dm @@ -69,10 +69,10 @@ GLOBAL_LIST_INIT(phobia_mobs, list( "birds" = typecacheof(list( /mob/living/basic/chick, /mob/living/basic/chicken, + /mob/living/basic/goose, /mob/living/basic/parrot, /mob/living/basic/pet/penguin, /mob/living/basic/raptor, - /mob/living/simple_animal/hostile/retaliate/goose, )), "conspiracies" = typecacheof(list( /mob/living/basic/drone, diff --git a/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm b/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm index feca9869093..9b3e2883290 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/find_food.dm @@ -8,6 +8,8 @@ var/found_food_key = BB_TARGET_FOOD ///key holding any emotes we play after eating food var/emotes_blackboard_list = BB_EAT_EMOTES + ///key where we store our search range + var/search_range = BB_SEARCH_RANGE /datum/ai_planning_subtree/find_food/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) var/list/foods_list = controller.blackboard[food_list_key] @@ -15,9 +17,11 @@ CRASH("the types of food has not been supplied in the [food_list_key] key!") if(controller.blackboard[BB_NEXT_FOOD_EAT] > world.time) return + if(!controller.blackboard_key_exists(found_food_key)) - controller.queue_behavior(finding_behavior, found_food_key, foods_list) + controller.queue_behavior(finding_behavior, found_food_key, foods_list, controller.blackboard[BB_SEARCH_RANGE]) return + controller.queue_behavior(/datum/ai_behavior/interact_with_target/eat_food, found_food_key, emotes_blackboard_list) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/ai/generic/find_and_set.dm b/code/datums/ai/generic/find_and_set.dm index c7534510b6a..dd25a730629 100644 --- a/code/datums/ai/generic/find_and_set.dm +++ b/code/datums/ai/generic/find_and_set.dm @@ -17,7 +17,7 @@ controller.set_blackboard_key(set_key, find_this_thing) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED -/datum/ai_behavior/find_and_set/proc/search_tactic(datum/ai_controller/controller, locate_path, search_range) +/datum/ai_behavior/find_and_set/proc/search_tactic(datum/ai_controller/controller, locate_path, search_range = 3) return locate(locate_path) in oview(search_range, controller.pawn) /** diff --git a/code/datums/elements/basic_eating.dm b/code/datums/elements/basic_eating.dm index 1e148b30b15..0e292054677 100644 --- a/code/datums/elements/basic_eating.dm +++ b/code/datums/elements/basic_eating.dm @@ -14,10 +14,12 @@ var/damage_type /// Whether to flavor it as drinking rather than eating. var/drinking + /// If true, we put food in our tummy instead of deleting it + var/add_to_contents /// Types the animal can eat. var/list/food_types -/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, food_types = list()) +/datum/element/basic_eating/Attach(datum/target, heal_amt = 0, damage_amount = 0, damage_type = null, drinking = FALSE, add_to_contents = FALSE, food_types = list()) . = ..() if(!isliving(target)) @@ -28,6 +30,7 @@ src.damage_amount = damage_amount src.damage_type = damage_type src.drinking = drinking + src.add_to_contents = add_to_contents src.food_types = food_types RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(try_feed)) @@ -65,6 +68,8 @@ return FALSE if(SEND_SIGNAL(eater, COMSIG_MOB_PRE_EAT, target, feeder) & COMSIG_MOB_CANCEL_EAT) return FALSE + if(add_to_contents && !ismovable(target)) + return FALSE var/eat_verb if(drinking) eat_verb = pick("slurp","sip","guzzle","drink","quaff","suck") @@ -98,5 +103,11 @@ if(isstack(target)) //if stack, only consume 1 var/obj/item/stack/food_stack = target final_target = food_stack.split_stack(eater, 1) - eater.log_message("has eaten [target]!", LOG_ATTACK) - qdel(final_target) + + eater.log_message("has eaten [target], [add_to_contents ? "swallowing it" : "destroying it"]!", LOG_ATTACK) + + if (add_to_contents) + var/atom/movable/movable_target = final_target + movable_target.forceMove(eater) + else + qdel(final_target) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index ab5d93f7064..cb0e0b24cca 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -657,7 +657,7 @@ GLOBAL_LIST_EMPTY(station_turfs) return TRUE /turf/proc/add_vomit_floor(mob/living/vomiter, vomit_type = /obj/effect/decal/cleanable/vomit, vomit_flags, purge_ratio = 0.1) - var/obj/effect/decal/cleanable/vomit/throw_up = new vomit_type (src, vomiter.get_static_viruses()) + var/obj/effect/decal/cleanable/vomit/throw_up = new vomit_type (src, vomiter?.get_static_viruses()) // if the vomit combined, apply toxicity and reagents to the old vomit if (QDELETED(throw_up)) diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index 77ef9785aba..ad2ab6adb62 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -391,6 +391,7 @@ /mob/living/basic/dark_wizard = 2, /mob/living/basic/flesh_spider = 2, /mob/living/basic/garden_gnome = 2, + /mob/living/basic/goose = 2, /mob/living/basic/killer_tomato = 2, /mob/living/basic/leaper = 1, /mob/living/basic/mega_arachnid = 1, @@ -404,7 +405,6 @@ /mob/living/basic/spider/giant/nurse/scrawny = 2, /mob/living/basic/spider/giant/tarantula/scrawny = 2, /mob/living/basic/spider/giant/hunter/scrawny = 2, - /mob/living/simple_animal/hostile/retaliate/goose = 2, /mob/living/simple_animal/hostile/ooze = 1, ) diff --git a/code/modules/events/ghost_role/sentience.dm b/code/modules/events/ghost_role/sentience.dm index b12dd5c5174..60b43216ab2 100644 --- a/code/modules/events/ghost_role/sentience.dm +++ b/code/modules/events/ghost_role/sentience.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( /mob/living/basic/crab, /mob/living/basic/cow, /mob/living/basic/goat, + /mob/living/basic/goose/vomit, /mob/living/basic/lizard, /mob/living/basic/mouse/brown/tom, /mob/living/basic/parrot, @@ -17,7 +18,6 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( /mob/living/basic/snake, /mob/living/basic/spider/giant/sgt_araneus, /mob/living/simple_animal/bot/secbot/beepsky, - /mob/living/simple_animal/hostile/retaliate/goose/vomit, /mob/living/basic/bear/snow/misha, /mob/living/basic/mining/lobstrosity/juvenile, ))) diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index c3abb3d2bd1..bd990e98c34 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -295,11 +295,11 @@ var/static/list/mob_list = list( /mob/living/basic/bear, /mob/living/basic/cockroach/glockroach/mobroach, + /mob/living/basic/goose, /mob/living/basic/lightgeist, /mob/living/basic/mothroach, /mob/living/basic/mushroom, /mob/living/basic/viscerator, - /mob/living/simple_animal/hostile/retaliate/goose, //Janitors HATE geese. /mob/living/basic/pet/gondola, ) return pick(mob_list) diff --git a/code/modules/events/wizard/petsplosion.dm b/code/modules/events/wizard/petsplosion.dm index 58d463ab9df..09ee4348f70 100644 --- a/code/modules/events/wizard/petsplosion.dm +++ b/code/modules/events/wizard/petsplosion.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(petsplosion_candidates, typecacheof(list( /mob/living/basic/chicken, /mob/living/basic/cow, /mob/living/basic/goat, + /mob/living/basic/goose/vomit, /mob/living/basic/lizard, /mob/living/basic/mothroach, /mob/living/basic/mouse/brown/tom, @@ -17,7 +18,6 @@ GLOBAL_LIST_INIT(petsplosion_candidates, typecacheof(list( /mob/living/basic/sloth, /mob/living/basic/snake, /mob/living/basic/spider/giant/sgt_araneus, - /mob/living/simple_animal/hostile/retaliate/goose/vomit, ))) /datum/round_event_control/wizard/petsplosion //the horror diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose.dm b/code/modules/mob/living/basic/farm_animals/goose/goose.dm new file mode 100644 index 00000000000..0a34400f161 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/goose/goose.dm @@ -0,0 +1,177 @@ +/// The most random things a goose can have inside of it +#define GOOSE_SATIATED 50 + +/// A mob that gets mad at people at random and tries to eat nearby objects +/mob/living/basic/goose + name = "goose" + desc = "It's loose." + icon_state = "goose" + icon_living = "goose" + icon_dead = "goose_dead" + mob_biotypes = MOB_ORGANIC|MOB_BEAST + faction = list(FACTION_NEUTRAL) + maxHealth = 25 + health = 25 + melee_damage_lower = 5 + melee_damage_upper = 5 + attack_verb_continuous = "pecks" + attack_verb_simple = "peck" + attack_sound = "goose" + attack_vis_effect = ATTACK_EFFECT_BITE + speak_emote = list("honks") + 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" + ai_controller = /datum/ai_controller/basic_controller/goose + butcher_results = list(/obj/item/food/meat/slab/grassfed = 2) + gold_core_spawnable = HOSTILE_SPAWN + /// Do we actually destroy food we eat? + var/conserve_food = FALSE + /// Unfortunately, geese want to eat every item + var/static/list/item_typecache = typecacheof(/obj/item) + +/mob/living/basic/goose/Initialize(mapload) + . = ..() + AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/content_barfer) + AddElement(/datum/element/basic_eating, add_to_contents = conserve_food, food_types = string_list(list(/obj/item))) + + RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(on_tried_gobbling)) + RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(on_gobbled)) + + ai_controller.set_blackboard_key(BB_BASIC_FOODS, item_typecache) + +/mob/living/basic/goose/death(gibbed) + if (!gibbed && length(contents)) + var/turf/drop_turf = drop_location() + if (istype(drop_turf)) + playsound(drop_turf, 'sound/effects/splat.ogg', 50, TRUE) + drop_turf.add_vomit_floor(src) + return ..() + +/// Called when we try to eat something +/mob/living/basic/goose/proc/on_tried_gobbling(datum/source, obj/item/potential_food) + SIGNAL_HANDLER + if (ai_controller?.blackboard[BB_GOOSE_PANICKED]) + return COMSIG_MOB_CANCEL_EAT + if (potential_food.has_material_type(/datum/material/plastic) || IsEdible(potential_food)) + return NONE// Geese only eat FOOD or PLASTIC + return COMSIG_MOB_CANCEL_EAT + +/// Called when we've eaten something +/mob/living/basic/goose/proc/on_gobbled(atom/source, obj/item/food, mob/feeder) + SIGNAL_HANDLER + if (!food.has_material_type(/datum/material/plastic)) + return NONE + + visible_message(span_boldwarning("[src] is choking on \the [food]!")) + food.forceMove(src) + choke(food) + + return COMSIG_MOB_TERMINATE_EAT + +/// Start choking on something we just ate +/mob/living/basic/goose/proc/choke(obj/item/not_food_after_all) + apply_status_effect(/datum/status_effect/goose_choking) + +/// A less grumpy but much grosser variant of the goose, who will decorate the halls in their own special way +/mob/living/basic/goose/vomit + name = "Birdboat" + real_name = "Birdboat" + desc = "It's a sick-looking goose, probably ate too much maintenance trash. Best not to move it around too much." + gender = MALE + faction = list(FACTION_NEUTRAL, FACTION_MAINT_CREATURES) + gold_core_spawnable = NO_SPAWN + ai_controller = /datum/ai_controller/basic_controller/goose/calm + conserve_food = TRUE + /// Cooldown to make sure we can't spam chat with notifications that we are full + COOLDOWN_DECLARE(eat_fail_feedback_cooldown) + /// An action we use to throw up + var/datum/action/cooldown/mob_cooldown/goose_vomit/vomit_action + +/mob/living/basic/goose/vomit/Initialize(mapload) + . = ..() + + vomit_action = new(src) + vomit_action.Grant(src) + RegisterSignal(src, COMSIG_MOB_ABILITY_STARTED, PROC_REF(on_started_vomiting)) + + // 5% chance every round to have anarchy mode deadchat control on birdboat. + if (!prob(5)) + return + desc = "[initial(desc)] It's waddling more than usual. It seems to be possessed." + deadchat_plays() + +/mob/living/basic/goose/vomit/Destroy() + . = ..() + QDEL_NULL(vomit_action) + +/mob/living/basic/goose/vomit/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + var/vomit_chance = ai_controller?.blackboard[BB_GOOSE_VOMIT_CHANCE] || 0 + if (prob(vomit_chance)) + vomit() + +/mob/living/basic/goose/vomit/examine(mob/user) + . = ..() + . += span_notice("Somehow, it still looks hungry.") + +/mob/living/basic/goose/vomit/on_gobbled(atom/source, obj/item/food, mob/feeder) + if (length(contents) > GOOSE_SATIATED) + if (COOLDOWN_FINISHED(src, eat_fail_feedback_cooldown)) + if (feeder) + visible_message(span_notice("[src] looks too full to eat \the [food]!")) + COOLDOWN_START(src, eat_fail_feedback_cooldown, 5 SECONDS) + return COMSIG_MOB_TERMINATE_EAT + + . = ..() + if (. == COMSIG_MOB_TERMINATE_EAT) + return NONE// It's plastic, if it's not plastic we already filtered it for edible + + // This also increases my vomit chance, but we atomised this field to the inside of a component and I need to read it + var/datum/component/edible/edible = food.GetComponent(/datum/component/edible) + if ((edible?.foodtypes & GROSS)) + ai_controller?.add_blackboard_key(BB_GOOSE_VOMIT_CHANCE, 3) + vomit_action?.extra_duration += 0.2 SECONDS + else + ai_controller?.add_blackboard_key(BB_GOOSE_VOMIT_CHANCE, 1) + +/mob/living/basic/goose/vomit/choke(obj/item/not_food_after_all) + if (prob(75)) + return ..() + visible_message(span_warning("[src] is gagging on \the [not_food_after_all]!")) + manual_emote("gags!") + addtimer(CALLBACK(src, PROC_REF(vomit)), 5 SECONDS) + +/// Start making a mess +/mob/living/basic/goose/vomit/proc/vomit() + vomit_action?.Trigger(target = src) + +/mob/living/basic/goose/vomit/proc/on_started_vomiting(mob/living/owner, datum/action/cooldown/activated) + SIGNAL_HANDLER + if (activated != vomit_action) + return + remove_status_effect(/datum/status_effect/goose_choking) // We're going to cough it out + +/mob/living/basic/goose/vomit/proc/stop_deadchat_plays() + var/initial_behaviour = initial(ai_controller?.idle_behavior) + ai_controller?.idle_behavior = SSidle_ai_behaviors.idle_behaviors[initial_behaviour] + +/mob/living/basic/goose/vomit/deadchat_plays(mode = ANARCHY_MODE, cooldown = 12 SECONDS) + var/list/goose_inputs = list( + "vomit" = CALLBACK(src, PROC_REF(vomit)), + "honk" = CALLBACK(src, TYPE_PROC_REF(/atom/movable, say), "HONK!!!"), + "spin" = CALLBACK(src, TYPE_PROC_REF(/mob, emote), "spin")) + + . = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, goose_inputs, cooldown, CALLBACK(src, PROC_REF(stop_deadchat_plays))) + + if (. == COMPONENT_INCOMPATIBLE) + return + + // Stop automated movement, retain the other behaviour so you can lead the horse to plastic and have it drink. + ai_controller?.idle_behavior = null + +#undef GOOSE_SATIATED diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm b/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm new file mode 100644 index 00000000000..cd10e45adc5 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/goose/goose_ai.dm @@ -0,0 +1,82 @@ +/// Geese like to eat random objects and kill themselves, and occasionally get pissed off for no reason +/datum/ai_controller/basic_controller/goose + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_SEARCH_RANGE = 1, + BB_EAT_FOOD_COOLDOWN = 10 SECONDS, + BB_EAT_EMOTES = list() + ) + + ai_traits = STOP_MOVING_WHEN_PULLED + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk/goose + + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/goose, + /datum/ai_planning_subtree/capricious_retaliate, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/find_food/goose, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/// Goose who doesn't randomly retaliate but does still try to die by eating random items +/datum/ai_controller/basic_controller/goose/calm + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_SEARCH_RANGE = 1, + BB_EAT_FOOD_COOLDOWN = 0.5 SECONDS, // Uh oh + BB_EAT_EMOTES = list() + ) + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/goose, + /datum/ai_planning_subtree/use_mob_ability/goose_vomit, + /datum/ai_planning_subtree/target_retaliate, + /datum/ai_planning_subtree/find_food/goose, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/// Walk more if we're choking or vomiting +/datum/idle_behavior/idle_random_walk/goose + +/datum/idle_behavior/idle_random_walk/goose/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller) + walk_chance = controller.blackboard[BB_GOOSE_PANICKED] ? 100 : 25 // I think this sets it for every goose but that's fine because it'll reset it before using it + return ..() + +/// Only look for things geese will try to eat +/datum/ai_planning_subtree/find_food/goose + finding_behavior = /datum/ai_behavior/find_and_set/in_list/goose_food + +/datum/ai_planning_subtree/find_food/goose/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if (controller.blackboard[BB_GOOSE_PANICKED]) + return // Don't look for food while choking or vomiting + return ..() + +/// Only set things geese will try to eat +/datum/ai_behavior/find_and_set/in_list/goose_food + +/datum/ai_behavior/find_and_set/in_list/goose_food/search_tactic(datum/ai_controller/controller, locate_paths, search_range) + var/list/found = typecache_filter_list(oview(search_range, controller.pawn), locate_paths) + if(!length(found)) + return + + var/list/filtered = list() + for (var/obj/item/thing as anything in found) + if (IsEdible(thing) || thing.has_material_type(/datum/material/plastic)) + filtered += thing + + if(length(filtered)) + return pick(filtered) + +/// Use this ability only if we roll a dice correctly +/datum/ai_planning_subtree/use_mob_ability/goose_vomit + +/datum/ai_planning_subtree/use_mob_ability/goose_vomit/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/trigger_prob = controller.blackboard[BB_GOOSE_VOMIT_CHANCE] || 0 + if (prob(trigger_prob)) + return ..() + +/datum/ai_planning_subtree/random_speech/goose + speech_chance = 3 + emote_hear = list("honks.", "honks loudly.", "honks aggressively.") + emote_see = list("flaps.", "preens.", "glares around.") + speak = list("Honk!") diff --git a/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm b/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm new file mode 100644 index 00000000000..2b347903e22 --- /dev/null +++ b/code/modules/mob/living/basic/farm_animals/goose/goose_vomit.dm @@ -0,0 +1,187 @@ +/// Repeatedly throw up until there's nothing left inside, regrettably sufficiently complex that it requires its own file +/datum/action/cooldown/mob_cooldown/goose_vomit + name = "Vomit" + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED + button_icon_state = "vomit" + button_icon = 'icons/mob/simple/animal.dmi' + cooldown_time = INFINITY // We reset the cooldown when we are done throwing up + text_cooldown = FALSE + melee_cooldown_time = 0 + shared_cooldown = NONE + click_to_activate = FALSE + /// Extra time to spend chundering + var/extra_duration = 0 SECONDS + +/datum/action/cooldown/mob_cooldown/goose_vomit/Grant(mob/granted_to) + . = ..() + if(!owner) + return + RegisterSignals(owner, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED), PROC_REF(update_status_on_signal)) + +/datum/action/cooldown/mob_cooldown/goose_vomit/Remove(mob/removed_from) + UnregisterSignal(owner, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED)) + return ..() + +/datum/action/cooldown/mob_cooldown/goose_vomit/IsAvailable(feedback) + . = ..() + if (!.) + return FALSE + if (!length(owner.contents)) + if (feedback) + owner.balloon_alert(owner, "stomach empty!") + return FALSE + if (!isliving(owner)) + if (feedback) + owner.balloon_alert(owner, "you're not alive!") + return FALSE + return TRUE + +/datum/action/cooldown/mob_cooldown/goose_vomit/Activate(atom/target) + StartCooldown(INFINITY) + if (istype(owner, /mob/living/basic/goose)) + owner.icon_state = "vomit" + flick("vomit_start", owner) + owner.ai_controller?.set_blackboard_key(BB_GOOSE_VOMIT_CHANCE, 0) + addtimer(CALLBACK(src, PROC_REF(start_vomiting)), 13) // 13 frame long animation + else + start_vomiting() + +/// Start the performance +/datum/action/cooldown/mob_cooldown/goose_vomit/proc/start_vomiting() + var/mob/living/living_owner = owner + living_owner.apply_status_effect(/datum/status_effect/goose_vomit, extra_duration) + extra_duration = 0 + +/// Handles iteratively emptying our stomach +/datum/status_effect/goose_vomit + id = "goose_vomit" + alert_type = null + tick_interval = 1 SECONDS + /// How long do we vomit for? + var/vomit_duration = 2.5 SECONDS + /// How long have we spent vomiting? + var/elapsed_time = 0 SECONDS + /// Chance to step in a random direction + var/move_chance = 80 + /// Chance to produce an item per tick + var/vomit_item_chance = 50 + +/datum/status_effect/goose_vomit/on_creation(mob/living/new_owner, extra_duration = 0) + vomit_duration += extra_duration + return ..() + +/datum/status_effect/goose_vomit/on_apply() + owner.set_jitter_if_lower(vomit_duration) + owner.ai_controller?.set_blackboard_key(BB_GOOSE_PANICKED, TRUE) + RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(on_owner_died)) + RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(on_owner_moved)) + return TRUE + +/datum/status_effect/goose_vomit/on_remove() + UnregisterSignal(owner, list(COMSIG_LIVING_DEATH, COMSIG_MOVABLE_MOVED)) + owner.ai_controller?.set_blackboard_key(BB_GOOSE_PANICKED, FALSE) + if (istype(owner, /mob/living/basic/goose) && owner.stat != DEAD) + var/mob/living/basic/goose_mob = owner + flick("vomit_end", owner) + goose_mob.icon_state = goose_mob.icon_living + + var/datum/action/cooldown/mob_cooldown/goose_vomit/vomit_action = locate() in owner.actions + vomit_action?.StartCooldown(0 SECONDS) + +/// Don't keep vomiting from beyond the grave +/datum/status_effect/goose_vomit/proc/on_owner_died() + SIGNAL_HANDLER + qdel(src) + +/// For good measure we'll spit up every time we take a step too +/datum/status_effect/goose_vomit/proc/on_owner_moved() + SIGNAL_HANDLER + vomit_iteratively(can_move = FALSE) + +/datum/status_effect/goose_vomit/tick(seconds_between_ticks) + elapsed_time += seconds_between_ticks + + if (!length(owner.contents)) + qdel(src) + return + + if (elapsed_time <= vomit_duration) + vomit_iteratively() + else + vomit_finale() + +/// One to come up +/datum/status_effect/goose_vomit/proc/vomit_iteratively(can_move = TRUE) + if (prob(vomit_item_chance)) + hurl_item() + else + make_mess(owner.drop_location()) + + if (can_move && prob(move_chance)) + var/move_dir = pick(GLOB.alldirs) + var/turf/destination_turf = get_step(owner, move_dir) + owner.Move(destination_turf, move_dir) + +/// Stop fucking around and get the rest of it out +/datum/status_effect/goose_vomit/proc/vomit_finale() + tick_interval = 0.1 SECONDS + owner.set_jitter_if_lower(1 SECONDS) + hurl_item(vomit_strongly = TRUE) + +/// Produce an item from our inventory +/datum/status_effect/goose_vomit/proc/hurl_item(vomit_strongly = FALSE) + if (!length(owner.contents)) + return + var/obj/item/thing = pick_n_take(owner.contents) + if (!ismovable(thing) || HAS_TRAIT(thing, TRAIT_NOT_BARFABLE)) + qdel(src) // Someone is fucking around with this goose, let's not get stuck in this forever + return + var/drop_location = owner.drop_location() + + thing.forceMove(drop_location) + if (isopenturf(drop_location)) + make_mess(drop_location) + var/destination = get_edge_target_turf(drop_location, pick(GLOB.alldirs)) + var/throwRange = vomit_strongly ? rand(2, 8) : 1 + thing.safe_throw_at(destination, throwRange, 2) + +/// Make a mess +/datum/status_effect/goose_vomit/proc/make_mess(turf/open/drop_turf) + if (!istype(drop_turf)) + return + playsound(drop_turf, 'sound/effects/splat.ogg', 50, TRUE) + drop_turf.add_vomit_floor(owner) + + +/// Wheeze until we die +/datum/status_effect/goose_choking + id = "goose_choking" + alert_type = null + duration = 30 SECONDS + tick_interval = 2 SECONDS + /// Chance per second to emote + var/emote_prob = 18 + /// What things do we do while dying + var/static/list/emotes = list("chokes.", "coughs.", "gasps.", "tries urgently to breathe.", "shudders violently.", "wheezes.") + +/datum/status_effect/goose_choking/tick(seconds_between_ticks) + if (SPT_PROB(emote_prob, seconds_between_ticks)) + owner.manual_emote(pick(emotes)) + +/datum/status_effect/goose_choking/on_apply() + owner.set_jitter_if_lower(duration) + owner.ai_controller?.set_blackboard_key(BB_GOOSE_PANICKED, TRUE) + RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(on_owner_died)) + return TRUE + +/datum/status_effect/goose_choking/on_remove() + UnregisterSignal(owner, COMSIG_LIVING_DEATH) + if (duration >= world.time) + return // Saved by something, although probably by dying early + owner.death_message = "lets out one final oxygen-deprived honk before [owner.p_they()] go[owner.p_es()] limp and lifeless.." + owner.death() + +/// Don't keep dying if we died +/datum/status_effect/goose_choking/proc/on_owner_died() + SIGNAL_HANDLER + qdel(src) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index ce1c4e7cf19..9336af84f0e 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -47,12 +47,15 @@ else can_lay_eggs = FALSE + var/list/food_types = string_list(list(/obj/item/stack/ore)) var/static/list/innate_actions = list( /datum/action/cooldown/mob_cooldown/spit_ore = BB_SPIT_ABILITY, /datum/action/cooldown/mob_cooldown/burrow = BB_BURROW_ABILITY, ) grant_actions_by_list(innate_actions) + AddElement(/datum/element/ore_collecting) + AddElement(/datum/element/basic_eating, food_types = food_types, add_to_contents = TRUE) AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) AddComponent(/datum/component/ai_listen_to_weather) AddComponent(\ @@ -60,14 +63,15 @@ overlay_icon = 'icons/mob/simple/lavaland/lavaland_monsters_wide.dmi',\ overlay_state = "goldgrub_alert",\ ) + if(can_tame) - make_tameable() + make_tameable(food_types) if(can_lay_eggs) make_egg_layer() + ADD_TRAIT(src, TRAIT_BOULDER_BREAKER, INNATE_TRAIT) ADD_TRAIT(src, TRAIT_INSTANTLY_PROCESSES_BOULDERS, INNATE_TRAIT) RegisterSignal(src, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(block_bullets)) - RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(on_eat)) /mob/living/basic/mining/goldgrub/proc/block_bullets(datum/source, obj/projectile/hitting_projectile) SIGNAL_HANDLER @@ -105,8 +109,7 @@ barf_contents(gibbed) return ..() -/mob/living/basic/mining/goldgrub/proc/make_tameable() - var/list/food_types = string_list(list(/obj/item/stack/ore)) +/mob/living/basic/mining/goldgrub/proc/make_tameable(list/food_types) AddComponent(/datum/component/tameable, food_types = food_types, tame_chance = 25, bonus_tame_chance = 5) /mob/living/basic/mining/goldgrub/tamed(mob/living/tamer, atom/food) @@ -135,12 +138,6 @@ return new /obj/item/food/egg/green/grub_egg(get_turf(src)) -/mob/living/basic/mining/goldgrub/proc/on_eat(atom/source, atom/movable/food, mob/feeder) - SIGNAL_HANDLER - - food.forceMove(src) - return COMSIG_MOB_TERMINATE_EAT - /mob/living/basic/mining/goldgrub/baby icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi' name = "goldgrub baby" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm deleted file mode 100644 index b177cc651ec..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/goose.dm +++ /dev/null @@ -1,269 +0,0 @@ -#define GOOSE_SATIATED 50 -/mob/living/simple_animal/hostile/retaliate/goose - name = "goose" - desc = "It's loose" - icon_state = "goose" // sprites by cogwerks from goonstation, used with permission - icon_living = "goose" - icon_dead = "goose_dead" - mob_biotypes = MOB_ORGANIC|MOB_BEAST - speak_chance = 0 - turns_per_move = 5 - butcher_results = list(/obj/item/food/meat/slab/grassfed = 2) - 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" - emote_taunt = list("hisses") - taunt_chance = 30 - speed = 0 - maxHealth = 25 - health = 25 - harm_intent_damage = 5 - melee_damage_lower = 5 - melee_damage_upper = 5 - attack_verb_continuous = "pecks" - attack_verb_simple = "peck" - attack_sound = "goose" - attack_vis_effect = ATTACK_EFFECT_BITE - speak_emote = list("honks") - faction = list(FACTION_NEUTRAL) - attack_same = TRUE - gold_core_spawnable = HOSTILE_SPAWN - var/random_retaliate = TRUE - var/icon_vomit_start = "vomit_start" - var/icon_vomit = "vomit" - var/icon_vomit_end = "vomit_end" - var/message_cooldown = 0 - var/choking = FALSE - -/mob/living/simple_animal/hostile/retaliate/goose/Initialize(mapload) - . = ..() - RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(goosement)) - -/mob/living/simple_animal/hostile/retaliate/goose/proc/goosement(atom/movable/AM, OldLoc, Dir, Forced) - SIGNAL_HANDLER - if(stat == DEAD) - return - if(prob(5) && random_retaliate) - Retaliate() - -/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_action() - . = ..() - feed_random() - -/mob/living/simple_animal/hostile/retaliate/goose/proc/feed_random() - var/obj/item/eat_it_motherfucker = pick(locate(/obj/item) in loc) - if(!eat_it_motherfucker) - return - feed(eat_it_motherfucker) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/feed_random() - for(var/obj/item/eat_it_motherfucker in loc) - if(!eat_it_motherfucker.has_material_type(/datum/material/plastic)) - continue - feed(eat_it_motherfucker) - break - -/mob/living/simple_animal/hostile/retaliate/goose/proc/feed(obj/item/suffocator) - if(stat == DEAD || choking) // plapatin I swear to god - return FALSE - if(suffocator.has_material_type(/datum/material/plastic)) // dumb goose'll swallow food or drink with plastic in it - visible_message(span_danger("[src] hungrily gobbles up \the [suffocator]! ")) - visible_message(span_boldwarning("[src] is choking on \the [suffocator]! ")) - suffocator.forceMove(src) - choke(suffocator) - choking = TRUE - return TRUE - -/mob/living/simple_animal/hostile/retaliate/goose/vomit - name = "Birdboat" - real_name = "Birdboat" - desc = "It's a sick-looking goose, probably ate too much maintenance trash. Best not to move it around too much." - gender = MALE - 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" - faction = list(FACTION_NEUTRAL, FACTION_MAINT_CREATURES) - gold_core_spawnable = NO_SPAWN - random_retaliate = FALSE - var/vomiting = FALSE - var/vomitCoefficient = 1 - var/vomitTimeBonus = 0 - var/datum/action/cooldown/vomit/goosevomit - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/Initialize(mapload) - . = ..() - goosevomit = new - goosevomit.Grant(src) - // 5% chance every round to have anarchy mode deadchat control on birdboat. - if(prob(5)) - desc = "[initial(desc)] It's waddling more than usual. It seems to be possessed." - deadchat_plays() - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/Destroy() - UnregisterSignal(src, COMSIG_MOVABLE_MOVED) - QDEL_NULL(goosevomit) - return ..() - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/examine(user) - . = ..() - . += span_notice("Somehow, it still looks hungry.") - -/mob/living/simple_animal/hostile/retaliate/goose/attackby(obj/item/O, mob/user) - . = ..() - if(feed(O)) - return TRUE - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/feed(obj/item/food/tasty) - . = ..() - if(. || !istype(tasty)) - return FALSE - if (contents.len > GOOSE_SATIATED) - if(message_cooldown < world.time) - visible_message(span_notice("[src] looks too full to eat \the [tasty]!")) - message_cooldown = world.time + 5 SECONDS - return FALSE - if (tasty.foodtypes & GROSS) - visible_message(span_notice("[src] hungrily gobbles up \the [tasty]!")) - tasty.forceMove(src) - playsound(src,'sound/items/eatfood.ogg', 70, TRUE) - vomitCoefficient += 3 - vomitTimeBonus += 2 - return TRUE - else - if(message_cooldown < world.time) - visible_message(span_notice("[src] refuses to eat \the [tasty].")) - message_cooldown = world.time + 5 SECONDS - return FALSE - -/mob/living/simple_animal/hostile/retaliate/goose/proc/choke(obj/item/food/plastic) - if(stat == DEAD || choking) - return - addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/choke(obj/item/food/plastic) - if(stat == DEAD || choking) - return - if(prob(25)) - visible_message(span_warning("[src] is gagging on \the [plastic]!")) - manual_emote("gags!") - addtimer(CALLBACK(src, PROC_REF(vomit)), 30 SECONDS) - else - addtimer(CALLBACK(src, PROC_REF(suffocate)), 30 SECONDS) - -/mob/living/simple_animal/hostile/retaliate/goose/Life(seconds_per_tick = SSMOBS_DT, times_fired) - . = ..() - if(!choking || stat) - return - do_jitter_animation(50) - if(SPT_PROB(10, seconds_per_tick)) - INVOKE_ASYNC(src, PROC_REF(emote), "gasp") - -/mob/living/simple_animal/hostile/retaliate/goose/proc/suffocate() - if(!choking) - return - death_message = "lets out one final oxygen-deprived honk before [p_they()] go[p_es()] limp and lifeless.." - death() - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit() - if (stat == DEAD) - return - var/turf/T = get_turf(src) - var/obj/item/consumed = locate() in contents //Barf out a single food item from our guts - choking = FALSE // assume birdboat is vomiting out whatever he was choking on - if (prob(50) && consumed) - barf_food(consumed) - else - playsound(T, 'sound/effects/splat.ogg', 50, TRUE) - T.add_vomit_floor(src) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/barf_food(atom/A, hard = FALSE) - if (stat == DEAD) - return - if(!istype(A, /obj/item/food)) - return - var/turf/currentTurf = get_turf(src) - var/obj/item/food/consumed = A - consumed.forceMove(currentTurf) - var/destination = get_edge_target_turf(currentTurf, pick(GLOB.alldirs)) //Pick a random direction to toss them in - var/throwRange = hard ? rand(2,8) : 1 - consumed.safe_throw_at(destination, throwRange, 2) //Thow the food at a random tile 1 spot away - sleep(0.2 SECONDS) - if (QDELETED(src) || QDELETED(consumed)) - return - currentTurf = get_turf(consumed) - currentTurf.add_vomit_floor(src) - playsound(currentTurf, 'sound/effects/splat.ogg', 50, TRUE) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_prestart(duration) - flick("vomit_start",src) - addtimer(CALLBACK(src, PROC_REF(vomit_start), duration), 13) //13 is the length of the vomit_start animation in gooseloose.dmi - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_start(duration) - vomiting = TRUE - icon_state = "vomit" - vomit() - addtimer(CALLBACK(src, PROC_REF(vomit_preend)), duration) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_preend() - for (var/obj/item/consumed in contents) //Get rid of any food left in the poor thing - barf_food(consumed, TRUE) - sleep(0.1 SECONDS) - if (QDELETED(src)) - return - vomit_end() - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_end() - flick("vomit_end",src) - vomiting = FALSE - icon_state = initial(icon_state) - -/mob/living/simple_animal/hostile/retaliate/goose/vomit/goosement(atom/movable/AM, OldLoc, Dir, Forced) - . = ..() - if(vomiting) - INVOKE_ASYNC(src, PROC_REF(vomit)) // its supposed to keep vomiting if you move - return - if(prob(vomitCoefficient * 0.2)) - vomit_prestart(vomitTimeBonus + 25) - vomitCoefficient = 1 - vomitTimeBonus = 0 - -/// A proc to make it easier for admins to make the goose playable by deadchat. -/mob/living/simple_animal/hostile/retaliate/goose/vomit/deadchat_plays(mode = ANARCHY_MODE, cooldown = 12 SECONDS) - . = AddComponent(/datum/component/deadchat_control/cardinal_movement, mode, list( - "vomit" = CALLBACK(src, PROC_REF(vomit_prestart), 25), - "honk" = CALLBACK(src, TYPE_PROC_REF(/atom/movable, say), "HONK!!!"), - "spin" = CALLBACK(src, TYPE_PROC_REF(/mob, emote), "spin")), cooldown, CALLBACK(src, PROC_REF(stop_deadchat_plays))) - - if(. == COMPONENT_INCOMPATIBLE) - return - - stop_automated_movement = TRUE - -/datum/action/cooldown/vomit - name = "Vomit" - check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED - button_icon_state = "vomit" - button_icon = 'icons/mob/simple/animal.dmi' - cooldown_time = 250 - -/datum/action/cooldown/vomit/Activate(atom/target) - if(!istype(owner, /mob/living/simple_animal/hostile/retaliate/goose/vomit)) - return FALSE - - StartCooldown(10 SECONDS) - var/mob/living/simple_animal/hostile/retaliate/goose/vomit/probably_birdboat = owner - if(!probably_birdboat.vomiting) - probably_birdboat.vomit_prestart(probably_birdboat.vomitTimeBonus + 25) - probably_birdboat.vomitCoefficient = 1 - probably_birdboat.vomitTimeBonus = 0 - - StartCooldown() - return TRUE - -#undef GOOSE_SATIATED diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm deleted file mode 100644 index bf1c12d5da1..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ /dev/null @@ -1,59 +0,0 @@ -/mob/living/simple_animal/hostile/retaliate - ///A list of weakrefs pointing at things that we consider targets - var/list/enemies = list() - -/mob/living/simple_animal/hostile/retaliate/Found(atom/A) - if(isliving(A)) - var/mob/living/L = A - if(!L.stat) - return L - else - enemies -= WEAKREF(L) - else if(ismecha(A)) - var/obj/vehicle/sealed/mecha/M = A - if(LAZYLEN(M.occupants)) - return A - -/mob/living/simple_animal/hostile/retaliate/ListTargets() - if(!enemies.len) - return list() - var/list/see = ..() - var/list/actual_enemies = list() - for(var/datum/weakref/enemy as anything in enemies) - var/mob/flesh_and_blood = enemy.resolve() - if(!flesh_and_blood) - enemies -= enemy - continue - actual_enemies += flesh_and_blood - - see &= actual_enemies // Remove all entries that aren't in enemies - return see - -/mob/living/simple_animal/hostile/retaliate/proc/Retaliate() - var/list/around = view(src, vision_range) - - for(var/atom/movable/A in around) - if(A == src) - continue - if(isliving(A)) - var/mob/living/M = A - if(faction_check_atom(M) && attack_same || !faction_check_atom(M)) - enemies |= WEAKREF(M) - else if(ismecha(A)) - var/obj/vehicle/sealed/mecha/M = A - if(LAZYLEN(M.occupants)) - enemies |= WEAKREF(M) - add_enemies(M.occupants) - - for(var/mob/living/simple_animal/hostile/retaliate/H in around) - if(faction_check_atom(H) && !attack_same && !H.attack_same) - H.enemies |= enemies - -/mob/living/simple_animal/hostile/retaliate/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(. > 0 && stat == CONSCIOUS) - Retaliate() - -/mob/living/simple_animal/hostile/retaliate/proc/add_enemies(new_enemies) - for(var/new_enemy in new_enemies) - enemies |= WEAKREF(new_enemy) diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 39e239a37ed..0bea535c3e3 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -58,9 +58,6 @@ /mob/living/simple_animal/hostile/ooze, /mob/living/simple_animal/hostile/ooze/gelatinous, /mob/living/simple_animal/hostile/ooze/grapes, - /mob/living/simple_animal/hostile/retaliate, - /mob/living/simple_animal/hostile/retaliate/goose, - /mob/living/simple_animal/hostile/retaliate/goose/vomit, /mob/living/simple_animal/soulscythe, // DO NOT ADD NEW ENTRIES TO THIS LIST // READ THE COMMENT ABOVE diff --git a/tgstation.dme b/tgstation.dme index 9be45492d4f..25ecd8cb435 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4934,6 +4934,9 @@ #include "code\modules\mob\living\basic\farm_animals\goat\_goat.dm" #include "code\modules\mob\living\basic\farm_animals\goat\goat_ai.dm" #include "code\modules\mob\living\basic\farm_animals\goat\goat_subtypes.dm" +#include "code\modules\mob\living\basic\farm_animals\goose\goose.dm" +#include "code\modules\mob\living\basic\farm_animals\goose\goose_ai.dm" +#include "code\modules\mob\living\basic\farm_animals\goose\goose_vomit.dm" #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla.dm" #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_accessories.dm" #include "code\modules\mob\living\basic\farm_animals\gorilla\gorilla_ai.dm" @@ -5378,8 +5381,6 @@ #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\herald.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\legionnaire.dm" #include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\pandora.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\goose.dm" -#include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob_spawn\mob_spawn.dm" #include "code\modules\mob_spawn\corpses\job_corpses.dm" #include "code\modules\mob_spawn\corpses\mining_corpses.dm" diff --git a/tools/UpdatePaths/Scripts/89204_simple_to_basic_goose.txt b/tools/UpdatePaths/Scripts/89204_simple_to_basic_goose.txt new file mode 100644 index 00000000000..29ba0e74f54 --- /dev/null +++ b/tools/UpdatePaths/Scripts/89204_simple_to_basic_goose.txt @@ -0,0 +1 @@ +/mob/living/simple_animal/hostile/retaliate/goose/@SUBTYPES : /mob/living/basic/goose/@SUBTYPES{@OLD}