diff --git a/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm b/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm
index dc8bea108bf..f97270c35a8 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm
@@ -33,7 +33,7 @@
/turf/simulated/floor/engine,
/area/template_noop)
"fK" = (
-/mob/living/simple_animal/hostile/viscerator{
+/mob/living/basic/viscerator{
faction = list("malf_drone")
},
/obj/structure/table/glass/reinforced/plastitanium,
@@ -57,7 +57,7 @@
/turf/simulated/floor/mineral/plastitanium/red,
/area/template_noop)
"ia" = (
-/mob/living/simple_animal/hostile/malf_drone,
+/mob/living/basic/malf_drone,
/turf/template_noop,
/area/template_noop)
"ir" = (
@@ -265,7 +265,7 @@
/turf/template_noop,
/area/template_noop)
"EF" = (
-/mob/living/simple_animal/hostile/viscerator{
+/mob/living/basic/viscerator{
faction = list("malf_drone")
},
/obj/structure/table/glass/reinforced/plastitanium,
@@ -347,7 +347,7 @@
/turf/template_noop,
/area/template_noop)
"OI" = (
-/mob/living/simple_animal/hostile/viscerator{
+/mob/living/basic/viscerator{
faction = list("malf_drone")
},
/turf/simulated/floor/mineral/plastitanium/red,
@@ -430,7 +430,7 @@
/turf/template_noop,
/area/template_noop)
"Ze" = (
-/mob/living/simple_animal/hostile/viscerator{
+/mob/living/basic/viscerator{
faction = list("malf_drone")
},
/obj/structure/table/glass/reinforced/plastitanium,
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm b/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
index 512adf52460..56ca8566050 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
@@ -39,7 +39,7 @@
/obj/structure/cable{
icon_state = "2-4"
},
-/mob/living/simple_animal/hostile/malf_drone,
+/mob/living/basic/malf_drone,
/obj/effect/spawner/random/cobweb/left/frequent,
/turf/simulated/floor/catwalk,
/area/ruin/space/telecomms/powercontrol)
@@ -1756,7 +1756,7 @@
"Dy" = (
/obj/structure/lattice,
/obj/structure/grille/broken,
-/mob/living/simple_animal/hostile/malf_drone,
+/mob/living/basic/malf_drone,
/turf/template_noop,
/area/space/nearstation/no_teleport)
"DT" = (
@@ -2677,7 +2677,7 @@
/turf/simulated/floor/catwalk,
/area/ruin/space/telecomms)
"TY" = (
-/mob/living/simple_animal/hostile/malf_drone,
+/mob/living/basic/malf_drone,
/turf/template_noop,
/area/space/no_teleport)
"Uw" = (
diff --git a/code/__DEFINES/ai/blackboard_defines.dm b/code/__DEFINES/ai/blackboard_defines.dm
index f41b38f7374..48dbccf7fa3 100644
--- a/code/__DEFINES/ai/blackboard_defines.dm
+++ b/code/__DEFINES/ai/blackboard_defines.dm
@@ -224,3 +224,7 @@
#define BB_SPIDER_EGG_LAYING_ACTION "BB_spider_egg_laying_action"
/// Key used by changelings who control spiders
#define BB_CHANGELING_SPIDER_ORDER "BB_changeling_spider_order"
+
+// Malf Drones
+/// Are we active?
+#define BB_MALF_DRONE_PASSIVE "BB_MALF_DRONE_PASSIVE"
diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm
index 0cd91ef881e..52a96772b69 100644
--- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm
+++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm
@@ -6,7 +6,7 @@
var/spawner_type = null // must be an object path
var/deliveryamt = 1 // amount of type to deliver
var/flash_viewers = TRUE
- spawner_type = /mob/living/simple_animal/hostile/viscerator
+ spawner_type = /mob/living/basic/viscerator
/obj/item/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it.
diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm
index c4fe2d40650..cca4ef28954 100644
--- a/code/modules/events/rogue_drones.dm
+++ b/code/modules/events/rogue_drones.dm
@@ -10,11 +10,11 @@
var/num = rand(2, 12)
for(var/i = 0, i < num, i++)
- var/mob/living/simple_animal/hostile/malf_drone/D = new(get_turf(pick(possible_spawns)))
+ var/mob/living/basic/malf_drone/D = new(get_turf(pick(possible_spawns)))
RegisterSignal(D, COMSIG_PARENT_QDELETING, PROC_REF(remove_drone))
drones_list.Add(D)
-/datum/event/rogue_drone/proc/remove_drone(mob/living/simple_animal/hostile/malf_drone/D)
+/datum/event/rogue_drone/proc/remove_drone(mob/living/basic/malf_drone/D)
SIGNAL_HANDLER
drones_list -= D
@@ -33,7 +33,7 @@
/datum/event/rogue_drone/end()
var/num_recovered = 0
- for(var/mob/living/simple_animal/hostile/malf_drone/D in drones_list)
+ for(var/mob/living/basic/malf_drone/D in drones_list)
do_sparks(3, 0, D.loc)
qdel(D)
num_recovered++
diff --git a/code/modules/mob/living/basic/hostile/viscerator.dm b/code/modules/mob/living/basic/hostile/viscerator.dm
new file mode 100644
index 00000000000..e805757cc50
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/viscerator.dm
@@ -0,0 +1,33 @@
+/mob/living/basic/viscerator
+ name = "viscerator"
+ desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
+ icon = 'icons/mob/critter.dmi'
+ icon_state = "viscerator_attack"
+ icon_living = "viscerator_attack"
+ pass_flags = PASSTABLE | PASSMOB
+ a_intent = INTENT_HARM
+ mob_biotypes = MOB_ROBOTIC
+ health = 15
+ maxHealth = 15
+ melee_attack_cooldown_min = 1.5 SECONDS
+ melee_attack_cooldown_max = 2.5 SECONDS
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attack_verb_continuous = "cuts"
+ attack_verb_simple = "cut"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ faction = list("syndicate")
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minimum_survivable_temperature = 0
+ mob_size = MOB_SIZE_TINY
+ density = FALSE
+ bubble_icon = "syndibot"
+ gold_core_spawnable = HOSTILE_SPAWN
+ basic_mob_flags = DEL_ON_DEATH
+ death_message = "is smashed into pieces!"
+ initial_traits = list(TRAIT_FLYING)
+ ai_controller = /datum/ai_controller/basic_controller/simple/simple_hostile_obstacles
+
+/mob/living/basic/viscerator/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/swarming)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/combat_drone.dm b/code/modules/mob/living/basic/retaliate/combat_drone.dm
similarity index 65%
rename from code/modules/mob/living/simple_animal/hostile/retaliate/combat_drone.dm
rename to code/modules/mob/living/basic/retaliate/combat_drone.dm
index 577cadca0c1..60ac532c7f8 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/combat_drone.dm
+++ b/code/modules/mob/living/basic/retaliate/combat_drone.dm
@@ -1,60 +1,50 @@
-
-//malfunctioning combat drones
-/mob/living/simple_animal/hostile/malf_drone
+// malfunctioning combat drones
+/mob/living/basic/malf_drone
name = "combat drone"
desc = "An automated combat drone armed with state of the art weaponry and shielding."
icon_state = "drone3"
icon_living = "drone3"
icon_dead = "drone_dead"
mob_biotypes = MOB_ROBOTIC
- ranged = TRUE
- rapid = 3
- retreat_distance = 3
- minimum_distance = 3
- speak_chance = 5
- turns_per_move = 3
- response_help = "pokes the"
- response_disarm = "gently pushes aside the"
- response_harm = "hits the"
- speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
- emote_see = list("beeps menacingly.", "whirrs threateningly.", "scans for targets.")
+ response_disarm_continuous = "gently pushes aside the"
+ response_disarm_simple = "gently pushes aside the"
a_intent = INTENT_HARM
health = 200
maxHealth = 200
speed = 8
- projectiletype = /obj/item/projectile/beam/immolator/weak/hitscan
- projectilesound = 'sound/weapons/laser3.ogg'
+ is_ranged = TRUE
+ ranged_burst_count = 3
+ ranged_burst_interval = 0.4
+ projectile_type = /obj/item/projectile/beam/immolator/weak/hitscan
+ projectile_sound = 'sound/weapons/laser3.ogg'
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
+ minimum_survivable_temperature = 0
faction = list("malf_drone")
- deathmessage = "suddenly breaks apart."
- del_on_death = TRUE
+ death_message = "suddenly breaks apart."
+ basic_mob_flags = DEL_ON_DEATH
advanced_bullet_dodge_chance = 25 // This will be adjusted when active, vs deactivated. Randomises on hit if it is zero.
- var/passive_mode = TRUE // if true, don't target anything.
+ ai_controller = /datum/ai_controller/basic_controller/simple/malf_drone
+ /// Is the drone passive?
+ var/passive = FALSE
-/mob/living/simple_animal/hostile/malf_drone/Initialize(mapload)
+/mob/living/basic/malf_drone/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(create_trail))
+ add_language("Galactic Common")
+ set_default_language(GLOB.all_languages["Galactic Common"])
+ AddElement(/datum/element/ai_retaliate)
update_icons()
-/mob/living/simple_animal/hostile/malf_drone/proc/create_trail(datum/source, atom/oldloc, _dir, forced)
+/mob/living/basic/malf_drone/proc/create_trail(datum/source, atom/oldloc, _dir, forced)
var/turf/T = get_turf(oldloc)
if(!has_gravity(T))
new /obj/effect/particle_effect/ion_trails(T, _dir)
-/mob/living/simple_animal/hostile/malf_drone/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
+/mob/living/basic/malf_drone/Process_Spacemove(movement_dir = 0, continuous_move = FALSE)
return 1
-/mob/living/simple_animal/hostile/malf_drone/ListTargets()
- if(passive_mode)
- return list()
- return ..()
-
-/mob/living/simple_animal/hostile/malf_drone/AttackingTarget()
- OpenFire(target) // prevents it pointlessly nuzzling its target in melee if its cornered
-
-/mob/living/simple_animal/hostile/malf_drone/update_icons()
- if(passive_mode)
+/mob/living/basic/malf_drone/update_icons()
+ if(passive)
icon_state = "drone_dead"
else if(health / maxHealth > 0.9)
icon_state = "drone3"
@@ -65,36 +55,39 @@
else
icon_state = "drone0"
-/mob/living/simple_animal/hostile/malf_drone/adjustHealth(damage, updating_health)
+/mob/living/basic/malf_drone/adjustHealth(damage, updating_health)
do_sparks(3, 1, src)
- passive_mode = FALSE
+ if(!QDELETED(src))
+ ai_controller.set_blackboard_key(BB_MALF_DRONE_PASSIVE, FALSE)
+ passive = FALSE
update_icons()
if(!advanced_bullet_dodge_chance)
advanced_bullet_dodge_chance = 25
. = ..() // this will handle finding a target if there is a valid one nearby
-/mob/living/simple_animal/hostile/malf_drone/Life(seconds, times_fired)
+/mob/living/basic/malf_drone/Life(seconds, times_fired)
. = ..()
if(.) // mob is alive. We check this just in case Life() can fire for qdel'ed mobs.
if(times_fired % 15 == 0) // every 15 cycles, aka 30 seconds, 50% chance to switch between modes
scramble_settings()
-/mob/living/simple_animal/hostile/malf_drone/proc/scramble_settings()
+/mob/living/basic/malf_drone/proc/scramble_settings()
if(prob(50))
do_sparks(3, 1, src)
- passive_mode = !passive_mode
- if(passive_mode)
+ passive = !passive
+ ai_controller.set_blackboard_key(BB_MALF_DRONE_PASSIVE, passive)
+ if(passive)
visible_message("[src] retracts several targetting vanes.")
advanced_bullet_dodge_chance = 0
- if(target)
- LoseTarget()
+ ai_controller.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, null)
else
visible_message("[src] suddenly lights up, and additional targetting vanes slide into place.")
advanced_bullet_dodge_chance = 25
+ ai_controller.cancel_actions()
update_icons()
/// We overide the basic effect, as malfunctioning drones are in space, and use jets to dodge. Also lets us do cool effects.
-/mob/living/simple_animal/hostile/malf_drone/advanced_bullet_dodge(mob/living/source, obj/item/projectile/hitting_projectile)
+/mob/living/basic/malf_drone/advanced_bullet_dodge(mob/living/source, obj/item/projectile/hitting_projectile)
if(HAS_TRAIT(source, TRAIT_IMMOBILIZED))
return NONE
if(source.stat != CONSCIOUS)
@@ -112,15 +105,15 @@
advanced_bullet_dodge_chance = 0
return ATOM_PREHIT_FAILURE
-/mob/living/simple_animal/hostile/malf_drone/emp_act(severity)
+/mob/living/basic/malf_drone/emp_act(severity)
adjustHealth(100 / severity) // takes the same damage as a mining drone from emp
-/mob/living/simple_animal/hostile/malf_drone/drop_loot()
+/mob/living/basic/malf_drone/drop_loot()
do_sparks(3, 1, src)
var/turf/T = get_turf(src)
- //shards
+ // shards
var/obj/O = new /obj/item/shard(T)
step_to(O, get_turf(pick(view(7, src))))
if(prob(75))
@@ -133,13 +126,13 @@
O = new /obj/item/shard(T)
step_to(O, get_turf(pick(view(7, src))))
- //rods
+ // rods
var/obj/item/stack/K = new /obj/item/stack/rods(T)
step_to(K, get_turf(pick(view(7, src))))
K.amount = pick(1, 2, 3, 4)
K.update_icon()
- //plasteel
+ // plasteel
K = new /obj/item/stack/sheet/plasteel(T)
step_to(K, get_turf(pick(view(7, src))))
K.amount = pick(1, 2, 3, 4)
@@ -203,3 +196,39 @@
/obj/item/circuitboard/random_tech_level/morality
name = "Corrupted drone morality core"
origin_tech = "syndicate="
+
+/datum/ai_controller/basic_controller/simple/malf_drone
+ movement_delay = 2 SECONDS
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/malf_drone,
+ BB_AGGRO_RANGE = 7,
+ BB_BASIC_MOB_FLEE_DISTANCE = 3,
+ BB_MALF_DRONE_PASSIVE = FALSE,
+ )
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/malf_drone,
+ /datum/ai_planning_subtree/target_retaliate/check_faction,
+ /datum/ai_planning_subtree/simple_find_target/malf_drone,
+ /datum/ai_planning_subtree/maintain_distance,
+ /datum/ai_planning_subtree/ranged_skirmish/no_minimum,
+ )
+
+/datum/ai_planning_subtree/simple_find_target/malf_drone
+
+/datum/ai_planning_subtree/simple_find_target/malf_drone/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
+ if(controller.blackboard[BB_MALF_DRONE_PASSIVE])
+ return // Only target if we're not in passive mode
+ return ..()
+
+/datum/ai_planning_subtree/random_speech/malf_drone
+ speech_chance = 4
+ speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
+ emote_see = list("beeps menacingly.", "whirrs threateningly.", "scans for targets.")
+
+/datum/targeting_strategy/basic/malf_drone
+
+/// Returns false if we're on passive mode. If we get attacked, we swap out of passive mode.
+/datum/targeting_strategy/basic/malf_drone/can_attack(mob/living/living_mob, atom/target, vision_range)
+ if(living_mob?.ai_controller?.blackboard[BB_MALF_DRONE_PASSIVE])
+ return FALSE
+ return ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm b/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm
index a875c72b0d2..73632893123 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate_mobs.dm
@@ -858,39 +858,6 @@
depotarea.unlock_lockers()
return ..()
-//////////////////////////////
-// MARK: VISCERATOR
-//////////////////////////////
-/mob/living/simple_animal/hostile/viscerator
- name = "viscerator"
- desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
- icon = 'icons/mob/critter.dmi'
- icon_state = "viscerator_attack"
- icon_living = "viscerator_attack"
- pass_flags = PASSTABLE | PASSMOB
- a_intent = INTENT_HARM
- mob_biotypes = MOB_ROBOTIC
- health = 15
- maxHealth = 15
- obj_damage = 0
- melee_damage_lower = 15
- melee_damage_upper = 15
- attacktext = "cuts"
- attack_sound = 'sound/weapons/bladeslice.ogg'
- faction = list(SYNDICATE)
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- mob_size = MOB_SIZE_TINY
- bubble_icon = "syndibot"
- gold_core_spawnable = HOSTILE_SPAWN
- del_on_death = TRUE
- deathmessage = "is smashed into pieces!"
- initial_traits = list(TRAIT_FLYING)
-
-/mob/living/simple_animal/hostile/viscerator/Initialize(mapload)
- . = ..()
- AddComponent(/datum/component/swarming)
-
#undef BLOOD_HELMET
#undef BLOOD_MASK
#undef BLOOD_ARMOR
diff --git a/code/modules/procedural_mapping/mapGenerators/syndicate_mapgen.dm b/code/modules/procedural_mapping/mapGenerators/syndicate_mapgen.dm
index 0c6dfaef3b9..531eab4d8d4 100644
--- a/code/modules/procedural_mapping/mapGenerators/syndicate_mapgen.dm
+++ b/code/modules/procedural_mapping/mapGenerators/syndicate_mapgen.dm
@@ -18,7 +18,7 @@
clusterCheckFlags = MAP_GENERATOR_CLUSTER_CHECK_SAME_ATOMS
spawnableAtoms = list(/mob/living/simple_animal/hostile/syndicate = 50, \
/mob/living/simple_animal/hostile/syndicate/ranged = 20, \
- /mob/living/simple_animal/hostile/viscerator = 30)
+ /mob/living/basic/viscerator = 30)
spawnableTurfs = list()
// Generators
diff --git a/paradise.dme b/paradise.dme
index f768390df1b..58945e4edb3 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2466,6 +2466,7 @@
#include "code\modules\mob\living\basic\hostile\killertomato.dm"
#include "code\modules\mob\living\basic\hostile\pirate.dm"
#include "code\modules\mob\living\basic\hostile\skeleton_mob.dm"
+#include "code\modules\mob\living\basic\hostile\viscerator.dm"
#include "code\modules\mob\living\basic\hostile\soviet.dm"
#include "code\modules\mob\living\basic\hostile\alien\alien_mob_ai.dm"
#include "code\modules\mob\living\basic\hostile\alien\alien_mob_drone.dm"
@@ -2495,6 +2496,7 @@
#include "code\modules\mob\living\basic\nether_mobs\faithless.dm"
#include "code\modules\mob\living\basic\nether_mobs\migo.dm"
#include "code\modules\mob\living\basic\nether_mobs\nether_mobs.dm"
+#include "code\modules\mob\living\basic\retaliate\combat_drone.dm"
#include "code\modules\mob\living\basic\retaliate\clown.dm"
#include "code\modules\mob\living\basic\retaliate\kangaroo.dm"
#include "code\modules\mob\living\brain\brain_death.dm"
@@ -2713,7 +2715,6 @@
#include "code\modules\mob\living\simple_animal\hostile\mining\elites\herald.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining\elites\legionnaire.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining\elites\pandora.dm"
-#include "code\modules\mob\living\simple_animal\hostile\retaliate\combat_drone.dm"
#include "code\modules\mob\living\simple_animal\hostile\retaliate\fish.dm"
#include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm"
#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\actions.dm"
diff --git a/tools/ci/check_simplemob_additions.py b/tools/ci/check_simplemob_additions.py
index 56b8aff677d..ec2dacaf23d 100644
--- a/tools/ci/check_simplemob_additions.py
+++ b/tools/ci/check_simplemob_additions.py
@@ -124,7 +124,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/hostile/illusion/escape/cult",
"/mob/living/simple_animal/hostile/illusion/escape/stealth",
"/mob/living/simple_animal/hostile/illusion/mirage",
- "/mob/living/simple_animal/hostile/malf_drone",
"/mob/living/simple_animal/hostile/megafauna",
"/mob/living/simple_animal/hostile/megafauna/ancient_robot",
"/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner",
@@ -193,7 +192,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/hostile/syndicate/shield",
"/mob/living/simple_animal/hostile/tree",
"/mob/living/simple_animal/hostile/venus_human_trap",
- "/mob/living/simple_animal/hostile/viscerator",
"/mob/living/simple_animal/hostile/winter",
"/mob/living/simple_animal/hostile/winter/reindeer",
"/mob/living/simple_animal/hostile/winter/santa",