diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
index 9a6ba2b97df..1e073292fb1 100644
--- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
+++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
@@ -42,7 +42,7 @@
/area/ruin/unpowered/xenonest)
"n" = (
/obj/structure/alien/weeds,
-/mob/living/simple_animal/hostile/alien/lavaland,
+/mob/living/basic/alien/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"o" = (
@@ -60,7 +60,7 @@
/area/ruin/unpowered/xenonest)
"t" = (
/obj/structure/alien/weeds,
-/mob/living/simple_animal/hostile/alien/sentinel/lavaland,
+/mob/living/basic/alien/sentinel/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"u" = (
@@ -108,12 +108,12 @@
/area/ruin/unpowered/xenonest)
"E" = (
/obj/structure/alien/weeds,
-/mob/living/simple_animal/hostile/alien/drone/lavaland,
+/mob/living/basic/alien/drone/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"F" = (
/obj/structure/alien/weeds,
-/mob/living/simple_animal/hostile/alien/queen/large/lavaland,
+/mob/living/basic/alien/queen/large/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"G" = (
@@ -135,7 +135,7 @@
/area/ruin/unpowered/xenonest)
"K" = (
/obj/structure/alien/weeds/node,
-/mob/living/simple_animal/hostile/alien/drone/lavaland,
+/mob/living/basic/alien/drone/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"M" = (
@@ -155,7 +155,7 @@
"Q" = (
/obj/structure/alien/weeds,
/obj/effect/decal/cleanable/blood,
-/mob/living/simple_animal/hostile/alien/drone/lavaland,
+/mob/living/basic/alien/drone/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
"R" = (
@@ -164,7 +164,7 @@
/area/ruin/unpowered/xenonest)
"X" = (
/obj/structure/alien/weeds/node,
-/mob/living/simple_animal/hostile/alien/lavaland,
+/mob/living/basic/alien/lavaland,
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/derelict1.dmm b/_maps/map_files/RandomRuins/SpaceRuins/derelict1.dmm
index 97cf1402ced..320266f046e 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/derelict1.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/derelict1.dmm
@@ -73,7 +73,7 @@
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
/obj/effect/decal/remains/xeno,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plating/airless,
/area/ruin/space/unpowered)
"v" = (
@@ -85,13 +85,13 @@
/area/space/nearstation)
"F" = (
/obj/structure/alien/weeds/node,
-/mob/living/simple_animal/hostile/alien/maid,
+/mob/living/basic/alien/maid,
/turf/simulated/floor/plating/airless,
/area/ruin/space/unpowered)
"G" = (
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plating/airless,
/area/ruin/space/unpowered)
"I" = (
@@ -104,7 +104,7 @@
/obj/structure/alien/weeds,
/obj/structure/bed/nest,
/obj/effect/decal/remains/human,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plating/airless,
/area/ruin/space/unpowered)
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm b/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm
index 7277cfc6a9f..0b67401fe01 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/moonoutpost19.dmm
@@ -57,7 +57,7 @@
/area/ruin/space/moonbase19)
"aj" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plating{
icon_state = "asteroidplating"
},
@@ -1859,7 +1859,7 @@
/area/ruin/space/moonbase19)
"gh" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"gi" = (
@@ -2140,7 +2140,7 @@
/area/ruin/space/moonbase19)
"hc" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "cafeteria"
@@ -2583,7 +2583,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
icon_state = "white";
dir = 8
@@ -2739,7 +2739,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "caution"
@@ -3062,7 +3062,7 @@
/area/ruin/space/moonbase19)
"jC" = (
/obj/effect/mapping_helpers/turfs/damage,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plating,
/area/ruin/space/moonbase19)
"jD" = (
@@ -3517,7 +3517,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"lc" = (
@@ -3983,7 +3983,7 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"mW" = (
@@ -4251,7 +4251,7 @@
/obj/machinery/light/small{
dir = 1
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"nZ" = (
@@ -4309,7 +4309,7 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"on" = (
@@ -4327,7 +4327,7 @@
},
/area/ruin/space/moonbase19)
"op" = (
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "cafeteria"
@@ -4773,7 +4773,7 @@
/area/ruin/space/moonbase19)
"qc" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/plasteel{
icon_state = "caution";
dir = 8
@@ -5700,7 +5700,7 @@
/area/ruin/space/moonbase19)
"uf" = (
/obj/structure/window/reinforced,
-/mob/living/simple_animal/hostile/alien/drone,
+/mob/living/basic/alien/drone,
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "cafeteria"
@@ -6963,7 +6963,7 @@
},
/area/ruin/space/moonbase19)
"Aj" = (
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"Ak" = (
@@ -7925,7 +7925,7 @@
pixel_x = -1;
pixel_y = -5
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/obj/structure/cable{
icon_state = "4-8"
},
@@ -8085,7 +8085,7 @@
/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
dir = 4
},
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"Fe" = (
@@ -8158,7 +8158,7 @@
/area/ruin/space/moonbase19)
"Ft" = (
/obj/effect/turf_decal/stripes/corner,
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/obj/effect/decal/cleanable/blood/splatter,
/turf/simulated/floor/plasteel{
dir = 5;
@@ -8322,7 +8322,7 @@
/obj/structure/railing/cap{
dir = 9
},
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "cafeteria"
@@ -10451,7 +10451,7 @@
/turf/simulated/floor/carpet,
/area/ruin/space/moonbase19)
"Qk" = (
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"Ql" = (
@@ -11119,7 +11119,7 @@
/area/ruin/space/moonbase19)
"Tr" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
icon_state = "white";
dir = 8
@@ -11429,7 +11429,7 @@
},
/area/ruin/space/moonbase19)
"UD" = (
-/mob/living/simple_animal/hostile/alien/drone,
+/mob/living/basic/alien/drone,
/turf/simulated/floor/plasteel,
/area/ruin/space/moonbase19)
"UF" = (
@@ -12275,7 +12275,7 @@
"Yu" = (
/obj/structure/toilet/directional/north,
/obj/effect/decal/cleanable/vomit/green,
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/simulated/floor/plasteel{
icon_state = "freezerfloor"
},
@@ -12342,7 +12342,7 @@
/obj/structure/railing{
dir = 8
},
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/simulated/floor/catwalk,
/area/ruin/space/moonbase19)
"YL" = (
@@ -12424,7 +12424,7 @@
/area/ruin/space/moonbase19)
"Zf" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien/queen/large{
+/mob/living/basic/alien/queen/large{
melee_damage_upper = 35;
melee_damage_lower = 30
},
@@ -12527,7 +12527,7 @@
"Zw" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/obj/structure/cable{
icon_state = "1-2"
},
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 494b8068d6f..dc8bea108bf 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/submaps/telecomns_returns_submap.dmm
@@ -10,14 +10,14 @@
/turf/simulated/floor/engine,
/area/template_noop)
"cl" = (
-/mob/living/simple_animal/hostile/alien/queen/large,
+/mob/living/basic/alien/queen/large,
/turf/template_noop,
/area/template_noop)
"da" = (
/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/template_noop)
"dD" = (
-/mob/living/simple_animal/hostile/alien/sentinel,
+/mob/living/basic/alien/sentinel,
/turf/template_noop,
/area/template_noop)
"fm" = (
@@ -369,7 +369,7 @@
/turf/template_noop,
/area/template_noop)
"RE" = (
-/mob/living/simple_animal/hostile/alien/drone,
+/mob/living/basic/alien/drone,
/turf/template_noop,
/area/template_noop)
"RH" = (
@@ -387,7 +387,7 @@
/turf/simulated/floor/mineral/plastitanium/red,
/area/template_noop)
"Ul" = (
-/mob/living/simple_animal/hostile/alien,
+/mob/living/basic/alien,
/turf/template_noop,
/area/template_noop)
"Vd" = (
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/syndiecakesfactory.dmm b/_maps/map_files/RandomRuins/SpaceRuins/syndiecakesfactory.dmm
index e9985212a92..736647381b7 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/syndiecakesfactory.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/syndiecakesfactory.dmm
@@ -391,27 +391,6 @@
icon_state = "floorgrime"
},
/area/ruin/space/syndicakefactory)
-"qx" = (
-/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/alien/sentinel{
- animal_species = /mob/living/simple_animal/pet/dog;
- attack_sound = 'sound/weapons/bite.ogg';
- attacktext = "bites";
- damage_coeff = list("brute" = 1, "fire" = 1, "tox" = 1, "clone" = 1, "stamina" = 1, "oxy" = 1);
- death_sound = null;
- deathmessage = "";
- desc = "This is no longer a goodboy. Not anymore. He has seen too much.";
- icon = 'icons/mob/pets.dmi';
- icon_living = "corgi";
- icon_state = "corgi";
- name = "angry corgi";
- retreat_distance = 2;
- icon_dead = "corgi_dead"
- },
-/turf/simulated/floor/plasteel{
- icon_state = "cafeteria"
- },
-/area/ruin/space/syndicakefactory)
"qX" = (
/obj/machinery/conveyor/east{
id = "garbage";
@@ -1016,6 +995,12 @@
icon_state = "floorgrime"
},
/area/ruin/space/syndicakefactory)
+"MK" = (
+/mob/living/basic/alien/sentinel/corgi,
+/turf/simulated/floor/plasteel{
+ icon_state = "cafeteria"
+ },
+/area/ruin/space/syndicakefactory)
"MV" = (
/obj/structure/table/glass/reinforced/plastitanium,
/obj/item/storage/box/papersack{
@@ -1101,26 +1086,6 @@
},
/turf/simulated/floor/engine/airless,
/area/ruin/space/syndicakefactory)
-"OU" = (
-/mob/living/simple_animal/hostile/alien/sentinel{
- animal_species = /mob/living/simple_animal/pet/dog;
- attack_sound = 'sound/weapons/bite.ogg';
- attacktext = "bites";
- damage_coeff = list("brute" = 1, "fire" = 1, "tox" = 1, "clone" = 1, "stamina" = 1, "oxy" = 1);
- death_sound = null;
- deathmessage = "";
- desc = "This is no longer a goodboy. Not anymore. He has seen too much.";
- icon = 'icons/mob/pets.dmi';
- icon_living = "corgi";
- icon_state = "corgi";
- name = "angry corgi";
- retreat_distance = 2;
- icon_dead = "corgi_dead"
- },
-/turf/simulated/floor/plasteel{
- icon_state = "cafeteria"
- },
-/area/ruin/space/syndicakefactory)
"PH" = (
/obj/structure/railing,
/turf/simulated/floor/plasteel{
@@ -1298,21 +1263,7 @@
},
/area/ruin/space/syndicakefactory)
"YR" = (
-/mob/living/simple_animal/hostile/alien/sentinel{
- animal_species = /mob/living/simple_animal/pet/dog;
- attack_sound = 'sound/weapons/bite.ogg';
- attacktext = "bites";
- damage_coeff = list("brute" = 1, "fire" = 1, "tox" = 1, "clone" = 1, "stamina" = 1, "oxy" = 1);
- death_sound = null;
- deathmessage = "";
- desc = "This is no longer a goodboy. Not anymore. He has seen too much.";
- icon = 'icons/mob/pets.dmi';
- icon_living = "corgi";
- icon_state = "corgi";
- name = "angry corgi";
- retreat_distance = 2;
- icon_dead = "corgi_dead"
- },
+/mob/living/basic/alien/sentinel/corgi,
/turf/simulated/floor/grass,
/area/ruin/space/syndicakefactory)
"Zs" = (
@@ -1675,7 +1626,7 @@ oB
bn
bn
Iz
-qx
+oB
Kr
bG
TM
@@ -1716,7 +1667,7 @@ Vt
gx
DY
XZ
-bn
+MK
bG
uA
bG
@@ -1794,7 +1745,7 @@ wC
bn
Qv
oB
-bn
+MK
bn
bn
bn
@@ -1802,9 +1753,9 @@ oB
bn
bn
Kr
-bn
+MK
yV
-OU
+bn
oB
RO
wI
@@ -1830,7 +1781,7 @@ EJ
EJ
rJ
bn
-OU
+bn
bn
oH
EJ
diff --git a/code/__DEFINES/ai/blackboard_defines.dm b/code/__DEFINES/ai/blackboard_defines.dm
index cf9f76fd1dd..27c543720d5 100644
--- a/code/__DEFINES/ai/blackboard_defines.dm
+++ b/code/__DEFINES/ai/blackboard_defines.dm
@@ -165,6 +165,9 @@
// Misc
+/// Target define for cleaning
+#define BB_CLEAN_TARGET "BB_clean_target"
+
/// For /datum/ai_behavior/find_potential_targets, what if any field are we using currently
#define BB_FIND_TARGETS_FIELD(type) "BB_FIND_TARGETS_FIELD_[type]"
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm
index a99be14545f..fcd8e460392 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/ranged_skirmish.dm
@@ -19,7 +19,7 @@
/// How often will we try to perform our ranged attack?
/datum/ai_behavior/ranged_skirmish
action_cooldown = 0.5 SECONDS
- ///do we care about avoiding friendly fire?
+ /// Do we care about shooting friends?
var/avoid_friendly_fire = FALSE
/datum/ai_behavior/ranged_skirmish/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key, max_range, min_range)
@@ -44,6 +44,8 @@
var/distance = get_dist(controller.pawn, target)
if(distance > max_range || distance < min_range)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
+ if(avoid_friendly_fire && check_friendly_in_path(controller.pawn, target, targeting_strategy))
+ return AI_BEHAVIOR_DELAY
if(avoid_friendly_fire && check_friendly_in_path(controller.pawn, target, targeting_strategy))
return AI_BEHAVIOR_DELAY
diff --git a/code/datums/ai/basic_mobs/hunting_behavior/find_and_hunt_target.dm b/code/datums/ai/basic_mobs/hunting_behavior/find_and_hunt_target.dm
index 6aae13f7b4b..77aeef11270 100644
--- a/code/datums/ai/basic_mobs/hunting_behavior/find_and_hunt_target.dm
+++ b/code/datums/ai/basic_mobs/hunting_behavior/find_and_hunt_target.dm
@@ -50,3 +50,10 @@
hunt_targets = list(/obj/item/stack/ore)
hunt_chance = 90
hunt_range = 9
+
+/// Find and clean things
+/datum/ai_planning_subtree/find_and_hunt_target/clean
+ target_key = BB_CLEAN_TARGET
+ hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/clean
+ hunt_targets = list(/obj/effect/decal/cleanable)
+ hunt_range = 4
diff --git a/code/datums/ai/basic_mobs/hunting_behavior/hunt_target.dm b/code/datums/ai/basic_mobs/hunting_behavior/hunt_target.dm
index 4de9964d17b..8673b3addec 100644
--- a/code/datums/ai/basic_mobs/hunting_behavior/hunt_target.dm
+++ b/code/datums/ai/basic_mobs/hunting_behavior/hunt_target.dm
@@ -61,3 +61,8 @@
always_reset_target = TRUE
hunt_cooldown = 2 SECONDS
behavior_intent = INTENT_HELP
+
+/datum/ai_behavior/hunt_target/interact_with_target/clean
+ always_reset_target = TRUE
+ hunt_cooldown = 2 SECONDS
+ behavior_intent = INTENT_HELP
diff --git a/code/modules/mob/living/basic/basic_mob.dm b/code/modules/mob/living/basic/basic_mob.dm
index edc91d3a2c7..0bf5f76c411 100644
--- a/code/modules/mob/living/basic/basic_mob.dm
+++ b/code/modules/mob/living/basic/basic_mob.dm
@@ -162,7 +162,6 @@ RESTRICT_TYPE(/mob/living/basic)
var/ranged_burst_interval = 0.2 SECONDS
/// Time between bursts
var/ranged_cooldown = 2 SECONDS
-
/// What casing type is the projectile?
var/casing_type
/// What projectile do we shoot?
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_ai.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_ai.dm
new file mode 100644
index 00000000000..9c85b7ffa74
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_ai.dm
@@ -0,0 +1,91 @@
+/datum/ai_controller/basic_controller/alien
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/alien,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
+ )
+ ai_traits = AI_FLAG_PAUSE_DURING_DO_AFTER
+ movement_delay = 0.8 SECONDS
+
+/datum/ai_controller/basic_controller/alien/sentinel
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/alien,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/maintain_distance,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
+ /datum/ai_planning_subtree/ranged_skirmish,
+ )
+
+/datum/ai_controller/basic_controller/alien/corgi
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/maintain_distance,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
+ /datum/ai_planning_subtree/ranged_skirmish,
+ )
+
+/datum/ai_controller/basic_controller/alien/drone
+ idle_behavior = /datum/idle_behavior/idle_random_walk/plant_weeds
+
+/datum/ai_controller/basic_controller/alien/queen
+ idle_behavior = /datum/idle_behavior/idle_random_walk/plant_weeds/queen
+
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/alien,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/maintain_distance,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
+ /datum/ai_planning_subtree/ranged_skirmish,
+ )
+
+/datum/ai_controller/basic_controller/alien/maid
+ 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/find_and_hunt_target/clean,
+ )
+
+/**
+ * Alien projectile
+ * Try to avoid friendly fire, and has a 3 second delay.
+ */
+
+/datum/idle_behavior/idle_random_walk/plant_weeds
+ var/plant_cooldown = 30
+ var/plants_off = 0
+
+/datum/idle_behavior/idle_random_walk/plant_weeds/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller)
+ . = ..()
+ if(!.)
+ return .
+ plant_cooldown--
+ var/mob/living/basic/alien/alien_pawn = controller.pawn
+ if(alien_pawn.can_plant_weeds && !plants_off && plant_cooldown <= 0)
+ plant_cooldown = initial(plant_cooldown)
+ alien_pawn.spread_plants()
+
+/datum/idle_behavior/idle_random_walk/plant_weeds/queen
+ var/eggs_off = 0
+ var/egg_cooldown = 30
+
+/datum/idle_behavior/idle_random_walk/plant_weeds/queen/perform_idle_behavior(seconds_per_tick, datum/ai_controller/controller)
+ . = ..()
+ if(!.)
+ return .
+ egg_cooldown--
+ var/mob/living/basic/alien/alien_pawn = controller.pawn
+ if(alien_pawn.can_lay_eggs && !eggs_off && egg_cooldown <= 0)
+ egg_cooldown = initial(egg_cooldown)
+ alien_pawn.lay_eggs()
+
+/datum/ai_planning_subtree/random_speech/alien
+ speech_chance = 2
+ sound = list('sound/voice/hiss1.ogg', 'sound/voice/hiss2.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss4.ogg')
+ emote_hear = list("hisses.")
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_drone.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_drone.dm
new file mode 100644
index 00000000000..ac6ea807e8d
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_drone.dm
@@ -0,0 +1,12 @@
+/mob/living/basic/alien/drone
+ name = "alien drone"
+ icon_state = "aliend_running"
+ icon_living = "aliend_running"
+ icon_dead = "aliend_dead"
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+
+ ai_controller = /datum/ai_controller/basic_controller/alien/drone
+
+/mob/living/basic/alien/drone/lavaland
+ maximum_survivable_temperature = INFINITY
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_hunter.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_hunter.dm
new file mode 100644
index 00000000000..590d46fcb7d
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_hunter.dm
@@ -0,0 +1,71 @@
+/mob/living/basic/alien
+ name = "alien hunter"
+ desc = "Hiss!"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "alienh_running"
+ icon_living = "alienh_running"
+ icon_dead = "alienh_dead"
+ icon_gib = "syndicate_gib"
+ gender = FEMALE
+ speed = 0
+ status_flags = CANPUSH
+ basic_mob_flags = FLAMMABLE_MOB
+ butcher_results = list(/obj/item/food/monstermeat/xenomeat= 3, /obj/item/stack/sheet/animalhide/xeno = 1)
+ maxHealth = 125
+ health = 125
+ harm_intent_damage = 5
+ obj_damage = 60
+
+ melee_attack_cooldown_min = 1.5 SECONDS
+ melee_attack_cooldown_max = 2.5 SECONDS
+ speak_emote = list("hisses")
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+ attack_verb_continuous = "slashes"
+ attack_verb_simple = "slash"
+ environment_smash = ENVIRONMENT_SMASH_STRUCTURES
+
+ bubble_icon = "alien"
+ a_intent = INTENT_HARM
+ attack_sound = 'sound/weapons/bladeslice.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)
+ unsuitable_atmos_damage = 15
+ unsuitable_heat_damage = 20
+ faction = list("alien")
+ minimum_survivable_temperature = 0
+ see_in_dark = 8
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ death_sound = 'sound/voice/hiss6.ogg'
+ deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..."
+ step_type = FOOTSTEP_MOB_CLAW
+ loot = list(/obj/effect/decal/cleanable/blood/gibs/xeno/limb, /obj/effect/decal/cleanable/blood/gibs/xeno/core, /obj/effect/decal/cleanable/blood/xeno/splatter, /obj/effect/decal/cleanable/blood/gibs/xeno/body, /obj/effect/decal/cleanable/blood/gibs/xeno/down)
+
+ ai_controller = /datum/ai_controller/basic_controller/alien
+
+ /// Boolean on whether the xeno can plant weeds.
+ var/can_plant_weeds = TRUE
+ /// Boolean on whether the xeno can lay eggs.
+ var/can_lay_eggs = FALSE
+
+/mob/living/basic/alien/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/aggro_emote, emote_list = list("flutters"), emote_chance = 20)
+
+/mob/living/basic/alien/proc/spread_plants()
+ if(!isturf(loc) || isspaceturf(loc))
+ return
+ if(locate(/obj/structure/alien/weeds/node) in get_turf(src))
+ return
+ visible_message("[src] has planted some alien weeds!")
+ new /obj/structure/alien/weeds/node(loc)
+
+/mob/living/basic/alien/proc/lay_eggs()
+ if(!isturf(loc) || isspaceturf(loc))
+ return
+ if(locate(/obj/structure/alien/egg) in get_turf(src))
+ return
+ visible_message("[src] has laid an egg!")
+ new /obj/structure/alien/egg(loc)
+
+/mob/living/basic/alien/lavaland
+ maximum_survivable_temperature = INFINITY
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_maid.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_maid.dm
new file mode 100644
index 00000000000..a476d5f5b94
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_maid.dm
@@ -0,0 +1,43 @@
+/mob/living/basic/alien/maid
+ name = "lusty xenomorph maid"
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ a_intent = INTENT_HELP
+ friendly_verb_continuous = "caresses"
+ friendly_verb_simple = "caress"
+ obj_damage = 0
+ environment_smash = ENVIRONMENT_SMASH_NONE
+ gold_core_spawnable = HOSTILE_SPAWN
+ ai_controller = /datum/ai_controller/basic_controller/alien/maid
+ icon_state = "maid"
+ icon_living = "maid"
+ icon_dead = "maid_dead"
+ /// How fast do we clean?
+ var/cleanspeed = 15
+
+/mob/living/basic/alien/maid/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/ai_retaliate)
+
+/// Clean instead of attack.
+/mob/living/basic/alien/maid/early_melee_attack(atom/target, list/modifiers, ignore_cooldown)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ clean_target(target)
+ return FALSE
+
+/mob/living/basic/alien/maid/proc/clean_target(atom/target)
+ if(ishuman(target))
+ var/atom/movable/H = target
+ H.clean_blood()
+ visible_message("\The [src] polishes \the [target].")
+ return FALSE
+ target.cleaning_act(src, src, cleanspeed, text_description = ".") // LXM is both the user and the cleaning implement itself. Wow!
+
+/mob/living/basic/alien/maid/can_clean()
+ return TRUE
+
+/mob/living/basic/alien/maid/lavaland
+ maximum_survivable_temperature = INFINITY
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_queen.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_queen.dm
new file mode 100644
index 00000000000..242441696df
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_queen.dm
@@ -0,0 +1,34 @@
+/mob/living/basic/alien/queen
+ name = "alien queen"
+ icon_state = "alienq_running"
+ icon_living = "alienq_running"
+ icon_dead = "alienq_dead"
+ health = 250
+ maxHealth = 250
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ status_flags = NONE // can't shove the queen, kiddo.
+
+ ai_controller = /datum/ai_controller/basic_controller/alien/queen
+
+ is_ranged = TRUE
+ projectile_type = /obj/item/projectile/neurotox
+ projectile_sound = 'sound/weapons/pierce.ogg'
+ ranged_cooldown = 3 SECONDS
+
+/mob/living/basic/alien/queen/lavaland
+ maximum_survivable_temperature = INFINITY
+
+/mob/living/basic/alien/queen/large
+ name = "alien empress"
+ icon = 'icons/mob/alienlarge.dmi'
+ icon_state = "queen_s"
+ icon_living = "queen_s"
+ icon_dead = "queen_dead"
+ bubble_icon = "alienroyal"
+ maxHealth = 400
+ health = 400
+ mob_size = MOB_SIZE_LARGE
+
+/mob/living/basic/alien/queen/large/lavaland
+ maximum_survivable_temperature = INFINITY
diff --git a/code/modules/mob/living/basic/hostile/alien/alien_mob_sentinel.dm b/code/modules/mob/living/basic/hostile/alien/alien_mob_sentinel.dm
new file mode 100644
index 00000000000..3514258cf9b
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/alien/alien_mob_sentinel.dm
@@ -0,0 +1,37 @@
+/mob/living/basic/alien/sentinel
+ name = "alien sentinel"
+ icon_state = "aliens_running"
+ icon_living = "aliens_running"
+ icon_dead = "aliens_dead"
+ health = 150
+ maxHealth = 150
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+
+ ai_controller = /datum/ai_controller/basic_controller/alien/sentinel
+
+ is_ranged = TRUE
+ projectile_type = /obj/item/projectile/neurotox
+ projectile_sound = 'sound/weapons/pierce.ogg'
+ ranged_cooldown = 3 SECONDS
+
+/mob/living/basic/alien/sentinel/corgi
+ name = "angry corgi"
+ real_name = "angry corgi"
+ desc = "It's a corgi."
+ icon_state = "corgi"
+ icon_living = "corgi"
+ icon_dead = "corgi_dead"
+ icon = 'icons/mob/pets.dmi';
+ desc = "This is no longer a goodboy. Not anymore. He has seen too much.";
+ attack_sound = 'sound/weapons/bite.ogg';
+ attack_verb_continuous = "bites";
+ attack_verb_simple = "bites";
+ damage_coeff = list("brute" = 1, "fire" = 1, "tox" = 1, "clone" = 1, "stamina" = 1, "oxy" = 1);
+ death_sound = null;
+ deathmessage = "";
+
+ ai_controller = /datum/ai_controller/basic_controller/alien/corgi
+
+/mob/living/basic/alien/sentinel/lavaland
+ maximum_survivable_temperature = INFINITY
diff --git a/code/modules/mob/living/simple_animal/hostile/alien_types.dm b/code/modules/mob/living/simple_animal/hostile/alien_types.dm
deleted file mode 100644
index ab66a947f94..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/alien_types.dm
+++ /dev/null
@@ -1,180 +0,0 @@
-/mob/living/simple_animal/hostile/alien
- name = "alien hunter"
- desc = "Hiss!"
- icon = 'icons/mob/alien.dmi'
- icon_state = "alienh_running"
- icon_living = "alienh_running"
- icon_dead = "alienh_dead"
- icon_gib = "syndicate_gib"
- gender = FEMALE
- speed = 0
- butcher_results = list(/obj/item/food/monstermeat/xenomeat= 3, /obj/item/stack/sheet/animalhide/xeno = 1)
- maxHealth = 125
- health = 125
- harm_intent_damage = 5
- obj_damage = 60
- melee_damage_lower = 25
- melee_damage_upper = 25
- attacktext = "slashes"
- speak_emote = list("hisses")
- bubble_icon = "alien"
- a_intent = INTENT_HARM
- attack_sound = 'sound/weapons/bladeslice.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)
- unsuitable_atmos_damage = 15
- heat_damage_per_tick = 20
- faction = list("alien")
- minbodytemp = 0
- see_in_dark = 8
- lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- death_sound = 'sound/voice/hiss6.ogg'
- deathmessage = "lets out a waning guttural screech, green blood bubbling from its maw..."
- footstep_type = FOOTSTEP_MOB_CLAW
- loot = list(/obj/effect/decal/cleanable/blood/gibs/xeno/limb, /obj/effect/decal/cleanable/blood/gibs/xeno/core, /obj/effect/decal/cleanable/blood/xeno/splatter, /obj/effect/decal/cleanable/blood/gibs/xeno/body, /obj/effect/decal/cleanable/blood/gibs/xeno/down)
-
-/mob/living/simple_animal/hostile/alien/ListTargetsLazy()
- return ListTargets()
-
-/mob/living/simple_animal/hostile/alien/Aggro()
- . = ..()
- if(target)
- playsound(loc, 'sound/voice/hiss4.ogg', 70, TRUE)
-
-/mob/living/simple_animal/hostile/alien/drone
- name = "alien drone"
- icon_state = "aliend_running"
- icon_living = "aliend_running"
- icon_dead = "aliend_dead"
- melee_damage_lower = 15
- melee_damage_upper = 15
- var/plant_cooldown = 30
- var/plants_off = 0
-
-/mob/living/simple_animal/hostile/alien/drone/handle_automated_action()
- if(!..()) //AIStatus is off
- return
- plant_cooldown--
- if(AIStatus == AI_IDLE)
- if(!plants_off && prob(10) && plant_cooldown<=0)
- plant_cooldown = initial(plant_cooldown)
- SpreadPlants()
-
-/mob/living/simple_animal/hostile/alien/sentinel
- name = "alien sentinel"
- icon_state = "aliens_running"
- icon_living = "aliens_running"
- icon_dead = "aliens_dead"
- health = 150
- maxHealth = 150
- melee_damage_lower = 15
- melee_damage_upper = 15
- ranged = TRUE
- retreat_distance = 5
- minimum_distance = 5
- projectiletype = /obj/item/projectile/neurotox
- projectilesound = 'sound/weapons/pierce.ogg'
-
-/mob/living/simple_animal/hostile/alien/queen
- name = "alien queen"
- icon_state = "alienq_running"
- icon_living = "alienq_running"
- icon_dead = "alienq_dead"
- health = 250
- maxHealth = 250
- melee_damage_lower = 15
- melee_damage_upper = 15
- ranged = TRUE
- retreat_distance = 5
- minimum_distance = 5
- move_to_delay = 4
- butcher_results = list(/obj/item/food/monstermeat/xenomeat= 4, /obj/item/stack/sheet/animalhide/xeno = 1)
- projectiletype = /obj/item/projectile/neurotox
- projectilesound = 'sound/weapons/pierce.ogg'
- status_flags = 0
- var/sterile = 1
- var/plants_off = 0
- var/egg_cooldown = 30
- var/plant_cooldown = 30
-
-/mob/living/simple_animal/hostile/alien/queen/handle_automated_action()
- if(!..())
- return
- egg_cooldown--
- plant_cooldown--
- if(AIStatus == AI_IDLE)
- if(!plants_off && prob(10) && plant_cooldown<=0)
- plant_cooldown = initial(plant_cooldown)
- SpreadPlants()
- if(!sterile && prob(10) && egg_cooldown<=0)
- egg_cooldown = initial(egg_cooldown)
- LayEggs()
-
-/mob/living/simple_animal/hostile/alien/proc/SpreadPlants()
- if(!isturf(loc) || isspaceturf(loc))
- return
- if(locate(/obj/structure/alien/weeds/node) in get_turf(src))
- return
- visible_message("[src] has planted some alien weeds!")
- new /obj/structure/alien/weeds/node(loc)
-
-/mob/living/simple_animal/hostile/alien/proc/LayEggs()
- if(!isturf(loc) || isspaceturf(loc))
- return
- if(locate(/obj/structure/alien/egg) in get_turf(src))
- return
- visible_message("[src] has laid an egg!")
- new /obj/structure/alien/egg(loc)
-
-/mob/living/simple_animal/hostile/alien/queen/large
- name = "alien empress"
- icon = 'icons/mob/alienlarge.dmi'
- icon_state = "queen_s"
- icon_living = "queen_s"
- icon_dead = "queen_dead"
- bubble_icon = "alienroyal"
- maxHealth = 400
- health = 400
- butcher_results = list(/obj/item/food/monstermeat/xenomeat= 10, /obj/item/stack/sheet/animalhide/xeno = 2)
- mob_size = MOB_SIZE_LARGE
-
-/obj/item/projectile/neurotox
- name = "neurotoxin"
- damage = 30
- icon_state = "toxin"
-
-/mob/living/simple_animal/hostile/alien/maid
- name = "lusty xenomorph maid"
- melee_damage_lower = 0
- melee_damage_upper = 0
- a_intent = INTENT_HELP
- friendly = "caresses"
- obj_damage = 0
- environment_smash = ENVIRONMENT_SMASH_NONE
- gold_core_spawnable = HOSTILE_SPAWN
- icon_state = "maid"
- icon_living = "maid"
- icon_dead = "maid_dead"
- var/cleanspeed = 15
-
-/mob/living/simple_animal/hostile/alien/maid/AttackingTarget()
- if(ishuman(target))
- var/atom/movable/H = target
- H.clean_blood()
- visible_message("\The [src] polishes \the [target].")
- return TRUE
- target.cleaning_act(src, src, cleanspeed, text_description = ".") //LXM is both the user and the cleaning implement itself. Wow!
-
-/mob/living/simple_animal/hostile/alien/maid/can_clean()
- return TRUE
-
-/mob/living/simple_animal/hostile/alien/lavaland
- maxbodytemp = INFINITY
-
-/mob/living/simple_animal/hostile/alien/drone/lavaland
- maxbodytemp = INFINITY
-
-/mob/living/simple_animal/hostile/alien/sentinel/lavaland
- maxbodytemp = INFINITY
-
-/mob/living/simple_animal/hostile/alien/queen/large/lavaland
- maxbodytemp = INFINITY
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index a1196b3a676..0893c4471c8 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -159,7 +159,7 @@
temp_img = icon('icons/obj/butts.dmi', "drone")
else if(isnymph(copymob))
temp_img = icon('icons/obj/butts.dmi', "nymph")
- else if(isalien(copymob) || istype(copymob,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro.
+ else if(isalien(copymob) || istype(copymob,/mob/living/basic/alien)) //Xenos have their own asses, thanks to Pybro.
temp_img = icon('icons/obj/butts.dmi', "xeno")
else
return
diff --git a/code/modules/projectiles/projectile/spit.dm b/code/modules/projectiles/projectile/spit.dm
new file mode 100644
index 00000000000..e61049179a2
--- /dev/null
+++ b/code/modules/projectiles/projectile/spit.dm
@@ -0,0 +1,4 @@
+/obj/item/projectile/neurotox
+ name = "neurotoxin"
+ damage = 30
+ icon_state = "toxin"
diff --git a/paradise.dme b/paradise.dme
index a07f3462628..2786e0d195e 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2445,6 +2445,12 @@
#include "code\modules\mob\living\basic\hostile\hivebot_ai.dm"
#include "code\modules\mob\living\basic\hostile\killertomato.dm"
#include "code\modules\mob\living\basic\hostile\skeleton_mob.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"
+#include "code\modules\mob\living\basic\hostile\alien\alien_mob_hunter.dm"
+#include "code\modules\mob\living\basic\hostile\alien\alien_mob_maid.dm"
+#include "code\modules\mob\living\basic\hostile\alien\alien_mob_queen.dm"
+#include "code\modules\mob\living\basic\hostile\alien\alien_mob_sentinel.dm"
#include "code\modules\mob\living\basic\mining\basilisk.dm"
#include "code\modules\mob\living\basic\mining\basilisk_ai.dm"
#include "code\modules\mob\living\basic\mining\hivelord.dm"
@@ -2651,7 +2657,6 @@
#include "code\modules\mob\living\simple_animal\friendly\nian_caterpillar.dm"
#include "code\modules\mob\living\simple_animal\friendly\pet.dm"
#include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm"
-#include "code\modules\mob\living\simple_animal\hostile\alien_types.dm"
#include "code\modules\mob\living\simple_animal\hostile\angel_statue.dm"
#include "code\modules\mob\living\simple_animal\hostile\bees.dm"
#include "code\modules\mob\living\simple_animal\hostile\deathsquid.dm"
@@ -2928,6 +2933,7 @@
#include "code\modules\projectiles\projectile\magic_projectiles.dm"
#include "code\modules\projectiles\projectile\reusable.dm"
#include "code\modules\projectiles\projectile\special_projectiles.dm"
+#include "code\modules\projectiles\projectile\spit.dm"
#include "code\modules\reagents\chem_splash.dm"
#include "code\modules\reagents\reagent_containers.dm"
#include "code\modules\reagents\reagent_dispenser.dm"