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"