Basic Constructs: Artificer (#79015)

## About The Pull Request

Really getting into the meat of the constructs now. Artificers have
become basic mobs.

On the whole, this was a pretty rote conversion, with no significant
gameplay changes other than the switch to using healing hands rather
than a unique heal ability. The player experience as an artificer is
more or less identical.

The _interesting_ part comes with the AI for the seldom-used "hostile"
variant. Hostile artificers, being squishy and laughably weak, are now a
dedicated "medic" role for constructs. They will perform triage, always
seeking the most wounded construct (or shade!) to give healing to. They
will not attack at all, but they _will_ flee with great speed if
attacked and not busy healing. If they are healing another construct,
they will remain even if they are beaten to death.

I've added some more AI functionality that may come in handy in the
future, and done some refactoring to keep things from getting out of
hand:
- A planning subtree for finding targets that will always select the
most heavily wounded living target that the mob can see (or rather, the
one with the least health). Useful again for medical triage, or for
making a particularly cruel mob that always attacks whoever is easiest
to kill. I plan to use this for NPC wraith constructs when I convert
them.
- Targeting datums can now check a blackboard key to see if they should
only target wounded mobs. This is particularly useful for "medic" type
mobs such as this one.
- I've refactored the "minimum stat" behavior of targeting datums to be
stored in a blackboard key. This removes the need to have unique
subtypes for each different minimum stat we might want. Which... for the
most part, weren't even used, leading to proliferation of several
completely identical targeting datums in a bunch of different files.
Hopefully this change will make things cleaner.

In addition, this PR fixes a pair of bugs from #78807 that I didn't
catch:
- Healing constructs can now actually heal shades. Turns out I forgot to
add the correct biotype.
- Healing hands, when set to print the target's remaining health, no
longer does so as a visible message.

The one thing I didn't do that I kind of wanted to is make NPC
artificers heal themselves when wounded and not busy doing something
else, but it ended up being kind of annoying to make a mob willingly
target itself. NPC artificers never had this behavior before, so I
consider it okay, but maybe I'll circle back to it later.
## Why It's Good For The Game

Another basic conversion, another 5 items off the checklist. Very little
should change in-game, though I think the new NPC AI could make for
interesting challenges in ruins or bitrunning or something.
## Changelog
🆑
refactor: Artificer constructs have been converted to the basic mob
framework. This should change very little about them, but please report
any bugs. NPC artificers are now smarter, and will focus on healing
nearby wounded constructs - if you see them, take them out first!
/🆑
This commit is contained in:
lizardqueenlexi
2023-10-20 00:03:27 -05:00
committed by GitHub
parent 47f10ca860
commit 0c17553a96
33 changed files with 137 additions and 113 deletions

View File

@@ -111,7 +111,7 @@
/turf/open/floor/cult,
/area/shuttle/escape)
"w" = (
/mob/living/simple_animal/hostile/construct/artificer,
/mob/living/basic/construct/artificer,
/turf/open/floor/cult,
/area/shuttle/escape)
"x" = (

View File

@@ -43,6 +43,10 @@
#define BB_BASIC_MOB_EXECUTION_TARGET "BB_basic_execution_target"
///Blackboard key for a whitelist typecache of "things we can target while trying to move"
#define BB_OBSTACLE_TARGETTING_WHITELIST "BB_targetting_whitelist"
/// Key for the minimum status at which we want to target mobs (does not need to be specified if CONSCIOUS)
#define BB_TARGET_MINIMUM_STAT "BB_target_minimum_stat"
/// Flag for whether to target only wounded mobs
#define BB_TARGET_WOUNDED_ONLY "BB_target_wounded_only"
/// Blackboard key storing how long your targetting datum has held a particular target
#define BB_BASIC_MOB_HAS_TARGET_TIME "BB_basic_mob_has_target_time"

View File

@@ -925,6 +925,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_FISH_FED_LUBE "fish_fed_lube"
#define TRAIT_FISH_NO_HUNGER "fish_no_hunger"
/// Trait given to angelic constructs to let them purge cult runes
#define TRAIT_ANGELIC "angelic"
// common trait sources
#define TRAIT_GENERIC "generic"
#define UNCONSCIOUS_TRAIT "unconscious"

View File

@@ -194,3 +194,7 @@
var/datum/award/award_a = SSachievements.awards[type_a]
var/datum/award/award_b = SSachievements.awards[type_b]
return award_b?.load_priority - award_a?.load_priority
/// Orders mobs by health
/proc/cmp_mob_health(mob/living/mob_a, mob/living/mob_b)
return mob_b.health - mob_a.health

View File

@@ -0,0 +1,11 @@
/// Picks targets based on which one has the lowest health
/datum/ai_behavior/find_potential_targets/most_wounded
/datum/ai_behavior/find_potential_targets/most_wounded/pick_final_target(datum/ai_controller/controller, list/filtered_targets)
var/list/living_targets = list()
for(var/mob/living/living_target in filtered_targets)
living_targets += filtered_targets
if(living_targets.len)
sortTim(living_targets, GLOBAL_PROC_REF(cmp_mob_health))
return living_targets[1]
return ..()

View File

@@ -0,0 +1,6 @@
/// Selects the most wounded potential target that we can see
/datum/ai_planning_subtree/simple_find_wounded_target
/datum/ai_planning_subtree/simple_find_wounded_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
. = ..()
controller.queue_behavior(/datum/ai_behavior/find_potential_targets/most_wounded, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETTING_DATUM, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION)

View File

@@ -15,10 +15,12 @@
/datum/targetting_datum/basic
/// When we do our basic faction check, do we look for exact faction matches?
var/check_factions_exactly = FALSE
/// Minimum status to attack living beings
var/stat_attack = CONSCIOUS
///Whether we care for seeing the target or not
/// Whether we care for seeing the target or not
var/ignore_sight = FALSE
/// Blackboard key containing the minimum stat of a living mob to target
var/minimum_stat_key = BB_TARGET_MINIMUM_STAT
/// If this blackboard key is TRUE, makes us only target wounded mobs
var/target_wounded_key
/datum/targetting_datum/basic/can_attack(mob/living/living_mob, atom/the_target, vision_range)
var/datum/ai_controller/basic_controller/our_controller = living_mob.ai_controller
@@ -54,7 +56,9 @@
var/mob/living/living_target = the_target
if(faction_check(our_controller, living_mob, living_target))
return FALSE
if(living_target.stat > stat_attack)
if(living_target.stat > our_controller.blackboard[minimum_stat_key])
return FALSE
if(target_wounded_key && our_controller.blackboard[target_wounded_key] && living_target.health == living_target.maxHealth)
return FALSE
return TRUE
@@ -121,8 +125,8 @@
find_smaller = FALSE
inclusive = FALSE
/datum/targetting_datum/basic/attack_until_dead
stat_attack = HARD_CRIT
/// Makes the mob only attack their own faction. Useful mostly if their attacks do something helpful (e.g. healing touch).
/datum/targetting_datum/basic/same_faction
/datum/targetting_datum/basic/attack_even_if_dead
stat_attack = DEAD
/datum/targetting_datum/basic/same_faction/faction_check(mob/living/living_mob, mob/living/the_target)
return !..() // inverts logic to ONLY target mobs that share a faction

View File

@@ -159,7 +159,7 @@
if(show_health && !iscarbon(target))
var/formatted_string = format_string("%TARGET% now has <b>[target.health]/[target.maxHealth] health.</b>", healer, target)
healer.visible_message(span_danger(formatted_string))
to_chat(healer, span_danger(formatted_string))
/// Reformats the passed string with the replacetext keys
/datum/component/healing_touch/proc/format_string(string, atom/source, atom/target)

View File

@@ -185,11 +185,10 @@
UnregisterSignal(unfriended, COMSIG_ATOM_WAS_ATTACKED)
/datum/pet_command/protect_owner/execute_action(datum/ai_controller/controller)
var/datum/targetting_datum/basic/targetting = controller.blackboard[BB_TARGETTING_DATUM]
var/mob/living/victim = controller.blackboard[BB_CURRENT_PET_TARGET]
if(QDELETED(victim))
return
if(victim.stat > targetting.stat_attack)
if(victim.stat > controller.blackboard[BB_TARGET_MINIMUM_STAT])
controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND)
return
controller.queue_behavior(protect_behavior, BB_CURRENT_PET_TARGET, BB_PET_TARGETTING_DATUM)

View File

@@ -112,7 +112,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
/obj/effect/rune/attack_animal(mob/living/simple_animal/user, list/modifiers)
if(isshade(user) || isconstruct(user))
if(istype(user, /mob/living/simple_animal/hostile/construct/wraith/angelic) || istype(user, /mob/living/simple_animal/hostile/construct/juggernaut/angelic) || istype(user, /mob/living/simple_animal/hostile/construct/artificer/angelic))
if(HAS_TRAIT(user, TRAIT_ANGELIC))
to_chat(user, span_warning("You purge the rune!"))
qdel(src)
else if(construct_invoke || !IS_CULTIST(user)) //if you're not a cult construct we want the normal fail message

View File

@@ -485,15 +485,15 @@
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith/noncult, target, creator, cultoverride, loc_override)
if(CONSTRUCT_ARTIFICER)
if(IS_CULTIST(creator))
makeNewConstruct(/mob/living/simple_animal/hostile/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc
makeNewConstruct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc
return
switch(theme)
if(THEME_WIZARD)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/artificer/mystic, target, creator, cultoverride, loc_override)
makeNewConstruct(/mob/living/basic/construct/artificer/mystic, target, creator, cultoverride, loc_override)
if(THEME_HOLY)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/artificer/angelic, target, creator, cultoverride, loc_override)
makeNewConstruct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override)
if(THEME_CULT)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/artificer/noncult, target, creator, cultoverride, loc_override)
makeNewConstruct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override)
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null)
if(QDELETED(target))

View File

@@ -23,7 +23,7 @@
max_wizard_trigger_potency = 7
/datum/round_event/portal_storm/portal_storm_narsie
boss_types = list(/mob/living/simple_animal/hostile/construct/artificer/hostile = 6)
boss_types = list(/mob/living/basic/construct/artificer/hostile = 6)
hostile_types = list(/mob/living/simple_animal/hostile/construct/juggernaut/hostile = 8,\
/mob/living/simple_animal/hostile/construct/wraith/hostile = 6)

View File

@@ -4,7 +4,8 @@
*/
/datum/ai_controller/basic_controller/blobbernaut
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/jps
@@ -20,7 +21,8 @@
*/
/datum/ai_controller/basic_controller/blob_zombie
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/jps
@@ -37,7 +39,8 @@
*/
/datum/ai_controller/basic_controller/blob_spore
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/jps

View File

@@ -14,6 +14,7 @@
/datum/ai_controller/basic_controller/clown/murder
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_BASIC_MOB_SPEAK_LINES = null,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)

View File

@@ -61,6 +61,7 @@
heal_burn = 0,\
heal_time = 0,\
valid_targets_typecache = typecacheof(list(/mob/living/basic/construct, /mob/living/simple_animal/hostile/construct, /mob/living/simple_animal/shade)),\
valid_biotypes = MOB_MINERAL | MOB_SPIRIT,\
self_targetting = can_repair_self ? HEALING_TOUCH_ANYONE : HEALING_TOUCH_NOT_SELF,\
action_text = "%SOURCE% begins repairing %TARGET%'s dents.",\
complete_text = "%TARGET%'s dents are repaired.",\

View File

@@ -1,4 +1,4 @@
/mob/living/simple_animal/hostile/construct/artificer
/mob/living/basic/construct/artificer
name = "Artificer"
real_name = "Artificer"
desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar'Sie's armies."
@@ -8,15 +8,11 @@
health = 50
response_harm_continuous = "viciously beats"
response_harm_simple = "viciously beat"
harm_intent_damage = 5
obj_damage = 60
melee_damage_lower = 5
melee_damage_upper = 5
retreat_distance = 10
minimum_distance = 10 //AI artificers will flee like fuck
attack_verb_continuous = "rams"
attack_verb_simple = "ram"
environment_smash = ENVIRONMENT_SMASH_WALLS
attack_sound = 'sound/weapons/punch2.ogg'
construct_spells = list(
/datum/action/cooldown/spell/conjure/cult_floor,
@@ -33,70 +29,38 @@
can_repair = TRUE
can_repair_self = TRUE
smashes_walls = TRUE
///The health HUD applied to this mob.
var/health_hud = DATA_HUD_MEDICAL_ADVANCED
/mob/living/simple_animal/hostile/construct/artificer/Initialize(mapload)
/mob/living/basic/construct/artificer/Initialize(mapload)
. = ..()
AddElement(/datum/element/ai_retaliate)
var/datum/atom_hud/datahud = GLOB.huds[health_hud]
datahud.show_to(src)
/mob/living/simple_animal/hostile/construct/artificer/Found(atom/thing) //what have we found here?
if(!isconstruct(thing)) //is it a construct?
return FALSE
var/mob/living/simple_animal/hostile/construct/cultie = thing
if(cultie.health < cultie.maxHealth) //is it hurt? let's go heal it if it is
return TRUE
/// Hostile NPC version. Heals nearby constructs and cult structures, avoids targets that aren't extremely hurt.
/mob/living/basic/construct/artificer/hostile
ai_controller = /datum/ai_controller/basic_controller/artificer
smashes_walls = FALSE
/mob/living/simple_animal/hostile/construct/artificer/CanAttack(atom/the_target)
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
return FALSE
if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible
return TRUE //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs
return FALSE
/mob/living/simple_animal/hostile/construct/artificer/MoveToTarget(list/possible_targets)
..()
if(!isliving(target))
return
var/mob/living/victim = target
if(isconstruct(victim) && victim.health >= victim.maxHealth) //is this target an unhurt construct? stop trying to heal it
LoseTarget()
return
if(victim.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
retreat_distance = null
minimum_distance = 1
/mob/living/simple_animal/hostile/construct/artificer/Aggro()
..()
if(isconstruct(target)) //oh the target is a construct no need to flee
retreat_distance = null
minimum_distance = 1
/mob/living/simple_animal/hostile/construct/artificer/LoseAggro()
..()
retreat_distance = initial(retreat_distance)
minimum_distance = initial(minimum_distance)
/mob/living/simple_animal/hostile/construct/artificer/hostile //actually hostile, will move around, hit things, heal other constructs
AIStatus = AI_ON
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
/////////////////////////////Artificer-alts/////////////////////////
/mob/living/simple_animal/hostile/construct/artificer/angelic
// Alternate artificer themes
/mob/living/basic/construct/artificer/angelic
desc = "A bulbous construct dedicated to building and maintaining holy armies."
theme = THEME_HOLY
loot = list(/obj/item/ectoplasm/angelic)
construct_spells = list(
/datum/action/cooldown/spell/conjure/soulstone/purified,
/datum/action/cooldown/spell/conjure/construct/lesser,
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
/datum/action/innate/cult/create_rune/revive,
)
/mob/living/simple_animal/hostile/construct/artificer/mystic
/mob/living/basic/construct/artificer/angelic/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_ANGELIC, INNATE_TRAIT)
/mob/living/basic/construct/artificer/mystic
theme = THEME_WIZARD
loot = list(/obj/item/ectoplasm/mystic)
construct_spells = list(
/datum/action/cooldown/spell/conjure/cult_floor,
/datum/action/cooldown/spell/conjure/cult_wall,
@@ -106,7 +70,7 @@
/datum/action/innate/cult/create_rune/revive,
)
/mob/living/simple_animal/hostile/construct/artificer/noncult
/mob/living/basic/construct/artificer/noncult
construct_spells = list(
/datum/action/cooldown/spell/conjure/cult_floor,
/datum/action/cooldown/spell/conjure/cult_wall,

View File

@@ -0,0 +1,25 @@
/// Artificers
/datum/ai_controller/basic_controller/artificer
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/same_faction/construct,
BB_FLEE_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_WOUNDED_ONLY = TRUE,
)
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
/datum/ai_planning_subtree/simple_find_wounded_target,
/datum/ai_planning_subtree/basic_melee_attack_subtree,
/datum/ai_planning_subtree/target_retaliate/to_flee,
/datum/ai_planning_subtree/flee_target/from_flee_key,
)
/// Targetting datum that will only allow mobs that constructs can heal.
/datum/targetting_datum/basic/same_faction/construct
target_wounded_key = BB_TARGET_WOUNDED_ONLY
/datum/targetting_datum/basic/same_faction/construct/can_attack(mob/living/living_mob, atom/the_target, vision_range, check_faction = TRUE)
if(isconstruct(the_target) || istype(the_target, /mob/living/simple_animal/shade))
return ..()
return FALSE

View File

@@ -1,7 +1,8 @@
/// Pretty basic, just click people to death. Also hunt and eat bananas.
/datum/ai_controller/basic_controller/gorilla
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/gorilla,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items,
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
BB_EMOTE_KEY = "ooga",
BB_EMOTE_CHANCE = 40,
)
@@ -18,9 +19,6 @@
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/datum/targetting_datum/basic/allow_items/gorilla
stat_attack = UNCONSCIOUS
/datum/ai_planning_subtree/attack_obstacle_in_path/gorilla
attack_behaviour = /datum/ai_behavior/attack_obstructions/gorilla

View File

@@ -78,7 +78,8 @@
/datum/ai_controller/basic_controller/star_gazer
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/star_gazer(),
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
BB_PET_TARGETTING_DATUM = new /datum/targetting_datum/basic/not_friends/attack_closed_turfs,
)
@@ -92,9 +93,6 @@
/datum/ai_planning_subtree/basic_melee_attack_subtree,
)
/datum/targetting_datum/basic/star_gazer
stat_attack = HARD_CRIT
/datum/ai_planning_subtree/attack_obstacle_in_path/star_gazer
attack_behaviour = /datum/ai_behavior/attack_obstructions/star_gazer

View File

@@ -1,7 +1,8 @@
#define ENRAGE_ADDITION 25
/datum/ai_controller/basic_controller/ice_whelp
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/goliath,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
BB_WHELP_ENRAGED = 0,
)

View File

@@ -3,7 +3,8 @@
*/
/datum/ai_controller/basic_controller/brimdemon
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/brimdemon,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_traits = PAUSE_DURING_DO_AFTER
@@ -16,9 +17,6 @@
/datum/ai_planning_subtree/targeted_mob_ability/brimbeam,
)
/datum/targetting_datum/basic/brimdemon
stat_attack = HARD_CRIT
/datum/ai_planning_subtree/move_to_cardinal/brimdemon
move_behaviour = /datum/ai_behavior/move_to_cardinal/brimdemon

View File

@@ -3,7 +3,8 @@
/datum/ai_controller/basic_controller/goliath
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items/goliath,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/allow_items,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/basic_avoidance
@@ -19,9 +20,6 @@
/datum/ai_planning_subtree/goliath_dig,
)
/datum/targetting_datum/basic/allow_items/goliath
stat_attack = HARD_CRIT
/datum/ai_planning_subtree/basic_melee_attack_subtree/goliath
operational_datums = list(/datum/component/ai_target_timer)
melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/goliath

View File

@@ -1,7 +1,8 @@
/// Keep away and launch skulls at every opportunity, prioritising injured allies
/datum/ai_controller/basic_controller/legion
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead/legion,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/legion,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
BB_AGGRO_RANGE = 5, // Unobservant
BB_BASIC_MOB_FLEE_DISTANCE = 6,
)
@@ -18,7 +19,8 @@
/// Chase and attack whatever we are targetting, if it's friendly we will heal them
/datum/ai_controller/basic_controller/legion_brood
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead/legion,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/legion,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/basic_avoidance
@@ -29,9 +31,9 @@
)
/// Target nearby friendlies if they are hurt (and are not themselves Legions)
/datum/targetting_datum/basic/attack_until_dead/legion
/datum/targetting_datum/basic/legion
/datum/targetting_datum/basic/attack_until_dead/legion/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
/datum/targetting_datum/basic/legion/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)
if (!living_mob.faction_check_atom(the_target, exact_match = check_factions_exactly))
return FALSE
if (istype(the_target, living_mob.type))

View File

@@ -1,6 +1,7 @@
/datum/ai_controller/basic_controller/lobstrosity
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/lobster,
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
BB_LOBSTROSITY_EXPLOIT_TRAITS = list(TRAIT_INCAPACITATED, TRAIT_FLOORED, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT),
BB_LOBSTROSITY_FINGER_LUST = 0
)
@@ -18,9 +19,6 @@
/datum/ai_planning_subtree/find_fingers,
)
/datum/targetting_datum/basic/lobster
stat_attack = HARD_CRIT
/datum/ai_planning_subtree/basic_melee_attack_subtree/lobster
melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/lobster

View File

@@ -55,7 +55,8 @@
/datum/ai_controller/basic_controller/faithless
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/faithless(),
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = UNCONSCIOUS,
BB_LOW_PRIORITY_HUNTING_TARGET = null, // lights
)
@@ -69,6 +70,3 @@
/datum/ai_planning_subtree/find_and_hunt_target/look_for_light_fixtures,
/datum/ai_planning_subtree/random_speech/faithless,
)
/datum/targetting_datum/basic/faithless
stat_attack = UNCONSCIOUS

View File

@@ -58,6 +58,7 @@
/datum/ai_controller/basic_controller/mushroom
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/mushroom,
BB_TARGET_MINIMUM_STAT = DEAD,
)
ai_movement = /datum/ai_movement/basic_avoidance
@@ -70,7 +71,6 @@
/datum/targetting_datum/basic/mushroom
stat_attack = DEAD
///we only attacked another mushrooms
/datum/targetting_datum/basic/mushroom/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target)

View File

@@ -1,6 +1,7 @@
/datum/ai_controller/basic_controller/syndicate
blackboard = list(
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/attack_until_dead
BB_TARGETTING_DATUM = new /datum/targetting_datum/basic,
BB_TARGET_MINIMUM_STAT = HARD_CRIT,
)
ai_movement = /datum/ai_movement/basic_avoidance

View File

@@ -480,7 +480,7 @@
if(2)
new /mob/living/simple_animal/hostile/construct/wraith/hostile(get_turf(src))
if(3)
new /mob/living/simple_animal/hostile/construct/artificer/hostile(get_turf(src))
new /mob/living/basic/construct/artificer/hostile(get_turf(src))
if(4)
new /mob/living/simple_animal/hostile/construct/proteon/hostile(get_turf(src))
spawn_dust()

View File

@@ -68,6 +68,10 @@
theme = THEME_HOLY
loot = list(/obj/item/ectoplasm/angelic)
/mob/living/simple_animal/hostile/construct/juggernaut/angelic/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_ANGELIC, INNATE_TRAIT)
/mob/living/simple_animal/hostile/construct/juggernaut/mystic
theme = THEME_WIZARD
loot = list(/obj/item/ectoplasm/mystic)

View File

@@ -67,6 +67,10 @@
)
loot = list(/obj/item/ectoplasm/angelic)
/mob/living/simple_animal/hostile/construct/wraith/angelic/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_ANGELIC, INNATE_TRAIT)
/mob/living/simple_animal/hostile/construct/wraith/mystic
theme = THEME_WIZARD
construct_spells = list(

View File

@@ -67,11 +67,6 @@
/mob/living/simple_animal/hostile/asteroid/polarbear/lesser,
/mob/living/simple_animal/hostile/asteroid/wolf,
/mob/living/simple_animal/hostile/construct,
/mob/living/simple_animal/hostile/construct/artificer,
/mob/living/simple_animal/hostile/construct/artificer/angelic,
/mob/living/simple_animal/hostile/construct/artificer/hostile,
/mob/living/simple_animal/hostile/construct/artificer/mystic,
/mob/living/simple_animal/hostile/construct/artificer/noncult,
/mob/living/simple_animal/hostile/construct/juggernaut,
/mob/living/simple_animal/hostile/construct/juggernaut/angelic,
/mob/living/simple_animal/hostile/construct/juggernaut/hostile,

View File

@@ -825,6 +825,7 @@
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\tipped_reaction.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\travel_towards.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\ventcrawling.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\wounded_targetting.dm"
#include "code\datums\ai\basic_mobs\basic_ai_behaviors\write_on_paper.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\attack_adjacent_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\attack_obstacle_in_path.dm"
@@ -844,6 +845,7 @@
#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\simple_find_wounded_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\sleep_with_no_target.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\speech_subtree.dm"
#include "code\datums\ai\basic_mobs\basic_subtrees\stare_at_thing.dm"
@@ -4372,6 +4374,8 @@
#include "code\modules\mob\living\basic\clown\clown.dm"
#include "code\modules\mob\living\basic\clown\clown_ai.dm"
#include "code\modules\mob\living\basic\constructs\_construct.dm"
#include "code\modules\mob\living\basic\constructs\artificer.dm"
#include "code\modules\mob\living\basic\constructs\construct_ai.dm"
#include "code\modules\mob\living\basic\constructs\harvester.dm"
#include "code\modules\mob\living\basic\farm_animals\deer.dm"
#include "code\modules\mob\living\basic\farm_animals\pig.dm"
@@ -4758,7 +4762,6 @@
#include "code\modules\mob\living\simple_animal\hostile\vatbeast.dm"
#include "code\modules\mob\living\simple_animal\hostile\wizard.dm"
#include "code\modules\mob\living\simple_animal\hostile\zombie.dm"
#include "code\modules\mob\living\simple_animal\hostile\constructs\artificer.dm"
#include "code\modules\mob\living\simple_animal\hostile\constructs\constructs.dm"
#include "code\modules\mob\living\simple_animal\hostile\constructs\juggernaut.dm"
#include "code\modules\mob\living\simple_animal\hostile\constructs\wraith.dm"

View File

@@ -0,0 +1 @@
/mob/living/simple_animal/hostile/construct/artificer/@SUBTYPES : /mob/living/basic/construct/artificer/@SUBTYPES{@OLD}