From e14a43eea1e2238a96e053788c458e0770707c76 Mon Sep 17 00:00:00 2001
From: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Date: Wed, 1 Oct 2025 10:32:00 -0400
Subject: [PATCH] Basic diona nymphs, spiderbots, and crabs (#30377)
* Basic nymphs, spiderbots, and crabs
* Nutrition fix
* Forgot a line
* Cooldown on eat
---------
Signed-off-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
---
.../RandomRuins/SpaceRuins/abandonedzoo.dmm | 2 +-
_maps/map_files/stations/boxstation.dmm | 2 +-
_maps/map_files/stations/cerestation.dmm | 2 +-
_maps/map_files/stations/deltastation.dmm | 2 +-
_maps/map_files/stations/emeraldstation.dmm | 2 +-
_maps/map_files/templates/biodome_beach.dmm | 2 +-
code/__DEFINES/dcs/mob_signals.dm | 3 +
code/__DEFINES/mob_defines.dm | 2 +-
code/_onclick/hud/alert.dm | 8 +-
code/datums/elements/sideways_movement.dm | 27 +++
.../spell_targeting/matter_eater_targeting.dm | 4 +-
code/game/gamemodes/objective.dm | 2 +-
code/game/gamemodes/wizard/artefact.dm | 2 +-
code/game/objects/items/robot/robot_parts.dm | 2 +-
.../items/weapons/grenades/clusterbuster.dm | 2 +-
code/game/objects/structures/nest.dm | 2 +-
code/modules/admin/topic.dm | 4 +-
code/modules/events/clogged_disposals.dm | 4 +-
code/modules/hydroponics/beekeeping/beebox.dm | 2 +-
code/modules/hydroponics/grown.dm | 2 +-
code/modules/hydroponics/grown/nymph.dm | 2 +-
.../modules/mob/living/basic/friendly/crab.dm | 73 ++++++++
.../friendly/diona_nymph.dm | 164 ++++++++++++------
.../friendly/spiderbot.dm | 53 +++---
.../carbon/human/species/diona_species.dm | 2 +-
.../mob/living/carbon/human/species/kidan.dm | 2 +-
.../mob/living/carbon/human/species/unathi.dm | 3 +-
.../living/carbon/human/species/vulpkanin.dm | 3 +-
.../mob/living/simple_animal/friendly/crab.dm | 58 -------
.../simple_animal/friendly/friendly_emote.dm | 2 +-
code/modules/mob/mob_movement.dm | 2 +
.../projectile/magic_projectiles.dm | 2 +-
.../reagents/chemistry/reagents/toxins.dm | 2 +-
code/modules/research/strange_objects.dm | 4 +-
paradise.dme | 9 +-
tools/ci/check_simplemob_additions.py | 5 -
36 files changed, 281 insertions(+), 183 deletions(-)
create mode 100644 code/datums/elements/sideways_movement.dm
create mode 100644 code/modules/mob/living/basic/friendly/crab.dm
rename code/modules/mob/living/{simple_animal => basic}/friendly/diona_nymph.dm (59%)
rename code/modules/mob/living/{simple_animal => basic}/friendly/spiderbot.dm (78%)
delete mode 100644 code/modules/mob/living/simple_animal/friendly/crab.dm
diff --git a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm
index 9b351e76dc8..d1e3f6f9ae5 100644
--- a/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm
+++ b/_maps/map_files/RandomRuins/SpaceRuins/abandonedzoo.dmm
@@ -639,7 +639,7 @@
/turf/simulated/floor/plating,
/area/ruin/space/unpowered)
"bJ" = (
-/mob/living/simple_animal/crab{
+/mob/living/basic/crab{
faction = list("carp")
},
/turf/simulated/floor/plating,
diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm
index 8eee186cfc5..639ab4c30bc 100644
--- a/_maps/map_files/stations/boxstation.dmm
+++ b/_maps/map_files/stations/boxstation.dmm
@@ -13753,7 +13753,7 @@
},
/area/station/medical/reception)
"aWJ" = (
-/mob/living/simple_animal/crab/coffee,
+/mob/living/basic/crab/coffee,
/turf/simulated/floor/beach/water{
icon_state = "seadeep"
},
diff --git a/_maps/map_files/stations/cerestation.dmm b/_maps/map_files/stations/cerestation.dmm
index 3b3a2086bed..607878cb866 100644
--- a/_maps/map_files/stations/cerestation.dmm
+++ b/_maps/map_files/stations/cerestation.dmm
@@ -38555,7 +38555,7 @@
},
/area/station/security/permabrig)
"gUJ" = (
-/mob/living/simple_animal/crab{
+/mob/living/basic/crab{
desc = "The local trainer hired to keep the crew in shape by aggressively snipping at them.";
name = "Crabohydrates"
},
diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm
index 8bc75c9fd6a..c39d3cedc0d 100644
--- a/_maps/map_files/stations/deltastation.dmm
+++ b/_maps/map_files/stations/deltastation.dmm
@@ -51400,7 +51400,7 @@
/obj/structure/window/reinforced{
dir = 1
},
-/mob/living/simple_animal/crab/coffee,
+/mob/living/basic/crab/coffee,
/turf/simulated/floor/beach/water{
icon_state = "seadeep"
},
diff --git a/_maps/map_files/stations/emeraldstation.dmm b/_maps/map_files/stations/emeraldstation.dmm
index d94f69df2d1..fa9a1231cf1 100644
--- a/_maps/map_files/stations/emeraldstation.dmm
+++ b/_maps/map_files/stations/emeraldstation.dmm
@@ -81452,7 +81452,7 @@
},
/area/station/security/warden)
"pUT" = (
-/mob/living/simple_animal/crab/coffee,
+/mob/living/basic/crab/coffee,
/turf/simulated/floor/carpet/red,
/area/station/public/fitness)
"pUV" = (
diff --git a/_maps/map_files/templates/biodome_beach.dmm b/_maps/map_files/templates/biodome_beach.dmm
index a834e42917c..443c6bab1cf 100644
--- a/_maps/map_files/templates/biodome_beach.dmm
+++ b/_maps/map_files/templates/biodome_beach.dmm
@@ -284,7 +284,7 @@
/turf/simulated/floor/beach/sand,
/area/ruin/powered/beach)
"bz" = (
-/mob/living/simple_animal/crab,
+/mob/living/basic/crab,
/turf/simulated/floor/beach/sand,
/area/ruin/powered/beach)
"bA" = (
diff --git a/code/__DEFINES/dcs/mob_signals.dm b/code/__DEFINES/dcs/mob_signals.dm
index 7b713d27487..c3eb668e7fa 100644
--- a/code/__DEFINES/dcs/mob_signals.dm
+++ b/code/__DEFINES/dcs/mob_signals.dm
@@ -273,3 +273,6 @@
/// From base of /datum/action/cooldown/proc/set_statpanel_format(): (list/stat_panel_data)
#define COMSIG_ACTION_SET_STATPANEL "ability_set_statpanel"
+
+/// From base of /client/Move(): (direction, old_dir)
+#define COMSIG_MOB_CLIENT_MOVED "mob_client_moved"
diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm
index 13acb49f0bf..722ff1172e6 100644
--- a/code/__DEFINES/mob_defines.dm
+++ b/code/__DEFINES/mob_defines.dm
@@ -251,7 +251,7 @@
#define ismouse(A) (istype((A), /mob/living/basic/mouse))
#define isbot(A) (istype((A), /mob/living/simple_animal/bot))
#define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian))
-#define isnymph(A) (istype((A), /mob/living/simple_animal/diona))
+#define isnymph(A) (istype((A), /mob/living/basic/diona_nymph))
#define iscaterpillar(A) (istype((A), /mob/living/basic/nian_caterpillar))
#define ishostile(A) (istype((A), /mob/living/simple_animal/hostile))
#define isretaliate(A) (istype((A), /mob/living/simple_animal/hostile/retaliate))
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 787c2b65e66..d8e39ad3d0f 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -450,7 +450,7 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
if(!..())
return
if(isnymph(usr))
- var/mob/living/simple_animal/diona/D = usr
+ var/mob/living/basic/diona_nymph/D = usr
return D.resist()
/atom/movable/screen/alert/gestalt
@@ -462,14 +462,14 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the
return
var/list/nymphs = list()
- for(var/mob/living/simple_animal/diona/D in usr.contents)
+ for(var/mob/living/basic/diona_nymph/D in usr.contents)
nymphs += D
if(length(nymphs) == 1)
- var/mob/living/simple_animal/diona/D = nymphs[1]
+ var/mob/living/basic/diona_nymph/D = nymphs[1]
D.split(TRUE)
else
- var/mob/living/simple_animal/diona/D = tgui_input_list(usr, "Select a nymph to drop:", "Nymph Dropping", nymphs)
+ var/mob/living/basic/diona_nymph/D = tgui_input_list(usr, "Select a nymph to drop:", "Nymph Dropping", nymphs)
if(D in usr.contents)
D.split(TRUE)
diff --git a/code/datums/elements/sideways_movement.dm b/code/datums/elements/sideways_movement.dm
new file mode 100644
index 00000000000..435b31863e5
--- /dev/null
+++ b/code/datums/elements/sideways_movement.dm
@@ -0,0 +1,27 @@
+/// A simple element that forces the mob to face a perpendicular direction when moving, like crabs.
+/datum/element/sideways_movement
+
+/datum/element/sideways_movement/Attach(atom/movable/target)
+ . = ..()
+ if(!ismovable(target))
+ return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_MOB_CLIENT_MOVED, PROC_REF(on_client_move))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED_FROM_LOOP, PROC_REF(on_moved_from_loop))
+
+/datum/element/sideways_movement/proc/on_client_move(atom/movable/source, direction, old_dir)
+ SIGNAL_HANDLER
+ on_move(source, direction, old_dir)
+
+/datum/element/sideways_movement/proc/on_moved_from_loop(atom/movable/source, datum/move_loop/loop, old_dir, direction)
+ SIGNAL_HANDLER
+ if(!CHECK_MOVE_LOOP_FLAGS(source, MOVEMENT_LOOP_NO_DIR_UPDATE))
+ on_move(source, direction, old_dir)
+
+/// retain the old dir unless walking straight ahead or backward, in which case rotate the dir left or right by a 90°
+/datum/element/sideways_movement/proc/on_move(atom/movable/source, direction, old_dir)
+ if(!source.set_dir_on_move)
+ return
+ var/new_dir = old_dir
+ if(direction == old_dir || direction == REVERSE_DIR(old_dir))
+ new_dir = turn(source.dir, pick(90, -90))
+ source.setDir(new_dir)
diff --git a/code/datums/spell_targeting/matter_eater_targeting.dm b/code/datums/spell_targeting/matter_eater_targeting.dm
index b739c1a2930..48db830d147 100644
--- a/code/datums/spell_targeting/matter_eater_targeting.dm
+++ b/code/datums/spell_targeting/matter_eater_targeting.dm
@@ -8,7 +8,7 @@
/mob/living/simple_animal/pet,
/mob/living/simple_animal/hostile,
/mob/living/simple_animal/parrot,
- /mob/living/simple_animal/crab,
+ /mob/living/basic/crab,
/mob/living/basic/mouse,
/mob/living/carbon/human,
/mob/living/simple_animal/slime,
@@ -18,7 +18,7 @@
/mob/living/basic/chicken,
/mob/living/basic/lizard,
/mob/living/basic/cow,
- /mob/living/simple_animal/spiderbot
+ /mob/living/basic/spiderbot
)
var/list/own_blacklist = list(
/obj/item/organ,
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 4d5bbdcc099..b095d6475f9 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -183,7 +183,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/proc/is_special_dead(mob/target_current, check_silicon = TRUE)
if(check_silicon && issilicon(target_current))
return TRUE
- return isbrain(target_current) || istype(target_current, /mob/living/simple_animal/spiderbot)
+ return isbrain(target_current) || istype(target_current, /mob/living/basic/spiderbot)
// Setup and return the objective target jobs list based on target department
/datum/objective/proc/setup_target_jobs()
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index cf55bc927ae..375db16bff9 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -156,7 +156,7 @@
/obj/item/veilrender/crabrender
name = "crab render"
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast aquarium."
- spawn_type = /mob/living/simple_animal/crab
+ spawn_type = /mob/living/basic/crab
spawn_amt = 10
activate_descriptor = "sea life"
rend_desc = "Gently wafting with the sounds of endless clacking."
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index ca486f85c65..96fbb028ded 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -409,7 +409,7 @@
to_chat(user, "You insert the flash into the eye socket!")
else if(istype(W, /obj/item/stock_parts/manipulator))
to_chat(user, "You install some manipulators and modify the head, creating a functional spider-bot!")
- new /mob/living/simple_animal/spiderbot(get_turf(loc))
+ new /mob/living/basic/spiderbot(get_turf(loc))
user.drop_item()
qdel(W)
qdel(src)
diff --git a/code/game/objects/items/weapons/grenades/clusterbuster.dm b/code/game/objects/items/weapons/grenades/clusterbuster.dm
index 706fb58cfb5..875ea7cf794 100644
--- a/code/game/objects/items/weapons/grenades/clusterbuster.dm
+++ b/code/game/objects/items/weapons/grenades/clusterbuster.dm
@@ -213,7 +213,7 @@
/obj/item/grenade/clusterbuster/crab
name = "\improper Crab Grenade"
desc = "Reserved for those pesky request."
- payload = /mob/living/simple_animal/crab
+ payload = /mob/living/basic/crab
/obj/item/grenade/clusterbuster/plasma
name = "\improper Plasma Cluster Grenade"
diff --git a/code/game/objects/structures/nest.dm b/code/game/objects/structures/nest.dm
index 46fdcd4a2ec..9220eacd61d 100644
--- a/code/game/objects/structures/nest.dm
+++ b/code/game/objects/structures/nest.dm
@@ -21,7 +21,7 @@
var/spawn_byproduct_max = 3 // Maximum number of item spawns
var/spawn_is_triggered = FALSE // This is set to TRUE once the nest is triggered, preventing multiple triggers; set it to FALSE to re-activate it
var/spawn_max = 2 // Maximum number of mob spawns
- var/spawn_mob_options = list(/mob/living/simple_animal/crab) // The nest picks one mob type of this list and spawns them
+ var/spawn_mob_options = list(/mob/living/basic/crab) // The nest picks one mob type of this list and spawns them
var/spawn_trigger_distance = 7 // The triggered nest will look this many tiles around itself to find other triggerable nests
/obj/structure/nest/Initialize(mapload)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index cb353198acd..ffed5945eb2 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -494,8 +494,8 @@
if("cat") M.change_mob_type( /mob/living/simple_animal/pet/cat , null, null, delmob, 1)
if("runtime") M.change_mob_type( /mob/living/simple_animal/pet/cat/runtime , null, null, delmob, 1)
if("corgi") M.change_mob_type( /mob/living/simple_animal/pet/dog/corgi , null, null, delmob, 1)
- if("crab") M.change_mob_type( /mob/living/simple_animal/crab , null, null, delmob, 1)
- if("coffee") M.change_mob_type( /mob/living/simple_animal/crab/coffee , null, null, delmob, 1)
+ if("crab") M.change_mob_type( /mob/living/basic/crab , null, null, delmob, 1)
+ if("coffee") M.change_mob_type( /mob/living/basic/crab/coffee , null, null, delmob, 1)
if("parrot") M.change_mob_type( /mob/living/simple_animal/parrot , null, null, delmob, 1)
if("polyparrot") M.change_mob_type( /mob/living/simple_animal/parrot/poly , null, null, delmob, 1)
if("constructarmoured") M.change_mob_type( /mob/living/simple_animal/hostile/construct/armoured , null, null, delmob, 1)
diff --git a/code/modules/events/clogged_disposals.dm b/code/modules/events/clogged_disposals.dm
index 3c90882656f..0a9d18a0073 100644
--- a/code/modules/events/clogged_disposals.dm
+++ b/code/modules/events/clogged_disposals.dm
@@ -48,9 +48,9 @@
/mob/living/basic/clown/goblin = 5,
/mob/living/basic/goat = 5,
// Friendly
+ /mob/living/basic/diona_nymph = 5,
+ /mob/living/basic/crab = 5,
/mob/living/basic/mouse = 5,
- /mob/living/simple_animal/diona = 5,
- /mob/living/simple_animal/crab = 5,
/mob/living/simple_animal/pet/dog/corgi = 5,
/mob/living/simple_animal/hostile/retaliate/carp/koi = 5
)
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index f3c10dbcf64..6b2363ca660 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -19,7 +19,7 @@
return FALSE
return TRUE
-/mob/living/simple_animal/diona/bee_friendly()
+/mob/living/basic/diona_nymph/bee_friendly()
return TRUE
/mob/living/carbon/human/bee_friendly()
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index dd7346661d3..e64a18418f6 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -200,7 +200,7 @@
// Diona Nymphs can eat these as well as weeds to gain nutrition.
/obj/item/food/grown/attack_animal(mob/living/simple_animal/M)
if(isnymph(M))
- var/mob/living/simple_animal/diona/D = M
+ var/mob/living/basic/diona_nymph/D = M
D.consume(src)
else
return ..()
diff --git a/code/modules/hydroponics/grown/nymph.dm b/code/modules/hydroponics/grown/nymph.dm
index eff1b44270a..0a3fcf6ce63 100644
--- a/code/modules/hydroponics/grown/nymph.dm
+++ b/code/modules/hydroponics/grown/nymph.dm
@@ -23,7 +23,7 @@
if(..())
return ITEM_INTERACT_COMPLETE
- new /mob/living/simple_animal/diona(get_turf(user))
+ new /mob/living/basic/diona_nymph(get_turf(user))
to_chat(user, "You crack open [src], letting the nymph out.")
user.drop_item()
qdel(src)
diff --git a/code/modules/mob/living/basic/friendly/crab.dm b/code/modules/mob/living/basic/friendly/crab.dm
new file mode 100644
index 00000000000..6affd81e25b
--- /dev/null
+++ b/code/modules/mob/living/basic/friendly/crab.dm
@@ -0,0 +1,73 @@
+//Look Sir, free crabs!
+/mob/living/basic/crab
+ name = "crab"
+ desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
+ icon_state = "crab"
+ icon_living = "crab"
+ icon_dead = "crab_dead"
+ speak_emote = list("clicks")
+ butcher_results = list(/obj/item/food/meat = 1)
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "pushes"
+ response_disarm_simple = "push"
+ response_harm_continuous = "stomps"
+ response_harm_simple = "stomp"
+ friendly_verb_continuous = "pinches"
+ friendly_verb_simple = "pinch"
+ ventcrawler = VENTCRAWLER_ALWAYS
+ can_hide = TRUE
+ gold_core_spawnable = FRIENDLY_SPAWN
+
+ ai_controller = /datum/ai_controller/basic_controller/crab
+
+/mob/living/basic/crab/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/wears_collar)
+ AddElement(/datum/element/ai_retaliate)
+ AddElement(/datum/element/sideways_movement)
+
+/mob/living/basic/crab/valid_respawn_target_for(mob/user)
+ . = ..()
+ return TRUE
+
+// COFFEE! SQUEEEEEEEEE!
+/mob/living/basic/crab/coffee
+ name = "Coffee"
+ real_name = "Coffee"
+ desc = "It's Coffee, the other pet!"
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/basic/crab/evil
+ name = "Evil Crab"
+ real_name = "Evil Crab"
+ desc = "Unnerving, isn't it? It has to be planning something nefarious..."
+ icon_state = "evilcrab"
+ icon_living = "evilcrab"
+ icon_dead = "evilcrab_dead"
+ response_help_continuous = "pokes"
+ response_help_simple = "poke"
+ response_disarm_continuous = "shoves"
+ response_disarm_simple = "shove"
+ gold_core_spawnable = HOSTILE_SPAWN
+
+/// Crabs don't do much, but they want to live. They will flee when attacked, but will opportunistically melee attack people who do
+/datum/ai_controller/basic_controller/crab
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+ ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED | AI_FLAG_PAUSE_DURING_DO_AFTER
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee,
+ /datum/ai_planning_subtree/flee_target,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/opportunistic,
+ /datum/ai_planning_subtree/random_speech/crab,
+ )
+
+
+/datum/ai_planning_subtree/random_speech/crab
+ speech_chance = 5
+ emote_hear = list("clicks")
+ emote_see = list("clacks")
diff --git a/code/modules/mob/living/simple_animal/friendly/diona_nymph.dm b/code/modules/mob/living/basic/friendly/diona_nymph.dm
similarity index 59%
rename from code/modules/mob/living/simple_animal/friendly/diona_nymph.dm
rename to code/modules/mob/living/basic/friendly/diona_nymph.dm
index 29ad8d58d41..e0b59211026 100644
--- a/code/modules/mob/living/simple_animal/friendly/diona_nymph.dm
+++ b/code/modules/mob/living/basic/friendly/diona_nymph.dm
@@ -6,7 +6,7 @@
#define GESTALT_ALERT "gestalt screen alert"
#define NYMPH_ALERT "nymph screen alert"
-/mob/living/simple_animal/diona
+/mob/living/basic/diona_nymph
name = "diona nymph"
icon = 'icons/mob/monkey.dmi'
icon_state = "nymph"
@@ -18,94 +18,111 @@
mob_size = MOB_SIZE_SMALL
ventcrawler = VENTCRAWLER_ALWAYS
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
maxHealth = 50
health = 50
voice_name = "diona nymph"
speak_emote = list("chirrups")
- emote_hear = list("chirrups")
- emote_see = list("chirrups")
- response_help = "pets"
- response_disarm = "pushes"
- response_harm = "kicks"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "pushes"
+ response_disarm_simple = "push"
+ response_harm_continuous = "kicks"
+ response_harm_simple = "kick"
melee_damage_lower = 5
melee_damage_upper = 8
- attacktext = "bites"
+ melee_attack_cooldown_min = 1.5 SECONDS
+ melee_attack_cooldown_max = 2.5 SECONDS
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
attack_sound = 'sound/weapons/bite.ogg'
- speed = 0
- turns_per_move = 4
+ ai_controller = /datum/ai_controller/basic_controller/diona_nymph
var/list/donors = list()
holder_type = /obj/item/holder/diona
- var/evolve_donors = 5 //amount of blood donors needed before evolving
- var/awareness_donors = 3 //amount of blood donors needed for understand language
- var/nutrition_need = 500 //amount of nutrition needed before evolving
+ /// Amount of blood donors needed to evolve
+ var/evolve_donors = 5
+ /// Amount of blood donors needed for understand language
+ var/awareness_donors = 3
+ /// Amount of nutrition needed before evolving
+ var/nutrition_need = 500
+ /// List of stuff (mice) that we want to eat
+ var/static/list/edibles = list(
+ /obj/item/food/grown,
+ )
- var/datum/action/innate/diona/merge/merge_action = new()
- var/datum/action/innate/diona/evolve/evolve_action = new()
- var/datum/action/innate/diona/steal_blood/steal_blood_action = new()
+ var/datum/action/innate/diona_nymph/merge/merge_action = new()
+ var/datum/action/innate/diona_nymph/evolve/evolve_action = new()
+ var/datum/action/innate/diona_nymph/steal_blood/steal_blood_action = new()
-/mob/living/simple_animal/diona/Initialize(mapload)
+/mob/living/basic/diona_nymph/Initialize(mapload)
. = ..()
AddElement(/datum/element/wears_collar)
- if(name == initial(name)) //To stop named dionas becoming generic.
+ if(name == initial(name)) // To stop named dionas becoming generic.
name = "[name] ([rand(1, 1000)])"
real_name = name
add_language("Rootspeak")
merge_action.Grant(src)
evolve_action.Grant(src)
steal_blood_action.Grant(src)
+ AddElement(/datum/element/ai_retaliate)
+ AddElement(/datum/element/basic_eating, heal_amt_ = 2, food_types_ = edibles)
+ RegisterSignal(src, COMSIG_MOB_PRE_EAT, PROC_REF(check_full))
+ RegisterSignal(src, COMSIG_MOB_ATE, PROC_REF(consume))
+ ai_controller.set_blackboard_key(BB_BASIC_FOODS, typecacheof(edibles))
-/datum/action/innate/diona/merge
+/datum/action/innate/diona_nymph/merge
name = "Merge with gestalt"
button_icon = 'icons/mob/human_races/r_diona.dmi'
button_icon_state = "preview"
-/datum/action/innate/diona/merge/Activate()
- var/mob/living/simple_animal/diona/user = owner
+/datum/action/innate/diona_nymph/merge/Activate()
+ var/mob/living/basic/diona_nymph/user = owner
user.merge()
-/datum/action/innate/diona/evolve
+/datum/action/innate/diona_nymph/evolve
name = "Evolve"
button_icon = 'icons/obj/cloning.dmi'
button_icon_state = "pod_cloning"
-/datum/action/innate/diona/evolve/Activate()
- var/mob/living/simple_animal/diona/user = owner
+/datum/action/innate/diona_nymph/evolve/Activate()
+ var/mob/living/basic/diona_nymph/user = owner
user.evolve()
-/datum/action/innate/diona/steal_blood
+/datum/action/innate/diona_nymph/steal_blood
name = "Steal blood"
button_icon = 'icons/goonstation/objects/iv.dmi'
button_icon_state = "bloodbag"
-/datum/action/innate/diona/steal_blood/Activate()
- var/mob/living/simple_animal/diona/user = owner
+/datum/action/innate/diona_nymph/steal_blood/Activate()
+ var/mob/living/basic/diona_nymph/user = owner
user.steal_blood()
-/mob/living/simple_animal/diona/UnarmedAttack(atom/A)
- if(isdiona(A) && (src in A.contents)) //can't attack your gestalt
+/mob/living/basic/diona_nymph/UnarmedAttack(atom/A)
+ // Can't attack your gestalt
+ if(isdiona(A) && (src in A.contents))
visible_message("[src] wiggles around a bit.")
else
..()
-/mob/living/simple_animal/diona/run_resist()
+/mob/living/basic/diona_nymph/run_resist()
if(!split())
..()
-/mob/living/simple_animal/diona/attack_hand(mob/living/carbon/human/M)
- //Let people pick the little buggers up.
+/mob/living/basic/diona_nymph/attack_hand(mob/living/carbon/human/M)
+ // Let people pick the little buggers up.
if(M.a_intent == INTENT_HELP)
if(isdiona(M))
to_chat(M, "You feel your being twine with that of [src] as it merges with your biomass.")
to_chat(src, "You feel your being twine with that of [M] as you merge with its biomass.")
- throw_alert(GESTALT_ALERT, /atom/movable/screen/alert/nymph, new_master = src) //adds a screen alert that can call resist
+ // adds a screen alert that can call resist
+ throw_alert(GESTALT_ALERT, /atom/movable/screen/alert/nymph, new_master = src)
M.throw_alert(NYMPH_ALERT, /atom/movable/screen/alert/gestalt, new_master = src)
forceMove(M)
else if(isrobot(M))
@@ -115,7 +132,7 @@
else
..()
-/mob/living/simple_animal/diona/proc/merge()
+/mob/living/basic/diona_nymph/proc/merge()
if(stat != CONSCIOUS)
return FALSE
@@ -131,7 +148,8 @@
var/mob/living/M = tgui_input_list(src, "Who do you wish to merge with?", "Nymph Merging", choices)
- if(!M || !src || !(Adjacent(M)) || stat != CONSCIOUS) //input can take a while, so re-validate
+ // input can take a while, so re-validate
+ if(!M || !src || !(Adjacent(M)) || stat != CONSCIOUS)
return FALSE
if(isdiona(M))
@@ -139,13 +157,14 @@
M.status_flags |= PASSEMOTES
to_chat(src, "You feel your being twine with that of [M] as you merge with its biomass.")
forceMove(M)
- throw_alert(GESTALT_ALERT, /atom/movable/screen/alert/nymph, new_master = src) //adds a screen alert that can call resist
+ // adds a screen alert that can call resist
+ throw_alert(GESTALT_ALERT, /atom/movable/screen/alert/nymph, new_master = src)
M.throw_alert(NYMPH_ALERT, /atom/movable/screen/alert/gestalt, new_master = src)
return TRUE
else
return FALSE
-/mob/living/simple_animal/diona/proc/split(forced = FALSE)
+/mob/living/basic/diona_nymph/proc/split(forced = FALSE)
if((stat != CONSCIOUS && !forced) || !isdiona(loc))
return FALSE
var/mob/living/carbon/human/D = loc
@@ -167,7 +186,7 @@
clear_alert(GESTALT_ALERT)
return TRUE
-/mob/living/simple_animal/diona/proc/evolve()
+/mob/living/basic/diona_nymph/proc/evolve()
if(stat != CONSCIOUS)
return FALSE
@@ -179,7 +198,7 @@
to_chat(src, "You need to binge on weeds in order to have the energy to grow...")
return FALSE
- if(isdiona(loc) && !split()) //if it's merged with diona, needs to able to split before evolving
+ if(isdiona(loc) && !split()) // if it's merged with diona, needs to able to split before evolving
return FALSE
visible_message("[src] begins to shift and quiver, and erupts in a shower of shed bark as it splits into a tangle of nearly a dozen new dionaea.","You begin to shift and quiver, feeling your awareness splinter. All at once, we consume our stored nutrients to surge with growth, splitting into a tangle of at least a dozen new dionaea. We have attained our gestalt form.")
@@ -202,7 +221,7 @@
adult.name = "diona ([rand(100,999)])"
adult.real_name = adult.name
adult.ckey = ckey
- adult.real_name = adult.dna.species.get_random_name() //I hate this being here of all places but unfortunately dna is based on real_name!
+ adult.real_name = adult.dna.species.get_random_name() // I hate this being here of all places but unfortunately dna is based on real_name!
// [Nymph -> Diona] is from xenobio (or botany) and does not give vampires usuble blood and cannot be converted by cult.
ADD_TRAIT(adult.mind, TRAIT_XENOBIO_SPAWNED_HUMAN, ROUNDSTART_TRAIT)
@@ -212,21 +231,21 @@
qdel(src)
return TRUE
-// Consumes plant matter other than weeds to evolve
-/mob/living/simple_animal/diona/proc/consume(obj/item/food/grown/G)
- if(nutrition >= nutrition_need) // Prevents griefing by overeating plant items without evolving.
+/mob/living/basic/diona_nymph/proc/check_full(datum/source, obj/item/potential_food)
+ SIGNAL_HANDLER // COMSIG_MOB_PRE_EAT
+ if(nutrition >= nutrition_need) // Prevents griefing by overeating food items without evolving.
to_chat(src, "You're too full to consume this! Perhaps it's time to grow bigger...")
- else
- if(do_after_once(src, 20, target = G))
- visible_message("[src] ravenously consumes [G].", "You ravenously devour [G].")
- playsound(loc, 'sound/items/eatfood.ogg', 30, FALSE, frequency = 1.5)
- if(G.reagents.get_reagent_amount("nutriment") + G.reagents.get_reagent_amount("plantmatter") < 1)
- adjust_nutrition(2)
- else
- adjust_nutrition((G.reagents.get_reagent_amount("nutriment") + G.reagents.get_reagent_amount("plantmatter")) * 2)
- qdel(G)
+ return COMSIG_MOB_TERMINATE_EAT
-/mob/living/simple_animal/diona/proc/steal_blood()
+// Consumes plant matter other than weeds to evolve
+/mob/living/basic/diona_nymph/proc/consume(datum/source, obj/item/potential_food)
+ SIGNAL_HANDLER // COMSIG_MOB_ATE
+ if(potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter") < 1)
+ adjust_nutrition(2)
+ else
+ adjust_nutrition((potential_food.reagents.get_reagent_amount("nutriment") + potential_food.reagents.get_reagent_amount("plantmatter")) * 2)
+
+/mob/living/basic/diona_nymph/proc/steal_blood()
if(stat != CONSCIOUS)
return FALSE
@@ -261,7 +280,7 @@
spawn(25)
update_progression()
-/mob/living/simple_animal/diona/proc/update_progression()
+/mob/living/basic/diona_nymph/proc/update_progression()
if(stat != CONSCIOUS || !length(donors))
return FALSE
@@ -274,20 +293,51 @@
to_chat(src, "The blood seeps into your small form, and you draw out the echoes of memories and personality from it, working them into your budding mind.")
-/mob/living/simple_animal/diona/put_in_hands(obj/item/W)
+/mob/living/basic/diona_nymph/put_in_hands(obj/item/W)
W.forceMove(get_turf(src))
W.layer = initial(W.layer)
W.plane = initial(W.plane)
W.dropped()
-/mob/living/simple_animal/diona/put_in_active_hand(obj/item/W)
+/mob/living/basic/diona_nymph/put_in_active_hand(obj/item/W)
to_chat(src, "You don't have any hands!")
return
-/mob/living/simple_animal/diona/npc_safe(mob/user)
+/mob/living/basic/diona_nymph/valid_respawn_target_for(mob/user)
if(!jobban_isbanned(user, ROLE_NYMPH))
return TRUE
return FALSE
+/// Diona nymphs want to eat plant matter to get to evolution stage, but won't evolve or sample blood on their own. They flee when attacked.
+/datum/ai_controller/basic_controller/diona_nymph
+ blackboard = list(
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+ ai_traits = AI_FLAG_STOP_MOVING_WHEN_PULLED | AI_FLAG_PAUSE_DURING_DO_AFTER
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/find_nearest_thing_which_attacked_me_to_flee,
+ /datum/ai_planning_subtree/flee_target,
+ /datum/ai_planning_subtree/find_food/diona_nymph,
+ /datum/ai_planning_subtree/random_speech/diona_nymph,
+ )
+
+/datum/ai_planning_subtree/find_food/diona_nymph
+
+/datum/ai_planning_subtree/find_food/diona_nymph/select_behaviors(datum/ai_controller/controller, seconds_per_tick)
+ var/mob/living/basic/diona_nymph/nymph = controller.pawn
+ if(nymph.nutrition >= nymph.nutrition_need)
+ // Put eating on cooldown so it doesn't keep trying to eat.
+ var/food_cooldown = controller.blackboard[BB_EAT_FOOD_COOLDOWN] || EAT_FOOD_COOLDOWN
+ controller.set_blackboard_key(BB_NEXT_FOOD_EAT, world.time + food_cooldown)
+ return SUBTREE_RETURN_FINISH_PLANNING
+ return ..()
+
+/datum/ai_planning_subtree/random_speech/diona_nymph
+ speech_chance = 5
+ emote_hear = list("chirrups.")
+ emote_see = list("chirrups.")
+
#undef GESTALT_ALERT
#undef NYMPH_ALERT
diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/basic/friendly/spiderbot.dm
similarity index 78%
rename from code/modules/mob/living/simple_animal/friendly/spiderbot.dm
rename to code/modules/mob/living/basic/friendly/spiderbot.dm
index 7146cfdc855..7e3fcc68aec 100644
--- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm
+++ b/code/modules/mob/living/basic/friendly/spiderbot.dm
@@ -1,11 +1,11 @@
-/mob/living/simple_animal/spiderbot
+// No AI controller for these guys - they should be inert if they're not player controlled.
+/mob/living/basic/spiderbot
name = "Spider-bot"
- desc = "A skittering robotic friend!" //More like ultimate shitter
+ desc = "A skittering robotic friend!" // More like ultimate shitter
icon = 'icons/mob/robots.dmi'
icon_state = "spiderbot-chassis"
icon_living = "spiderbot-chassis"
icon_dead = "spiderbot-smashed"
- wander = FALSE
universal_speak = TRUE
health = 40
maxHealth = 40
@@ -14,31 +14,38 @@
melee_damage_lower = 2
melee_damage_upper = 2
melee_damage_type = BURN
- attacktext = "shocks"
+ attack_verb_continuous = "shocks"
+ attack_verb_simple = "shocks"
attack_sound = "sparks"
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
+ response_help_continuous = "pets"
+ response_help_simple = "pet"
+ response_disarm_continuous = "shoos"
+ response_disarm_simple = "shoo"
+ response_harm_continuous = "stomps on"
+ response_harm_simple = "stomps on"
speed = 0
mob_biotypes = MOB_ROBOTIC
mob_size = MOB_SIZE_SMALL
- speak_emote = list("beeps","clicks","chirps")
+ speak_emote = list("beeps", "clicks", "chirps")
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
- maxbodytemp = 500
+ minimum_survivable_temperature = 0
+ maximum_survivable_temperature = 500
can_hide = TRUE
ventcrawler = VENTCRAWLER_ALWAYS
loot = list(/obj/effect/decal/cleanable/blood/gibs/robot)
- del_on_death = TRUE
+ basic_mob_flags = DEL_ON_DEATH
- var/emagged = FALSE //is it getting ready to explode?
+ /// Is it getting ready to explode?
+ var/emagged = FALSE
+ /// MMI it contains
var/obj/item/mmi/mmi = null
- var/mob/emagged_master = null //for administrative purposes, to see who emagged the spiderbot; also for a holder for if someone emags an empty frame first then inserts an MMI.
+ /// Who emagged the spiderbot
+ var/mob/emagged_master = null
-/mob/living/simple_animal/spiderbot/Destroy()
+/mob/living/basic/spiderbot/Destroy()
if(emagged)
QDEL_NULL(mmi)
explosion(get_turf(src), -1, -1, 3, 5, cause = "Emagged spiderbot destruction")
@@ -46,10 +53,10 @@
eject_brain()
return ..()
-/mob/living/simple_animal/spiderbot/item_interaction(mob/living/user, obj/item/O, list/modifiers)
+/mob/living/basic/spiderbot/item_interaction(mob/living/user, obj/item/O, list/modifiers)
if(istype(O, /obj/item/mmi))
var/obj/item/mmi/B = O
- if(mmi) //There's already a brain in it.
+ if(mmi) // There's already a brain in it.
to_chat(user, "There's already a brain in [src]!")
return ITEM_INTERACT_COMPLETE
if(!B.brainmob)
@@ -62,7 +69,7 @@
if(ghost.ghost_flags & GHOST_CAN_REENTER && ghost.mind == B.brainmob.mind)
ghost_can_reenter = 1
break
- for(var/mob/living/simple_animal/S in GLOB.player_list)
+ for(var/mob/living/basic/S in GLOB.player_list)
if(HAS_TRAIT(S, TRAIT_RESPAWNABLE))
ghost_can_reenter = 1
break
@@ -113,10 +120,10 @@
to_chat(user, "You swipe your card, with no effect.")
return ITEM_INTERACT_COMPLETE
-/mob/living/simple_animal/spiderbot/welder_act(mob/user, obj/item/I)
+/mob/living/basic/spiderbot/welder_act(mob/user, obj/item/I)
if(user.a_intent != INTENT_HELP)
return
- if(user == src) //No self-repair dummy
+ if(user == src) // No self-repair dummy
return
if(health >= maxHealth)
to_chat(user, "[src] does not need repairing!")
@@ -128,7 +135,7 @@
add_fingerprint(user)
user.visible_message("[user] repairs [src]!","You repair [src].")
-/mob/living/simple_animal/spiderbot/emag_act(mob/living/user)
+/mob/living/basic/spiderbot/emag_act(mob/living/user)
if(emagged)
to_chat(user, "[src] doesn't seem to respond.")
return 0
@@ -145,7 +152,7 @@
attack_sound = 'sound/machines/defib_zap.ogg'
return TRUE
-/mob/living/simple_animal/spiderbot/proc/transfer_personality(obj/item/mmi/M)
+/mob/living/basic/spiderbot/proc/transfer_personality(obj/item/mmi/M)
mind = M.brainmob.mind
mind.key = M.brainmob.key
ckey = M.brainmob.ckey
@@ -153,7 +160,7 @@
if(emagged)
to_chat(src, "You have been emagged; you are now completely loyal to [emagged_master] and [emagged_master.p_their()] every order!")
-/mob/living/simple_animal/spiderbot/update_icon_state()
+/mob/living/basic/spiderbot/update_icon_state()
if(mmi)
if(istype(mmi, /obj/item/mmi))
icon_state = "spiderbot-chassis-mmi"
@@ -166,7 +173,7 @@
icon_state = "spiderbot-chassis"
icon_living = "spiderbot-chassis"
-/mob/living/simple_animal/spiderbot/proc/eject_brain()
+/mob/living/basic/spiderbot/proc/eject_brain()
if(mmi)
var/turf/T = get_turf(src)
mmi.forceMove(T)
diff --git a/code/modules/mob/living/carbon/human/species/diona_species.dm b/code/modules/mob/living/carbon/human/species/diona_species.dm
index a0737965222..dfb892d88ec 100644
--- a/code/modules/mob/living/carbon/human/species/diona_species.dm
+++ b/code/modules/mob/living/carbon/human/species/diona_species.dm
@@ -77,7 +77,7 @@
. = ..()
H.clear_alert("nolight")
- for(var/mob/living/simple_animal/diona/N in H.contents) // Let nymphs wiggle out
+ for(var/mob/living/basic/diona_nymph/N in H.contents) // Let nymphs wiggle out
N.split()
/datum/species/diona/handle_reagents(mob/living/carbon/human/H, datum/reagent/R)
diff --git a/code/modules/mob/living/carbon/human/species/kidan.dm b/code/modules/mob/living/carbon/human/species/kidan.dm
index 70eb61d77a9..0de8da4dcba 100644
--- a/code/modules/mob/living/carbon/human/species/kidan.dm
+++ b/code/modules/mob/living/carbon/human/species/kidan.dm
@@ -38,7 +38,7 @@
"lantern" = /obj/item/organ/internal/lantern
)
- allowed_consumed_mobs = list(/mob/living/simple_animal/diona)
+ allowed_consumed_mobs = list(/mob/living/basic/diona_nymph)
suicide_messages = list(
"is attempting to bite their antenna off!",
diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm
index f9b4222f7fa..4f1537c1705 100644
--- a/code/modules/mob/living/carbon/human/species/unathi.dm
+++ b/code/modules/mob/living/carbon/human/species/unathi.dm
@@ -47,13 +47,12 @@
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/unathi //3 darksight.
)
-
allowed_consumed_mobs = list(
/mob/living/basic/mouse,
/mob/living/basic/lizard,
/mob/living/basic/chick,
/mob/living/basic/chicken,
- /mob/living/simple_animal/crab,
+ /mob/living/basic/crab,
/mob/living/basic/butterfly,
/mob/living/simple_animal/parrot,
/mob/living/simple_animal/hostile/poison/bees,
diff --git a/code/modules/mob/living/carbon/human/species/vulpkanin.dm b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
index 89c68723816..fff950cae47 100644
--- a/code/modules/mob/living/carbon/human/species/vulpkanin.dm
+++ b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
@@ -37,13 +37,12 @@
"eyes" = /obj/item/organ/internal/eyes/vulpkanin /*Most Vulpkanin see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2)
unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/
)
-
allowed_consumed_mobs = list(
/mob/living/basic/mouse,
/mob/living/basic/lizard,
/mob/living/basic/chick,
/mob/living/basic/chicken,
- /mob/living/simple_animal/crab,
+ /mob/living/basic/crab,
/mob/living/basic/butterfly,
/mob/living/simple_animal/parrot,
/mob/living/simple_animal/hostile/poison/bees,
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
deleted file mode 100644
index 20e44fa3743..00000000000
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ /dev/null
@@ -1,58 +0,0 @@
-//Look Sir, free crabs!
-/mob/living/simple_animal/crab
- name = "crab"
- desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
- icon_state = "crab"
- icon_living = "crab"
- icon_dead = "crab_dead"
- speak_emote = list("clicks")
- emote_hear = list("clicks")
- emote_see = list("clacks")
- speak_chance = 1
- turns_per_move = 5
- butcher_results = list(/obj/item/food/meat = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
- stop_automated_movement = TRUE
- friendly = "pinches"
- ventcrawler = VENTCRAWLER_ALWAYS
- can_hide = TRUE
- gold_core_spawnable = FRIENDLY_SPAWN
-
-/mob/living/simple_animal/crab/Initialize(mapload)
- . = ..()
- AddElement(/datum/element/wears_collar)
-
-/mob/living/simple_animal/crab/handle_automated_movement()
- //CRAB movement
- if(stat == CONSCIOUS || !isturf(loc) || IS_HORIZONTAL(src) || buckled)
- return
-
- turns_since_move++
- if(turns_since_move >= turns_per_move)
- var/east_vs_west = pick(4, 8)
- if(Process_Spacemove(east_vs_west))
- Move(get_step(src, east_vs_west), east_vs_west)
-
-/mob/living/simple_animal/crab/npc_safe(mob/user)
- return TRUE
-
-//COFFEE! SQUEEEEEEEEE!
-/mob/living/simple_animal/crab/coffee
- name = "Coffee"
- real_name = "Coffee"
- desc = "It's Coffee, the other pet!"
- gold_core_spawnable = NO_SPAWN
- unique_pet = TRUE
-
-/mob/living/simple_animal/crab/evil
- name = "Evil Crab"
- real_name = "Evil Crab"
- desc = "Unnerving, isn't it? It has to be planning something nefarious..."
- icon_state = "evilcrab"
- icon_living = "evilcrab"
- icon_dead = "evilcrab_dead"
- response_help = "pokes"
- response_disarm = "shoves"
- gold_core_spawnable = HOSTILE_SPAWN
diff --git a/code/modules/mob/living/simple_animal/friendly/friendly_emote.dm b/code/modules/mob/living/simple_animal/friendly/friendly_emote.dm
index 3ce84e6cfdb..92a6913dd0e 100644
--- a/code/modules/mob/living/simple_animal/friendly/friendly_emote.dm
+++ b/code/modules/mob/living/simple_animal/friendly/friendly_emote.dm
@@ -7,7 +7,7 @@
message = "chirps!"
sound = "sound/creatures/nymphchirp.ogg"
emote_type = EMOTE_AUDIBLE
- mob_type_allowed_typecache = list(/mob/living/simple_animal/diona)
+ mob_type_allowed_typecache = list(/mob/living/basic/diona_nymph)
// Dog emotes
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 099d33c1d36..301ffaed121 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -159,6 +159,7 @@
//Basically an optional override for our glide size
//Sometimes you want to look like you're moving with a delay you don't actually have yet
visual_delay = 0
+ var/old_dir = mob.dir
if(istype(living_mob))
var/newdir = NONE
@@ -198,6 +199,7 @@
mob.set_glide_size(new_glide_size)
move_delay += add_delay
+ SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVED, direct, old_dir)
if(mob.pulledby)
mob.pulledby.stop_pulling()
diff --git a/code/modules/projectiles/projectile/magic_projectiles.dm b/code/modules/projectiles/projectile/magic_projectiles.dm
index 3a1b81efd8c..c8fba685cf9 100644
--- a/code/modules/projectiles/projectile/magic_projectiles.dm
+++ b/code/modules/projectiles/projectile/magic_projectiles.dm
@@ -206,7 +206,7 @@ GLOBAL_LIST_INIT(wabbajack_hostile_animals, list(
GLOBAL_LIST_INIT(wabbajack_docile_animals, list(
"parrot" = /mob/living/simple_animal/parrot,
"corgi" = /mob/living/simple_animal/pet/dog/corgi,
- "crab" = /mob/living/simple_animal/crab,
+ "crab" = /mob/living/basic/crab,
"cat" = /mob/living/simple_animal/pet/cat,
"mouse" = /mob/living/basic/mouse,
"chicken" = /mob/living/basic/chicken,
diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm
index 13f56965ca1..d7e0abf3e09 100644
--- a/code/modules/reagents/chemistry/reagents/toxins.dm
+++ b/code/modules/reagents/chemistry/reagents/toxins.dm
@@ -1092,7 +1092,7 @@
if(!C.wear_mask) // If not wearing a mask
C.adjustToxLoss(lethality)
if(isnymph(M)) //nymphs take EVEN MORE damage
- var/mob/living/simple_animal/diona/D = M
+ var/mob/living/basic/diona_nymph/D = M
D.adjustHealth(100)
..()
diff --git a/code/modules/research/strange_objects.dm b/code/modules/research/strange_objects.dm
index c4080415187..bffb202d6f0 100644
--- a/code/modules/research/strange_objects.dm
+++ b/code/modules/research/strange_objects.dm
@@ -52,7 +52,7 @@
/mob/living/basic/mouse,
/mob/living/simple_animal/pet/dog/pug,
/mob/living/basic/lizard,
- /mob/living/simple_animal/diona,
+ /mob/living/basic/diona_nymph,
/mob/living/basic/butterfly,
/mob/living/carbon/human/monkey,
)
@@ -128,7 +128,7 @@
/mob/living/basic/butterfly,
/mob/living/simple_animal/pet/cat,
/mob/living/simple_animal/pet/dog/corgi,
- /mob/living/simple_animal/crab,
+ /mob/living/basic/crab,
/mob/living/simple_animal/pet/dog/fox,
/mob/living/basic/lizard,
/mob/living/basic/mouse,
diff --git a/paradise.dme b/paradise.dme
index 5d605c95be8..4d167b3eb9c 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -666,6 +666,7 @@
#include "code\datums\elements\ridable.dm"
#include "code\datums\elements\rust_element.dm"
#include "code\datums\elements\shatters_when_thrown.dm"
+#include "code\datums\elements\sideways_movement.dm"
#include "code\datums\elements\strippable.dm"
#include "code\datums\elements\waddling.dm"
#include "code\datums\elements\wears_collar.dm"
@@ -2450,6 +2451,9 @@
#include "code\modules\mob\living\taste.dm"
#include "code\modules\mob\living\basic\basic_emotes.dm"
#include "code\modules\mob\living\basic\basic_mob.dm"
+#include "code\modules\mob\living\basic\friendly\crab.dm"
+#include "code\modules\mob\living\basic\friendly\diona_nymph.dm"
+#include "code\modules\mob\living\basic\friendly\nian_caterpillar.dm"
#include "code\modules\mob\living\basic\posessed_object.dm"
#include "code\modules\mob\living\basic\farm_animals\chicken.dm"
#include "code\modules\mob\living\basic\farm_animals\goat.dm"
@@ -2468,10 +2472,10 @@
#include "code\modules\mob\living\basic\friendly\cockroach.dm"
#include "code\modules\mob\living\basic\friendly\lightgeist.dm"
#include "code\modules\mob\living\basic\friendly\lizard.dm"
-#include "code\modules\mob\living\basic\friendly\nian_caterpillar.dm"
#include "code\modules\mob\living\basic\friendly\penguin.dm"
#include "code\modules\mob\living\basic\friendly\sloth.dm"
#include "code\modules\mob\living\basic\friendly\snake.dm"
+#include "code\modules\mob\living\basic\friendly\spiderbot.dm"
#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"
@@ -2696,13 +2700,10 @@
#include "code\modules\mob\living\simple_animal\bot\syndicate_bots.dm"
#include "code\modules\mob\living\simple_animal\friendly\cat.dm"
#include "code\modules\mob\living\simple_animal\friendly\corgi_stripping.dm"
-#include "code\modules\mob\living\simple_animal\friendly\crab.dm"
-#include "code\modules\mob\living\simple_animal\friendly\diona_nymph.dm"
#include "code\modules\mob\living\simple_animal\friendly\dog.dm"
#include "code\modules\mob\living\simple_animal\friendly\fox.dm"
#include "code\modules\mob\living\simple_animal\friendly\friendly_emote.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\angel_statue.dm"
#include "code\modules\mob\living\simple_animal\hostile\bees.dm"
#include "code\modules\mob\living\simple_animal\hostile\deathsquid.dm"
diff --git a/tools/ci/check_simplemob_additions.py b/tools/ci/check_simplemob_additions.py
index d9e2948cf78..93809441411 100644
--- a/tools/ci/check_simplemob_additions.py
+++ b/tools/ci/check_simplemob_additions.py
@@ -45,9 +45,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/bot/secbot/griefsky/toy",
"/mob/living/simple_animal/bot/secbot/ofitser",
"/mob/living/simple_animal/bot/secbot/pingsky",
- "/mob/living/simple_animal/crab",
- "/mob/living/simple_animal/crab/coffee",
- "/mob/living/simple_animal/crab/evil",
"/mob/living/simple_animal/demon",
"/mob/living/simple_animal/demon/pulse_demon",
"/mob/living/simple_animal/demon/pulse_demon/wizard",
@@ -56,7 +53,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/demon/slaughter/cult",
"/mob/living/simple_animal/demon/slaughter/laughter",
"/mob/living/simple_animal/demon/slaughter/lesser",
- "/mob/living/simple_animal/diona",
"/mob/living/simple_animal/drone",
"/mob/living/simple_animal/hostile",
"/mob/living/simple_animal/hostile/ancient_robot_leg",
@@ -224,7 +220,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/slime/pet",
"/mob/living/simple_animal/slime/random",
"/mob/living/simple_animal/slime/unit_test_dummy",
- "/mob/living/simple_animal/spiderbot",
}
}