From 3a03e29187f97de6fb9940d70e365096a4a97318 Mon Sep 17 00:00:00 2001
From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Date: Thu, 31 Jul 2025 02:14:05 -0400
Subject: [PATCH] Converts hivebots to basic mob AI (#29849)
* Converts hivebots to basic mob AI
* Updatepaths
* Linters
* Hivebot beacon
* New linters
---------
Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
---
.../RandomRuins/SpaceRuins/oldstation.dmm | 92 ++++++-------
.../SpaceRuins/telecomns_returns.dmm | 4 +-
code/__DEFINES/ai/blackboard_defines.dm | 9 ++
.../mission_code/ruins/telecomns.dm | 22 +--
code/modules/mob/living/basic/basic_mob.dm | 13 ++
.../mob/living/basic/hostile/hivebot.dm | 96 +++++++++++++
.../mob/living/basic/hostile/hivebot_ai.dm | 128 ++++++++++++++++++
.../living/simple_animal/hostile/hivebot.dm | 102 --------------
paradise.dme | 3 +-
tools/UpdatePaths/Scripts/29849_hivebot.txt | 1 +
10 files changed, 309 insertions(+), 161 deletions(-)
create mode 100644 code/modules/mob/living/basic/hostile/hivebot.dm
create mode 100644 code/modules/mob/living/basic/hostile/hivebot_ai.dm
delete mode 100644 code/modules/mob/living/simple_animal/hostile/hivebot.dm
create mode 100644 tools/UpdatePaths/Scripts/29849_hivebot.txt
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/map_files/RandomRuins/SpaceRuins/oldstation.dmm
index 3a171529490..eb76ef87707 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/oldstation.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/oldstation.dmm
@@ -83,7 +83,7 @@
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"ap" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"aq" = (
@@ -222,7 +222,7 @@
"aM" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 8
},
@@ -522,7 +522,7 @@
/area/ruin/ancientstation)
"bI" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "whitecorner"
@@ -716,7 +716,7 @@
/area/ruin/ancientstation/engi)
"co" = (
/obj/effect/decal/cleanable/blood/oil,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"cs" = (
@@ -742,7 +742,7 @@
/obj/effect/decal/remains/robot{
icon_state = "gib2"
},
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"cw" = (
@@ -850,11 +850,11 @@
/obj/effect/decal/remains/robot{
icon_state = "gib5"
},
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"cL" = (
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"cM" = (
@@ -872,7 +872,7 @@
/area/ruin/ancientstation/atmo)
"cP" = (
/obj/effect/decal/cleanable/blood/oil,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"cQ" = (
@@ -1007,7 +1007,7 @@
"dm" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/structure/cable{
@@ -1054,7 +1054,7 @@
/obj/effect/decal/remains/robot{
icon_state = "gibup"
},
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel/dark,
/area/ruin/ancientstation/hivebot)
"dt" = (
@@ -1147,7 +1147,7 @@
/area/ruin/ancientstation/rnd)
"dH" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plating,
/area/ruin/ancientstation/thetacorridor)
"dI" = (
@@ -1162,7 +1162,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "4-8"
},
@@ -1175,7 +1175,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/obj/item/kirbyplants/large/dead,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"dL" = (
@@ -1411,7 +1411,7 @@
"ew" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"ex" = (
@@ -1426,7 +1426,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plating,
/area/ruin/ancientstation/thetacorridor)
"ez" = (
@@ -1534,7 +1534,7 @@
/area/ruin/ancientstation)
"eN" = (
/obj/machinery/door/firedoor,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/turf/simulated/floor/plasteel,
@@ -1991,7 +1991,7 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 10
},
@@ -2411,7 +2411,7 @@
/turf/simulated/floor/plating/airless,
/area/ruin/ancientstation/betanorth)
"hg" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/firealarm/directional/west,
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 4
@@ -2432,7 +2432,7 @@
},
/area/ruin/ancientstation/rnd)
"hj" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 5
},
@@ -2474,7 +2474,7 @@
"hn" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"ho" = (
@@ -2557,7 +2557,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
},
@@ -2618,7 +2618,7 @@
/area/ruin/ancientstation/hydroponics)
"hE" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 8
},
@@ -2717,7 +2717,7 @@
/area/ruin/ancientstation/rnd)
"hT" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel{
dir = 9;
icon_state = "whitepurple"
@@ -2847,7 +2847,7 @@
"ih" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "1-2"
},
@@ -3078,7 +3078,7 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
},
@@ -3626,13 +3626,13 @@
/area/ruin/ancientstation/thetacorridor)
"kL" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel/white,
/area/ruin/ancientstation/rnd)
"kM" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/door/firedoor,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
@@ -3650,13 +3650,13 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/obj/machinery/door/firedoor,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"kP" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot/strong,
+/mob/living/basic/hivebot/strong,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/rnd)
"kR" = (
@@ -3675,7 +3675,7 @@
/area/ruin/ancientstation/thetacorridor)
"kS" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"kT" = (
@@ -3780,7 +3780,7 @@
"lh" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/firealarm/directional/south,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
"li" = (
@@ -3849,7 +3849,7 @@
in_use = 1
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
},
@@ -3879,7 +3879,7 @@
/obj/structure/cable{
icon_state = "2-8"
},
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/manifold/hidden/supply,
/obj/effect/decal/cleanable/dirt,
@@ -4001,7 +4001,7 @@
/turf/simulated/floor/plating/airless,
/area/ruin/ancientstation/atmo)
"lK" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 6
},
@@ -4366,7 +4366,7 @@
/area/ruin/ancientstation/atmo)
"qj" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "1-2"
},
@@ -5425,7 +5425,7 @@
/area/ruin/ancientstation/thetacorridor)
"CN" = (
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "2-8"
},
@@ -5445,7 +5445,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
},
@@ -5715,7 +5715,7 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "4-8"
},
@@ -6084,7 +6084,7 @@
/area/space/nearstation)
"LB" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "1-2"
},
@@ -6195,7 +6195,7 @@
/turf/simulated/floor/plasteel/white,
/area/ruin/ancientstation/proto)
"MP" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/effect/decal/cleanable/dirt,
/obj/effect/spawner/random/cobweb/right/frequent,
/turf/simulated/floor/plating,
@@ -6338,7 +6338,7 @@
},
/area/ruin/ancientstation/engi)
"OW" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/effect/decal/cleanable/dirt,
/obj/machinery/light{
dir = 8
@@ -6464,7 +6464,7 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "2-4"
},
@@ -6539,7 +6539,7 @@
},
/area/ruin/ancientstation/comm)
"Ru" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/effect/decal/cleanable/dirt,
/turf/simulated/floor/plasteel,
/area/ruin/ancientstation/thetacorridor)
@@ -6898,7 +6898,7 @@
/obj/machinery/light,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/structure/cable{
icon_state = "4-8"
},
@@ -6977,7 +6977,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/machinery/door/firedoor,
/obj/structure/cable{
icon_state = "1-2"
@@ -7073,7 +7073,7 @@
/turf/simulated/floor/plating/airless,
/area/ruin/ancientstation/betanorth)
"Xq" = (
-/mob/living/simple_animal/hostile/hivebot,
+/mob/living/basic/hivebot,
/obj/effect/decal/cleanable/dirt,
/turf/simulated/floor/plating,
/area/ruin/ancientstation/thetacorridor)
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm b/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
index d371d1d7322..8fcfc730121 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/telecomns_returns.dmm
@@ -1393,7 +1393,7 @@
icon_state = "4-8"
},
/obj/machinery/recharge_station/upgraded,
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg,
+/mob/living/basic/hivebot/strong/malfborg,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "vault";
@@ -2471,7 +2471,7 @@
icon_state = "2-4"
},
/obj/machinery/recharge_station/upgraded,
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg,
+/mob/living/basic/hivebot/strong/malfborg,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "vault";
diff --git a/code/__DEFINES/ai/blackboard_defines.dm b/code/__DEFINES/ai/blackboard_defines.dm
index adb7f72e57a..ac248a6ff2c 100644
--- a/code/__DEFINES/ai/blackboard_defines.dm
+++ b/code/__DEFINES/ai/blackboard_defines.dm
@@ -85,6 +85,12 @@
/// key holding a range to look for vents (recommended: 10)
#define BB_VENT_SEARCH_RANGE "BB_VENT_SEARCH_RANGE"
+// Ranged
+/// Minimum range to keep target within
+#define BB_RANGED_SKIRMISH_MIN_DISTANCE "BB_ranged_skirmish_min_distance"
+/// Maximum range to keep target within
+#define BB_RANGED_SKIRMISH_MAX_DISTANCE "BB_ranged_skirmish_max_distance"
+
// Tipped blackboards
/// Bool that means a basic mob will start reacting to being tipped in its planning
@@ -143,6 +149,9 @@
/// List of strings used to apologize for attacking friends.
#define BB_OWNER_FRIENDLY_FIRE_APOLOGIES "BB_FF_APOLOGIES"
+// Hivebot keys
+/// the hivebot partner we will go communicate with
+#define BB_HIVE_PARTNER "BB_HIVE_PARTNER"
// Misc
diff --git a/code/modules/awaymissions/mission_code/ruins/telecomns.dm b/code/modules/awaymissions/mission_code/ruins/telecomns.dm
index 651019383f0..90ab71ac61b 100644
--- a/code/modules/awaymissions/mission_code/ruins/telecomns.dm
+++ b/code/modules/awaymissions/mission_code/ruins/telecomns.dm
@@ -324,7 +324,7 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank)
aggressive = TRUE
aggressive_tilt_chance = 100 //It will tip on you, and it will be funny.
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg
+/mob/living/basic/hivebot/strong/malfborg
name = "Security cyborg"
desc = "Oh god they still have access to these!"
icon = 'icons/mob/robots.dmi'
@@ -332,37 +332,39 @@ GLOBAL_LIST_EMPTY(telecomms_trap_tank)
health = 200
maxHealth = 200
faction = list("malf_drone")
- rapid = 2
speed = 0.5
- projectiletype = /obj/item/projectile/beam/disabler/weak
- projectilesound = 'sound/weapons/taser2.ogg'
+ projectile_type = /obj/item/projectile/beam/disabler/weak
+ projectile_sound = 'sound/weapons/taser2.ogg'
+ ranged_burst_count = 2
gold_core_spawnable = NO_SPAWN // Could you imagine xenobio with this? lmao.
a_intent = INTENT_HARM
var/obj/item/melee/baton/infinite_cell/baton = null // stunbaton bot uses to melee attack
+ ai_controller = /datum/ai_controller/basic_controller/simple/simple_skirmisher
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg/Initialize(mapload)
+/mob/living/basic/hivebot/strong/malfborg/Initialize(mapload)
. = ..()
baton = new(src)
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg/Destroy()
+/mob/living/basic/hivebot/strong/malfborg/Destroy()
QDEL_NULL(baton)
return ..()
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg/AttackingTarget()
+/mob/living/basic/hivebot/strong/malfborg/melee_attack(atom/target, list/modifiers, ignore_cooldown)
+ . = ..()
if(QDELETED(target))
return
face_atom(target)
baton.melee_attack_chain(src, target)
return TRUE
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
+/mob/living/basic/hivebot/strong/malfborg/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!used_item && !isturf(A))
used_item = baton
..()
-/mob/living/simple_animal/hostile/hivebot/strong/malfborg/emp_act(severity)
+/mob/living/basic/hivebot/strong/malfborg/emp_act(severity)
. = ..()
- target = null
+ ai_controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET)
adjustBruteLoss(50)
/obj/structure/displaycase/dvoraks_treat
diff --git a/code/modules/mob/living/basic/basic_mob.dm b/code/modules/mob/living/basic/basic_mob.dm
index 429f276be59..37a0859c706 100644
--- a/code/modules/mob/living/basic/basic_mob.dm
+++ b/code/modules/mob/living/basic/basic_mob.dm
@@ -154,6 +154,17 @@ RESTRICT_TYPE(/mob/living/basic)
/// Footsteps
var/step_type
+ /// Does this type do range attacks?
+ var/is_ranged = FALSE
+ /// How many shots in a burst?
+ var/ranged_burst_count = 1
+ /// How fast do we fire between bursts?
+ var/ranged_burst_interval = 0.2 SECONDS
+ /// What projectile do we shoot?
+ var/projectile_type
+ /// What sound does it make when firing?
+ var/projectile_sound
+
/mob/living/basic/Initialize(mapload)
. = ..()
@@ -164,6 +175,8 @@ RESTRICT_TYPE(/mob/living/basic)
apply_temperature_requirements()
if(step_type)
AddComponent(/datum/component/footstep, step_type)
+ if(is_ranged)
+ AddComponent(/datum/component/ranged_attacks, projectile_type = projectile_type, projectile_sound = projectile_sound, burst_shots = ranged_burst_count, burst_intervals = ranged_burst_interval)
/mob/living/basic/Destroy()
if(nest)
diff --git a/code/modules/mob/living/basic/hostile/hivebot.dm b/code/modules/mob/living/basic/hostile/hivebot.dm
new file mode 100644
index 00000000000..c01e6821d29
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/hivebot.dm
@@ -0,0 +1,96 @@
+/obj/item/projectile/hivebotbullet
+
+/mob/living/basic/hivebot
+ name = "Hivebot"
+ desc = "A small robot."
+ icon = 'icons/mob/hivebot.dmi'
+ icon_state = "basic"
+ icon_living = "basic"
+ icon_dead = "basic"
+ mob_biotypes = MOB_ROBOTIC
+ health = 15
+ maxHealth = 15
+ melee_damage_lower = 2
+ melee_damage_upper = 3
+ melee_attack_cooldown_min = 1.5 SECONDS
+ melee_attack_cooldown_max = 2.5 SECONDS
+ attack_verb_continuous = "claws"
+ attack_verb_simple = "claw"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ faction = list("hivebot")
+ 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
+ speak_emote = list("states")
+ gold_core_spawnable = HOSTILE_SPAWN
+ loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
+ death_message = "blows apart!"
+ bubble_icon = "machine"
+ basic_mob_flags = DEL_ON_DEATH
+ step_type = FOOTSTEP_MOB_CLAW
+ ai_controller = /datum/ai_controller/basic_controller/hivebot
+ projectile_type = /obj/item/projectile/hivebotbullet
+ projectile_sound = 'sound/weapons/gunshots/gunshot.ogg'
+
+/mob/living/basic/hivebot/range
+ desc = "A smallish robot, this one is armed!"
+ is_ranged = TRUE
+ ai_controller = /datum/ai_controller/basic_controller/hivebot/ranged
+
+/mob/living/basic/hivebot/rapid
+ is_ranged = TRUE
+ ranged_burst_count = 3
+ ai_controller = /datum/ai_controller/basic_controller/hivebot/ranged/rapid
+
+/mob/living/basic/hivebot/strong
+ name = "Strong Hivebot"
+ desc = "A robot, this one is armed and looks tough!"
+ health = 80
+ maxHealth = 80
+ is_ranged = TRUE
+ ai_controller = /datum/ai_controller/basic_controller/hivebot/ranged
+
+/mob/living/basic/hivebot/death(gibbed)
+ // Only execute the below if we successfully died
+ . = ..(gibbed)
+ if(!.)
+ return FALSE
+ do_sparks(3, 1, src)
+
+/mob/living/basic/hivebot/tele // Hivebot Telebeacon
+ name = "Beacon"
+ desc = "Some odd beacon thing."
+ icon_state = "def_radar-off"
+ icon_living = "def_radar-off"
+ health = 200
+ maxHealth = 200
+ status_flags = 0
+ anchored = TRUE
+ ai_controller = /datum/ai_controller/basic_controller/beacon
+ /// The total number of hivebots to spawn
+ var/bot_amt = 10
+
+/mob/living/basic/hivebot/tele/Initialize(mapload)
+ . = ..()
+ var/datum/effect_system/smoke_spread/smoke = new
+ smoke.set_up(5, FALSE, loc)
+ smoke.start()
+ visible_message("[src] warps in!")
+ playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1)
+
+/mob/living/basic/hivebot/tele/proc/warpbots()
+ icon_state = "def_radar"
+ visible_message("[src] turns on!")
+ while(bot_amt > 0)
+ bot_amt--
+ if(bot_amt > 3)
+ var/mob/living/basic/hivebot/H = new /mob/living/basic/hivebot(get_turf(src))
+ H.faction = faction
+ else if(bot_amt > 0)
+ var/mob/living/basic/hivebot/range/R = new /mob/living/basic/hivebot/range(get_turf(src))
+ R.faction = faction
+ else
+ var/mob/living/basic/hivebot/rapid/F = new /mob/living/basic/hivebot/rapid(get_turf(src))
+ F.faction = faction
+ spawn(100)
+ qdel(src)
+ return
diff --git a/code/modules/mob/living/basic/hostile/hivebot_ai.dm b/code/modules/mob/living/basic/hostile/hivebot_ai.dm
new file mode 100644
index 00000000000..e66e357c1a4
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/hivebot_ai.dm
@@ -0,0 +1,128 @@
+/datum/ai_controller/basic_controller/hivebot
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/hive_communicate,
+ )
+
+/datum/ai_controller/basic_controller/hivebot/ranged
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_ranged_attack_subtree/hivebot,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/hive_communicate,
+ )
+
+/datum/ai_controller/basic_controller/hivebot/ranged/rapid
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_ranged_attack_subtree/hivebot_rapid,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/hive_communicate,
+ )
+
+/datum/ai_planning_subtree/basic_ranged_attack_subtree/hivebot_rapid
+ ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/hivebot_rapid
+
+/datum/ai_planning_subtree/basic_ranged_attack_subtree/hivebot
+ ranged_attack_behavior = /datum/ai_behavior/basic_ranged_attack/hivebot
+
+/datum/ai_planning_subtree/hive_communicate
+ /// chance to go and relay message
+ var/relay_chance = 10
+
+/datum/ai_planning_subtree/hive_communicate/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
+
+ if(!SPT_PROB(relay_chance, seconds_per_tick))
+ return
+
+ if(controller.blackboard_key_exists(BB_HIVE_PARTNER))
+ controller.queue_behavior(/datum/ai_behavior/relay_message, BB_HIVE_PARTNER)
+ return SUBTREE_RETURN_FINISH_PLANNING
+ controller.queue_behavior(/datum/ai_behavior/find_and_set/hive_partner, BB_HIVE_PARTNER, /mob/living/basic/hivebot)
+
+/datum/ai_behavior/find_and_set/hive_partner
+
+/datum/ai_behavior/find_and_set/hive_partner/search_tactic(datum/ai_controller/controller, locate_path, search_range)
+ var/mob/living/living_pawn = controller.pawn
+ var/list/hive_partners = list()
+ for(var/mob/living/target in oview(10, living_pawn))
+ if(!istype(target, locate_path))
+ continue
+ if(target.stat == DEAD)
+ continue
+ hive_partners += target
+
+ if(length(hive_partners))
+ return pick(hive_partners)
+
+/// behavior that allow us to go communicate with other hivebots
+/datum/ai_behavior/relay_message
+ /// length of the message we will relay
+ var/length_of_message = 4
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT| AI_BEHAVIOR_REQUIRE_REACH | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
+
+/datum/ai_behavior/relay_message/setup(datum/ai_controller/controller, target_key)
+ . = ..()
+ var/mob/living/target = controller.blackboard[target_key]
+ // It stopped existing
+ if(QDELETED(target))
+ return FALSE
+ set_movement_target(controller, target)
+
+/datum/ai_behavior/relay_message/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
+ var/mob/living/target = controller.blackboard[target_key]
+ var/mob/living/living_pawn = controller.pawn
+
+ if(QDELETED(target))
+ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
+ var/message_relayed = ""
+ for(var/i in 1 to length_of_message)
+ message_relayed += prob(50) ? "1" : "0"
+ living_pawn.say(message_relayed)
+ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
+
+/datum/ai_behavior/relay_message/finish_action(datum/ai_controller/controller, succeeded, target_key)
+ . = ..()
+ controller.clear_blackboard_key(target_key)
+
+/datum/ai_behavior/basic_ranged_attack/hivebot
+ action_cooldown = 3 SECONDS
+ avoid_friendly_fire = TRUE
+
+/datum/ai_behavior/basic_ranged_attack/hivebot_rapid
+ action_cooldown = 1 SECONDS
+ avoid_friendly_fire = TRUE
+
+/datum/ai_controller/basic_controller/beacon
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = null
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/warpbots,
+ /datum/ai_planning_subtree/hive_communicate,
+ )
+
+/datum/ai_planning_subtree/warpbots
+ /// chance to summon hivebots
+ var/warp_chance = 2
+
+/datum/ai_planning_subtree/warpbots/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
+
+ if(!SPT_PROB(warp_chance, seconds_per_tick))
+ return
+
+ if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET))
+ var/mob/living/basic/hivebot/tele/beacon = controller.pawn
+ beacon.warpbots()
+ return SUBTREE_RETURN_FINISH_PLANNING
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
deleted file mode 100644
index def1d8d926d..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ /dev/null
@@ -1,102 +0,0 @@
-/obj/item/projectile/hivebotbullet
-
-/mob/living/simple_animal/hostile/hivebot
- name = "Hivebot"
- desc = "A small robot."
- icon = 'icons/mob/hivebot.dmi'
- icon_state = "basic"
- icon_living = "basic"
- icon_dead = "basic"
- mob_biotypes = MOB_ROBOTIC
- health = 15
- maxHealth = 15
- melee_damage_lower = 2
- melee_damage_upper = 3
- attacktext = "claws"
- attack_sound = 'sound/weapons/bladeslice.ogg'
- projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
- projectiletype = /obj/item/projectile/hivebotbullet
- faction = list("hivebot")
- check_friendly_fire = TRUE
- 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
- speak_emote = list("states")
- gold_core_spawnable = HOSTILE_SPAWN
- loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
- deathmessage = "blows apart!"
- bubble_icon = "machine"
- del_on_death = TRUE
- footstep_type = FOOTSTEP_MOB_CLAW
-
-/mob/living/simple_animal/hostile/hivebot/range
- desc = "A smallish robot, this one is armed!"
- ranged = TRUE
- retreat_distance = 5
- minimum_distance = 5
-
-/mob/living/simple_animal/hostile/hivebot/rapid
- ranged = TRUE
- rapid = 3
- retreat_distance = 5
- minimum_distance = 5
-
-/mob/living/simple_animal/hostile/hivebot/strong
- name = "Strong Hivebot"
- desc = "A robot, this one is armed and looks tough!"
- health = 80
- maxHealth = 80
- ranged = TRUE
-
-/mob/living/simple_animal/hostile/hivebot/death(gibbed)
- // Only execute the below if we successfully died
- . = ..(gibbed)
- if(!.)
- return FALSE
- do_sparks(3, 1, src)
-
-/mob/living/simple_animal/hostile/hivebot/tele
- name = "Beacon"
- desc = "Some odd beacon thing."
- icon_state = "def_radar-off"
- icon_living = "def_radar-off"
- health = 200
- maxHealth = 200
- status_flags = 0
- anchored = TRUE
- stop_automated_movement = TRUE
- var/bot_type = "norm"
- var/bot_amt = 10
- var/spawn_delay = 600
-
-/mob/living/simple_animal/hostile/hivebot/tele/Initialize(mapload)
- . = ..()
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(5, FALSE, loc)
- smoke.start()
- visible_message("[src] warps in!")
- playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1)
-
-/mob/living/simple_animal/hostile/hivebot/tele/proc/warpbots()
- icon_state = "def_radar"
- visible_message("[src] turns on!")
- while(bot_amt > 0)
- bot_amt--
- switch(bot_type)
- if("norm")
- var/mob/living/simple_animal/hostile/hivebot/H = new /mob/living/simple_animal/hostile/hivebot(get_turf(src))
- H.faction = faction
- if("range")
- var/mob/living/simple_animal/hostile/hivebot/range/R = new /mob/living/simple_animal/hostile/hivebot/range(get_turf(src))
- R.faction = faction
- if("rapid")
- var/mob/living/simple_animal/hostile/hivebot/rapid/F = new /mob/living/simple_animal/hostile/hivebot/rapid(get_turf(src))
- F.faction = faction
- spawn(100)
- qdel(src)
- return
-
-/mob/living/simple_animal/hostile/hivebot/tele/handle_automated_action()
- if(!..())
- return
- if(prob(2))//Might be a bit low, will mess with it likely
- warpbots()
diff --git a/paradise.dme b/paradise.dme
index c06bc1522e0..85034a94f7e 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2417,6 +2417,8 @@
#include "code\modules\mob\living\basic\hostile\bats.dm"
#include "code\modules\mob\living\basic\hostile\bear.dm"
#include "code\modules\mob\living\basic\hostile\carp.dm"
+#include "code\modules\mob\living\basic\hostile\hivebot.dm"
+#include "code\modules\mob\living\basic\hostile\hivebot_ai.dm"
#include "code\modules\mob\living\basic\hostile\skeleton_mob.dm"
#include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider.dm"
#include "code\modules\mob\living\basic\hostile\giant_spider\giant_spider_actions.dm"
@@ -2636,7 +2638,6 @@
#include "code\modules\mob\living\simple_animal\hostile\drakehound.dm"
#include "code\modules\mob\living\simple_animal\hostile\floorcluwne.dm"
#include "code\modules\mob\living\simple_animal\hostile\headslug.dm"
-#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"
#include "code\modules\mob\living\simple_animal\hostile\hostile.dm"
#include "code\modules\mob\living\simple_animal\hostile\illusion.dm"
#include "code\modules\mob\living\simple_animal\hostile\jungle_animals.dm"
diff --git a/tools/UpdatePaths/Scripts/29849_hivebot.txt b/tools/UpdatePaths/Scripts/29849_hivebot.txt
new file mode 100644
index 00000000000..28ee194ffa0
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/29849_hivebot.txt
@@ -0,0 +1 @@
+/mob/living/simple_animal/hostile/hivebot/@SUBTYPES : /mob/living/basic/hivebot/@SUBTYPES{@OLD}