diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm
index 3e6c7e5c478..a89ac854596 100644
--- a/_maps/map_files/Delta/delta.dmm
+++ b/_maps/map_files/Delta/delta.dmm
@@ -78837,7 +78837,7 @@
/turf/simulated/floor/plasteel,
/area/toxins/xenobiology)
"cKn" = (
-/mob/living/carbon/slime,
+/mob/living/simple_animal/slime,
/turf/simulated/floor/greengrid,
/area/toxins/xenobiology)
"cKo" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
index c9c348db8d1..02acdb8fe7e 100644
--- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm
@@ -23103,7 +23103,7 @@
/turf/simulated/floor/plasteel,
/area/storage/tools)
"aOE" = (
-/mob/living/carbon/slime,
+/mob/living/simple_animal/slime,
/turf/simulated/floor/plasteel,
/area/toxins/xenobiology{
name = "\improper Secure Lab"
diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm
index 2162c77926e..02bd3ad1e7c 100644
--- a/_maps/map_files/cyberiad/cyberiad.dmm
+++ b/_maps/map_files/cyberiad/cyberiad.dmm
@@ -79739,7 +79739,7 @@
/obj/effect/landmark{
name = "revenantspawn"
},
-/mob/living/carbon/slime,
+/mob/living/simple_animal/slime,
/turf/simulated/floor/engine,
/area/toxins/xenobiology)
"cMh" = (
@@ -81166,7 +81166,7 @@
},
/area/toxins/xenobiology)
"cOS" = (
-/obj/machinery/optable,
+/obj/structure/table,
/turf/simulated/floor/plasteel{
icon_state = "white"
},
@@ -81933,10 +81933,8 @@
/area/toxins/xenobiology)
"cQt" = (
/obj/structure/table/reinforced,
-/obj/item/circular_saw{
- pixel_y = 0
- },
/obj/item/scalpel,
+/obj/item/hemostat,
/turf/simulated/floor/plasteel{
icon_state = "white"
},
diff --git a/christmas.dm b/christmas.dm
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 0e5c5316254..5f9e2b463ff 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list(
#define isaliensentinel(A) (istype(A, /mob/living/carbon/alien/humanoid/sentinel))
-#define isslime(A) (istype((A), /mob/living/carbon/slime))
+#define isslime(A) (istype((A), /mob/living/simple_animal/slime))
//Structures
#define isstructure(A) (istype((A), /obj/structure))
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 0a551570472..1db82f879fe 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -95,6 +95,21 @@
#define APPEARANCE_ALL_BODY APPEARANCE_ALL_HAIR|APPEARANCE_HEAD_ACCESSORY|APPEARANCE_MARKINGS|APPEARANCE_BODY_ACCESSORY|APPEARANCE_ALT_HEAD
#define APPEARANCE_ALL 32767
+//Slime evolution threshold. Controls how fast slimes can split/grow
+#define SLIME_EVOLUTION_THRESHOLD 10
+
+//Slime extract crossing. Controls how many extracts is required to feed to a slime to core-cross.
+#define SLIME_EXTRACT_CROSSING_REQUIRED 10
+
+//Slime commands defines
+#define SLIME_FRIENDSHIP_FOLLOW 3 //Min friendship to order it to follow
+#define SLIME_FRIENDSHIP_STOPEAT 5 //Min friendship to order it to stop eating someone
+#define SLIME_FRIENDSHIP_STOPEAT_NOANGRY 7 //Min friendship to order it to stop eating someone without it losing friendship
+#define SLIME_FRIENDSHIP_STOPCHASE 4 //Min friendship to order it to stop chasing someone (their target)
+#define SLIME_FRIENDSHIP_STOPCHASE_NOANGRY 6 //Min friendship to order it to stop chasing someone (their target) without it losing friendship
+#define SLIME_FRIENDSHIP_STAY 3 //Min friendship to order it to stay
+#define SLIME_FRIENDSHIP_ATTACK 8 //Min friendship to order it to attack
+
//If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm
//Hostile Mob AI Status
#define AI_ON 1
@@ -200,7 +215,7 @@
// For the tcomms monitor
#define ispathhuman(A) (ispath(A, /mob/living/carbon/human))
#define ispathbrain(A) (ispath(A, /mob/living/carbon/brain))
-#define ispathslime(A) (ispath(A, /mob/living/carbon/slime))
+#define ispathslime(A) (ispath(A, /mob/living/simple_animal/slime))
#define ispathbot(A) (ispath(A, /mob/living/simple_animal/bot))
#define ispathsilicon(A) (ispath(A, /mob/living/silicon))
#define ispathanimal(A) (ispath(A, /mob/living/simple_animal))
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 3aaf3164428..82295bc9d80 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -421,7 +421,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M)
for(var/mob/new_player/M in sortmob)
moblist.Add(M)
- for(var/mob/living/carbon/slime/M in sortmob)
+ for(var/mob/living/simple_animal/slime/M in sortmob)
moblist.Add(M)
for(var/mob/living/simple_animal/M in sortmob)
moblist.Add(M)
@@ -1530,6 +1530,23 @@ var/mob/dview/dview_mob = new
return FALSE
return TRUE
+//datum may be null, but it does need to be a typed var
+#define NAMEOF(datum, X) (#X || ##datum.##X)
+
+#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
+//dupe code because dm can't handle 3 level deep macros
+#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
+
+/proc/___callbackvarset(list_or_datum, var_name, var_value)
+ if(length(list_or_datum))
+ list_or_datum[var_name] = var_value
+ return
+ var/datum/D = list_or_datum
+ if(IsAdminAdvancedProcCall())
+ D.vv_edit_var(var_name, var_value) //same result generally, unless badmemes
+ else
+ D.vars[var_name] = var_value
+
//Get the dir to the RIGHT of dir if they were on a clock
//NORTH --> NORTHEAST
/proc/get_clockwise_dir(dir)
diff --git a/code/_onclick/hud/slime.dm b/code/_onclick/hud/slime.dm
index 9f5621b75ee..f49228ddf66 100644
--- a/code/_onclick/hud/slime.dm
+++ b/code/_onclick/hud/slime.dm
@@ -1,18 +1,8 @@
-/mob/living/carbon/slime/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/slime(src)
-
-/mob/living/simple_animal/slime/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/slime(src)
-
-/datum/hud/slime/New(mob/owner)
+/datum/hud/slime/New(mob/living/simple_animal/slime/owner, ui_style = 'icons/mob/screen_slime.dmi')
..()
mymob.healths = new /obj/screen/healths/slime()
infodisplay += mymob.healths
- mymob.pullin = new /obj/screen/pull()
- mymob.pullin.icon = 'icons/mob/screen_slime.dmi'
- mymob.pullin.update_icon(mymob)
- mymob.pullin.screen_loc = ui_construct_pull
- hotkeybuttons += mymob.pullin
+/mob/living/simple_animal/slime/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud/slime(src)
\ No newline at end of file
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 53f2a89f9c1..d4ef3799610 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -84,11 +84,13 @@
Slimes
Nothing happening here
*/
-/mob/living/carbon/slime/UnarmedAttack(var/atom/A)
+/mob/living/simple_animal/slime/UnarmedAttack(atom/A)
A.attack_slime(src)
-/atom/proc/attack_slime(mob/user as mob)
+
+/atom/proc/attack_slime(mob/user)
return
-/mob/living/carbon/slime/RestrainedClickOn(var/atom/A)
+
+/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
/*
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 766c52c7b65..f619e9aa9bd 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -186,7 +186,7 @@
stage3 = list("Your appendages are melting away.", "Your limbs begin to lose their shape.")
stage4 = list("You are turning into a slime.")
stage5 = list("You have become a slime.")
- new_form = /mob/living/carbon/slime/random
+ new_form = /mob/living/simple_animal/slime/random
/datum/disease/transformation/slime/stage_act()
..()
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 65e188512d5..bb424a9afdf 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -140,6 +140,8 @@
var/mob/living/L = teleatom
if(L.buckled)
L.buckled.unbuckle_mob(L, force = TRUE)
+ if(L.has_buckled_mobs())
+ L.unbuckle_all_mobs(force = TRUE)
destarea.Entered(teleatom)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index d03207ef41a..84d5ab32b8a 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1729,7 +1729,7 @@
mind.active = 1 //indicates that the mind is currently synced with a client
//slime
-/mob/living/carbon/slime/mind_initialize()
+/mob/living/simple_animal/slime/mind_initialize()
..()
mind.assigned_role = "slime"
diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm
index 023939c2747..2f07f106d2a 100644
--- a/code/datums/spells/area_teleport.dm
+++ b/code/datums/spells/area_teleport.dm
@@ -58,6 +58,9 @@
if(target && target.buckled)
target.buckled.unbuckle_mob(target, force = TRUE)
+ if(target && target.has_buckled_mobs())
+ target.unbuckle_all_mobs(force = TRUE)
+
var/list/tempL = L
var/attempt = null
var/success = 0
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index e4b1f1e8a49..b95d3afc3f7 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -155,6 +155,9 @@
if(usr.abiotic())
to_chat(usr, "Subject cannot have abiotic items on.")
return
+ if(usr.has_buckled_mobs()) //mob attached to us
+ to_chat(usr, "[usr] will not fit into the [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
+ return
usr.stop_pulling()
usr.forceMove(src)
src.occupant = usr
@@ -190,10 +193,9 @@
if(L.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
return
- for(var/mob/living/carbon/slime/M in range(1,L))
- if(M.Victim == L)
- to_chat(usr, "[L.name] will not fit into the [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
- return
+ if(L.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[L] will not fit into [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
+ return
if(L == user)
visible_message("[user] climbs into the [src].")
else
@@ -242,6 +244,9 @@
if(G.affecting.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
return
+ if(G.affecting.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "will not fit into the [src] because [G.affecting.p_they()] [G.affecting.p_have()] a slime latched onto [G.affecting.p_their()] head.")
+ return
if(panel_open)
to_chat(usr, "Close the maintenance panel first.")
return
diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm
index 85e7126ae73..fa9f2a323e8 100644
--- a/code/game/dna/genes/goon_powers.dm
+++ b/code/game/dna/genes/goon_powers.dm
@@ -241,7 +241,7 @@
/mob/living/simple_animal/crab,
/mob/living/simple_animal/mouse,
/mob/living/carbon/human,
- /mob/living/carbon/slime,
+ /mob/living/simple_animal/slime,
/mob/living/carbon/alien/larva,
/mob/living/simple_animal/slime,
/mob/living/simple_animal/chick,
diff --git a/code/game/gamemodes/miniantags/abduction/gland.dm b/code/game/gamemodes/miniantags/abduction/gland.dm
index 2b0162829e1..2378ab1f789 100644
--- a/code/game/gamemodes/miniantags/abduction/gland.dm
+++ b/code/game/gamemodes/miniantags/abduction/gland.dm
@@ -129,7 +129,7 @@
to_chat(owner, "You feel nauseous!")
owner.vomit(20)
- var/mob/living/carbon/slime/Slime = new/mob/living/carbon/slime(get_turf(owner))
+ var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
Slime.Friends = list(owner)
Slime.Leader = owner
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index db6f07c1d24..fd7e7892cd4 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -27,10 +27,9 @@
return //occupied
if(target.buckled)
return
- for(var/mob/living/carbon/slime/M in range(1, target))
- if(M.Victim == target)
- to_chat(user, "[target] has a slime attached to [target.p_them()], deal with that first.")
- return
+ if(target.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[target] will not fit into [src] because [target.p_they()] [target.p_have()] a slime latched onto [target.p_their()] head.")
+ return
visible_message("[user] puts [target] into the [src].")
target.forceMove(src)
@@ -191,10 +190,9 @@
if(occupant)
to_chat(user, "The [src] is already occupied!")
return
- for(var/mob/living/carbon/slime/S in range(1, grabbed.affecting))
- if(S.Victim == grabbed.affecting)
- to_chat(user, "[grabbed.affecting] has a slime attached to them, deal with that first.")
- return
+ if(grabbed.affecting.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[grabbed.affecting] will not fit into [src] because [grabbed.affecting.p_they()] [grabbed.affecting.p_have()] a slime latched onto [grabbed.affecting.p_their()] head.")
+ return
visible_message("[user] puts [grabbed.affecting] into the [src].")
var/mob/living/carbon/human/H = grabbed.affecting
H.forceMove(src)
diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
index 3c0ca1955fb..6ea14557e06 100644
--- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
+++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
@@ -346,7 +346,7 @@
S.DisperseTarget(src)
return TRUE
-/mob/living/carbon/slime/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+/mob/living/simple_animal/slime/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "This biological resource is somehow resisting our bluespace transceiver. Aborting.")
return FALSE
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index c447ff26e72..aefe99213e1 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -328,10 +328,9 @@
if(occupant)
to_chat(user, "The sleeper is already occupied!")
return
- for(var/mob/living/carbon/slime/M in range(1, G.affecting))
- if(M.Victim == G.affecting)
- to_chat(user, "[G.affecting.name] will not fit into the sleeper because [G.affecting.p_they()] [G.affecting.p_have()] a slime latched onto [G.affecting.p_their()] head.")
- return
+ if(G.affecting.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[G.affecting] will not fit into [src] because [G.affecting.p_they()] [G.affecting.p_have()] a slime latched onto [G.affecting.p_their()] head.")
+ return
visible_message("[user] starts putting [G.affecting.name] into the sleeper.")
@@ -488,10 +487,9 @@
if(L.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
return
- for(var/mob/living/carbon/slime/M in range(1,L))
- if(M.Victim == L)
- to_chat(usr, "[L.name] will not fit into the sleeper because [L.p_they()] [L.p_have()] a slime latched onto their head.")
- return
+ if(L.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[L] will not fit into [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
+ return
if(L == user)
visible_message("[user] starts climbing into the sleeper.")
else
@@ -529,10 +527,9 @@
return
if(usr.incapacitated()) //are you cuffed, dying, lying, stunned or other
return
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
- to_chat(usr, "You're too busy getting your life sucked out of you.")
- return
+ if(usr.has_buckled_mobs()) //mob attached to us
+ to_chat(usr, "[usr] will not fit into [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
+ return
visible_message("[usr] starts climbing into the sleeper.")
if(do_after(usr, 20, target = usr))
if(occupant)
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index adb08949732..1fb4c505170 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -77,10 +77,9 @@
if(occupant)
to_chat(user, "The scanner is already occupied!")
return
- for(var/mob/living/carbon/slime/M in range(1, TYPECAST_YOUR_SHIT.affecting))
- if(M.Victim == TYPECAST_YOUR_SHIT.affecting)
- to_chat(user, "[TYPECAST_YOUR_SHIT.affecting.name] has a fucking slime attached to [TYPECAST_YOUR_SHIT.affecting.p_them()], deal with that first.")
- return
+ if(TYPECAST_YOUR_SHIT.affecting.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[TYPECAST_YOUR_SHIT.affecting] will not fit into [src] because [TYPECAST_YOUR_SHIT.affecting.p_they()] [TYPECAST_YOUR_SHIT.affecting.p_have()] a fucking slime latched onto [TYPECAST_YOUR_SHIT.affecting.p_their()] head.")
+ return
var/mob/living/carbon/human/M = TYPECAST_YOUR_SHIT.affecting
if(M.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
@@ -117,10 +116,9 @@
if(H.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
return FALSE
- for(var/mob/living/carbon/slime/M in range(1, H))
- if(M.Victim == H)
- to_chat(user, "[H] has a fucking slime attached to [H.p_them()], deal with that first.")
- return FALSE
+ if(H.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[H] will not fit into [src] because [H.p_they()] [H.p_have()] a slime latched onto [H.p_their()] head.")
+ return
if(H == user)
visible_message("[user] climbs into [src].")
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index b45a8331188..0546b0e9462 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -108,10 +108,9 @@
if(L.abiotic())
to_chat(user, "Subject cannot have abiotic items on.")
return
- for(var/mob/living/carbon/slime/M in range(1,L))
- if(M.Victim == L)
- to_chat(usr, "[L.name] will not fit into the cryo cell because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
- return
+ if(L.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[L] will not fit into [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
+ return
if(put_mob(L))
if(L == user)
visible_message("[user] climbs into the cryo cell.")
@@ -305,10 +304,9 @@
return
if(!ismob(GG.affecting))
return
- for(var/mob/living/carbon/slime/M in range(1,GG.affecting))
- if(M.Victim == GG.affecting)
- to_chat(usr, "[GG.affecting.name] will not fit into the cryo because [GG.affecting.p_they()] [GG.affecting.p_have()] a slime latched onto [GG.affecting.p_their()] head.")
- return
+ if(GG.affecting.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[GG.affecting] will not fit into [src] because [GG.affecting.p_they()] [GG.affecting.p_have()] a slime latched onto [GG.affecting.p_their()] head.")
+ return
var/mob/M = GG.affecting
if(put_mob(M))
qdel(GG)
@@ -468,10 +466,9 @@
set category = "Object"
set src in oview(1)
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
- to_chat(usr, "You're too busy getting your life sucked out of you.")
- return
+ if(usr.has_buckled_mobs()) //mob attached to us
+ to_chat(usr, "[usr] will not fit into [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
+ return
if(stat & (NOPOWER|BROKEN))
return
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index f9d708a6200..9d6be29c84f 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -554,10 +554,9 @@
to_chat(user, "Dead people can not be put into cryo.")
return
- for(var/mob/living/carbon/slime/M in range(1,L))
- if(M.Victim == L)
- to_chat(usr, "[L.name] will not fit into the cryo pod because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
- return
+ if(L.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[L] will not fit into [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")
+ return
var/willing = null //We don't want to allow people to be forced into despawning.
@@ -658,10 +657,9 @@
to_chat(usr, "\The [src] is in use.")
return
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
- to_chat(usr, "You're too busy getting your life sucked out of you.")
- return
+ if(usr.has_buckled_mobs()) //mob attached to us
+ to_chat(usr, "[usr] will not fit into [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
+ return
visible_message("[usr] starts climbing into [src].")
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index e1c5a03b3a6..517d6dd4019 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -1144,10 +1144,6 @@
if(user.has_buckled_mobs()) //mob attached to us
to_chat(user, "You can't enter the exosuit with other creatures attached to you!")
return
- for(var/mob/living/carbon/slime/S in range(1,user))
- if(S.Victim == user)
- to_chat(user, "You're too busy getting your life sucked out of you.")
- return
visible_message("[user] starts to climb into [src]")
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 2116114a305..7acaf887828 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -471,7 +471,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
to_chat(user, "You're going to need to remove that mask/helmet/glasses first!")
return
- if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/carbon/slime))//Aliens don't have eyes./N slimes also don't have eyes!
+ if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/simple_animal/slime))//Aliens don't have eyes./N slimes also don't have eyes!
to_chat(user, "You cannot locate any eyes on this creature!")
return
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 841850ee418..6c5b9cae2d6 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -547,39 +547,46 @@ proc/healthscan(mob/user, mob/living/M, mode = 1, upgraded = FALSE)
throw_range = 7
materials = list(MAT_METAL=30, MAT_GLASS=20)
-/obj/item/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob)
- slime_scan(M, user)
-
-/proc/slime_scan(mob/living/carbon/slime/M, mob/living/user)
- if(!isslime(M))
- user.show_message("This device can only scan slimes!", 1)
+/obj/item/slime_scanner/attack(mob/living/M, mob/living/user)
+ if(user.incapacitated() || user.eye_blind)
return
- var/mob/living/carbon/slime/T = M
- user.show_message("Slime scan results:", 1)
- user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby"), 1)
- user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition()), 1)
+ if(!isslime(M))
+ to_chat(user, "This device can only scan slimes!")
+ return
+ var/mob/living/simple_animal/slime/T = M
+ slime_scan(T, user)
+
+/proc/slime_scan(mob/living/simple_animal/slime/T, mob/living/user)
+ to_chat(user, "========================")
+ to_chat(user, "Slime scan results:")
+ to_chat(user, "[T.colour] [T.is_adult ? "adult" : "baby"] slime")
+ to_chat(user, "Nutrition: [T.nutrition]/[T.get_max_nutrition()]")
if(T.nutrition < T.get_starve_nutrition())
- user.show_message("Warning: slime is starving!", 1)
+ to_chat(user, "Warning: slime is starving!")
else if(T.nutrition < T.get_hunger_nutrition())
- user.show_message("Warning: slime is hungry", 1)
- user.show_message("Electric change strength: [T.powerlevel]", 1)
- user.show_message("Health: [T.health]", 1)
+ to_chat(user, "Warning: slime is hungry")
+ to_chat(user, "Electric change strength: [T.powerlevel]")
+ to_chat(user, "Health: [round(T.health/T.maxHealth,0.01)*100]%")
if(T.slime_mutation[4] == T.colour)
- user.show_message("This slime does not evolve any further.", 1)
+ to_chat(user, "This slime does not evolve any further.")
else
if(T.slime_mutation[3] == T.slime_mutation[4])
if(T.slime_mutation[2] == T.slime_mutation[1])
- user.show_message("Possible mutation: [T.slime_mutation[3]]", 1)
- user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting", 1)
+ to_chat(user, "Possible mutation: [T.slime_mutation[3]]")
+ to_chat(user, "Genetic destability: [T.mutation_chance/2] % chance of mutation on splitting")
else
- user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)", 1)
- user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1)
+ to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)")
+ to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
else
- user.show_message("Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]", 1)
- user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting", 1)
+ to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]")
+ to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
if(T.cores > 1)
- user.show_message("Anomalous slime core amount detected", 1)
- user.show_message("Growth progress: [T.amount_grown]/10", 1)
+ to_chat(user, "Multiple cores detected")
+ to_chat(user, "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]")
+ if(T.effectmod)
+ to_chat(user, "Core mutation in progress: [T.effectmod]")
+ to_chat(user, "Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]")
+ to_chat(user, "========================")
/obj/item/bodyanalyzer
name = "handheld body analyzer"
diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm
index cef14d28796..5727fe08cd0 100644
--- a/code/game/objects/items/weapons/implants/implantchair.dm
+++ b/code/game/objects/items/weapons/implants/implantchair.dm
@@ -79,7 +79,7 @@
return
var/mob/M = G.affecting
if(M.has_buckled_mobs())
- to_chat(usr, "[M] will not fit into [src] because [M.p_they()] [M.p_have()] a slime latched onto [M.p_their()] head.")
+ to_chat(user, "[M] will not fit into [src] because [M.p_they()] [M.p_have()] a slime latched onto [M.p_their()] head.")
return
if(put_mob(M))
qdel(G)
diff --git a/code/game/objects/items/weapons/scrolls.dm b/code/game/objects/items/weapons/scrolls.dm
index 696d54cc3bf..79d33de586f 100644
--- a/code/game/objects/items/weapons/scrolls.dm
+++ b/code/game/objects/items/weapons/scrolls.dm
@@ -85,6 +85,9 @@
if(user && user.buckled)
user.buckled.unbuckle_mob(user, force = TRUE)
+ if(user && user.has_buckled_mobs())
+ user.unbuckle_all_mobs(force = TRUE)
+
var/list/tempL = L
var/attempt = null
var/success = 0
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 572495b503f..6f007a6bdbc 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -126,10 +126,10 @@
if(. && !play_soundeffect)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
-/obj/attack_slime(mob/living/carbon/slime/user)
+/obj/attack_slime(mob/living/simple_animal/slime/user)
if(!user.is_adult)
return
- attack_generic(user, rand(10, 15), "melee", 1)
+ attack_generic(user, rand(10, 15), BRUTE, "melee", 1)
/obj/mech_melee_attack(obj/mecha/M)
M.do_attack_animation(src)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index dba81195e6e..efca449bbf3 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -105,7 +105,7 @@
continue
if(istype(M, /mob/living/simple_animal/bot/mulebot))
continue
- if(M.buckled || M.anchored)
+ if(M.buckled || M.anchored || M.has_buckled_mobs())
continue
M.forceMove(src)
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index f4efa5452b0..03e80563224 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -90,7 +90,7 @@
attack_generic(M, M.melee_damage_upper)
/obj/structure/inflatable/attack_slime(mob/user as mob)
- var/mob/living/carbon/slime/S = user
+ var/mob/living/simple_animal/slime/S = user
if(!S.is_adult)
return
attack_generic(user, rand(10, 15))
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 923fab9e885..f40d7f7f2de 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -108,7 +108,7 @@
/obj/structure/mirror/attack_slime(mob/living/user)
user.changeNext_move(CLICK_CD_MELEE)
- var/mob/living/carbon/slime/S = user
+ var/mob/living/simple_animal/slime/S = user
if(!S.is_adult)
return
user.do_attack_animation(src)
@@ -153,7 +153,7 @@
H.dna.real_name = newname
if(H.mind)
H.mind.name = newname
-
+
if(newname)
curse(user)
@@ -197,7 +197,7 @@
if(voice_choice)
curse(user)
-
+
/obj/structure/mirror/magic/on_ui_close(mob/user)
curse(user)
diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm
index 0b171dac199..50b53cc7dd9 100644
--- a/code/game/verbs/suicide.dm
+++ b/code/game/verbs/suicide.dm
@@ -209,7 +209,7 @@
adjustOxyLoss(max(175 - getFireLoss() - getBruteLoss() - getOxyLoss(), 0))
-/mob/living/carbon/slime/verb/suicide()
+/mob/living/simple_animal/slime/verb/suicide()
set hidden = 1
if(stat == 2)
to_chat(src, "You're already dead!")
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 754091a30db..a6926fe3414 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -345,7 +345,7 @@
var/mob/living/carbon/human/newmob = M.change_mob_type(/mob/living/carbon/human, null, null, delmob, 1)
if(posttransformoutfit && istype(newmob))
newmob.equipOutfit(posttransformoutfit)
- if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob, 1 )
+ if("slime") M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob, 1 )
if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob, 1 )
if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob, 1 )
if("cat") M.change_mob_type( /mob/living/simple_animal/pet/cat , null, null, delmob, 1 )
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 11664349274..57f88d20351 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -95,6 +95,16 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
to_chat(usr, "[procname] returned: [!isnull(returnval) ? returnval : "null"]")
feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+GLOBAL_VAR(AdminProcCaller)
+GLOBAL_PROTECT(AdminProcCaller)
+
+/proc/IsAdminAdvancedProcCall()
+#ifdef TESTING
+ return FALSE
+#else
+ return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
+#endif
+
/client/proc/callproc_datum(var/A as null|area|mob|obj|turf)
set category = "Debug"
set name = "Atom ProcCall"
diff --git a/code/modules/admin/verbs/freeze.dm b/code/modules/admin/verbs/freeze.dm
index bdef649468d..4d60fb72bee 100644
--- a/code/modules/admin/verbs/freeze.dm
+++ b/code/modules/admin/verbs/freeze.dm
@@ -61,14 +61,12 @@ var/global/list/frozen_mob_list = list()
update_icons()
-/mob/living/carbon/slime/admin_Freeze(admin)
+/mob/living/simple_animal/slime/admin_Freeze(admin)
..(admin)
- adjustToxLoss(1010101010) //arbitrary large value
+ adjustHealth(1000) //arbitrary large value
-/mob/living/carbon/slime/admin_unFreeze(admin)
+/mob/living/simple_animal/slime/admin_unFreeze(admin)
..(admin)
- adjustToxLoss(-1010101010)
- stat = 0
revive()
diff --git a/code/modules/events/anomaly_pyro.dm b/code/modules/events/anomaly_pyro.dm
index 3c2e6025952..f281c549c97 100644
--- a/code/modules/events/anomaly_pyro.dm
+++ b/code/modules/events/anomaly_pyro.dm
@@ -22,7 +22,10 @@
if(newAnomaly.loc)
explosion(get_turf(newAnomaly), -1,0,3, flame_range = 4)
- var/mob/living/carbon/slime/S = new/mob/living/carbon/slime(get_turf(newAnomaly))
- S.colour = pick("red", "orange")
-
+ var/turf/T = get_turf(src)
+ var/new_colour = pick("red", "orange")
+ var/mob/living/simple_animal/slime/S = new(T, new_colour)
+ S.rabid = TRUE
+ S.amount_grown = SLIME_EVOLUTION_THRESHOLD
+ S.Evolve()
qdel(newAnomaly)
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index 19c866fae43..394ee10384b 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -30,13 +30,10 @@
rating_speed = M.rating
/obj/machinery/processor/process()
- ..()
- // The irony
- // To be clear, if it's grinding, then it can't suck them up
if(processing)
return
- var/mob/living/carbon/slime/picked_slime
- for(var/mob/living/carbon/slime/slime in range(1, src))
+ var/mob/living/simple_animal/slime/picked_slime
+ for(var/mob/living/simple_animal/slime/slime in range(1, src))
if(slime.loc == src)
continue
if(slime.stat)
@@ -48,7 +45,7 @@
if(!P)
return
- visible_message("[picked_slime] is sucked into \the [src].")
+ visible_message("[picked_slime] is sucked into [src].")
picked_slime.forceMove(src)
//RECIPE DATUMS
@@ -110,18 +107,18 @@
/////MOB RECIPIES/////
//////////////////////
/datum/food_processor_process/mob/slime
- input = /mob/living/carbon/slime
+ input = /mob/living/simple_animal/slime
output = null
/datum/food_processor_process/mob/slime/process_food(loc, what, obj/machinery/processor/processor)
- var/mob/living/carbon/slime/S = what
+ var/mob/living/simple_animal/slime/S = what
var/C = S.cores
if(S.stat != DEAD)
- S.loc = loc
+ S.forceMove(processor.drop_location())
S.visible_message("[S] crawls free of the processor!")
return
for(var/i in 1 to (C+processor.rating_amount-1))
- new S.coretype(loc)
+ new S.coretype(processor.drop_location())
feedback_add_details("slime_core_harvested","[replacetext(S.colour," ","_")]")
..()
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index d7881367d13..0f57ac11757 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -75,3 +75,12 @@ In all, this is a lot like the monkey code. /N
adjustCloneLoss(damage)
if(STAMINA)
adjustStaminaLoss(damage)
+
+/mob/living/carbon/alien/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(10, 40)
+ adjustBruteLoss(damage)
+ add_attack_logs(src, M, "Slime'd for [damage] damage")
+ updatehealth("slime attack")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 788b8aa936d..d6bb6c6c1ac 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -65,15 +65,6 @@
take_overall_damage(b_loss, f_loss)
-/mob/living/carbon/alien/humanoid/attack_slime(mob/living/carbon/slime/M)
- ..()
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(10, 40)
- adjustBruteLoss(damage)
- add_attack_logs(src, M, "Slime'd for [damage] damage")
- return
-
/mob/living/carbon/alien/humanoid/restrained()
if(handcuffed)
return 1
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index 5ebaaffac0c..1ba5e4530ff 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -71,16 +71,6 @@
/mob/living/carbon/alien/larva/attack_ui(slot_id)
return
-/mob/living/carbon/alien/larva/attack_slime(mob/living/carbon/slime/M)
- ..()
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(20, 40)
- adjustBruteLoss(damage)
- add_attack_logs(src, M, "Slime'd for [damage] damage")
- updatehealth()
- return
-
/mob/living/carbon/alien/larva/restrained()
return 0
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm
index 8d17b84c724..34b5adf8dbf 100644
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ b/code/modules/mob/living/carbon/brain/brain.dm
@@ -41,7 +41,7 @@
return 1
if(istype(other, /mob/living/carbon/human))
return 1
- if(istype(other, /mob/living/carbon/slime))
+ if(istype(other, /mob/living/simple_animal/slime))
return 1
return ..()
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index c583d9873b6..a89c73b6db2 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -48,16 +48,25 @@
return 1
return 0
-/mob/living/carbon/attack_slime(mob/living/carbon/slime/M)
- if(..())
- var/power = M.powerlevel + rand(0,3)
- Weaken(power)
- Stuttering(power)
- Stun(power)
- var/stunprob = M.powerlevel * 7 + 10
- if(prob(stunprob) && M.powerlevel >= 8)
- adjustFireLoss(M.powerlevel * rand(6,10))
- updatehealth("slime attack")
+/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ if(M.powerlevel > 0)
+ var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
+ if(prob(stunprob))
+ M.powerlevel -= 3
+ if(M.powerlevel < 0)
+ M.powerlevel = 0
+
+ visible_message("The [M.name] has shocked [src]!", "The [M.name] has shocked you!")
+
+ do_sparks(5, TRUE, src)
+ var/power = M.powerlevel + rand(0,3)
+ Stun(power)
+ if(stuttering < power)
+ stuttering = power
+ if (prob(stunprob) && M.powerlevel >= 8)
+ adjustFireLoss(M.powerlevel * rand(6,10))
+ updatehealth("slime attack")
return 1
/mob/living/carbon/is_mouth_covered(head_only = FALSE, mask_only = FALSE)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 87bc491f4ab..e2472513250 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -451,22 +451,22 @@ emp_act
apply_damage(damage, M.melee_damage_type, affecting, armor)
updatehealth("animal attack")
-/mob/living/carbon/human/attack_slime(mob/living/carbon/slime/M)
- ..()
- var/damage = rand(1, 3)
+/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(5, 25)
+ if(M.is_adult)
+ damage = rand(10, 35)
- if(M.is_adult)
- damage = rand(10, 35)
- else
- damage = rand(5, 25)
+ if(check_shields(M, damage, "the [M.name]"))
+ return FALSE
- var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot")
+ var/dam_zone = pick("head", "chest", "groin", "l_arm", "l_hand", "r_arm", "r_hand", "l_leg", "l_foot", "r_leg", "r_foot")
- var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
- var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
-
- return
+ var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone))
+ if(!affecting)
+ affecting = get_organ("chest")
+ var/armor_block = run_armor_check(affecting, "melee")
+ apply_damage(damage, BRUTE, affecting, armor_block)
/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == INTENT_HARM)
diff --git a/code/modules/mob/living/carbon/slime/death.dm b/code/modules/mob/living/carbon/slime/death.dm
deleted file mode 100644
index 055f972df07..00000000000
--- a/code/modules/mob/living/carbon/slime/death.dm
+++ /dev/null
@@ -1,21 +0,0 @@
-/mob/living/carbon/slime/death(gibbed)
- // Only execute the below if we successfully died
- . = ..()
- if(!.)
- return FALSE
- if(!gibbed)
- if(is_adult)
- var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc)
- M.colour = colour
- M.rabid = 1
- is_adult = 0
- maxHealth = 150
- revive()
- regenerate_icons()
- number = rand(1, 1000)
- name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
- return
- else
- visible_message("The [name] seizes up and falls limp...")
- icon_state = "[colour] baby slime dead"
- overlays.Cut()
diff --git a/code/modules/mob/living/carbon/slime/examine.dm b/code/modules/mob/living/carbon/slime/examine.dm
deleted file mode 100644
index 4dd67695e2a..00000000000
--- a/code/modules/mob/living/carbon/slime/examine.dm
+++ /dev/null
@@ -1,45 +0,0 @@
-/mob/living/carbon/slime/examine(mob/user)
- to_chat(user, "*---------*")
- ..(user)
- var/msg = ""
- if(src.stat == DEAD)
- msg += "It is limp and unresponsive.\n"
- else
- if(src.getBruteLoss())
- msg += ""
- if(src.getBruteLoss() < 40)
- msg += "It has some punctures in its flesh!"
- else
- msg += "It has severe punctures and tears in its flesh!"
- msg += "\n"
-
- switch(powerlevel)
-
- if(2 to 3)
- msg += "It is flickering gently with a little electrical activity.\n"
-
- if(4 to 5)
- msg += "It is glowing gently with moderate levels of electrical activity.\n"
-
- if(6 to 9)
- msg += "It is glowing brightly with high levels of electrical activity.\n"
-
- if(10)
- msg += "It is radiating with massive levels of electrical activity!\n"
-
- msg += ""
- switch(wetlevel)
- if(1)
- msg += "It looks a bit damp.\n"
- if(2)
- msg += "It looks a little bit wet.\n"
- if(3)
- msg += "It looks wet.\n"
- if(4)
- msg += "It looks very wet.\n"
- if(5)
- msg += "It looks absolutely soaked.\n"
- msg += ""
-
- msg += "*---------*"
- to_chat(user, msg)
diff --git a/code/modules/mob/living/carbon/slime/life.dm b/code/modules/mob/living/carbon/slime/life.dm
deleted file mode 100644
index e3bfcb74431..00000000000
--- a/code/modules/mob/living/carbon/slime/life.dm
+++ /dev/null
@@ -1,570 +0,0 @@
-/mob/living/carbon/slime
- var/AIproc = 0 // determines if the AI loop is activated
- var/Atkcool = 0 // attack cooldown
- var/Tempstun = 0 // temporary temperature stuns
- var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while
- var/SStun = 0 // stun variable
-
-/mob/living/carbon/slime/Life(seconds, times_fired)
- if(..())
- handle_nutrition()
- handle_targets()
- if(!ckey)
- handle_speech_and_mood()
-
-/mob/living/carbon/slime/breathe()
- return
-
-/mob/living/carbon/slime/proc/AIprocess() // the master AI process
-
- if(AIproc || stat == DEAD || client) return
-
- var/hungry = 0
- if(nutrition < get_starve_nutrition())
- hungry = 2
- else if(nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
- hungry = 1
-
- AIproc = 1
-
- while(AIproc && stat != 2 && (attacked || hungry || rabid || Victim))
- if(Victim) // can't eat AND have this little process at the same time
- break
-
- if(!Target || client)
- break
-
- if(Target.health <= -70 || Target.stat == 2)
- Target = null
- AIproc = 0
- break
-
- if(Target)
- for(var/mob/living/carbon/slime/M in view(1,Target))
- if(M.Victim == Target)
- Target = null
- AIproc = 0
- break
- if(!AIproc)
- break
-
- if(Target in view(1,src))
- if(istype(Target, /mob/living/silicon))
- if(!Atkcool)
- Atkcool = 1
- spawn(45)
- Atkcool = 0
-
- if(Target.Adjacent(src))
- Target.attack_slime(src)
- return
- if(!Target.lying && prob(80))
-
- if(Target.client && Target.health >= 20)
- if(!Atkcool)
- Atkcool = 1
- spawn(45)
- Atkcool = 0
-
- if(Target.Adjacent(src))
- Target.attack_slime(src)
-
- else
- if(!Atkcool && Target.Adjacent(src))
- Feedon(Target)
-
- else
- if(!Atkcool && Target.Adjacent(src))
- Feedon(Target)
-
- else
- if(Target in view(7, src))
- if(!Target.Adjacent(src)) // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them
- step_to(src, Target)
- sleep(5)
-
- else
- Target = null
- AIproc = 0
- break
-
- var/sleeptime = movement_delay()
- if(sleeptime <= 0) sleeptime = 1
-
- sleep(sleeptime + 2) // this is about as fast as a player slime can go
-
- AIproc = 0
-
-/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment)
- if(!environment)
- adjustToxLoss(rand(10,20))
- return
-
- //var/environment_heat_capacity = environment.heat_capacity()
- var/loc_temp = T0C
- if(istype(get_turf(src), /turf/space))
- //environment_heat_capacity = loc:heat_capacity
- var/turf/heat_turf = get_turf(src)
- loc_temp = heat_turf.temperature
- else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell))
- loc_temp = loc:air_contents.temperature
- else
- loc_temp = environment.temperature
-
- //Account for massive pressure differences
- if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc
- if(bodytemperature <= (T0C - 40)) // stun temperature
- Tempstun = 1
-
- if(bodytemperature <= (T0C - 50)) // hurt temperature
- if(bodytemperature <= 50) // sqrting negative numbers is bad
- adjustToxLoss(301) //The config.health_threshold_dead is -100 by default, and slimes have 150hp (200hp for adults),
- else //so the ToxLoss needs to be 300 or above to guarrantee an instant death
- adjustToxLoss(round(sqrt(bodytemperature)) * 2)
- else
- Tempstun = 0
-
-
- /*moved after the temperature damage code so freeze beams can instantly kill slimes -Deity Link*/
- if(loc_temp < 310.15) // a cold place
- bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1)
- else // a hot place
- bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1)
-
- updatehealth("handle environment")
-
- return //TODO: DEFERRED
-
-/mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost)
- var/temperature = current
- var/difference = abs(current-loc_temp) //get difference
- var/increments// = difference/10 //find how many increments apart they are
- if(difference > 50)
- increments = difference/5
- else
- increments = difference/10
- var/change = increments*boost // Get the amount to change by (x per increment)
- var/temp_change
- if(current < loc_temp)
- temperature = min(loc_temp, temperature+change)
- else if(current > loc_temp)
- temperature = max(loc_temp, temperature-change)
- temp_change = (temperature - current)
- return temp_change
-
-/mob/living/carbon/slime/handle_chemicals_in_body()
-
- if(reagents)
- reagents.metabolize(src)
-
- if(reagents.get_reagent_amount("plasma")>=5)
- mutation_chance = min(mutation_chance + 5,50) //Prevents mutation chance going >50%
- reagents.remove_reagent("plasma", 5)
- if(reagents.get_reagent_amount("epinephrine")>=5)
- mutation_chance = max(mutation_chance - 5,0) //Prevents mutation chance going <0%
- reagents.remove_reagent("epinephrine", 5)
- updatehealth("handle chemicals in body")
-
- return //TODO: DEFERRED
-
-/mob/living/carbon/slime/handle_regular_status_updates()
-
- if(is_adult)
- health = 200 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
- else
- health = 150 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
-
- if(health < HEALTH_THRESHOLD_DEAD && check_death_method() && stat != DEAD)
- death()
- return
-
- else if(src.health <= HEALTH_THRESHOLD_CRIT && check_death_method())
-
- if(!src.reagents.has_reagent("epinephrine"))
- src.adjustOxyLoss(10)
-
- if(src.stat != DEAD)
- src.stat = UNCONSCIOUS
-
- if(prob(30)) //I think this is meant to allow slimes to starve to death
- adjustOxyLoss(-1)
- adjustToxLoss(-1)
- adjustFireLoss(-1)
- adjustCloneLoss(-1)
- adjustBruteLoss(-1)
-
- if(src.stat == DEAD)
- src.lying = 1
- else
- if(src.paralysis || src.stunned || src.weakened || (status_flags && FAKEDEATH)) //Stunned etc.
- if(src.stunned > 0)
- AdjustStunned(-1)
- src.stat = 0
- if(src.weakened > 0)
- AdjustWeakened(-1)
- src.lying = 0
- src.stat = 0
- if(src.paralysis > 0)
- AdjustParalysis(-1)
- src.lying = 0
- src.stat = 0
-
- else
- src.lying = 0
- src.stat = 0
-
- if(src.stuttering) src.stuttering = 0
-
- if(src.eye_blind)
- src.SetEyeBlind(0)
-
- src.density = !( src.lying )
-
- if(src.eye_blurry > 0)
- SetEyeBlurry(0)
-
- if(src.druggy > 0)
- SetDruggy(0)
-
- return 1
-
-/mob/living/carbon/slime/proc/handle_nutrition()
-
- if(docile) //God as my witness, I will never go hungry again
- nutrition = 700
- return
-
- if(prob(15))
- nutrition -= 1 + is_adult
-
- if(nutrition <= 0)
- nutrition = 0
- if(prob(75))
- adjustToxLoss(rand(0,5))
-
- else if(nutrition >= get_grow_nutrition() && amount_grown < 10)
- nutrition -= 20
- amount_grown++
- update_action_buttons_icon()
-
- if(amount_grown >= 10 && !Victim && !Target && !ckey)
- if(is_adult)
- Reproduce()
- else
- Evolve()
-
-/mob/living/carbon/slime/proc/add_nutrition(nutrition_to_add = 0, lastnut = 0)
- nutrition = min((nutrition + nutrition_to_add), get_max_nutrition())
- if(nutrition >= (lastnut + 50))
- if(prob(80))
- lastnut = nutrition
- powerlevel++
- if(powerlevel > 10)
- powerlevel = 10
- adjustToxLoss(-10)
-
-/mob/living/carbon/slime/proc/handle_targets()
- if(Tempstun)
- if(!Victim) // not while they're eating!
- canmove = 0
- else
- canmove = 1
-
- if(attacked > 50) attacked = 50
-
- if(attacked > 0)
- attacked--
-
- if(Discipline > 0)
-
- if(Discipline >= 5 && rabid)
- if(prob(60)) rabid = 0
-
- if(prob(10))
- Discipline--
-
- if(!client)
- if(!canmove) return
-
- if(Victim) return // if it's eating someone already, continue eating!
-
- if(Target)
- --target_patience
- if(target_patience <= 0 || SStun || Discipline || attacked || docile) // Tired of chasing or something draws out attention
- target_patience = 0
- Target = null
-
- if(AIproc && SStun) return
-
- var/hungry = 0 // determines if the slime is hungry
-
- if(nutrition < get_starve_nutrition())
- hungry = 2
- else if(nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
- hungry = 1
-
- if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
- if(Friends.len > 0 && prob(1))
- var/mob/nofriend = pick(Friends)
- --Friends[nofriend]
-
- if(!Target)
- if(will_hunt() && hungry || attacked || rabid) // Only add to the list if we need to
- var/list/targets = list()
-
- for(var/mob/living/L in view(7,src))
-
- if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
- continue
-
- if(L in Friends) // No eating friends!
- continue
-
- if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
- targets += L // Possible target found!
-
- if(istype(L, /mob/living/carbon/human)) //Ignore slime(wo)men
- var/mob/living/carbon/human/H = L
- if(isslimeperson(H))
- continue
-
- if(!L.canmove) // Only one slime can latch on at a time.
- var/notarget = 0
- for(var/mob/living/carbon/slime/M in view(1,L))
- if(M.Victim == L)
- notarget = 1
- if(notarget)
- continue
-
- targets += L // Possible target found!
-
- if(targets.len > 0)
- if(attacked || rabid || hungry == 2)
- Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
- else
- for(var/mob/living/carbon/C in targets)
- if(!Discipline && prob(5))
- if(ishuman(C) || isalienadult(C))
- Target = C
- break
-
- if(islarva(C) || issmall(C))
- Target = C
- break
-
- if(Target)
- target_patience = rand(5,7)
- if(is_adult)
- target_patience += 3
-
- if(!Target) // If we have no target, we are wandering or following orders
- if(Leader)
- if(holding_still)
- holding_still = max(holding_still - 1, 0)
- else if(canmove && isturf(loc))
- step_to(src, Leader)
-
- else if(hungry)
- if(holding_still)
- holding_still = max(holding_still - hungry, 0)
- else if(canmove && isturf(loc) && prob(50))
- step(src, pick(cardinal))
-
- else
- if(holding_still)
- holding_still = max(holding_still - 1, 0)
- else if(docile && pulledby)
- holding_still = 10
- else if(canmove && isturf(loc) && prob(33))
- step(src, pick(cardinal))
- else if(!AIproc)
- spawn()
- AIprocess()
-
-/mob/living/carbon/slime/proc/handle_speech_and_mood()
- //Mood starts here
- var/newmood = ""
- if(rabid || attacked)
- newmood = "angry"
- else if(docile)
- newmood = ":3"
- else if(Target)
- newmood = "mischevous"
-
- if(!newmood)
- if(Discipline && prob(25))
- newmood = "pout"
- else if(prob(1))
- newmood = pick("sad", ":3", "pout")
-
- if((mood == "sad" || mood == ":3" || mood == "pout") && !newmood)
- if(prob(75)) newmood = mood
-
- if(newmood != mood) // This is so we don't redraw them every time
- mood = newmood
- regenerate_icons()
-
- //Speech understanding starts here
- var/to_say
- if(speech_buffer.len > 0)
- var/who = speech_buffer[1] // Who said it?
- var/phrase = speech_buffer[2] // What did they say?
- if((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us
- if(findtext(phrase, "hello") || findtext(phrase, "hi"))
- to_say = pick("Hello...", "Hi...")
- else if(findtext(phrase, "follow"))
- if(Leader)
- if(Leader == who) // Already following him
- to_say = pick("Yes...", "Lead...", "Following...")
- else if(Friends[who] > Friends[Leader]) // VIVA
- Leader = who
- to_say = "Yes... I follow [who]..."
- else
- to_say = "No... I follow [Leader]..."
- else
- if(Friends[who] > 2)
- Leader = who
- to_say = "I follow..."
- else // Not friendly enough
- to_say = pick("No...", "I won't follow...")
- else if(findtext(phrase, "stop"))
- if(Victim) // We are asked to stop feeding
- if(Friends[who] > 4)
- Victim = null
- Target = null
- if(Friends[who] < 7)
- --Friends[who]
- to_say = "Grrr..." // I'm angry but I do it
- else
- to_say = "Fine..."
- else if(Target) // We are asked to stop chasing
- if(Friends[who] > 3)
- Target = null
- if(Friends[who] < 6)
- --Friends[who]
- to_say = "Grrr..." // I'm angry but I do it
- else
- to_say = "Fine..."
- else if(Leader) // We are asked to stop following
- if(Leader == who)
- to_say = "Yes... I'll stay..."
- Leader = null
- else
- if(Friends[who] > Friends[Leader])
- Leader = null
- to_say = "Yes... I'll stop..."
- else
- to_say = "No... I'll keep following..."
- else if(findtext(phrase, "stay"))
- if(Leader)
- if(Leader == who)
- holding_still = Friends[who] * 10
- to_say = "Yes... Staying..."
- else if(Friends[who] > Friends[Leader])
- holding_still = (Friends[who] - Friends[Leader]) * 10
- to_say = "Yes... Staying..."
- else
- to_say = "No... I'll keep following..."
- else
- if(Friends[who] > 2)
- holding_still = Friends[who] * 10
- to_say = "Yes... Staying..."
- else
- to_say = "No... I won't stay..."
- speech_buffer = list()
-
- //Speech starts here
- if(to_say)
- say (to_say)
- else if(prob(1))
- emote(pick("bounce","sway","light","vibrate","jiggle"))
- else
- var/t = 10
- var/slimes_near = -1 // Don't count myself
- var/dead_slimes = 0
- var/friends_near = list()
- for(var/mob/living/carbon/M in view(7,src))
- if(isslime(M))
- ++slimes_near
- if(M.stat == DEAD)
- ++dead_slimes
- if(M in Friends)
- t += 20
- friends_near += M
- if(nutrition < get_hunger_nutrition()) t += 10
- if(nutrition < get_starve_nutrition()) t += 10
- if(prob(2) && prob(t))
- var/phrases = list()
- if(Target) phrases += "[Target]... looks tasty..."
- if(nutrition < get_starve_nutrition())
- phrases += "So... hungry..."
- phrases += "Very... hungry..."
- phrases += "Need... food..."
- phrases += "Must... eat..."
- else if(nutrition < get_hunger_nutrition())
- phrases += "Hungry..."
- phrases += "Where is the food?"
- phrases += "I want to eat..."
- phrases += "Rawr..."
- phrases += "Blop..."
- phrases += "Blorble..."
- if(rabid || attacked)
- phrases += "Hrr..."
- phrases += "Nhuu..."
- phrases += "Unn..."
- if(mood == ":3")
- phrases += "Purr..."
- if(attacked)
- phrases += "Grrr..."
- if(getToxLoss() > 30)
- phrases += "Cold..."
- if(getToxLoss() > 60)
- phrases += "So... cold..."
- phrases += "Very... cold..."
- if(getToxLoss() > 90)
- phrases += "..."
- phrases += "C... c..."
- if(Victim)
- phrases += "Nom..."
- phrases += "Tasty..."
- if(powerlevel > 3) phrases += "Bzzz..."
- if(powerlevel > 5) phrases += "Zap..."
- if(powerlevel > 8) phrases += "Zap... Bzz..."
- if(mood == "sad") phrases += "Bored..."
- if(slimes_near) phrases += "Brother..."
- if(slimes_near > 1) phrases += "Brothers..."
- if(dead_slimes) phrases += "What happened?"
- if(!slimes_near)
- phrases += "Lonely..."
- for(var/M in friends_near)
- phrases += "[M]... friend..."
- if(nutrition < get_hunger_nutrition())
- phrases += "[M]... feed me..."
- say (pick(phrases))
-
-/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it
- if(is_adult) return 1200
- else return 1000
-
-/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat
- if(is_adult) return 1000
- else return 800
-
-/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat
- if(is_adult) return 600
- else return 500
-
-/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else
- if(is_adult) return 300
- else return 200
-
-/mob/living/carbon/slime/proc/will_hunt(hunger = -1) // Check for being stopped from feeding and chasing
- if(docile)
- return 0
- if(hunger == 2 || rabid || attacked)
- return 1
- if(Leader)
- return 0
- if(holding_still)
- return 0
- return 1
diff --git a/code/modules/mob/living/carbon/slime/powers.dm b/code/modules/mob/living/carbon/slime/powers.dm
deleted file mode 100644
index 40f9060ee63..00000000000
--- a/code/modules/mob/living/carbon/slime/powers.dm
+++ /dev/null
@@ -1,233 +0,0 @@
-/mob/living/carbon/slime/verb/Feed()
- set category = "Slime"
- set desc = "This will let you feed on any valid creature in the surrounding area. This should also be used to halt the feeding process."
- if(Victim)
- Feedstop()
- return 0
-
- if(docile)
- to_chat(src, "I'm not hungry anymore...")
- return 0
-
- if(stat)
- to_chat(src, "I must be conscious to do this...")
- return 0
-
- var/list/choices = list()
- for(var/mob/living/C in view(1,src))
- if(C!=src && !istype(C,/mob/living/carbon/slime) && Adjacent(C))
- choices += C
-
- var/mob/living/M = input(src,"Who do you wish to feed on?") in null|choices
- if(!M)
- return 0
- if(Adjacent(M))
- if(isbrain(M))
- to_chat(src, "This subject does not have an edible life energy...")
- return 0
-
- if(iscarbon(M) && (M.health < -70))
- to_chat(src, "This subject does not have a strong enough life energy...")
- return 0
-
- if(isanimal(M) && (M.health < 1))//animals don't go into crit, stupid; fixes infinite energy exploit
- to_chat(src, "This subject does not have a strong enough life energy...")
- return 0
-
- for(var/mob/living/carbon/slime/met in view())
- if(met.Victim == M && met != src)
- to_chat(src, "The [met.name] is already feeding on this subject...")
- return 0
-
- to_chat(src, "I have latched onto the subject and begun feeding...")
- to_chat(M, "The [name] has latched onto your head!")
-
- Feedon(M)
- return 1
-
-/mob/living/carbon/slime/proc/Feedon(var/mob/living/M)
- Victim = M
- forceMove(M.loc)
- canmove = 0
- anchored = 1
- var/lastnut = nutrition
- var/fed_succesfully = 0
- var/health_minimum = -70
- if(is_adult)
- icon_state = "[colour] adult slime eat"
- else
- icon_state = "[colour] baby slime eat"
-
- if(isanimal(Victim))
- health_minimum = 0
- while(Victim && Victim.health > health_minimum && stat != DEAD)
- canmove = 0
-
- if(Adjacent(Victim))
- forceMove(M.loc)
-
- if(iscarbon(Victim))
- Victim.adjustCloneLoss(rand(5,6))
- Victim.adjustToxLoss(rand(1,2))
- if(Victim.health <= 0)
- Victim.adjustToxLoss(rand(2,4))
-
- if(prob(15) && Victim.client)
- to_chat(Victim, "[pick("You can feel your body becoming weak!", \
- "You feel like you're about to die!", \
- "You feel every part of your body screaming in agony!", \
- "A low, rolling pain passes through your body!", \
- "Your body feels as if it's falling apart!", \
- "You feel extremely weak!", \
- "A sharp, deep pain bathes every inch of your body!")]")
-
- fed_succesfully = 1
-
- else if(health_minimum == 0) //we already know it's a simple_animal from above
- Victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
- fed_succesfully = 1
-
- else
- to_chat(src, "[pick("This subject is incompatable", \
- "This subject does not have a life energy", "This subject is empty", \
- "I am not satisified", "I can not feed from this subject", \
- "I do not feel nourished", "This subject is not food")]...")
-
- if(fed_succesfully)
- add_nutrition(rand(15,30), lastnut)
-
- //Heal yourself.
- adjustOxyLoss(-10)
- adjustBruteLoss(-10)
- adjustFireLoss(-10)
- adjustCloneLoss(-10)
-
- updatehealth("slime feeding")
- if(Victim)
- Victim.updatehealth("slime feeding")
-
- sleep(rand(15,45))
-
- else
- break
-
- if(stat == 2)
- if(!is_adult)
- icon_state = "[colour] baby slime dead"
-
- else
- if(is_adult)
- icon_state = "[colour] adult slime"
- else
- icon_state = "[colour] baby slime"
-
- canmove = 1
- anchored = 0
-
- if(M)
- if(M.health <= health_minimum)
- M.canmove = 0
- if(!client)
- if(Victim && !rabid && !attacked)
- if(Victim.LAssailant && Victim.LAssailant != Victim)
- if(prob(50))
- if(!(Victim.LAssailant in Friends))
- Friends[Victim.LAssailant] = 1
- //Friends.Add(Victim.LAssailant) // no idea why i was using the |= operator
- else
- ++Friends[Victim.LAssailant]
-
-
- if(M.client && istype(src, /mob/living/carbon/human))
- if(prob(85))
- rabid = 1 // UUUNNBGHHHH GONNA EAT JUUUUUU
-
- if(client)
- to_chat(src, "This subject does not have a strong enough life energy anymore...")
- else
- M.canmove = 1
- if(client)
- to_chat(src, "I have stopped feeding...")
- else
- if(client)
- to_chat(src, "I have stopped feeding...")
-
- Victim = null
-
-/mob/living/carbon/slime/proc/Feedstop()
- if(Victim)
- if(Victim.client)
- to_chat(Victim, "[src] has let go of your head!")
- Victim = null
-
-/mob/living/carbon/slime/proc/UpdateFeed(var/mob/M)
- if(Victim)
- if(Victim == M)
- forceMove(M.loc) // simple "attach to head" effect!
-
-
-/mob/living/carbon/slime/verb/Evolve()
- set category = "Slime"
- set desc = "This will let you evolve from baby to adult slime."
-
- if(stat)
- to_chat(src, "I must be conscious to do this...")
- return
- if(!is_adult)
- if(amount_grown >= 10)
- is_adult = 1
- maxHealth = 200
- amount_grown = 0
- regenerate_icons()
- name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")
- else
- to_chat(src, "I am not ready to evolve yet...")
- else
- to_chat(src, "I have already evolved...")
-
-/mob/living/carbon/slime/verb/Reproduce()
- set category = "Slime"
- set desc = "This will make you split into four Slimes."
-
- if(stat)
- to_chat(src, "I must be conscious to do this...")
- return
-
- if(is_adult)
- if(amount_grown >= 10)
- if(stat)
- to_chat(src, "I must be conscious to do this...")
- return
-
- var/list/babies = list()
- var/new_nutrition = round(nutrition * 0.9)
- var/new_powerlevel = round(powerlevel / 4)
- for(var/i=1,i<=4,i++)
- var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc)
- if(mutation_chance >= 100)
- M.colour = "rainbow"
- else if(prob(mutation_chance))
- M.colour = slime_mutation[rand(1,4)]
- else
- M.colour = colour
- if(ckey)
- M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
- M.powerlevel = new_powerlevel
- if(i != 1)
- step_away(M,src)
- M.Friends = Friends.Copy()
- babies += M
- M.mutation_chance = Clamp(mutation_chance+(rand(5,-5)),0,100)
- feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]")
-
- var/mob/living/carbon/slime/new_slime = pick(babies)
- new_slime.universal_speak = universal_speak
- if(src.mind)
- src.mind.transfer_to(new_slime)
- else
- new_slime.key = src.key
- qdel(src)
- else
- to_chat(src, "I am not ready to reproduce yet...")
- else
- to_chat(src, "I am not old enough to reproduce yet...")
diff --git a/code/modules/mob/living/carbon/slime/say.dm b/code/modules/mob/living/carbon/slime/say.dm
deleted file mode 100644
index 2096da01360..00000000000
--- a/code/modules/mob/living/carbon/slime/say.dm
+++ /dev/null
@@ -1,29 +0,0 @@
-/mob/living/carbon/slime/say_quote(var/text, var/datum/language/speaking)
- var/verb = "telepathically chirps"
- var/ending = copytext(text, length(text))
-
- if(ending == "?")
- verb = "telepathically asks"
- else if(ending == "!")
- verb = "telepathically cries"
-
- return verb
-
-/mob/living/carbon/slime/say_understands(var/other)
- if(istype(other, /mob/living/carbon/slime))
- return 1
- return ..()
-
-/mob/living/carbon/slime/hear_say(list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
- if(speaker in Friends)
- speech_buffer = list()
- speech_buffer.Add(speaker)
- speech_buffer.Add(lowertext(html_decode(multilingual_to_message(message_pieces))))
- ..()
-
-/mob/living/carbon/slime/hear_radio(list/message_pieces, var/verb="says", var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="", var/atom/follow_target)
- if(speaker in Friends)
- speech_buffer = list()
- speech_buffer.Add(speaker)
- speech_buffer.Add(lowertext(html_decode(multilingual_to_message(message_pieces))))
- ..()
diff --git a/code/modules/mob/living/carbon/slime/slime.dm b/code/modules/mob/living/carbon/slime/slime.dm
deleted file mode 100644
index afd358ab99f..00000000000
--- a/code/modules/mob/living/carbon/slime/slime.dm
+++ /dev/null
@@ -1,546 +0,0 @@
-/mob/living/carbon/slime
- name = "baby slime"
- icon = 'icons/mob/slimes.dmi'
- icon_state = "grey baby slime"
- pass_flags = PASSTABLE
- ventcrawler = 2
- speak_emote = list("telepathically chirps")
- layer = 5
- maxHealth = 150
- health = 150
- gender = NEUTER
- nutrition = 700
- see_in_dark = 8
- update_slimes = 0
- faction = list("slime","neutral")
- // canstun and canweaken don't affect slimes because they ignore stun and weakened variables
- // for the sake of cleanliness, though, here they are.
- status_flags = CANPARALYSE|CANPUSH
-
- var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
- var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
-
- var/powerlevel = 0 // 1-10 controls how much electricity they are generating
- var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
-
- var/number = 0 // Used to understand when someone is talking to it
-
- var/mob/living/Victim = null // the person the slime is currently feeding on
- var/mob/living/Target = null // AI variable - tells the slime to hunt this down
- var/mob/living/Leader = null // AI variable - tells the slime to follow this person
-
- var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable
- var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with
- var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place
- var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target
-
- var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting
-
- var/list/speech_buffer = list() // Last phrase said near it and person who said it
-
- var/mood = "" // To show its face
- var/is_adult = 0
- var/docile = 0
- var/core_removal_stage = 0 //For removing cores.
- var/mutator_used = FALSE //So you can't shove a dozen mutators into a single slime
-
- ///////////TIME FOR SUBSPECIES
-
- var/colour = "grey"
- var/coretype = /obj/item/slime_extract/grey
- var/list/slime_mutation[4]
-
-/mob/living/carbon/slime/New()
- create_reagents(100)
- spawn (0)
- number = rand(1, 1000)
- name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
- icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
- real_name = name
- slime_mutation = mutation_table(colour)
- var/sanitizedcolour = replacetext(colour, " ", "")
- coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
- ..()
-
-/mob/living/carbon/slime/random/New()
- colour = pick("grey","orange", "metal", "blue", "purple", "dark purple", "dark blue", "green", "silver", "yellow", "gold", "yellow", "red", "silver", "pink", "cerulean", "sepia", "bluespace", "pyrite", "light pink", "oil", "adamantine", "black")
- ..()
-
-/mob/living/carbon/slime/Destroy()
- for(var/obj/machinery/computer/camera_advanced/xenobio/X in GLOB.machines)
- if(src in X.stored_slimes)
- X.stored_slimes -= src
- return ..()
-
-/mob/living/carbon/slime/can_unbuckle()
- return FALSE
-
-/mob/living/carbon/slime/can_buckle()
- return FALSE
-
-/mob/living/carbon/slime/get_mob_buckling_height(mob/seat)
- if(..())
- return 3
-
-/mob/living/carbon/slime/regenerate_icons()
- icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
- overlays.len = 0
- if(mood)
- overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
- ..()
-
-/mob/living/carbon/slime/movement_delay()
- if(bodytemperature >= 330.23) // 135 F
- return -1 // slimes become supercharged at high temperatures
-
- . = ..()
-
- var/health_deficiency = (100 - health)
- if(health_deficiency >= 45)
- . += (health_deficiency / 25)
-
- if(bodytemperature < 183.222)
- . += (283.222 - bodytemperature) / 10 * 1.75
-
- if(reagents)
- if(reagents.has_reagent("methamphetamine")) // Meth slows slimes down
- . *= 2
-
- if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
- . *= 5
-
- if(health <= 0) // if damaged, the slime moves twice as slow
- . *= 2
-
- . += config.slime_delay
-
-/mob/living/carbon/slime/ObjBump(obj/O)
- if(!client && powerlevel > 0)
- var/chance = 10
- switch(powerlevel)
- if(1 to 2) chance = 20
- if(3 to 4) chance = 30
- if(5 to 6) chance = 40
- if(7 to 8) chance = 60
- if(9) chance = 70
- if(10) chance = 95
- if(prob(chance))
- if(istype(O, /obj/structure/window) || istype(O, /obj/structure/grille))
- if(nutrition <= get_hunger_nutrition() && !Atkcool)
- if(is_adult || prob(5))
- O.attack_slime(src)
- Atkcool = 1
- spawn(45)
- Atkcool = 0
-
-/mob/living/carbon/slime/Process_Spacemove(var/movement_dir = 0)
- return 2
-
-/mob/living/carbon/slime/Stat()
- ..()
-
- statpanel("Status")
- if(is_adult)
- stat(null, "Health: [round((health / 200) * 100)]%")
- else
- stat(null, "Health: [round((health / 150) * 100)]%")
-
- if(client.statpanel == "Status")
- if(!docile)
- stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]")
- if(amount_grown >= 10)
- if(is_adult)
- stat(null, "You can reproduce!")
- else
- stat(null, "You can evolve!")
-
- stat(null,"Power Level: [powerlevel]")
-
-/mob/living/carbon/slime/updatehealth(reason)
- . = ..()
- update_health_hud()
-
-/mob/living/carbon/slime/proc/update_health_hud()
- if(hud_used)
- var/severity = 0
- var/healthpercent = (health/maxHealth) * 100
- if(stat != DEAD)
- switch(healthpercent)
- if(100 to INFINITY)
- healths.icon_state = "slime_health0"
- if(80 to 100)
- healths.icon_state = "slime_health1"
- severity = 1
- if(60 to 80)
- healths.icon_state = "slime_health2"
- severity = 2
- if(40 to 60)
- healths.icon_state = "slime_health3"
- severity = 3
- if(20 to 40)
- healths.icon_state = "slime_health4"
- severity = 4
- if(0 to 20)
- healths.icon_state = "slime_health5"
- severity = 5
- if(-199 to 0)
- healths.icon_state = "slime_health6"
- severity = 6
- else
- healths.icon_state = "slime_health7"
- severity = 6
- if(severity > 0)
- overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
- else
- clear_fullscreen("brute")
-
-/mob/living/carbon/slime/adjustFireLoss(amount)
- ..(-abs(amount)) // Heals them
- return
-
-/mob/living/carbon/slime/bullet_act(var/obj/item/projectile/Proj)
- attacked += 10
- ..(Proj)
- return 0
-
-/mob/living/carbon/slime/emp_act(severity)
- powerlevel = 0 // oh no, the power!
- ..()
-
-/mob/living/carbon/slime/ex_act(severity)
- ..()
-
- var/b_loss = null
- var/f_loss = null
- switch(severity)
- if(1.0)
- qdel(src)
- return
-
- if(2.0)
-
- b_loss += 60
- f_loss += 60
-
-
- if(3.0)
- b_loss += 30
-
- adjustBruteLoss(b_loss)
- adjustFireLoss(f_loss)
-
- updatehealth()
-
-
-/mob/living/carbon/slime/blob_act()
- show_message(" The blob attacks you!")
- adjustBruteLoss(20)
- updatehealth()
- return
-
-/mob/living/carbon/slime/MouseDrop(atom/movable/A)
- if(isliving(A) && A != src && usr == src)
- var/mob/living/Food = A
- if(Food.Adjacent(src) && !stat && Food.stat != DEAD) //messy
- Feedon(Food)
- ..()
-
-/mob/living/carbon/slime/unEquip(obj/item/W as obj, force)
- return
-
-/mob/living/carbon/slime/attack_ui(slot)
- return
-
-/mob/living/carbon/slime/attack_slime(mob/living/carbon/slime/M)
- ..()
- if(Victim)
- Victim = null
- visible_message("[M] pulls [src] off!")
- return
- attacked += 5
- if(nutrition >= 100) //steal some nutrition. negval handled in life()
- nutrition -= (50 + (5 * M.amount_grown))
- M.add_nutrition(50 + (5 * M.amount_grown))
- if(health > 0)
- adjustBruteLoss(4 + (2 * M.amount_grown)) //amt_grown isn't very linear but it works
- updatehealth()
- M.adjustBruteLoss(-4 + (-2 * M.amount_grown))
- M.updatehealth()
-
-/mob/living/carbon/slime/attack_animal(mob/living/simple_animal/M)
- . = ..()
- if(.)
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- attacked += 10
- adjustBruteLoss(damage)
- updatehealth()
-
-/mob/living/carbon/slime/attack_larva(mob/living/carbon/alien/larva/L)
- if(..()) //successful larva bite.
- var/damage = rand(1, 3)
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- adjustBruteLoss(damage)
- updatehealth()
-
-/mob/living/carbon/slime/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
- if(user.a_intent == INTENT_HARM)
- if(Victim || Target)
- Victim = null
- Target = null
- anchored = 0
- if(prob(80) && !client)
- Discipline++
- spawn(0)
- step_away(src, user, 15)
- sleep(3)
- step_away(src, user, 15)
- ..(user, TRUE)
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[user] has punched [src]!", "[user] has punched [src]!")
- adjustBruteLoss(15)
- return TRUE
-
-/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M)
- if(Victim)
- M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- if(Victim == M)
- if(prob(60))
- visible_message("[M] attempts to wrestle \the [name] off!")
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
-
- else
- visible_message(" [M] manages to wrestle \the [name] off!")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- if(prob(90) && !client)
- Discipline++
-
- SStun = 1
- spawn(rand(45,60))
- SStun = 0
-
- Victim = null
- anchored = 0
- step_away(src,M)
-
- return
-
- else
- if(prob(30))
- visible_message("[M] attempts to wrestle \the [name] off of [Victim]!")
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
-
- else
- visible_message(" [M] manages to wrestle \the [name] off of [Victim]!")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- if(prob(80) && !client)
- Discipline++
-
- if(!is_adult)
- if(Discipline == 1)
- attacked = 0
-
- SStun = 1
- spawn(rand(55,65))
- SStun = 0
-
- Victim = null
- anchored = 0
- step_away(src,M)
-
- return
-
- if(..()) //To allow surgery to return properly.
- return
-
- switch(M.a_intent)
-
- if(INTENT_HELP)
- help_shake_act(M)
-
- if(INTENT_GRAB)
- grabbedby(M)
-
- else
- M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- var/damage = rand(1, 9)
- attacked += 10
- if(prob(90))
- playsound(loc, "punch", 25, 1, -1)
- add_attack_logs(M, src, "Melee attacked with fists")
- visible_message("[M] has punched [src]!", \
- "[M] has punched [src]!")
- if(stat != DEAD)
- adjustBruteLoss(damage)
- updatehealth()
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to punch [src]!")
- return
-
-/mob/living/carbon/slime/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- if(M.a_intent == INTENT_HARM)
- if(prob(95))
- attacked += 10
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- var/damage = rand(15, 30)
- if(damage >= 25)
- damage = rand(20, 40)
- visible_message("[M] has slashed [name]!", \
- "[M] has slashed [name]!")
- else
- visible_message("[M] has wounded [name]!", \
- ")[M] has wounded [name]!")
- add_attack_logs(M, src, "Alien attacked")
- if(stat != DEAD)
- adjustBruteLoss(damage)
- updatehealth()
- else
- playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to lunge at [name]!", \
- "[M] has attempted to lunge at [name]!")
-
- if(M.a_intent == INTENT_DISARM)
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- var/damage = 5
- attacked += 10
-
- if(prob(95))
- visible_message("[M] has tackled [name]!", \
- "[M] has tackled [name]!")
-
- if(Victim || Target)
- Victim = null
- Target = null
- anchored = 0
- if(prob(80) && !client)
- Discipline++
- if(!isslime(src))
- if(Discipline == 1)
- attacked = 0
-
- SStun = 1
- spawn(rand(5,20))
- SStun = 0
-
- spawn(0)
-
- step_away(src,M,15)
- sleep(3)
- step_away(src,M,15)
-
- else
- drop_item()
- visible_message("[M] has disarmed [name]!",
- "[M] has disarmed [name]!")
- add_attack_logs(M, src, "Alien disarmed")
- adjustBruteLoss(damage)
- updatehealth()
- return
-
-/mob/living/carbon/slime/attackby(obj/item/W, mob/living/user, params)
- if(istype(W,/obj/item/stack/sheet/mineral/plasma)) //Lets you feed slimes plasma.
- if(user in Friends)
- ++Friends[user]
- else
- Friends[user] = 1
- to_chat(user, "You feed the slime the plasma. It chirps happily.")
- var/obj/item/stack/sheet/mineral/plasma/S = W
- S.use(1)
- return
- else if(W.force > 0)
- attacked += 10
- if(prob(25))
- user.do_attack_animation(src)
- to_chat(user, "[W] passes right through [src]!")
- return
- if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
- Discipline = 0
- else if(W.force >= 3)
- if(is_adult)
- if(prob(5 + round(W.force/2)))
- if(Victim || Target)
- if(prob(80) && !client)
- Discipline++
-
- Victim = null
- Target = null
- anchored = 0
-
- SStun = 1
- spawn(rand(5,20))
- SStun = 0
-
- spawn(0)
- if(user)
- canmove = 0
- step_away(src, user)
- if(prob(25 + W.force))
- sleep(2)
- if(user)
- step_away(src, user)
- canmove = 1
-
- else
- if(prob(10 + W.force*2))
- if(Victim || Target)
- if(prob(80) && !client)
- Discipline++
- if(Discipline == 1)
- attacked = 0
- SStun = 1
- spawn(rand(5,20))
- SStun = 0
-
- Victim = null
- Target = null
- anchored = 0
-
- spawn(0)
- if(user)
- canmove = 0
- step_away(src, user)
- if(prob(25 + W.force*4))
- sleep(2)
- if(user)
- step_away(src, user)
- canmove = 1
- ..()
-
-/mob/living/carbon/slime/restrained()
- return 0
-
-mob/living/carbon/slime/var/temperature_resistance = T0C+75
-
-/mob/living/carbon/slime/show_inv(mob/user)
- return
-
-/mob/living/carbon/slime/toggle_throw_mode()
- return
-
-/mob/living/carbon/slime/water_act(volume, temperature, source, method = TOUCH)
- . = ..()
-
- var/water_damage = rand(10, 15) * volume
- adjustToxLoss(water_damage)
-
- if(!client && Target && volume >= 3)
- Target = null
- ++Discipline
-
-/mob/living/carbon/slime/can_use_vents()
- if(Victim)
- return "You cannot ventcrawl while feeding."
- ..()
-
-/mob/living/carbon/slime/forceFed(var/obj/item/reagent_containers/food/toEat, mob/user, fullness)
- if(istype(toEat, /obj/item/reagent_containers/food/drinks))
- return 1
- to_chat(user, "This creature does not seem to have a mouth!")
- return 0
-
-/mob/living/carbon/slime/can_hear()
- . = TRUE //honestly fuck slimes and organ bullshit
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/slime/update_icons.dm b/code/modules/mob/living/carbon/slime/update_icons.dm
deleted file mode 100644
index 2310f32a76e..00000000000
--- a/code/modules/mob/living/carbon/slime/update_icons.dm
+++ /dev/null
@@ -1 +0,0 @@
-//no special icon processing
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index ea3db60383d..3d3fb2b3d49 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -541,10 +541,6 @@
if(s_active && !(s_active in contents) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much.
s_active.close(src)
- if(update_slimes)
- for(var/mob/living/carbon/slime/M in view(1,src))
- M.UpdateFeed(src)
-
/mob/living/proc/handle_footstep(turf/T)
if(istype(T))
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index e9cfac7ae0a..ce758f0e856 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -277,33 +277,21 @@
return G
-/mob/living/attack_slime(mob/living/carbon/slime/M)
+/mob/living/attack_slime(mob/living/simple_animal/slime/M)
if(!SSticker)
to_chat(M, "You cannot attack people before the game has started.")
return
- if(M.Victim)
+ if(M.buckled)
+ if(M in buckled_mobs)
+ M.Feedstop()
return // can't attack while eating!
if(stat != DEAD)
+ add_attack_logs(src, M, "Slime'd")
M.do_attack_animation(src)
- visible_message("The [M.name] glomps [src]!", \
- "The [M.name] glomps [src]!")
-
- if(M.powerlevel > 0)
- var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
- if(prob(stunprob))
- M.powerlevel -= 3
- if(M.powerlevel < 0)
- M.powerlevel = 0
-
- visible_message("The [M.name] has shocked [src]!", \
- "The [M.name] has shocked [src]!")
-
- do_sparks(5, 1, src)
- return 1
- add_attack_logs(src, M, "Slime'd")
- return
+ visible_message("\The [M.name] glomps [src]!", "\The [M.name] glomps you!")
+ return TRUE
/mob/living/attack_animal(mob/living/simple_animal/M)
M.face_atom(src)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 1e3343f90f7..5bc42caab14 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -28,7 +28,6 @@
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
- var/update_slimes = 1
var/implanting = 0 //Used for the mind-slave implant
var/floating = 0
var/mob_size = MOB_SIZE_HUMAN
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
index c8ffebc6647..702b745e4fc 100644
--- a/code/modules/mob/living/silicon/ai/ai_defense.dm
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -4,5 +4,5 @@
return
..()
-/mob/living/silicon/ai/attack_slime(mob/living/carbon/slime/user)
+/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
return //immune to slimes
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 85cc2ad5786..9b4f1089f46 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -19,7 +19,7 @@
..()
return
-/mob/living/silicon/robot/attack_slime(mob/living/carbon/slime/M)
+/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M)
if(..()) //successful slime shock
flash_eyes(affect_silicon = 1)
var/stunprob = M.powerlevel * 7 + 10
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 119eb1b29c0..d827bf03692 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -58,12 +58,12 @@
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
return attack_threshold_check(damage, M.melee_damage_type)
-/mob/living/simple_animal/attack_slime(mob/living/carbon/slime/M)
- ..()
- var/damage = rand(15, 25)
- if(M.is_adult)
- damage = rand(20, 35)
- attack_threshold_check(damage)
+/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(15, 25)
+ if(M.is_adult)
+ damage = rand(20, 35)
+ return attack_threshold_check(damage)
/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE, armorcheck = "melee")
var/temp_damage = damage
diff --git a/code/modules/mob/living/simple_animal/friendly/slime.dm b/code/modules/mob/living/simple_animal/friendly/slime.dm
deleted file mode 100644
index ac913170c86..00000000000
--- a/code/modules/mob/living/simple_animal/friendly/slime.dm
+++ /dev/null
@@ -1,60 +0,0 @@
-/mob/living/simple_animal/slime
- name = "pet slime"
- desc = "A lovable, domesticated slime."
- icon = 'icons/mob/slimes.dmi'
- icon_state = "grey baby slime"
- icon_living = "grey baby slime"
- icon_dead = "grey baby slime dead"
- speak_emote = list("chirps")
- health = 100
- maxHealth = 100
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
- emote_see = list("jiggles", "bounces in place")
- pass_flags = PASSTABLE
- var/colour = "grey"
-
-/mob/living/simple_animal/slime/adult
- health = 200
- maxHealth = 200
- icon_state = "grey adult slime"
- icon_living = "grey adult slime"
-
-/mob/living/simple_animal/slime/New()
- ..()
- overlays += "aslime-:33"
-
-/mob/living/simple_animal/slime/updatehealth(reason)
- . = ..()
- update_health_hud()
-
-/mob/living/simple_animal/slime/proc/update_health_hud()
- if(hud_used)
- var/severity = 0
- var/healthpercent = (health/maxHealth) * 100
- switch(healthpercent)
- if(100 to INFINITY)
- healths.icon_state = "slime_health0"
- if(80 to 100)
- healths.icon_state = "slime_health1"
- severity = 1
- if(60 to 80)
- healths.icon_state = "slime_health2"
- severity = 2
- if(40 to 60)
- healths.icon_state = "slime_health3"
- severity = 3
- if(20 to 40)
- healths.icon_state = "slime_health4"
- severity = 4
- if(1 to 20)
- healths.icon_state = "slime_health5"
- severity = 5
- else
- healths.icon_state = "slime_health7"
- severity = 6
- if(severity > 0)
- overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
- else
- clear_fullscreen("brute")
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 2e126412580..502adb937e3 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -605,7 +605,7 @@
real_name = P.tagname
/mob/living/simple_animal/regenerate_icons()
- cut_overlays()
if(pcollar && collar_type)
+ cut_overlays()
add_overlay("[collar_type]collar")
add_overlay("[collar_type]tag")
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/slime/death.dm b/code/modules/mob/living/simple_animal/slime/death.dm
new file mode 100644
index 00000000000..29a1adbd347
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/death.dm
@@ -0,0 +1,32 @@
+/mob/living/simple_animal/slime/death(gibbed)
+ if(stat == DEAD)
+ return
+ if(!gibbed)
+ if(is_adult)
+ var/mob/living/simple_animal/slime/M = new(loc, colour)
+ M.rabid = TRUE
+ M.regenerate_icons()
+
+ is_adult = FALSE
+ maxHealth = 150
+ for(var/datum/action/innate/slime/reproduce/R in actions)
+ R.Remove(src)
+ var/datum/action/innate/slime/evolve/E = new
+ E.Grant(src)
+ revive()
+ regenerate_icons()
+ update_name()
+ return
+
+ if(buckled)
+ Feedstop(silent = TRUE) //releases ourselves from the mob we fed on.
+
+ stat = DEAD //Temporarily set to dead for icon updates
+ regenerate_icons()
+ stat = CONSCIOUS
+
+ return ..(gibbed)
+
+/mob/living/simple_animal/slime/gib()
+ death(TRUE)
+ qdel(src)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/slime/emote.dm b/code/modules/mob/living/simple_animal/slime/emote.dm
similarity index 95%
rename from code/modules/mob/living/carbon/slime/emote.dm
rename to code/modules/mob/living/simple_animal/slime/emote.dm
index c938ac17214..7fc7f4c5f87 100644
--- a/code/modules/mob/living/carbon/slime/emote.dm
+++ b/code/modules/mob/living/simple_animal/slime/emote.dm
@@ -1,4 +1,7 @@
-/mob/living/carbon/slime/emote(act, m_type = 1, message = null, force)
+/mob/living/simple_animal/slime/emote(act, m_type = 1, message = null, force)
+ if(stat)
+ return
+
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
//param = copytext(act, t1 + 1, length(act) + 1)
@@ -99,6 +102,4 @@
loc.audible_message(message)
if(regenerate_icons)
- regenerate_icons()
-
- return
\ No newline at end of file
+ regenerate_icons()
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
new file mode 100644
index 00000000000..efd4c19d55c
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -0,0 +1,617 @@
+
+/mob/living/simple_animal/slime
+ var/AIproc = 0 // determines if the AI loop is activated
+ var/Atkcool = 0 // attack cooldown
+ var/Tempstun = 0 // temporary temperature stuns
+ var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while
+ var/SStun = 0 // stun variable
+
+
+/mob/living/simple_animal/slime/Life()
+ set invisibility = 0
+ if(notransform)
+ return
+ if(..())
+ if(buckled)
+ handle_feeding()
+ if(!stat) // Slimes in stasis don't lose nutrition, don't change mood and don't respond to speech
+ handle_nutrition()
+ if(QDELETED(src)) // Stop if the slime split during handle_nutrition()
+ return
+ reagents.remove_all(0.5 * REAGENTS_METABOLISM * reagents.reagent_list.len) //Slimes are such snowflakes
+ handle_targets()
+ if(!ckey)
+ handle_mood()
+ handle_speech()
+
+// Unlike most of the simple animals, slimes support UNCONSCIOUS
+/mob/living/simple_animal/slime/update_stat()
+ if(stat == UNCONSCIOUS && health > 0)
+ return
+ ..()
+
+/mob/living/simple_animal/slime/proc/AIprocess() // the master AI process
+
+ if(AIproc || stat || client)
+ return
+
+ var/hungry = 0
+ if (nutrition < get_starve_nutrition())
+ hungry = 2
+ else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
+ hungry = 1
+
+ AIproc = 1
+
+ while(AIproc && stat != DEAD && (attacked || hungry || rabid || buckled))
+ if(!canmove) //also covers buckling. Not sure why buckled is in the while condition if we're going to immediately break, honestly
+ break
+
+ if(!Target || client)
+ break
+
+ if(Target.health <= -70 || Target.stat == DEAD)
+ Target = null
+ AIproc = 0
+ break
+
+ if(Target)
+ if(locate(/mob/living/simple_animal/slime) in Target.buckled_mobs)
+ Target = null
+ AIproc = 0
+ break
+ if(!AIproc)
+ break
+
+ if(Target in view(1,src))
+ if(!CanFeedon(Target)) //If they're not able to be fed upon, ignore them.
+ if(!Atkcool)
+ Atkcool = TRUE
+ addtimer(VARSET_CALLBACK(src, Atkcool, FALSE), 4.5 SECONDS)
+
+ if(Target.Adjacent(src))
+ Target.attack_slime(src)
+ break
+ if(!Target.lying && prob(80))
+
+ if(Target.client && Target.health >= 20)
+ if(!Atkcool)
+ Atkcool = TRUE
+ addtimer(VARSET_CALLBACK(src, Atkcool, FALSE), 4.5 SECONDS)
+
+ if(Target.Adjacent(src))
+ Target.attack_slime(src)
+
+ else
+ if(!Atkcool && Target.Adjacent(src))
+ Feedon(Target)
+
+ else
+ if(!Atkcool && Target.Adjacent(src))
+ Feedon(Target)
+
+ else if(Target in view(7, src))
+ if(!Target.Adjacent(src))
+ // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them
+ step_to(src, Target)
+ else
+ Target = null
+ AIproc = 0
+ break
+
+ var/sleeptime = movement_delay()
+ if(sleeptime <= 0)
+ sleeptime = 1
+
+ sleep(sleeptime + 2) // this is about as fast as a player slime can go
+
+ AIproc = 0
+
+/mob/living/simple_animal/slime/handle_environment(datum/gas_mixture/environment)
+ if(!environment)
+ return
+
+ var/loc_temp = get_temperature(environment)
+
+ adjust_bodytemperature(adjust_body_temperature(bodytemperature, loc_temp, 1))
+
+ //Account for massive pressure differences
+
+ if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc
+ if(bodytemperature <= (T0C - 40)) // stun temperature
+ Tempstun = 1
+
+ if(bodytemperature <= (T0C - 50)) // hurt temperature
+ if(bodytemperature <= 50) // sqrting negative numbers is bad
+ adjustBruteLoss(200)
+ else
+ adjustBruteLoss(round(sqrt(bodytemperature)) * 2)
+
+ else
+ Tempstun = 0
+
+ updatehealth("handle environment")
+
+
+ return //TODO: DEFERRED
+
+/mob/living/simple_animal/slime/proc/adjust_body_temperature(current, loc_temp, boost)
+ var/temperature = current
+ var/difference = abs(current - loc_temp) //get difference
+ var/increments// = difference/10 //find how many increments apart they are
+ if(difference > 50)
+ increments = difference / 5
+ else
+ increments = difference / 10
+ var/change = increments * boost // Get the amount to change by (x per increment)
+ var/temp_change
+ if(current < loc_temp)
+ temperature = min(loc_temp, temperature+change)
+ else if(current > loc_temp)
+ temperature = max(loc_temp, temperature-change)
+ temp_change = (temperature - current)
+ return temp_change
+
+/mob/living/simple_animal/slime/handle_status_effects()
+ ..()
+ if(prob(30) && !stat)
+ adjustBruteLoss(-1)
+
+/mob/living/simple_animal/slime/proc/handle_feeding()
+ if(!ismob(buckled))
+ return
+ var/mob/M = buckled
+
+ if(stat)
+ Feedstop(silent = TRUE)
+
+ if(M.stat == DEAD) // our victim died
+ if(!client)
+ if(!rabid && !attacked)
+ if(M.LAssailant && M.LAssailant != M)
+ if(prob(50))
+ if(!(M.LAssailant in Friends))
+ Friends[M.LAssailant] = 1
+ else
+ ++Friends[M.LAssailant]
+ else
+ to_chat(src, "This subject does not have a strong enough life energy anymore...")
+
+ if(M.client && ishuman(M))
+ if(prob(85))
+ rabid = 1 //we go rabid after finishing to feed on a human with a client.
+
+ Feedstop()
+ return
+
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.adjustCloneLoss(rand(2, 4))
+ C.adjustToxLoss(rand(1, 2))
+
+ if(prob(10) && C.client)
+ to_chat(C, "[pick("You can feel your body becoming weak!", \
+ "You feel like you're about to die!", \
+ "You feel every part of your body screaming in agony!", \
+ "A low, rolling pain passes through your body!", \
+ "Your body feels as if it's falling apart!", \
+ "You feel extremely weak!", \
+ "A sharp, deep pain bathes every inch of your body!")]")
+
+ else if(isanimal(M))
+ var/mob/living/simple_animal/SA = M
+
+ var/totaldamage = 0 //total damage done to this unfortunate animal
+ totaldamage += SA.adjustCloneLoss(rand(2, 4))
+ totaldamage += SA.adjustToxLoss(rand(1, 2))
+
+ if(totaldamage <= 0) //if we did no(or negative!) damage to it, stop
+ Feedstop(0, 0)
+ return
+
+ else
+ Feedstop(0, 0)
+ return
+
+ add_nutrition(rand(7, 15))
+
+ //Heal yourself.
+ adjustBruteLoss(-3)
+
+/mob/living/simple_animal/slime/proc/handle_nutrition()
+
+ if(docile) //God as my witness, I will never go hungry again
+ set_nutrition(700) //fuck you for using the base nutrition var
+ return
+
+ if(prob(15))
+ adjust_nutrition(-(1 + is_adult))
+
+ if(nutrition <= 0)
+ set_nutrition(0)
+ if(prob(75))
+ adjustBruteLoss(rand(0, 5))
+
+ else if(nutrition >= get_grow_nutrition() && amount_grown < SLIME_EVOLUTION_THRESHOLD)
+ adjust_nutrition(-20)
+ amount_grown++
+ update_action_buttons_icon()
+
+ if(amount_grown >= SLIME_EVOLUTION_THRESHOLD && !buckled && !Target && !ckey)
+ if(is_adult)
+ Reproduce()
+ else
+ Evolve()
+
+/mob/living/simple_animal/slime/proc/add_nutrition(nutrition_to_add = 0)
+ set_nutrition(min((nutrition + nutrition_to_add), get_max_nutrition()))
+ if(nutrition >= get_grow_nutrition())
+ if(powerlevel<10)
+ if(prob(30-powerlevel*2))
+ powerlevel++
+ else if(nutrition >= get_hunger_nutrition() + 100) //can't get power levels unless you're a bit above hunger level.
+ if(powerlevel<5)
+ if(prob(25-powerlevel*5))
+ powerlevel++
+
+
+
+
+/mob/living/simple_animal/slime/proc/handle_targets()
+ update_canmove()
+ if(Tempstun)
+ if(!buckled) // not while they're eating!
+ canmove = 0
+ else
+ canmove = 1
+
+ if(attacked > 50)
+ attacked = 50
+
+ if(attacked > 0)
+ attacked--
+
+ if(Discipline > 0)
+
+ if(Discipline >= 5 && rabid)
+ if(prob(60))
+ rabid = 0
+
+ if(prob(10))
+ Discipline--
+
+ if(!client)
+ if(!canmove)
+ return
+
+ if(buckled)
+ return // if it's eating someone already, continue eating!
+
+ if(Target)
+ --target_patience
+ if (target_patience <= 0 || SStun > world.time || Discipline || attacked || docile) // Tired of chasing or something draws out attention
+ target_patience = 0
+ Target = null
+
+ if(AIproc && SStun > world.time)
+ return
+
+ var/hungry = 0 // determines if the slime is hungry
+
+ if (nutrition < get_starve_nutrition())
+ hungry = 2
+ else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
+ hungry = 1
+
+ if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
+ if(Friends.len > 0 && prob(1))
+ var/mob/nofriend = pick(Friends)
+ --Friends[nofriend]
+
+ if(!Target)
+ if(will_hunt() && hungry || attacked || rabid) // Only add to the list if we need to
+ var/list/targets = list()
+
+ for(var/mob/living/L in view(7,src))
+
+ if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
+ continue
+
+ if(L in Friends) // No eating friends!
+ continue
+
+ var/ally = FALSE
+ for(var/F in faction)
+ if(F == "neutral") //slimes are neutral so other mobs not target them, but they can target neutral mobs
+ continue
+ if(F in L.faction)
+ ally = TRUE
+ break
+ if(ally)
+ continue
+
+ if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
+ targets += L // Possible target found!
+
+ if(locate(/mob/living/simple_animal/slime) in L.buckled_mobs) // Only one slime can latch on at a time.
+ continue
+
+ targets += L // Possible target found!
+
+ if(targets.len > 0)
+ if(attacked || rabid || hungry == 2)
+ Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
+ else
+ for(var/mob/living/carbon/C in targets)
+ if(!Discipline && prob(5))
+ if(ishuman(C) || isalienadult(C))
+ Target = C
+ break
+
+ if(islarva(C) || issmall(C))
+ Target = C
+ break
+
+ if (Target)
+ target_patience = rand(5, 7)
+ if(is_adult)
+ target_patience += 3
+
+ if(!Target) // If we have no target, we are wandering or following orders
+ if (Leader)
+ if(holding_still)
+ holding_still = max(holding_still - 1, 0)
+ else if(canmove && isturf(loc))
+ step_to(src, Leader)
+
+ else if(hungry)
+ if (holding_still)
+ holding_still = max(holding_still - hungry, 0)
+ else if(canmove && isturf(loc) && prob(50))
+ step(src, pick(cardinal))
+
+ else
+ if(holding_still)
+ holding_still = max(holding_still - 1, 0)
+ else if (docile && pulledby)
+ holding_still = 10
+ else if(canmove && isturf(loc) && prob(33))
+ step(src, pick(cardinal))
+ else if(!AIproc)
+ INVOKE_ASYNC(src, .proc/AIprocess)
+
+/mob/living/simple_animal/slime/handle_automated_movement()
+ return //slime random movement is currently handled in handle_targets()
+
+/mob/living/simple_animal/slime/handle_automated_speech()
+ return //slime random speech is currently handled in handle_speech()
+
+/mob/living/simple_animal/slime/proc/handle_mood()
+ var/newmood = ""
+ if (rabid || attacked)
+ newmood = "angry"
+ else if (docile)
+ newmood = ":3"
+ else if (Target)
+ newmood = "mischievous"
+
+ if (!newmood)
+ if (Discipline && prob(25))
+ newmood = "pout"
+ else if (prob(1))
+ newmood = pick("sad", ":3", "pout")
+
+ if ((mood == "sad" || mood == ":3" || mood == "pout") && !newmood)
+ if(prob(75))
+ newmood = mood
+
+ if(newmood != mood) // This is so we don't redraw them every time
+ mood = newmood
+ regenerate_icons()
+
+/mob/living/simple_animal/slime/proc/handle_speech()
+ //Speech understanding starts here
+ var/to_say
+ if(speech_buffer.len > 0)
+ var/who = speech_buffer[1] // Who said it?
+ var/phrase = speech_buffer[2] // What did they say?
+ if((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us
+ if(findtext(phrase, "hello") || findtext(phrase, "hi"))
+ to_say = pick("Hello...", "Hi...")
+ else if(findtext(phrase, "follow"))
+ if(Leader)
+ if(Leader == who) // Already following him
+ to_say = pick("Yes...", "Lead...", "Follow...")
+ else if(Friends[who] > Friends[Leader]) // VIVA
+ Leader = who
+ to_say = "Yes... I follow [who]..."
+ else
+ to_say = "No... I follow [Leader]..."
+ else
+ if(Friends[who] >= SLIME_FRIENDSHIP_FOLLOW)
+ Leader = who
+ to_say = "I follow..."
+ else // Not friendly enough
+ to_say = pick("No...", "I no follow...")
+ else if(findtext(phrase, "stop"))
+ if(buckled) // We are asked to stop feeding
+ if (Friends[who] >= SLIME_FRIENDSHIP_STOPEAT)
+ Feedstop()
+ Target = null
+ if (Friends[who] < SLIME_FRIENDSHIP_STOPEAT_NOANGRY)
+ --Friends[who]
+ to_say = "Grrr..." // I'm angry but I do it
+ else
+ to_say = "Fine..."
+ else if(Target) // We are asked to stop chasing
+ if(Friends[who] >= SLIME_FRIENDSHIP_STOPCHASE)
+ Target = null
+ if(Friends[who] < SLIME_FRIENDSHIP_STOPCHASE_NOANGRY)
+ --Friends[who]
+ to_say = "Grrr..." // I'm angry but I do it
+ else
+ to_say = "Fine..."
+ else if(Leader) // We are asked to stop following
+ if(Leader == who)
+ to_say = "Yes... I stay..."
+ Leader = null
+ else
+ if(Friends[who] > Friends[Leader])
+ Leader = null
+ to_say = "Yes... I stop..."
+ else
+ to_say = "No... keep follow..."
+ else if(findtext(phrase, "stay"))
+ if(Leader)
+ if (Leader == who)
+ holding_still = Friends[who] * 10
+ to_say = "Yes... stay..."
+ else if(Friends[who] > Friends[Leader])
+ holding_still = (Friends[who] - Friends[Leader]) * 10
+ to_say = "Yes... stay..."
+ else
+ to_say = "No... keep follow..."
+ else
+ if(Friends[who] >= SLIME_FRIENDSHIP_STAY)
+ holding_still = Friends[who] * 10
+ to_say = "Yes... stay..."
+ else
+ to_say = "No... won't stay..."
+ else if(findtext(phrase, "attack"))
+ if(rabid && prob(20))
+ Target = who
+ AIprocess() //Wake up the slime's Target AI, needed otherwise this doesn't work
+ to_say = "ATTACK!?!?"
+ else if(Friends[who] >= SLIME_FRIENDSHIP_ATTACK)
+ for(var/mob/living/L in view(7,src)-list(src,who))
+ if(findtext(phrase, lowertext(L.name)))
+ if(isslime(L))
+ to_say = "NO... [L] slime friend"
+ --Friends[who] //Don't ask a slime to attack its friend
+ else if(!Friends[L] || Friends[L] < 1)
+ Target = L
+ AIprocess()//Wake up the slime's Target AI, needed otherwise this doesn't work
+ to_say = "Ok... I attack [Target]"
+ else
+ to_say = "No... like [L] ..."
+ --Friends[who] //Don't ask a slime to attack its friend
+ break
+ else
+ to_say = "No... no listen"
+
+ speech_buffer = list()
+
+ //Speech starts here
+ if(to_say)
+ say (to_say)
+ else if(prob(1))
+ emote(pick("bounce", "sway", "light", "vibrate", "jiggle"))
+ else
+ var/t = 10
+ var/slimes_near = 0
+ var/dead_slimes = 0
+ var/friends_near = list()
+ for(var/mob/living/L in view(7,src))
+ if(isslime(L) && L != src)
+ ++slimes_near
+ if (L.stat == DEAD)
+ ++dead_slimes
+ if(L in Friends)
+ t += 20
+ friends_near += L
+ if(nutrition < get_hunger_nutrition())
+ t += 10
+ if(nutrition < get_starve_nutrition())
+ t += 10
+ if(prob(2) && prob(t))
+ var/phrases = list()
+ if(Target)
+ phrases += "[Target]... look yummy..."
+ if(nutrition < get_starve_nutrition())
+ phrases += "So... hungry..."
+ phrases += "Very... hungry..."
+ phrases += "Need... food..."
+ phrases += "Must... eat..."
+ else if(nutrition < get_hunger_nutrition())
+ phrases += "Hungry..."
+ phrases += "Where food?"
+ phrases += "I want to eat..."
+ phrases += "Rawr..."
+ phrases += "Blop..."
+ phrases += "Blorble..."
+ if(rabid || attacked)
+ phrases += "Hrr..."
+ phrases += "Nhuu..."
+ phrases += "Unn..."
+ if(mood == ":3")
+ phrases += "Purr..."
+ if(attacked)
+ phrases += "Grrr..."
+ if(bodytemperature < T0C)
+ phrases += "Cold..."
+ if(bodytemperature < T0C - 30)
+ phrases += "So... cold..."
+ phrases += "Very... cold..."
+ if(bodytemperature < T0C - 50)
+ phrases += "..."
+ phrases += "C... c..."
+ if(buckled)
+ phrases += "Nom..."
+ phrases += "Yummy..."
+ if(powerlevel > 3)
+ phrases += "Bzzz..."
+ if(powerlevel > 5)
+ phrases += "Zap..."
+ if(powerlevel > 8)
+ phrases += "Zap... Bzz..."
+ if(mood == "sad")
+ phrases += "Bored..."
+ if(slimes_near)
+ phrases += "Slime friend..."
+ if(slimes_near > 1)
+ phrases += "Slime friends..."
+ if(dead_slimes)
+ phrases += "What happened?"
+ if(!slimes_near)
+ phrases += "Lonely..."
+ for(var/M in friends_near)
+ phrases += "[M]... friend..."
+ if(nutrition < get_hunger_nutrition())
+ phrases += "[M]... feed me..."
+ if(!stat)
+ say (pick(phrases))
+
+/mob/living/simple_animal/slime/proc/get_max_nutrition() // Can't go above it
+ if(is_adult)
+ return 1200
+ else
+ return 1000
+
+/mob/living/simple_animal/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat
+ if(is_adult)
+ return 1000
+ else
+ return 800
+
+/mob/living/simple_animal/slime/proc/get_hunger_nutrition() // Below it we will always eat
+ if(is_adult)
+ return 600
+ else
+ return 500
+
+/mob/living/simple_animal/slime/proc/get_starve_nutrition() // Below it we will eat before everything else
+ if(is_adult)
+ return 300
+ else
+ return 200
+
+/mob/living/simple_animal/slime/proc/will_hunt(hunger = -1) // Check for being stopped from feeding and chasing
+ if(docile)
+ return 0
+ if(hunger == 2 || rabid || attacked)
+ return 1
+ if(Leader)
+ return 0
+ if(holding_still)
+ return 0
+ return 1
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
new file mode 100644
index 00000000000..bd9d001f12f
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -0,0 +1,215 @@
+#define SIZE_DOESNT_MATTER -1
+#define BABIES_ONLY 0
+#define ADULTS_ONLY 1
+
+#define NO_GROWTH_NEEDED 0
+#define GROWTH_NEEDED 1
+
+/datum/action/innate/slime
+ check_flags = AB_CHECK_CONSCIOUS
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ var/needs_growth = NO_GROWTH_NEEDED
+
+/datum/action/innate/slime/IsAvailable()
+ if(..())
+ var/mob/living/simple_animal/slime/S = owner
+ if(needs_growth == GROWTH_NEEDED)
+ if(S.amount_grown >= SLIME_EVOLUTION_THRESHOLD)
+ return 1
+ return 0
+ return 1
+
+/mob/living/simple_animal/slime/verb/Feed()
+ set category = "Slime"
+ set desc = "This will let you feed on any valid creature in the surrounding area. This should also be used to halt the feeding process."
+
+ if(stat)
+ return 0
+
+ var/list/choices = list()
+ for(var/mob/living/C in view(1,src))
+ if(C!=src && Adjacent(C))
+ choices += C
+
+ var/mob/living/M = input(src,"Who do you wish to feed on?") in null|choices
+ if(!M)
+ return 0
+ if(CanFeedon(M))
+ Feedon(M)
+ return 1
+
+/datum/action/innate/slime/feed
+ name = "Feed"
+ button_icon_state = "slimeeat"
+
+
+/datum/action/innate/slime/feed/Activate()
+ var/mob/living/simple_animal/slime/S = owner
+ S.Feed()
+
+/mob/living/simple_animal/slime/proc/CanFeedon(mob/living/M, silent = FALSE)
+ if(!Adjacent(M))
+ return FALSE
+
+ if(buckled)
+ Feedstop()
+ return FALSE
+
+ if(issilicon(M))
+ return FALSE
+
+ if(isanimal(M))
+ var/mob/living/simple_animal/S = M
+ if(S.damage_coeff[TOX] <= 0 && S.damage_coeff[CLONE] <= 0) //The creature wouldn't take any damage, it must be too weird even for us.
+ if(silent)
+ return FALSE
+ to_chat(src, "[pick("This subject is incompatible", \
+ "This subject does not have life energy", "This subject is empty", \
+ "I am not satisified", "I can not feed from this subject", \
+ "I do not feel nourished", "This subject is not food")]!")
+ return FALSE
+
+ if(isslime(M))
+ if(silent)
+ return FALSE
+ to_chat(src, "I can't latch onto another slime...")
+ return FALSE
+
+ if(docile)
+ if(silent)
+ return FALSE
+ to_chat(src, "I'm not hungry anymore...")
+ return FALSE
+
+ if(stat)
+ if(silent)
+ return FALSE
+ to_chat(src, "I must be conscious to do this...")
+ return FALSE
+
+ if(M.stat == DEAD)
+ if(silent)
+ return FALSE
+ to_chat(src, "This subject does not have a strong enough life energy...")
+ return FALSE
+
+ if(locate(/mob/living/simple_animal/slime) in M.buckled_mobs)
+ if(silent)
+ return FALSE
+ to_chat(src, "Another slime is already feeding on this subject...")
+ return FALSE
+ return TRUE
+
+/mob/living/simple_animal/slime/proc/Feedon(mob/living/M)
+ M.unbuckle_all_mobs(force = TRUE) //Slimes rip other mobs (eg: shoulder parrots) off (Slimes Vs Slimes is already handled in CanFeedon())
+ if(M.buckle_mob(src, force = TRUE))
+ layer = M.layer + 0.01 //appear above the target mob
+ M.visible_message("[name] has latched onto [M]!", \
+ "[name] has latched onto [M]!")
+ else
+ to_chat(src, "I have failed to latch onto the subject!")
+
+/mob/living/simple_animal/slime/proc/Feedstop(silent = FALSE, living = 1)
+ if(buckled)
+ if(!living)
+ to_chat(src, "[pick("This subject is incompatible", \
+ "This subject does not have life energy", "This subject is empty", \
+ "I am not satisified", "I can not feed from this subject", \
+ "I do not feel nourished", "This subject is not food")]!")
+ if(!silent)
+ visible_message("[src] has let go of [buckled]!", \
+ "I stopped feeding.")
+ layer = initial(layer)
+ buckled.unbuckle_mob(src,force=TRUE)
+
+/mob/living/simple_animal/slime/verb/Evolve()
+ set category = "Slime"
+ set desc = "This will let you evolve from baby to adult slime."
+
+ if(stat)
+ to_chat(src, "I must be conscious to do this...")
+ return
+ if(!is_adult)
+ if(amount_grown >= SLIME_EVOLUTION_THRESHOLD)
+ is_adult = 1
+ maxHealth = 200
+ amount_grown = 0
+ for(var/datum/action/innate/slime/evolve/E in actions)
+ E.Remove(src)
+ regenerate_icons()
+ update_name()
+ else
+ to_chat(src, "I am not ready to evolve yet...")
+ else
+ to_chat(src, "I have already evolved...")
+
+/datum/action/innate/slime/evolve
+ name = "Evolve"
+ button_icon_state = "slimegrow"
+ needs_growth = GROWTH_NEEDED
+
+/datum/action/innate/slime/evolve/Activate()
+ var/mob/living/simple_animal/slime/S = owner
+ S.Evolve()
+ if(S.is_adult)
+ var/datum/action/innate/slime/reproduce/A = new
+ A.Grant(S)
+
+/mob/living/simple_animal/slime/verb/Reproduce()
+ set category = "Slime"
+ set desc = "This will make you split into four Slimes."
+
+ if(stat)
+ to_chat(src, "I must be conscious to do this...")
+ return
+
+ if(is_adult)
+ if(amount_grown >= SLIME_EVOLUTION_THRESHOLD)
+ if(stat)
+ to_chat(src, "I must be conscious to do this...")
+ return
+
+ var/list/babies = list()
+ var/new_nutrition = round(nutrition * 0.9)
+ var/new_powerlevel = round(powerlevel / 4)
+ for(var/i=1,i<=4,i++)
+ var/child_colour
+ if(mutation_chance >= 100)
+ child_colour = "rainbow"
+ else if(prob(mutation_chance))
+ child_colour = slime_mutation[rand(1,4)]
+ else
+ child_colour = colour
+ var/mob/living/simple_animal/slime/M
+ M = new(loc, child_colour)
+ if(ckey)
+ M.set_nutrition(new_nutrition) //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
+ M.powerlevel = new_powerlevel
+ if(i != 1)
+ step_away(M,src)
+ M.Friends = Friends.Copy()
+ babies += M
+ M.mutation_chance = Clamp(mutation_chance+(rand(5,-5)),0,100)
+ feedback_add_details("slime_babies_born", "slimebirth_[replacetext(M.colour," ","_")]")
+
+ var/mob/living/simple_animal/slime/new_slime = pick(babies)
+ new_slime.a_intent = INTENT_HARM
+ if(src.mind)
+ src.mind.transfer_to(new_slime)
+ else
+ new_slime.key = src.key
+ qdel(src)
+ else
+ to_chat(src, "I am not ready to reproduce yet...")
+ else
+ to_chat(src, "I am not old enough to reproduce yet...")
+
+/datum/action/innate/slime/reproduce
+ name = "Reproduce"
+ button_icon_state = "slimesplit"
+ needs_growth = GROWTH_NEEDED
+
+/datum/action/innate/slime/reproduce/Activate()
+ var/mob/living/simple_animal/slime/S = owner
+ S.Reproduce()
diff --git a/code/modules/mob/living/simple_animal/slime/say.dm b/code/modules/mob/living/simple_animal/slime/say.dm
new file mode 100644
index 00000000000..01269aab8aa
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/say.dm
@@ -0,0 +1,18 @@
+/mob/living/simple_animal/slime/say_quote(text, datum/language/speaking)
+ var/verb = "blorbles"
+ var/ending = copytext(text, length(text))
+
+ if(ending == "?")
+ verb = "inquisitively blorbles"
+ else if(ending == "!")
+ verb = "loudly blorbles"
+
+ return verb
+
+/mob/living/simple_animal/slime/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol)
+ if(speaker != src && !stat)
+ if(speaker in Friends)
+ speech_buffer = list()
+ speech_buffer.Add(speaker)
+ speech_buffer.Add(lowertext(html_decode(multilingual_to_message(message_pieces))))
+ ..()
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
new file mode 100644
index 00000000000..a325ecfdefe
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -0,0 +1,505 @@
+/mob/living/simple_animal/slime
+ name = "grey baby slime (123)"
+ icon = 'icons/mob/slimes.dmi'
+ icon_state = "grey baby slime"
+ pass_flags = PASSTABLE | PASSGRILLE
+ ventcrawler = VENTCRAWLER_ALWAYS
+ gender = NEUTER
+ var/is_adult = 0
+ var/docile = 0
+ faction = list("slime", "neutral")
+
+ harm_intent_damage = 5
+ icon_living = "grey baby slime"
+ icon_dead = "grey baby slime dead"
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+ emote_see = list("jiggles", "bounces in place")
+ speak_emote = list("blorbles")
+
+ 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)
+
+ maxHealth = 150
+ health = 150
+ healable = 0
+ gender = NEUTER
+
+ see_in_dark = 8
+
+ // canstun and canknockdown don't affect slimes because they ignore stun and knockdown variables
+ // for the sake of cleanliness, though, here they are.
+ status_flags = CANPARALYSE | CANPUSH
+
+ var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
+ var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
+
+ var/powerlevel = 0 // 1-10 controls how much electricity they are generating
+ var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
+
+ var/number = 0 // Used to understand when someone is talking to it
+
+ var/mob/living/Target = null // AI variable - tells the slime to hunt this down
+ var/mob/living/Leader = null // AI variable - tells the slime to follow this person
+
+ var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable
+ var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with
+ var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place
+ var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target
+
+ var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting
+
+ var/list/speech_buffer = list() // Last phrase said near it and person who said it
+
+ var/mood = "" // To show its face
+ var/mutator_used = FALSE //So you can't shove a dozen mutators into a single slime
+ var/force_stasis = FALSE
+
+ var/static/regex/slime_name_regex = new("\\w+ (baby|adult) slime \\(\\d+\\)")
+ ///////////TIME FOR SUBSPECIES
+
+ var/colour = "grey"
+ var/coretype = /obj/item/slime_extract/grey
+ var/list/slime_mutation[4]
+
+ var/static/list/slime_colours = list("rainbow", "grey", "purple", "metal", "orange",
+ "blue", "dark blue", "dark purple", "yellow", "silver", "pink", "red",
+ "gold", "green", "adamantine", "oil", "light pink", "bluespace",
+ "cerulean", "sepia", "black", "pyrite")
+
+ ///////////CORE-CROSSING CODE
+
+ var/effectmod //What core modification is being used.
+ var/applied = 0 //How many extracts of the modtype have been applied.
+
+
+/mob/living/simple_animal/slime/Initialize(mapload, new_colour = "grey", new_is_adult = FALSE)
+ var/datum/action/innate/slime/feed/F = new
+ F.Grant(src)
+
+ is_adult = new_is_adult
+
+ if(is_adult)
+ var/datum/action/innate/slime/reproduce/R = new
+ R.Grant(src)
+ health = 200
+ maxHealth = 200
+ else
+ var/datum/action/innate/slime/evolve/E = new
+ E.Grant(src)
+ create_reagents(100)
+ set_colour(new_colour)
+ . = ..()
+ set_nutrition(700)
+ add_language("Bubblish")
+
+/mob/living/simple_animal/slime/Destroy()
+ for(var/A in actions)
+ var/datum/action/AC = A
+ AC.Remove(src)
+ for(var/obj/machinery/computer/camera_advanced/xenobio/X in GLOB.machines)
+ if(src in X.stored_slimes)
+ X.stored_slimes -= src
+ return ..()
+
+/mob/living/simple_animal/slime/proc/set_colour(new_colour)
+ colour = new_colour
+ update_name()
+ slime_mutation = mutation_table(colour)
+ var/sanitizedcolour = replacetext(colour, " ", "")
+ coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
+ regenerate_icons()
+
+/mob/living/simple_animal/slime/proc/update_name()
+ if(slime_name_regex.Find(name))
+ number = rand(1, 1000)
+ name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
+ real_name = name
+
+/mob/living/simple_animal/slime/proc/random_colour()
+ set_colour(pick(slime_colours))
+
+/mob/living/simple_animal/slime/regenerate_icons()
+ cut_overlays()
+ var/icon_text = "[colour] [is_adult ? "adult" : "baby"] slime"
+ icon_dead = "[icon_text] dead"
+ if(stat != DEAD)
+ icon_state = icon_text
+ if(mood && !stat)
+ add_overlay("aslime-[mood]")
+ else
+ icon_state = icon_dead
+ ..()
+
+/mob/living/simple_animal/slime/movement_delay()
+ if(bodytemperature >= 330.23) // 135 F or 57.08 C
+ return -1 // slimes become supercharged at high temperatures
+
+ . = ..()
+
+ var/health_deficiency = (maxHealth - health)
+ if(health_deficiency >= 45)
+ . += (health_deficiency / 25)
+
+ if(bodytemperature < 183.222)
+ . += (283.222 - bodytemperature) / 10 * 1.75
+
+ if(reagents)
+ if(reagents.has_reagent("morphine")) // morphine slows slimes down
+ . *= 2
+
+ if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
+ . *= 5
+
+ if(health <= 0) // if damaged, the slime moves twice as slow
+ . *= 2
+
+ . += config.slime_delay
+
+/mob/living/simple_animal/slime/handle_hud_icons_health()
+ if(hud_used)
+ if(!client)
+ return
+
+ if(healths)
+ var/severity = 0
+ var/healthpercent = (health / maxHealth) * 100
+ switch(healthpercent)
+ if(100 to INFINITY)
+ healths.icon_state = "slime_health0"
+ if(80 to 100)
+ healths.icon_state = "slime_health1"
+ severity = 1
+ if(60 to 80)
+ healths.icon_state = "slime_health2"
+ severity = 2
+ if(40 to 60)
+ healths.icon_state = "slime_health3"
+ severity = 3
+ if(20 to 40)
+ healths.icon_state = "slime_health4"
+ severity = 4
+ if(1 to 20)
+ healths.icon_state = "slime_health5"
+ severity = 5
+ else
+ healths.icon_state = "slime_health7"
+ severity = 6
+ if(severity > 0)
+ overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
+ else
+ clear_fullscreen("brute")
+
+/mob/living/simple_animal/slime/ObjBump(obj/O)
+ if(!client && powerlevel > 0)
+ var/probab = 10
+ switch(powerlevel)
+ if(1 to 2)
+ probab = 20
+ if(3 to 4)
+ probab = 30
+ if(5 to 6)
+ probab = 40
+ if(7 to 8)
+ probab = 60
+ if(9)
+ probab = 70
+ if(10)
+ probab = 95
+ if(prob(probab))
+ if(istype(O, /obj/structure/window) || istype(O, /obj/structure/grille))
+ if(nutrition <= get_hunger_nutrition() && !Atkcool)
+ if (is_adult || prob(5))
+ O.attack_slime(src)
+ Atkcool = TRUE
+ addtimer(VARSET_CALLBACK(src, Atkcool, FALSE), 4.5 SECONDS)
+
+/mob/living/simple_animal/slime/Process_Spacemove(movement_dir = 0)
+ return 2
+
+/mob/living/simple_animal/slime/Stat()
+ if(..())
+
+ if(!docile)
+ stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]")
+ if(amount_grown >= SLIME_EVOLUTION_THRESHOLD)
+ if(is_adult)
+ stat(null, "You can reproduce!")
+ else
+ stat(null, "You can evolve!")
+
+ if(stat == UNCONSCIOUS)
+ stat(null,"You are knocked out by high levels of BZ!")
+ else
+ stat(null,"Power Level: [powerlevel]")
+
+
+/mob/living/simple_animal/slime/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
+ if(!forced)
+ amount = -abs(amount)
+ return ..() //Heals them
+
+/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj)
+ if(!Proj)
+ return
+ attacked += 10
+ if((Proj.damage_type == BURN))
+ adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
+ Proj.on_hit(src)
+ else
+ ..(Proj)
+ return FALSE
+
+/mob/living/simple_animal/slime/emp_act(severity)
+ ..()
+ powerlevel = 0 // oh no, the power!
+
+/mob/living/simple_animal/slime/MouseDrop(atom/movable/A)
+ if(isliving(A) && A != src && usr == src)
+ var/mob/living/Food = A
+ if(CanFeedon(Food))
+ Feedon(Food)
+ return ..()
+
+/mob/living/simple_animal/slime/unEquip(obj/item/I)
+ return
+
+/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
+ return
+
+/mob/living/simple_animal/slime/attack_ui(slot)
+ return
+
+/mob/living/simple_animal/slime/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ if(M == src)
+ return
+ if(buckled)
+ Feedstop(silent = TRUE)
+ visible_message("[M] pulls [src] off!", \
+ "You pull [src] off!")
+ return
+ attacked += 5
+ if(nutrition >= 100) //steal some nutrition. negval handled in life()
+ adjust_nutrition(-(50 + (40 * M.is_adult)))
+ M.add_nutrition(50 + (40 * M.is_adult))
+ if(health > 0)
+ M.adjustBruteLoss(-10 + (-10 * M.is_adult))
+ M.updatehealth()
+
+/mob/living/simple_animal/slime/attack_animal(mob/living/simple_animal/M)
+ . = ..()
+ if(.)
+ attacked += 10
+
+/mob/living/simple_animal/slime/attack_larva(mob/living/carbon/alien/larva/L)
+ if(..()) //successful larva bite.
+ attacked += 10
+
+/mob/living/simple_animal/slime/attack_hulk(mob/living/carbon/human/user)
+ if(user.a_intent == INTENT_HARM)
+ discipline_slime(user)
+ return ..()
+
+/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M)
+ if(buckled)
+ M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
+ if(buckled == M)
+ if(prob(60))
+ M.visible_message("[M] attempts to wrestle \the [name] off!", \
+ "You attempt to wrestle \the [name] off!")
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1)
+
+ else
+ M.visible_message("[M] manages to wrestle \the [name] off!", \
+ "You manage to wrestle \the [name] off!")
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
+
+ discipline_slime(M)
+
+ else
+ if(prob(30))
+ buckled.visible_message("[M] attempts to wrestle \the [name] off of [buckled]!", \
+ "[M] attempts to wrestle \the [name] off of you!")
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1)
+
+ else
+ buckled.visible_message("[M] manages to wrestle \the [name] off of [buckled]!", \
+ "[M] manage to wrestle \the [name] off of you!")
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
+
+ discipline_slime(M)
+ else
+ if(stat == DEAD && surgeries.len)
+ if(M.a_intent == INTENT_HELP || M.a_intent == INTENT_DISARM)
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(M, src))
+ return 1
+ if(..()) //successful attack
+ attacked += 10
+
+/mob/living/simple_animal/slime/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(..()) //if harm or disarm intent.
+ attacked += 10
+ discipline_slime(M)
+
+
+/mob/living/simple_animal/slime/attackby(obj/item/I, mob/living/user, params)
+ if(stat == DEAD && surgeries.len)
+ if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user, src))
+ return 1
+ if(istype(I, /obj/item/stack/sheet/mineral/plasma) && !stat) //Let's you feed slimes plasma.
+ if(user in Friends)
+ ++Friends[user]
+ else
+ Friends[user] = 1
+ to_chat(user, "You feed the slime the plasma. It chirps happily.")
+ var/obj/item/stack/sheet/mineral/plasma/S = I
+ S.use(1)
+ return
+ if(I.force > 0)
+ attacked += 10
+ if(prob(25))
+ user.do_attack_animation(src)
+ user.changeNext_move(CLICK_CD_MELEE)
+ to_chat(user, "[I] passes right through [src]!")
+ return
+ if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
+ Discipline = 0
+ if(I.force >= 3)
+ var/force_effect = 2 * I.force
+ if(is_adult)
+ force_effect = round(I.force / 2)
+ if(prob(10 + force_effect))
+ discipline_slime(user)
+/* if(istype(I, /obj/item/storage/bag/bio))
+ var/obj/item/storage/P = I
+ if(!effectmod)
+ to_chat(user, "The slime is not currently being mutated.")
+ return
+ var/hasOutput = FALSE //Have we outputted text?
+ var/hasFound = FALSE //Have we found an extract to be added?
+ for(var/obj/item/slime_extract/S in P.contents)
+ if(S.effectmod == effectmod)
+ SEND_SIGNAL(P, COMSIG_TRY_STORAGE_TAKE, S, get_turf(src), TRUE)
+ qdel(S)
+ applied++
+ hasFound = TRUE
+ if(applied >= SLIME_EXTRACT_CROSSING_REQUIRED)
+ to_chat(user, "You feed the slime as many of the extracts from the bag as you can, and it mutates!")
+ playsound(src, 'sound/effects/attackblob.ogg', 50, TRUE)
+ spawn_corecross()
+ hasOutput = TRUE
+ break
+ if(!hasOutput)
+ if(!hasFound)
+ to_chat(user, "There are no extracts in the bag that this slime will accept!")
+ else
+ to_chat(user, "You feed the slime some extracts from the bag.")
+ playsound(src, 'sound/effects/attackblob.ogg', 50, TRUE)
+ return */
+ ..()
+/*
+/mob/living/simple_animal/slime/proc/spawn_corecross()
+ var/static/list/crossbreeds = subtypesof(/obj/item/slimecross)
+ visible_message("[src] shudders, its mutated core consuming the rest of its body!")
+ playsound(src, 'sound/magic/smoke.ogg', 50, TRUE)
+ var/crosspath
+ for(var/X in crossbreeds)
+ var/obj/item/slimecross/S = X
+ if(initial(S.colour) == colour && initial(S.effect) == effectmod)
+ crosspath = S
+ break
+ if(crosspath)
+ new crosspath(loc)
+ else
+ visible_message("The mutated core shudders, and collapses into a puddle, unable to maintain its form.")
+ qdel(src)
+*/
+/mob/living/simple_animal/slime/water_act(volume, temperature, source, method = TOUCH)
+ . = ..()
+ var/water_damage = rand(10, 15) * volume
+ adjustBruteLoss(water_damage)
+ if(!client && Target && volume >= 3) // Like cats
+ Target = null
+ ++Discipline
+
+/mob/living/simple_animal/slime/examine(mob/user)
+ to_chat(user, "*---------*\nThis is [bicon(src)] \a [src]!")
+ if(stat == DEAD)
+ to_chat(user, "It is limp and unresponsive.")
+ else
+ if(stat == UNCONSCIOUS) // Slime stasis
+ to_chat(user, "It appears to be alive but unresponsive.")
+ if(getBruteLoss())
+ to_chat(user, "")
+ if (getBruteLoss() < 40)
+ to_chat(user, "It has some punctures in its flesh!")
+ else
+ to_chat(user, "It has severe punctures and tears in its flesh!")
+ to_chat(user, "\n")
+
+ switch(powerlevel)
+ if(2 to 3)
+ to_chat(user, "It is flickering gently with a little electrical activity.")
+
+ if(4 to 5)
+ to_chat(user, "It is glowing gently with moderate levels of electrical activity.")
+
+ if(6 to 9)
+ to_chat(user, "It is glowing brightly with high levels of electrical activity.")
+
+ if(10)
+ to_chat(user, "It is radiating with massive levels of electrical activity!")
+
+ to_chat(user, "*---------*")
+
+/mob/living/simple_animal/slime/proc/discipline_slime(mob/user)
+ if(stat)
+ return
+
+ if(prob(80) && !client)
+ Discipline++
+
+ if(!is_adult)
+ if(Discipline == 1)
+ attacked = 0
+
+ if(Target)
+ Target = null
+ if(buckled)
+ Feedstop(silent = TRUE) //we unbuckle the slime from the mob it latched onto.
+
+ SStun = world.time + rand(20,60)
+ spawn(0)
+ canmove = FALSE
+ if(user)
+ step_away(src,user,15)
+ sleep(3)
+ if(user)
+ step_away(src,user,15)
+ update_canmove()
+
+/mob/living/simple_animal/slime/pet
+ docile = TRUE
+
+/mob/living/simple_animal/slime/can_unbuckle()
+ return FALSE
+
+/mob/living/simple_animal/slime/can_buckle()
+ return FALSE
+
+/mob/living/simple_animal/slime/get_mob_buckling_height(mob/seat)
+ if(..())
+ return 3
+
+/mob/living/simple_animal/slime/random/Initialize(mapload, new_colour, new_is_adult)
+ . = ..(mapload, pick(slime_colours), prob(50))
+
+/mob/living/simple_animal/slime/handle_ventcrawl(atom/A)
+ if(buckled)
+ to_chat(src, "I can't vent crawl while feeding...")
+ return
+ ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/slime/subtypes.dm b/code/modules/mob/living/simple_animal/slime/subtypes.dm
similarity index 96%
rename from code/modules/mob/living/carbon/slime/subtypes.dm
rename to code/modules/mob/living/simple_animal/slime/subtypes.dm
index 35d38e31a48..b5720c62250 100644
--- a/code/modules/mob/living/carbon/slime/subtypes.dm
+++ b/code/modules/mob/living/simple_animal/slime/subtypes.dm
@@ -1,4 +1,4 @@
-proc/mutation_table(var/colour)
+/mob/living/simple_animal/slime/proc/mutation_table(colour)
var/list/slime_mutation[4]
switch(colour)
//Tier 1
@@ -76,4 +76,4 @@ proc/mutation_table(var/colour)
slime_mutation[2] = colour
slime_mutation[3] = colour
slime_mutation[4] = colour
- return(slime_mutation)
\ No newline at end of file
+ return(slime_mutation)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 5154f19fda7..a03b7745d0a 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -135,41 +135,38 @@
qdel(src)
return
-/mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num)
+/mob/living/carbon/human/proc/slimeize(reproduce as num)
if(notransform)
return
- for(var/obj/item/W in src)
- unEquip(W)
+ notransform = TRUE
+ canmove = FALSE
+ for(var/obj/item/I in src)
+ unEquip(I)
regenerate_icons()
- notransform = 1
- canmove = 0
icon = null
- invisibility = 101
+ invisibility = INVISIBILITY_MAXIMUM
for(var/t in bodyparts)
qdel(t)
- var/mob/living/carbon/slime/new_slime
+ var/mob/living/simple_animal/slime/new_slime
if(reproduce)
var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring)
var/list/babies = list()
for(var/i=1,i<=number,i++)
- var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc)
+ var/mob/living/simple_animal/slime/M = new/mob/living/simple_animal/slime(loc)
M.set_nutrition(round(nutrition / number))
step_away(M,src)
babies += M
new_slime = pick(babies)
else
- new_slime = new /mob/living/carbon/slime(loc)
- if(adult)
- new_slime.is_adult = 1
- else
+ new_slime = new /mob/living/simple_animal/slime(loc)
+ new_slime.a_intent = INTENT_HARM
new_slime.key = key
to_chat(new_slime, "You are now a slime. Skreee!")
new_slime.update_pipe_vision()
- spawn(0)//To prevent the proc from returning null.
- qdel(src)
- return
+ . = new_slime
+ qdel(src)
/mob/living/carbon/human/proc/corgize()
if(notransform)
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 4bf6c98fc50..76d7c513bcc 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -202,7 +202,7 @@
if(ishuman(M))
Robot.mmi.transfer_identity(M) //Does not transfer key/client.
if("slime")
- new_mob = new /mob/living/carbon/slime/random(M.loc)
+ new_mob = new /mob/living/simple_animal/slime/random(M.loc)
new_mob.universal_speak = TRUE
if("xeno")
if(prob(50))
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 331e5d9ca8f..b594743baef 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -74,6 +74,18 @@ var/const/INGEST = 2
handle_reactions()
return total_transfered
+/datum/reagents/proc/remove_all(amount = 1)
+ var/list/cached_reagents = reagent_list
+ if(total_volume > 0)
+ var/part = amount / total_volume
+ for(var/reagent in cached_reagents)
+ var/datum/reagent/R = reagent
+ remove_reagent(R.id, R.volume * part)
+
+ update_total()
+ handle_reactions()
+ return amount
+
/datum/reagents/proc/get_master_reagent()
var/the_reagent = null
var/the_volume = 0
@@ -803,7 +815,7 @@ var/const/INGEST = 2
if(!R.taste_mult)
continue
//nutriment carries a list of tastes that originates from the snack food that the nutriment came from
- if(istype(R, /datum/reagent/consumable/nutriment))
+ if(istype(R, /datum/reagent/consumable/nutriment))
var/list/nutriment_taste_data = R.data
for(var/nutriment_taste in nutriment_taste_data)
var/ratio = nutriment_taste_data[nutriment_taste]
diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm
index afc4c4f2f8f..5353dc54b88 100644
--- a/code/modules/reagents/chemistry/reagents/food.dm
+++ b/code/modules/reagents/chemistry/reagents/food.dm
@@ -279,8 +279,8 @@
/datum/reagent/consumable/frostoil/reaction_turf(turf/T, volume)
if(volume >= 5)
- for(var/mob/living/carbon/slime/M in T)
- M.adjustToxLoss(rand(15,30))
+ for(var/mob/living/simple_animal/slime/M in T)
+ M.adjustToxLoss(rand(15, 30))
/datum/reagent/consumable/sodiumchloride
name = "Salt"
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
index a01c034a4ae..17eee91080e 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
@@ -356,7 +356,7 @@
if(volume >= 3)
T.MakeSlippery(TURF_WET_ICE)
if(volume >= 5)
- for(var/mob/living/carbon/slime/M in T)
+ for(var/mob/living/simple_animal/slime/M in T)
M.adjustToxLoss(rand(15,30))
/datum/reagent/pyrosium
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index 5a831aa91de..ef836462543 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -76,8 +76,8 @@
if(floor_only)
T.clean_blood()
- for(var/mob/living/carbon/slime/M in T)
- M.adjustToxLoss(rand(5,10))
+ for(var/mob/living/simple_animal/slime/M in T)
+ M.adjustToxLoss(rand(5, 10))
if(istype(T, /turf/simulated))
var/turf/simulated/S = T
S.dirt = 0
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index a1e96ea35f5..1767d3964a1 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -11,9 +11,8 @@
/datum/chemical_reaction/slimespawn/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/mob/living/carbon/slime/S = new /mob/living/carbon/slime
- S.forceMove(get_turf(holder.my_atom))
- S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
+ var/mob/living/simple_animal/slime/S = new(get_turf(holder.my_atom), "grey")
+ S.visible_message("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!")
/datum/chemical_reaction/slimeinaprov
name = "Slime epinephrine"
@@ -425,7 +424,12 @@
/datum/chemical_reaction/slimebloodlust/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null))
+ for(var/mob/living/simple_animal/slime/slime in viewers(get_turf(holder.my_atom), null))
+ if(slime.docile) //Undoes docility, but doesn't make rabid.
+ slime.visible_message("[slime] forgets its training, becoming wild once again!")
+ slime.docile = FALSE
+ slime.update_name()
+ continue
slime.rabid = 1
slime.visible_message("The [slime] is driven into a frenzy!")
@@ -667,9 +671,8 @@
/datum/chemical_reaction/slimeRNG/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/mob/living/carbon/slime/random/S = new /mob/living/carbon/slime/random
- S.forceMove(get_turf(holder.my_atom))
- S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
+ var/mob/living/simple_animal/slime/random/S = new (get_turf(holder.my_atom))
+ S.visible_message("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!")
/datum/chemical_reaction/slime_transfer
name = "Transfer Potion"
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 6a5d85e0631..2182df4c9a8 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -175,7 +175,7 @@
// mouse drop another mob or self
//
/obj/machinery/disposal/MouseDrop_T(mob/target, mob/user)
- if(!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
+ if(!istype(target) || target.buckled || target.has_buckled_mobs() || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
return
if(isanimal(user) && target != user) return //animals cannot put mobs other than themselves into disposal
src.add_fingerprint(user)
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index 785c03b13a1..f6df6ece19b 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -48,7 +48,7 @@
/obj/machinery/computer/camera_advanced/xenobio/Destroy()
QDEL_NULL(current_potion)
- for(var/mob/living/carbon/slime/S in stored_slimes)
+ for(var/mob/living/simple_animal/slime/S in stored_slimes)
S.forceMove(drop_location())
stored_slimes.Cut()
return ..()
@@ -173,7 +173,7 @@
var/obj/machinery/computer/camera_advanced/xenobio/X = target
if(cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/carbon/slime/S in X.stored_slimes)
+ for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
S.forceMove(remote_eye.loc)
S.visible_message("[S] warps in!")
X.stored_slimes -= S
@@ -192,14 +192,13 @@
var/obj/machinery/computer/camera_advanced/xenobio/X = target
if(cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/carbon/slime/S in remote_eye.loc)
+ for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
if(X.stored_slimes.len >= X.max_slimes)
break
if(!S.ckey)
if(S.buckled)
- S.buckled.unbuckle_mob(S, force = TRUE)
- S.Feedstop()
- S.visible_message("[S] vanishes in a flash of light!")
+ S.Feedstop(silent = TRUE)
+ S.visible_message("[S] vanishes in a flash of light!")
S.forceMove(X)
X.stored_slimes += S
else
@@ -265,7 +264,7 @@
var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
if(cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/carbon/slime/S in remote_eye.loc)
+ for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
slime_scan(S, C)
else
to_chat(owner, "Target is not near a camera. Cannot proceed.")
@@ -287,7 +286,7 @@
return
if(cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/carbon/slime/S in remote_eye.loc)
+ for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
X.current_potion.attack(S, C)
break
else
@@ -310,17 +309,17 @@
// Alternate clicks for slime, monkey and open turf if using a xenobio console
// Scans slime
-/mob/living/carbon/slime/CtrlClick(mob/user)
+/mob/living/simple_animal/slime/CtrlClick(mob/user)
SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_CTRL, src)
..()
//Feeds a potion to slime
-/mob/living/carbon/slime/AltClick(mob/user)
+/mob/living/simple_animal/slime/AltClick(mob/user)
SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_ALT, src)
..()
//Picks up slime
-/mob/living/carbon/slime/ShiftClick(mob/user)
+/mob/living/simple_animal/slime/ShiftClick(mob/user)
SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_SHIFT, src)
..()
@@ -341,7 +340,7 @@
..()
// Scans slime
-/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/carbon/slime/S)
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/simple_animal/slime/S)
if(!cameranet.checkTurfVis(S.loc))
to_chat(user, "Target is not near a camera. Cannot proceed.")
return
@@ -352,7 +351,7 @@
slime_scan(S, C)
//Feeds a potion to slime
-/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/carbon/slime/S)
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/simple_animal/slime/S)
if(!cameranet.checkTurfVis(S.loc))
to_chat(user, "Target is not near a camera. Cannot proceed.")
return
@@ -367,7 +366,7 @@
X.current_potion.attack(S, C)
//Picks up slime
-/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/carbon/slime/S)
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/simple_animal/slime/S)
if(!cameranet.checkTurfVis(S.loc))
to_chat(user, "Target is not near a camera. Cannot proceed.")
return
@@ -377,14 +376,16 @@
var/area/mobarea = get_area(S.loc)
if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
if(X.stored_slimes.len >= X.max_slimes)
+ to_chat(C, "Slime storage is full.")
return
- if(!S.ckey)
- if(S.buckled)
- S.buckled.unbuckle_mob(S, force = TRUE)
- S.Feedstop()
- S.visible_message("[S] vanishes in a flash of light!")
- S.forceMove(X)
- X.stored_slimes += S
+ if(S.ckey)
+ to_chat(C, "The slime wiggled free!")
+ return
+ if(S.buckled)
+ S.Feedstop(silent = TRUE)
+ S.visible_message("[S] vanishes in a flash of light!")
+ S.forceMove(X)
+ X.stored_slimes += S
//Place slimes
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickShift(mob/living/user, turf/T)
@@ -396,9 +397,9 @@
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
var/area/turfarea = get_area(T)
if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
- for(var/mob/living/carbon/slime/S in X.stored_slimes)
+ for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
S.forceMove(T)
- S.visible_message("[S] warps in!")
+ S.visible_message("[S] warps in!")
X.stored_slimes -= S
//Place monkey
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 1dd4f05eb97..f7798df7892 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -139,7 +139,7 @@
icon_state = "bottle19"
var/being_used = 0
-/obj/item/slimepotion/slime/docility/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/docility/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The potion only works on slimes!")
return
@@ -149,7 +149,12 @@
if(being_used)
to_chat(user, "You're already using this on another slime!")
return
-
+ if(M.rabid) //Stops being rabid, but doesn't become truly docile.
+ to_chat(M, "You absorb the potion, and your rabid hunger finally settles to a normal desire to feed.")
+ to_chat(user, "You feed the slime the potion, calming its rabid rage.")
+ M.rabid = FALSE
+ qdel(src)
+ return
M.docile = 1
M.set_nutrition(700)
to_chat(M, "You absorb the potion and feel your intense desire to feed melt away.")
@@ -272,7 +277,7 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
-/obj/item/slimepotion/slime/steroid/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/steroid/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))//If target is not a slime.
to_chat(user, "The steroid only works on baby slimes!")
return ..()
@@ -302,7 +307,7 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle15"
-/obj/item/slimepotion/slime/stabilizer/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/stabilizer/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The stabilizer only works on slimes!")
return ..()
@@ -323,7 +328,7 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle3"
-/obj/item/slimepotion/slime/mutator/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/mutator/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The mutator only works on slimes!")
return ..()
diff --git a/code/modules/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm
index 0bc9a074179..be21fe0ef9a 100644
--- a/code/modules/spacepods/spacepod.dm
+++ b/code/modules/spacepods/spacepod.dm
@@ -765,10 +765,9 @@ obj/spacepod/proc/add_equipment(mob/user, var/obj/item/spacepod_equipment/SPE, v
to_chat(user, "The nuke-disk is locking the door every time you try to open it. You get the feeling that it doesn't want to go into the spacepod.")
return 0
- for(var/mob/living/carbon/slime/S in range(1,usr))
- if(S.Victim == user)
- to_chat(user, "You're too busy getting your life sucked out of you.")
- return 0
+ if(user.has_buckled_mobs()) //mob attached to us
+ to_chat(user, "[user] will not fit into [src] because [user.p_they()] [user.p_have()] creatures attached to [user.p_them()]!")
+ return
move_inside(user)
diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm
new file mode 100644
index 00000000000..21458720978
--- /dev/null
+++ b/code/modules/surgery/core_removal.dm
@@ -0,0 +1,61 @@
+/datum/surgery/core_removal
+ name = "core removal"
+ steps = list(/datum/surgery_step/slime/cut_flesh, /datum/surgery_step/slime/extract_core)
+ allowed_mob = list(/mob/living/simple_animal/slime)
+ possible_locs = list("chest", "head", "l_arm", "l_hand", "r_arm", "r_hand", "r_leg", "r_foot", "l_leg", "l_foot", "groin")
+
+/datum/surgery_step/slime
+
+/datum/surgery_step/slime/is_valid_target(mob/living/simple_animal/slime/target)
+ return istype(target, /mob/living/simple_animal/slime)
+
+/datum/surgery_step/slime/can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ return istype(target) && target.stat == DEAD
+
+/datum/surgery_step/slime/cut_flesh
+ allowed_tools = list(/obj/item/scalpel = 100, /obj/item/melee/energy/sword = 75, /obj/item/kitchen/knife = 65, /obj/item/shard = 45)
+ time = 16
+
+/datum/surgery_step/slime/cut_flesh/begin_step(mob/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", "You start cutting through [target]'s flesh with \the [tool].")
+
+/datum/surgery_step/slime/cut_flesh/end_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ user.visible_message(" [user] cuts through [target]'s flesh with \the [tool].",
+ " You cut through [target]'s flesh with \the [tool], revealing its silky innards.")
+ return TRUE
+
+/datum/surgery_step/slime/cut_flesh/fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ user.visible_message(" [user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \
+ " Your hand slips, tearing [target]'s flesh with \the [tool]!")
+ return FALSE
+
+/datum/surgery_step/slime/extract_core
+ name = "extract core"
+ allowed_tools = list(/obj/item/hemostat = 100, /obj/item/crowbar = 100)
+ time = 16
+
+/datum/surgery_step/slime/extract_core/begin_step(mob/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ user.visible_message("[user] begins to extract a core from [target].",
+ "You begin to extract a core from [target]...")
+
+/datum/surgery_step/slime/extract_core/end_step(mob/user, mob/living/simple_animal/slime/slime, target_zone, obj/item/tool)
+ if(slime.cores > 0)
+ slime.cores--
+ user.visible_message("[user] successfully extracts a core from [slime]!",
+ "You successfully extract a core from [slime]. [slime.cores] core\s remaining.")
+
+ new slime.coretype(slime.loc)
+
+ if(slime.cores <= 0)
+ slime.icon_state = "[slime.colour] baby slime dead-nocore"
+ return TRUE
+ else
+ return FALSE
+ else
+ to_chat(user, "There aren't any cores left in [slime]!")
+ return TRUE
+
+/datum/surgery_step/slime/extract_core/fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
+ user.visible_message(" [user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \
+ " Your hand slips, tearing [target]'s flesh with \the [tool]!")
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/surgery/slime.dm b/code/modules/surgery/slime.dm
deleted file mode 100644
index 77614d41430..00000000000
--- a/code/modules/surgery/slime.dm
+++ /dev/null
@@ -1,103 +0,0 @@
-//////////////////////////////////////////////////////////////////
-// SLIME CORE EXTRACTION //
-//////////////////////////////////////////////////////////////////
-/datum/surgery/core_removal
- name = "core removal"
- steps = list(/datum/surgery_step/slime/cut_flesh, /datum/surgery_step/slime/cut_innards, /datum/surgery_step/slime/saw_core)
- allowed_mob = list(/mob/living/carbon/slime)
- possible_locs = list("chest")//urgghhhhhhhhhhhh
-
-
-/datum/surgery_step/slime
- is_valid_target(mob/living/carbon/slime/target)
- return istype(target, /mob/living/carbon/slime/)
-
- can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- return target.stat == DEAD
-
-/datum/surgery_step/slime/cut_flesh
- allowed_tools = list(
- /obj/item/scalpel = 100, \
- /obj/item/kitchen/knife = 90, \
- /obj/item/shard = 60, \
- )
-
- time = 16
-
-/datum/surgery_step/slime/cut_flesh/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- return ..() && istype(target) && target.core_removal_stage == 0
-
-/datum/surgery_step/slime/cut_flesh/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \
- "You start cutting through [target]'s flesh with \the [tool].")
-
-/datum/surgery_step/slime/cut_flesh/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message(" [user] cuts through [target]'s flesh with \the [tool].", \
- " You cut through [target]'s flesh with \the [tool], revealing its silky innards.")
- target.core_removal_stage = 1
-
- return 1
-
-/datum/surgery_step/slime/cut_flesh/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message(" [user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \
- " Your hand slips, tearing [target]'s flesh with \the [tool]!")
- return 0
-
-/datum/surgery_step/slime/cut_innards
- allowed_tools = list(
- /obj/item/scalpel = 100, \
- /obj/item/kitchen/knife = 90, \
- /obj/item/shard = 60, \
- )
-
- time = 16
-
-/datum/surgery_step/slime/cut_innards/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- return ..() && istype(target) && target.core_removal_stage == 1
-
-/datum/surgery_step/slime/cut_innards/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \
- "You start cutting [target]'s silky innards apart with \the [tool].")
-
-/datum/surgery_step/slime/cut_innards/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message(" [user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \
- " You cut [target]'s innards apart with \the [tool], exposing the cores.")
- target.core_removal_stage = 2
- return 1
-
-/datum/surgery_step/slime/cut_innards/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message(" [user]'s hand slips, tearing [target]'s innards with \the [tool]!", \
- " Your hand slips, tearing [target]'s innards with \the [tool]!")
- return 0
-
-/datum/surgery_step/slime/saw_core
- allowed_tools = list(
- /obj/item/circular_saw = 100, \
- /obj/item/hatchet = 90
- )
-
- time = 16
-
-/datum/surgery_step/slime/saw_core/can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why.
-
-/datum/surgery_step/slime/saw_core/begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \
- "You start cutting out one of [target]'s cores with \the [tool].")
-
-/datum/surgery_step/slime/saw_core/end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- target.cores--
- user.visible_message(" [user] cuts out one of [target]'s cores with \the [tool].", \
- " You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.")
-
- if(target.cores >= 0)
- new target.coretype(target.loc)
- if(target.cores <= 0)
- target.icon_state = "[target.colour] baby slime dead-nocore"
-
- return 1
-
-/datum/surgery_step/slime/saw_core/fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
- user.visible_message(" [user]'s hand slips, causing [user.p_them()] to miss the core!", \
- " Your hand slips, causing you to miss the core!")
- return 0
diff --git a/icons/mob/actions/actions_slime.dmi b/icons/mob/actions/actions_slime.dmi
new file mode 100644
index 00000000000..acf7a31c6ed
Binary files /dev/null and b/icons/mob/actions/actions_slime.dmi differ
diff --git a/icons/mob/slimes.dmi b/icons/mob/slimes.dmi
index 0ef5ac0bee4..f9998d6f106 100644
Binary files a/icons/mob/slimes.dmi and b/icons/mob/slimes.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 554b6f1c041..70d97ffd787 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1834,15 +1834,6 @@
#include "code\modules\mob\living\carbon\human\species\vulpkanin.dm"
#include "code\modules\mob\living\carbon\human\species\wryn.dm"
#include "code\modules\mob\living\carbon\human\species\zombies.dm"
-#include "code\modules\mob\living\carbon\slime\death.dm"
-#include "code\modules\mob\living\carbon\slime\emote.dm"
-#include "code\modules\mob\living\carbon\slime\examine.dm"
-#include "code\modules\mob\living\carbon\slime\life.dm"
-#include "code\modules\mob\living\carbon\slime\powers.dm"
-#include "code\modules\mob\living\carbon\slime\say.dm"
-#include "code\modules\mob\living\carbon\slime\slime.dm"
-#include "code\modules\mob\living\carbon\slime\subtypes.dm"
-#include "code\modules\mob\living\carbon\slime\update_icons.dm"
#include "code\modules\mob\living\silicon\death.dm"
#include "code\modules\mob\living\silicon\emote.dm"
#include "code\modules\mob\living\silicon\laws.dm"
@@ -1940,7 +1931,6 @@
#include "code\modules\mob\living\simple_animal\friendly\mouse.dm"
#include "code\modules\mob\living\simple_animal\friendly\penguin.dm"
#include "code\modules\mob\living\simple_animal\friendly\pet.dm"
-#include "code\modules\mob\living\simple_animal\friendly\slime.dm"
#include "code\modules\mob\living\simple_animal\friendly\sloth.dm"
#include "code\modules\mob\living\simple_animal\friendly\spiderbot.dm"
#include "code\modules\mob\living\simple_animal\hostile\alien.dm"
@@ -2015,6 +2005,13 @@
#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\terror_ai.dm"
#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\terror_spiders.dm"
#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\white.dm"
+#include "code\modules\mob\living\simple_animal\slime\death.dm"
+#include "code\modules\mob\living\simple_animal\slime\emote.dm"
+#include "code\modules\mob\living\simple_animal\slime\life.dm"
+#include "code\modules\mob\living\simple_animal\slime\powers.dm"
+#include "code\modules\mob\living\simple_animal\slime\say.dm"
+#include "code\modules\mob\living\simple_animal\slime\slime.dm"
+#include "code\modules\mob\living\simple_animal\slime\subtypes.dm"
#include "code\modules\mob\new_player\login.dm"
#include "code\modules\mob\new_player\logout.dm"
#include "code\modules\mob\new_player\new_player.dm"
@@ -2394,6 +2391,7 @@
#include "code\modules\store\store.dm"
#include "code\modules\surgery\bones.dm"
#include "code\modules\surgery\cavity_implant.dm"
+#include "code\modules\surgery\core_removal.dm"
#include "code\modules\surgery\dental_implant.dm"
#include "code\modules\surgery\encased.dm"
#include "code\modules\surgery\generic.dm"
@@ -2407,7 +2405,6 @@
#include "code\modules\surgery\remove_embedded_object.dm"
#include "code\modules\surgery\rig_removal.dm"
#include "code\modules\surgery\robotics.dm"
-#include "code\modules\surgery\slime.dm"
#include "code\modules\surgery\surgery.dm"
#include "code\modules\surgery\tools.dm"
#include "code\modules\surgery\organs\augments_arms.dm"