diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 88c19401..6aea7611 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -454,7 +454,9 @@ SUBSYSTEM_DEF(job)
to_chat(M, "[job.custom_spawn_text]")
if(CONFIG_GET(number/minimal_access_threshold))
to_chat(M, "As this station was initially staffed with a [CONFIG_GET(flag/jobs_have_minimal_access) ? "full crew, only your job's necessities" : "skeleton crew, additional access may"] have been added to your ID card.")
-
+
+ job.after_spawn(H, M, joined_late)
+
//Account ID. ID is handled by human initialization
if(ishuman(H))
var/mob/living/carbon/human/wageslave = H
diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm
index 9870a895..37081453 100644
--- a/code/modules/atmospherics/machinery/other/meter.dm
+++ b/code/modules/atmospherics/machinery/other/meter.dm
@@ -134,6 +134,9 @@
else
to_chat(user, status())
+/obj/machinery/meter/attack_ghost(mob/user)
+ to_chat(user, status())
+
/obj/machinery/meter/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_FIVE)
@@ -141,6 +144,7 @@
// TURF METER - REPORTS A TILE'S AIR CONTENTS
// why are you yelling?
+// i hope they aren't mad
/obj/machinery/meter/turf
/obj/machinery/meter/turf/reattach_to_layer()
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index a0e3dd38..afd1e918 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -377,6 +377,17 @@
air_update_turf() // Update the environment if needed.
update_icon()
+/obj/machinery/portable_atmospherics/canister/attack_ghost(mob/user)
+ if(user.client)
+ if(IsAdminGhost(user))
+ attack_ai(user)
+ return FALSE
+ else if(user.client.prefs.inquisitive_ghost)
+ user.examinate(src)
+ return FALSE
+ atmosanalyzer_scan(air_contents, user, src, FALSE)
+ return FALSE
+
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index e5c5a4f9..b76beaa5 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -23,7 +23,7 @@
/obj/machinery/gibber/RefreshParts()
var/gib_time = 40
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
- meat_produced += B.rating
+ meat_produced += 1.6 * B.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
gib_time -= 5 * M.rating
gibtime = gib_time
diff --git a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
index c25cb228..789c54f7 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
@@ -1,6 +1,8 @@
+GLOBAL_LIST_EMPTY(monkey_recyclers)
+
/obj/machinery/monkey_recycler
name = "monkey recycler"
- desc = "A machine used for recycling dead monkeys into monkey cubes. It currently produces 1 cube for every 5 monkeys inserted." // except it literally never does
+ desc = "A machine used for recycling dead monkeys into monkey cubes. You can use a multitool to link it to a xenobiology console. It currently produces 0.2 cubes for every monkey inserted."
icon = 'icons/obj/kitchen.dmi'
icon_state = "grinder"
layer = BELOW_OBJ_LAYER
@@ -9,20 +11,29 @@
idle_power_usage = 5
active_power_usage = 50
circuit = /obj/item/circuitboard/machine/monkey_recycler
- var/grinded = 0
- var/required_grind = 5
- var/cube_production = 1
+ var/stored_matter = 0
+ var/cube_production = 0.2
+ var/list/connected = list() //Xenobio consoles
+
+/obj/machinery/monkey_recycler/Initialize(mapload)
+ . = ..()
+ GLOB.monkey_recyclers += src
-/obj/machinery/monkey_recycler/RefreshParts()
- var/req_grind = 5
- var/cubes_made = 1
+/obj/machinery/monkey_recycler/Destroy()
+ if(src in GLOB.monkey_recyclers)
+ GLOB.monkey_recyclers -= src
+ for(var/obj/machinery/computer/camera_advanced/xenobio/C in connected)
+ var/obj/machinery/computer/camera_advanced/xenobio/console = C
+ console.connected_recycler = null
+ return ..()
+
+/obj/machinery/monkey_recycler/RefreshParts() //Ranges from 0.2 to 0.8 per monkey recycled
+ cube_production = 0
for(var/obj/item/stock_parts/manipulator/B in component_parts)
- req_grind -= B.rating
+ cube_production += B.rating * 0.1
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
- cubes_made = M.rating
- cube_production = cubes_made
- required_grind = req_grind
- src.desc = "A machine used for recycling dead monkeys into monkey cubes. It currently produces [cubes_made] cube(s) for every [required_grind] monkey(s) inserted."
+ cube_production += M.rating * 0.1
+ desc = "A machine used for recycling dead monkeys into monkey cubes. You can use a multitool to link it to a xenobiology console. It currently produces [cube_production] cubes for every monkey inserted."
/obj/machinery/monkey_recycler/attackby(obj/item/O, mob/user, params)
if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O))
@@ -64,17 +75,22 @@
var/offset = prob(50) ? -2 : 2
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking
use_power(500)
- grinded++
+ stored_matter += cube_production
addtimer(VARSET_CALLBACK(src, pixel_x, initial(pixel_x)))
- addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, user, "The machine now has [grinded] monkey\s worth of material stored."))
+ addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, user, "The machine now has [stored_matter] monkey\s worth of material stored."))
/obj/machinery/monkey_recycler/interact(mob/user)
- if(grinded >= required_grind)
- to_chat(user, "The machine hisses loudly as it condenses the grinded monkey meat. After a moment, it dispenses a brand new monkey cube.")
+ if(stored_matter >= 1)
+ to_chat(user, "The machine hisses loudly as it condenses the ground monkey meat. After a moment, it dispenses a brand new monkey cube.")
playsound(src.loc, 'sound/machines/hiss.ogg', 50, 1)
- grinded -= required_grind
- for(var/i = 0, i < cube_production, i++)
- new /obj/item/reagent_containers/food/snacks/monkeycube(src.loc)
- to_chat(user, "The machine's display flashes that it has [grinded] monkeys worth of material left.")
+ for(var/i in 1 to max(stored_matter, 1))
+ new /obj/item/reagent_containers/food/snacks/monkeycube(loc)
+ to_chat(user, "The machine's display flashes that it has [stored_matter] monkeys worth of material left.")
else
- to_chat(user, "The machine needs at least [required_grind] monkey(s) worth of material to produce a monkey cube. It only has [grinded].")
+ to_chat(user, "The machine needs at least 1 monkey worth of material to produce a monkey cube. It currently has [stored_matter].")
+
+/obj/machinery/monkey_recycler/multitool_act(mob/living/user, obj/item/multitool/I)
+ if(istype(I))
+ to_chat(user, "You log [src] in the multitool's buffer.")
+ I.buffer = src
+ return TRUE
diff --git a/code/modules/holiday/halloween/jacqueen.dm b/code/modules/holiday/halloween/jacqueen.dm
index 3cdd4798..5b3b7077 100644
--- a/code/modules/holiday/halloween/jacqueen.dm
+++ b/code/modules/holiday/halloween/jacqueen.dm
@@ -368,7 +368,7 @@
C.reagents.add_reagent(/datum/reagent/fermi/eigenstate, 30)
if(5)
visible_message("[src] waves their arms around, \"A new familiar for me, and you'll see it's thee!\"")
- C.reagents.add_reagent("secretcatchem", 30)
+ C.reagents.add_reagent(/datum/reagent/fermi/secretcatchem, 30)
if(6)
visible_message("[src] waves their arms around, \"While you may not be a ghost, for this sheet you'll always be it's host.\"")
var/mob/living/carbon/human/H = C
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
index feca1a40..7d97858f 100644
--- a/code/modules/jobs/job_types/civilian.dm
+++ b/code/modules/jobs/job_types/civilian.dm
@@ -18,7 +18,7 @@ Clown
minimal_access = list(ACCESS_THEATRE)
/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
- . = ..()
+ ..()
H.apply_pref_name("clown", M.client)
/datum/outfit/job/clown
@@ -83,6 +83,7 @@ Mime
minimal_access = list(ACCESS_THEATRE)
/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
+ ..()
H.apply_pref_name("mime", M.client)
/datum/outfit/job/mime
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm
index d593bfd8..7b4ed75c 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/job.dm
@@ -66,7 +66,7 @@
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
- //do actions on H but send messages to M as the key may not have been transferred_yet
+ //do actions on H but send messages to M as the key may not have been transferred yet
if(mind_traits)
for(var/t in mind_traits)
ADD_TRAIT(H.mind, t, JOB_TRAIT)
diff --git a/code/modules/jobs/job_types/silicon.dm b/code/modules/jobs/job_types/silicon.dm
index 31f0c87f..4d0b4d66 100644
--- a/code/modules/jobs/job_types/silicon.dm
+++ b/code/modules/jobs/job_types/silicon.dm
@@ -21,7 +21,7 @@ AI
. = H.AIize(latejoin)
/datum/job/ai/after_spawn(mob/H, mob/M, latejoin)
- . = ..()
+ ..()
if(latejoin)
var/obj/structure/AIcore/latejoin_inactive/lateJoinCore
for(var/obj/structure/AIcore/latejoin_inactive/P in GLOB.latejoin_ai_cores)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index f3ee17a4..b842ba42 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -437,11 +437,11 @@
var/obj/item/reagent_containers/spray/cyborg_drying/CD = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules
if(CD)
- CD.reagents.add_reagent("drying_agent", 5 * coeff)
+ CD.reagents.add_reagent(/datum/reagent/drying_agent, 5 * coeff)
var/obj/item/reagent_containers/spray/cyborg_lube/CL = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules
if(CL)
- CL.reagents.add_reagent("lube", 2 * coeff)
+ CL.reagents.add_reagent(/datum/reagent/lube, 2 * coeff)
/obj/item/robot_module/clown
name = "Clown"
diff --git a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
index 9013468f..459747e0 100644
--- a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
+++ b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm
@@ -316,9 +316,9 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0)
to_chat(H, "WHAT THE FUCK IS THAT?!")
to_chat(H, ".KNOH !nuf hcum os si uoy htiw gniyalP .KNOH KNOH KNOH")
H.playsound_local(src,'sound/hallucinations/im_here1.ogg', 25)
- H.reagents.add_reagent("mindbreaker", 3)
- H.reagents.add_reagent("laughter", 5)
- H.reagents.add_reagent("mercury", 3)
+ H.reagents.add_reagent(/datum/reagent/toxin/mindbreaker, 3)
+ H.reagents.add_reagent(/datum/reagent/consumable/laughter, 5)
+ H.reagents.add_reagent(/datum/reagent/mercury, 3)
Appear()
manifested = FALSE
addtimer(CALLBACK(src, /mob/living/simple_animal/hostile/floor_cluwne/.proc/Manifest), 2)
diff --git a/code/modules/pool/pool_main.dm b/code/modules/pool/pool_main.dm
index f5ccc40f..a15f3427 100644
--- a/code/modules/pool/pool_main.dm
+++ b/code/modules/pool/pool_main.dm
@@ -171,7 +171,7 @@
/turf/open/pool/attackby(obj/item/W, mob/living/user)
if(istype(W, /obj/item/mop) && filled)
- W.reagents.add_reagent("water", 5)
+ W.reagents.add_reagent(/datum/reagent/water, 5)
to_chat(user, "You wet [W] in [src].")
playsound(src, 'sound/effects/slosh.ogg', 25, TRUE)
else
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index 5aebd1ba..04cf006e 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -1,6 +1,6 @@
//Xenobio control console
/mob/camera/aiEye/remote/xenobio
- visible_icon = 1
+ visible_icon = TRUE
icon = 'icons/obj/abductor.dmi'
icon_state = "camera_target"
var/allowed_area = null
@@ -22,15 +22,11 @@
desc = "A computer used for remotely handling slimes."
networks = list("ss13")
circuit = /obj/item/circuitboard/computer/xenobiology
- var/datum/action/innate/slime_place/slime_place_action
- var/datum/action/innate/slime_pick_up/slime_up_action
- var/datum/action/innate/feed_slime/feed_slime_action
- var/datum/action/innate/monkey_recycle/monkey_recycle_action
- var/datum/action/innate/slime_scan/scan_action
- var/datum/action/innate/feed_potion/potion_action
+ var/datum/action/innate/hotkey_help/hotkey_help
var/datum/component/redirect/listener
+ var/obj/machinery/monkey_recycler/connected_recycler
var/list/stored_slimes
var/obj/item/slimepotion/slime/current_potion
var/max_slimes = 5
@@ -43,14 +39,13 @@
/obj/machinery/computer/camera_advanced/xenobio/Initialize()
. = ..()
- slime_place_action = new
- slime_up_action = new
- feed_slime_action = new
- monkey_recycle_action = new
- scan_action = new
- potion_action = new
+ hotkey_help = new
stored_slimes = list()
listener = AddComponent(/datum/component/redirect, list(COMSIG_ATOM_CONTENTS_DEL = CALLBACK(src, .proc/on_contents_del)))
+ for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
+ if(get_area(src) == get_area(recycler))
+ connected_recycler = recycler
+ connected_recycler.connected += src
/obj/machinery/computer/camera_advanced/xenobio/Destroy()
stored_slimes = null
@@ -61,45 +56,56 @@
S.forceMove(drop_location())
return ..()
+/obj/machinery/computer/camera_advanced/xenobio/examine(mob/user)
+ . = ..()
+ var/thing = "It has "
+ if((upgradetier & XENOBIO_UPGRADE_SLIMEADV))
+ thing += "an advanced slime upgrade disk "
+ if((upgradetier & XENOBIO_UPGRADE_MONKEYS))
+ thing += "and a monkey upgrade disk "
+ else if((upgradetier & XENOBIO_UPGRADE_SLIMEBASIC))
+ thing += "a basic slime upgrade disk "
+ if((upgradetier & XENOBIO_UPGRADE_MONKEYS))
+ thing += "and a monkey upgrade disk "
+ else if((upgradetier & XENOBIO_UPGRADE_MONKEYS))
+ thing += "a monkey upgrade disk "
+ else
+ thing += "no upgrades installed."
+ . += thing
+ return
+ thing += "installed."
+ . += thing
+
/obj/machinery/computer/camera_advanced/xenobio/CreateEye()
eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src))
eyeobj.origin = src
- eyeobj.visible_icon = 1
+ eyeobj.visible_icon = TRUE
eyeobj.icon = 'icons/obj/abductor.dmi'
eyeobj.icon_state = "camera_target"
/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user)
..()
- if(slime_up_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
- slime_up_action.target = src
- slime_up_action.Grant(user)
- actions += slime_up_action
+ if(hotkey_help)
+ hotkey_help.target = src
+ hotkey_help.Grant(user)
+ actions += hotkey_help
- if(slime_place_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
- slime_place_action.target = src
- slime_place_action.Grant(user)
- actions += slime_place_action
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl)
- if(feed_slime_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
- feed_slime_action.target = src
- feed_slime_action.Grant(user)
- actions += feed_slime_action
-
- if(monkey_recycle_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
- monkey_recycle_action.target = src
- monkey_recycle_action.Grant(user)
- actions += monkey_recycle_action
-
- if(scan_action)
- scan_action.target = src
- scan_action.Grant(user)
- actions += scan_action
-
- if(potion_action && (upgradetier & XENOBIO_UPGRADE_SLIMEADV)) // CIT CHANGE - makes giving slimes potions via console require XENOBIO_UPGRADE_SLIMEADV
- potion_action.target = src
- potion_action.Grant(user)
- actions += potion_action
+/obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL)
+ ..()
/obj/machinery/computer/camera_advanced/xenobio/proc/on_contents_del(atom/deleted)
if(current_potion == deleted)
@@ -134,135 +140,161 @@
current_potion = O
to_chat(user, "You load [O] in the console's potion slot[replaced ? ", replacing the one that was there before" : ""].")
return
+ else if(istype(O, /obj/item/multitool))
+ var/obj/item/multitool/M = O
+ if(istype(M.buffer))
+ to_chat(user, "You link [src] with [M.buffer] in [M] buffer.")
+ connected_recycler = M.buffer
+ connected_recycler += src
+ return
+ else
+ to_chat(user, "[M] has no buffer.")
+ return
..()
-/datum/action/innate/slime_place
- name = "Place Slimes"
+/datum/action/innate/hotkey_help
+ name = "Hotkey Help"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "slime_down"
+ button_icon_state = "hotkey_help"
-/datum/action/innate/slime_place/Activate()
+/datum/action/innate/hotkey_help/Activate()
if(!target || !isliving(owner))
return
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
- var/obj/machinery/computer/camera_advanced/xenobio/X = target
+ to_chat(owner, "Click shortcuts:")
+ to_chat(owner, "Shift-click a slime to pick it up, or the floor to drop all held slimes.")
+ to_chat(owner, "Ctrl-click a slime to scan it.")
+ to_chat(owner, "Alt-click a slime to feed it a potion.")
+ to_chat(owner, "Ctrl-click on a dead monkey to recycle it, or the floor to place a new monkey.")
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
- S.forceMove(remote_eye.loc)
+//
+// Alternate clicks for slime, monkey and open turf if using a xenobio console
+
+//Picks up slime
+/mob/living/simple_animal/slime/ShiftClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_SHIFT, src)
+ ..()
+
+//Place slimes
+/turf/open/ShiftClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_SHIFT, src)
+ ..()
+
+//Place monkey
+/turf/open/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_CTRL, src)
+ ..()
+
+//Pick up monkey
+/mob/living/carbon/monkey/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src)
+ ..()
+
+// Scans slime
+/mob/living/simple_animal/slime/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_CTRL, src)
+ ..()
+
+//Feeds a potion to slime
+/mob/living/simple_animal/slime/AltClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_ALT, src)
+ ..()
+
+//Picks up slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/simple_animal/slime/S)
+ if(!(upgradetier & XENOBIO_UPGRADE_SLIMEBASIC))
+ return
+ if(!GLOB.cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/area/mobarea = get_area(S.loc)
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(mobarea.name == X.allowed_area || mobarea.xenobiology_compatible)
+ if(stored_slimes.len >= max_slimes)
+ to_chat(user, "Slime storage is full.")
+ return
+ if(S.ckey)
+ to_chat(user, "The slime wiggled free!")
+ return
+ if(S.buckled)
+ S.Feedstop(silent = TRUE)
+ S.visible_message("[S] vanishes in a flash of light!")
+ S.forceMove(src)
+ stored_slimes += S
+
+//Place slimes
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickShift(mob/living/user, turf/open/T)
+ if(!(upgradetier & XENOBIO_UPGRADE_SLIMEBASIC))
+ return
+ if(!GLOB.cameranet.checkTurfVis(T))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/area/turfarea = get_area(T)
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(turfarea.name == X.allowed_area || turfarea.xenobiology_compatible)
+ for(var/mob/living/simple_animal/slime/S in stored_slimes)
+ S.forceMove(T)
S.visible_message("[S] warps in!")
- X.stored_slimes -= S
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
+ stored_slimes -= S
-/datum/action/innate/slime_pick_up
- name = "Pick up Slime"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "slime_up"
-
-/datum/action/innate/slime_pick_up/Activate()
- if(!target || !isliving(owner))
+//Place monkey
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickCtrl(mob/living/user, turf/open/T)
+ if(!(upgradetier & XENOBIO_UPGRADE_MONKEYS))
return
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
- var/obj/machinery/computer/camera_advanced/xenobio/X = target
-
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
- if(X.stored_slimes.len >= X.max_slimes)
- break
- if(!S.ckey)
- if(S.buckled)
- S.Feedstop(silent = TRUE)
- S.visible_message("[S] vanishes in a flash of light!")
- S.forceMove(X)
- X.stored_slimes += S
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
-
-
-/datum/action/innate/feed_slime
- name = "Feed Slimes"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "monkey_down"
-
-/datum/action/innate/feed_slime/Activate()
- if(!target || !isliving(owner))
+ if(!GLOB.cameranet.checkTurfVis(T))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
return
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
- var/obj/machinery/computer/camera_advanced/xenobio/X = target
+ var/area/turfarea = get_area(T)
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(turfarea.name == X.allowed_area || turfarea.xenobiology_compatible)
+ if(monkeys >= 1)
+ var/mob/living/carbon/monkey/food = new/mob/living/carbon/monkey(T, TRUE, user)
+ if(!QDELETED(food))
+ food.LAssailant = user
+ monkeys = round(monkeys-1, 0.1)
+ to_chat(user, "[src] now has [monkeys] monkeys stored.")
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- if(X.monkeys >= 1)
- var/mob/living/carbon/monkey/food = new /mob/living/carbon/monkey(remote_eye.loc, TRUE, owner)
- if (!QDELETED(food))
- food.LAssailant = C
- X.monkeys --
- to_chat(owner, "[X] now has [X.monkeys] monkeys left.")
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
-
-
-/datum/action/innate/monkey_recycle
- name = "Recycle Monkeys"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "monkey_up"
-
-/datum/action/innate/monkey_recycle/Activate()
- if(!target || !isliving(owner))
+//Pick up monkey
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/monkey/M)
+ if(!(upgradetier & XENOBIO_UPGRADE_MONKEYS))
return
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
- var/obj/machinery/computer/camera_advanced/xenobio/X = target
-
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/carbon/monkey/M in remote_eye.loc)
- if(M.stat)
- M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
- X.monkeys = round(X.monkeys + 0.2,0.1)
- qdel(M)
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
-
-/datum/action/innate/slime_scan
- name = "Scan Slime"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "slime_scan"
-
-/datum/action/innate/slime_scan/Activate()
- if(!target || !isliving(owner))
+ if(!connected_recycler)
+ to_chat(user, "There is no connected monkey recycler. You can connect one with a multitool.")
return
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
-
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
- slime_scan(S, C)
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
-
-/datum/action/innate/feed_potion
- name = "Apply Potion"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
- button_icon_state = "slime_potion"
-
-/datum/action/innate/feed_potion/Activate()
- if(!target || !isliving(owner))
+ if(!GLOB.cameranet.checkTurfVis(M.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
return
+ var/area/mobarea = get_area(M.loc)
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(mobarea.name == X.allowed_area || mobarea.xenobiology_compatible)
+ if(!M.stat)
+ return
+ M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
+ connected_recycler.use_power(500)
+ monkeys += connected_recycler.cube_production
+ to_chat(user, "[src] now has [monkeys] monkeys available.")
+ qdel(M)
- var/mob/living/C = owner
- var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
- var/obj/machinery/computer/camera_advanced/xenobio/X = target
-
- if(QDELETED(X.current_potion))
- to_chat(owner, "No potion loaded.")
+// Scans slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/simple_animal/slime/S)
+ if(!GLOB.cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
return
+ var/area/mobarea = get_area(S.loc)
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(mobarea.name == X.allowed_area || mobarea.xenobiology_compatible)
+ slime_scan(S, user)
- if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
- for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
- X.current_potion.attack(S, C)
- break
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
+//Feeds a potion to slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/simple_animal/slime/S)
+ if(!(upgradetier & XENOBIO_UPGRADE_SLIMEBASIC))
+ return
+ if(!GLOB.cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/area/mobarea = get_area(S.loc)
+ if(QDELETED(current_potion))
+ to_chat(user, "No potion loaded.")
+ return
+ var/mob/camera/aiEye/remote/xenobio/X = eyeobj
+ if(mobarea.name == X.allowed_area || mobarea.xenobiology_compatible)
+ current_potion.attack(S, user)
diff --git a/icons/mob/actions/actions_silicon.dmi b/icons/mob/actions/actions_silicon.dmi
index cd997a25..cf3d7a2a 100644
Binary files a/icons/mob/actions/actions_silicon.dmi and b/icons/mob/actions/actions_silicon.dmi differ
diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm
index 9a1a46fe..ef45e07b 100644
--- a/modular_citadel/code/datums/status_effects/chems.dm
+++ b/modular_citadel/code/datums/status_effects/chems.dm
@@ -105,7 +105,7 @@
o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
sizeMoveMod(moveCalc)
*/
- if((B.cached_size) < 40)
+ if((B?.cached_size) < 40)
..()
/*