diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm
index 8dd637e58f..fde7b78aca 100644
--- a/code/ZAS/Airflow.dm
+++ b/code/ZAS/Airflow.dm
@@ -22,7 +22,7 @@ mob/proc/airflow_stun()
mob/living/silicon/airflow_stun()
return
-mob/living/carbon/slime/airflow_stun()
+mob/living/simple_animal/slime/airflow_stun()
return
mob/living/carbon/human/airflow_stun()
diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm
index 2207ffb075..08131f99bb 100644
--- a/code/__defines/chemistry.dm
+++ b/code/__defines/chemistry.dm
@@ -34,6 +34,8 @@
#define CE_ALCOHOL_TOXIC "alcotoxic" // Liver damage
#define CE_SPEEDBOOST "gofast" // Hyperzine
+#define REAGENTS_PER_SHEET 20
+
// Chemistry lists.
var/list/tachycardics = list("coffee", "inaprovaline", "hyperzine", "nitroglycerin", "thirteenloko", "nicotine") // Increase heart rate.
var/list/bradycardics = list("neurotoxin", "cryoxadone", "clonexadone", "space_drugs", "stoxin") // Decrease heart rate.
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index ef00eed334..de957d8b21 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -212,4 +212,10 @@
#define FBP_NONE ""
#define FBP_CYBORG "Cyborg"
#define FBP_POSI "Positronic"
-#define FBP_DRONE "Drone"
\ No newline at end of file
+#define FBP_DRONE "Drone"
+
+// Used to seperate simple animals by ""intelligence"".
+#define SA_PLANT 1
+#define SA_ANIMAL 2
+#define SA_ROBOTIC 3
+#define SA_HUMANOID 4
\ No newline at end of file
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 63bac6e134..152f5e2a9a 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -492,8 +492,6 @@ 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)
- moblist.Add(M)
for(var/mob/living/simple_animal/M in sortmob)
moblist.Add(M)
// for(var/mob/living/silicon/hivebot/M in world)
diff --git a/code/_macros.dm b/code/_macros.dm
index 454a4eaacd..38b9d15c71 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -40,7 +40,9 @@
#define isvoice(A) istype(A, /mob/living/voice)
-#define isslime(A) istype(A, /mob/living/carbon/slime)
+#define isslime(A) istype(A, /mob/living/simple_animal/slime)
+
+#define isbot(A) istype(A, /mob/living/bot)
#define isxeno(A) istype(A, /mob/living/simple_animal/xeno)
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index ac07b8d075..b4eb89b8b3 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -58,77 +58,6 @@
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
A.attack_generic(src,rand(5,6),"bitten")
-/*
- Slimes
- Nothing happening here
-*/
-
-/mob/living/carbon/slime/RestrainedClickOn(var/atom/A)
- return
-
-/mob/living/carbon/slime/UnarmedAttack(var/atom/A, var/proximity)
-
- if(!..())
- return
-
- // Eating
- if(Victim)
- if (Victim == A)
- Feedstop()
- return
-
- //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too
- setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
-
- var/mob/living/M = A
- if (istype(M))
-
- switch(src.a_intent)
- if (I_HELP) // We just poke the other
- M.visible_message("[src] gently pokes [M]!", "[src] gently pokes you!")
- if (I_DISARM) // We stun the target, with the intention to feed
- var/stunprob = 1
- var/power = max(0, min(10, (powerlevel + rand(0, 3))))
- if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- stunprob *= max(H.species.siemens_coefficient,0)
-
-
- switch(power * 10)
- if(0) stunprob *= 10
- if(1 to 2) stunprob *= 20
- if(3 to 4) stunprob *= 30
- if(5 to 6) stunprob *= 40
- if(7 to 8) stunprob *= 60
- if(9) stunprob *= 70
- if(10) stunprob *= 95
-
- if(prob(stunprob))
- powerlevel = max(0, powerlevel-3)
- M.visible_message("[src] has shocked [M]!", "[src] has shocked you!")
- M.Weaken(power)
- M.Stun(power)
- M.stuttering = max(M.stuttering, power)
-
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, M)
- s.start()
-
- if(prob(stunprob) && powerlevel >= 8)
- M.adjustFireLoss(powerlevel * rand(6,10))
- else if(prob(40))
- M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!")
- M.Weaken(power)
- else
- M.visible_message("[src] has tried to pounce at [M]!", "[src] has tried to pounce at you!")
- M.updatehealth()
- if (I_GRAB) // We feed
- Wrap(M)
- if (I_HURT) // Attacking
- A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped")
- else
- A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") // Basic attack.
/*
New Players:
Have no reason to click on anything at all.
@@ -140,15 +69,40 @@
Animals
*/
/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity)
-
if(!..())
return
+ if(prob(spattack_prob))
+ if(spattack_min_range <= 1)
+ target_mob = A
+ SpecialAtkTarget()
+ target_mob = null
+ return
+
if(melee_damage_upper == 0 && istype(A,/mob/living))
custom_emote(1,"[friendly] [A]!")
return
setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
- var/damage = rand(melee_damage_lower, melee_damage_upper)
- if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound)
- playsound(loc, attack_sound, 50, 1, 1)
+ if(isliving(A))
+ target_mob = A
+ PunchTarget()
+ target_mob = null
+ else
+ A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext)
+
+/mob/living/simple_animal/RangedAttack(var/atom/A)
+ setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ var/distance = get_dist(src, A)
+
+ if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range))
+ target_mob = A
+ SpecialAtkTarget()
+ target_mob = null
+ return
+
+ if(ranged && distance <= shoot_range)
+ target_mob = A
+ ShootTarget(A)
+ target_mob = null
+
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index fcf239c88f..8d02fda2eb 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -133,9 +133,6 @@
if("Vote")
debug_variables(vote)
feedback_add_details("admin_verb", "DVote")
- if("Xenobio")
- debug_variables(xenobio_controller)
- feedback_add_details("admin_verb", "DXenobio")
if("Planets")
debug_variables(planet_controller)
feedback_add_details("admin_verb", "DPlanets")
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index cb49518bd8..2c0faffc1e 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -499,7 +499,7 @@
if(!mind.assigned_role) mind.assigned_role = "Assistant" //defualt
//slime
-/mob/living/carbon/slime/mind_initialize()
+/mob/living/simple_animal/slime/mind_initialize()
..()
mind.assigned_role = "slime"
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 64ae0722f8..fa533f5d55 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -94,6 +94,8 @@
/atom/movable/proc/throw_impact(atom/hit_atom, var/speed)
if(istype(hit_atom,/mob/living))
var/mob/living/M = hit_atom
+ if(M.buckled == src)
+ return // Don't hit the thing we're buckled to.
M.hitby(src,speed)
else if(isobj(hit_atom))
diff --git a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm
index 0106ff027e..f45461592d 100644
--- a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm
+++ b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm
@@ -63,7 +63,7 @@
targets.Add(T)
if(!targets.len)
- user << "The teleporter matrix was unable to locate a suitable teleport destination, as all the possibilities \
+ user << "\The [src] was unable to locate a suitable teleport destination, as all the possibilities \
were nonexistant or hazardous. Try a different area."
return
var/turf/simulated/destination = null
@@ -75,6 +75,5 @@
user << "You are teleported to \the [A]."
uses--
if(uses <= 0)
- user << "\The [src] has ran out of uses, and disintegrates from your hands, to prevent \
- reverse engineering by outsiders."
+ user << "\The [src] has ran out of uses, and disintegrates from your hands"
qdel(src)
\ No newline at end of file
diff --git a/code/game/gamemodes/technomancer/spells/control.dm b/code/game/gamemodes/technomancer/spells/control.dm
index 50549ca004..c4591345e5 100644
--- a/code/game/gamemodes/technomancer/spells/control.dm
+++ b/code/game/gamemodes/technomancer/spells/control.dm
@@ -33,7 +33,7 @@
/mob/living/simple_animal/mouse,
/mob/living/simple_animal/parrot,
/mob/living/simple_animal/slime,
- /mob/living/simple_animal/adultslime,
+// /mob/living/simple_animal/adultslime,
/mob/living/simple_animal/tindalos,
/mob/living/simple_animal/yithian,
/mob/living/simple_animal/hostile/bear,
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index f980cfd0b1..31fe02cdcb 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -46,8 +46,8 @@
if(occupant)
user << "The scanner is already occupied!"
return
- for(var/mob/living/carbon/slime/M in range(1, H.affecting))
- if(M.Victim == H.affecting)
+ for(var/mob/living/simple_animal/slime/M in range(1, H.affecting))
+ if(M.victim == H.affecting)
user << "[H.affecting.name] has a fucking slime attached to them, deal with that first."
return
var/mob/M = H.affecting
@@ -83,8 +83,8 @@
if(O.abiotic())
user << "Subject cannot have abiotic items on."
return 0
- for(var/mob/living/carbon/slime/M in range(1, O))
- if(M.Victim == O)
+ for(var/mob/living/simple_animal/slime/M in range(1, O))
+ if(M.victim == O)
user << "[O] has a fucking slime attached to them, deal with that first."
return 0
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 1e27f61866..33529f4447 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -180,15 +180,16 @@
G.loc = src
user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!")
else if(istype(G, /obj/item/weapon/grab))
- if(!ismob(G:affecting))
+ var/obj/item/weapon/grab/grab = G
+ if(!ismob(grab.affecting))
return
- for(var/mob/living/carbon/slime/M in range(1,G:affecting))
- if(M.Victim == G:affecting)
- usr << "[G:affecting:name] will not fit into the cryo because they have a slime latched onto their head."
+ for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting))
+ if(M.victim == grab.affecting)
+ usr << "[grab.affecting.name] will not fit into the cryo because they have a slime latched onto their head."
return
- var/mob/M = G:affecting
+ var/mob/M = grab.affecting
if(put_mob(M))
- qdel(G)
+ qdel(grab)
return
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(var/mob/target, var/mob/user) //Allows borgs to put people into cryo without external assistance
@@ -343,8 +344,8 @@
set name = "Move Inside"
set category = "Object"
set src in oview(1)
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
+ for(var/mob/living/simple_animal/slime/M in range(1,usr))
+ if(M.victim == usr)
usr << "You're too busy getting your life sucked out of you."
return
if(usr.stat != 0)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 08a1282e52..3ef7fe00a7 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -539,8 +539,8 @@
usr << "\The [src] is in use."
return
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
+ for(var/mob/living/simple_animal/slime/M in range(1,usr))
+ if(M.victim == usr)
usr << "You're too busy getting your life sucked out of you."
return
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 5449d3436b..4fc02c70cc 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -180,6 +180,21 @@
if (src.operating == 1)
return
+ // Fixing.
+ if(istype(I, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP)
+ var/obj/item/weapon/weldingtool/WT = I
+ if(health < maxhealth)
+ if(WT.remove_fuel(1 ,user))
+ to_chat(user, "You begin repairing [src]...")
+ playsound(src, WT.usesound, 50, 1)
+ if(do_after(user, 40 * WT.toolspeed, target = src))
+ health = maxhealth
+ update_icon()
+ to_chat(user, "You repair [src].")
+ else
+ to_chat(user, "[src] is already in good condition!")
+ return
+
//Emags and ninja swords? You may pass.
if (istype(I, /obj/item/weapon/melee/energy/blade))
if(emag_act(10, user))
diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm
index 5b78f81249..9732b166f0 100644
--- a/code/game/machinery/kitchen/smartfridge.dm
+++ b/code/game/machinery/kitchen/smartfridge.dm
@@ -65,19 +65,11 @@
req_access = list(access_research)
/obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O as obj)
- if(istype(O,/obj/item/xenoproduct/))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/extract/New()
- ..()
- var/datum/stored_item/I = new(src, /obj/item/xenoproduct/slime/core)
- item_records.Add(I)
- for(var/i=1 to 5)
- var/obj/item/xenoproduct/slime/core/C = new(src)
- C.traits = new()
- C.nameVar = "grey"
- I.add_product(C)
+ if(istype(O, /obj/item/slime_extract))
+ return TRUE
+ if(istype(O, /obj/item/slimepotion))
+ return TRUE
+ return FALSE
/obj/machinery/smartfridge/secure/medbay
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index 1e10e03f4f..acd680ba57 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -39,8 +39,8 @@
if(occupant)
occupant_message("The sleeper is already occupied")
return
- for(var/mob/living/carbon/slime/M in range(1,target))
- if(M.Victim == target)
+ for(var/mob/living/simple_animal/slime/M in range(1,target))
+ if(M.victim == target)
occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.")
return
occupant_message("You start putting [target] into [src].")
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 4d7ee902d8..a1cbba3102 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -1154,8 +1154,8 @@
usr << "Kinda hard to climb in while handcuffed don't you think?"
return
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
+ for(var/mob/living/simple_animal/slime/M in range(1,usr))
+ if(M.victim == usr)
usr << "You're too busy getting your life sucked out of you."
return
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 5d7d16a126..6f117b2f3e 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -1015,8 +1015,8 @@
usr << "Access denied"
src.log_append_to_last("Permission denied.")
return
- for(var/mob/living/carbon/slime/M in range(1,usr))
- if(M.Victim == usr)
+ for(var/mob/living/simple_animal/slime/M in range(1,usr))
+ if(M.victim == usr)
usr << "You're too busy getting your life sucked out of you."
return
// usr << "You start climbing into [src.name]"
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index c963a902bb..a26a0de0e8 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -1,4 +1,6 @@
-/obj
+
+
+/atom/movable
var/can_buckle = 0
var/buckle_movable = 0
var/buckle_dir = 0
@@ -6,7 +8,8 @@
var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes
var/mob/living/buckled_mob = null
-/obj/attack_hand(mob/living/user)
+
+/atom/movable/attack_hand(mob/living/user)
. = ..()
if(can_buckle && buckled_mob)
user_unbuckle_mob(user)
@@ -16,18 +19,20 @@
return attack_hand(user) //Process as if we're a normal person touching the object.
return ..() //Otherwise, treat this as an AI click like usual.
-/obj/MouseDrop_T(mob/living/M, mob/living/user)
+/atom/movable/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
if(can_buckle && istype(M))
user_buckle_mob(M, user)
-/obj/Destroy()
+/atom/movable/Destroy()
unbuckle_mob()
return ..()
-/obj/proc/buckle_mob(mob/living/M)
- if(!can_buckle || !istype(M) || (M.loc != loc) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained()))
+/atom/movable/proc/buckle_mob(mob/living/M, forced = FALSE, check_loc = TRUE)
+ if((!can_buckle && !forced) || !istype(M) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained()))
+ return 0
+ if(check_loc && M.loc != loc)
return 0
if(buckled_mob) //Handles trying to buckle yourself to the chair when someone is on it
M << "\The [src] already has someone buckled to it."
@@ -43,7 +48,7 @@
post_buckle_mob(M)
return 1
-/obj/proc/unbuckle_mob()
+/atom/movable/proc/unbuckle_mob()
if(buckled_mob && buckled_mob.buckled == src)
. = buckled_mob
buckled_mob.buckled = null
@@ -54,19 +59,16 @@
post_buckle_mob(.)
-/obj/proc/post_buckle_mob(mob/living/M)
+/atom/movable/proc/post_buckle_mob(mob/living/M)
return
-/obj/proc/user_buckle_mob(mob/living/M, mob/user)
+/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, var/forced = FALSE, var/silent = FALSE)
if(!ticker)
user << "You can't buckle anyone in before the game starts."
if(!user.Adjacent(M) || user.restrained() || user.lying || user.stat || istype(user, /mob/living/silicon/pai))
return
if(M == buckled_mob)
return
- if(istype(M, /mob/living/carbon/slime))
- user << "The [M] is too squishy to buckle in."
- return
add_fingerprint(user)
unbuckle_mob()
@@ -75,20 +77,21 @@
if(M.loc != src.loc)
step_towards(M, src)
- . = buckle_mob(M)
+ . = buckle_mob(M, forced)
if(.)
- if(M == user)
- M.visible_message(\
- "[M.name] buckles themselves to [src].",\
- "You buckle yourself to [src].",\
- "You hear metal clanking.")
- else
- M.visible_message(\
- "[M.name] is buckled to [src] by [user.name]!",\
- "You are buckled to [src] by [user.name]!",\
- "You hear metal clanking.")
+ if(!silent)
+ if(M == user)
+ M.visible_message(\
+ "[M.name] buckles themselves to [src].",\
+ "You buckle yourself to [src].",\
+ "You hear metal clanking.")
+ else
+ M.visible_message(\
+ "[M.name] is buckled to [src] by [user.name]!",\
+ "You are buckled to [src] by [user.name]!",\
+ "You hear metal clanking.")
-/obj/proc/user_unbuckle_mob(mob/user)
+/atom/movable/proc/user_unbuckle_mob(mob/user)
var/mob/living/M = unbuckle_mob()
if(M)
if(M != user)
@@ -104,3 +107,19 @@
add_fingerprint(user)
return M
+/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
+ if(buckled_mob)
+// if(!buckled_mob.Move(newloc, direct))
+ if(!buckled_mob.forceMove(newloc, direct))
+ loc = buckled_mob.loc
+ last_move = buckled_mob.last_move
+ buckled_mob.inertia_dir = last_move
+ return FALSE
+ else
+ buckled_mob.set_dir(dir)
+ return TRUE
+
+/atom/movable/Move(atom/newloc, direct = 0)
+ . = ..()
+ if(. && buckled_mob && !handle_buckled_mob_movement(newloc, direct)) //movement failed due to buckled mob(s)
+ . = 0
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 996f848849..973cb522e7 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -448,10 +448,11 @@
/obj/item/device/flashlight/slime
gender = PLURAL
name = "glowing slime extract"
- desc = "A glowing ball of what appears to be amber."
+ desc = "A slimy ball that appears to be glowing from bioluminesence."
icon = 'icons/obj/lighting.dmi'
icon_state = "floor1" //not a slime extract sprite but... something close enough!
item_state = "slime"
+ light_color = "#FFF423"
w_class = ITEMSIZE_TINY
brightness_on = 6
on = 1 //Bio-luminesence has one setting, on.
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index cfd0693b15..d903499ee0 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -364,32 +364,38 @@ REAGENT SCANNER
matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20)
/obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob)
- if (!isslime(M))
+ if(!isslime(M))
user << "This device can only scan slimes!"
return
- var/mob/living/carbon/slime/T = M
+ var/mob/living/simple_animal/slime/S = M
user.show_message("Slime scan results:")
- user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby"))
- user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition()))
- if (T.nutrition < T.get_starve_nutrition())
- user.show_message("Warning: slime is starving!")
- else if (T.nutrition < T.get_hunger_nutrition())
- user.show_message("Warning: slime is hungry")
- user.show_message("Electric change strength: [T.powerlevel]")
- user.show_message("Health: [T.health]")
- if (T.slime_mutation[4] == T.colour)
- user.show_message("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(text("Possible mutation: []", T.slime_mutation[3]))
- user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting")
- else
- user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3]))
- user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting")
- else
- user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4]))
- user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting")
- if (T.cores > 1)
- user.show_message("Anomalious slime core amount detected")
- user.show_message("Growth progress: [T.amount_grown]/10")
+ user.show_message(text("[S.slime_color] [] slime", S.is_adult ? "adult" : "baby"))
+
+ user.show_message("Health: [S.health]")
+ user.show_message("Mutation Probability: [S.mutation_chance]")
+
+ var/list/mutations = list()
+ for(var/potential_color in S.slime_mutation)
+ var/mob/living/simple_animal/slime/slime = potential_color
+ mutations.Add(initial(slime.slime_color))
+
+ user.show_message("Potental to mutate into [english_list(mutations)] colors.")
+ user.show_message("Extract potential: [S.cores]")
+
+ user.show_message(text("Nutrition: [S.nutrition]/[]", S.get_max_nutrition()))
+ if (S.nutrition < S.get_starve_nutrition())
+ user.show_message("Warning: Subject is starving!")
+ else if (S.nutrition < S.get_hunger_nutrition())
+ user.show_message("Warning: Subject is hungry.")
+ user.show_message("Electric change strength: [S.power_charge]")
+
+ if(S.resentment)
+ user.show_message("Warning: Subject is harboring resentment.")
+ if(S.docile)
+ user.show_message("Subject has been pacified.")
+ if(S.rabid)
+ user.show_message("Subject is enraged and extremely dangerous!")
+ if(S.unity)
+ user.show_message("Subject is friendly to other slime colors.")
+
+ user.show_message("Growth progress: [S.amount_grown]/10")
diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm
index 66080882be..44b33721cf 100644
--- a/code/game/objects/items/weapons/implants/implantchair.dm
+++ b/code/game/objects/items/weapons/implants/implantchair.dm
@@ -76,13 +76,14 @@
attackby(var/obj/item/weapon/G as obj, var/mob/user as mob)
if(istype(G, /obj/item/weapon/grab))
- if(!ismob(G:affecting))
+ var/obj/item/weapon/grab/grab = G
+ if(!ismob(grab.affecting))
return
- for(var/mob/living/carbon/slime/M in range(1,G:affecting))
- if(M.Victim == G:affecting)
- usr << "[G:affecting:name] will not fit into the [src.name] because they have a slime latched onto their head."
+ for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting))
+ if(M.victim == grab.affecting)
+ usr << "[grab.affecting.name] will not fit into the [src.name] because they have a slime latched onto their head."
return
- var/mob/M = G:affecting
+ var/mob/M = grab.affecting
if(put_mob(M))
qdel(G)
src.updateUsrDialog()
diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm
index 192f667feb..3a2373c696 100644
--- a/code/game/objects/items/weapons/power_cells.dm
+++ b/code/game/objects/items/weapons/power_cells.dm
@@ -14,6 +14,8 @@
var/maxcharge = 1000
var/rigged = 0 // true if rigged to explode
var/minor_fault = 0 //If not 100% reliable, it will build up faults.
+ var/self_recharge = FALSE // If true, the cell will recharge itself.
+ var/charge_amount = 25 // How much power to give, if self_recharge is true. The number is in absolute cell charge, as it gets divided by CELLRATE later.
matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50)
suicide_act(mob/user)
@@ -125,8 +127,10 @@
/obj/item/weapon/cell/slime
name = "charged slime core"
desc = "A yellow slime core infused with phoron, it crackles with power."
- origin_tech = list(TECH_POWER = 2, TECH_BIO = 4)
+ origin_tech = list(TECH_POWER = 4, TECH_BIO = 5)
icon = 'icons/mob/slimes.dmi' //'icons/obj/harvest.dmi'
icon_state = "yellow slime extract" //"potato_battery"
+ description_info = "This 'cell' holds a max charge of 10k and self recharges over time."
maxcharge = 10000
matter = null
+ self_recharge = TRUE
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 2f4b2f3a8c..1b54df33e6 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -90,7 +90,7 @@
icon_state = "[initial(name)]"
if(icon_state == "[initial(name)]_active")
- set_light(1.5, 1, lightcolor)
+ set_light(2, 1, lightcolor)
else
set_light(0)
@@ -237,4 +237,16 @@
else
user << "[src] already has a cell."
else
- user << "This cell is not fitted for [src]."
\ No newline at end of file
+ user << "This cell is not fitted for [src]."
+
+/obj/item/weapon/melee/baton/get_description_interaction()
+ var/list/results = list()
+
+ if(bcell)
+ results += "[desc_panel_image("offhand")]to remove the weapon cell."
+ else
+ results += "[desc_panel_image("weapon cell")]to add a new weapon cell."
+
+ results += ..()
+
+ return results
\ No newline at end of file
diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm
index 3afaa7a665..4da7cc6aeb 100644
--- a/code/game/objects/random/random.dm
+++ b/code/game/objects/random/random.dm
@@ -828,7 +828,6 @@ something, make sure it's not in one of the other lists.*/
/obj/random/maintenance/research/item_to_spawn()
return pick(prob(320);/obj/random/maintenance/clean,
prob(3);/obj/item/device/analyzer/plant_analyzer,
- prob(2);/obj/item/device/analyzer/xeno_analyzer,
prob(1);/obj/item/device/flash/synthetic,
prob(2);/obj/item/weapon/bucket_sensor,
prob(1);/obj/item/weapon/cell/device/weapon,
diff --git a/code/game/objects/structures/crates_lockers/closets/l3closet.dm b/code/game/objects/structures/crates_lockers/closets/l3closet.dm
index c00875e522..7c54614aa7 100644
--- a/code/game/objects/structures/crates_lockers/closets/l3closet.dm
+++ b/code/game/objects/structures/crates_lockers/closets/l3closet.dm
@@ -67,6 +67,11 @@
new /obj/item/clothing/suit/bio_suit/scientist(src)
new /obj/item/clothing/head/bio_hood/scientist(src)
+/obj/structure/closet/l3closet/scientist/double/New()
+ ..()
+ new /obj/item/clothing/suit/bio_suit/scientist(src)
+ new /obj/item/clothing/head/bio_hood/scientist(src)
+
/obj/structure/closet/l3closet/medical
icon_state = "bio_scientist"
diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
index 67a4d3e788..110790aa82 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -88,6 +88,15 @@
new /obj/item/weapon/extinguisher(src)
new /obj/item/clothing/head/hardhat/red(src)
+/obj/structure/closet/firecloset/full/double/New()
+ ..()
+ new /obj/item/clothing/suit/fire/firefighter(src)
+ new /obj/item/clothing/mask/gas(src)
+ new /obj/item/device/flashlight(src)
+ new /obj/item/weapon/tank/oxygen/red(src)
+ new /obj/item/weapon/extinguisher(src)
+ new /obj/item/clothing/head/hardhat/red(src)
+
/obj/structure/closet/firecloset/update_icon()
if(!opened)
icon_state = icon_closed
@@ -175,6 +184,12 @@
new /obj/item/clothing/shoes/black( src )
new /obj/item/clothing/head/bomb_hood( src )
+/obj/structure/closet/bombcloset/double/New() // Makes two suits.
+ ..()
+ new /obj/item/clothing/suit/bomb_suit( src )
+ new /obj/item/clothing/under/color/black( src )
+ new /obj/item/clothing/shoes/black( src )
+ new /obj/item/clothing/head/bomb_hood( src )
/obj/structure/closet/bombclosetsecurity
name = "\improper EOD closet"
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 51e37d462f..ca9276c6c2 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -59,10 +59,13 @@
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
if(health < maxhealth / 4 && initialhealth >= maxhealth / 4)
visible_message("[src] looks like it's about to shatter!" )
+ update_icon()
else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2)
visible_message("[src] looks seriously damaged!" )
+ update_icon()
else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4)
visible_message("Cracks begin to appear in [src]!" )
+ update_icon()
return
/obj/structure/window/proc/apply_silicate(var/amount)
@@ -204,6 +207,8 @@
return
if(damage >= 10)
visible_message("[user] smashes into [src]!")
+ if(reinf)
+ damage = damage / 2
take_damage(damage)
else
visible_message("\The [user] bonks \the [src] harmlessly.")
@@ -212,6 +217,24 @@
/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob)
if(!istype(W)) return//I really wish I did not need this
+
+ // Fixing.
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP)
+ var/obj/item/weapon/weldingtool/WT = W
+ if(health < maxhealth)
+ if(WT.remove_fuel(1 ,user))
+ to_chat(user, "You begin repairing [src]...")
+ playsound(src, WT.usesound, 50, 1)
+ if(do_after(user, 40 * WT.toolspeed, target = src))
+ health = maxhealth
+ // playsound(src, 'sound/items/Welder.ogg', 50, 1)
+ update_icon()
+ to_chat(user, "You repair [src].")
+ else
+ to_chat(user, "[src] is already in good condition!")
+ return
+
+ // Slamming.
if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
var/obj/item/weapon/grab/G = W
if(istype(G.affecting,/mob/living))
@@ -408,6 +431,15 @@
var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1))
overlays += I
+ // Damage overlays.
+ var/ratio = health / maxhealth
+ ratio = Ceiling(ratio * 4) * 25
+
+ if(ratio > 75)
+ return
+ var/image/I = image(icon, "damage[ratio]", layer + 0.1)
+ overlays += I
+
return
/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -437,6 +469,10 @@
damage_per_fire_tick = 1.0
maxhealth = 40.0
+/obj/structure/window/phoronbasic/full
+ dir = SOUTHWEST
+ maxhealth = 80
+
/obj/structure/window/phoronreinforced
name = "reinforced borosilicate window"
desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
@@ -449,6 +485,9 @@
damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
maxhealth = 80.0
+/obj/structure/window/phoronreinforced/full
+ dir = SOUTHWEST
+ maxhealth = 160
/obj/structure/window/reinforced
name = "reinforced window"
@@ -470,9 +509,9 @@
state = 0
/obj/structure/window/reinforced/full
- dir = 5
+ dir = SOUTHWEST
icon_state = "fwindow"
- maxhealth = 60
+ maxhealth = 80
/obj/structure/window/reinforced/tinted
name = "tinted window"
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index f7bfd311e2..be376e0f65 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -50,7 +50,7 @@ var/list/mechtoys = list(
explosion_resistance = 5
var/list/mobs_can_pass = list(
/mob/living/bot,
- /mob/living/carbon/slime,
+ /mob/living/simple_animal/slime,
/mob/living/simple_animal/mouse,
/mob/living/silicon/robot/drone
)
diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm
index 6e23d74bbb..8f6beee8d6 100644
--- a/code/game/verbs/suicide.dm
+++ b/code/game/verbs/suicide.dm
@@ -164,24 +164,3 @@
death(0)
else
src << "Aborting suicide attempt."
-
-/mob/living/carbon/slime/verb/suicide()
- set hidden = 1
- if (stat == 2)
- src << "You're already dead!"
- return
-
- if (suiciding)
- src << "You're already committing suicide! Be patient!"
- return
-
- var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No")
-
- if(confirm == "Yes")
- suiciding = 30
- setOxyLoss(100)
- adjustBruteLoss(100 - getBruteLoss())
- setToxLoss(100)
- setCloneLoss(100)
-
- updatehealth()
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 6b3560a824..84a2320a2f 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -114,8 +114,7 @@ proc/admin_notice(var/message, var/rights)
else if(ishuman(M))
body += {"Make AI |
Make Robot |
- Make Alien |
- Make slime
+ Make Alien
"}
//Simple Animals
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index ab3fa05d21..f43af3ec86 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -190,7 +190,6 @@ var/list/admin_verbs_debug = list(
/client/proc/overlay_random_map,
/client/proc/delete_random_map,
/client/proc/show_plant_genes,
- /client/proc/show_xenobio_genes,
/client/proc/enable_debug_verbs,
/client/proc/callproc,
/client/proc/callproc_target,
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index fde36a734c..db16b214b2 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -266,7 +266,7 @@
if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob )
if("nymph") M.change_mob_type( /mob/living/carbon/alien/diona , null, null, delmob )
if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"])
- if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob )
+ if("slime") M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob )
if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob )
if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob )
if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob )
@@ -1146,16 +1146,6 @@
log_admin("[key_name(usr)] AIized [key_name(H)]")
H.AIize()
- else if(href_list["makeslime"])
- if(!check_rights(R_SPAWN)) return
-
- var/mob/living/carbon/human/H = locate(href_list["makeslime"])
- if(!istype(H))
- usr << "This can only be used on instances of type /mob/living/carbon/human"
- return
-
- usr.client.cmd_admin_slimeize(H)
-
else if(href_list["makerobot"])
if(!check_rights(R_SPAWN)) return
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 80ed64458e..a3fd6acf3e 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -100,23 +100,6 @@
paiController.pai_candidates.Remove(candidate)
feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-/client/proc/cmd_admin_slimeize(var/mob/M in mob_list)
- set category = "Fun"
- set name = "Make slime"
-
- if(!ticker)
- alert("Wait until the game starts")
- return
- if(ishuman(M))
- log_admin("[key_name(src)] has slimeized [M.key].")
- spawn(10)
- M:slimeize()
- feedback_add_details("admin_verb","MKMET") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- log_admin("[key_name(usr)] made [key_name(M)] into a slime.")
- message_admins("[key_name_admin(usr)] made [key_name(M)] into a slime.", 1)
- else
- alert("Invalid mob")
-
/*
/client/proc/cmd_admin_monkeyize(var/mob/M in world)
set category = "Fun"
diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm
index 95945f82e0..81780f2103 100644
--- a/code/modules/admin/view_variables/helpers.dm
+++ b/code/modules/admin/view_variables/helpers.dm
@@ -68,7 +68,6 @@
-
"}
/obj/get_view_variables_options()
diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm
index d68d51ae4a..7d0966dc59 100644
--- a/code/modules/admin/view_variables/topic.dm
+++ b/code/modules/admin/view_variables/topic.dm
@@ -281,20 +281,6 @@
return
holder.Topic(href, list("makealien"=href_list["makealien"]))
- else if(href_list["makeslime"])
- if(!check_rights(R_SPAWN)) return
-
- var/mob/living/carbon/human/H = locate(href_list["makeslime"])
- if(!istype(H))
- usr << "This can only be done to instances of type /mob/living/carbon/human"
- return
-
- if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return
- if(!H)
- usr << "Mob doesn't exist anymore"
- return
- holder.Topic(href, list("makeslime"=href_list["makeslime"]))
-
else if(href_list["makeai"])
if(!check_rights(R_SPAWN)) return
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 9629a53283..7e951f57e1 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -78,7 +78,8 @@
name = "Radiation Hood"
icon_state = "rad"
desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation"
- flags_inv = BLOCKHAIR
+// flags_inv = BLOCKHAIR
+ item_flags = THICKMATERIAL
body_parts_covered = HEAD|FACE|EYES
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
@@ -94,3 +95,4 @@
slowdown = 1.5
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100)
flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER
+ item_flags = THICKMATERIAL
diff --git a/code/modules/examine/stat_icons.dm b/code/modules/examine/stat_icons.dm
index 49b511de2e..b2ed64032a 100644
--- a/code/modules/examine/stat_icons.dm
+++ b/code/modules/examine/stat_icons.dm
@@ -8,6 +8,8 @@ var/global/list/description_icons = list(
"radiation_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="radiation_protection"),
"biohazard_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="biohazard_protection"),
+ "offhand" = image(icon='icons/mob/screen1_stats.dmi',icon_state="offhand"),
+
"welder" = image(icon='icons/obj/tools.dmi',icon_state="welder"),
"wirecutters" = image(icon='icons/obj/tools.dmi',icon_state="cutters"),
"screwdriver" = image(icon='icons/obj/tools.dmi',icon_state="screwdriver"),
@@ -19,6 +21,12 @@ var/global/list/description_icons = list(
"plasteel sheet" = image(icon='icons/obj/items.dmi',icon_state="sheet-plasteel"),
"air tank" = image(icon='icons/obj/tank.dmi',icon_state="oxygen"),
+ "connector" = image(icon='icons/obj/pipes.dmi',icon_state="connector"),
- "connector" = image(icon='icons/obj/pipes.dmi',icon_state="connector")
+ "stunbaton" = image(icon='icons/obj/weapons.dmi',icon_state="stunbaton_active"),
+ "slimebaton" = image(icon='icons/obj/weapons.dmi',icon_state="slimebaton_active"),
+
+ "power cell" = image(icon='icons/obj/power.dmi',icon_state="hcell"),
+ "device cell" = image(icon='icons/obj/power.dmi',icon_state="dcell"),
+ "weapon cell" = image(icon='icons/obj/power.dmi',icon_state="wcell"),
)
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index 971a04bd22..c839b506fa 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -128,6 +128,9 @@
..(message, null, verb)
+/mob/living/bot/speech_bubble_appearance()
+ return "machine"
+
/mob/living/bot/Bump(var/atom/A)
if(on && botcard && istype(A, /obj/machinery/door))
var/obj/machinery/door/D = A
@@ -313,6 +316,18 @@
return L
+// Similar to above but not restricted to just cardinal directions.
+/turf/proc/TurfsWithAccess(var/obj/item/weapon/card/id/ID)
+ var/L[] = new()
+
+ for(var/d in alldirs)
+ var/turf/T = get_step(src, d)
+ if(istype(T) && !T.density)
+ if(!LinkBlockedWithAccess(src, T, ID))
+ L.Add(T)
+ return L
+
+
// Returns true if a link between A and B is blocked
// Movement through doors allowed if ID has access
/proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID)
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index d6a014c450..9e3a266a64 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -13,6 +13,7 @@
patrol_speed = 2
target_speed = 3
+ var/default_icon_state = "secbot"
var/idcheck = 0 // If true, arrests for having weapons without authorization.
var/check_records = 0 // If true, arrests people without a record.
var/check_arrest = 1 // If true, arrests people who are set to arrest.
@@ -21,23 +22,44 @@
var/is_ranged = 0
var/awaiting_surrender = 0
+ var/can_next_insult = 0 // Uses world.time
+ var/stun_strength = 60 // For humans.
+ var/xeno_stun_strength = 0 // For simple mobs.
+ var/xeno_harm_strength = 15 // Ditto.
+ var/baton_glow = "#FF6A00"
var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
var/list/preparing_arrest_sounds = list('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg')
+ var/list/fighting_sounds = list('sound/voice/biamthelaw.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bjustice.ogg')
/mob/living/bot/secbot/beepsky
name = "Officer Beepsky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
will_patrol = 1
+/mob/living/bot/secbot/slime
+ name = "Slime Securitron"
+ desc = "A little security robot, with a slime baton subsituted for the regular one."
+ default_icon_state = "slimesecbot"
+ stun_strength = 10 // Slimebatons aren't meant for humans.
+ xeno_stun_strength = 5
+ xeno_harm_strength = 9
+ baton_glow = "#33CCFF"
+ req_one_access = list(access_research, access_robotics)
+ botcard_access = list(access_research, access_robotics, access_xenobiology, access_xenoarch, access_tox, access_tox_storage, access_maint_tunnels)
+
+/mob/living/bot/secbot/slime/slimesky
+ name = "Doctor Slimesky"
+ desc = "An old friend of Officer Beep O'sky. He prescribes beatings to rowdy slimes so that real doctors don't need to treat the xenobiologists."
+
/mob/living/bot/secbot/update_icons()
if(on && busy)
- icon_state = "secbot-c"
+ icon_state = "[default_icon_state]-c"
else
- icon_state = "secbot[on]"
+ icon_state = "[default_icon_state][on]"
if(on)
- set_light(2, 1, "#FF6A00")
+ set_light(2, 1, baton_glow)
else
set_light(0)
@@ -114,6 +136,11 @@
if(!target && health < curhealth && shooter && (shooter in view(world.view, src)))
react_to_attack(shooter)
+/mob/living/bot/secbot/attack_generic(var/mob/attacker)
+ if(attacker)
+ react_to_attack(attacker)
+ ..()
+
/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
if(!target)
playsound(src.loc, pick(threat_found_sounds), 50)
@@ -163,6 +190,7 @@
awaiting_surrender = -1
say("Level [threat] infraction alert!")
custom_emote(1, "points at [M.name]!")
+ playsound(src.loc, pick(threat_found_sounds), 50)
return
/mob/living/bot/secbot/handleAdjacentTarget()
@@ -174,9 +202,25 @@
++awaiting_surrender
else
if(declare_arrests)
- broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect [target_name(target)] in [get_area(src)].", src)
+ var/action = arrest_type ? "detaining" : "arresting"
+ if(istype(target, /mob/living/simple_animal))
+ action = "fighting"
+ broadcast_security_hud_message("[src] is [action] a level [threat] [action != "fighting" ? "suspect" : "threat"] [target_name(target)] in [get_area(src)].", src)
UnarmedAttack(target)
+// So Beepsky talks while beating up simple mobs.
+/mob/living/bot/secbot/proc/insult(var/mob/living/L)
+ if(can_next_insult > world.time)
+ return
+ var/threat = check_threat(L)
+ if(threat >= 10)
+ playsound(src.loc, 'sound/voice/binsult.ogg', 75)
+ can_next_insult = world.time + 20 SECONDS
+ else
+ playsound(src.loc, pick(fighting_sounds), 75)
+ can_next_insult = world.time + 5 SECONDS
+
+
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
if(!..())
return
@@ -194,7 +238,7 @@
if(!C.lying || C.handcuffed || arrest_type)
cuff = 0
if(!cuff)
- C.stun_effect_act(0, 60, null)
+ C.stun_effect_act(0, stun_strength, null)
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
do_attack_animation(C)
busy = 1
@@ -203,6 +247,7 @@
busy = 0
update_icons()
visible_message("\The [C] was prodded by \the [src] with a stun baton!")
+ insult(C)
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
visible_message("\The [src] is trying to put handcuffs on \the [C]!")
@@ -214,8 +259,8 @@
busy = 0
else if(istype(M, /mob/living/simple_animal))
var/mob/living/simple_animal/S = M
- S.AdjustStunned(10)
- S.adjustBruteLoss(15)
+ S.Weaken(xeno_stun_strength)
+ S.adjustBruteLoss(xeno_harm_strength)
do_attack_animation(M)
playsound(loc, "swing_hit", 50, 1, -1)
busy = 1
@@ -224,6 +269,15 @@
busy = 0
update_icons()
visible_message("\The [M] was beaten by \the [src] with a stun baton!")
+ insult(S)
+
+/mob/living/bot/secbot/slime/UnarmedAttack(var/mob/living/L, var/proximity)
+ ..()
+
+ if(istype(L, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = L
+ S.adjust_discipline(2)
+
/mob/living/bot/secbot/explode()
@@ -323,8 +377,12 @@
else if(istype(W, /obj/item/weapon/melee/baton) && build_step == 3)
user.drop_item()
user << "You complete the Securitron! Beep boop."
- var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src))
- S.name = created_name
+ if(istype(W, /obj/item/weapon/melee/baton/slime))
+ var/mob/living/bot/secbot/slime/S = new /mob/living/bot/secbot/slime(get_turf(src))
+ S.name = created_name
+ else
+ var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src))
+ S.name = created_name
qdel(W)
qdel(src)
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm
index 2905b4fe4d..af4093688b 100644
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ b/code/modules/mob/living/carbon/brain/brain.dm
@@ -45,7 +45,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/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index b432139325..e37be0e032 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -355,6 +355,9 @@ emp_act
//this proc handles being hit by a thrown atom
/mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)
+// if(buckled && buckled == AM)
+// return // Don't get hit by the thing we're buckled to.
+
if(istype(AM,/obj/))
var/obj/O = AM
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index c87338d26c..a0276a15ac 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -38,6 +38,15 @@
say(temp)
winset(client, "input", "text=[null]")
+/mob/living/carbon/human/speech_bubble_appearance()
+ if(isSynthetic())
+ var/datum/robolimb/robo = isSynthetic()
+ return robo.speech_bubble_appearance
+ else
+ if(species)
+ return species.speech_bubble_appearance
+ return "normal"
+
/mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null)
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
@@ -55,7 +64,7 @@
return 1
if (istype(other, /mob/living/carbon/brain))
return 1
- if (istype(other, /mob/living/carbon/slime))
+ if (istype(other, /mob/living/simple_animal/slime))
return 1
//This is already covered by mob/say_understands()
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index f547cba9fc..9dc3291215 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -13,6 +13,8 @@
var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set.
var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set.
+ var/speech_bubble_appearance = "normal" // Part of icon_state to use for speech bubbles when talking. See talk.dmi for available icons.
+
// Damage overlay and masks.
var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi'
var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi'
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index 802cf43154..3a2eb6af49 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -28,6 +28,8 @@ var/datum/species/shapeshifter/promethean/prometheans
breath_type = null
poison_type = null
+ speech_bubble_appearance = "slime"
+
male_cough_sounds = list('sound/effects/slime_squish.ogg')
female_cough_sounds = list('sound/effects/slime_squish.ogg')
diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm
index c59c6826d5..db66524a29 100644
--- a/code/modules/mob/living/carbon/metroid/items.dm
+++ b/code/modules/mob/living/carbon/metroid/items.dm
@@ -9,27 +9,27 @@
throw_speed = 3
throw_range = 6
origin_tech = list(TECH_BIO = 4)
- var/Uses = 1 // uses before it goes inert
+ var/uses = 1 // uses before it goes inert
var/enhanced = 0 //has it been enhanced before?
flags = OPENCONTAINER
-
- attackby(obj/item/O as obj, mob/user as mob)
- if(istype(O, /obj/item/weapon/slimesteroid2))
- if(enhanced == 1)
- user << " This extract has already been enhanced!"
- return ..()
- if(Uses == 0)
- user << " You can't enhance a used extract!"
- return ..()
- user <<"You apply the enhancer. It now has triple the amount of uses."
- Uses = 3
- enhanced = 1
- qdel(O)
-
+/*
+/obj/item/slime_extract/attackby(obj/item/O as obj, mob/user as mob)
+ if(istype(O, /obj/item/weapon/slimesteroid2))
+ if(enhanced == 1)
+ user << " This extract has already been enhanced!"
+ return ..()
+ if(Uses == 0)
+ user << " You can't enhance a used extract!"
+ return ..()
+ user <<"You apply the enhancer. It now has triple the amount of uses."
+ Uses = 3
+ enhanced = 1
+ qdel(O)
+*/
/obj/item/slime_extract/New()
..()
- create_reagents(100)
- reagents.add_reagent("slimejelly", 30)
+ create_reagents(5)
+// reagents.add_reagent("slimejelly", 30)
/obj/item/slime_extract/grey
name = "grey slime extract"
@@ -51,7 +51,7 @@
name = "purple slime extract"
icon_state = "purple slime extract"
-/obj/item/slime_extract/darkpurple
+/obj/item/slime_extract/dark_purple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
@@ -71,7 +71,7 @@
name = "blue slime extract"
icon_state = "blue slime extract"
-/obj/item/slime_extract/darkblue
+/obj/item/slime_extract/dark_blue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
@@ -119,41 +119,66 @@
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
-////Pet Slime Creation///
+/obj/item/slimepotion
+ icon = 'icons/obj/chemical.dmi'
-/obj/item/weapon/slimepotion
+////Pet Slime Creation///
+/*
+/obj/item/slimepotion/docility
name = "docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame."
- icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
- attack(mob/living/carbon/slime/M as mob, mob/user as mob)
- if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
- user << " The potion only works on baby slimes!"
- return ..()
- if(M.is_adult) //Can't tame adults
- user << " Only baby slimes can be tamed!"
- return..()
- if(M.stat)
- user << " The slime is dead!"
- return..()
- if(M.mind)
- user << " The slime resists!"
- return ..()
- var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
- pet.icon_state = "[M.colour] baby slime"
- pet.icon_living = "[M.colour] baby slime"
- pet.icon_dead = "[M.colour] baby slime dead"
- pet.colour = "[M.colour]"
- user <<"You feed the slime the potion, removing it's powers and calming it."
- qdel(M)
- var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN)
+/obj/item/slimepotion/docility/attack(mob/living/carbon/slime/M as mob, mob/user as mob)
+ if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
+ user << " The potion only works on slimes!"
+ return ..()
+// if(M.is_adult) //Can't tame adults
+// user << " Only baby slimes can be tamed!"
+// return..()
+ if(M.stat)
+ user << " The slime is dead!"
+ return..()
+ if(M.mind)
+ user << " The slime resists!"
+ return ..()
+ var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
+ pet.icon_state = "[M.colour] [M.is_adult ? "adult" : "baby"] slime"
+ pet.icon_living = "[M.colour] [M.is_adult ? "adult" : "baby"] slime"
+ pet.icon_dead = "[M.colour] [M.is_adult ? "adult" : "baby"] slime dead"
+ pet.colour = "[M.colour]"
+ to_chat(user, "You feed the slime the potion, removing it's powers and calming it.")
+
+ qdel(M)
+
+ var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN)
+
+ if (!newname)
+ newname = "pet slime"
+ pet.name = newname
+ pet.real_name = newname
+ qdel(src)
+
+/obj/item/slimepotion/stabilizer
+ name = "slime stabilizer"
+ desc = "A potent chemical mix that will reduce the chance of a slime mutating."
+ icon_state = "potcyan"
+
+/obj/item/slimepotion/stabilizer/attack(mob/living/carbon/slime/M, mob/user)
+ if(!isslime(M))
+ to_chat(user, "The stabilizer only works on slimes!")
+ return ..()
+ if(M.stat)
+ to_chat(user, "The slime is dead!")
+ return ..()
+ if(M.mutation_chance == 0)
+ to_chat(user, "The slime already has no chance of mutating!")
+ return ..()
+
+ to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.")
+ M.mutation_chance = Clamp(M.mutation_chance-15,0,100)
+ qdel(src)
- if (!newname)
- newname = "pet slime"
- pet.name = newname
- pet.real_name = newname
- qdel(src)
/obj/item/weapon/slimepotion2
name = "advanced docility potion"
@@ -187,7 +212,7 @@
qdel(src)
-/obj/item/weapon/slimesteroid
+/obj/item/slimesteroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
@@ -211,7 +236,7 @@
M.cores = 3
qdel(src)
-/obj/item/weapon/slimesteroid2
+/obj/item/slimesteroid2
name = "extract enhancer"
desc = "A potent chemical mix that will give a slime extract three uses."
icon = 'icons/obj/chemical.dmi'
@@ -229,7 +254,7 @@
target.Uses = 3
target.enahnced = 1
qdel(src)*/
-
+*/
/obj/effect/golemrune
anchored = 1
desc = "a strange rune used to create golems. It glows when spirits are nearby."
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 8880efe0da..c313b1482c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -90,9 +90,6 @@ default behaviour is:
forceMove(tmob.loc)
tmob.forceMove(oldloc)
now_pushing = 0
- for(var/mob/living/carbon/slime/slime in view(1,tmob))
- if(slime.Victim == tmob)
- slime.UpdateFeed()
return
if(!can_move_mob(tmob, 0, 0))
@@ -571,7 +568,8 @@ default behaviour is:
fire_stacks = 0
/mob/living/proc/rejuvenate()
- reagents.clear_reagents()
+ if(reagents)
+ reagents.clear_reagents()
// shut down various types of badness
setToxLoss(0)
@@ -642,8 +640,17 @@ default behaviour is:
return
/mob/living/Move(a, b, flag)
- if (buckled)
- return
+// if (buckled)
+// world << "[src].Move() failed; buckled."
+// return
+
+ if (buckled && buckled.loc != a) //not updating position
+ if (!buckled.anchored)
+ world << "[src].Move(); will return [buckled].Move ."
+ return buckled.Move(a, b)
+ else
+ world << "[src].Move() failed; buckled to anchored [buckled]."
+ return 0
if (restrained())
stop_pulling()
@@ -724,10 +731,6 @@ default behaviour is:
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)
return FALSE
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 80c0dbc505..dea3c82461 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -298,7 +298,8 @@ proc/get_radio_key_from_channel(var/channel)
//The 'post-say' static speech bubble
var/speech_bubble_test = say_test(message)
- var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
+ var/speech_type = speech_bubble_appearance()
+ var/image/speech_bubble = image('icons/mob/talk.dmi',src,"[speech_type][speech_bubble_test]")
spawn(30) qdel(speech_bubble)
//Main 'say' and 'whisper' message delivery
@@ -341,3 +342,6 @@ proc/get_radio_key_from_channel(var/channel)
/mob/living/proc/GetVoice()
return name
+
+/mob/proc/speech_bubble_appearance()
+ return "normal"
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index 7a107d1d0e..87c36b5ac4 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -76,11 +76,14 @@
/obj/item/weapon/disk,
/obj/item/weapon/circuitboard,
/obj/item/weapon/reagent_containers/glass,
- /obj/item/weapon/reagent_containers/food/snacks/monkeycube,
- /obj/item/xenoproduct/slime/core,
/obj/item/device/assembly/prox_sensor,
- /obj/item/device/healthanalyzer //to build medibots
-// /obj/item/slime_extract, ### Outdated
+ /obj/item/device/healthanalyzer, //to build medibots
+ /obj/item/slime_cube,
+ /obj/item/slime_crystal,
+ /obj/item/weapon/disposable_teleporter/slime,
+ /obj/item/slimepotion,
+ /obj/item/slime_extract,
+ /obj/item/weapon/reagent_containers/food/snacks/monkeycube,
)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index de9517fd0c..70bf0c7475 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -720,6 +720,8 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
src.modules += new /obj/item/weapon/storage/part_replacer(src)
src.modules += new /obj/item/weapon/shockpaddles/robot/jumper(src)
+ src.modules += new /obj/item/weapon/melee/baton/slime/robot(src)
+ src.modules += new /obj/item/weapon/gun/energy/taser/xeno/robot(src)
src.emag = new /obj/item/weapon/hand_tele(src)
var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000)
diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm
index 8b721bc24b..359ee492f2 100644
--- a/code/modules/mob/living/silicon/say.dm
+++ b/code/modules/mob/living/silicon/say.dm
@@ -14,6 +14,9 @@
message_mode = null
return radio.talk_into(src,message,message_mode,verb,speaking)
+/mob/living/silicon/speech_bubble_appearance()
+ return "synthetic"
+
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
..()
if(message_mode == "department")
diff --git a/code/modules/mob/living/simple_animal/aliens/alien.dm b/code/modules/mob/living/simple_animal/aliens/alien.dm
index 7748559017..52f9121855 100644
--- a/code/modules/mob/living/simple_animal/aliens/alien.dm
+++ b/code/modules/mob/living/simple_animal/aliens/alien.dm
@@ -8,6 +8,7 @@
icon_gib = "syndicate_gib"
faction = "xeno"
+ intelligence_level = SA_HUMANOID
cooperative = 1
run_at_them = 0
diff --git a/code/modules/mob/living/simple_animal/aliens/creature.dm b/code/modules/mob/living/simple_animal/aliens/creature.dm
index 544a44d001..3de6d687af 100644
--- a/code/modules/mob/living/simple_animal/aliens/creature.dm
+++ b/code/modules/mob/living/simple_animal/aliens/creature.dm
@@ -7,6 +7,7 @@
icon_dead = "otherthing-dead"
faction = "creature"
+ intelligence_level = SA_ANIMAL
maxHealth = 40
health = 40
speed = 8
diff --git a/code/modules/mob/living/simple_animal/aliens/drone.dm b/code/modules/mob/living/simple_animal/aliens/drone.dm
index 3c550e862f..2a41e81667 100644
--- a/code/modules/mob/living/simple_animal/aliens/drone.dm
+++ b/code/modules/mob/living/simple_animal/aliens/drone.dm
@@ -8,6 +8,7 @@
icon_dead = "drone_dead"
faction = "malf_drone"
+ intelligence_level = SA_ROBOTIC
maxHealth = 300
health = 300
speed = 8
diff --git a/code/modules/mob/living/simple_animal/aliens/faithless.dm b/code/modules/mob/living/simple_animal/aliens/faithless.dm
index 0b41471c32..24eacae40e 100644
--- a/code/modules/mob/living/simple_animal/aliens/faithless.dm
+++ b/code/modules/mob/living/simple_animal/aliens/faithless.dm
@@ -6,6 +6,7 @@
icon_dead = "faithless_dead"
faction = "faithless"
+ intelligence_level = SA_HUMANOID
maxHealth = 50
health = 50
speed = 8
@@ -14,7 +15,7 @@
response_help = "passes through"
response_disarm = "shoves"
response_harm = "hits"
-
+
harm_intent_damage = 10
melee_damage_lower = 5
melee_damage_upper = 5
diff --git a/code/modules/mob/living/simple_animal/aliens/hivebot.dm b/code/modules/mob/living/simple_animal/aliens/hivebot.dm
index 6b15830b9a..d3193adfb6 100644
--- a/code/modules/mob/living/simple_animal/aliens/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/aliens/hivebot.dm
@@ -7,6 +7,7 @@
icon_dead = "basic"
faction = "hivebot"
+ intelligence_level = SA_ROBOTIC
maxHealth = 15
health = 15
speed = 4
diff --git a/code/modules/mob/living/simple_animal/aliens/mimic.dm b/code/modules/mob/living/simple_animal/aliens/mimic.dm
index 3373760bf8..b79b524875 100644
--- a/code/modules/mob/living/simple_animal/aliens/mimic.dm
+++ b/code/modules/mob/living/simple_animal/aliens/mimic.dm
@@ -10,6 +10,7 @@
icon_living = "crate"
faction = "mimic"
+ intelligence_level = SA_ANIMAL
maxHealth = 250
health = 250
diff --git a/code/modules/mob/living/simple_animal/aliens/shade.dm b/code/modules/mob/living/simple_animal/aliens/shade.dm
index f1b227436e..2d502bc10a 100644
--- a/code/modules/mob/living/simple_animal/aliens/shade.dm
+++ b/code/modules/mob/living/simple_animal/aliens/shade.dm
@@ -8,6 +8,7 @@
icon_dead = "shade_dead"
faction = "cult"
+ intelligence_level = SA_HUMANOID
maxHealth = 50
health = 50
diff --git a/code/modules/mob/living/simple_animal/animals/bat.dm b/code/modules/mob/living/simple_animal/animals/bat.dm
index 1d722c0b8a..a429b2ca7f 100644
--- a/code/modules/mob/living/simple_animal/animals/bat.dm
+++ b/code/modules/mob/living/simple_animal/animals/bat.dm
@@ -8,6 +8,7 @@
icon_gib = "bat_dead"
faction = "scarybat"
+ intelligence_level = SA_ANIMAL
maxHealth = 20
health = 20
diff --git a/code/modules/mob/living/simple_animal/animals/bear.dm b/code/modules/mob/living/simple_animal/animals/bear.dm
index 228e92e5b7..ea8398afc2 100644
--- a/code/modules/mob/living/simple_animal/animals/bear.dm
+++ b/code/modules/mob/living/simple_animal/animals/bear.dm
@@ -8,6 +8,7 @@
icon_gib = "bear_gib"
faction = "russian"
+ intelligence_level = SA_ANIMAL
cooperative = 1
maxHealth = 60
diff --git a/code/modules/mob/living/simple_animal/animals/carp.dm b/code/modules/mob/living/simple_animal/animals/carp.dm
index b8813c8a61..ff626e5eab 100644
--- a/code/modules/mob/living/simple_animal/animals/carp.dm
+++ b/code/modules/mob/living/simple_animal/animals/carp.dm
@@ -7,6 +7,7 @@
icon_gib = "carp_gib"
faction = "carp"
+ intelligence_level = SA_ANIMAL
maxHealth = 25
health = 25
speed = 4
diff --git a/code/modules/mob/living/simple_animal/animals/cat.dm b/code/modules/mob/living/simple_animal/animals/cat.dm
index 9b3df51247..b1c1cefb5f 100644
--- a/code/modules/mob/living/simple_animal/animals/cat.dm
+++ b/code/modules/mob/living/simple_animal/animals/cat.dm
@@ -2,6 +2,7 @@
/mob/living/simple_animal/cat
name = "cat"
desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers."
+ intelligence_level = SA_ANIMAL
icon_state = "cat2"
item_state = "cat2"
icon_living = "cat2"
diff --git a/code/modules/mob/living/simple_animal/animals/corgi.dm b/code/modules/mob/living/simple_animal/animals/corgi.dm
index 1823c5a91e..4be02a9b0b 100644
--- a/code/modules/mob/living/simple_animal/animals/corgi.dm
+++ b/code/modules/mob/living/simple_animal/animals/corgi.dm
@@ -3,6 +3,7 @@
name = "\improper corgi"
real_name = "corgi"
desc = "It's a corgi."
+ intelligence_level = SA_ANIMAL
icon_state = "corgi"
icon_living = "corgi"
icon_dead = "corgi_dead"
diff --git a/code/modules/mob/living/simple_animal/animals/crab.dm b/code/modules/mob/living/simple_animal/animals/crab.dm
index acb95ac64c..acad7f6378 100644
--- a/code/modules/mob/living/simple_animal/animals/crab.dm
+++ b/code/modules/mob/living/simple_animal/animals/crab.dm
@@ -5,6 +5,7 @@
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
+ intelligence_level = SA_ANIMAL
wander = 0
stop_automated_movement = 1
diff --git a/code/modules/mob/living/simple_animal/animals/farm_animals.dm b/code/modules/mob/living/simple_animal/animals/farm_animals.dm
index adc4fe83bf..2fe58dc76f 100644
--- a/code/modules/mob/living/simple_animal/animals/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/animals/farm_animals.dm
@@ -7,6 +7,7 @@
icon_dead = "goat_dead"
faction = "goat"
+ intelligence_level = SA_ANIMAL
health = 40
turns_per_move = 5
@@ -88,6 +89,7 @@
icon_living = "cow"
icon_dead = "cow_dead"
icon_gib = "cow_gib"
+ intelligence_level = SA_ANIMAL
health = 50
turns_per_move = 5
@@ -155,6 +157,7 @@
icon_living = "chick"
icon_dead = "chick_dead"
icon_gib = "chick_gib"
+ intelligence_level = SA_ANIMAL
health = 1
turns_per_move = 2
@@ -203,6 +206,7 @@ var/global/chicken_count = 0
icon_state = "chicken"
icon_living = "chicken"
icon_dead = "chicken_dead"
+ intelligence_level = SA_ANIMAL
health = 10
turns_per_move = 3
diff --git a/code/modules/mob/living/simple_animal/animals/fish.dm b/code/modules/mob/living/simple_animal/animals/fish.dm
index b2778d3c33..dbbd12a9a3 100644
--- a/code/modules/mob/living/simple_animal/animals/fish.dm
+++ b/code/modules/mob/living/simple_animal/animals/fish.dm
@@ -4,6 +4,7 @@
desc = "Its a fishy. No touchy fishy."
icon = 'icons/mob/fish.dmi'
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+ intelligence_level = SA_ANIMAL
// By defautl they can be in any water turf. Subtypes might restrict to deep/shallow etc
var/global/list/suitable_turf_types = list(
diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider.dm b/code/modules/mob/living/simple_animal/animals/giant_spider.dm
index 5cb191726f..7359763e15 100644
--- a/code/modules/mob/living/simple_animal/animals/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/animals/giant_spider.dm
@@ -13,6 +13,7 @@
icon_dead = "guard_dead"
faction = "spiders"
+ intelligence_level = SA_ANIMAL
maxHealth = 200
health = 200
pass_flags = PASSTABLE
diff --git a/code/modules/mob/living/simple_animal/animals/goose.dm b/code/modules/mob/living/simple_animal/animals/goose.dm
index ded7c5214a..3b3e3bfa21 100644
--- a/code/modules/mob/living/simple_animal/animals/goose.dm
+++ b/code/modules/mob/living/simple_animal/animals/goose.dm
@@ -7,6 +7,7 @@
icon_gib = "generic_gib"
faction = "geese"
+ intelligence_level = SA_ANIMAL
maxHealth = 15
health = 15
diff --git a/code/modules/mob/living/simple_animal/animals/lizard.dm b/code/modules/mob/living/simple_animal/animals/lizard.dm
index 5c986d21bb..e9032a96ef 100644
--- a/code/modules/mob/living/simple_animal/animals/lizard.dm
+++ b/code/modules/mob/living/simple_animal/animals/lizard.dm
@@ -5,6 +5,7 @@
icon_state = "lizard"
icon_living = "lizard"
icon_dead = "lizard-dead"
+ intelligence_level = SA_ANIMAL
health = 5
maxHealth = 5
diff --git a/code/modules/mob/living/simple_animal/animals/mouse.dm b/code/modules/mob/living/simple_animal/animals/mouse.dm
index 68c54b3d38..4f0cbb9162 100644
--- a/code/modules/mob/living/simple_animal/animals/mouse.dm
+++ b/code/modules/mob/living/simple_animal/animals/mouse.dm
@@ -6,6 +6,7 @@
item_state = "mouse_gray"
icon_living = "mouse_gray"
icon_dead = "mouse_gray_dead"
+ intelligence_level = SA_ANIMAL
maxHealth = 5
health = 5
diff --git a/code/modules/mob/living/simple_animal/animals/parrot.dm b/code/modules/mob/living/simple_animal/animals/parrot.dm
index 73892b26a1..1e17212708 100644
--- a/code/modules/mob/living/simple_animal/animals/parrot.dm
+++ b/code/modules/mob/living/simple_animal/animals/parrot.dm
@@ -35,6 +35,7 @@
icon_state = "parrot_fly"
icon_living = "parrot_fly"
icon_dead = "parrot_dead"
+ intelligence_level = SA_ANIMAL
turns_per_move = 5
pass_flags = PASSTABLE
diff --git a/code/modules/mob/living/simple_animal/animals/penguin.dm b/code/modules/mob/living/simple_animal/animals/penguin.dm
index 90074edef5..09adf4ed41 100644
--- a/code/modules/mob/living/simple_animal/animals/penguin.dm
+++ b/code/modules/mob/living/simple_animal/animals/penguin.dm
@@ -5,6 +5,7 @@
icon_living = "penguin"
icon_dead = "penguin_dead"
icon_gib = "generic_gib"
+ intelligence_level = SA_ANIMAL
maxHealth = 20
health = 20
diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm
index 79e796d7ff..fbbebff081 100644
--- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm
+++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm
@@ -5,6 +5,7 @@
icon_state = "spiderbot-chassis"
icon_living = "spiderbot-chassis"
icon_dead = "spiderbot-smashed"
+ intelligence_level = SA_HUMANOID // Because its piloted by players.
health = 10
maxHealth = 10
diff --git a/code/modules/mob/living/simple_animal/animals/tomato.dm b/code/modules/mob/living/simple_animal/animals/tomato.dm
index ea133a8581..d1bffc6fe1 100644
--- a/code/modules/mob/living/simple_animal/animals/tomato.dm
+++ b/code/modules/mob/living/simple_animal/animals/tomato.dm
@@ -4,6 +4,7 @@
icon_state = "tomato"
icon_living = "tomato"
icon_dead = "tomato_dead"
+ intelligence_level = SA_PLANT
faction = "plants"
maxHealth = 15
diff --git a/code/modules/mob/living/simple_animal/animals/tree.dm b/code/modules/mob/living/simple_animal/animals/tree.dm
index bf97641248..7d31e46772 100644
--- a/code/modules/mob/living/simple_animal/animals/tree.dm
+++ b/code/modules/mob/living/simple_animal/animals/tree.dm
@@ -6,6 +6,7 @@
icon_living = "pine_1"
icon_dead = "pine_1"
icon_gib = "pine_1"
+ intelligence_level = SA_PLANT
faction = "carp" //Trees can be carp friends?
maxHealth = 250
diff --git a/code/modules/mob/living/simple_animal/animals/worm.dm b/code/modules/mob/living/simple_animal/animals/worm.dm
index dfb8a5a195..48ed6039c5 100644
--- a/code/modules/mob/living/simple_animal/animals/worm.dm
+++ b/code/modules/mob/living/simple_animal/animals/worm.dm
@@ -5,6 +5,7 @@
icon_state = "spaceworm"
icon_living = "spaceworm"
icon_dead = "spacewormdead"
+ intelligence_level = SA_ANIMAL
maxHealth = 30
diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm
index 7498c83a7a..e18a345066 100644
--- a/code/modules/mob/living/simple_animal/borer/borer.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer.dm
@@ -4,6 +4,7 @@
desc = "A small, quivering sluglike creature."
speak_emote = list("chirrups")
emote_hear = list("chirrups")
+ intelligence_level = SA_HUMANOID // Player controlled.
response_help = "pokes"
response_disarm = "prods"
response_harm = "stomps on"
diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm
index 0159e4ab5f..f386016c17 100644
--- a/code/modules/mob/living/simple_animal/constructs/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm
@@ -7,6 +7,7 @@
response_help = "thinks better of touching"
response_disarm = "flailed at"
response_harm = "punched"
+ intelligence_level = SA_HUMANOID // Player controlled.
icon_dead = "shade_dead"
speed = -1
a_intent = I_HURT
diff --git a/code/modules/mob/living/simple_animal/humanoids/clown.dm b/code/modules/mob/living/simple_animal/humanoids/clown.dm
index 5bf310b165..ee1341ff38 100644
--- a/code/modules/mob/living/simple_animal/humanoids/clown.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/clown.dm
@@ -5,6 +5,7 @@
icon_living = "clown"
icon_dead = "clown_dead"
icon_gib = "clown_gib"
+ intelligence_level = SA_HUMANOID
faction = "clown"
maxHealth = 75
diff --git a/code/modules/mob/living/simple_animal/humanoids/head.dm b/code/modules/mob/living/simple_animal/humanoids/head.dm
index f0e8b8abde..22460f0990 100644
--- a/code/modules/mob/living/simple_animal/humanoids/head.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/head.dm
@@ -5,6 +5,7 @@
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
+ intelligence_level = SA_ANIMAL
wander = 0
stop_automated_movement = 1
diff --git a/code/modules/mob/living/simple_animal/humanoids/kobold.dm b/code/modules/mob/living/simple_animal/humanoids/kobold.dm
index 8f3ce0d28c..7355fce470 100644
--- a/code/modules/mob/living/simple_animal/humanoids/kobold.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/kobold.dm
@@ -6,6 +6,7 @@
icon_state = "kobold_idle"
icon_living = "kobold_idle"
icon_dead = "kobold_dead"
+ intelligence_level = SA_HUMANOID
run_at_them = 0
cooperative = 1
diff --git a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm
index ae700d60b7..3cfafda91a 100644
--- a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm
@@ -5,6 +5,7 @@
icon_state = "darkgygax"
icon_living = "darkgygax"
icon_dead = "darkgygax-broken"
+ intelligence_level = SA_HUMANOID // Piloted by a human.
faction = "syndicate"
maxHealth = 300
diff --git a/code/modules/mob/living/simple_animal/humanoids/pirate.dm b/code/modules/mob/living/simple_animal/humanoids/pirate.dm
index 02d1a8eb72..f0c7c05ddc 100644
--- a/code/modules/mob/living/simple_animal/humanoids/pirate.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/pirate.dm
@@ -4,6 +4,7 @@
icon_state = "piratemelee"
icon_living = "piratemelee"
icon_dead = "piratemelee_dead"
+ intelligence_level = SA_HUMANOID
faction = "pirate"
maxHealth = 100
diff --git a/code/modules/mob/living/simple_animal/humanoids/russian.dm b/code/modules/mob/living/simple_animal/humanoids/russian.dm
index 96ff3a5177..1589fe2a7d 100644
--- a/code/modules/mob/living/simple_animal/humanoids/russian.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/russian.dm
@@ -5,6 +5,7 @@
icon_living = "russianmelee"
icon_dead = "russianmelee_dead"
icon_gib = "syndicate_gib"
+ intelligence_level = SA_HUMANOID
faction = "russian"
maxHealth = 100
diff --git a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm
index 6dbe2fcfa4..edc46025a9 100644
--- a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm
@@ -5,6 +5,7 @@
icon_living = "syndicate"
icon_dead = "syndicate_dead"
icon_gib = "syndicate_gib"
+ intelligence_level = SA_HUMANOID
faction = "syndicate"
maxHealth = 100
@@ -165,6 +166,7 @@
icon = 'icons/mob/critter.dmi'
icon_state = "viscerator_attack"
icon_living = "viscerator_attack"
+ intelligence_level = SA_ROBOTIC
faction = "syndicate"
maxHealth = 15
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 39f272a8e8..b915411544 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -17,11 +17,12 @@
var/show_stat_health = 1 // Does the percentage health show in the stat panel for the mob
var/ai_inactive = 0 // Set to 1 to turn off most AI actions
- //Mob icon settings
+ //Mob icon/appearance settings
var/icon_living = "" // The iconstate if we're alive, required
var/icon_dead = "" // The iconstate if we're dead, required
var/icon_gib = null // The iconstate for being gibbed, optional
var/icon_rest = null // The iconstate for resting, optional
+ var/image/modifier_overlay = null // Holds overlays from modifiers.
//Mob talking settings
universal_speak = 0 // Can all mobs in the entire universe understand this one?
@@ -59,6 +60,7 @@
var/list/loot_list = list() // The list of lootable objects to drop, with "/path = prob%" structure
var/recruitable = 0 // Mob can be bossed around
var/recruit_cmd_str = "Hey," // The thing you prefix commands with when bossing them around
+ var/intelligence_level = SA_ANIMAL// How 'smart' the mob is ICly, used to deliniate between animal, robot, and humanoid SAs.
//Mob environment settings
var/minbodytemp = 250 // Minimum "okay" temperature in kelvin
@@ -116,6 +118,7 @@
var/run_at_them = 1 // Don't use A* pathfinding, use walk_to
var/move_to_delay = 4 // Delay for the automated movement (deciseconds)
var/destroy_surroundings = 1 // Should I smash things to get to my target?
+ var/astar_adjacent_proc = /turf/proc/CardinalTurfsWithAccess // Proc to use when A* pathfinding. Default makes them bound to cardinals.
//Damage resistances
var/resistance = 0 // Damage reduction for all types
@@ -205,6 +208,7 @@
src.client.screen += src.client.void
ai_inactive = 1
handle_stance(STANCE_IDLE)
+ LoseTarget()
src.client << "Mob AI disabled while you are controlling the mob."
..()
@@ -241,11 +245,11 @@
/mob/living/simple_animal/update_icon()
..()
//Awake and normal
- if((stat == CONSCIOUS) && (!icon_rest || !resting))
+ if((stat == CONSCIOUS) && (!icon_rest || !resting || !incapacitated(INCAPACITATION_DISABLED) ))
icon_state = icon_living
//Resting or KO'd
- else if(((stat == UNCONSCIOUS) || resting) && icon_rest)
+ else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest)
icon_state = icon_rest
//Dead
@@ -256,6 +260,26 @@
else
icon_state = initial(icon_state)
+// If your simple mob's update_icon() call calls overlays.Cut(), this needs to be called after this, or manually apply modifier_overly to overlays.
+/mob/living/simple_animal/update_modifier_visuals()
+ var/image/effects = null
+ if(modifier_overlay)
+ overlays -= modifier_overlay
+ modifier_overlay.overlays.Cut()
+ effects = modifier_overlay
+ else
+ effects = new()
+
+ for(var/datum/modifier/M in modifiers)
+ if(M.mob_overlay_state)
+ var/image/I = image("icon" = 'icons/mob/modifier_effects.dmi', "icon_state" = M.mob_overlay_state)
+ I.appearance_flags = RESET_COLOR // So colored mobs don't affect the overlay.
+ effects.overlays += I
+
+ modifier_overlay = effects
+ overlays += modifier_overlay
+
+
/mob/living/simple_animal/Life()
..()
@@ -288,7 +312,7 @@
//Resisting out buckles
if(stance != STANCE_IDLE && incapacitated(INCAPACITATION_BUCKLED_PARTIALLY))
- resist()
+ handle_resist()
//Resisting out of closets
if(istype(loc,/obj/structure/closet))
@@ -300,6 +324,11 @@
return 1
+// Resists out of things.
+// Sometimes there are times you want SAs to be buckled to something, so override this for when that is needed.
+/mob/living/simple_animal/proc/handle_resist()
+ resist()
+
// Peforms the random walk wandering
/mob/living/simple_animal/proc/handle_wander_movement()
if(isturf(src.loc) && !resting && !buckled && canmove) //Physically capable of moving?
@@ -482,6 +511,8 @@
if(Proj.firer)
react_to_attack(Proj.firer)
+ Proj.on_hit(src)
+
return 0
// When someone clicks us with an empty hand
@@ -550,11 +581,9 @@
if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch))
harvest(user)
else
- if(!O.force)
- visible_message("[user] gently taps [src] with \the [O].")
- else
- O.attack(src, user, user.zone_sel.selecting)
- ai_log("attackby() I was weapon'd by: [user]",2)
+ O.attack(src, user, user.zone_sel.selecting)
+ ai_log("attackby() I was weapon'd by: [user]",2)
+ if(O.force)
react_to_attack(user)
/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone)
@@ -645,18 +674,58 @@
if(3.0)
adjustBruteLoss(30)
+// Don't understand why simple animals don't use the regular /mob/living health system.
/mob/living/simple_animal/adjustBruteLoss(damage)
+ if(damage > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ damage *= M.incoming_damage_percent
+ if(!isnull(M.incoming_brute_damage_percent))
+ damage *= M.incoming_brute_damage_percent
+ else if(damage < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ damage *= M.incoming_healing_percent
+
health = Clamp(health - damage, 0, getMaxHealth())
+ updatehealth()
/mob/living/simple_animal/adjustFireLoss(damage)
+ if(damage > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ damage *= M.incoming_damage_percent
+ if(!isnull(M.incoming_fire_damage_percent))
+ damage *= M.incoming_brute_damage_percent
+ else if(damage < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ damage *= M.incoming_healing_percent
+
health = Clamp(health - damage, 0, getMaxHealth())
+ updatehealth()
+
+/mob/living/simple_animal/adjustToxLoss(damage)
+ if(damage > 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_damage_percent))
+ damage *= M.incoming_damage_percent
+ if(!isnull(M.incoming_tox_damage_percent))
+ damage *= M.incoming_brute_damage_percent
+ else if(damage < 0)
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.incoming_healing_percent))
+ damage *= M.incoming_healing_percent
+
+ health = Clamp(health - damage, 0, getMaxHealth())
+ updatehealth()
// Check target_mob if worthy of attack (i.e. check if they are dead or empty mecha)
/mob/living/simple_animal/proc/SA_attackable(target_mob)
ai_log("SA_attackable([target_mob])",3)
if (isliving(target_mob))
var/mob/living/L = target_mob
- if(!L.stat)
+ if(L.stat != DEAD)
return 1
if (istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
@@ -777,6 +846,8 @@
continue
else if(!SA_attackable(L))
continue
+ else if(!special_target_check(L))
+ continue
else
T = L
break
@@ -785,6 +856,8 @@
var/obj/mecha/M = A
if(!SA_attackable(M))
continue
+ else if(!special_target_check(M))
+ continue
if((M.occupant.faction != src.faction) || attack_same)
T = M
break
@@ -801,6 +874,10 @@
/mob/living/simple_animal/proc/Found(var/atom/A)
return
+// Used for somewhat special targeting, but not to the extent of using Found()
+/mob/living/simple_animal/proc/special_target_check(var/atom/A)
+ return TRUE
+
//Requesting help from like-minded individuals
/mob/living/simple_animal/proc/RequestHelp()
if(!cooperative || ((world.time - last_helpask_time) < 10 SECONDS))
@@ -833,6 +910,12 @@
if(set_follow(F, 10 SECONDS))
handle_stance(STANCE_FOLLOW)
+// Can be used to conditionally do a ranged or melee attack.
+// Note that the SA must be able to do an attack at the specified range or else it may get trapped in a loop of switching
+// between STANCE_ATTACK and STANCE_ATTACKING, due to being told by MoveToTarget() that they're in range but being told by AttackTarget() that they're not.
+/mob/living/simple_animal/proc/ClosestDistance()
+ return ranged ? shoot_range - 1 : 1 // Shoot range -1 just because we don't want to constantly get kited
+
//Move to a target (or near if we're ranged)
/mob/living/simple_animal/proc/MoveToTarget()
if(incapacitated(INCAPACITATION_DISABLED))
@@ -857,9 +940,9 @@
ForgetPath()
//Find out where we're getting to
- var/get_to = ranged ? shoot_range-1 : 1 //Shoot range -1 just because we don't want to constantly get kited
+ var/get_to = ClosestDistance()
var/distance = get_dist(src,target_mob)
- ai_log("MoveToTarget() [src] [get_to] [distance]",2)
+ ai_log("MoveToTarget() [src] get_to: [get_to] distance: [distance]",2)
//We're here!
if(distance <= get_to)
@@ -919,6 +1002,7 @@
if(incapacitated(INCAPACITATION_DISABLED))
ai_log("FollowTarget() Bailing because we're disabled",2)
+ LoseFollow()
return
if((get_dist(src,follow_mob) <= follow_dist))
@@ -972,7 +1056,7 @@
/mob/living/simple_animal/proc/GetPath(var/turf/target,var/get_to = 1,var/max_distance = world.view*6)
ai_log("GetPath([target],[get_to],[max_distance])",2)
ForgetPath()
- var/list/new_path = AStar(get_turf(loc), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, min_target_dist = get_to, max_node_depth = max_distance, id = myid, exclude = obstacles)
+ var/list/new_path = AStar(get_turf(loc), target, astar_adjacent_proc, /turf/proc/Distance, min_target_dist = get_to, max_node_depth = max_distance, id = myid, exclude = obstacles)
if(new_path && new_path.len)
walk_list = new_path
@@ -1082,6 +1166,10 @@
//Get into attack mode on a target
/mob/living/simple_animal/proc/AttackTarget()
stop_automated_movement = 1
+ if(incapacitated(INCAPACITATION_DISABLED))
+ ai_log("AttackTarget() Bailing because we're disabled",2)
+ LoseTarget()
+ return 0
if(!target_mob || !SA_attackable(target_mob))
LoseTarget()
return 0
@@ -1111,6 +1199,7 @@
//They ran away!
else
ai_log("AttackTarget() out of range!",3)
+ sleep(1) // Unfortunately this is needed to protect from ClosestDistance() sometimes not updating fast enough to prevent an infinite loop.
handle_stance(STANCE_ATTACK)
return 0
@@ -1118,7 +1207,8 @@
/mob/living/simple_animal/proc/PunchTarget()
if(!Adjacent(target_mob))
return
- sleep(rand(8) + 8)
+ if(!client)
+ sleep(rand(8) + 8)
if(isliving(target_mob))
var/mob/living/L = target_mob
@@ -1129,39 +1219,51 @@
src.do_attack_animation(src)
return L
else
- L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ DoPunch(L)
return L
if(istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
- M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ DoPunch(M)
return M
+// This is the actual act of 'punching'. Override for special behaviour.
+/mob/living/simple_animal/proc/DoPunch(var/atom/A)
+ if(!Adjacent(target_mob)) // They could've moved in the meantime.
+ return
+ var/damage_to_do = rand(melee_damage_lower, melee_damage_upper)
+
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.outgoing_melee_damage_percent))
+ damage_to_do *= M.outgoing_melee_damage_percent
+
+ A.attack_generic(src, damage_to_do, attacktext)
+
//The actual top-level ranged attack proc
/mob/living/simple_animal/proc/ShootTarget()
var/target = target_mob
var/tturf = get_turf(target)
- if(firing_lines && !CheckFiringLine(tturf))
+ if((firing_lines && !client) && !CheckFiringLine(tturf))
step_rand(src)
face_atom(tturf)
return 0
- visible_message("[src] fires at [target]!", 1)
+ visible_message("[src] fires at [target]!")
if(rapid)
spawn(1)
- Shoot(tturf, src.loc, src)
+ Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(4)
- Shoot(tturf, src.loc, src)
+ Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
spawn(6)
- Shoot(tturf, src.loc, src)
+ Shoot(target, src.loc, src)
if(casingtype)
new casingtype(get_turf(src))
else
- Shoot(tturf, src.loc, src)
+ Shoot(target, src.loc, src)
if(casingtype)
new casingtype
@@ -1201,9 +1303,9 @@
playsound(user, projectilesound, 100, 1)
if(!A) return
- if (!istype(target, /turf))
- qdel(A)
- return
+// if (!istype(target, /turf))
+// qdel(A)
+// return
A.launch(target)
return
@@ -1226,6 +1328,43 @@
handle_stance(STANCE_IDLE)
GiveUpMoving()
+// Makes the simple mob stop everything. Useful for when it get stunned.
+/mob/living/simple_animal/proc/Disable()
+ ai_log("Disable() [target_mob]",2)
+ spawn(0)
+ LoseTarget()
+ LoseFollow()
+
+/mob/living/simple_animal/Stun(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
+/mob/living/simple_animal/AdjustStunned(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
+/mob/living/simple_animal/Weaken(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
+/mob/living/simple_animal/AdjustWeakened(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
+/mob/living/simple_animal/Paralyse(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
+/mob/living/simple_animal/AdjustParalysis(amount)
+ if(amount > 0)
+ Disable()
+ ..(amount)
+
//Find me some targets
/mob/living/simple_animal/proc/ListTargets(var/dist = view_range)
var/list/L = hearers(src, dist)
@@ -1244,22 +1383,32 @@
var/turf/problem_turf = get_step(src, direction)
ai_log("DestroySurroundings([direction])",3)
+ var/damage_to_do = rand(melee_damage_lower, melee_damage_upper)
+
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.outgoing_melee_damage_percent))
+ damage_to_do *= M.outgoing_melee_damage_percent
+
for(var/obj/structure/window/obstacle in problem_turf)
if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
ai_log("DestroySurroundings() directional window hit",3)
- obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ obstacle.attack_generic(src, damage_to_do, attacktext)
+ return
+ else if(obstacle.is_fulltile())
+ ai_log("DestroySurroundings() full tile window hit",3)
+ obstacle.attack_generic(src, damage_to_do, attacktext)
return
var/obj/structure/obstacle = locate(/obj/structure, problem_turf)
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
ai_log("DestroySurroundings() generic structure hit [obstacle]",3)
- obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ obstacle.attack_generic(src, damage_to_do ,attacktext)
return
for(var/obj/machinery/door/baddoor in problem_turf) //Required since firelocks take up the same turf
if(baddoor.density)
ai_log("DestroySurroundings() door hit [baddoor]",3)
- baddoor.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ baddoor.attack_generic(src, damage_to_do ,attacktext)
return
//Check for shuttle bumrush
diff --git a/code/modules/mob/living/simple_animal/slime/ai.dm b/code/modules/mob/living/simple_animal/slime/ai.dm
new file mode 100644
index 0000000000..2a61f91e31
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/ai.dm
@@ -0,0 +1,58 @@
+/mob/living/simple_animal/slime/FindTarget()
+ if(victim) // Don't worry about finding another target if we're eatting someone.
+ return
+// if(!will_hunt())
+// return
+ ..()
+
+/mob/living/simple_animal/slime/special_target_check(mob/living/L)
+ if(istype(L, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/buddy = L
+ if(buddy.slime_color == src.slime_color || discipline || unity || buddy.unity)
+ return FALSE // Don't hurt same colored slimes.
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.species && H.species.name == "Promethean")
+ return FALSE // Prometheans are always our friends.
+ else if(istype(H.species, /datum/species/monkey)) // istype() is so they'll eat the alien monkeys too.
+ return TRUE // Monkeys are always food.
+ if(discipline && !rabid)
+ return FALSE // We're a good slime. For now at least
+
+ if(issilicon(L) || isbot(L) )
+ if(discipline && !rabid)
+ return FALSE // We're a good slime. For now at least.
+ return ..() // Other colors and nonslimes are jerks however.
+
+/mob/living/simple_animal/slime/ClosestDistance()
+ if(target_mob.stat == DEAD)
+ return 1 // Melee (eat) the target if dead, don't shoot it.
+ return ..()
+
+/mob/living/simple_animal/slime/HelpRequested(var/mob/living/simple_animal/slime/buddy)
+ if(istype(buddy))
+ if(buddy.slime_color != src.slime_color && (!unity || !buddy.unity)) // We only help slimes of the same color, if it's another slime calling for help.
+ ai_log("HelpRequested() by [buddy] but they are a [buddy.slime_color] while we are a [src.slime_color].",2)
+ return
+ if(buddy.target_mob)
+ if(!special_target_check(buddy.target_mob))
+ ai_log("HelpRequested() by [buddy] but special_target_check() failed when passed [buddy.target_mob].",2)
+ return
+ ..()
+
+
+/mob/living/simple_animal/slime/handle_resist()
+ if(buckled && victim && isliving(buckled) && victim == buckled) // If it's buckled to a living thing it's probably eating it.
+ return
+ else
+ ..()
+
+/*
+/mob/living/simple_animal/slime/proc/will_hunt() // Check for being stopped from feeding and chasing
+ if(nutrition <= get_starve_nutrition() || rabid)
+ return TRUE
+ if(nutrition <= get_hunger_nutrition() || prob(25))
+ return TRUE
+ return FALSE
+*/
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/slime/combat.dm b/code/modules/mob/living/simple_animal/slime/combat.dm
new file mode 100644
index 0000000000..eb77f338c2
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/combat.dm
@@ -0,0 +1,276 @@
+
+
+/*
+// Check target_mob if worthy of attack
+/mob/living/simple_animal/slime/SA_attackable(target_mob)
+ ai_log("SA_attackable([target_mob])",3)
+ if(isliving(target_mob))
+ var/mob/living/L = target_mob
+ if(L.stat == DEAD)
+ if(can_consume(L)) // If we can eat them, then it doesn't matter if they're dead.
+ return TRUE
+ ..()
+*/
+
+/mob/living/simple_animal/slime/PunchTarget()
+ if(victim)
+ return // Already eatting someone.
+ if(!client) // AI controlled.
+ if( (!target_mob.lying && prob(60 + (power_charge * 4) ) || (!target_mob.lying && optimal_combat) )) // "Smart" slimes always stun first.
+ a_intent = I_DISARM // Stun them first.
+ else if(can_consume(target_mob) && target_mob.lying)
+ a_intent = I_GRAB // Then eat them.
+ else
+ a_intent = I_HURT // Otherwise robust them.
+ ai_log("PunchTarget() will [a_intent] [target_mob]",2)
+ ..()
+
+/mob/living/simple_animal/slime/proc/can_consume(var/mob/living/L)
+ if(!L || !istype(L))
+ to_chat(src, "This subject is incomparable...")
+ return FALSE
+ if(L.isSynthetic())
+ to_chat(src, "This subject is not biological...")
+ return FALSE
+ if(L.getarmor(null, "bio") >= 80)
+ to_chat(src, "I cannot reach this subject's biological matter...")
+ return FALSE
+ if(istype(L, /mob/living/simple_animal/slime))
+ to_chat(src, "I cannot feed on other slimes...")
+ return FALSE
+ if(!Adjacent(L))
+ to_chat(src, "This subject is too far away...")
+ return FALSE
+ if(istype(L, /mob/living/carbon) && L.getCloneLoss() >= L.getMaxHealth() * 1.5 || istype(L, /mob/living/simple_animal) && L.stat == DEAD)
+ to_chat(src, "This subject does not have an edible life energy...")
+ return FALSE
+ if(L.buckled_mob)
+ if(istype(L.buckled_mob, /mob/living/simple_animal/slime))
+ if(L.buckled_mob != src)
+ to_chat(src, "\The [L.buckled_mob] is already feeding on this subject...")
+ return FALSE
+ return TRUE
+
+/mob/living/simple_animal/slime/proc/start_consuming(var/mob/living/L)
+ if(!can_consume(L))
+ return
+ if(!Adjacent(L))
+ return
+ step_towards(src, L) // Get on top of them to feed.
+ if(loc != L.loc)
+ return
+ if(L.buckle_mob(src, forced = TRUE))
+ victim = L
+ update_icon()
+ victim.visible_message("\The [src] latches onto [victim]!",
+ "\The [src] latches onto you!")
+
+/mob/living/simple_animal/slime/proc/stop_consumption()
+ if(!victim)
+ return
+ victim.unbuckle_mob()
+ victim.visible_message("\The [src] slides off of [victim]!",
+ "\The [src] slides off of you!")
+ victim = null
+ update_icon()
+
+
+/mob/living/simple_animal/slime/proc/handle_consumption()
+ if(victim && can_consume(victim) && !stat)
+
+ var/armor_modifier = abs((victim.getarmor(null, "bio") / 100) - 1)
+ if(istype(victim, /mob/living/carbon))
+ victim.adjustCloneLoss(rand(5,6) * armor_modifier)
+ victim.adjustToxLoss(rand(1,2) * armor_modifier)
+ if(victim.health <= 0)
+ victim.adjustToxLoss(rand(2,4) * armor_modifier)
+
+ else if(istype(victim, /mob/living/simple_animal))
+ victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
+
+ 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")]...")
+ stop_consumption()
+
+ adjust_nutrition(50 * armor_modifier)
+
+ adjustOxyLoss(-10 * armor_modifier) //Heal yourself
+ adjustBruteLoss(-10 * armor_modifier)
+ adjustFireLoss(-10 * armor_modifier)
+ adjustCloneLoss(-10 * armor_modifier)
+ updatehealth()
+ if(victim)
+ victim.updatehealth()
+ else
+ stop_consumption()
+
+/mob/living/simple_animal/slime/DoPunch(var/mob/living/L)
+ if(!Adjacent(L)) // Might've moved away in the meantime.
+ return
+
+ if(istype(L))
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ // Slime attacks can be blocked with shields.
+ if(H.check_shields(damage = 0, damage_source = null, attacker = src, def_zone = null, attack_text = "the attack"))
+ return
+
+ switch(a_intent)
+ if(I_HELP)
+ ai_log("DoPunch() against [L], helping.",2)
+ L.visible_message("[src] gently pokes [L]!",
+ "[src] gently pokes you!")
+ do_attack_animation(L)
+ post_attack(L, a_intent)
+
+ if(I_DISARM)
+ ai_log("DoPunch() against [L], disarming.",2)
+ var/stun_power = between(0, power_charge + rand(0, 3), 10)
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ stun_power *= max(H.species.siemens_coefficient,0)
+
+
+ if(prob(stun_power * 10))
+ power_charge = max(0, power_charge - 3)
+ L.visible_message("[src] has shocked [L]!", "[src] has shocked you!")
+ playsound(src, 'sound/weapons/Egloves.ogg', 75, 1)
+ L.Weaken(4)
+ L.Stun(4)
+ do_attack_animation(L)
+ if(L.buckled)
+ L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents slimes from jumping on you.
+ L.stuttering = max(L.stuttering, stun_power)
+
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, L)
+ s.start()
+
+ if(prob(stun_power * 10) && stun_power >= 8)
+ L.adjustFireLoss(power_charge * rand(1, 2))
+ post_attack(L, a_intent)
+
+ else if(prob(40))
+ L.visible_message("[src] has pounced at [L]!", "[src] has pounced at you!")
+ playsound(src, 'sound/weapons/thudswoosh.ogg', 75, 1)
+ L.Weaken(2)
+ do_attack_animation(L)
+ if(L.buckled)
+ L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents slimes from jumping on you.
+ post_attack(L, a_intent)
+ else
+ L.visible_message("[src] has tried to pounce at [L]!", "[src] has tried to pounce at you!")
+ playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1)
+ do_attack_animation(L)
+ L.updatehealth()
+ return L
+
+ if(I_GRAB)
+ ai_log("DoPunch() against [L], grabbing.",2)
+ start_consuming(L)
+ post_attack(L, a_intent)
+
+ if(I_HURT)
+ ai_log("DoPunch() against [L], hurting.",2)
+ var/damage_to_do = rand(melee_damage_lower, melee_damage_upper)
+ var/armor_modifier = abs((L.getarmor(null, "bio") / 100) - 1)
+
+ L.attack_generic(src, damage_to_do, attacktext)
+ playsound(src, 'sound/weapons/bite.ogg', 75, 1)
+
+ // Give the slime some nutrition, if applicable.
+ if(!L.isSynthetic())
+ if(ishuman(L))
+ if(L.getCloneLoss() < L.getMaxHealth() * 1.5)
+ adjust_nutrition(damage_to_do * armor_modifier)
+
+ else if(istype(L, /mob/living/simple_animal))
+ if(!isslime(L))
+ var/mob/living/simple_animal/SA = L
+ if(!SA.stat)
+ adjust_nutrition(damage_to_do)
+
+ post_attack(L, a_intent)
+
+ if(istype(L,/obj/mecha))
+ var/obj/mecha/M = L
+ M.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext)
+
+/mob/living/simple_animal/slime/proc/post_attack(var/mob/living/L, var/intent = I_HURT)
+ if(intent != I_HELP)
+ if(L.reagents && L.can_inject() && reagent_injected)
+ L.reagents.add_reagent(reagent_injected, injection_amount)
+
+/mob/living/simple_animal/slime/attackby(obj/item/W, mob/user)
+ if(istype(W, /obj/item/clothing/head)) // Handle hat simulator.
+ give_hat(W, user)
+ return
+
+ // Otherwise they're probably fighting the slime.
+ if(prob(25))
+ visible_message("\The [user]'s [W] passes right through [src]!")
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ return
+ ..()
+
+/mob/living/simple_animal/slime/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone)
+ ..()
+ if(!stat)
+ if(O.force > 0 && discipline && !rabid) // wow, buddy, why am I getting attacked??
+ adjust_discipline(1)
+ return
+ if(O.force >= 3)
+ if(victim || target_mob) // We've been a bad slime.
+ if(is_adult)
+ if(prob(5 + round(O.force / 2)) )
+ if(prob(80) && !client)
+ adjust_discipline(2)
+ if(user)
+ step_away(src, user)
+ else
+ if(prob(10 + O.force * 2))
+ if(prob(80) && !client)
+ adjust_discipline(2)
+ if(user)
+ step_away(src, user)
+ else
+ if(user in friends) // Friend attacking us for no reason.
+ if(prob(25))
+ friends -= user
+ say("[user]... not friend...")
+
+/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M as mob)
+ if(victim) // Are we eating someone?
+ var/fail_odds = 30
+ if(victim == M) // Harder to get the slime off if its eating you right now.
+ fail_odds = 60
+
+ if(prob(fail_odds))
+ 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(40) && !client)
+ adjust_discipline(1)
+ stop_consumption()
+ step_away(src,M)
+ else
+ if(M.a_intent == I_HELP)
+ if(hat)
+ remove_hat(M)
+ else
+ ..()
+ else
+ ..()
+
+// Shocked grilles don't hurt slimes, and in fact give them charge.
+/mob/living/simple_animal/slime/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null)
+ power_charge = between(0, power_charge + round(shock_damage / 10), 10)
+ to_chat(src, "\The [source] shocks you, and it charges you.")
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 0000000000..01500db42e
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/death.dm
@@ -0,0 +1,24 @@
+/mob/living/simple_animal/slime/death(gibbed)
+
+ if(stat == DEAD)
+ return
+
+ if(!gibbed && is_adult)
+ var/mob/living/simple_animal/slime/S = make_new_slime()
+ S.rabid = TRUE
+ step_away(S, src)
+ is_adult = FALSE
+ maxHealth = initial(maxHealth)
+ revive()
+ if(!client)
+ rabid = TRUE
+ number = rand(1, 1000)
+ update_name()
+ return
+
+ stop_consumption()
+ . = ..(gibbed, "stops moving and partially dissolves...")
+
+ update_icon()
+
+ return
\ 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 0000000000..30c2dba554
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -0,0 +1,174 @@
+/mob/living/simple_animal/slime/proc/adjust_nutrition(input)
+ nutrition = between(0, nutrition + input, get_max_nutrition())
+
+ if(input > 0)
+ if(prob(input * 2)) // Gain around one level per 50 nutrition
+ power_charge = min(power_charge++, 10)
+ if(power_charge == 10)
+ adjustToxLoss(-10)
+
+
+/mob/living/simple_animal/slime/proc/get_max_nutrition() // Can't go above it
+ if(is_adult)
+ return 1200
+ 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
+ return 800
+
+/mob/living/simple_animal/slime/proc/get_hunger_nutrition() // Below it we will always eat
+ if(is_adult)
+ return 600
+ return 500
+
+/mob/living/simple_animal/slime/proc/get_starve_nutrition() // Below it we will eat before everything else
+ if(is_adult)
+ return 300
+ return 200
+
+/mob/living/simple_animal/slime/proc/handle_nutrition()
+ if(docile)
+ return
+ if(prob(15))
+ adjust_nutrition(-1 - is_adult)
+
+ if(nutrition <= get_starve_nutrition())
+ handle_starvation()
+
+ else if(nutrition >= get_grow_nutrition() && amount_grown < 10)
+ adjust_nutrition(-20)
+ amount_grown = between(0, amount_grown + 1, 10)
+
+/mob/living/simple_animal/slime/proc/handle_starvation()
+ if(nutrition < get_starve_nutrition() && !client) // if a slime is starving, it starts losing its friends
+ if(friends.len && prob(1))
+ var/mob/nofriend = pick(friends)
+ if(nofriend)
+ friends -= nofriend
+ say("[nofriend]... food now...")
+
+ if(nutrition <= 0)
+ adjustToxLoss(rand(1,3))
+ if(client && prob(5))
+ to_chat(src, "You are starving!")
+
+/mob/living/simple_animal/slime/proc/handle_discipline()
+ if(discipline > 0)
+ update_mood()
+ // if(discipline >= 5 && rabid)
+ // if(prob(60))
+ // rabid = 0
+ // adjust_discipline(1) // So it stops trying to murder everyone.
+
+ // Handle discipline decay.
+ if(!prob(75 + (obedience * 5)))
+ adjust_discipline(-1)
+ if(!discipline)
+ update_mood()
+
+/mob/living/simple_animal/slime/handle_regular_status_updates()
+ if(stat != DEAD)
+ handle_nutrition()
+
+ handle_discipline()
+
+ if(prob(30))
+ adjustOxyLoss(-1)
+ adjustToxLoss(-1)
+ adjustFireLoss(-1)
+ adjustCloneLoss(-1)
+ adjustBruteLoss(-1)
+
+ if(victim)
+ handle_consumption()
+
+ if(amount_grown >= 10 && !target_mob && !client)
+ if(is_adult)
+ reproduce()
+ else
+ evolve()
+
+ handle_stuttering()
+
+ ..()
+
+
+// This is to make slime responses feel a bit more natural and not instant.
+/mob/living/simple_animal/slime/proc/delayed_say(var/message, var/mob/target)
+ sleep(rand(1 SECOND, 2 SECONDS))
+ if(target)
+ face_atom(target)
+ say(message)
+
+//Commands, reactions, etc
+/mob/living/simple_animal/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
+ ..()
+ if((findtext(message, num2text(number)) || findtext(message, name) || findtext(message, "slimes"))) // Talking to us
+
+ // Say hello back.
+ if(findtext(message, "hello") || findtext(message, "hi") || findtext(message, "greetings"))
+ delayed_say(pick("Hello...", "Hi..."), speaker)
+
+ // Follow request.
+ if(findtext(message, "follow") || findtext(message, "come with me"))
+ if(!can_command(speaker))
+ delayed_say(pick("No...", "I won't follow..."), speaker)
+ return
+
+ delayed_say("Yes... I follow \the [speaker]...", speaker)
+ set_follow(speaker)
+ FollowTarget()
+
+ // Stop request.
+ if(findtext(message, "stop") || findtext(message, "halt") || findtext(message, "cease"))
+ if(victim) // We're being asked to stop eatting someone.
+ if(!can_command(speaker))
+ delayed_say("No...", speaker)
+ return
+ else
+ delayed_say("Fine...", speaker)
+ stop_consumption()
+ adjust_discipline(1, TRUE)
+
+ if(target_mob) // We're being asked to stop chasing someone.
+ if(!can_command(speaker))
+ delayed_say("No...", speaker)
+ return
+ else
+ delayed_say("Fine...", speaker)
+ LoseTarget()
+ adjust_discipline(1, TRUE)
+
+ if(follow_mob) // We're being asked to stop following someone.
+ if(follow_mob == speaker)
+ delayed_say("Yes... I'll stop...", speaker)
+ LoseFollow()
+ else
+ delayed_say("No... I'll keep following \the [follow_mob]...", speaker)
+
+ // Help request
+ if(findtext(message, "help"))
+ if(!can_command(speaker))
+ delayed_say("No...", speaker)
+ return
+ else
+ delayed_say("I will protect \the [speaker].", speaker)
+
+ // Murder request
+ if(findtext(message, "harm") || findtext(message, "kill") || findtext(message, "murder") || findtext(message, "eat") || findtext(message, "consume"))
+ if(!can_command(speaker))
+ delayed_say("No...", speaker)
+ return
+
+ //LoseFollow()
+
+ /*
+ if(reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language))
+ var/mob/living/L = speaker
+ if(L.faction == faction)
+ spawn(10)
+ face_atom(speaker)
+ say(reactions[message])
+ */
\ No newline at end of file
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 0000000000..bc91e44884
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -0,0 +1,433 @@
+/mob/living/simple_animal/slime
+ name = "baby slime"
+ desc = "The most basic of slimes. The grey slime has no remarkable qualities, however it remains one of the most useful colors for scientists."
+ icon = 'icons/mob/slime2.dmi'
+ icon_state = "grey baby slime"
+ intelligence_level = SA_ANIMAL
+ pass_flags = PASSTABLE
+ var/shiny = FALSE // If true, will add a 'shiny' overlay.
+ var/glows = FALSE // If true, will glow in the same color as the color var.
+ var/icon_state_override = null // Used for special slime appearances like the rainbow slime.
+ pass_flags = PASSTABLE
+
+ speak_emote = list("chirps")
+
+ maxHealth = 150
+ var/maxHealth_adult = 200
+ melee_damage_lower = 5
+ melee_damage_upper = 25
+ melee_miss_chance = 0
+ gender = NEUTER
+
+ // Atmos stuff.
+ minbodytemp = T0C-30
+ heat_damage_per_tick = 0
+ cold_damage_per_tick = 40
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ unsuitable_atoms_damage = 0
+
+
+ speak = list(
+ "Blorp...",
+ "Blop..."
+
+ )
+ emote_hear = list(
+
+ )
+ emote_see = list(
+ "bounces",
+ "jiggles",
+ "sways"
+ )
+
+ hostile = 1
+ retaliate = 1
+ attack_same = 1
+ cooperative = 1
+ faction = "slime" // Slimes will help other slimes, provided they share the same color.
+
+ color = "#CACACA"
+ var/is_adult = FALSE
+ var/cores = 1 // How many cores you get when placed in a Processor.
+ var/power_charge = 0 // 0-10 controls how much electricity they are generating. High numbers encourage the slime to stun someone with electricity.
+ var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
+ var/number = 0 // This is used to make the slime semi-unique for indentification.
+
+ var/mob/living/victim = null // the person the slime is currently feeding on
+ var/rabid = FALSE // If true, will attack anyone and everyone.
+ var/docile = FALSE // Basically the opposite of above. If true, will never harm anything and won't get hungry.
+ var/discipline = 0 // Beating slimes makes them less likely to lash out. In theory.
+ var/resentment = 0 // 'Unjustified' beatings make this go up, and makes it more likely for abused slimes to go berserk.
+ var/obedience = 0 // Conversely, 'justified' beatings make this go up, and makes discipline decay slowly, potentially making it not decay at all.
+ var/unity = FALSE // If true, slimes will consider other colors as their own. Other slimes will see this slime as the same color as well. A rainbow slime is required to get this.
+ var/optimal_combat = FALSE // Used to dumb down the combat AI somewhat. If true, the slime tends to be really dangerous to fight alone due to stunlocking.
+ var/mood = ":3" // Icon to use to display 'mood'.
+ var/obj/item/clothing/head/hat = null // The hat the slime may be wearing.
+
+ var/slime_color = "grey"
+ var/mutation_chance = 25 // Odds of spawning as a new color when reproducing. Can be modified by certain xenobio products. Carried across generations of slimes.
+ var/coretype = /obj/item/slime_extract/grey
+ // List of potential slime color mutations. This must have exactly four types.
+ var/list/slime_mutation = list(
+ /mob/living/simple_animal/slime/orange,
+ /mob/living/simple_animal/slime/metal,
+ /mob/living/simple_animal/slime/blue,
+ /mob/living/simple_animal/slime/purple
+ )
+
+ var/reagent_injected = null // Some slimes inject reagents on attack. This tells the game what reagent to use.
+ var/injection_amount = 5 // This determines how much.
+
+/mob/living/simple_animal/slime/New(var/location, var/start_as_adult = FALSE)
+ verbs += /mob/living/proc/ventcrawl
+ if(start_as_adult)
+ make_adult()
+ health = maxHealth
+// slime_mutation = mutation_table(slime_color)
+ update_icon()
+ number = rand(1, 1000)
+ update_name()
+ ..(location)
+
+/mob/living/simple_animal/slime/Destroy()
+ if(hat)
+ drop_hat()
+ return ..()
+
+/mob/living/simple_animal/slime/proc/make_adult()
+ if(is_adult)
+ return
+
+ is_adult = TRUE
+ melee_damage_lower = 20
+ melee_damage_upper = 40
+ maxHealth = maxHealth_adult
+ amount_grown = 0
+ update_icon()
+ update_name()
+
+/mob/living/simple_animal/slime/proc/update_name()
+ if(docile) // Docile slimes are generally named, so we shouldn't mess with it.
+ return
+ name = "[slime_color] [is_adult ? "adult" : "baby"] slime ([number])"
+ real_name = name
+
+/mob/living/simple_animal/slime/update_icon()
+ if(stat == DEAD)
+ icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead"
+ set_light(0)
+ else
+ if(incapacitated(INCAPACITATION_DISABLED))
+ icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead"
+ else
+ icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"][victim ? " eating":""]"
+
+ overlays.Cut()
+ if(stat != DEAD)
+ var/image/I = image(icon, src, "slime light")
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ if(shiny)
+ I = image(icon, src, "slime shiny")
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ I = image(icon, src, "aslime-[mood]")
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ if(glows)
+ set_light(3, 2, color)
+
+ if(hat)
+ var/hat_state = hat.item_state ? hat.item_state : hat.icon_state
+ var/image/I = image('icons/mob/head.dmi', src, hat_state)
+ I.pixel_y = -7 // Slimes are small.
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ if(modifier_overlay) // Restore our modifier overlay.
+ overlays += modifier_overlay
+
+/mob/living/simple_animal/slime/proc/update_mood()
+ var/old_mood = mood
+ if(incapacitated(INCAPACITATION_DISABLED))
+ mood = "sad"
+ else if(rabid)
+ mood = "angry"
+ else if(target_mob)
+ mood = "mischevous"
+ else if(discipline)
+ mood = "pout"
+ else if(docile)
+ mood = ":33"
+ else
+ mood = ":3"
+ if(old_mood != mood)
+ update_icon()
+
+// Makes the slime very angry and dangerous.
+/mob/living/simple_animal/slime/proc/enrage()
+ if(docile)
+ return
+ rabid = TRUE
+ update_mood()
+ visible_message("\The [src] enrages!")
+
+// Makes the slime safe and harmless.
+/mob/living/simple_animal/slime/proc/pacify()
+ rabid = FALSE
+ docile = TRUE
+ hostile = FALSE
+ retaliate = FALSE
+ cooperative = FALSE
+
+ // If for whatever reason the mob AI decides to try to attack something anyways.
+ melee_damage_upper = 0
+ melee_damage_lower = 0
+
+ update_mood()
+
+/mob/living/simple_animal/slime/proc/unify()
+ unity = TRUE
+ attack_same = FALSE
+
+/mob/living/simple_animal/slime/examine(mob/user)
+ ..()
+ if(hat)
+ to_chat(user, "It is wearing \a [hat].")
+
+ if(stat == DEAD)
+ to_chat(user, "It appears to be dead.")
+ else if(incapacitated(INCAPACITATION_DISABLED))
+ to_chat(user, "It appears to be incapacitated.")
+ else if(rabid)
+ to_chat(user, "It seems very, very angry and upset.")
+ else if(obedience >= 5)
+ to_chat(user, "It looks rather obedient.")
+ else if(discipline)
+ to_chat(user, "It has been subjugated by force, at least for now.")
+ else if(docile)
+ to_chat(user, "It appears to have been pacified.")
+
+/mob/living/simple_animal/slime/water_act(amount) // This is called if a slime enters a water tile.
+ adjustBruteLoss(40 * amount)
+
+/mob/living/simple_animal/slime/proc/adjust_discipline(amount, silent)
+ if(amount > 0)
+ if(!rabid)
+ var/justified = is_justified_to_discipline()
+ spawn(0)
+ stop_consumption()
+ LoseTarget()
+ if(!silent)
+ if(justified)
+ say(pick("Fine...", "Okay...", "Sorry...", "I yield...", "Mercy..."))
+ else
+ say(pick("Why...?", "I don't understand...?", "Cruel...", "Stop...", "Nooo..."))
+ if(justified)
+ obedience++
+ else
+ if(prob(resentment * 20))
+ enrage() // Pushed the slime too far.
+ say(pick("Evil...", "Kill...", "Tyrant..."))
+ resentment++ // Done after check so first time will never enrage.
+
+ discipline = between(0, discipline + amount, 10)
+
+/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
+
+ . += config.slime_delay
+
+/mob/living/simple_animal/slime/Process_Spacemove()
+ return 2
+
+/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(docile)
+ to_chat(src, "I have been pacified. I cannot evolve...")
+ return
+
+ if(!is_adult)
+ if(amount_grown >= 10)
+ make_adult()
+ else
+ to_chat(src, "I am not ready to evolve yet...")
+ else
+ to_chat(src, "I have already evolved...")
+
+/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(docile)
+ to_chat(src, "I have been pacified. I cannot reproduce...")
+ return
+
+ if(is_adult)
+ if(amount_grown >= 10)
+
+ var/list/babies = list()
+ for(var/i = 1 to 4)
+ babies.Add(make_new_slime())
+
+ var/mob/living/simple_animal/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...")
+
+// Used for reproducing and dying.
+/mob/living/simple_animal/slime/proc/make_new_slime()
+ var/t = src.type
+ if(prob(mutation_chance) && slime_mutation.len)
+ t = slime_mutation[rand(1, slime_mutation.len)]
+ var/mob/living/simple_animal/slime/baby = new t(loc)
+
+ // Handle 'inheriting' from parent slime.
+ baby.mutation_chance = mutation_chance
+ baby.power_charge = round(power_charge / 4)
+ baby.resentment = max(resentment - 1, 0)
+ baby.discipline = max(discipline - 1, 0)
+ baby.obedience = max(obedience - 1, 0)
+ baby.unity = unity
+ baby.faction = faction
+ baby.friends = friends.Copy()
+ if(rabid)
+ baby.enrage()
+
+ step_away(baby, src)
+ return baby
+
+/mob/living/simple_animal/slime/speech_bubble_appearance()
+ return "slime"
+
+// Called after they finish eatting someone.
+/mob/living/simple_animal/slime/proc/befriend(var/mob/living/friend)
+ if(!(friend in friends))
+ friends |= friend
+ say("[friend]... friend...")
+
+/mob/living/simple_animal/slime/proc/can_command(var/mob/living/commander)
+ if(rabid)
+ return FALSE
+ if(docile)
+ return TRUE
+ if(commander in friends)
+ return TRUE
+ if(faction == commander.faction)
+ return TRUE
+ if(discipline > resentment && obedience >= 5)
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/slime/proc/give_hat(var/obj/item/clothing/head/new_hat, var/mob/living/user)
+ if(!istype(new_hat))
+ to_chat(user, "\The [new_hat] isn't a hat.")
+ return
+ if(hat)
+ to_chat(user, "\The [src] is already wearing \a [hat].")
+ return
+ else
+ user.drop_item(new_hat)
+ hat = new_hat
+ new_hat.forceMove(src)
+ to_chat(user, "You place \a [new_hat] on \the [src]. How adorable!")
+ update_icon()
+ return
+
+/mob/living/simple_animal/slime/proc/remove_hat(var/mob/living/user)
+ if(!hat)
+ to_chat(user, "\The [src] doesn't have a hat to remove.")
+ else
+ hat.forceMove(get_turf(src))
+ user.put_in_hands(hat)
+ to_chat(user, "You take away \the [src]'s [hat.name]. How mean.")
+ hat = null
+ update_icon()
+
+/mob/living/simple_animal/slime/proc/drop_hat()
+ if(!hat)
+ return
+ hat.forceMove(get_turf(src))
+ hat = null
+ update_icon()
+
+// Checks if disciplining the slime would be 'justified' right now.
+/mob/living/simple_animal/slime/proc/is_justified_to_discipline()
+ if(rabid)
+ return TRUE
+ if(target_mob)
+ if(ishuman(target_mob))
+ var/mob/living/carbon/human/H = target_mob
+ if(istype(H.species, /datum/species/monkey))
+ return FALSE
+ return TRUE
+ return FALSE
+
+
+/mob/living/simple_animal/slime/get_description_interaction()
+ var/list/results = list()
+
+ if(!stat)
+ results += "[desc_panel_image("slimebaton")]to stun the slime, if it's being bad."
+
+ results += ..()
+
+ return results
+
+/mob/living/simple_animal/slime/get_description_info()
+ var/list/lines = list()
+ var/intro_line = "Slimes are generally the test subjects of Xenobiology, with different colors having different properties. \
+ They can be extremely dangerous if not handled properly."
+ lines.Add(intro_line)
+ lines.Add(null) // To pad the line breaks.
+
+ var/list/rewards = list()
+ for(var/potential_color in slime_mutation)
+ var/mob/living/simple_animal/slime/S = potential_color
+ rewards.Add(initial(S.slime_color))
+ var/reward_line = "This color of slime can mutate into [english_list(rewards)] colors, when it reproduces. It will do so when it has eatten enough."
+ lines.Add(reward_line)
+ lines.Add(null)
+
+ lines.Add(description_info)
+ return lines.Join("\n")
+
diff --git a/code/modules/mob/living/simple_animal/slime/subtypes.dm b/code/modules/mob/living/simple_animal/slime/subtypes.dm
new file mode 100644
index 0000000000..4f71f91d3f
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/slime/subtypes.dm
@@ -0,0 +1,697 @@
+// Tier 1
+
+/mob/living/simple_animal/slime/purple
+ desc = "This slime is rather toxic to handle, as it is poisonous."
+ color = "#CC23FF"
+ slime_color = "purple"
+ coretype = /obj/item/slime_extract/purple
+ reagent_injected = "toxin"
+
+ description_info = "This slime spreads a toxin when it attacks. A biosuit or other thick armor can protect from the toxic attack."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/dark_purple,
+ /mob/living/simple_animal/slime/dark_blue,
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime
+ )
+
+
+/mob/living/simple_animal/slime/orange
+ desc = "This slime is known to be flammable and can ignite enemies."
+ color = "#FFA723"
+ slime_color = "orange"
+ coretype = /obj/item/slime_extract/orange
+
+ description_info = "Attacks from this slime can ignite you. A firesuit can protect from the burning attacks of this slime."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/dark_purple,
+ /mob/living/simple_animal/slime/yellow,
+ /mob/living/simple_animal/slime/red,
+ /mob/living/simple_animal/slime
+ )
+
+/mob/living/simple_animal/slime/orange/post_attack(mob/living/L, intent)
+ if(intent != I_HELP)
+ L.adjust_fire_stacks(1)
+ if(prob(25))
+ L.IgniteMob()
+ ..()
+
+/mob/living/simple_animal/slime/blue
+ desc = "This slime produces 'cryotoxin' and uses it against their foes. Very deadly to other slimes."
+ color = "#19FFFF"
+ slime_color = "blue"
+ coretype = /obj/item/slime_extract/blue
+ reagent_injected = "cryotoxin"
+
+ description_info = "Attacks from this slime can chill you. A biosuit or other thick armor can protect from the chilling attack."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/dark_blue,
+ /mob/living/simple_animal/slime/silver,
+ /mob/living/simple_animal/slime/pink,
+ /mob/living/simple_animal/slime
+ )
+
+
+/mob/living/simple_animal/slime/metal
+ desc = "This slime is a lot more resilient than the others, due to having a metamorphic metallic and sloped surface."
+ color = "#5F5F5F"
+ slime_color = "metal"
+ shiny = 1
+ coretype = /obj/item/slime_extract/metal
+
+ description_info = "This slime is a lot more durable and tough to damage than the others."
+
+ resistance = 10 // Sloped armor is strong.
+ maxHealth = 250
+ maxHealth_adult = 350
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/silver,
+ /mob/living/simple_animal/slime/yellow,
+ /mob/living/simple_animal/slime/gold,
+ /mob/living/simple_animal/slime
+ )
+
+// Tier 2
+
+/mob/living/simple_animal/slime/yellow
+ desc = "This slime is very conductive, and is known to use electricity as a means of defense moreso than usual for slimes."
+ color = "#FFF423"
+ slime_color = "yellow"
+ coretype = /obj/item/slime_extract/yellow
+
+ ranged = 1
+ shoot_range = 3
+ firing_lines = 1
+ projectiletype = /obj/item/projectile/beam/lightning/slime
+ projectilesound = 'sound/weapons/gauss_shoot.ogg' // Closest thing to a 'thunderstrike' sound we have.
+ glows = TRUE
+
+ description_info = "This slime will fire lightning attacks at enemies if they are at range, and generate electricity \
+ for their stun attack faster than usual. Insulative or reflective armor can protect from the lightning."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/bluespace,
+ /mob/living/simple_animal/slime/bluespace,
+ /mob/living/simple_animal/slime/metal,
+ /mob/living/simple_animal/slime/orange
+ )
+
+/mob/living/simple_animal/slime/yellow/handle_regular_status_updates()
+ if(stat == CONSCIOUS)
+ if(prob(25))
+ power_charge = between(0, power_charge + 1, 10)
+ ..()
+
+/obj/item/projectile/beam/lightning/slime
+ power = 15
+
+/mob/living/simple_animal/slime/yellow/ClosestDistance() // Needed or else they won't eat monkeys outside of melee range.
+ if(target_mob && ishuman(target_mob))
+ var/mob/living/carbon/human/H = target_mob
+ if(istype(H.species, /datum/species/monkey))
+ return 1
+ return ..()
+
+
+/mob/living/simple_animal/slime/dark_purple
+ desc = "This slime produces ever-coveted phoron. Risky to handle but very much worth it."
+ color = "#CC23FF"
+ slime_color = "dark purple"
+ coretype = /obj/item/slime_extract/dark_purple
+ reagent_injected = "phoron"
+
+ description_info = "This slime applies phoron to enemies it attacks. A biosuit or other thick armor can protect from the toxic attack. \
+ If hit with a burning attack, it will erupt in flames."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/purple,
+ /mob/living/simple_animal/slime/orange,
+ /mob/living/simple_animal/slime/ruby,
+ /mob/living/simple_animal/slime/ruby
+ )
+
+/mob/living/simple_animal/slime/dark_purple/proc/ignite()
+ visible_message("\The [src] erupts in an inferno!")
+ for(var/turf/simulated/target_turf in view(2, src))
+ target_turf.assume_gas("phoron", 30, 1500+T0C)
+ spawn(0)
+ target_turf.hotspot_expose(1500+T0C, 400)
+ qdel(src)
+
+/mob/living/simple_animal/slime/dark_purple/ex_act(severity)
+ log_and_message_admins("[src] ignited due to a chain reaction with an explosion.")
+ ignite()
+
+/mob/living/simple_animal/slime/dark_purple/fire_act(datum/gas_mixture/air, temperature, volume)
+ log_and_message_admins("[src] ignited due to exposure to fire.")
+ ignite()
+
+/mob/living/simple_animal/slime/dark_purple/bullet_act(var/obj/item/projectile/P, var/def_zone)
+ if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security.
+ log_and_message_admins("[src] ignited due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].")
+ ignite()
+ else
+ ..()
+
+/mob/living/simple_animal/slime/dark_purple/attackby(var/obj/item/weapon/W, var/mob/user)
+ if(istype(W) && W.force && W.damtype == BURN)
+ log_and_message_admins("[src] ignited due to being hit with a burning weapon ([W]) by [key_name(user)].")
+ ignite()
+ else
+ ..()
+
+
+
+
+/mob/living/simple_animal/slime/dark_blue
+ desc = "This slime makes other entities near it feel much colder, and is more resilient to the cold. It tends to kill other slimes rather quickly."
+ color = "#2398FF"
+ glows = TRUE
+ slime_color = "dark blue"
+ coretype = /obj/item/slime_extract/dark_blue
+
+ description_info = "This slime is immune to the cold, however water will still kill it. A winter coat or other cold-resistant clothing can protect from the chilling aura."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/purple,
+ /mob/living/simple_animal/slime/blue,
+ /mob/living/simple_animal/slime/cerulean,
+ /mob/living/simple_animal/slime/cerulean
+ )
+
+ minbodytemp = 0
+ cold_damage_per_tick = 0
+
+/mob/living/simple_animal/slime/dark_blue/Life()
+ if(stat != DEAD)
+ cold_aura()
+ ..()
+
+/mob/living/simple_animal/slime/dark_blue/proc/cold_aura()
+ for(var/mob/living/L in view(2, src))
+ var/protection = L.get_cold_protection()
+
+ if(protection < 1)
+ var/cold_factor = abs(protection - 1)
+ var/delta = -20
+ delta *= cold_factor
+ L.bodytemperature = max(50, delta)
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ env.add_thermal_energy(-10 * 1000)
+
+
+/mob/living/simple_animal/slime/silver
+ desc = "This slime is shiny, and can deflect lasers or other energy weapons directed at it."
+ color = "#AAAAAA"
+ slime_color = "silver"
+ coretype = /obj/item/slime_extract/silver
+ shiny = TRUE
+
+ description_info = "Tasers, including the slime version, are ineffective against this slime. The slimebation still works."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/metal,
+ /mob/living/simple_animal/slime/blue,
+ /mob/living/simple_animal/slime/amber,
+ /mob/living/simple_animal/slime/amber
+ )
+
+/mob/living/simple_animal/slime/silver/bullet_act(var/obj/item/projectile/P, var/def_zone)
+ if(istype(P,/obj/item/projectile/beam) || istype(P, /obj/item/projectile/energy))
+ visible_message("\The [src] reflects \the [P]!")
+
+ // Find a turf near or on the original location to bounce to
+ var/new_x = P.starting.x + pick(0, 0, 0, -1, 1, -2, 2)
+ var/new_y = P.starting.y + pick(0, 0, 0, -1, 1, -2, 2)
+ var/turf/curloc = get_turf(src)
+
+ // redirect the projectile
+ P.redirect(new_x, new_y, curloc, src)
+ return PROJECTILE_CONTINUE // complete projectile permutation
+ else
+ ..()
+
+
+// Tier 3
+
+/mob/living/simple_animal/slime/bluespace
+ desc = "Trapping this slime in a cell is generally futile, as it can teleport at will."
+ color = null
+ slime_color = "bluespace"
+ icon_state_override = "bluespace"
+ coretype = /obj/item/slime_extract/bluespace
+
+ description_info = "This slime will teleport to attack something if it is within a range of seven tiles. The teleport has a cooldown of five seconds."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/bluespace,
+ /mob/living/simple_animal/slime/bluespace,
+ /mob/living/simple_animal/slime/yellow,
+ /mob/living/simple_animal/slime/yellow
+ )
+
+ spattack_prob = 100
+ spattack_min_range = 3
+ spattack_max_range = 7
+ var/last_tele = null // Uses world.time
+ var/tele_cooldown = 5 SECONDS
+
+/mob/living/simple_animal/slime/bluespace/ClosestDistance() // Needed or the SA AI won't ever try to teleport.
+ if(world.time > last_tele + tele_cooldown)
+ return spattack_max_range - 1
+ return ..()
+
+/mob/living/simple_animal/slime/bluespace/SpecialAtkTarget()
+ // Teleport attack.
+ if(!target_mob)
+ to_chat(src, "There's nothing to teleport to.")
+ return FALSE
+
+ if(world.time < last_tele + tele_cooldown)
+ to_chat(src, "You can't teleport right now, wait a few seconds.")
+ return FALSE
+
+ var/list/nearby_things = range(1, target_mob)
+ var/list/valid_turfs = list()
+
+ // All this work to just go to a non-dense tile.
+ for(var/turf/potential_turf in nearby_things)
+ var/valid_turf = TRUE
+ if(potential_turf.density)
+ continue
+ for(var/atom/movable/AM in potential_turf)
+ if(AM.density)
+ valid_turf = FALSE
+ if(valid_turf)
+ valid_turfs.Add(potential_turf)
+
+
+
+ var/turf/T = get_turf(src)
+ var/turf/target_turf = pick(valid_turfs)
+
+ if(!target_turf)
+ to_chat(src, "There wasn't an unoccupied spot to teleport to.")
+ return FALSE
+
+ var/datum/effect/effect/system/spark_spread/s1 = new /datum/effect/effect/system/spark_spread
+ s1.set_up(5, 1, T)
+ var/datum/effect/effect/system/spark_spread/s2 = new /datum/effect/effect/system/spark_spread
+ s2.set_up(5, 1, target_turf)
+
+
+ T.visible_message("\The [src] vanishes!")
+ s1.start()
+
+ forceMove(target_turf)
+ playsound(target_turf, 'sound/effects/phasein.ogg', 50, 1)
+ to_chat(src, "You teleport to \the [target_turf].")
+
+ target_turf.visible_message("\The [src] appears!")
+ s2.start()
+
+ last_tele = world.time
+
+ if(Adjacent(target_mob))
+ PunchTarget()
+ return TRUE
+
+/mob/living/simple_animal/slime/ruby
+ desc = "This slime has great physical strength."
+ color = "#FF3333"
+ slime_color = "ruby"
+ shiny = TRUE
+ glows = TRUE
+ coretype = /obj/item/slime_extract/ruby
+
+ description_info = "This slime is unnaturally stronger, allowing it to hit much harder, take less damage, and be stunned for less time."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/dark_purple,
+ /mob/living/simple_animal/slime/dark_purple,
+ /mob/living/simple_animal/slime/ruby,
+ /mob/living/simple_animal/slime/ruby
+ )
+
+/mob/living/simple_animal/slime/ruby/New()
+ ..()
+ add_modifier(/datum/modifier/slime_strength, null, src) // Slime is always swole.
+
+
+/mob/living/simple_animal/slime/amber
+ desc = "This slime seems to be an expert in the culinary arts, as they create their own food to share with others. \
+ They would probably be very important to other slimes, if the other colors didn't try to kill them."
+ color = "#FFBB00"
+ slime_color = "amber"
+ shiny = TRUE
+ glows = TRUE
+ coretype = /obj/item/slime_extract/amber
+
+ description_info = "This slime feeds nearby entities passively while it is alive. This can cause uncontrollable \
+ slime growth and reproduction if not kept in check."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/silver,
+ /mob/living/simple_animal/slime/silver,
+ /mob/living/simple_animal/slime/amber,
+ /mob/living/simple_animal/slime/amber
+ )
+
+/mob/living/simple_animal/slime/amber/Life()
+ if(stat != DEAD)
+ feed_aura()
+ ..()
+
+/mob/living/simple_animal/slime/amber/proc/feed_aura()
+ for(var/mob/living/L in view(2, src))
+ if(L == src) // Don't feed themselves, or it is impossible to stop infinite slimes without killing all of the ambers.
+ continue
+ if(isslime(L))
+ var/mob/living/simple_animal/slime/S = L
+ S.adjust_nutrition(rand(15, 25))
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.isSynthetic())
+ continue
+ H.nutrition = between(0, H.nutrition + rand(15, 25), 600)
+
+
+
+/mob/living/simple_animal/slime/cerulean
+ desc = "This slime is generally superior in a wide range of attributes, compared to the common slime. The jack of all trades, but master of none."
+ color = "#4F7EAA"
+ slime_color = "cerulean"
+ coretype = /obj/item/slime_extract/cerulean
+
+ // Less than the specialized slimes, but higher than the rest.
+ maxHealth = 200
+ maxHealth_adult = 250
+
+ melee_damage_lower = 10
+ melee_damage_upper = 30
+
+ move_to_delay = 3
+
+
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/dark_blue,
+ /mob/living/simple_animal/slime/dark_blue,
+ /mob/living/simple_animal/slime/cerulean,
+ /mob/living/simple_animal/slime/cerulean
+ )
+
+// Tier 4
+
+/mob/living/simple_animal/slime/red
+ desc = "This slime is full of energy, and very aggressive. 'The red ones go faster.' seems to apply here."
+ color = "#FF3333"
+ slime_color = "red"
+ coretype = /obj/item/slime_extract/red
+ move_to_delay = 3 // The red ones go faster.
+
+ description_info = "This slime is faster than the others. Attempting to discipline this slime will always cause it to go berserk."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/red,
+ /mob/living/simple_animal/slime/oil,
+ /mob/living/simple_animal/slime/oil,
+ /mob/living/simple_animal/slime/orange
+ )
+
+
+/mob/living/simple_animal/slime/red/adjust_discipline(amount)
+ if(amount > 0)
+ if(!rabid)
+ enrage() // How dare you try to control the red slime.
+ say("Grrr...!")
+
+
+/mob/living/simple_animal/slime/green
+ desc = "This slime is radioactive."
+ color = "#14FF20"
+ slime_color = "green"
+ coretype = /obj/item/slime_extract/green
+ glows = TRUE
+ reagent_injected = "radium"
+ var/rads = 25
+
+ description_info = "This slime will irradiate anything nearby passively, and will inject radium on attack. \
+ A radsuit or other thick and radiation-hardened armor can protect from this. It will only radiate while alive."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/purple,
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime/emerald,
+ /mob/living/simple_animal/slime/emerald
+ )
+
+/mob/living/simple_animal/slime/green/Life()
+ if(stat != DEAD)
+ irradiate()
+ ..()
+
+/mob/living/simple_animal/slime/green/proc/irradiate()
+ radiation_repository.radiate(src, rads)
+
+
+/mob/living/simple_animal/slime/pink
+ desc = "This slime has regenerative properties."
+ color = "#FF0080"
+ slime_color = "pink"
+ coretype = /obj/item/slime_extract/pink
+ glows = TRUE
+
+ description_info = "This slime will passively heal nearby entities within two tiles, including itself. It will only do this while alive."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/blue,
+ /mob/living/simple_animal/slime/light_pink,
+ /mob/living/simple_animal/slime/light_pink,
+ /mob/living/simple_animal/slime/pink
+ )
+
+/mob/living/simple_animal/slime/pink/Life()
+ if(stat != DEAD)
+ heal_aura()
+ ..()
+
+/mob/living/simple_animal/slime/pink/proc/heal_aura()
+ for(var/mob/living/L in view(src, 2))
+ if(L.stat == DEAD || L == target_mob)
+ continue
+ L.add_modifier(/datum/modifier/slime_heal, 5 SECONDS, src)
+
+/datum/modifier/slime_heal
+ name = "slime mending"
+ desc = "You feel somewhat gooy."
+ mob_overlay_state = "pink_sparkles"
+
+ on_created_text = "Twinkling spores of goo surround you. It makes you feel healthier."
+ on_expired_text = "The spores of goo have faded, although you feel much healthier than before."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/slime_heal/tick()
+ if(holder.stat == DEAD) // Required or else simple animals become immortal.
+ expire()
+ holder.adjustBruteLoss(-2)
+ holder.adjustFireLoss(-2)
+ holder.adjustToxLoss(-2)
+ holder.adjustOxyLoss(-2)
+ holder.adjustCloneLoss(-1)
+
+
+
+/mob/living/simple_animal/slime/gold
+ desc = "This slime absorbs energy, and cannot be stunned by normal means."
+ color = "#EEAA00"
+ shiny = TRUE
+ slime_color = "gold"
+ coretype = /obj/item/slime_extract/gold
+ description_info = "This slime is immune to the slimebaton and taser, and will actually charge the slime, however it will still discipline the slime."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/metal,
+ /mob/living/simple_animal/slime/gold,
+ /mob/living/simple_animal/slime/sapphire,
+ /mob/living/simple_animal/slime/sapphire
+ )
+
+/mob/living/simple_animal/slime/gold/Weaken(amount)
+ power_charge = between(0, power_charge + amount, 10)
+ return
+
+/mob/living/simple_animal/slime/gold/Stun(amount)
+ power_charge = between(0, power_charge + amount, 10)
+ return
+
+/mob/living/simple_animal/slime/gold/get_description_interaction() // So it doesn't say to use a baton on them.
+ return list()
+
+
+// Tier 5
+
+/mob/living/simple_animal/slime/oil
+ desc = "This slime is explosive and volatile. Smoking near it is probably a bad idea."
+ color = "#333333"
+ slime_color = "oil"
+ shiny = TRUE
+ coretype = /obj/item/slime_extract/oil
+
+ description_info = "If this slime suffers damage from a fire or heat based source, or if it is caught inside \
+ an explosion, it will explode. Rabid oil slimes will charge at enemies, then suicide-bomb themselves. \
+ Bomb suits can protect from the explosion."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/oil,
+ /mob/living/simple_animal/slime/oil,
+ /mob/living/simple_animal/slime/red,
+ /mob/living/simple_animal/slime/red
+ )
+
+/mob/living/simple_animal/slime/oil/proc/explode()
+ if(stat != DEAD)
+ // explosion(src.loc, 1, 2, 4)
+ explosion(src.loc, 0, 2, 4) // A bit weaker since the suicide charger tended to gib the poor sod being targeted.
+ if(src) // Delete ourselves if the explosion didn't do it.
+ qdel(src)
+
+/mob/living/simple_animal/slime/oil/post_attack(var/mob/living/L, var/intent = I_HURT)
+ if(!rabid)
+ return ..()
+ if(intent == I_HURT || intent == I_GRAB)
+ say(pick("Sacrifice...!", "Sssss...", "Boom...!"))
+ sleep(2 SECOND)
+ log_and_message_admins("[src] has suicide-bombed themselves while trying to kill \the [L].")
+ explode()
+
+/mob/living/simple_animal/slime/oil/ex_act(severity)
+ log_and_message_admins("[src] exploded due to a chain reaction with another explosion.")
+ explode()
+
+/mob/living/simple_animal/slime/oil/fire_act(datum/gas_mixture/air, temperature, volume)
+ log_and_message_admins("[src] exploded due to exposure to fire.")
+ explode()
+
+/mob/living/simple_animal/slime/oil/bullet_act(var/obj/item/projectile/P, var/def_zone)
+ if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security.
+ log_and_message_admins("[src] exploded due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].")
+ explode()
+ else
+ ..()
+
+/mob/living/simple_animal/slime/oil/attackby(var/obj/item/weapon/W, var/mob/user)
+ if(istype(W) && W.force && W.damtype == BURN)
+ log_and_message_admins("[src] exploded due to being hit with a burning weapon ([W]) by [key_name(user)].")
+ explode()
+ else
+ ..()
+
+
+/mob/living/simple_animal/slime/sapphire
+ desc = "This slime seems a bit brighter than the rest, both figuratively and literally."
+ color = "#2398FF"
+ slime_color = "sapphire"
+ shiny = TRUE
+ glows = TRUE
+ coretype = /obj/item/slime_extract/sapphire
+
+ optimal_combat = TRUE // Lift combat AI restrictions to look smarter.
+ run_at_them = FALSE // Use fancy A* pathing.
+ astar_adjacent_proc = /turf/proc/TurfsWithAccess // Normal slimes don't care about cardinals (because BYOND) so smart slimes shouldn't as well.
+ move_to_delay = 3 // A* chasing is slightly slower in terms of movement speed than regular pathing so reducing this hopefully makes up for that.
+
+ description_info = "This slime uses more robust tactics when fighting and won't hold back, so it is dangerous to be alone \
+ with one if hostile, and especially dangerous if they outnumber you."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/sapphire,
+ /mob/living/simple_animal/slime/sapphire,
+ /mob/living/simple_animal/slime/gold,
+ /mob/living/simple_animal/slime/gold
+ )
+
+/mob/living/simple_animal/slime/emerald
+ desc = "This slime is faster than usual, even more so than the red slimes."
+ color = "#22FF22"
+ shiny = TRUE
+ glows = TRUE
+ slime_color = "emerald"
+ coretype = /obj/item/slime_extract/emerald
+
+ description_info = "This slime will make everything around it, and itself, faster for a few seconds, if close by."
+ move_to_delay = 2
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime/emerald,
+ /mob/living/simple_animal/slime/emerald
+ )
+
+/mob/living/simple_animal/slime/emerald/Life()
+ if(stat != DEAD)
+ zoom_aura()
+ ..()
+
+/mob/living/simple_animal/slime/emerald/proc/zoom_aura()
+ for(var/mob/living/L in view(src, 2))
+ if(L.stat == DEAD || L == target_mob)
+ continue
+ L.add_modifier(/datum/modifier/technomancer/haste, 5 SECONDS, src)
+
+/mob/living/simple_animal/slime/light_pink
+ desc = "This slime seems a lot more peaceful than the others."
+ color = "#FF8888"
+ slime_color = "light_pink"
+ coretype = /obj/item/slime_extract/light_pink
+
+ description_info = "This slime is effectively always disciplined initially."
+ obedience = 5
+ discipline = 5
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime/green,
+ /mob/living/simple_animal/slime/emerald,
+ /mob/living/simple_animal/slime/emerald
+ )
+
+// Special
+/mob/living/simple_animal/slime/rainbow
+ desc = "This slime changes colors constantly."
+ color = null // Only slime subtype that uses a different icon_state.
+ slime_color = "rainbow"
+ coretype = /obj/item/slime_extract/rainbow
+ icon_state_override = "rainbow"
+
+ description_info = "This slime is considered to be the same color as all other slime colors at the same time for the purposes of \
+ other slimes being friendly to them, and therefore will never be harmed by another slime. \
+ Attacking this slime will provoke the wrath of all slimes within range."
+
+ slime_mutation = list(
+ /mob/living/simple_animal/slime/rainbow,
+ /mob/living/simple_animal/slime/rainbow,
+ /mob/living/simple_animal/slime/rainbow,
+ /mob/living/simple_animal/slime/rainbow
+ )
+
+/mob/living/simple_animal/slime/rainbow/New()
+ unify()
+ ..()
+
+// The RD's pet slime.
+/mob/living/simple_animal/slime/rainbow/kendrick
+ name = "Kendrick"
+ desc = "The Research Director's pet slime. It shifts colors constantly."
+
+/mob/living/simple_animal/slime/rainbow/kendrick/New()
+ pacify()
+ ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm
index dbace03e52..3bc7929eac 100644
--- a/code/modules/mob/living/voice/voice.dm
+++ b/code/modules/mob/living/voice/voice.dm
@@ -111,7 +111,8 @@
//Speech bubbles.
if(comm)
var/speech_bubble_test = say_test(message)
- var/image/speech_bubble = image('icons/mob/talk.dmi',comm,"h[speech_bubble_test]")
+ var/speech_type = speech_bubble_appearance()
+ var/image/speech_bubble = image('icons/mob/talk.dmi',comm,"[speech_type][speech_bubble_test]")
spawn(30)
qdel(speech_bubble)
@@ -121,6 +122,12 @@
..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking.
+// Proc: speech_bubble_appearance()
+// Parameters: 0
+// Description: Gets the correct icon_state information for chat bubbles to work.
+/mob/living/voice/speech_bubble_appearance()
+ return "comm"
+
/mob/living/voice/say_understands(var/other,var/datum/language/speaking = null)
//These only pertain to common. Languages are handled by mob/say_understands()
if (!speaking)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index ba5b24dbe7..b01d346c23 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -536,13 +536,40 @@ proc/is_blind(A)
return threatcount
-/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
+/mob/living/simple_animal/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
var/threatcount = ..()
if(. == SAFE_PERP)
return SAFE_PERP
if(!istype(src, /mob/living/simple_animal/retaliate/goat))
+ if(hostile)
+ if(faction != "neutral") // Otherwise Runtime gets killed.
+ threatcount += 4
+ return threatcount
+
+// Beepsky will (try to) only beat 'bad' slimes.
+/mob/living/simple_animal/slime/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest)
+ var/threatcount = 0
+
+ if(stat == DEAD)
+ return SAFE_PERP
+
+ if(is_justified_to_discipline())
threatcount += 4
+/*
+ if(discipline && !rabid)
+ if(!target_mob || istype(target_mob, /mob/living/carbon/human/monkey))
+ return SAFE_PERP
+
+ if(target_mob)
+ threatcount += 4
+
+ if(victim)
+ threatcount += 4
+*/
+ if(rabid)
+ threatcount = 10
+
return threatcount
#undef SAFE_PERP
diff --git a/code/modules/mob/modifiers.dm b/code/modules/mob/modifiers.dm
index 0b39c9e275..95d3db1e93 100644
--- a/code/modules/mob/modifiers.dm
+++ b/code/modules/mob/modifiers.dm
@@ -92,7 +92,7 @@
/mob/living/proc/add_modifier(var/modifier_type, var/expire_at = null, var/mob/living/origin = null)
// First, check if the mob already has this modifier.
for(var/datum/modifier/M in modifiers)
- if(istype(modifier_type, M))
+ if(ispath(modifier_type, M))
switch(M.stacks)
if(MODIFIER_STACK_FORBID)
return // Stop here.
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index f5445e0e5a..b5add4f23f 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -35,6 +35,9 @@
usr << "Speech is currently admin-disabled."
return
+ if(!client)
+ return // Clientless mobs shouldn't be trying to talk in deadchat.
+
if(!src.client.holder)
if(!config.dsay_allowed)
src << "Deadchat is globally muted."
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 085f601aef..03e4227f6e 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -161,40 +161,6 @@
qdel(src)
return O
-/mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num)
- if (transforming)
- return
- for(var/obj/item/W in src)
- drop_from_inventory(W)
- regenerate_icons()
- transforming = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs)
- qdel(t)
-
- var/mob/living/carbon/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)
- M.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.key = key
-
- new_slime << "You are now a slime. Skreee!"
- qdel(src)
- return
-
/mob/living/carbon/human/proc/corgize()
if (transforming)
return
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
index 8a8d92f2c7..0ce5f390c4 100644
--- a/code/modules/mob/typing_indicator.dm
+++ b/code/modules/mob/typing_indicator.dm
@@ -12,7 +12,7 @@ mob/var/obj/effect/decal/typing_indicator
if(!typing_indicator)
typing_indicator = new
typing_indicator.icon = 'icons/mob/talk.dmi'
- typing_indicator.icon_state = "typing"
+ typing_indicator.icon_state = "[speech_bubble_appearance()]_typing"
if(client && !stat)
typing_indicator.invisibility = invisibility
diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm
index a93f37bd56..a055409531 100644
--- a/code/modules/organs/robolimbs.dm
+++ b/code/modules/organs/robolimbs.dm
@@ -44,6 +44,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
var/parts = BP_ALL //Defines what parts said brand can replace on a body.
var/health_hud_intensity = 1 // Intensity modifier for the health GUI indicator.
var/suggested_species = "Human" //If it should make the torso a species
+ var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons.
/datum/robolimb/unbranded_monitor
company = "Unbranded Monitor"
@@ -135,6 +136,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
unavailable_to_build = 1
lifelike = 1
blood_color = "#CCCCCC"
+ speech_bubble_appearance = "normal"
/datum/robolimb/wardtakahashi
company = "Ward-Takahashi"
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index f6d192276f..4a81179c72 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -19,7 +19,7 @@
/obj/item/weapon/paper_bin/MouseDrop(mob/user as mob)
if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr))))))
- if(!istype(usr, /mob/living/carbon/slime) && !istype(usr, /mob/living/simple_animal))
+ if(!istype(usr, /mob/living/simple_animal))
if( !usr.get_active_hand() ) //if active hand is empty
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/temp = H.organs_by_name["r_hand"]
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index c58bd2f166..d3cde87049 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -6,6 +6,19 @@
..()
charge = maxcharge
update_icon()
+ if(self_recharge)
+ processing_objects |= src
+
+/obj/item/weapon/cell/Destroy()
+ if(self_recharge)
+ processing_objects -= src
+ return ..()
+
+/obj/item/weapon/cell/process()
+ if(self_recharge)
+ give(charge_amount / CELLRATE)
+ else
+ return PROCESS_KILL
/obj/item/weapon/cell/drain_power(var/drain_check, var/surge, var/power = 0)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index bddc1fe490..0bdf518a2c 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -174,4 +174,17 @@
power_supply = new /obj/item/weapon/cell/device/weapon(src)
self_recharge = 1
processing_objects.Add(src)
- update_icon()
\ No newline at end of file
+ update_icon()
+
+/obj/item/weapon/gun/energy/get_description_interaction()
+ var/list/results = list()
+
+ if(!battery_lock && !self_recharge)
+ if(power_supply)
+ results += "[desc_panel_image("offhand")]to remove the weapon cell."
+ else
+ results += "[desc_panel_image("weapon cell")]to add a new weapon cell."
+
+ results += ..()
+
+ return results
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm
index 64f708891b..5e24564292 100644
--- a/code/modules/projectiles/guns/energy/temperature.dm
+++ b/code/modules/projectiles/guns/energy/temperature.dm
@@ -2,78 +2,14 @@
name = "temperature gun"
icon_state = "freezegun"
fire_sound = 'sound/weapons/pulse3.ogg'
- desc = "A gun that changes temperatures. It has a small label on the side, 'More extreme temperatures will cost more charge!'"
- var/temperature = T20C
- var/current_temperature = T20C
- charge_cost = 24
+ desc = "A gun that can add or remove heat from entities it hits. In other words, it can fire 'cold', and 'hot' beams."
+ charge_cost = 240
origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 4, TECH_POWER = 3, TECH_MAGNET = 2)
slot_flags = SLOT_BELT|SLOT_BACK
projectile_type = /obj/item/projectile/temp
- cell_type = /obj/item/weapon/cell/high
-
-/obj/item/weapon/gun/energy/temperature/New()
- ..()
- processing_objects.Add(src)
-
-
-/obj/item/weapon/gun/energy/temperature/Destroy()
- processing_objects.Remove(src)
- ..()
-
-
-/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob)
- user.set_machine(src)
- var/temp_text = ""
- if(temperature > (T0C - 50))
- temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
- else
- temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)"
-
- var/dat = {"Freeze Gun Configuration:
- Current output temperature: [temp_text]
- Target output temperature: - - - [current_temperature] + + +
- "}
-
- user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1")
- onclose(user, "window=freezegun", src)
-
-
-/obj/item/weapon/gun/energy/temperature/Topic(href, href_list)
- if (..())
- return 1
- usr.set_machine(src)
- src.add_fingerprint(usr)
-
-
-
- if(href_list["temp"])
- var/amount = text2num(href_list["temp"])
- if(amount > 0)
- src.current_temperature = min(500, src.current_temperature+amount)
- else
- src.current_temperature = max(0, src.current_temperature+amount)
- if (istype(src.loc, /mob))
- attack_self(src.loc)
- src.add_fingerprint(usr)
- return
-
-
-/obj/item/weapon/gun/energy/temperature/process()
- switch(temperature)
- if(0 to 100) charge_cost = 1000
- if(100 to 250) charge_cost = 500
- if(251 to 300) charge_cost = 100
- if(301 to 400) charge_cost = 500
- if(401 to 500) charge_cost = 1000
-
- if(current_temperature != temperature)
- var/difference = abs(current_temperature - temperature)
- if(difference >= 10)
- if(current_temperature < temperature)
- temperature -= 10
- else
- temperature += 10
- else
- temperature = current_temperature
+ firemodes = list(
+ list(mode_name="endothermic beam", projectile_type = /obj/item/projectile/temp, charge_cost = 240),
+ list(mode_name="exothermic beam", projectile_type = /obj/item/projectile/temp/hot, charge_cost = 240),
+ )
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index f5a7460cc3..3144f9eb09 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -76,7 +76,7 @@
/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
if(blocked >= 100) return 0//Full block
if(!isliving(target)) return 0
- if(isanimal(target)) return 0
+// if(isanimal(target)) return 0
var/mob/living/L = target
L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked) // add in AGONY!
return 1
diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm
index b389d39153..6f19b29bbb 100644
--- a/code/modules/projectiles/projectile/change.dm
+++ b/code/modules/projectiles/projectile/change.dm
@@ -52,7 +52,7 @@
Robot.mmi = new /obj/item/device/mmi(new_mob)
Robot.mmi.transfer_identity(M) //Does not transfer key/client.
if("slime")
- new_mob = new /mob/living/carbon/slime(M.loc)
+ new_mob = new /mob/living/simple_animal/slime(M.loc)
new_mob.universal_speak = 1
else
var/mob/living/carbon/human/H
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index c15e7cda4a..dd268f09b7 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -35,19 +35,45 @@
icon_state = "ice_2"
damage = 0
damage_type = BURN
+ pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
nodamage = 1
- check_armour = "energy"
- var/temperature = 300
+ check_armour = "energy" // It actually checks heat/cold protection.
+ var/target_temperature = 50
light_range = 2
light_power = 0.5
light_color = "#55AAFF"
+/obj/item/projectile/temp/on_hit(atom/target, blocked = FALSE)
+ ..()
+ if(isliving(target))
+ var/mob/living/L = target
- on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob
- if(istype(target, /mob/living))
- var/mob/M = target
- M.bodytemperature = temperature
- return 1
+ var/protection = null
+ var/potential_temperature_delta = null
+ var/new_temperature = L.bodytemperature
+
+ if(target_temperature >= T20C) // Make it cold.
+ protection = L.get_cold_protection(target_temperature)
+ potential_temperature_delta = 75
+ new_temperature = max(new_temperature - potential_temperature_delta, target_temperature)
+ else // Make it hot.
+ protection = L.get_heat_protection(target_temperature)
+ potential_temperature_delta = 200 // Because spacemen temperature needs stupid numbers to actually hurt people.
+ new_temperature = min(new_temperature + potential_temperature_delta, target_temperature)
+
+ var/temp_factor = abs(protection - 1)
+
+ new_temperature = round(new_temperature * temp_factor)
+ L.bodytemperature = new_temperature
+
+// L.bodytemperature = between(target_temperature,(L.bodytemperature - ((L.bodytemperature + potential_temperature_delta) * temp_factor) ), L.bodytemperature)
+ world << "Temperature of [L] is now [L.bodytemperature]."
+
+ return 1
+
+/obj/item/projectile/temp/hot
+ name = "heat beam"
+ target_temperature = 1000
/obj/item/projectile/meteor
name = "meteor"
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index d634711379..ab83fbe8a0 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -381,10 +381,6 @@
if(type == CHEM_TOUCH)
var/datum/reagents/R = C.touching
return trans_to_holder(R, amount, multiplier, copy)
- else if(isxeno(target))
- var/mob/living/simple_animal/xeno/X = target
- var/datum/reagents/R = X.reagents
- return trans_to_holder(R, amount, multiplier, copy)
else
var/datum/reagents/R = new /datum/reagents(amount)
. = trans_to_holder(R, amount, multiplier, copy)
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index ccf7c62ac1..3c71a0b089 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -2,7 +2,7 @@
#define LIQUID 2
#define GAS 3
-#define REAGENTS_PER_SHEET 20
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -294,6 +294,7 @@
/obj/item/stack/material/phoron = "phoron",
/obj/item/stack/material/gold = "gold",
/obj/item/stack/material/silver = "silver",
+ /obj/item/stack/material/platinum = "platinum",
/obj/item/stack/material/mhydrogen = "hydrogen"
)
@@ -500,5 +501,3 @@
qdel(O)
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
break
-
-#undef REAGENTS_PER_SHEET
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
index f6208f59ff..6fb44ad814 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
@@ -133,23 +133,19 @@
/datum/reagent/water/touch_mob(var/mob/living/L, var/amount)
if(istype(L))
+ // First, kill slimes.
+ if(istype(L, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = L
+ S.adjustToxLoss(15 * amount)
+ S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!")
+
+ // Then extinguish people on fire.
var/needed = L.fire_stacks * 5
if(amount > needed)
L.ExtinguishMob()
L.adjust_fire_stacks(-(amount / 5))
remove_self(needed)
-/datum/reagent/water/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
- if(istype(M, /mob/living/carbon/slime))
- var/mob/living/carbon/slime/S = M
- S.adjustToxLoss(15 * removed) // Babies have 150 health, adults have 200; So, 10 units and 13.5
- if(!S.client)
- if(S.Target) // Like cats
- S.Target = null
- ++S.Discipline
- if(dose == removed)
- S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!")
-
/datum/reagent/fuel
name = "Welding fuel"
id = "fuel"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
index 6732f4c192..8cfb1b5e93 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
@@ -287,7 +287,7 @@
M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0)
if(prob(1))
M.emote("shiver")
- if(istype(M, /mob/living/carbon/slime))
+ if(istype(M, /mob/living/simple_animal/slime))
M.bodytemperature = max(M.bodytemperature - rand(10,20), 0)
holder.remove_reagent("capsaicin", 5)
@@ -319,7 +319,7 @@
M.apply_effect(2, AGONY, 0)
if(prob(5))
M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!")
- if(istype(M, /mob/living/carbon/slime))
+ if(istype(M, /mob/living/simple_animal/slime))
M.bodytemperature += rand(10, 25)
holder.remove_reagent("frostoil", 5)
@@ -404,7 +404,7 @@
M.apply_effect(4, AGONY, 0)
if(prob(5))
M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!")
- if(istype(M, /mob/living/carbon/slime))
+ if(istype(M, /mob/living/simple_animal/slime))
M.bodytemperature += rand(15, 30)
holder.remove_reagent("frostoil", 5)
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
index 0a7c78f952..c554959435 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
@@ -169,6 +169,14 @@
reagent_state = SOLID
color = "#B8B8C0"
+/datum/reagent/platinum
+ name = "Platinum"
+ id = "platinum"
+ description = "Platinum is a dense, malleable, ductile, highly unreactive, precious, gray-white transition metal. It is very resistant to corrosion."
+ taste_description = "metal"
+ reagent_state = SOLID
+ color = "#777777"
+
/datum/reagent/uranium/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
affect_ingest(M, alien, removed)
@@ -298,7 +306,7 @@
S.dirt = 0
T.clean_blood()
- for(var/mob/living/carbon/slime/M in T)
+ for(var/mob/living/simple_animal/slime/M in T)
M.adjustToxLoss(rand(5, 10))
/datum/reagent/space_cleaner/affect_touch(var/mob/living/carbon/M, var/alien, var/removed)
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 8df309b1b8..5e38218ac0 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -604,16 +604,75 @@
/* Solidification */
-/datum/chemical_reaction/phoronsolidification
+/datum/chemical_reaction/solidification
+ name = "Solid Iron"
+ id = "solidiron"
+ result = null
+ required_reagents = list("frostoil" = 5, "iron" = REAGENTS_PER_SHEET)
+ result_amount = 1
+ var/sheet_to_give = /obj/item/stack/material/iron
+
+/datum/chemical_reaction/solidification/on_reaction(var/datum/reagents/holder, var/created_volume)
+ new sheet_to_give(get_turf(holder.my_atom), created_volume)
+ return
+
+
+/datum/chemical_reaction/solidification/phoron
name = "Solid Phoron"
id = "solidphoron"
- result = null
- required_reagents = list("iron" = 5, "frostoil" = 5, "phoron" = 20)
- result_amount = 1
+ required_reagents = list("frostoil" = 5, "phoron" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/phoron
+
+
+/datum/chemical_reaction/solidification/silver
+ name = "Solid Silver"
+ id = "solidsilver"
+ required_reagents = list("frostoil" = 5, "silver" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/silver
+
+
+/datum/chemical_reaction/solidification/gold
+ name = "Solid Gold"
+ id = "solidgold"
+ required_reagents = list("frostoil" = 5, "gold" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/gold
+
+
+/datum/chemical_reaction/solidification/platinum
+ name = "Solid Platinum"
+ id = "solidplatinum"
+ required_reagents = list("frostoil" = 5, "platinum" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/platinum
+
+
+/datum/chemical_reaction/solidification/uranium
+ name = "Solid Uranium"
+ id = "soliduranium"
+ required_reagents = list("frostoil" = 5, "uranium" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/uranium
+
+
+/datum/chemical_reaction/solidification/hydrogen
+ name = "Solid Hydrogen"
+ id = "solidhydrogen"
+ required_reagents = list("frostoil" = 100, "hydrogen" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/mhydrogen
+
+
+// These are from Xenobio.
+/datum/chemical_reaction/solidification/steel
+ name = "Solid Steel"
+ id = "solidsteel"
+ required_reagents = list("frostoil" = 5, "steel" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/steel
+
+
+/datum/chemical_reaction/solidification/plasteel
+ name = "Solid Plasteel"
+ id = "solidplasteel"
+ required_reagents = list("frostoil" = 10, "plasteel" = REAGENTS_PER_SHEET)
+ sheet_to_give = /obj/item/stack/material/plasteel
-/datum/chemical_reaction/phoronsolidification/on_reaction(var/datum/reagents/holder, var/created_volume)
- new /obj/item/stack/material/phoron(get_turf(holder.my_atom), created_volume)
- return
/datum/chemical_reaction/plastication
name = "Plastic"
@@ -1038,30 +1097,6 @@
/datum/chemical_reaction/aluminum_paint/send_data()
return "#F0F8FF"
-/* Slime cores */
-
-/datum/chemical_reaction/slime
- var/required = null
-
-//Slimed monkeys
-/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder)
- if(holder.my_atom && istype(holder.my_atom, required))
- return ..()
- return 0
-
-/datum/chemical_reaction/slime/golem
- name = "Prometheans"
- id = "m_promethean"
- result = null
- required_reagents = list("mutationtoxin" = 1)
- result_amount = 1
- required = /obj/item/weapon/reagent_containers/food/snacks/monkeycube
-
-/datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder)
- var/location = get_turf(holder.my_atom)
- new /obj/item/slime_cube(location)
- qdel(holder.my_atom)
-
/* Food */
/datum/chemical_reaction/food/tofu
diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm
index f28b8c6b62..908c7d6332 100644
--- a/code/modules/reagents/reagent_containers/food/snacks.dm
+++ b/code/modules/reagents/reagent_containers/food/snacks.dm
@@ -90,8 +90,6 @@
user << "\The [blocked] is in the way!"
return
- if(!istype(M, /mob/living/carbon/slime)) //If you're feeding it to someone else.
-
if (fullness <= (550 * (1 + M.overeatduration / 1000)))
user.visible_message("[user] attempts to feed [M] [src].")
else
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index bd670cc8bc..ba1df21038 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -42,8 +42,7 @@
/obj/machinery/smartfridge/,
/obj/machinery/biogenerator,
/obj/structure/frame,
- /obj/machinery/radiocarbon_spectrometer,
- /obj/machinery/xenobio2/manualinjector
+ /obj/machinery/radiocarbon_spectrometer
)
/obj/item/weapon/reagent_containers/glass/New()
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index fea929006e..536a069474 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -79,9 +79,6 @@
user << "There is already a blood sample in this syringe."
return
if(istype(target, /mob/living/carbon))
- if(istype(target, /mob/living/carbon/slime))
- user << "You are unable to locate any blood."
- return
var/amount = reagents.get_free_space()
var/mob/living/carbon/T = target
if(!T.dna)
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 28b2e0575b..228d4296ed 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -471,6 +471,8 @@
qdel(H)
/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ if(istype(mover, /obj/item/projectile))
+ return 1
if (istype(mover,/obj/item) && mover.throwing)
var/obj/item/I = mover
if(istype(I, /obj/item/projectile))
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index fd75b22eaf..55981fd672 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -592,6 +592,20 @@ other types of metals and chemistry for reagents).
build_path = /obj/item/weapon/gun/energy/floragun
sort_string = "TBAAA"
+/datum/design/item/weapon/slimebation
+ id = "slimebation"
+ req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_POWER = 3, TECH_COMBAT = 3)
+ materials = list(DEFAULT_WALL_MATERIAL = 5000)
+ build_path = /obj/item/weapon/melee/baton/slime
+ sort_string = "TBAAB"
+
+/datum/design/item/weapon/slimetaser
+ id = "slimetaser"
+ req_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_POWER = 4, TECH_COMBAT = 4)
+ materials = list(DEFAULT_WALL_MATERIAL = 5000)
+ build_path = /obj/item/weapon/gun/energy/taser/xeno
+ sort_string = "TBAAC"
+
/datum/design/item/stock_part/subspace_ansible
id = "s-ansible"
req_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2)
diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm
index 038dc7f6d4..256f4d377f 100644
--- a/code/modules/surgery/slimes.dm
+++ b/code/modules/surgery/slimes.dm
@@ -3,10 +3,10 @@
//////////////////////////////////////////////////////////////////
/datum/surgery_step/slime
- is_valid_target(mob/living/carbon/slime/target)
- return istype(target, /mob/living/carbon/slime/)
+ is_valid_target(mob/living/simple_animal/slime/target)
+ return istype(target, /mob/living/simple_animal/slime/)
- can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
return target.stat == 2
/datum/surgery_step/slime/cut_flesh
@@ -19,19 +19,19 @@
min_duration = 30
max_duration = 50
- can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
return ..() && istype(target) && target.core_removal_stage == 0
- begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ 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].")
- end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ 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.")
target.core_removal_stage = 1
- fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ 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]!")
@@ -45,19 +45,19 @@
min_duration = 30
max_duration = 50
- can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
return ..() && istype(target) && target.core_removal_stage == 1
- begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ begin_step(mob/user, mob/living/simple_animal/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].")
- end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ end_step(mob/living/user, mob/living/simple_animal/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
- fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ 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 innards with \the [tool]!", \
"Your hand slips, tearing [target]'s innards with \the [tool]!")
@@ -70,14 +70,14 @@
min_duration = 50
max_duration = 70
- can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ can_use(mob/living/user, mob/living/simple_animal/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.
- begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ begin_step(mob/user, mob/living/simple_animal/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].")
- end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ end_step(mob/living/user, mob/living/simple_animal/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.")
@@ -85,9 +85,9 @@
if(target.cores >= 0)
new target.coretype(target.loc)
if(target.cores <= 0)
- target.icon_state = "[target.colour] baby slime dead-nocore"
+ target.icon_state = "slime extracted"
- fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool)
+ fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool)
user.visible_message("[user]'s hand slips, causing \him to miss the core!", \
"Your hand slips, causing you to miss the core!")
\ No newline at end of file
diff --git a/code/modules/ventcrawl/ventcrawl.dm b/code/modules/ventcrawl/ventcrawl.dm
index 1ece024833..8978305ec2 100644
--- a/code/modules/ventcrawl/ventcrawl.dm
+++ b/code/modules/ventcrawl/ventcrawl.dm
@@ -35,8 +35,8 @@ var/list/ventcrawl_machinery = list(
remove_ventcrawl()
add_ventcrawl(loc)
-/mob/living/carbon/slime/can_ventcrawl()
- if(Victim)
+/mob/living/simple_animal/slime/can_ventcrawl()
+ if(victim)
to_chat(src, "You cannot ventcrawl while feeding.")
return FALSE
. = ..()
diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm
new file mode 100644
index 0000000000..cf3e96c52a
--- /dev/null
+++ b/code/modules/xenobio/items/extracts.dm
@@ -0,0 +1,973 @@
+// Base
+/obj/item/slime_extract
+ name = "slime extract"
+ desc = "Goo extracted from a slime, which can do different things depending on its color and what it is injected with."
+ icon = 'icons/mob/slimes.dmi'
+ icon_state = "grey slime extract"
+ force = 1
+ w_class = ITEMSIZE_TINY
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 6
+ origin_tech = list(TECH_BIO = 4)
+ var/uses = 1 // uses before it goes inert
+ var/enhanced = FALSE
+ flags = OPENCONTAINER
+
+
+/obj/item/slime_extract/New()
+ ..()
+ create_reagents(60)
+
+/obj/item/slime_extract/attackby(obj/item/O, mob/user)
+ if(istype(O, /obj/item/slimepotion/enhancer))
+ if(enhanced)
+ to_chat(user, "You cannot enhance this extract further!")
+ return ..()
+ to_chat(user, "You apply the enhancer to the slime extract. It may now be reused one more time.")
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ uses += 2
+ enhanced = TRUE
+ name = initial(name) // To remove the 'inert' part of the name.
+ qdel(O)
+ ..()
+
+/obj/item/slime_extract/examine(mob/user)
+ ..()
+ if(uses)
+ to_chat(user, "This extract has [uses] more use\s.")
+ else
+ to_chat(user, "This extract is inert.")
+
+/datum/chemical_reaction/slime
+ var/required = null
+
+/datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder)
+ if(holder.my_atom && istype(holder.my_atom, required))
+ var/obj/item/slime_extract/T = holder.my_atom
+ if(T.uses > 0)
+ return ..()
+ return FALSE
+
+/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder)
+ var/obj/item/slime_extract/T = holder.my_atom
+ T.uses--
+ if(T.uses <= 0)
+ T.visible_message("\icon[T]\The [T] goes inert.")
+ T.name = "inert [initial(T.name)]"
+
+
+// ***************
+// * Grey slimes *
+// ***************
+
+
+/obj/item/slime_extract/grey
+ name = "grey slime extract"
+ icon_state = "grey slime extract"
+ description_info = "This extract will create a new grey baby slime if injected with phoron, or some new monkey cubes if injected with blood."
+
+/datum/chemical_reaction/slime/grey_new_slime
+ name = "Slime Spawn"
+ id = "m_spawn"
+ result = null
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/grey
+
+/datum/chemical_reaction/slime/grey_new_slime/on_reaction(var/datum/reagents/holder)
+ holder.my_atom.visible_message("Infused with phoron, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
+ new /mob/living/simple_animal/slime(get_turf(holder.my_atom))
+ ..()
+
+/datum/chemical_reaction/slime/grey_monkey
+ name = "Slime Monkey"
+ id = "m_monkey"
+ result = null
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/grey
+
+/datum/chemical_reaction/slime/grey_monkey/on_reaction(var/datum/reagents/holder)
+ for(var/i = 1 to 4)
+ new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(holder.my_atom))
+ ..()
+
+
+// ****************
+// * Metal slimes *
+// ****************
+
+
+/obj/item/slime_extract/metal
+ name = "metal slime extract"
+ icon_state = "metal slime extract"
+ description_info = "This extract will create a metamorphic liquid which will transform into metallic liquid it comes into contact with, when injected with phoron. \
+ It can also create a metallic binding liquid which will force metallic liquids to mix to form alloys when solified, when injected with water."
+
+// 'Duplicates' liquid metals, consuming itself in the process.
+/datum/reagent/toxin/metamorphic_metal
+ name = "Metamorphic Metal"
+ id = "metamorphic"
+ description = "A strange metallic liquid which can rearrange itself to take the form of other metals it touches."
+ taste_description = "metallic"
+ taste_mult = 1.1
+ reagent_state = LIQUID
+ color = "#666666"
+ strength = 20
+
+/datum/chemical_reaction/slime/metal_metamorphic
+ name = "Slime Metal"
+ id = "m_metal"
+ required_reagents = list("phoron" = 5)
+ result = "metamorphic"
+ result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal.
+ required = /obj/item/slime_extract/metal
+
+
+/datum/chemical_reaction/metamorphic
+ result_amount = REAGENTS_PER_SHEET * 2
+
+
+/obj/item/weapon/reagent_containers/glass/bottle/metamorphic
+ name = "Metamorphic Metal Bottle"
+ desc = "A small bottle. Contains some really weird liquid metal."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "bottle-4"
+
+/obj/item/weapon/reagent_containers/glass/bottle/metamorphic/New()
+ ..()
+ reagents.add_reagent("metamorphic", 60)
+ update_icon()
+
+
+// This is kind of a waste since iron is in the chem dispenser but it would be inconsistent if this wasn't here.
+/datum/chemical_reaction/metamorphic/iron
+ name = "Morph into Iron"
+ id = "morph_iron"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "iron" = REAGENTS_PER_SHEET)
+ result = "iron"
+
+
+/datum/chemical_reaction/metamorphic/silver
+ name = "Morph into Silver"
+ id = "morph_silver"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "silver" = REAGENTS_PER_SHEET)
+ result = "silver"
+
+
+/datum/chemical_reaction/metamorphic/gold
+ name = "Morph into Gold"
+ id = "morph_gold"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "gold" = REAGENTS_PER_SHEET)
+ result = "gold"
+
+
+/datum/chemical_reaction/metamorphic/platinum
+ name = "Morph into Platinum"
+ id = "morph_platinum"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "platinum" = REAGENTS_PER_SHEET)
+ result = "platinum"
+
+
+/datum/chemical_reaction/metamorphic/uranium
+ name = "Morph into Uranium"
+ id = "morph_uranium"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "uranium" = REAGENTS_PER_SHEET)
+ result = "uranium"
+
+
+/datum/chemical_reaction/metamorphic/phoron
+ name = "Morph into Phoron"
+ id = "morph_phoron"
+ required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "phoron" = REAGENTS_PER_SHEET)
+ result = "phoron"
+
+
+// Creates 'alloys' which can be finalized with frost oil.
+/datum/chemical_reaction/slime/metal_binding
+ name = "Slime Binding"
+ id = "m_binding"
+ required_reagents = list("water" = 5)
+ result = "binding"
+ result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal.
+ required = /obj/item/slime_extract/metal
+
+
+/datum/reagent/toxin/binding_metal
+ name = "Binding Metal"
+ id = "binding"
+ description = "A strange metallic liquid which can bind other metals together that would otherwise require intense heat to alloy."
+ taste_description = "metallic"
+ taste_mult = 1.1
+ reagent_state = LIQUID
+ color = "#666666"
+ strength = 20
+
+/obj/item/weapon/reagent_containers/glass/bottle/binding
+ name = "Binding Metal Bottle"
+ desc = "A small bottle. Contains some really weird liquid metal."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "bottle-4"
+
+/obj/item/weapon/reagent_containers/glass/bottle/binding/New()
+ ..()
+ reagents.add_reagent("binding", 60)
+ update_icon()
+
+
+/datum/chemical_reaction/binding
+ name = "Bind into Steel"
+ id = "bind_steel"
+ result = "steel"
+ required_reagents = list("binding" = REAGENTS_PER_SHEET, "iron" = REAGENTS_PER_SHEET, "carbon" = REAGENTS_PER_SHEET)
+ result_amount = REAGENTS_PER_SHEET
+
+/datum/reagent/steel
+ name = "Liquid Steel"
+ id = "steel"
+ description = "An 'alloy' of iron and carbon, forced to bind together by another strange metallic liquid."
+ taste_description = "metallic"
+ reagent_state = LIQUID
+ color = "#888888"
+
+
+/datum/chemical_reaction/binding/plasteel // Two parts 'steel', one part platnium matches the smelter alloy recipe.
+ name = "Bind into Plasteel"
+ id = "bind_plasteel"
+ required_reagents = list("binding" = REAGENTS_PER_SHEET, "steel" = REAGENTS_PER_SHEET * 2, "platinum" = REAGENTS_PER_SHEET)
+ result = "plasteel"
+
+/datum/reagent/plasteel
+ name = "Liquid Plasteel"
+ id = "plasteel"
+ description = "An 'alloy' of iron, carbon, and platinum, forced to bind together by another strange metallic liquid."
+ taste_description = "metallic"
+ reagent_state = LIQUID
+ color = "#AAAAAA"
+
+
+// ***************
+// * Blue slimes *
+// ***************
+
+
+/obj/item/slime_extract/blue
+ name = "blue slime extract"
+ icon_state = "blue slime extract"
+ description_info = "This extract will create frost oil when injected with phoron, which can be used to solidify liquid metals. \
+ The extract can also create a slime stability agent when injected with blood, which reduces the odds of newly created slimes mutating into \
+ a different color when a slime reproduces."
+
+/datum/chemical_reaction/slime/blue_frostoil
+ name = "Slime Frost Oil"
+ id = "m_frostoil"
+ result = "frostoil"
+ required_reagents = list("phoron" = 5)
+ result_amount = 20
+ required = /obj/item/slime_extract/blue
+
+
+/datum/chemical_reaction/slime/blue_stability
+ name = "Slime Stability"
+ id = "m_stability"
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/blue
+
+/datum/chemical_reaction/slime/blue_frostoil/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/stabilizer(get_turf(holder.my_atom))
+ ..()
+
+
+// *****************
+// * Purple slimes *
+// *****************
+
+
+/obj/item/slime_extract/purple
+ name = "purple slime extract"
+ icon_state = "purple slime extract"
+ description_info = "This extract can create a slime steroid agent when injected with phoron, which increases the amount of slime extracts the processor \
+ can extract from a slime specimen."
+
+
+/datum/chemical_reaction/slime/purple_steroid
+ name = "Slime Steroid"
+ id = "m_steroid"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/purple
+
+/datum/chemical_reaction/slime/purple_steroid/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/steroid(get_turf(holder.my_atom))
+ ..()
+
+
+// *****************
+// * Orange slimes *
+// *****************
+
+
+/obj/item/slime_extract/orange
+ name = "orange slime extract"
+ icon_state = "orange slime extract"
+ description_info = "This extract creates a fire when injected with phoron, after a five second delay."
+
+/datum/chemical_reaction/slime/orange_fire
+ name = "Slime Fire"
+ id = "m_fire"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/orange
+
+/datum/chemical_reaction/slime/orange_fire/on_reaction(var/datum/reagents/holder)
+ log_and_message_admins("Orange extract reaction (fire) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
+ holder.my_atom.visible_message("\The [src] begins to vibrate violently!")
+ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)
+ spawn(5 SECONDS)
+ if(holder && holder.my_atom)
+ var/turf/simulated/T = get_turf(holder.my_atom)
+ if(!istype(T))
+ return
+
+ for(var/turf/simulated/target_turf in view(2, T))
+ target_turf.assume_gas("volatile_fuel", 33, 1500+T0C)
+ target_turf.assume_gas("oxygen", 66, 1500+T0C)
+ spawn(0)
+ target_turf.hotspot_expose(1500+T0C, 400)
+
+ playsound(T, 'sound/effects/phasein.ogg', 75, 1)
+ ..()
+
+
+// *****************
+// * Yellow slimes *
+// *****************
+
+/obj/item/slime_extract/yellow
+ name = "yellow slime extract"
+ icon_state = "yellow slime extract"
+ description_info = "This extract will create a special 10k capacity power cell that self recharges slowly over time, when injected with phoron. \
+ When injected with blood, it will create a glob of slime which glows brightly. If injected with water, it will emit a strong EMP, after a five second delay."
+
+/datum/chemical_reaction/slime/yellow_emp
+ name = "Slime EMP"
+ id = "m_emp"
+ required_reagents = list("water" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/yellow
+
+/datum/chemical_reaction/slime/yellow_emp/on_reaction(var/datum/reagents/holder)
+ log_and_message_admins("Yellow extract reaction (emp) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
+ holder.my_atom.visible_message("\The [src] begins to vibrate violently!")
+ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)
+ spawn(5 SECONDS)
+ if(holder && holder.my_atom)
+ empulse(get_turf(holder.my_atom), 2, 4, 7, 10) // As strong as a normal EMP grenade.
+ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)
+ ..()
+
+
+/datum/chemical_reaction/slime/yellow_battery
+ name = "Slime Cell"
+ id = "m_cell"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/yellow
+
+/datum/chemical_reaction/slime/yellow_battery/on_reaction(var/datum/reagents/holder)
+ new /obj/item/weapon/cell/slime(get_turf(holder.my_atom))
+ ..()
+
+
+/datum/chemical_reaction/slime/yellow_flashlight
+ name = "Slime Flashlight"
+ id = "m_flashlight"
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/yellow
+
+/datum/chemical_reaction/slime/yellow_flashlight/on_reaction(var/datum/reagents/holder)
+ new /obj/item/device/flashlight/slime(get_turf(holder.my_atom))
+ ..()
+
+// ***************
+// * Gold slimes *
+// ***************
+
+/obj/item/slime_extract/gold
+ name = "gold slime extract"
+ icon_state = "gold slime extract"
+ description_info = "This extract will create 5u liquid gold when injected with phoron."
+
+
+/datum/chemical_reaction/slime/gold_gold
+ name = "Slime Gold"
+ id = "m_gold"
+ result = "gold"
+ required_reagents = list("phoron" = 5)
+ result_amount = 5
+ required = /obj/item/slime_extract/gold
+
+
+// *****************
+// * Silver slimes *
+// *****************
+
+/obj/item/slime_extract/silver
+ name = "silver slime extract"
+ icon_state = "silver slime extract"
+ description_info = "This extract will create 5u liquid silver when injected with phoron."
+
+
+/datum/chemical_reaction/slime/silver_silver
+ name = "Slime Silver"
+ id = "m_silver"
+ result = "silver"
+ required_reagents = list("phoron" = 5)
+ result_amount = 5
+ required = /obj/item/slime_extract/silver
+
+
+// **********************
+// * Dark Purple slimes *
+// **********************
+
+
+/obj/item/slime_extract/dark_purple
+ name = "dark purple slime extract"
+ icon_state = "dark purple slime extract"
+ description_info = "This extract will create 40u liquid phoron when injected with water."
+
+
+/datum/chemical_reaction/slime/dark_purple_phoron
+ name = "Slime Phoron"
+ id = "m_phoron_harvest"
+ result = "phoron"
+ required_reagents = list("water" = 5)
+ result_amount = REAGENTS_PER_SHEET * 2
+ required = /obj/item/slime_extract/dark_purple
+
+
+// ********************
+// * Dark Blue slimes *
+// ********************
+
+
+/obj/item/slime_extract/dark_blue
+ name = "dark blue slime extract"
+ icon_state = "dark blue slime extract"
+ description_info = "This extract will massively lower the temperature of the surrounding atmosphere when injected with phoron. \
+ Slimes will suffer massive harm from the cold snap and most colors will die instantly. Other entities are also chilled, however \
+ cold-resistant armor like winter coats can protect from this. Note that the user is not immune to the extract's effects."
+
+
+/datum/chemical_reaction/slime/dark_blue_cold_snap
+ name = "Slime Cold Snap"
+ id = "m_cold_snap"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/dark_blue
+
+// This iterates over a ZAS zone's contents, so that things seperated in other zones aren't subjected to the temperature drop.
+/datum/chemical_reaction/slime/dark_blue_cold_snap/on_reaction(var/datum/reagents/holder)
+ var/turf/simulated/T = get_turf(holder.my_atom)
+ if(!T) // Nullspace lacks zones.
+ return
+
+ if(!istype(T))
+ return
+
+ var/zone/Z = T.zone
+ if(!Z) // Paranoid.
+ return
+
+ log_and_message_admins("Dark Blue extract reaction (cold snap) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
+
+ var/list/nearby_things = view(T)
+
+ // Hurt mobs.
+ for(var/mob/living/L in nearby_things)
+ var/turf/simulated/their_turf = get_turf(L)
+ if(!istype(their_turf)) // Not simulated.
+ continue
+
+ if(!(their_turf in Z.contents)) // Not in the same zone.
+ continue
+
+ if(istype(L, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = L
+ if(S.cold_damage_per_tick <= 0) // Immune to cold.
+ to_chat(S, "A chill is felt around you, however it cannot harm you.")
+ continue
+ if(S.client) // Don't instantly kill player slimes.
+ to_chat(S, "You feel your body crystalize as an intense chill overwhelms you!")
+ S.adjustToxLoss(S.cold_damage_per_tick * 2)
+ else
+ S.adjustToxLoss(S.cold_damage_per_tick * 5) // Metal slimes can survive this 'slime nuke'.
+ continue
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ var/protection = H.get_cold_protection()
+
+ if(protection < 1)
+ var/cold_factor = abs(protection - 1)
+ H.bodytemperature = between(50, (H.bodytemperature - ((H.bodytemperature - 50) * cold_factor) ), H.bodytemperature)
+
+ if(protection < 0.7)
+ to_chat(L, "A chilling wave of cold overwhelms you!")
+ else
+ to_chat(L, "A chilling wave of cold passes by you, as your armor protects you from it.")
+ continue
+
+ // Now make it very cold.
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ // This is most likely physically impossible but when has that stopped slimes before?
+ env.add_thermal_energy(-10 * 1000 * 1000) // For a moderately sized room this doesn't actually lower it that much.
+
+ playsound(T, 'sound/effects/phasein.ogg', 75, 1)
+
+ ..()
+
+
+// **************
+// * Red slimes *
+// **************
+
+/obj/item/slime_extract/red
+ name = "red slime extract"
+ icon_state = "red slime extract"
+ description_info = "This extract will create a slime mutator agent when injected with phoron, which increases a slime's odds of mutating \
+ into a different color when reproducing by 12%. Injecting with blood causes all slimes that can see the user to enrage, becoming very violent and \
+ out of control."
+
+
+/datum/chemical_reaction/slime/red_enrage
+ name = "Slime Enrage"
+ id = "m_enrage"
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/red
+
+/datum/chemical_reaction/slime/red_enrage/on_reaction(var/datum/reagents/holder)
+ for(var/mob/living/simple_animal/slime/S in view(get_turf(holder.my_atom)))
+ if(S.stat || S.docile || S.rabid)
+ continue
+
+ if(S.client) // Player slimes always have free will.
+ to_chat(S, "An intense wave of rage almost overcomes you, but you remain in control of yourself.")
+ continue
+
+ S.enrage()
+
+ log_and_message_admins("Red extract reaction (enrage) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
+
+ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)
+ ..()
+
+
+
+/datum/chemical_reaction/slime/red_mutation
+ name = "Slime Mutation"
+ id = "m_mutation"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/red
+
+/datum/chemical_reaction/slime/red_mutation/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/mutator(get_turf(holder.my_atom))
+ ..()
+
+// ***************
+// * Green slime *
+// ***************
+
+/obj/item/slime_extract/green
+ name = "green slime extract"
+ icon_state = "green slime extract"
+ description_info = "This extract will create 5u of liquid uranium when injected with phoron."
+
+/datum/chemical_reaction/slime/green_uranium
+ name = "Slime Uranium"
+ id = "m_uranium"
+ result = "uranium"
+ required_reagents = list("phoron" = 5)
+ result_amount = 5
+ required = /obj/item/slime_extract/green
+
+
+// ***************
+// * Pink slimes *
+// ***************
+
+/obj/item/slime_extract/pink
+ name = "pink slime extract"
+ icon_state = "pink slime extract"
+ description_info = "This extract will create 20u of blood clotting agent if injected with blood. It can also create 20u of bone binding agent if injected \
+ with phoron. When injected with water, it will create an organ-mending agent. The slime medications have a very low threshold for overdosage, however."
+
+
+/datum/chemical_reaction/slime/pink_clotting
+ name = "Slime Clotting Med"
+ id = "m_clotting"
+ result = "slime_bleed_fixer"
+ required_reagents = list("blood" = 5)
+ result_amount = 30
+ required = /obj/item/slime_extract/pink
+
+
+/datum/chemical_reaction/slime/pink_bone_fix
+ name = "Slime Bone Med"
+ id = "m_bone_fixer"
+ result = "slime_bone_fixer"
+ required_reagents = list("phoron" = 5)
+ result_amount = 30
+ required = /obj/item/slime_extract/pink
+
+
+/datum/chemical_reaction/slime/pink_organ_fix
+ name = "Slime Organ Med"
+ id = "m_organ_fixer"
+ result = "slime_organ_fixer"
+ required_reagents = list("water" = 5)
+ result_amount = 30
+ required = /obj/item/slime_extract/pink
+
+
+/datum/reagent/myelamine/slime
+ name = "Agent A"
+ id = "slime_bleed_fixer"
+ description = "A slimy liquid which appears to rapidly clot internal hemorrhages by increasing the effectiveness of platelets at low quantities. Toxic in high quantities."
+ taste_description = "slime"
+ overdose = 5
+
+/datum/reagent/osteodaxon/slime
+ name = "Agent B"
+ id = "slime_bone_fixer"
+ description = "A slimy liquid which can be used to heal bone fractures at low quantities. Toxic in high quantities."
+ taste_description = "slime"
+ overdose = 5
+
+/datum/reagent/peridaxon/slime
+ name = "Agent C"
+ id = "slime_organ_fixer"
+ description = "A slimy liquid which is used to encourage recovery of internal organs and nervous systems in low quantities. Toxic in high quantities."
+ taste_description = "slime"
+ overdose = 5
+
+
+// **************
+// * Oil slimes *
+// **************
+
+/obj/item/slime_extract/oil
+ name = "oil slime extract"
+ icon_state = "oil slime extract"
+ description_info = "This extract cause a moderately sized delayed explosion if injected with phoron. The delay is five seconds. Extract enhancers will \
+ increase the power of the explosion instead of allowing for multiple explosions."
+
+
+/datum/chemical_reaction/slime/oil_griff
+ name = "Slime Explosion"
+ id = "m_boom"
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/oil
+
+
+/datum/chemical_reaction/slime/oil_griff/on_reaction(var/datum/reagents/holder)
+ ..()
+ var/obj/item/slime_extract/E = holder.my_atom
+ var/power = 1
+ if(E.enhanced)
+ power++
+ E.uses = 0
+
+ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)
+ holder.my_atom.visible_message("\The [holder.my_atom] begins to vibrate violently!")
+ log_and_message_admins("Oil extract reaction (explosion) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
+
+ spawn(5 SECONDS)
+ if(holder && holder.my_atom)
+ explosion(get_turf(holder.my_atom), 1 * power, 3 * power, 6 * power)
+
+ if(holder && holder.my_atom) // Explosion may or may not have deleted the extract.
+ qdel(holder.my_atom)
+
+// ********************
+// * Bluespace slimes *
+// ********************
+
+/obj/item/slime_extract/bluespace
+ name = "bluespace slime extract"
+ icon_state = "bluespace slime extract"
+ description_info = "This extract creates slime crystals. When injected with water, it creates five 'lesser' slime crystals, which allow for limited \
+ short ranged, random teleporting. When injected with phoron, it creates one 'greater' slime crystal, which allows for a one time precise teleport to \
+ a specific area."
+
+/datum/chemical_reaction/slime/bluespace_lesser
+ name = "Slime Lesser Tele"
+ id = "m_tele_lesser"
+ required_reagents = list("water" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/bluespace
+
+/datum/chemical_reaction/slime/bluespace_lesser/on_reaction(var/datum/reagents/holder)
+ for(var/i = 1 to 5)
+ new /obj/item/slime_crystal(get_turf(holder.my_atom))
+ ..()
+
+/datum/chemical_reaction/slime/bluespace_greater
+ name = "Slime Greater Tele"
+ id = "m_tele_lesser"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/bluespace
+
+/datum/chemical_reaction/slime/bluespace_greater/on_reaction(var/datum/reagents/holder)
+ new /obj/item/weapon/disposable_teleporter/slime(get_turf(holder.my_atom))
+ ..()
+
+// *******************
+// * Cerulean slimes *
+// *******************
+
+/obj/item/slime_extract/cerulean
+ name = "cerulean slime extract"
+ icon_state = "cerulean slime extract"
+ description_info = "This extract creates a slime extract enhancer agent, when injected with phoron. The agent allows an extract to have more \
+ 'charges' before it goes inert."
+
+
+/datum/chemical_reaction/slime/cerulean_enhancer
+ name = "Slime Enhancer"
+ id = "m_enhancer"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/cerulean
+
+/datum/chemical_reaction/slime/cerulean_enhance/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom))
+ ..()
+
+// ****************
+// * Amber slimes *
+// ****************
+
+/obj/item/slime_extract/amber
+ name = "amber slime extract"
+ icon_state = "amber slime extract"
+ description_info = "This extract creates a slime feeding agent when injected with phoron, which will instantly feed the slime and make it reproduce. When \
+ injected with water, it will create a very delicious and filling product."
+
+
+/datum/chemical_reaction/slime/amber_slimefood
+ name = "Slime Feeding"
+ id = "m_slime_food"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/amber
+
+/datum/chemical_reaction/slime/amber_slimefood/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/feeding(get_turf(holder.my_atom))
+ ..()
+
+
+/datum/chemical_reaction/slime/amber_peoplefood
+ name = "Slime Food"
+ id = "m_people_food"
+ required_reagents = list("water" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/amber
+
+/datum/chemical_reaction/slime/amber_peoplefood/on_reaction(var/datum/reagents/holder)
+ new /obj/item/weapon/reagent_containers/food/snacks/slime(get_turf(holder.my_atom))
+ ..()
+
+
+// *******************
+// * Sapphire slimes *
+// *******************
+// Renamed from adamantine.
+
+/obj/item/slime_extract/sapphire
+ name = "sapphire slime extract"
+ icon_state = "sapphire slime extract"
+ description_info = "This extract will create one 'slime cube' when injected with phoron. The slime cube is needed to create a Promethean."
+
+
+/datum/chemical_reaction/slime/sapphire_promethean
+ name = "Slime Promethean"
+ id = "m_promethean"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/sapphire
+
+/datum/chemical_reaction/slime/sapphire_promethean/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slime_cube(get_turf(holder.my_atom))
+ ..()
+
+// ***************
+// * Ruby slimes *
+// ***************
+
+/obj/item/slime_extract/ruby
+ name = "ruby slime extract"
+ icon_state = "ruby slime extract"
+ description_info = "This extract will cause all entities close to the extract to become stronger for ten minutes, when injected with phoron. \
+ When injected with blood, makes a slime loyalty agent which will make the slime fight other dangerous entities but not station crew."
+
+/datum/chemical_reaction/slime/ruby_swole
+ name = "Slime Strength"
+ id = "m_strength"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/ruby
+
+/datum/chemical_reaction/slime/ruby_swole/on_reaction(var/datum/reagents/holder)
+ for(var/mob/living/L in range(1, holder.my_atom))
+ L.add_modifier(/datum/modifier/slime_strength, 10 MINUTES, src)
+ ..()
+
+
+/datum/modifier/slime_strength
+ name = "slime strength"
+ desc = "You feel much stronger than usual."
+ mob_overlay_state = "pink_sparkles"
+
+ on_created_text = "Twinkling spores of goo surround you. It makes you feel stronger and more robust."
+ on_expired_text = "The spores of goo have faded, and you feel your strength returning to what it was before."
+ stacks = MODIFIER_STACK_EXTEND
+
+ max_health_flat = 50
+ outgoing_melee_damage_percent = 2
+ disable_duration_percent = 0.5
+ incoming_damage_percent = 0.75
+
+
+/datum/chemical_reaction/slime/ruby_loyalty
+ name = "Slime Loyalty"
+ id = "m_strength"
+ required_reagents = list("blood" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/ruby
+
+/datum/chemical_reaction/slime/ruby_loyalty/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/loyalty(get_turf(holder.my_atom))
+ ..()
+
+
+// *****************
+// * Emerald slime *
+// *****************
+
+/obj/item/slime_extract/emerald
+ name = "emerald slime extract"
+ icon_state = "emerald slime extract"
+ description_info = "This extract will cause all entities close to the extract to become more agile for ten minutes, when injected with phoron."
+
+/datum/chemical_reaction/slime/emerald_fast
+ name = "Slime Agility"
+ id = "m_agility"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/emerald
+
+/datum/chemical_reaction/slime/emerald_fast/on_reaction(var/datum/reagents/holder)
+ for(var/mob/living/L in range(1, holder.my_atom))
+ L.add_modifier(/datum/modifier/slime_agility, 10 MINUTES, src)
+ ..()
+
+/datum/modifier/slime_agility
+ name = "slime agility"
+ desc = "You feel much faster than usual."
+ mob_overlay_state = "green_sparkles"
+
+ on_created_text = "Twinkling spores of goo surround you. It makes you feel fast and more agile."
+ on_expired_text = "The spores of goo have faded, and you feel your agility returning to what it was before."
+ stacks = MODIFIER_STACK_EXTEND
+
+ evasion = 2
+ slowdown = -1
+
+
+// *********************
+// * Light Pink slimes *
+// *********************
+
+/obj/item/slime_extract/light_pink
+ name = "light pink slime extract"
+ icon_state = "light pink slime extract"
+ description_info = "This extract creates a slime docility agent when injected with water, which will make the slime be harmless forever. \
+ When injected with phoron, it instead creates a slime friendship agent, which makes the slime consider the user their ally. The agent \
+ might be useful on other specimens as well."
+
+/datum/chemical_reaction/slime/light_pink_docility
+ name = "Slime Docility"
+ id = "m_docile"
+ required_reagents = list("water" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/light_pink
+
+/datum/chemical_reaction/slime/light_pink_docility/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/docility(get_turf(holder.my_atom))
+ ..()
+
+
+/datum/chemical_reaction/slime/light_pink_friendship
+ name = "Slime Friendship"
+ id = "m_friendship"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/light_pink
+
+/datum/chemical_reaction/slime/light_pink_friendship/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/friendship(get_turf(holder.my_atom))
+ ..()
+
+
+// ******************
+// * Rainbow slimes *
+// ******************
+
+
+/obj/item/slime_extract/rainbow
+ name = "rainbow slime extract"
+ icon_state = "rainbow slime extract"
+ description_info = "This extract will create a baby slime of a random color when injected with phoron, or a slime unification agent if injected with water, \
+ which makes slimes stop attacking other slime colors."
+
+
+/datum/chemical_reaction/slime/rainbow_random_slime
+ name = "Slime Random Slime"
+ id = "m_rng_slime"
+ required_reagents = list("phoron" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/rainbow
+
+/datum/chemical_reaction/slime/rainbow_random_slime/on_reaction(var/datum/reagents/holder)
+ var/list/forbidden_types = list(
+ /mob/living/simple_animal/slime/rainbow/kendrick
+ )
+ var/list/potential_types = typesof(/mob/living/simple_animal/slime) - forbidden_types
+ var/slime_type = pick(potential_types)
+ new slime_type(get_turf(holder.my_atom))
+ ..()
+
+
+/datum/chemical_reaction/slime/rainbow_unity
+ name = "Slime Unity"
+ id = "m_unity"
+ required_reagents = list("water" = 5)
+ result_amount = 1
+ required = /obj/item/slime_extract/rainbow
+
+/datum/chemical_reaction/slime/rainbow_unity/on_reaction(var/datum/reagents/holder)
+ new /obj/item/slimepotion/unity(get_turf(holder.my_atom))
+ ..()
+
+
+
diff --git a/code/modules/xenobio/items/slime_objects.dm b/code/modules/xenobio/items/slime_objects.dm
new file mode 100644
index 0000000000..03b048a49b
--- /dev/null
+++ b/code/modules/xenobio/items/slime_objects.dm
@@ -0,0 +1,128 @@
+// Slime cube lives here. Makes Prometheans.
+/obj/item/slime_cube
+ name = "slimy monkey cube"
+ desc = "Wonder what might come out of this."
+ icon = 'icons/mob/slime2.dmi'
+ icon_state = "slime cube"
+ description_info = "Use in your hand to attempt to create a Promethean. It functions similarly to a positronic brain, in that a ghost is needed to become the Promethean."
+ var/searching = 0
+
+/obj/item/slime_cube/attack_self(mob/user as mob)
+ if(!searching)
+ user << "You stare at the slimy cube, watching as some activity occurs."
+ icon_state = "slime cube active"
+ searching = 1
+ request_player()
+ spawn(60 SECONDS)
+ reset_search()
+
+// Sometime down the road it would be great to make all of these 'ask ghosts if they want to be X' procs into a generic datum.
+/obj/item/slime_cube/proc/request_player()
+ for(var/mob/observer/dead/O in player_list)
+ if(!O.MayRespawn())
+ continue
+ if(O.client)
+ if(O.client.prefs.be_special & BE_ALIEN)
+ question(O.client)
+
+/obj/item/slime_cube/proc/question(var/client/C)
+ spawn(0)
+ if(!C)
+ return
+ var/response = alert(C, "Someone is requesting a soul for a promethean. Would you like to play as one?", "Promethean request", "Yes", "No", "Never for this round")
+ if(response == "Yes")
+ response = alert(C, "Are you sure you want to play as a promethean?", "Promethean request", "Yes", "No")
+ if(!C || 2 == searching)
+ return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
+ if(response == "Yes")
+ transfer_personality(C.mob)
+ else if(response == "Never for this round")
+ C.prefs.be_special ^= BE_ALIEN
+
+/obj/item/slime_cube/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
+ icon_state = "slime cube"
+ if(searching == 1)
+ searching = 0
+ var/turf/T = get_turf_or_move(src.loc)
+ for (var/mob/M in viewers(T))
+ M.show_message("The activity in the cube dies down. Maybe it will spark another time.")
+
+/obj/item/slime_cube/proc/transfer_personality(var/mob/candidate)
+ announce_ghost_joinleave(candidate, 0, "They are a promethean now.")
+ src.searching = 2
+ var/mob/living/carbon/human/S = new(get_turf(src))
+ S.client = candidate.client
+ to_chat(S, "You are a promethean, brought into existence on [station_name()].")
+ S.mind.assigned_role = "Promethean"
+ S.set_species("Promethean")
+ S.shapeshifter_set_colour("#2398FF")
+ visible_message("The monkey cube suddenly takes the shape of a humanoid!")
+ var/newname = sanitize(input(S, "You are a Promethean. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN)
+ if(newname)
+ S.real_name = newname
+ S.name = S.real_name
+ S.dna.real_name = newname
+ if(S.mind)
+ S.mind.name = S.name
+ qdel(src)
+
+
+
+// More or less functionally identical to the telecrystal tele.
+/obj/item/slime_crystal
+ name = "lesser slime cystal"
+ desc = "A small, gooy crystal."
+ description_info = "This will teleport you to a mostly 'safe' tile when used in-hand, consuming the slime crystal. \
+ It can also teleport someone else, by throwing it at them or attacking them with it."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "slime_crystal_small"
+ w_class = ITEMSIZE_TINY
+ origin_tech = list(TECH_MAGNETS = 6, TECH_BLUESPACE = 3)
+ force = 1 //Needs a token force to ensure you can attack because for some reason you can't attack with 0 force things
+
+/obj/item/slime_crystal/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
+ target.visible_message("\The [target] has been teleported with \the [src] by \the [user]!")
+ safe_blink(target, 14)
+ qdel(src)
+
+/obj/item/slime_crystal/attack_self(mob/user)
+ user.visible_message("\The [user] teleports themselves with \the [src]!")
+ safe_blink(user, 14)
+ qdel(src)
+
+/obj/item/slime_crystal/throw_impact(atom/movable/AM)
+ if(!istype(AM))
+ return
+
+ if(AM.anchored)
+ return
+
+ AM.visible_message("\The [AM] has been teleported with \the [src]!")
+ safe_blink(AM, 14)
+ qdel(src)
+
+/obj/item/weapon/disposable_teleporter/slime
+ name = "greater slime crystal"
+ desc = "A larger, gooier crystal."
+ description_info = "This will teleport you to a specific area once, when used in-hand."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "slime_crystal_large"
+ uses = 1
+ w_class = ITEMSIZE_SMALL
+ origin_tech = list(TECH_MAGNETS = 5, TECH_BLUESPACE = 4)
+
+
+
+// Very filling food.
+/obj/item/weapon/reagent_containers/food/snacks/slime
+ name = "slimy clump"
+ desc = "A glob of slime that is thick as honey. For the brave Xenobiologist."
+ icon_state = "honeycomb"
+ filling_color = "#FFBB00"
+ center_of_mass = list("x"=17, "y"=10)
+ nutriment_amt = 25 // Very filling.
+ nutriment_desc = list("slime" = 10, "sweetness" = 10, "bliss" = 5)
+
+/obj/item/weapon/reagent_containers/food/snacks/slime/New()
+ ..()
+ bitesize = 5
\ No newline at end of file
diff --git a/code/modules/xenobio/items/slimepotions.dm b/code/modules/xenobio/items/slimepotions.dm
new file mode 100644
index 0000000000..df03fdab6f
--- /dev/null
+++ b/code/modules/xenobio/items/slimepotions.dm
@@ -0,0 +1,255 @@
+// These things get applied to slimes to do things.
+
+/obj/item/slimepotion
+ name = "slime agent"
+ desc = "A flask containing strange, mysterious substances excreted by a slime."
+ icon = 'icons/obj/chemical.dmi'
+ w_class = ITEMSIZE_TINY
+ origin_tech = list(TECH_BIO = 4)
+
+// This is actually applied to an extract, so no attack() overriding needed.
+/obj/item/slimepotion/enhancer
+ name = "extract enhancer agent"
+ desc = "A potent chemical mix that will give a slime extract an additional two uses."
+ icon_state = "potpurple"
+ description_info = "This will even work on inert slime extracts, if it wasn't enhanced before. Extracts enhanced cannot be enhanced again."
+
+// Makes slimes less likely to mutate.
+/obj/item/slimepotion/stabilizer
+ name = "slime stabilizer agent"
+ desc = "A potent chemical mix that will reduce the chance of a slime mutating."
+ icon_state = "potcyan"
+ description_info = "The slime needs to be alive for this to work. It will reduce the chances of mutation by 15%."
+
+/obj/item/slimepotion/stabilizer/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The stabilizer only works on slimes!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The slime is dead!")
+ return ..()
+ if(M.mutation_chance == 0)
+ to_chat(user, "The slime already has no chance of mutating!")
+ return ..()
+
+ to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.")
+ M.mutation_chance = between(0, M.mutation_chance - 15, 100)
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+
+// The opposite, makes the slime more likely to mutate.
+/obj/item/slimepotion/mutator
+ name = "slime mutator agent"
+ desc = "A potent chemical mix that will increase the chance of a slime mutating."
+ description_info = "The slime needs to be alive for this to work. It will increase the chances of mutation by 12%."
+ icon_state = "potred"
+
+/obj/item/slimepotion/mutator/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The mutator only works on slimes!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The slime is dead!")
+ return ..()
+ if(M.mutation_chance == 100)
+ to_chat(user, "The slime is already guaranteed to mutate!")
+ return ..()
+
+ to_chat(user, "You feed the slime the mutator. It is now more likely to mutate.")
+ M.mutation_chance = between(0, M.mutation_chance + 12, 100)
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+
+// Makes the slime friendly forever.
+/obj/item/slimepotion/docility
+ name = "docility agent"
+ desc = "A potent chemical mix that nullifies a slime's hunger, causing it to become docile and tame. It might also work on other creatures?"
+ icon_state = "potlightpink"
+ description_info = "The target needs to be alive, not already passive, and have animal-like intelligence."
+
+/obj/item/slimepotion/docility/attack(mob/living/simple_animal/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The agent only works on creatures!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "\The [M] is dead!")
+ return ..()
+
+ // Slimes.
+ if(istype(M, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = M
+ if(S.docile)
+ to_chat(user, "The slime is already docile!")
+ return ..()
+
+ S.pacify()
+ S.nutrition = 700
+ to_chat(M, "You absorb the agent and feel your intense desire to feed melt away.")
+ to_chat(user, "You feed the slime the agent, removing its hunger and calming it.")
+
+ // Simple Animals.
+ else if(istype(M, /mob/living/simple_animal))
+ var/mob/living/simple_animal/SA = M
+ if(SA.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc.
+ to_chat(user, "\The [SA] is too intellient for this to affect them.")
+ return ..()
+ if(!SA.hostile)
+ to_chat(user, "\The [SA] is already passive!")
+ return ..()
+
+ SA.hostile = FALSE
+ to_chat(M, "You consume the agent and feel a serene sense of peace.")
+ to_chat(user, "You feed \the [SA] the agent, calming it.")
+
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore.
+ var/newname = copytext(sanitize(input(user, "Would you like to give \the [M] a name?", "Name your new pet", M.name) as null|text),1,MAX_NAME_LEN)
+
+ if(newname)
+ M.name = newname
+ M.real_name = newname
+ qdel(src)
+
+
+// Makes slimes make more extracts.
+/obj/item/slimepotion/steroid
+ name = "slime steroid agent"
+ desc = "A potent chemical mix that will increase the amount of extracts obtained from harvesting a slime."
+ description_info = "The slime needs to be alive and not an adult for this to work. It will increase the amount of extracts gained by one, up to a max of five per slime. \
+ Extra extracts are not passed down to offspring when reproducing."
+ icon_state = "potpurple"
+
+/obj/item/slimepotion/steroid/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The steroid only works on slimes!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The slime is dead!")
+ return ..()
+ if(M.is_adult) //Can't steroidify adults
+ to_chat(user, "Only baby slimes can use the steroid!")
+ return ..()
+ if(M.cores >= 5)
+ to_chat(user, "The slime already has the maximum amount of extract!")
+ return ..()
+
+ to_chat(user, "You feed the slime the steroid. It will now produce one more extract.")
+ M.cores++
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+
+// Makes slimes not try to murder other slime colors.
+/obj/item/slimepotion/unity
+ name = "slime unity agent"
+ desc = "A potent chemical mix that makes the slime feel and be seen as all the colors at once, and as a result not be considered an enemy to any other color."
+ description_info = "The slime needs to be alive for this to work. Slimes unified will not attack or be attacked by other colored slimes, and this will \
+ carry over to offspring when reproducing."
+ icon_state = "potpink"
+
+/obj/item/slimepotion/unity/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The agent only works on slimes!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The slime is dead!")
+ return ..()
+ if(M.unity == TRUE)
+ to_chat(user, "The slime is already unified!")
+ return ..()
+
+ to_chat(user, "You feed the slime the agent. It will now be friendly to all other slimes.")
+ to_chat(M, "\The [user] feeds you \the [src], and you suspect that all the other slimes will be \
+ your friends, at least if you don't attack them first.")
+ M.unify()
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+// Makes slimes not kill (most) humanoids but still fight spiders/carp/bears/etc.
+/obj/item/slimepotion/loyalty
+ name = "slime loyalty agent"
+ desc = "A potent chemical mix that makes an animal deeply loyal to the species of whoever applies this, and will attack threats to them."
+ description_info = "The slime or other animal needs to be alive for this to work. The slime this is applied to will have their 'faction' change to \
+ the user's faction, which means the slime will attack things that are hostile to the user's faction, such as carp, spiders, and other slimes."
+ icon_state = "potred"
+
+/obj/item/slimepotion/loyalty/attack(mob/living/simple_animal/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The agent only works on animals!")
+ return ..()
+ if(M.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc.
+ to_chat(user, "\The [M] is too intellient for this to affect them.")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The animal is dead!")
+ return ..()
+ if(M.faction == user.faction)
+ to_chat(user, "\The [M] is already loyal to your species!")
+ return ..()
+
+ to_chat(user, "You feed \the [M] the agent. It will now try to murder things that want to murder you instead.")
+ to_chat(M, "\The [user] feeds you \the [src], and feel that the others will regard you as an outsider now.")
+ M.faction = user.faction
+ M.attack_same = FALSE
+ M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore.
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+
+// User befriends the slime with this.
+/obj/item/slimepotion/friendship
+ name = "slime friendship agent"
+ desc = "A potent chemical mix that makes an animal deeply loyal to the the specific entity which feeds them this agent."
+ description_info = "The slime or other animal needs to be alive for this to work. The slime this is applied to will consider the user \
+ their 'friend', and will never attack them. This might also work on other things besides slimes."
+ icon_state = "potlightpink"
+
+/obj/item/slimepotion/friendship/attack(mob/living/simple_animal/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The agent only works on animals!")
+ return ..()
+ if(M.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc.
+ to_chat(user, "\The [M] is too intellient for this to affect them.")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The animal is dead!")
+ return ..()
+ if(user in M.friends)
+ to_chat(user, "\The [M] is already loyal to you!")
+ return ..()
+
+ to_chat(user, "You feed \the [M] the agent. It will now be your best friend.")
+ to_chat(M, "\The [user] feeds you \the [src], and feel that \the [user] wants to be best friends with you.")
+ if(isslime(M))
+ var/mob/living/simple_animal/slime/S = M
+ S.befriend(user)
+ else
+ M.friends.Add(user)
+ M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore.
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
+
+
+// Feeds the slime instantly.
+/obj/item/slimepotion/feeding
+ name = "slime feeding agent"
+ desc = "A potent chemical mix that will instantly sediate the slime."
+ description_info = "The slime needs to be alive for this to work. It will instantly grow the slime enough to reproduce."
+ icon_state = "potyellow"
+
+/obj/item/slimepotion/feeding/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!istype(M))
+ to_chat(user, "The mutator only works on slimes!")
+ return ..()
+ if(M.stat == DEAD)
+ to_chat(user, "The slime is dead!")
+ return ..()
+
+ to_chat(user, "You feed the slime the feeding agent. It will now instantly reproduce.")
+ M.make_adult()
+ M.amount_grown = 10
+ M.reproduce()
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ qdel(src)
diff --git a/code/modules/xenobio/items/weapons.dm b/code/modules/xenobio/items/weapons.dm
new file mode 100644
index 0000000000..3fdc758f84
--- /dev/null
+++ b/code/modules/xenobio/items/weapons.dm
@@ -0,0 +1,105 @@
+/obj/item/weapon/melee/baton/slime
+ name = "slimebaton"
+ desc = "A modified stun baton designed to stun slimes and other lesser xeno lifeforms for handling."
+ icon_state = "slimebaton"
+ item_state = "slimebaton"
+ slot_flags = SLOT_BELT
+ force = 9
+ lightcolor = "#33CCFF"
+ origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 4)
+ agonyforce = 10 //It's not supposed to be great at stunning human beings.
+ hitcost = 48 //Less zap for less cost
+ description_info = "This baton will stun a slime or other lesser lifeform for about five seconds, if hit with it while on."
+
+/obj/item/weapon/melee/baton/slime/attack(mob/M, mob/user, hit_zone)
+ // Simple Animals.
+ if(istype(M, /mob/living/simple_animal/slime) && status)
+ var/mob/living/simple_animal/SA = M
+ if(SA.intelligence_level <= SA_ANIMAL) // So it doesn't stun hivebots or syndies.
+ SA.Weaken(5)
+ if(isslime(SA))
+ var/mob/living/simple_animal/slime/S = SA
+ S.adjust_discipline(3)
+
+ // Prometheans.
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.species && H.species.name == "Promethean" && status)
+ var/agony_to_apply = 60 - agonyforce
+ H.apply_damage(agony_to_apply, HALLOSS)
+ ..()
+
+/obj/item/weapon/melee/baton/slime/loaded/New()
+ ..()
+ bcell = new/obj/item/weapon/cell/device(src)
+ update_icon()
+ return
+
+
+// Research borg's version
+/obj/item/weapon/melee/baton/slime/robot
+ hitcost = 200
+
+/obj/item/weapon/melee/baton/slime/robot/attack_self(mob/user)
+ //try to find our power cell
+ var/mob/living/silicon/robot/R = loc
+ if (istype(R))
+ bcell = R.cell
+ return ..()
+
+/obj/item/weapon/melee/baton/slime/robot/attackby(obj/item/weapon/W, mob/user)
+ return
+
+
+// Xeno stun gun + projectile
+/obj/item/weapon/gun/energy/taser/xeno
+ name = "xeno taser gun"
+ desc = "Straight out of NT's testing laboratories, this small gun is used to subdue non-humanoid xeno life forms. \
+ While marketed towards handling slimes, it may be useful for other creatures."
+ desc = "An easy to use weapon designed by NanoTrasen, for NanoTrasen. This weapon is designed to subdue lesser \
+ xeno lifeforms at a distance. It is ineffective at stunning larger lifeforms such as humanoids."
+ icon_state = "taserold"
+ fire_sound = 'sound/weapons/taser2.ogg'
+ charge_cost = 120 // Twice as many shots.
+ projectile_type = /obj/item/projectile/beam/stun/xeno
+ accuracy = 2 // Make it a bit easier to hit the slimes.
+ description_info = "This gun will stun a slime or other lesser lifeform for about two seconds, if hit with the projectile it fires."
+
+/obj/item/weapon/gun/energy/taser/xeno/robot // Borg version
+ self_recharge = 1
+ use_external_power = 1
+ recharge_time = 3
+
+
+/obj/item/projectile/beam/stun/xeno
+ icon_state = "omni"
+ agony = 4
+ nodamage = TRUE
+ // For whatever reason the projectile qdels itself early if this is on, meaning on_hit() won't be called on prometheans.
+ // Probably for the best so that it doesn't harm the slime.
+ taser_effect = FALSE
+
+ muzzle_type = /obj/effect/projectile/laser_omni/muzzle
+ tracer_type = /obj/effect/projectile/laser_omni/tracer
+ impact_type = /obj/effect/projectile/laser_omni/impact
+
+/obj/item/projectile/beam/stun/xeno/on_hit(var/atom/target, var/blocked = 0)
+ if(istype(target, /mob/living))
+ var/mob/living/L = target
+
+ // Simple Animals.
+ if(istype(L, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/SA = L
+ if(SA.intelligence_level <= SA_ANIMAL) // So it doesn't stun hivebots or syndies.
+ SA.Weaken(2) // Less powerful since its ranged, and therefore safer.
+ if(isslime(SA))
+ var/mob/living/simple_animal/slime/S = SA
+ S.adjust_discipline(2)
+
+ // Prometheans.
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.species && H.species.name == "Promethean")
+ var/agony_to_apply = 60 - agony
+ H.apply_damage(agony_to_apply, HALLOSS)
+ ..()
\ No newline at end of file
diff --git a/code/modules/xenobio/machinery/processor.dm b/code/modules/xenobio/machinery/processor.dm
new file mode 100644
index 0000000000..56b7cee3bf
--- /dev/null
+++ b/code/modules/xenobio/machinery/processor.dm
@@ -0,0 +1,118 @@
+// This is specifically for slimes since we don't have a 'normal' processor now.
+// Feel free to rename it if that ever changes.
+
+/obj/machinery/processor
+ name = "slime processor"
+ desc = "An industrial grinder used to automate the process of slime core extraction. It can also recycle biomatter."
+ icon = 'icons/obj/kitchen.dmi'
+ icon_state = "processor1"
+ density = TRUE
+ anchored = TRUE
+ var/processing = FALSE // So I heard you like processing.
+ var/list/to_be_processed = list()
+ var/monkeys_recycled = 0
+ description_info = "Clickdrag dead slimes or monkeys to it to insert them. It will make a new monkey cube for every four monkeys it processes."
+
+/obj/item/weapon/circuitboard/processor
+ name = T_BOARD("slime processor")
+ build_path = /obj/machinery/processor
+ origin_tech = list(TECH_DATA = 2, TECH_BIO = 2)
+
+/obj/machinery/processor/attack_hand(mob/living/user)
+ if(processing)
+ to_chat(user, "The processor is in the process of processing!")
+ return
+ if(to_be_processed.len)
+ spawn(1)
+ begin_processing()
+ else
+ to_chat(user, "The processor is empty.")
+ playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
+ return
+
+// Verb to remove everything.
+/obj/machinery/processor/verb/eject()
+ set category = "Object"
+ set name = "Eject Processor"
+ set src in oview(1)
+
+ if(usr.stat || !usr.canmove || usr.restrained())
+ return
+ empty()
+ add_fingerprint(usr)
+ return
+
+// Ejects all the things out of the machine.
+/obj/machinery/processor/proc/empty()
+ for(var/atom/movable/AM in to_be_processed)
+ to_be_processed.Remove(AM)
+ AM.forceMove(get_turf(src))
+
+// Ejects all the things out of the machine.
+/obj/machinery/processor/proc/insert(var/atom/movable/AM, var/mob/living/user)
+ if(!Adjacent(AM))
+ return
+ if(!can_insert(AM))
+ to_chat(user, "\The [src] cannot process \the [AM] at this time.")
+ playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
+ return
+ to_be_processed.Add(AM)
+ AM.forceMove(src)
+ visible_message("\the [user] places [AM] inside \the [src].")
+
+/obj/machinery/processor/proc/begin_processing()
+ if(processing)
+ return // Already doing it.
+ processing = TRUE
+ playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1)
+ for(var/atom/movable/AM in to_be_processed)
+ extract(AM)
+ sleep(1 SECONDS)
+
+ while(monkeys_recycled >= 4)
+ new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(src))
+ playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ monkeys_recycled -= 4
+ sleep(1 SECOND)
+
+ processing = FALSE
+ playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
+
+/obj/machinery/processor/proc/extract(var/atom/movable/AM)
+ if(istype(AM, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = AM
+ while(S.cores)
+ new S.coretype(get_turf(src))
+ playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ S.cores--
+ sleep(1 SECOND)
+ to_be_processed.Remove(S)
+ qdel(S)
+
+ if(istype(AM, /mob/living/carbon/human))
+ var/mob/living/carbon/human/M = AM
+ playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ to_be_processed.Remove(M)
+ qdel(M)
+ monkeys_recycled++
+ sleep(1 SECOND)
+
+/obj/machinery/processor/proc/can_insert(var/atom/movable/AM)
+ if(istype(AM, /mob/living/simple_animal/slime))
+ var/mob/living/simple_animal/slime/S = AM
+ if(S.stat != DEAD)
+ return FALSE
+ return TRUE
+ if(istype(AM, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = AM
+ if(!istype(H.species, /datum/species/monkey))
+ return FALSE
+ if(H.stat != DEAD)
+ return FALSE
+ return TRUE
+ return FALSE
+
+/obj/machinery/processor/MouseDrop_T(var/atom/movable/AM, var/mob/living/user)
+ if(user.stat || user.incapacitated(INCAPACITATION_DISABLED) || !istype(user))
+ return
+ insert(AM, user)
\ No newline at end of file
diff --git a/code/modules/xenobio2/tools/slime_handling_tools.dm b/code/modules/xenobio2/tools/slime_handling_tools.dm
index 050a97bc41..e69de29bb2 100644
--- a/code/modules/xenobio2/tools/slime_handling_tools.dm
+++ b/code/modules/xenobio2/tools/slime_handling_tools.dm
@@ -1,70 +0,0 @@
-/* What this file contains:
-
- * A specialized stun prod, for handling fiesty slimes
-
- * A specialized stun gun, for handling many fiesty slimes
-
- * A stun projectile for handling xenomorphs.
-
-*/
-/obj/item/weapon/melee/baton/slime
- name = "slimebaton"
- desc = "A modified stun baton designed to stun slimes for handling."
- icon_state = "slimebaton"
- item_state = "slimebaton"
- slot_flags = SLOT_BELT
- force = 9
- lightcolor = "#33CCFF"
- origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 4)
- agonyforce = 10 //It's not supposed to be great at stunning human beings.
- var/stasisforce = 60 //How much stasis it does to slimes, and 1/3rd to non-slimes.
- hitcost = 48 //Less zap for less cost
-
-/obj/item/weapon/melee/baton/slime/attack(mob/M, mob/user)
- if(istype(M, /mob/living/simple_animal/xeno))
- var/mob/living/simple_animal/xeno/X = M
- if(istype(M, /mob/living/simple_animal/xeno/slime))
- X.stasis += stasisforce
- else
- X.stasis += (stasisforce / 6)
- ..()
-
-/obj/item/weapon/melee/baton/slime/loaded/New()
- ..()
- bcell = new/obj/item/weapon/cell/device(src)
- update_icon()
- return
-
-
-// Xeno stun gun + projectile
-/obj/item/weapon/gun/energy/taser/xeno
- name = "xeno taser gun"
- desc = "Straight out of NT's testing laboratories, this small gun is used to subdue non-humanoid xeno life forms. While marketed towards handling slimes, it may be useful for other creatures."
- icon_state = "taserold"
- fire_sound = 'sound/weapons/taser2.ogg'
- projectile_type = /obj/item/projectile/beam/stun/xeno
-
-/obj/item/projectile/beam/stun/xeno
- icon_state = "omni"
- agony = 4
- var/stasisforce = 40
-
- muzzle_type = /obj/effect/projectile/laser_omni/muzzle
- tracer_type = /obj/effect/projectile/laser_omni/tracer
- impact_type = /obj/effect/projectile/laser_omni/impact
-/*
-/obj/item/projectile/beam/stun/xeno/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living/simple_animal/xeno))
- world << "is xeno"
- var/mob/living/simple_animal/xeno/X = target
- world << "[target.name]"
- if(istype(X, /mob/living/simple_animal/xeno/slime))
- world << "is slime"
- X.stasis += stasisforce
- else
- world << "is not slime"
- X.stasis += (stasisforce / 8)
- else
- world << "is not xeno"
- ..()
-*/
\ No newline at end of file
diff --git a/code/world.dm b/code/world.dm
index 9a031dda0f..9ef6abf8aa 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -76,9 +76,6 @@ var/global/datum/global_init/init = new ()
// Set up roundstart seed list.
plant_controller = new()
- // Set up roundstart gene masking
- xenobio_controller = new()
-
// This is kinda important. Set up details of what the hell things are made of.
populate_material_list()
diff --git a/icons/mob/modifier_effects.dmi b/icons/mob/modifier_effects.dmi
index e0fe0b1697..eca5286d9b 100644
Binary files a/icons/mob/modifier_effects.dmi and b/icons/mob/modifier_effects.dmi differ
diff --git a/icons/mob/screen1_stats.dmi b/icons/mob/screen1_stats.dmi
index 381f6a3660..701d7f1702 100644
Binary files a/icons/mob/screen1_stats.dmi and b/icons/mob/screen1_stats.dmi differ
diff --git a/icons/mob/slime2.dmi b/icons/mob/slime2.dmi
index 33ef237cba..a0b6051665 100644
Binary files a/icons/mob/slime2.dmi and b/icons/mob/slime2.dmi differ
diff --git a/icons/mob/slimes.dmi b/icons/mob/slimes.dmi
index f2da09ad8f..b452a1526d 100644
Binary files a/icons/mob/slimes.dmi and b/icons/mob/slimes.dmi differ
diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi
index 14d1d54ab9..acd94a74c3 100644
Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ
diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi
index f58a356c34..abcf7c1cf9 100644
Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index 2fa64c7ade..a8ae36b5e8 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi
index 83e20f0af3..32827b2b81 100644
Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 214428603e..8cc8557888 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/maps/example/example.dm b/maps/example/example.dm
index a103a32625..46ee489d5a 100644
--- a/maps/example/example.dm
+++ b/maps/example/example.dm
@@ -1,11 +1,13 @@
#if !defined(USING_MAP_DATUM)
- #include "example-1.dmm"
- #include "example-2.dmm"
+// #include "example-1.dmm"
+// #include "example-2.dmm"
+ #include "xenobio_test.dmm"
#include "example_defines.dm"
- #include "example_elevator.dm"
- #include "example_areas.dm"
+// #include "example_elevator.dm"
+// #include "example_areas.dm"
+
#define USING_MAP_DATUM /datum/map/example
diff --git a/maps/northern_star/polaris-1.dmm b/maps/northern_star/polaris-1.dmm
index 9bc000a95d..ae027eeab8 100644
--- a/maps/northern_star/polaris-1.dmm
+++ b/maps/northern_star/polaris-1.dmm
@@ -4887,7 +4887,7 @@
"bPY" = (/obj/machinery/computer/aifixer,/obj/effect/floor_decal/corner/purple/full,/obj/machinery/status_display{layer = 4; pixel_x = 0; pixel_y = -32},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice)
"bPZ" = (/obj/machinery/computer/robotics,/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice)
"bQa" = (/obj/machinery/computer/mecha,/obj/effect/floor_decal/corner/purple{dir = 10},/obj/machinery/ai_status_display{pixel_y = -32},/obj/machinery/camera/network/research{c_tag = "SCI - RD's Office"; dir = 1},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice)
-"bQb" = (/obj/effect/floor_decal/corner/purple/full{dir = 4},/obj/machinery/alarm{dir = 1; pixel_y = -22},/mob/living/simple_animal/slime/science,/turf/simulated/floor/tiled/white,/area/rnd/rdoffice)
+"bQb" = (/obj/effect/floor_decal/corner/purple/full{dir = 4},/obj/machinery/alarm{dir = 1; pixel_y = -22},/mob/living/simple_animal/slime/rainbow/kendrick,/turf/simulated/floor/tiled/white,/area/rnd/rdoffice)
"bQc" = (/obj/structure/table/rack,/obj/item/weapon/rig/hazmat/equipped,/obj/structure/extinguisher_cabinet{pixel_x = 25; pixel_y = 0},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/rnd/rdoffice)
"bQd" = (/obj/structure/table/standard,/obj/item/device/mmi,/obj/item/device/mmi,/obj/item/device/mmi,/obj/structure/extinguisher_cabinet{pixel_x = -27},/turf/simulated/floor/tiled,/area/assembly/robotics)
"bQe" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 21},/obj/effect/floor_decal/corner/pink{dir = 4},/turf/simulated/floor/tiled,/area/assembly/robotics)
@@ -9879,7 +9879,7 @@
"dHZ" = (/turf/space,/area/skipjack_station/southeast_solars)
"dIa" = (/turf/space,/area/syndicate_station/south)
"dIb" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/airless,/area/solar/starboard)
-
+
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/maps/northern_star/polaris-5.dmm b/maps/northern_star/polaris-5.dmm
index bb133806a4..28d2dc5f94 100644
--- a/maps/northern_star/polaris-5.dmm
+++ b/maps/northern_star/polaris-5.dmm
@@ -273,7 +273,7 @@
"fm" = (/obj/machinery/atmospherics/pipe/simple/visible/purple{dir = 6},/obj/machinery/light,/turf/simulated/floor/plating,/area/outpost/research/toxins_misc_lab)
"fn" = (/obj/structure/table/standard,/obj/machinery/microwave,/obj/machinery/status_display{layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor/tiled,/area/outpost/research/toxins_misc_lab)
"fo" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple,/turf/simulated/wall/r_wall,/area/outpost/research/toxins_misc_lab)
-"fp" = (/obj/machinery/xenobio2/manualinjector,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
+"fp" = (/obj,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"fq" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"fr" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/plating,/area/outpost/research/hallway/toxins_hallway)
"fs" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/emergency,/obj/item/clothing/accessory/armband/science,/obj/item/clothing/glasses/science,/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -21},/obj/item/device/suit_cooling_unit,/turf/simulated/floor/plating,/area/outpost/research/hallway/toxins_hallway)
@@ -299,17 +299,17 @@
"fM" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio2"; name = "Containment Blast Doors"; opacity = 0},/obj/machinery/door/window/southright{dir = 1; name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"fN" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio2"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/disposalpipe/segment,/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
"fO" = (/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
-"fP" = (/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
+"fP" = (/obj,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"fQ" = (/obj/structure/sign/securearea,/turf/simulated/wall/r_wall,/area/outpost/research/hallway/toxins_hallway)
"fR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/research{autoclose = 0; frequency = 1379; icon_state = "door_locked"; id_tag = "toxins_airlock_exterior"; locked = 1; name = "Toxins External Airlock"; req_access = list(7)},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1379; master_tag = "toxins_airlock_control"; name = "Toxins Access Button"; pixel_x = 26; pixel_y = 0; req_access = list(7)},/turf/simulated/floor/tiled/white,/area/outpost/research/hallway/toxins_hallway)
"fS" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/space,/area/space)
"fT" = (/obj/structure/sink{pixel_x = 0; pixel_y = 28},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"fU" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
-"fV" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Port"; dir = 2},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
+"fV" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Port"; dir = 2},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"fW" = (/obj/structure/table/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 10},/obj/machinery/button/remote/blast_door{id = "xenobio1"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"fX" = (/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"fY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
-"fZ" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
+"fZ" = (/obj/effect/floor_decal/industrial/warning,/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"ga" = (/obj/structure/table/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning,/obj/machinery/button/remote/blast_door{id = "xenobio2"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"gb" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"gc" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Starboard"; dir = 2},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
@@ -321,8 +321,8 @@
"gi" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/airless,/area/mine/explored)
"gj" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
"gk" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/device/flashlight,/obj/item/device/flashlight,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
-"gl" = (/obj/machinery/slime/extractor,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
-"gm" = (/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
+"gl" = (/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
+"gm" = (/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"gn" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"go" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"gp" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
@@ -370,7 +370,7 @@
"hf" = (/obj/machinery/shower{pixel_y = 3},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/freezer,/area/outpost/research/xenobiology)
"hg" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"hh" = (/obj/machinery/smartfridge/secure/extract,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
-"hi" = (/obj/machinery/slime/replicator,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
+"hi" = (/obj,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"hj" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"hk" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"hl" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio3"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
@@ -445,7 +445,7 @@
"iC" = (/obj/structure/disposaloutlet{dir = 1},/obj/structure/disposalpipe/trunk{dir = 8},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"iD" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk)
"iE" = (/obj/machinery/requests_console{department = "Science"; departmentType = 2; name = "Science Requests Console"; pixel_x = 0; pixel_y = 30},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
-"iF" = (/obj/structure/table/standard,/obj/item/weapon/clipboard,/obj/item/weapon/folder,/obj/item/weapon/pen,/obj/item/weapon/melee/baton/slime/loaded,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
+"iF" = (/obj/structure/table/standard,/obj/item/weapon/clipboard,/obj/item/weapon/folder,/obj/item/weapon/pen,/obj/item/weapon/melee/baton/slime/loaded,/obj,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
"iG" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"iH" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"iI" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/button/remote/blast_door{desc = "A remote control-switch for a door to space."; id = "xenobioout6"; name = "Containment Release Switch"; pixel_x = 0; pixel_y = -28; req_access = list(55)},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
@@ -458,10 +458,10 @@
"iP" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"iQ" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/table/reinforced,/obj/machinery/button/remote/blast_door{id = "xenobio5"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"iR" = (/obj/structure/table/standard,/obj/item/weapon/folder/red{pixel_y = 3},/obj/item/weapon/folder/blue{pixel_x = 5},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
-"iS" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Aft Starboard"; dir = 1},/obj/machinery/newscaster{pixel_y = -32},/obj/machinery/light,/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
+"iS" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Aft Starboard"; dir = 1},/obj/machinery/newscaster{pixel_y = -32},/obj/machinery/light,/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"iT" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk)
"iU" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk)
-"iV" = (/obj/structure/table/steel,/obj/item/clothing/glasses/science,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
+"iV" = (/obj/structure/table/steel,/obj/item/clothing/glasses/science,/obj,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
"iW" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/disposalpipe/segment,/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
"iX" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"iY" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
@@ -469,9 +469,9 @@
"ja" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio5"; name = "Containment Blast Doors"; opacity = 0},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"jb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio5"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology)
"jc" = (/obj/structure/extinguisher_cabinet{pixel_x = 25; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
-"jd" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/xenobiodisk,/obj/item/weapon/melee/baton/slime/loaded,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
+"jd" = (/obj/structure/table/standard,/obj,/obj/item/weapon/melee/baton/slime/loaded,/obj,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology)
"je" = (/turf/simulated/wall,/area/outpost/research/xenobiology)
-"jf" = (/obj/structure/closet,/obj/item/toy/figure/scientist,/obj/item/clothing/accessory/armband/science,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
+"jf" = (/obj/structure/closet,/obj/item/toy/figure/scientist,/obj/item/clothing/accessory/armband/science,/obj,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
"jg" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk)
"jh" = (/obj/machinery/light/small{dir = 8},/obj/structure/disposalpipe/segment,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
"ji" = (/obj/structure/disposaloutlet{dir = 4},/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology)
@@ -1587,7 +1587,7 @@
"EA" = (/obj/structure/table/steel,/obj/machinery/cell_charger,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery)
"EB" = (/obj/effect/floor_decal/industrial/warning/dust/corner,/obj/machinery/light/small,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery)
"EC" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
-"ED" = (/obj/machinery/xenobio/extractor,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
+"ED" = (/obj,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology)
"EE" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"EF" = (/obj/machinery/recharger/wallcharger{pixel_x = 32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
"EG" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/hydronutrients,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology)
@@ -1910,7 +1910,7 @@
"KL" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space)
"KM" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/airless{icon_state = "asteroidplating2"},/area/outpost/engineering/solarsoutside/aft)
"KN" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -20},/turf/simulated/floor/tiled,/area/outpost/mining_main/south_hall)
-
+
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/polaris.dme b/polaris.dme
index 94ce131288..959eb6c298 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1662,18 +1662,6 @@
#include "code\modules\mob\living\carbon\human\species\station\prometheans.dm"
#include "code\modules\mob\living\carbon\human\species\station\seromi.dm"
#include "code\modules\mob\living\carbon\human\species\station\station.dm"
-#include "code\modules\mob\living\carbon\metroid\death.dm"
-#include "code\modules\mob\living\carbon\metroid\emote.dm"
-#include "code\modules\mob\living\carbon\metroid\examine.dm"
-#include "code\modules\mob\living\carbon\metroid\hud.dm"
-#include "code\modules\mob\living\carbon\metroid\items.dm"
-#include "code\modules\mob\living\carbon\metroid\life.dm"
-#include "code\modules\mob\living\carbon\metroid\login.dm"
-#include "code\modules\mob\living\carbon\metroid\metroid.dm"
-#include "code\modules\mob\living\carbon\metroid\powers.dm"
-#include "code\modules\mob\living\carbon\metroid\say.dm"
-#include "code\modules\mob\living\carbon\metroid\subtypes.dm"
-#include "code\modules\mob\living\carbon\metroid\update_icons.dm"
#include "code\modules\mob\living\silicon\death.dm"
#include "code\modules\mob\living\silicon\laws.dm"
#include "code\modules\mob\living\silicon\login.dm"
@@ -1751,7 +1739,6 @@
#include "code\modules\mob\living\simple_animal\animals\mouse.dm"
#include "code\modules\mob\living\simple_animal\animals\parrot.dm"
#include "code\modules\mob\living\simple_animal\animals\penguin.dm"
-#include "code\modules\mob\living\simple_animal\animals\slime.dm"
#include "code\modules\mob\living\simple_animal\animals\spiderbot.dm"
#include "code\modules\mob\living\simple_animal\animals\tomato.dm"
#include "code\modules\mob\living\simple_animal\animals\tree.dm"
@@ -1769,6 +1756,12 @@
#include "code\modules\mob\living\simple_animal\humanoids\pirate.dm"
#include "code\modules\mob\living\simple_animal\humanoids\russian.dm"
#include "code\modules\mob\living\simple_animal\humanoids\syndicate.dm"
+#include "code\modules\mob\living\simple_animal\slime\ai.dm"
+#include "code\modules\mob\living\simple_animal\slime\combat.dm"
+#include "code\modules\mob\living\simple_animal\slime\death.dm"
+#include "code\modules\mob\living\simple_animal\slime\life.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\living\voice\voice.dm"
#include "code\modules\mob\new_player\login.dm"
#include "code\modules\mob\new_player\logout.dm"
@@ -2125,7 +2118,6 @@
#include "code\modules\surgery\organs_internal.dm"
#include "code\modules\surgery\other.dm"
#include "code\modules\surgery\robotics.dm"
-#include "code\modules\surgery\slimes.dm"
#include "code\modules\surgery\surgery.dm"
#include "code\modules\surgery\~defines.dm"
#include "code\modules\tables\bench.dm"
@@ -2216,23 +2208,11 @@
#include "code\modules\xenoarcheaology\tools\suspension_generator.dm"
#include "code\modules\xenoarcheaology\tools\tools.dm"
#include "code\modules\xenoarcheaology\tools\tools_pickaxe.dm"
-#include "code\modules\xenobio2\_xeno_setup.dm"
-#include "code\modules\xenobio2\controller.dm"
-#include "code\modules\xenobio2\machinery\core_extractor.dm"
-#include "code\modules\xenobio2\machinery\gene_manipulators.dm"
-#include "code\modules\xenobio2\machinery\injector.dm"
-#include "code\modules\xenobio2\machinery\injector_computer.dm"
-#include "code\modules\xenobio2\machinery\slime_replicator.dm"
-#include "code\modules\xenobio2\mob\xeno procs.dm"
-#include "code\modules\xenobio2\mob\xeno.dm"
-#include "code\modules\xenobio2\mob\xeno_product.dm"
-#include "code\modules\xenobio2\mob\slime\slime life.dm"
-#include "code\modules\xenobio2\mob\slime\slime procs.dm"
-#include "code\modules\xenobio2\mob\slime\slime.dm"
-#include "code\modules\xenobio2\mob\slime\slime_core.dm"
-#include "code\modules\xenobio2\mob\slime\slime_monkey.dm"
-#include "code\modules\xenobio2\tools\slime_handling_tools.dm"
-#include "code\modules\xenobio2\tools\xeno_trait_scanner.dm"
+#include "code\modules\xenobio\items\extracts.dm"
+#include "code\modules\xenobio\items\slime_objects.dm"
+#include "code\modules\xenobio\items\slimepotions.dm"
+#include "code\modules\xenobio\items\weapons.dm"
+#include "code\modules\xenobio\machinery\processor.dm"
#include "code\modules\xgm\xgm_gas_data.dm"
#include "code\modules\xgm\xgm_gas_mixture.dm"
#include "code\unit_tests\loadout_tests.dm"
@@ -2262,6 +2242,7 @@
#include "code\ZAS\Zone.dm"
#include "interface\interface.dm"
#include "interface\skin.dmf"
-#include "maps\northern_star\northern_star.dm"
+#include "maps\example\example.dm"
+#include "maps\example\xenobio_test.dmm"
#include "maps\~map_system\maps.dm"
// END_INCLUDE