From 912ac7b29db15d6194db45c5ce5ef12cc7f2a0b6 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Sun, 18 Dec 2022 01:15:34 +0000 Subject: [PATCH] Basic Mobs can run away (#71963) ## About The Pull Request That's right I'm still atomising #71421, some day I might even post something related to carp. This PR adds various behaviours to basic mobs allowing them to run away, in a couple of variations. Mice will flee from anyone who doesn't share their factions, at all times (so they will scatter from most humans, but not regal rats). Rabbits and Sheep will flee from anyone who has attacked them. Pigs will run away from people who have attacked them, but only if they're below half health. https://user-images.githubusercontent.com/7483112/207127135-d1737f91-d3f7-468a-ac60-7c7ae5d6623d.mp4 Mice are still plenty catchable because they don't run _very far_ (or very fast) but I think the chase will be good enrichment. To achieve this I had to change the signal COMSIG_CARBON_HEALTH_UPDATE into COMSIG_LIVING_HEALTH_UPDATE but frankly the latter seems more sensible anyway. ## Why It's Good For The Game More behaviours to use later when designing mobs, gradually gives mobs more things to do rather than just sort of moving aimlessly around the area you left them in. It'll give people hunting rats in maintenance some exercise. ## Changelog :cl: add: Mice will now run away from you, you have to catch them if you want to eat them. Use those traps! add: Rabbits, Sheep, and Pigs likewise won't just sit there and let you pulverise them if they can see an escape route. /:cl: --- code/__DEFINES/ai.dm | 3 ++ .../signals/signals_mob/signals_mob_carbon.dm | 2 - .../signals/signals_mob/signals_mob_living.dm | 2 + code/__DEFINES/mobfactions.dm | 2 + .../basic_ai_behaviors/basic_attacking.dm | 2 +- .../basic_ai_behaviors/nearest_targetting.dm | 13 ++++++ .../run_away_from_target.dm | 33 ++++++++++++++ .../basic_ai_behaviors/targetting.dm | 12 +++-- .../basic_mobs/basic_subtrees/flee_target.dm | 15 +++++++ .../simple_find_nearest_target_to_flee.dm | 17 +++++++ code/datums/elements/ai_flee_while_injured.dm | 45 +++++++++++++++++++ .../machinery/porta_turret/portable_turret.dm | 8 ++-- code/game/objects/items/food/monkeycube.dm | 2 +- .../heretic/knowledge/blade_lore.dm | 4 +- .../antagonists/slaughter/slaughter.dm | 2 +- .../mining/equipment/lazarus_injector.dm | 2 +- code/modules/mining/lavaland/tendril_loot.dm | 4 +- code/modules/mining/minebot.dm | 2 +- code/modules/mob/dead/observer/observer.dm | 2 +- .../mob/living/basic/farm_animals/pig.dm | 5 ++- .../mob/living/basic/farm_animals/rabbit.dm | 25 +++++++++-- .../mob/living/basic/farm_animals/sheep.dm | 9 +++- code/modules/mob/living/basic/pets/dog.dm | 4 +- .../mob/living/basic/vermin/mothroach.dm | 2 +- code/modules/mob/living/basic/vermin/mouse.dm | 17 ++++++- code/modules/mob/living/carbon/carbon.dm | 2 +- .../mob/living/carbon/human/monkey/monkey.dm | 2 +- code/modules/mob/living/living.dm | 1 + code/modules/mob/living/silicon/ai/life.dm | 1 + .../mob/living/simple_animal/bot/bot.dm | 2 +- .../simple_animal/friendly/drone/_drone.dm | 2 +- .../simple_animal/friendly/farm_animals.dm | 2 +- .../mob/living/simple_animal/hostile/ant.dm | 4 +- .../mob/living/simple_animal/hostile/bear.dm | 2 +- .../mob/living/simple_animal/hostile/carp.dm | 2 +- .../mob/living/simple_animal/hostile/goose.dm | 4 +- .../simple_animal/hostile/gorilla/gorilla.dm | 2 +- .../living/simple_animal/hostile/illusion.dm | 2 +- .../simple_animal/hostile/lightgeist.dm | 2 +- .../simple_animal/hostile/megafauna/drake.dm | 2 +- .../hostile/mining_mobs/polarbear.dm | 2 +- .../living/simple_animal/hostile/statue.dm | 2 +- .../living/simple_animal/hostile/vatbeast.dm | 2 +- .../mob/living/simple_animal/slime/life.dm | 2 +- .../mob/living/simple_animal/slime/slime.dm | 2 +- code/modules/mob/mob_defines.dm | 2 +- code/modules/pai/pai.dm | 1 + .../reagents/chemistry/recipes/others.dm | 2 +- .../chemistry/recipes/slime_extracts.dm | 6 +-- .../xenobiology/crossbreeding/_misc.dm | 2 +- .../research/xenobiology/xenobiology.dm | 4 +- tgstation.dme | 5 +++ 52 files changed, 240 insertions(+), 58 deletions(-) create mode 100644 code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm create mode 100644 code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm create mode 100644 code/datums/elements/ai_flee_while_injured.dm diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index b837799f963..6bb160969e2 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -223,6 +223,9 @@ ///List of mobs who have damaged us #define BB_BASIC_MOB_RETALIATE_LIST "BB_basic_mob_shitlist" +/// Flag to set on or off if you want your mob to prioritise running away +#define BB_BASIC_MOB_FLEEING "BB_basic_fleeing" + ///list of foods this mob likes #define BB_BASIC_FOODS "BB_basic_foods" diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index bb5987d927a..719f873beb9 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -81,8 +81,6 @@ #define COMSIG_CARBON_GAIN_TRAUMA "carbon_gain_trauma" ///Called when a carbon loses a brain trauma (source = carbon, trauma = what trauma was removed) #define COMSIG_CARBON_LOSE_TRAUMA "carbon_lose_trauma" -///Called when a carbon updates their health (source = carbon) -#define COMSIG_CARBON_HEALTH_UPDATE "carbon_health_update" ///Called when a carbon's health hud is updated. (source = carbon, shown_health_amount) #define COMSIG_CARBON_UPDATING_HEALTH_HUD "carbon_health_hud_update" /// Return if you override the carbon's health hud with something else diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 282a474fdf6..aed55ce70af 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -46,6 +46,8 @@ ///from base of element/bane/activate(): (item/weapon, mob/user) #define COMSIG_LIVING_BANED "living_baned" +/// from base of mob/living/updatehealth() +#define COMSIG_LIVING_HEALTH_UPDATE "living_health_update" ///from base of mob/living/death(): (gibbed) #define COMSIG_LIVING_DEATH "living_death" diff --git a/code/__DEFINES/mobfactions.dm b/code/__DEFINES/mobfactions.dm index fc4a9c96764..4fe9c522bee 100644 --- a/code/__DEFINES/mobfactions.dm +++ b/code/__DEFINES/mobfactions.dm @@ -5,3 +5,5 @@ #define FACTION_RAT "Rats" // Maint creatures have mutual respect for eachother. #define FACTION_MAINT_CREATURES "Maint_Creatures" + +#define FACTION_NEUTRAL "neutral" diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 64600e03f54..767b8447c66 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -1,6 +1,6 @@ /datum/ai_behavior/basic_melee_attack action_cooldown = 0.6 SECONDS - behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION /datum/ai_behavior/basic_melee_attack/setup(datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key) . = ..() diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm new file mode 100644 index 00000000000..8a570375cba --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/nearest_targetting.dm @@ -0,0 +1,13 @@ +/// Picks targets based on which one is closest to you, choice between targets at equal distance is arbitrary +/datum/ai_behavior/find_potential_targets/nearest + +/datum/ai_behavior/find_potential_targets/nearest/pick_final_target(datum/ai_controller/controller, list/filtered_targets) + var/turf/our_position = get_turf(controller.pawn) + return get_closest_atom(/atom/, filtered_targets, our_position) + +/// As above but targets have been filtered from the 'retaliate' blackboard list +/datum/ai_behavior/target_from_retaliate_list/nearest + +/datum/ai_behavior/target_from_retaliate_list/nearest/pick_final_target(datum/ai_controller/controller, list/enemies_list) + var/turf/our_position = get_turf(controller.pawn) + return get_closest_atom(/atom/, enemies_list, our_position) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm new file mode 100644 index 00000000000..c40c6ef432a --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm @@ -0,0 +1,33 @@ +/// Move to a position further away from your current target +/datum/ai_behavior/run_away_from_target + required_distance = 0 + action_cooldown = 0 + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + /// How far do we try to run? Further makes for smoother running, but potentially weirder pathfinding + var/run_distance = 9 + +/datum/ai_behavior/run_away_from_target/setup(datum/ai_controller/controller, target_key, hiding_location_key) + var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] + var/atom/target = weak_target?.resolve() + if(!target) + return FALSE + + plot_path_away_from(controller, target) + return ..() + +/datum/ai_behavior/run_away_from_target/perform(delta_time, datum/ai_controller/controller, target_key, hiding_location_key) + . = ..() + var/datum/weakref/weak_target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] + var/atom/target = weak_target?.resolve() + var/escaped = !target || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away + if (escaped) + finish_action(controller, succeeded = TRUE) + return + if (!in_range(controller.pawn, controller.current_movement_target)) + return + plot_path_away_from(controller, target) + +/datum/ai_behavior/run_away_from_target/proc/plot_path_away_from(datum/ai_controller/controller, atom/target) + var/run_direction = get_dir(controller.pawn, get_step_away(controller.pawn, target)) + var/turf/target_destination = get_ranged_target_turf(controller.pawn, run_direction, run_distance) + controller.set_movement_target(target_destination) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm index 0ebb2d3a3ff..c52a52bb104 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targetting.dm @@ -21,7 +21,7 @@ potential_targets += HM if(!potential_targets.len) - finish_action(controller, FALSE) + finish_action(controller, succeeded = FALSE) return var/list/filtered_targets = list() @@ -32,10 +32,10 @@ continue if(!filtered_targets.len) - finish_action(controller, FALSE) + finish_action(controller, succeeded = FALSE) return - var/atom/target = pick(filtered_targets) + var/atom/target = pick_final_target(controller, filtered_targets) controller.blackboard[target_key] = WEAKREF(target) var/atom/potential_hiding_location = targetting_datum.find_hidden_mobs(living_mob, target) @@ -43,4 +43,8 @@ if(potential_hiding_location) //If they're hiding inside of something, we need to know so we can go for that instead initially. controller.blackboard[hiding_location_key] = WEAKREF(potential_hiding_location) - finish_action(controller, TRUE) + finish_action(controller, succeeded = TRUE) + +/// Returns the desired final target from the filtered list of targets +/datum/ai_behavior/find_potential_targets/proc/pick_final_target(datum/ai_controller/controller, list/filtered_targets) + return pick(filtered_targets) diff --git a/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm new file mode 100644 index 00000000000..ef72743a5f5 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/flee_target.dm @@ -0,0 +1,15 @@ +/// Try to escape from your current target, without performing any other actions. +/datum/ai_planning_subtree/flee_target + /// Behaviour to execute in order to flee + var/flee_behaviour = /datum/ai_behavior/run_away_from_target + +/datum/ai_planning_subtree/flee_target/SelectBehaviors(datum/ai_controller/controller, delta_time) + . = ..() + if (!controller.blackboard[BB_BASIC_MOB_FLEEING]) + return + var/datum/weakref/weak_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] + var/atom/target = weak_target?.resolve() + if(!target || QDELETED(target)) + return + controller.queue_behavior(flee_behaviour, BB_BASIC_MOB_CURRENT_TARGET, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + return SUBTREE_RETURN_FINISH_PLANNING //we gotta get out of here. diff --git a/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm new file mode 100644 index 00000000000..d9f7ab9e337 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/simple_find_nearest_target_to_flee.dm @@ -0,0 +1,17 @@ +/// Find the nearest thing which we assume is hostile and set it as the flee target +/datum/ai_planning_subtree/simple_find_nearest_target_to_flee + +/datum/ai_planning_subtree/simple_find_nearest_target_to_flee/SelectBehaviors(datum/ai_controller/controller, delta_time) + . = ..() + if (!controller.blackboard[BB_BASIC_MOB_FLEEING]) + return + controller.queue_behavior(/datum/ai_behavior/find_potential_targets/nearest, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + +/// Find the nearest thing on our list of 'things which have done damage to me' and set it as the flee target +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee + +/datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee/SelectBehaviors(datum/ai_controller/controller, delta_time) + . = ..() + if (!controller.blackboard[BB_BASIC_MOB_FLEEING]) + return + controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list/nearest, BB_BASIC_MOB_RETALIATE_LIST, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) diff --git a/code/datums/elements/ai_flee_while_injured.dm b/code/datums/elements/ai_flee_while_injured.dm new file mode 100644 index 00000000000..f990d9d3166 --- /dev/null +++ b/code/datums/elements/ai_flee_while_injured.dm @@ -0,0 +1,45 @@ +/** + * Attached to a mob with an AI controller, simply sets a flag on whether or not to run away based on current health values. + */ +/datum/element/ai_flee_while_injured + element_flags = ELEMENT_BESPOKE + argument_hash_start_idx = 2 + /// Health value to end fleeing if at or above + var/stop_fleeing_at + /// Health value to start fleeing if at or below + var/start_fleeing_below + +/datum/element/ai_flee_while_injured/Attach(datum/target, stop_fleeing_at = 1, start_fleeing_below = 0.5) + . = ..() + if(!isliving(target)) + return ELEMENT_INCOMPATIBLE + var/mob/living/living_target = target + if(!living_target.ai_controller) + return ELEMENT_INCOMPATIBLE + src.stop_fleeing_at = stop_fleeing_at + src.start_fleeing_below = start_fleeing_below + RegisterSignal(target, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_changed)) + +/datum/element/ai_flee_while_injured/Detach(datum/source) + . = ..() + UnregisterSignal(source, COMSIG_LIVING_HEALTH_UPDATE) + +/// When the mob's health changes, check what the blackboard state should be +/datum/element/ai_flee_while_injured/proc/on_health_changed(mob/living/source) + SIGNAL_HANDLER + + if (!source.ai_controller) + return + + var/current_health_percentage = source.health / source.maxHealth + if (source.ai_controller.blackboard[BB_BASIC_MOB_FLEEING]) + if (current_health_percentage < stop_fleeing_at) + return + source.ai_controller.CancelActions() // Stop fleeing go back to whatever you were doing + source.ai_controller.blackboard[BB_BASIC_MOB_FLEEING] = FALSE + return + + if (current_health_percentage > start_fleeing_below) + return + source.ai_controller.CancelActions() + source.ai_controller.blackboard[BB_BASIC_MOB_FLEEING] = TRUE diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index c8ed058ffbe..0f5bdbf0e60 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -755,7 +755,7 @@ DEFINE_BITFIELD(turret_flags, list( /obj/machinery/porta_turret/syndicate/energy/raven stun_projectile = /obj/projectile/beam/laser stun_projectile_sound = 'sound/weapons/laser.ogg' - faction = list("neutral","silicon","turret") + faction = list(FACTION_NEUTRAL,"silicon","turret") /obj/machinery/porta_turret/syndicate/pod integrity_failure = 0.5 @@ -795,7 +795,7 @@ DEFINE_BITFIELD(turret_flags, list( lethal_projectile = /obj/projectile/plasma/turret lethal_projectile_sound = 'sound/weapons/plasma_cutter.ogg' mode = TURRET_LETHAL //It would be useless in stun mode anyway - faction = list("neutral","silicon","turret") //Minebots, medibots, etc that should not be shot. + faction = list(FACTION_NEUTRAL,"silicon","turret") //Minebots, medibots, etc that should not be shot. /obj/machinery/porta_turret/aux_base/assess_perp(mob/living/carbon/human/perp) return 0 //Never shoot humanoids. You are on your own if Ashwalkers or the like attack! @@ -824,7 +824,7 @@ DEFINE_BITFIELD(turret_flags, list( stun_projectile_sound = 'sound/weapons/plasma_cutter.ogg' icon_state = "syndie_off" base_icon_state = "syndie" - faction = list("neutral","silicon","turret") + faction = list(FACTION_NEUTRAL,"silicon","turret") mode = TURRET_LETHAL /obj/machinery/porta_turret/centcom_shuttle/Initialize(mapload) @@ -844,7 +844,7 @@ DEFINE_BITFIELD(turret_flags, list( desc = "A turret built with substandard parts and run down further with age. Still capable of delivering lethal lasers to the odd space carp, but not much else." stun_projectile = /obj/projectile/beam/weak/penetrator lethal_projectile = /obj/projectile/beam/weak/penetrator - faction = list("neutral","silicon","turret") + faction = list(FACTION_NEUTRAL,"silicon","turret") //////////////////////// //Turret Control Panel// diff --git a/code/game/objects/items/food/monkeycube.dm b/code/game/objects/items/food/monkeycube.dm index 8d533fec50d..d2fae2124ca 100644 --- a/code/game/objects/items/food/monkeycube.dm +++ b/code/game/objects/items/food/monkeycube.dm @@ -51,7 +51,7 @@ user.gib(null, TRUE, null, TRUE) /obj/item/food/monkeycube/syndicate - faction = list("neutral", ROLE_SYNDICATE) + faction = list(FACTION_NEUTRAL, ROLE_SYNDICATE) /obj/item/food/monkeycube/gorilla name = "gorilla cube" diff --git a/code/modules/antagonists/heretic/knowledge/blade_lore.dm b/code/modules/antagonists/heretic/knowledge/blade_lore.dm index 667c29ed3f4..e2f9e2d9051 100644 --- a/code/modules/antagonists/heretic/knowledge/blade_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/blade_lore.dm @@ -254,7 +254,7 @@ ADD_TRAIT(user, TRAIT_NODISMEMBER, type) RegisterSignal(user, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) RegisterSignal(user, COMSIG_CARBON_GAIN_WOUND, PROC_REF(on_wound_gain)) - RegisterSignal(user, COMSIG_CARBON_HEALTH_UPDATE, PROC_REF(on_health_update)) + RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_update)) on_health_update(user) // Run this once, so if the knowledge is learned while hurt it activates properly @@ -264,7 +264,7 @@ REMOVE_TRAIT(user, TRAIT_HARDLY_WOUNDED, type) REMOVE_TRAIT(user, TRAIT_BATON_RESISTANCE, type) - UnregisterSignal(user, list(COMSIG_PARENT_EXAMINE, COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_HEALTH_UPDATE)) + UnregisterSignal(user, list(COMSIG_PARENT_EXAMINE, COMSIG_CARBON_GAIN_WOUND, COMSIG_LIVING_HEALTH_UPDATE)) /datum/heretic_knowledge/duel_stance/proc/on_examine(mob/living/source, mob/user, list/examine_list) SIGNAL_HANDLER diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index 43f86eabe17..132a7860cf1 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -235,4 +235,4 @@ /mob/living/simple_animal/hostile/imp/slaughter/engine_demon name = "engine demon" - faction = list("hell", "neutral") + faction = list("hell", FACTION_NEUTRAL) diff --git a/code/modules/mining/equipment/lazarus_injector.dm b/code/modules/mining/equipment/lazarus_injector.dm index bda5871c349..8fed6b4bc79 100644 --- a/code/modules/mining/equipment/lazarus_injector.dm +++ b/code/modules/mining/equipment/lazarus_injector.dm @@ -41,7 +41,7 @@ to_chat(user, span_info("[src] is only effective on the dead.")) return - target_animal.faction = list("neutral") + target_animal.faction = list(FACTION_NEUTRAL) target_animal.revive(HEAL_ALL) if(ishostile(target)) var/mob/living/simple_animal/hostile/target_hostile = target_animal diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index a9c38110f42..2c260d59620 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -169,7 +169,7 @@ ADD_TRAIT(user, TRAIT_NODEATH, CLOTHING_TRAIT) ADD_TRAIT(user, TRAIT_NOHARDCRIT, CLOTHING_TRAIT) ADD_TRAIT(user, TRAIT_NOCRITDAMAGE, CLOTHING_TRAIT) - RegisterSignal(user, COMSIG_CARBON_HEALTH_UPDATE, PROC_REF(check_health)) + RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(check_health)) icon_state = "memento_mori_active" active_owner = user @@ -177,7 +177,7 @@ icon_state = "memento_mori" if(!active_owner) return - UnregisterSignal(active_owner, COMSIG_CARBON_HEALTH_UPDATE) + UnregisterSignal(active_owner, COMSIG_LIVING_HEALTH_UPDATE) var/mob/living/carbon/human/H = active_owner //to avoid infinite looping when dust unequips the pendant active_owner = null to_chat(H, span_userdanger("You feel your life rapidly slipping away from you!")) diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 9e18de9f5f8..e09ae57ebd5 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -11,7 +11,7 @@ icon_living = "mining_drone" status_flags = CANSTUN|CANKNOCKDOWN|CANPUSH mouse_opacity = MOUSE_OPACITY_ICON - faction = list("neutral") + faction = list(FACTION_NEUTRAL) combat_mode = TRUE atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 9be6f378bd3..46499f3fc73 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -684,7 +684,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return FALSE target.key = key - target.faction = list("neutral") + target.faction = list(FACTION_NEUTRAL) return TRUE /mob/dead/observer/_pointed(atom/pointed_at) diff --git a/code/modules/mob/living/basic/farm_animals/pig.dm b/code/modules/mob/living/basic/farm_animals/pig.dm index 8d1c4b323c4..fee809e43eb 100644 --- a/code/modules/mob/living/basic/farm_animals/pig.dm +++ b/code/modules/mob/living/basic/farm_animals/pig.dm @@ -32,6 +32,7 @@ /mob/living/basic/pig/Initialize() AddElement(/datum/element/pet_bonus, "oinks!") AddElement(/datum/element/ai_retaliate) + AddElement(/datum/element/ai_flee_while_injured) make_tameable() . = ..() @@ -47,7 +48,7 @@ /datum/ai_controller/basic_controller/pig blackboard = list( - BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction() + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction(), ) ai_traits = STOP_MOVING_WHEN_PULLED @@ -55,6 +56,8 @@ idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, /datum/ai_planning_subtree/target_retaliate, /datum/ai_planning_subtree/basic_melee_attack_subtree/pig, ) diff --git a/code/modules/mob/living/basic/farm_animals/rabbit.dm b/code/modules/mob/living/basic/farm_animals/rabbit.dm index 7677e6a98fd..071470264db 100644 --- a/code/modules/mob/living/basic/farm_animals/rabbit.dm +++ b/code/modules/mob/living/basic/farm_animals/rabbit.dm @@ -39,16 +39,26 @@ /mob/living/basic/rabbit/Initialize(mapload) . = ..() + AddElement(/datum/element/ai_retaliate) AddElement(/datum/element/pet_bonus, "hops around happily!") AddElement(/datum/element/animal_variety, icon_prefix, pick("brown", "black", "white"), TRUE) if(prob(20)) // bunny name = "bunny" /datum/ai_controller/basic_controller/rabbit + blackboard = list( + BB_BASIC_MOB_FLEEING = TRUE, + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction(), + ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk - planning_subtrees = list(/datum/ai_planning_subtree/random_speech/rabbit) + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/rabbit, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + ) + /// The easter subtype of rabbits, will lay eggs and say Eastery catchphrases. /mob/living/basic/rabbit/easter @@ -78,7 +88,12 @@ ) /datum/ai_controller/basic_controller/rabbit/easter - planning_subtrees = list(/datum/ai_planning_subtree/random_speech/rabbit/easter) + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/rabbit/easter, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + ) + /// Same deal as the standard easter subtype, but these ones are able to brave the cold of space with their handy gas mask. /mob/living/basic/rabbit/easter/space @@ -93,4 +108,8 @@ unsuitable_cold_damage = 0 // Zero because we are meant to survive in space. /datum/ai_controller/basic_controller/rabbit/easter/space - planning_subtrees = list(/datum/ai_planning_subtree/random_speech/rabbit/easter/space) + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/rabbit/easter/space, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, + ) diff --git a/code/modules/mob/living/basic/farm_animals/sheep.dm b/code/modules/mob/living/basic/farm_animals/sheep.dm index b28c35b334b..95e1a6737df 100644 --- a/code/modules/mob/living/basic/farm_animals/sheep.dm +++ b/code/modules/mob/living/basic/farm_animals/sheep.dm @@ -43,6 +43,7 @@ item_harvest_time = 5 SECONDS, \ item_harvest_sound = 'sound/surgery/scalpel1.ogg', \ ) + AddElement(/datum/element/ai_retaliate) RegisterSignal(src, COMSIG_LIVING_CULT_SACRIFICED, PROC_REF(on_sacrificed)) /mob/living/basic/sheep/update_overlays() @@ -80,9 +81,15 @@ update_appearance(UPDATE_ICON) /datum/ai_controller/basic_controller/sheep + blackboard = list( + BB_BASIC_MOB_FLEEING = TRUE, + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/ignore_faction(), + ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - /datum/ai_planning_subtree/random_speech/sheep + /datum/ai_planning_subtree/random_speech/sheep, + /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee, + /datum/ai_planning_subtree/flee_target, ) diff --git a/code/modules/mob/living/basic/pets/dog.dm b/code/modules/mob/living/basic/pets/dog.dm index e8d7ee702e0..a7c97867d98 100644 --- a/code/modules/mob/living/basic/pets/dog.dm +++ b/code/modules/mob/living/basic/pets/dog.dm @@ -9,7 +9,7 @@ response_harm_continuous = "kicks" response_harm_simple = "kick" speak_emote = list("barks", "woofs") - faction = list("neutral") + faction = list(FACTION_NEUTRAL) see_in_dark = 5 can_be_held = TRUE ai_controller = /datum/ai_controller/dog @@ -592,7 +592,7 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list( icon_state = "narsian" icon_living = "narsian" icon_dead = "narsian_dead" - faction = list("neutral", "cult") + faction = list(FACTION_NEUTRAL, "cult") gold_core_spawnable = NO_SPAWN nofur = TRUE unique_pet = TRUE diff --git a/code/modules/mob/living/basic/vermin/mothroach.dm b/code/modules/mob/living/basic/vermin/mothroach.dm index 816813bb942..15f82d38f85 100644 --- a/code/modules/mob/living/basic/vermin/mothroach.dm +++ b/code/modules/mob/living/basic/vermin/mothroach.dm @@ -30,7 +30,7 @@ response_help_continuous = "pats" response_help_simple = "pat" - faction = list("neutral") + faction = list(FACTION_NEUTRAL) ai_controller = /datum/ai_controller/basic_controller/mothroach diff --git a/code/modules/mob/living/basic/vermin/mouse.dm b/code/modules/mob/living/basic/vermin/mouse.dm index 906ad668421..0a659d3014c 100644 --- a/code/modules/mob/living/basic/vermin/mouse.dm +++ b/code/modules/mob/living/basic/vermin/mouse.dm @@ -234,6 +234,7 @@ response_harm_continuous = "splats" response_harm_simple = "splat" gold_core_spawnable = NO_SPAWN + faction = list(FACTION_RAT, FACTION_MAINT_CREATURES, FACTION_NEUTRAL) /mob/living/basic/mouse/brown/tom/Initialize(mapload) . = ..() @@ -326,22 +327,34 @@ /// The mouse AI controller /datum/ai_controller/basic_controller/mouse blackboard = list( + BB_BASIC_MOB_FLEEING = TRUE, // Always cowardly BB_CURRENT_HUNTING_TARGET = null, // cheese BB_LOW_PRIORITY_HUNTING_TARGET = null, // cable + BB_TARGETTING_DATUM = new /datum/targetting_datum/basic(), // Use this to find people to run away from ) ai_traits = STOP_MOVING_WHEN_PULLED ai_movement = /datum/ai_movement/basic_avoidance idle_behavior = /datum/idle_behavior/idle_random_walk planning_subtrees = list( - // Top priority is to look for and execute hunts for cheese + // Top priority is to look for and execute hunts for cheese even if someone is looking at us /datum/ai_planning_subtree/find_and_hunt_target/look_for_cheese, - // Try to speak after a cheese hunt, because it's cute + // Next priority is see if anyone is looking at us + /datum/ai_planning_subtree/simple_find_nearest_target_to_flee, + // Skedaddle + /datum/ai_planning_subtree/flee_target/mouse, + // Try to speak, because it's cute /datum/ai_planning_subtree/random_speech/mouse, // Otherwise, look for and execute hunts for cabling /datum/ai_planning_subtree/find_and_hunt_target/look_for_cables, ) +/datum/ai_planning_subtree/flee_target/mouse + flee_behaviour = /datum/ai_behavior/run_away_from_target/mouse + +/datum/ai_behavior/run_away_from_target/mouse + run_distance = 3 // Mostly exists in small tunnels, don't get ahead of yourself + /// AI controller for rats, slightly more complex than mice becuase they attack people /datum/ai_controller/basic_controller/mouse/rat blackboard = list( diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6a1fe23b05d..54f7a3a3824 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -525,7 +525,7 @@ add_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit) else remove_movespeed_modifier(/datum/movespeed_modifier/carbon_softcrit) - SEND_SIGNAL(src, COMSIG_CARBON_HEALTH_UPDATE) + SEND_SIGNAL(src, COMSIG_LIVING_HEALTH_UPDATE) /mob/living/carbon/update_stamina() var/stam = getStaminaLoss() diff --git a/code/modules/mob/living/carbon/human/monkey/monkey.dm b/code/modules/mob/living/carbon/human/monkey/monkey.dm index fdb5c54f91e..b5acde1e738 100644 --- a/code/modules/mob/living/carbon/human/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey/monkey.dm @@ -2,7 +2,7 @@ icon_state = "monkey" //for mapping race = /datum/species/monkey ai_controller = /datum/ai_controller/monkey - faction = list("neutral", "monkey") + faction = list(FACTION_NEUTRAL, "monkey") /mob/living/carbon/human/species/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner) if (cubespawned) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 6c9d0cd71f7..e24178f3225 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -696,6 +696,7 @@ med_hud_set_status() update_health_hud() update_stamina() + SEND_SIGNAL(src, COMSIG_LIVING_HEALTH_UPDATE) /mob/living/update_health_hud() var/severity = 0 diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index de3eb1ed7e9..1c03c27598f 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -62,6 +62,7 @@ update_stat() diag_hud_set_health() disconnect_shell() + SEND_SIGNAL(src, COMSIG_LIVING_HEALTH_UPDATE) /mob/living/silicon/ai/update_stat() if(status_flags & GODMODE) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 337af357340..40d072ef62b 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -23,7 +23,7 @@ initial_language_holder = /datum/language_holder/synthetic bubble_icon = "machine" speech_span = SPAN_ROBOT - faction = list("neutral", "silicon", "turret") + faction = list(FACTION_NEUTRAL, "silicon", "turret") light_system = MOVABLE_LIGHT light_range = 3 light_power = 0.9 diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index fc8b49d6438..fcd0d35d0cb 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -43,7 +43,7 @@ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD) unique_name = TRUE - faction = list("neutral","silicon","turret") + faction = list(FACTION_NEUTRAL,"silicon","turret") dextrous = TRUE dextrous_hud_type = /datum/hud/dextrous/drone lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 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 0ac1d83c35b..9cf65380fc4 100644 --- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm @@ -19,7 +19,7 @@ response_disarm_simple = "gently push aside" response_harm_continuous = "kicks" response_harm_simple = "kick" - faction = list("neutral") + faction = list(FACTION_NEUTRAL) mob_biotypes = MOB_ORGANIC|MOB_BEAST attack_same = 1 attack_verb_continuous = "kicks" diff --git a/code/modules/mob/living/simple_animal/hostile/ant.dm b/code/modules/mob/living/simple_animal/hostile/ant.dm index c64e1fe0c2e..72c29842bec 100644 --- a/code/modules/mob/living/simple_animal/hostile/ant.dm +++ b/code/modules/mob/living/simple_animal/hostile/ant.dm @@ -21,7 +21,7 @@ harm_intent_damage = 4 obj_damage = 5 melee_damage_lower = 5 - melee_damage_upper = 10 // Higher health than a base carp, so much lower damage. + melee_damage_upper = 10 // Higher health than a base carp, so much lower damage. attack_verb_continuous = "bites" attack_verb_simple = "bite" attack_sound = 'sound/weapons/bite.ogg' @@ -34,7 +34,7 @@ response_harm_continuous = "kicks" response_harm_simple = "kick" gold_core_spawnable = FRIENDLY_SPAWN - faction = list("neutral") + faction = list(FACTION_NEUTRAL) can_be_held = FALSE footstep_type = FOOTSTEP_MOB_CLAW health = 100 diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index 62beea9eaee..08797c90205 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -132,7 +132,7 @@ icon_living = "butterbear" icon_dead = "butterbear_dead" desc = "I can't believe its not a bear!" - faction = list("neutral", "russian") + faction = list(FACTION_NEUTRAL, "russian") obj_damage = 11 melee_damage_lower = 0 melee_damage_upper = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index 440695303aa..c59903c31fd 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -195,7 +195,7 @@ speak_emote = list("squeaks") ai_controller = null gold_core_spawnable = NO_SPAWN - faction = list("neutral") + faction = list(FACTION_NEUTRAL) health = 200 icon_dead = "magicarp_dead" icon_gib = "magicarp_gib" diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm index 2715e10cefb..eb08c3b15df 100644 --- a/code/modules/mob/living/simple_animal/hostile/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/goose.dm @@ -28,7 +28,7 @@ attack_sound = "goose" attack_vis_effect = ATTACK_EFFECT_BITE speak_emote = list("honks") - faction = list("neutral") + faction = list(FACTION_NEUTRAL) attack_same = TRUE gold_core_spawnable = HOSTILE_SPAWN var/random_retaliate = TRUE @@ -88,7 +88,7 @@ response_disarm_simple = "gently push aside" response_harm_continuous = "kicks" response_harm_simple = "kick" - faction = list("neutral", FACTION_MAINT_CREATURES) + faction = list(FACTION_NEUTRAL, FACTION_MAINT_CREATURES) gold_core_spawnable = NO_SPAWN random_retaliate = FALSE var/vomiting = FALSE diff --git a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm index daa191f71f7..1089bd8f448 100644 --- a/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm +++ b/code/modules/mob/living/simple_animal/hostile/gorilla/gorilla.dm @@ -122,7 +122,7 @@ desc = "Cargo's pet gorilla. They seem to have an 'I love Mom' tattoo." maxHealth = 200 health = 200 - faction = list("neutral", "monkey", "jungle") + faction = list(FACTION_NEUTRAL, "monkey", "jungle") gold_core_spawnable = NO_SPAWN unique_name = FALSE /// Whether we're currently being polled over diff --git a/code/modules/mob/living/simple_animal/hostile/illusion.dm b/code/modules/mob/living/simple_animal/hostile/illusion.dm index 75daa23d559..16817a1287c 100644 --- a/code/modules/mob/living/simple_animal/hostile/illusion.dm +++ b/code/modules/mob/living/simple_animal/hostile/illusion.dm @@ -38,7 +38,7 @@ melee_damage_lower = damage melee_damage_upper = damage multiply_chance = replicate - faction -= "neutral" + faction -= FACTION_NEUTRAL transform = initial(transform) pixel_x = base_pixel_x pixel_y = base_pixel_y diff --git a/code/modules/mob/living/simple_animal/hostile/lightgeist.dm b/code/modules/mob/living/simple_animal/hostile/lightgeist.dm index f2acd34730b..e5d5f1172b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/lightgeist.dm +++ b/code/modules/mob/living/simple_animal/hostile/lightgeist.dm @@ -34,7 +34,7 @@ initial_language_holder = /datum/language_holder/lightbringer damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) light_range = 4 - faction = list("neutral") + faction = list(FACTION_NEUTRAL) del_on_death = TRUE unsuitable_atmos_damage = 0 minbodytemp = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 6b4ce7d22a3..1b97ea781dd 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -347,7 +347,7 @@ name = "lesser ash drake" maxHealth = 200 health = 200 - faction = list("neutral") + faction = list(FACTION_NEUTRAL) obj_damage = 80 melee_damage_upper = 30 melee_damage_lower = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm index ffa74eb530b..5a002dbbf9a 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/polarbear.dm @@ -69,7 +69,7 @@ /mob/living/simple_animal/hostile/asteroid/polarbear/lesser name = "magic polar bear" desc = "It seems sentient somehow." - faction = list("neutral") + faction = list(FACTION_NEUTRAL) /obj/item/crusher_trophy/bear_paw name = "polar bear paw" diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index 3ff0a3a19ee..6b147cff367 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -145,7 +145,7 @@ return . - creator /mob/living/simple_animal/hostile/netherworld/statue/sentience_act() - faction -= "neutral" + faction -= FACTION_NEUTRAL // Statue powers diff --git a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm index a663b63217e..650443c79d7 100644 --- a/code/modules/mob/living/simple_animal/hostile/vatbeast.dm +++ b/code/modules/mob/living/simple_animal/hostile/vatbeast.dm @@ -34,7 +34,7 @@ /mob/living/simple_animal/hostile/vatbeast/proc/tamed(mob/living/tamer) buckle_lying = 0 AddElement(/datum/element/ridable, /datum/component/riding/creature/vatbeast) - faction = list("neutral") + faction = list(FACTION_NEUTRAL) /mob/living/simple_animal/hostile/vatbeast/add_cell_sample() AddElement(/datum/element/swabable, CELL_LINE_TABLE_VATBEAST, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index 894d376c48c..cbcb3d0e3f2 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -326,7 +326,7 @@ var/ally = FALSE for(var/F in faction) - if(F == "neutral") //slimes are neutral so other mobs not target them, but they can target neutral mobs + if(F == FACTION_NEUTRAL) //slimes are neutral so other mobs not target them, but they can target neutral mobs continue if(F in L.faction) ally = TRUE diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 70a38a93e48..b34170c3016 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -7,7 +7,7 @@ gender = NEUTER var/is_adult = 0 var/docile = 0 - faction = list("slime","neutral") + faction = list("slime", FACTION_NEUTRAL) harm_intent_damage = 5 icon_living = "grey baby slime" diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 0e348e58646..7a957a8e1c7 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -152,7 +152,7 @@ var/job = null//Living /// A list of factions that this mob is currently in, for hostile mob targetting, amongst other things - var/list/faction = list("neutral") + var/list/faction = list(FACTION_NEUTRAL) /// Can this mob enter shuttles var/move_on_shuttle = 1 diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm index b35342ab376..ede446a4d82 100644 --- a/code/modules/pai/pai.dm +++ b/code/modules/pai/pai.dm @@ -251,6 +251,7 @@ return set_health(maxHealth - getBruteLoss() - getFireLoss()) update_stat() + SEND_SIGNAL(src, COMSIG_LIVING_HEALTH_UPDATE) /** * Resolves the weakref of the pai's master. diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 40d470e4c82..56fe968362b 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -551,7 +551,7 @@ reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE /datum/chemical_reaction/life_friendly/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) - chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN, "neutral") + chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN, mob_faction = FACTION_NEUTRAL) /datum/chemical_reaction/corgium required_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent = 1, /datum/reagent/medicine/strange_reagent = 1, /datum/reagent/blood = 1) diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index befad835f8f..b8fe40c76ce 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -111,14 +111,14 @@ /datum/chemical_reaction/slime/slimemobspawn/lesser/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate violently!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, "neutral"), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, FACTION_NEUTRAL), 50) /datum/chemical_reaction/slime/slimemobspawn/friendly required_reagents = list(/datum/reagent/water = 1) /datum/chemical_reaction/slime/slimemobspawn/friendly/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate adorably!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, "neutral"), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, FACTION_NEUTRAL), 50) /datum/chemical_reaction/slime/slimemobspawn/spider required_reagents = list(/datum/reagent/spider_extract = 1) @@ -126,7 +126,7 @@ /datum/chemical_reaction/slime/slimemobspawn/spider/summon_mobs(datum/reagents/holder, turf/T) T.visible_message(span_danger("The slime extract begins to vibrate crikey-ingly!")) - addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/simple_animal/hostile/giant_spider/midwife, "neutral", FALSE), 50) + addtimer(CALLBACK(src, PROC_REF(chemical_mob_spawn), holder, 3, "Traitor Spider Slime", /mob/living/simple_animal/hostile/giant_spider/midwife, FACTION_NEUTRAL, FALSE), 50) //Silver diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 765553d34cc..14fc7db313d 100644 --- a/code/modules/research/xenobiology/crossbreeding/_misc.dm +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -185,7 +185,7 @@ Slimecrossing Items to_chat(user, span_warning("[M] refused to enter the device.")) return else - if(ishostile(M) && !("neutral" in M.faction)) + if(ishostile(M) && !(FACTION_NEUTRAL in M.faction)) to_chat(user, span_warning("This creature is too aggressive to capture.")) return to_chat(user, span_notice("You store [M] in the capture device.")) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 58957d8103c..b1c3ba068c6 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -126,7 +126,7 @@ user.visible_message(span_warning("[user] starts shaking!"),span_notice("Your [name] starts pulsing gently...")) if(do_after(user, 40, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), FRIENDLY_SPAWN) - spawned_mob.faction |= "neutral" + spawned_mob.faction |= FACTION_NEUTRAL playsound(user, 'sound/effects/splat.ogg', 50, TRUE) user.visible_message(span_warning("[user] spits out [spawned_mob]!"), span_notice("You spit out [spawned_mob]!")) return 300 @@ -136,7 +136,7 @@ if(do_after(user, 50, target = user)) var/mob/living/spawned_mob = create_random_mob(user.drop_location(), HOSTILE_SPAWN) if(!user.combat_mode) - spawned_mob.faction |= "neutral" + spawned_mob.faction |= FACTION_NEUTRAL else spawned_mob.faction |= "slime" playsound(user, 'sound/effects/splat.ogg', 50, TRUE) diff --git a/tgstation.dme b/tgstation.dme index 24a3031ee37..ac623496ae6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -716,11 +716,15 @@ #include "code\datums\ai\bane\bane_subtrees.dm" #include "code\datums\ai\basic_mobs\base_basic_controller.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\basic_attacking.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\nearest_targetting.dm" +#include "code\datums\ai\basic_mobs\basic_ai_behaviors\run_away_from_target.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\targetting.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm" #include "code\datums\ai\basic_mobs\basic_ai_behaviors\try_mob_ability.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\find_food.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\flee_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_attack_target.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_nearest_target_to_flee.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\simple_find_target.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\speech_subtree.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\target_retaliate.dm" @@ -1036,6 +1040,7 @@ #include "code\datums\diseases\advance\symptoms\weight.dm" #include "code\datums\diseases\advance\symptoms\youth.dm" #include "code\datums\elements\_element.dm" +#include "code\datums\elements\ai_flee_while_injured.dm" #include "code\datums\elements\ai_retaliate.dm" #include "code\datums\elements\animal_variety.dm" #include "code\datums\elements\art.dm"