diff --git a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
index 87c430c5d7..84ba70f55f 100644
--- a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
@@ -206,10 +206,10 @@
return data
-/obj/machinery/atmospherics/binary/algae_farm/tgui_act(action, params)
+/obj/machinery/atmospherics/binary/algae_farm/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
switch(action)
if("toggle")
diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
index 4a680494f7..fd1158f408 100644
--- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
@@ -203,7 +203,7 @@
/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob)
if(..())
return
- add_fingerprint(usr)
+ add_fingerprint(user)
if(!allowed(user))
to_chat(user, span_warning("Access denied."))
return
@@ -235,7 +235,7 @@
return data
-/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, params)
+/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -258,7 +258,7 @@
if("max")
target_pressure = max_pressure_setting
if("set")
- var/new_pressure = tgui_input_number(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure,max_pressure_setting,0)
+ var/new_pressure = tgui_input_number(ui.user,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure,max_pressure_setting,0)
src.target_pressure = between(0, new_pressure, max_pressure_setting)
if("set_flow_rate")
@@ -269,11 +269,11 @@
if("max")
set_flow_rate = air1.volume
if("set")
- var/new_flow_rate = tgui_input_number(usr,"Enter new flow rate limit (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate,air1.volume,0)
+ var/new_flow_rate = tgui_input_number(ui.user,"Enter new flow rate limit (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate,air1.volume,0)
src.set_flow_rate = between(0, new_flow_rate, air1.volume)
update_icon()
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.has_tool_quality(TOOL_WRENCH))
diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm
index 4c1a0d0ad8..70b498722f 100644
--- a/code/ATMOSPHERICS/components/binary_devices/pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm
@@ -201,13 +201,13 @@ Thus, the two variables affect pump operation are set in New():
/obj/machinery/atmospherics/binary/pump/attack_hand(mob/user)
if(..())
return
- add_fingerprint(usr)
+ add_fingerprint(user)
if(!allowed(user))
to_chat(user, span_warning("Access denied."))
return
tgui_interact(user)
-/obj/machinery/atmospherics/binary/pump/tgui_act(action, params)
+/obj/machinery/atmospherics/binary/pump/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -223,11 +223,11 @@ Thus, the two variables affect pump operation are set in New():
if("max")
target_pressure = max_pressure_setting
if("set")
- var/new_pressure = tgui_input_number(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure,max_pressure_setting,0)
+ var/new_pressure = tgui_input_number(ui.user,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure,max_pressure_setting,0)
src.target_pressure = between(0, new_pressure, max_pressure_setting)
. = TRUE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
update_icon()
/obj/machinery/atmospherics/binary/pump/power_change()
diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm
index 4409482f50..4d442b772a 100644
--- a/code/ATMOSPHERICS/components/omni_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm
@@ -152,7 +152,7 @@
else
return null
-/obj/machinery/atmospherics/omni/atmos_filter/tgui_act(action, params)
+/obj/machinery/atmospherics/omni/atmos_filter/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -171,7 +171,7 @@
if("set_flow_rate")
if(!configuring || use_power)
return
- var/new_flow_rate = tgui_input_number(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate,max_flow_rate,0)
+ var/new_flow_rate = tgui_input_number(ui.user,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate,max_flow_rate,0)
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
. = TRUE
if("switch_mode")
@@ -182,7 +182,7 @@
if("switch_filter")
if(!configuring || use_power)
return
- var/new_filter = tgui_input_list(usr, "Select filter mode:", "Change filter", list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide"))
+ var/new_filter = tgui_input_list(ui.user, "Select filter mode:", "Change filter", list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide"))
if(!new_filter)
return
switch_filter(dir_flag(params["dir"]), mode_return_switch(new_filter))
diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm
index 02c701c91e..9d0b9c78f7 100644
--- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/mixer.dm
@@ -164,7 +164,7 @@
return data
-/obj/machinery/atmospherics/omni/mixer/tgui_act(action, params)
+/obj/machinery/atmospherics/omni/mixer/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -184,7 +184,7 @@
. = TRUE
if(!configuring || use_power)
return
- var/new_flow_rate = tgui_input_number(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate,max_flow_rate,0)
+ var/new_flow_rate = tgui_input_number(ui.user,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate,max_flow_rate,0)
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
if("switch_mode")
. = TRUE
@@ -195,7 +195,7 @@
. = TRUE
if(!configuring || use_power)
return
- change_concentration(dir_flag(params["dir"]))
+ change_concentration(dir_flag(params["dir"]), ui.user)
if("switch_conlock")
. = TRUE
if(!configuring || use_power)
@@ -244,7 +244,7 @@
update_ports()
rebuild_mixing_inputs()
-/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
+/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH, mob/user)
tag_north_con = null
tag_south_con = null
tag_east_con = null
@@ -266,7 +266,7 @@
if(non_locked < 1)
return
- var/new_con = (tgui_input_number(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100, round(remain_con * 100, 0.5), 0)) / 100
+ var/new_con = (tgui_input_number(user,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100, round(remain_con * 100, 0.5), 0)) / 100
//cap it between 0 and the max remaining concentration
new_con = between(0, new_con, remain_con)
diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
index 9201cee4a1..9e6613ebf2 100644
--- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
@@ -101,7 +101,7 @@
if(..())
return
- src.add_fingerprint(usr)
+ src.add_fingerprint(user)
tgui_interact(user)
return
diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm
index 7517cbd7ef..2084b8c901 100644
--- a/code/ATMOSPHERICS/components/shutoff.dm
+++ b/code/ATMOSPHERICS/components/shutoff.dm
@@ -32,7 +32,7 @@ GLOBAL_LIST_EMPTY(shutoff_valves)
return src.attack_hand(user)
/obj/machinery/atmospherics/valve/shutoff/attack_hand(var/mob/user)
- src.add_fingerprint(usr)
+ src.add_fingerprint(user)
update_icon(1)
close_on_leaks = !close_on_leaks
to_chat(user, "You [close_on_leaks ? "enable" : "disable"] the automatic shutoff circuit.")
diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
index 31544ac1f7..f332afee61 100755
--- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
@@ -182,7 +182,7 @@
return data
-/obj/machinery/atmospherics/trinary/atmos_filter/tgui_act(action, params)
+/obj/machinery/atmospherics/trinary/atmos_filter/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -216,7 +216,7 @@
if(4)//removing N2O
filtered_out += "nitrous_oxide"
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
update_icon()
//
diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
index 6397be2c59..86ee751762 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
@@ -100,11 +100,11 @@
if(..())
return
tgui_interact(user)
- // src.add_fingerprint(usr)
+ // src.add_fingerprint(user)
// if(!src.allowed(user))
// to_chat(user, span_warning("Access denied."))
// return
- // usr.set_machine(src)
+ // user.set_machine(src)
// var/list/node_connects = get_node_connect_dirs()
// var/dat = {span_bold("Power: ") + "[use_power?"On":"Off"]
// Set Flow Rate Limit:
diff --git a/code/ATMOSPHERICS/components/tvalve.dm b/code/ATMOSPHERICS/components/tvalve.dm
index 0e051d9067..9f0f220ec2 100644
--- a/code/ATMOSPHERICS/components/tvalve.dm
+++ b/code/ATMOSPHERICS/components/tvalve.dm
@@ -161,7 +161,7 @@
return
/obj/machinery/atmospherics/tvalve/attack_hand(mob/user as mob)
- src.add_fingerprint(usr)
+ src.add_fingerprint(user)
update_icon(1)
sleep(10)
if (src.state)
diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm
index 9923078311..5dd984a0ff 100644
--- a/code/ATMOSPHERICS/components/unary/cold_sink.dm
+++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm
@@ -84,7 +84,7 @@
return data
-/obj/machinery/atmospherics/unary/freezer/tgui_act(action, params)
+/obj/machinery/atmospherics/unary/freezer/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -103,7 +103,7 @@
var/new_setting = between(0, text2num(params["value"]), 100)
set_power_level(new_setting)
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
/obj/machinery/atmospherics/unary/freezer/process()
..()
diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm
index 67839d7d3a..2c1a22a825 100644
--- a/code/ATMOSPHERICS/components/unary/heat_source.dm
+++ b/code/ATMOSPHERICS/components/unary/heat_source.dm
@@ -104,7 +104,7 @@
return data
-/obj/machinery/atmospherics/unary/heater/tgui_act(action, params)
+/obj/machinery/atmospherics/unary/heater/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -123,7 +123,7 @@
var/new_setting = between(0, text2num(params["value"]), 100)
set_power_level(new_setting)
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
//upgrading parts
/obj/machinery/atmospherics/unary/heater/RefreshParts()
diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm
index 9139f96e74..d51a369529 100644
--- a/code/ATMOSPHERICS/components/valve.dm
+++ b/code/ATMOSPHERICS/components/valve.dm
@@ -131,7 +131,7 @@
return
/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob)
- src.add_fingerprint(usr)
+ src.add_fingerprint(user)
update_icon(1)
sleep(10)
if (src.open)
diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm
index 5173da844c..2c4360add9 100644
--- a/code/__defines/MC.dm
+++ b/code/__defines/MC.dm
@@ -18,6 +18,15 @@
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
+///creates a running average of "things elapsed" per time period when you need to count via a smaller time period.
+///eg you want an average number of things happening per second but you measure the event every tick (50 milliseconds).
+///make sure both time intervals are in the same units. doesn't work if current_duration > total_duration or if total_duration == 0
+#define MC_AVG_OVER_TIME(average, current, total_duration, current_duration) ((((total_duration) - (current_duration)) / (total_duration)) * (average) + (current))
+
+#define MC_AVG_MINUTES(average, current, current_duration) (MC_AVG_OVER_TIME(average, current, 1 MINUTES, current_duration))
+
+#define MC_AVG_SECONDS(average, current, current_duration) (MC_AVG_OVER_TIME(average, current, 1 SECONDS, current_duration))
+
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
#define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum}
@@ -70,18 +79,35 @@
#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
/datum/controller/subsystem/##X/New(){\
- NEW_SS_GLOBAL(SS##X);\
- PreInit();\
+ NEW_SS_GLOBAL(SS##X);\
+ PreInit();\
}\
/datum/controller/subsystem/##X
+#define TIMER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/timer/##X);\
+/datum/controller/subsystem/timer/##X/New(){\
+ NEW_SS_GLOBAL(SS##X);\
+ PreInit();\
+}\
+/datum/controller/subsystem/timer/##X/fire() {..() /*just so it shows up on the profiler*/} \
+/datum/controller/subsystem/timer/##X
+
#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\
/datum/controller/subsystem/processing/##X/New(){\
- NEW_SS_GLOBAL(SS##X);\
- PreInit();\
+ NEW_SS_GLOBAL(SS##X);\
+ PreInit();\
}\
+/datum/controller/subsystem/processing/##X/fire() {..() /*just so it shows up on the profiler*/} \
/datum/controller/subsystem/processing/##X
+#define VERB_MANAGER_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/verb_manager/##X);\
+/datum/controller/subsystem/verb_manager/##X/New(){\
+ NEW_SS_GLOBAL(SS##X);\
+ PreInit();\
+}\
+/datum/controller/subsystem/verb_manager/##X/fire() {..() /*just so it shows up on the profiler*/} \
+/datum/controller/subsystem/verb_manager/##X
+
// Boilerplate code for multi-step processors. See machines.dm for example use.
#define INTERNAL_PROCESS_STEP(this_step, initial_step, proc_to_call, cost_var, next_step)\
if(current_step == this_step || (initial_step && !resumed)) /* So we start at step 1 if not resumed.*/ {\
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index a06ef90f7a..f8ee1c976e 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -187,6 +187,10 @@ What is the naming convention for planes or layers?
#define PLANE_PLAYER_HUD_ITEMS 96 //Separate layer with which to apply colorblindness
#define PLANE_PLAYER_HUD_ABOVE 97 //Things above the player hud
+#define RADIAL_BACKGROUND_LAYER 0
+///1000 is an unimportant number, it's just to normalize copied layers
+#define RADIAL_CONTENT_LAYER 1000
+
#define PLANE_ADMIN3 99 //Purely for shenanigans (above HUD)
diff --git a/code/__defines/callbacks.dm b/code/__defines/callbacks.dm
index 126ef1ea1c..91d036b944 100644
--- a/code/__defines/callbacks.dm
+++ b/code/__defines/callbacks.dm
@@ -1,4 +1,8 @@
-#define GLOBAL_PROC "some_magic_bullshit"
-
+#define GLOBAL_PROC "some_magic_bullshit"
+/// A shorthand for the callback datum, [documented here](datum/callback.html)
#define CALLBACK new /datum/callback
+
#define INVOKE_ASYNC world.ImmediateInvokeAsync
+
+/// like CALLBACK but specifically for verb callbacks
+#define VERB_CALLBACK new /datum/callback/verb_callback
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index 313da615bd..4d80021c0f 100644
--- a/code/__defines/subsystems.dm
+++ b/code/__defines/subsystems.dm
@@ -189,6 +189,8 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_OVERLAYS 500
#define FIRE_PRIORITY_TIMER 700
+#define FIRE_PRIORITY_SPEECH_CONTROLLER 900
+#define FIRE_PRIORITY_DELAYED_VERBS 950
#define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost.
/**
diff --git a/code/__defines/update_icons.dm b/code/__defines/update_icons.dm
index 4fa21751be..7120edd168 100644
--- a/code/__defines/update_icons.dm
+++ b/code/__defines/update_icons.dm
@@ -1 +1,49 @@
-#define MOB_WATER_LAYER 36
+// These are used as the layers for the icons, as well as indexes in a list that holds onto them.
+// Technically the layers used are all -100+layer to make them FLOAT_LAYER overlays.
+//Human Overlays Indexes/////////
+#define MUTATIONS_LAYER 1 //Mutations like fat, and lasereyes
+#define SKIN_LAYER 2 //Skin things added by a call on species
+#define BLOOD_LAYER 3 //Bloodied hands/feet/anything else
+#define BODYPARTS_LAYER 4 //Bodyparts layer
+#define MOB_DAM_LAYER 5 //Injury overlay sprites like open wounds
+#define SURGERY_LAYER 6 //Overlays for open surgical sites
+#define UNDERWEAR_LAYER 7 //Underwear/bras/etc
+#define TAIL_LOWER_LAYER 8 //Tail as viewed from the south
+#define WING_LOWER_LAYER 9 //Wings as viewed from the south
+#define SHOES_LAYER_ALT 10 //Shoe-slot item (when set to be under uniform via verb)
+#define UNIFORM_LAYER 11 //Uniform-slot item
+#define ID_LAYER 12 //ID-slot item
+#define SHOES_LAYER 13 //Shoe-slot item
+#define GLOVES_LAYER 14 //Glove-slot item
+#define BELT_LAYER 15 //Belt-slot item
+#define SUIT_LAYER 16 //Suit-slot item
+#define TAIL_UPPER_LAYER 17 //Some species have tails to render (As viewed from the N, E, or W)
+#define GLASSES_LAYER 18 //Eye-slot item
+#define BELT_LAYER_ALT 19 //Belt-slot item (when set to be above suit via verb)
+#define SUIT_STORE_LAYER 20 //Suit storage-slot item
+#define BACK_LAYER 21 //Back-slot item
+#define HAIR_LAYER 22 //The human's hair
+#define HAIR_ACCESSORY_LAYER 23 //Simply move this up a number if things are added.
+#define EARS_LAYER 24 //Both ear-slot items (combined image)
+#define EYES_LAYER 25 //Mob's eyes (used for glowing eyes)
+#define FACEMASK_LAYER 26 //Mask-slot item
+#define GLASSES_LAYER_ALT 27 //So some glasses can appear on top of hair and things
+#define HEAD_LAYER 28 //Head-slot item
+#define HANDCUFF_LAYER 29 //Handcuffs, if the human is handcuffed, in a secret inv slot
+#define LEGCUFF_LAYER 30 //Same as handcuffs, for legcuffs
+#define L_HAND_LAYER 31 //Left-hand item
+#define R_HAND_LAYER 32 //Right-hand item
+#define WING_LAYER 33 //Wings or protrusions over the suit.
+#define TAIL_UPPER_LAYER_ALT 34 //Modified tail-sprite layer. Tend to be larger.
+#define MODIFIER_EFFECTS_LAYER 35 //Effects drawn by modifiers
+#define FIRE_LAYER 36 //'Mob on fire' overlay layer
+#define MOB_WATER_LAYER 37
+#define TARGETED_LAYER 38 //'Aimed at' overlay layer
+#define VORE_BELLY_LAYER 39
+#define VORE_TAIL_LAYER 40
+
+#define TOTAL_LAYERS 40 // <---- KEEP THIS UPDATED, should always equal the highest number here, used to initialize a list.
+
+//These two are only used for gargoyles currently
+#define HUMAN_BODY_LAYERS list(MUTATIONS_LAYER, TAIL_LOWER_LAYER, WING_LOWER_LAYER, BODYPARTS_LAYER, SKIN_LAYER, BLOOD_LAYER, MOB_DAM_LAYER, TAIL_UPPER_LAYER, HAIR_LAYER, HAIR_ACCESSORY_LAYER, EYES_LAYER, WING_LAYER, VORE_BELLY_LAYER, VORE_TAIL_LAYER, TAIL_UPPER_LAYER_ALT)
+#define HUMAN_OTHER_LAYERS list(MODIFIER_EFFECTS_LAYER, FIRE_LAYER, MOB_WATER_LAYER, TARGETED_LAYER)
diff --git a/code/__defines/verb_manager.dm b/code/__defines/verb_manager.dm
new file mode 100644
index 0000000000..11ea6ada4d
--- /dev/null
+++ b/code/__defines/verb_manager.dm
@@ -0,0 +1,36 @@
+/**
+ * verb queuing thresholds. remember that since verbs execute after SendMaps the player wont see the effects of the verbs on the game world
+ * until SendMaps executes next tick, and then when that later update reaches them. thus most player input has a minimum latency of world.tick_lag + player ping.
+ * however thats only for the visual effect of player input, when a verb processes the actual latency of game state changes or semantic latency is effectively 1/2 player ping,
+ * unless that verb is queued for the next tick in which case its some number probably smaller than world.tick_lag.
+ * so some verbs that represent player input are important enough that we only introduce semantic latency if we absolutely need to.
+ * its for this reason why player clicks are handled in SSinput before even movement - semantic latency could cause someone to move out of range
+ * when the verb finally processes but it was in range if the verb had processed immediately and overtimed.
+ */
+
+///queuing tick_usage threshold for verbs that are high enough priority that they only queue if the server is overtiming.
+///ONLY use for critical verbs
+#define VERB_OVERTIME_QUEUE_THRESHOLD 100
+///queuing tick_usage threshold for verbs that need lower latency more than most verbs.
+#define VERB_HIGH_PRIORITY_QUEUE_THRESHOLD 95
+///default queuing tick_usage threshold for most verbs which can allow a small amount of latency to be processed in the next tick
+#define VERB_DEFAULT_QUEUE_THRESHOLD 85
+
+///attempt to queue this verb process if the server is overloaded. evaluates to FALSE if queuing isnt necessary or if it failed.
+///_verification_args... are only necessary if the verb_manager subsystem youre using checks them in can_queue_verb()
+///if you put anything in _verification_args that ISNT explicitely put in the can_queue_verb() override of the subsystem youre using,
+///it will runtime.
+#define TRY_QUEUE_VERB(_verb_callback, _tick_check, _subsystem_to_use, _verification_args...) (_queue_verb(_verb_callback, _tick_check, _subsystem_to_use, _verification_args))
+///queue wrapper for TRY_QUEUE_VERB() when you want to call the proc if the server isnt overloaded enough to queue
+#define QUEUE_OR_CALL_VERB(_verb_callback, _tick_check, _subsystem_to_use, _verification_args...) \
+ if(!TRY_QUEUE_VERB(_verb_callback, _tick_check, _subsystem_to_use, _verification_args)) {\
+ _verb_callback:InvokeAsync() \
+ };
+
+//goes straight to SSverb_manager with default tick threshold
+#define DEFAULT_TRY_QUEUE_VERB(_verb_callback, _verification_args...) (TRY_QUEUE_VERB(_verb_callback, VERB_DEFAULT_QUEUE_THRESHOLD, null, _verification_args))
+#define DEFAULT_QUEUE_OR_CALL_VERB(_verb_callback, _verification_args...) QUEUE_OR_CALL_VERB(_verb_callback, VERB_DEFAULT_QUEUE_THRESHOLD, null, _verification_args)
+
+//default tick threshold but nondefault subsystem
+#define TRY_QUEUE_VERB_FOR(_verb_callback, _subsystem_to_use, _verification_args...) (TRY_QUEUE_VERB(_verb_callback, VERB_DEFAULT_QUEUE_THRESHOLD, _subsystem_to_use, _verification_args))
+#define QUEUE_OR_CALL_VERB_FOR(_verb_callback, _subsystem_to_use, _verification_args...) QUEUE_OR_CALL_VERB(_verb_callback, VERB_DEFAULT_QUEUE_THRESHOLD, _subsystem_to_use, _verification_args)
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 59be2633d7..8b5c5d0325 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -420,7 +420,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/select_active_ai(var/mob/user)
var/list/ais = active_ais()
if(ais.len)
- if(user) . = tgui_input_list(usr, "AI signals detected:", "AI selection", ais)
+ if(user) . = tgui_input_list(user, "AI signals detected:", "AI selection", ais)
else . = pick(ais)
return .
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 15acd142c6..80d086a298 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -44,7 +44,7 @@
if(aiCamera && aiCamera.in_camera_mode)
aiCamera.camera_mode_off()
if(is_component_functioning("camera"))
- aiCamera.captureimage(A, usr)
+ aiCamera.captureimage(A, src)
else
to_chat(src, span_userdanger("Your camera isn't functional."))
return
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 774acba147..518c3e03c5 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -396,7 +396,7 @@ var/list/global_huds = list(
set hidden = 1
if(!hud_used)
- to_chat(usr, span_warning("This mob type does not use a HUD."))
+ to_chat(src, span_warning("This mob type does not use a HUD."))
return FALSE
if(!client)
return FALSE
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 32725ec5ae..b803227325 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -3,33 +3,52 @@
GLOBAL_LIST_EMPTY(radial_menus)
-// Ported from TG
-
/obj/screen/radial
icon = 'icons/mob/radial.dmi'
- layer = LAYER_HUD_ABOVE
plane = PLANE_PLAYER_HUD_ABOVE
+ vis_flags = VIS_INHERIT_PLANE
+ var/click_on_hover = FALSE
var/datum/radial_menu/parent
+/obj/screen/radial/proc/set_parent(new_value)
+ if(parent)
+ UnregisterSignal(parent, COMSIG_PARENT_QDELETING)
+ parent = new_value
+ if(parent)
+ RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(handle_parent_del))
+
+/obj/screen/radial/proc/handle_parent_del()
+ SIGNAL_HANDLER
+ set_parent(null)
+
/obj/screen/radial/slice
icon_state = "radial_slice"
var/choice
var/next_page = FALSE
var/tooltips = FALSE
-/obj/screen/radial/Destroy()
- parent = null
- return ..()
+/obj/screen/radial/slice/set_parent(new_value)
+ . = ..()
+ if(parent)
+ icon_state = parent.radial_slice_icon
/obj/screen/radial/slice/MouseEntered(location, control, params)
. = ..()
- icon_state = "radial_slice_focus"
+ if(next_page || !parent)
+ icon_state = "radial_slice_focus"
+ else
+ icon_state = "[parent.radial_slice_icon]_focus"
if(tooltips)
openToolTip(usr, src, params, title = name)
+ if (click_on_hover && !isnull(usr) && !isnull(parent))
+ Click(location, control, params)
/obj/screen/radial/slice/MouseExited(location, control, params)
. = ..()
- icon_state = "radial_slice"
+ if(next_page || !parent)
+ icon_state = "radial_slice"
+ else
+ icon_state = parent.radial_slice_icon
if(tooltips)
closeToolTip(usr)
@@ -38,7 +57,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
if(next_page)
parent.next_page()
else
- parent.element_chosen(choice,usr)
+ parent.element_chosen(choice, usr, params)
/obj/screen/radial/center
name = "Close Menu"
@@ -57,9 +76,18 @@ GLOBAL_LIST_EMPTY(radial_menus)
parent.finished = TRUE
/datum/radial_menu
- var/list/choices = list() //List of choice id's
- var/list/choices_icons = list() //choice_id -> icon
- var/list/choices_values = list() //choice_id -> choice
+ /// List of choice IDs
+ var/list/choices = list()
+
+ /// choice_id -> icon
+ var/list/choices_icons = list()
+
+ /// choice_id -> choice
+ var/list/choices_values = list()
+
+ /// choice_id -> /datum/radial_menu_choice
+ var/list/choice_datums = list()
+
var/list/page_data = list() //list of choices per page
@@ -87,6 +115,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/py_shift = 0
var/entry_animation = TRUE
+ ///A replacement icon state for the generic radial slice bg icon. Doesn't affect the next page nor the center buttons
+ var/radial_slice_icon
+
//If we swap to vis_contens inventory these will need a redo
/datum/radial_menu/proc/check_screen_border(mob/user)
var/atom/movable/AM = anchor
@@ -98,6 +129,8 @@ GLOBAL_LIST_EMPTY(radial_menus)
else
py_shift = 32
restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth.
+ else if(hudfix_method && AM.loc)
+ anchor = get_atom_on_turf(anchor)
//Sets defaults
//These assume 45 deg min_angle
@@ -116,7 +149,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
starting_angle = 180
ending_angle = 45
-/datum/radial_menu/proc/setup_menu(use_tooltips)
+/datum/radial_menu/proc/setup_menu(use_tooltips, set_page = 1, click_on_hover = FALSE)
if(ending_angle > starting_angle)
zone = ending_angle - starting_angle
else
@@ -129,7 +162,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
for(var/i in 1 to elements_to_add) //Create all elements
var/obj/screen/radial/slice/new_element = new /obj/screen/radial/slice
new_element.tooltips = use_tooltips
- new_element.parent = src
+ new_element.set_parent(src)
elements += new_element
var/page = 1
@@ -152,22 +185,31 @@ GLOBAL_LIST_EMPTY(radial_menus)
page_data[page] = current
pages = page
- current_page = 1
- update_screen_objects(anim = entry_animation)
+ current_page = clamp(set_page, 1, pages)
+ update_screen_objects(entry_animation, click_on_hover)
-/datum/radial_menu/proc/update_screen_objects(anim = FALSE)
+/datum/radial_menu/proc/update_screen_objects(anim = FALSE, click_on_hover = FALSE)
var/list/page_choices = page_data[current_page]
var/angle_per_element = round(zone / page_choices.len)
for(var/i in 1 to elements.len)
- var/obj/screen/radial/E = elements[i]
+ var/obj/screen/radial/element = elements[i]
var/angle = WRAP(starting_angle + (i - 1) * angle_per_element,0,360)
if(i > page_choices.len)
- HideElement(E)
+ HideElement(element)
+ element.click_on_hover = FALSE
else
- SetElement(E,page_choices[i],angle,anim = anim,anim_order = i)
+ SetElement(element,page_choices[i],angle,anim = anim,anim_order = i)
+ // Only activate click on hover after the animation plays
+ if (!click_on_hover)
+ continue
+ if (anim)
+ addtimer(VARSET_CALLBACK(element, click_on_hover, TRUE), i * 0.5)
+ else
+ element.click_on_hover = TRUE
/datum/radial_menu/proc/HideElement(obj/screen/radial/slice/E)
E.cut_overlays()
+ E.vis_contents.Cut()
E.alpha = 0
E.name = "None"
E.maptext = null
@@ -194,13 +236,22 @@ GLOBAL_LIST_EMPTY(radial_menus)
E.alpha = 255
E.mouse_opacity = MOUSE_OPACITY_ICON
E.cut_overlays()
+ E.vis_contents.Cut()
if(choice_id == NEXT_PAGE_ID)
E.name = "Next Page"
E.next_page = TRUE
+ E.icon_state = "radial_slice" // Resets the bg icon state to the default for next page buttons.
E.add_overlay("radial_next")
else
- if(istext(choices_values[choice_id]))
+ //This isn't granted to exist, so use the ?. operator for conditionals that use it.
+ var/datum/radial_menu_choice/choice_datum = choice_datums[choice_id]
+ if(choice_datum?.name)
+ E.name = choice_datum.name
+ else if(istext(choices_values[choice_id]))
E.name = choices_values[choice_id]
+ else if(ispath(choices_values[choice_id],/atom))
+ var/atom/A = choices_values[choice_id]
+ E.name = initial(A.name)
else
var/atom/movable/AM = choices_values[choice_id] //Movables only
E.name = AM.name
@@ -209,15 +260,21 @@ GLOBAL_LIST_EMPTY(radial_menus)
E.next_page = FALSE
if(choices_icons[choice_id])
E.add_overlay(choices_icons[choice_id])
+ if (choice_datum?.info)
+ var/obj/effect/abstract/info/info_button = new(E, choice_datum.info)
+ info_button.plane = PLANE_PLAYER_HUD_ABOVE
+ info_button.layer = RADIAL_CONTENT_LAYER
+ E.vis_contents += info_button
/datum/radial_menu/New()
close_button = new
- close_button.parent = src
+ close_button.set_parent(src)
/datum/radial_menu/proc/Reset()
choices.Cut()
choices_icons.Cut()
choices_values.Cut()
+ choice_datums.Cut()
current_page = 1
/datum/radial_menu/proc/element_chosen(choice_id,mob/user)
@@ -226,7 +283,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
/datum/radial_menu/proc/get_next_id()
return "c_[choices.len]"
-/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips)
+/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips, click_on_hover = FALSE, set_page = 1)
if(choices.len)
Reset()
for(var/E in new_choices)
@@ -237,13 +294,20 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/I = extract_image(new_choices[E])
if(I)
choices_icons[id] = I
- setup_menu(use_tooltips)
+ if (istype(new_choices[E], /datum/radial_menu_choice))
+ choice_datums[id] = new_choices[E]
+ setup_menu(use_tooltips, set_page, click_on_hover)
-/datum/radial_menu/proc/extract_image(E)
- var/mutable_appearance/MA = new /mutable_appearance(E)
+/datum/radial_menu/proc/extract_image(to_extract_from)
+ if (istype(to_extract_from, /datum/radial_menu_choice))
+ var/datum/radial_menu_choice/choice = to_extract_from
+ to_extract_from = choice.image
+
+ var/mutable_appearance/MA = new /mutable_appearance(to_extract_from)
if(MA)
- MA.layer = LAYER_HUD_ABOVE
+ MA.plane = PLANE_PLAYER_HUD_ABOVE
+ MA.layer = RADIAL_CONTENT_LAYER
MA.appearance_flags |= RESET_TRANSFORM
return MA
@@ -253,15 +317,16 @@ GLOBAL_LIST_EMPTY(radial_menus)
current_page = WRAP(current_page + 1,1,pages+1)
update_screen_objects()
-/datum/radial_menu/proc/show_to(mob/M)
+/datum/radial_menu/proc/show_to(mob/M, offset_x = 0, offset_y = 0)
if(current_user)
hide()
if(!M.client || !anchor)
return
current_user = M.client
//Blank
- menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = LAYER_HUD_ABOVE)
- menu_holder.appearance_flags |= KEEP_APART
+ menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER, pixel_x = offset_x, pixel_y = offset_y)
+ menu_holder.plane = PLANE_PLAYER_HUD_ABOVE
+ menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM
menu_holder.vis_contents += elements + close_button
current_user.images += menu_holder
@@ -283,9 +348,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
/datum/radial_menu/Destroy()
Reset()
hide()
- QDEL_LIST_NULL(elements)
- QDEL_NULL(close_button)
- QDEL_NULL(custom_check_callback)
+ custom_check_callback = null
. = ..()
/*
@@ -293,30 +356,66 @@ GLOBAL_LIST_EMPTY(radial_menus)
Choices should be a list where list keys are movables or text used for element names and return value
and list values are movables/icons/images used for element icons
*/
-/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE)
+/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, entry_animation = TRUE, click_on_hover = FALSE, user_space = FALSE)
if(!user || !anchor || !length(choices))
return
+
+ if(length(choices)==1 && autopick_single_option)
+ return choices[1]
+
if(!uniqueid)
uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
if(GLOB.radial_menus[uniqueid])
+ if(!no_repeat_close)
+ var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid]
+ menu.finished = TRUE
return
var/datum/radial_menu/menu = new
+ menu.entry_animation = entry_animation
GLOB.radial_menus[uniqueid] = menu
if(radius)
menu.radius = radius
if(istype(custom_check))
menu.custom_check_callback = custom_check
- menu.anchor = anchor
+ menu.anchor = user_space ? user : anchor
+ menu.radial_slice_icon = radial_slice_icon
menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud
- menu.set_choices(choices, tooltips)
- menu.show_to(user)
+ menu.set_choices(choices, tooltips, click_on_hover)
+ var/offset_x = 0
+ var/offset_y = 0
+ if (user_space)
+ var/turf/user_turf = get_turf(user)
+ var/turf/anchor_turf = get_turf(anchor)
+ offset_x = (anchor_turf.x - user_turf.x) * ICON_SIZE_X + anchor.pixel_x - user.pixel_x
+ offset_y = (anchor_turf.y - user_turf.y) * ICON_SIZE_Y + anchor.pixel_y - user.pixel_y
+ menu.show_to(user, offset_x, offset_y)
menu.wait(user, anchor, require_near)
var/answer = menu.selected_choice
- QDEL_NULL(menu)
+ qdel(menu)
GLOB.radial_menus -= uniqueid
+ if(require_near && !in_range(anchor, user))
+ return
+ if(istype(custom_check))
+ if(!custom_check.Invoke())
+ return
return answer
+/// Can be provided to choices in radial menus if you want to provide more information
+/datum/radial_menu_choice
+ /// Required -- what to display for this button
+ var/image
+
+ /// If provided, this will be the name the radial slice hud button. This has priority over everything else.
+ var/name
+
+ /// If provided, will display an info button that will put this text in your chat
+ var/info
+
+/datum/radial_menu_choice/Destroy(force)
+ . = ..()
+ QDEL_NULL(image)
+
#undef NEXT_PAGE_ID
#undef DEFAULT_CHECK_DELAY
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 06c93c37fb..4b062a6b5f 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -282,11 +282,11 @@ var/obj/screen/robot_inventory
//r.client.screen += robot_inventory //"store" icon
if(!r.module)
- to_chat(usr, span_danger("No module selected"))
+ to_chat(r, span_danger("No module selected"))
return
if(!r.module.modules)
- to_chat(usr, span_danger("Selected module has no modules to select"))
+ to_chat(r, span_danger("Selected module has no modules to select"))
return
if(!r.robot_modules_background)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
deleted file mode 100644
index b741f129ed..0000000000
--- a/code/controllers/configuration.dm
+++ /dev/null
@@ -1,1203 +0,0 @@
-var/list/gamemode_cache = list()
-
-/datum/configuration
- var/static/server_name = null // server name (for world name / status)
- var/static/server_suffix = 0 // generate numeric suffix based on server port
-
- var/static/nudge_script_path = "nudge.py" // where the nudge.py script is located
-
- var/static/log_ooc = 0 // log OOC channel
- var/static/log_access = 0 // log login/logout
- var/static/log_say = 0 // log client say
- var/static/log_admin = 0 // log admin actions
- var/static/log_debug = 1 // log debug output
- var/static/log_game = 0 // log game events
- var/static/log_vote = 0 // log voting
- var/static/log_whisper = 0 // log client whisper
- var/static/log_emote = 0 // log emotes
- var/static/log_attack = 0 // log attack messages
- var/static/log_adminchat = 0 // log admin chat messages
- var/static/log_adminwarn = 0 // log warnings admins get about bomb construction and such
- var/static/log_pda = 0 // log pda messages
- var/static/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
- var/static/log_runtime = 0 // logs world.log to a file
- var/static/log_world_output = 0 // log to_world_log(messages)
- var/static/log_graffiti = 0 // logs graffiti
- var/static/sql_enabled = 0 // for sql switching
- var/static/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
- var/static/allow_vote_restart = 0 // allow votes to restart
- var/static/ert_admin_call_only = 0
- var/static/allow_vote_mode = 0 // allow votes to change mode
- var/static/allow_admin_jump = 1 // allows admin jumping
- var/static/allow_admin_spawning = 1 // allows admin item spawning
- var/static/allow_admin_rev = 1 // allows admin revives
- var/static/pregame_time = 180 // pregame time in seconds
- var/static/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default)
- var/static/vote_period = 600 // length of voting period (deciseconds, default 1 minute)
- var/static/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called
- var/static/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote
- var/static/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100).
- var/static/vote_no_default = 0 // vote does not default to nochange/norestart (tbi)
- var/static/vote_no_dead = 0 // dead people can't vote (tbi)
-// var/static/enable_authentication = 0 // goon authentication
- var/static/del_new_on_log = 1 // del's new players if they log before they spawn in
- var/static/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard
- var/static/traitor_scaling = 0 //if amount of traitors scales based on amount of players
- var/static/objectives_disabled = 0 //if objectives are disabled or not
- var/static/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other
- var/static/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke.
- var/static/allow_Metadata = 0 // Metadata is supported.
- var/static/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1.
- var/static/fps = 20
- var/static/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling
- var/static/Tickcomp = 0
- var/static/socket_talk = 0 // use socket_talk to communicate with other processes
- var/static/list/resource_urls = null
- var/static/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
- var/static/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round.
- var/static/list/mode_names = list()
- var/static/list/modes = list() // allowed modes
- var/static/list/votable_modes = list() // votable modes
- var/static/list/probabilities = list() // relative probability of each mode
- var/static/list/player_requirements = list() // Overrides for how many players readied up a gamemode needs to start.
- var/static/list/player_requirements_secret = list() // Same as above, but for the secret gamemode.
- var/static/humans_need_surnames = 0
- var/static/allow_random_events = 0 // enables random events mid-round when set to 1
- var/static/enable_game_master = 0 // enables the 'smart' event system.
- var/static/allow_ai = 1 // allow ai job
- var/static/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable.
- var/static/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell
- var/static/hostedby = null
-
- var/static/respawn = 1
- var/static/respawn_time = 3000 // time before a dead player is allowed to respawn (in ds, though the config file asks for minutes, and it's converted below)
- var/static/respawn_message = span_boldnotice("Make sure to play a different character, and please roleplay correctly!")
-
- var/static/guest_jobban = 1
- var/static/usewhitelist = 0
- var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0
- var/static/show_mods = 0
- var/static/show_devs = 0
- var/static/show_mentors = 0
- var/static/show_event_managers = 0
- var/static/mods_can_tempban = 0
- var/static/mods_can_job_tempban = 0
- var/static/mod_tempban_max = 1440
- var/static/mod_job_tempban_max = 1440
- var/static/load_jobs_from_txt = 0
- var/static/ToRban = 0
- var/static/automute_on = 0 //enables automuting/spam prevention
- var/static/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
-
- var/static/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
- var/static/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
-
- var/static/character_slots = 10 // The number of available character slots
- var/static/loadout_slots = 3 // The number of loadout slots per character
-
- var/static/max_maint_drones = 5 //This many drones can spawn,
- var/static/allow_drone_spawn = 1 //assuming the admin allow them to.
- var/static/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes.
-
- var/static/disable_player_mice = 0
- var/static/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
-
- var/static/usealienwhitelist = 0
- var/static/limitalienplayers = 0
- var/static/alien_to_human_ratio = 0.5
- var/static/allow_extra_antags = 0
- var/static/guests_allowed = 1
- var/static/debugparanoid = 0
- var/static/panic_bunker = 0
- var/static/paranoia_logging = 0
-
- var/static/ip_reputation = FALSE //Should we query IPs to get scores? Generates HTTP traffic to an API service.
- var/static/ipr_email //Left null because you MUST specify one otherwise you're making the internet worse.
- var/static/ipr_block_bad_ips = FALSE //Should we block anyone who meets the minimum score below? Otherwise we just log it (If paranoia logging is on, visibly in chat).
- var/static/ipr_bad_score = 1 //The API returns a value between 0 and 1 (inclusive), with 1 being 'definitely VPN/Tor/Proxy'. Values equal/above this var are considered bad.
- var/static/ipr_allow_existing = FALSE //Should we allow known players to use VPNs/Proxies? If the player is already banned then obviously they still can't connect.
- var/static/ipr_minimum_age = 5 //How many days before a player is considered 'fine' for the purposes of allowing them to use VPNs.
-
- var/static/serverurl
- var/static/server
- var/static/banappeals
- var/static/wikiurl
- var/static/wikisearchurl
- var/static/forumurl
- var/static/githuburl
- var/static/discordurl
- var/static/rulesurl
- var/static/mapurl
- var/static/patreonurl
-
- //Alert level description
- var/static/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
- var/static/alert_desc_yellow_upto = "A minor security emergency has developed. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
- var/static/alert_desc_yellow_downto = "Code yellow procedures are now in effect. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
- var/static/alert_desc_violet_upto = "A major medical emergency has developed. Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey all relevant instructions from medical staff."
- var/static/alert_desc_violet_downto = "Code violet procedures are now in effect; Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey relevant instructions from medical staff."
- var/static/alert_desc_orange_upto = "A major engineering emergency has developed. Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
- var/static/alert_desc_orange_downto = "Code orange procedures are now in effect; Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
- var/static/alert_desc_blue_upto = "A major security emergency has developed. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
- var/static/alert_desc_blue_downto = "Code blue procedures are now in effect. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
- var/static/alert_desc_red_upto = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
- var/static/alert_desc_red_downto = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
- var/static/alert_desc_delta = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
-
- var/static/forbid_singulo_possession = 0
-
- //game_options.txt configs
-
- var/static/health_threshold_softcrit = 0
- var/static/health_threshold_crit = 0
- var/static/health_threshold_dead = -100
-
- var/static/organ_health_multiplier = 1
- var/static/organ_regeneration_multiplier = 1
- var/static/organs_decay
- var/static/default_brain_health = 400
- var/static/allow_headgibs = FALSE
-
- //Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt,
- //so that it's similar to HALLOSS. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun.
- var/static/organ_damage_spillover_multiplier = 0.5
-
- var/static/bones_can_break = 0
- var/static/limbs_can_break = 0
-
- var/static/revival_pod_plants = 1
- var/static/revival_cloning = 1
- var/static/revival_brain_life = -1
-
- var/static/use_loyalty_implants = 0
-
- var/static/welder_vision = 1
- var/static/generate_map = 0
- var/static/no_click_cooldown = 0
-
- //Used for modifying movement speed for mobs.
- //Unversal modifiers
- var/static/run_speed = 0
- var/static/walk_speed = 0
-
- //Mob specific modifiers. NOTE: These will affect different mob types in different ways
- var/static/human_delay = 0
- var/static/robot_delay = 0
- var/static/monkey_delay = 0
- var/static/alien_delay = 0
- var/static/slime_delay = 0
- var/static/animal_delay = 0
-
- var/static/footstep_volume = 0
-
- var/static/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
- var/static/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
- var/static/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
- var/static/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database
-
- var/static/simultaneous_pm_warning_timeout = 100
-
- var/static/use_recursive_explosions //Defines whether the server uses recursive or circular explosions.
- var/static/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels.
-
- var/static/assistant_maint = 0 //Do assistants get maint access?
- var/static/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour.
- var/static/ghost_interaction = 0
-
- var/static/comms_password = ""
-
- var/static/enter_allowed = 1
-
- var/use_irc_bot = 0
- var/use_node_bot = 0
- var/irc_bot_port = 0
- var/irc_bot_host = ""
- var/irc_bot_export = 0 // whether the IRC bot in use is a Bot32 (or similar) instance; Bot32 uses world.Export() instead of nudge.py/libnudge
- var/main_irc = ""
- var/admin_irc = ""
- var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix
- var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge.
- var/use_overmap = 0
-
- var/static/list/engine_map = list("Supermatter Engine", "Edison's Bane") // Comma separated list of engines to choose from. Blank means fully random.
-
- // Event settings
- var/static/expected_round_length = 3 * 60 * 60 * 10 // 3 hours
- // If the first delay has a custom start time
- // No custom time, no custom time, between 80 to 100 minutes respectively.
- var/static/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000))
- // The lowest delay until next event
- // 10, 30, 50 minutes respectively
- var/static/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000)
- // The upper delay until next event
- // 15, 45, 70 minutes respectively
- var/static/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000)
-
- var/static/aliens_allowed = 1 //Changed to 1 so player xenos can lay eggs.
- var/static/ninjas_allowed = 0
- var/static/abandon_allowed = 1
- var/static/ooc_allowed = 1
- var/static/looc_allowed = 1
- var/static/dooc_allowed = 1
- var/static/dsay_allowed = 1
-
- var/persistence_disabled = FALSE
- var/persistence_ignore_mapload = FALSE
-
- var/allow_byond_links = 0
- var/allow_discord_links = 0
- var/allow_url_links = 0 // honestly if I were you i'd leave this one off, only use in dire situations
-
- var/starlight = 0 // Whether space turfs have ambient light or not
-
- var/static/list/ert_species = list(SPECIES_HUMAN)
-
- var/static/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010"
-
- var/static/aggressive_changelog = 0
-
- var/static/list/language_prefixes = list(",","#")//Default language prefixes
-
- var/static/show_human_death_message = 1
-
- var/static/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf
- var/static/radiation_decay_rate = 1 //How much radiation is reduced by each tick
- var/static/radiation_resistance_multiplier = 8.5 //VOREstation edit
- var/static/radiation_material_resistance_divisor = 1
- var/static/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
-
- var/static/autostart_solars = FALSE // If true, specifically mapped in solar control computers will set themselves up when the round starts.
-
- // New shiny SQLite stuff.
- // The basics.
- var/static/sqlite_enabled = FALSE // If it should even be active. SQLite can be ran alongside other databases but you should not have them do the same functions.
-
- // In-Game Feedback.
- var/static/sqlite_feedback = FALSE // Feedback cannot be submitted if this is false.
- var/static/list/sqlite_feedback_topics = list("General") // A list of 'topics' that feedback can be catagorized under by the submitter.
- var/static/sqlite_feedback_privacy = FALSE // If true, feedback submitted can have its author name be obfuscated. This is not 100% foolproof (it's md5 ffs) but can stop casual snooping.
- var/static/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit.
- var/static/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers.
-
- var/static/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes.
- var/static/defib_braindamage_timer = 2 // How long until someone will get brain damage when defibbed, in minutes. The closer to the end of the above timer, the more brain damage they get.
-
- // disables the annoying "You have already logged in this round, disconnect or be banned" popup for multikeying, because it annoys the shit out of me when testing.
- var/static/disable_cid_warn_popup = FALSE
-
- // whether or not to use the nightshift subsystem to perform lighting changes
- var/static/enable_night_shifts = FALSE
-
- // How strictly the loadout enforces object species whitelists
- var/loadout_whitelist = LOADOUT_WHITELIST_LAX
-
- var/static/vgs_access_identifier = null // VOREStation Edit - VGS
- var/static/vgs_server_port = null // VOREStation Edit - VGS
-
- var/disable_webhook_embeds = FALSE
-
- var/static/list/jukebox_track_files
-
- var/static/suggested_byond_version
- var/static/suggested_byond_build
-
- var/static/invoke_youtubedl = null
-
-
- var/static/asset_transport
-
- var/static/cache_assets = FALSE
-
- var/static/save_spritesheets = FALSE
-
- var/static/asset_simple_preload = FALSE
-
- var/static/asset_cdn_webroot
-
- var/static/asset_cdn_url
-
- //Enables/Disables the appropriate mob type from obtaining the verb on spawn. Still allows admins to manually give it to them.
- var/static/allow_robot_recolor = FALSE
- var/static/allow_simple_mob_recolor = FALSE
-
-
-/datum/configuration/New()
- var/list/L = subtypesof(/datum/game_mode)
- for (var/T in L)
- // I wish I didn't have to instance the game modes in order to look up
- // their information, but it is the only way (at least that I know of).
- var/datum/game_mode/M = new T()
- if (M.config_tag)
- gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly.
- if(!(M.config_tag in modes)) // ensure each mode is added only once
- log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.")
- modes += M.config_tag
- mode_names[M.config_tag] = M.name
- probabilities[M.config_tag] = M.probability
- player_requirements[M.config_tag] = M.required_players
- player_requirements_secret[M.config_tag] = M.required_players_secret
- if (M.votable)
- src.votable_modes += M.config_tag
- src.votable_modes += "secret"
-
-/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist
- var/list/Lines = file2list(filename)
-
- for(var/t in Lines)
- if(!t) continue
-
- t = trim(t)
- if (length(t) == 0)
- continue
- else if (copytext(t, 1, 2) == "#")
- continue
-
- var/pos = findtext(t, " ")
- var/name = null
- var/value = null
-
- if (pos)
- name = lowertext(copytext(t, 1, pos))
- value = copytext(t, pos + 1)
- else
- name = lowertext(t)
-
- if (!name)
- continue
-
- if(type == "config")
- switch (name)
- if ("resource_urls")
- config.resource_urls = splittext(value, " ")
-
- if ("admin_legacy_system")
- config.admin_legacy_system = 1
-
- if ("ban_legacy_system")
- config.ban_legacy_system = 1
-
- if ("use_age_restriction_for_jobs")
- config.use_age_restriction_for_jobs = 1
-
- if ("use_age_restriction_for_antags")
- config.use_age_restriction_for_antags = 1
-
- if ("jobs_have_minimal_access")
- config.jobs_have_minimal_access = 1
-
- if ("use_recursive_explosions")
- use_recursive_explosions = 1
-
- if ("multi_z_explosion_scalar")
- multi_z_explosion_scalar = text2num(value)
-
- if ("log_ooc")
- config.log_ooc = 1
-
- if ("log_access")
- config.log_access = 1
-
- if ("sql_enabled")
- config.sql_enabled = 1
-
- if ("log_say")
- config.log_say = 1
-
- if ("debug_paranoid")
- config.debugparanoid = 1
-
- if ("log_admin")
- config.log_admin = 1
-
- if ("log_debug")
- config.log_debug = text2num(value)
-
- if ("log_game")
- config.log_game = 1
-
- if ("log_vote")
- config.log_vote = 1
-
- if ("log_whisper")
- config.log_whisper = 1
-
- if ("log_attack")
- config.log_attack = 1
-
- if ("log_emote")
- config.log_emote = 1
-
- if ("log_adminchat")
- config.log_adminchat = 1
-
- if ("log_adminwarn")
- config.log_adminwarn = 1
-
- if ("log_pda")
- config.log_pda = 1
-
- if ("log_world_output")
- config.log_world_output = 1
-
- if ("log_hrefs")
- config.log_hrefs = 1
-
- if ("log_runtime")
- config.log_runtime = 1
-
- if ("log_graffiti")
- config.log_graffiti = 1
-
- if ("generate_map")
- config.generate_map = 1
-
- if ("no_click_cooldown")
- config.no_click_cooldown = 1
-
- if("allow_admin_ooccolor")
- config.allow_admin_ooccolor = 1
-
- if ("allow_vote_restart")
- config.allow_vote_restart = 1
-
- if ("allow_vote_mode")
- config.allow_vote_mode = 1
-
- if ("allow_admin_jump")
- config.allow_admin_jump = 1
-
- if("allow_admin_rev")
- config.allow_admin_rev = 1
-
- if ("allow_admin_spawning")
- config.allow_admin_spawning = 1
-
- if ("allow_byond_links")
- allow_byond_links = 1
-
- if ("allow_discord_links")
- allow_discord_links = 1
-
- if ("allow_url_links")
- allow_url_links = 1
-
- if ("no_dead_vote")
- config.vote_no_dead = 1
-
- if ("default_no_vote")
- config.vote_no_default = 1
-
- if ("pregame_time")
- config.pregame_time = text2num(value)
-
- if ("vote_delay")
- config.vote_delay = text2num(value)
-
- if ("vote_period")
- config.vote_period = text2num(value)
-
- if ("vote_autotransfer_initial")
- config.vote_autotransfer_initial = text2num(value)
-
- if ("vote_autotransfer_interval")
- config.vote_autotransfer_interval = text2num(value)
-
- if ("vote_autogamemode_timeleft")
- config.vote_autogamemode_timeleft = text2num(value)
-
- if("ert_admin_only")
- config.ert_admin_call_only = 1
-
- if ("allow_ai")
- config.allow_ai = 1
-
- if ("allow_ai_shells")
- config.allow_ai_shells = TRUE
-
- if("give_free_ai_shell")
- config.give_free_ai_shell = TRUE
-
-// if ("authentication")
-// config.enable_authentication = 1
-
- if ("norespawn")
- config.respawn = 0
-
- if ("respawn_time")
- var/raw_minutes = text2num(value)
- config.respawn_time = raw_minutes MINUTES
-
- if ("respawn_message")
- config.respawn_message = span_boldnotice("[value]")
-
- if ("servername")
- config.server_name = value
-
- if ("serversuffix")
- config.server_suffix = 1
-
- if ("nudge_script_path")
- config.nudge_script_path = value
-
- if ("hostedby")
- config.hostedby = value
-
- if ("serverurl")
- config.serverurl = value
-
- if ("server")
- config.server = value
-
- if ("banappeals")
- config.banappeals = value
-
- if ("wikiurl")
- config.wikiurl = value
-
- if ("wikisearchurl")
- config.wikisearchurl = value
-
- if ("forumurl")
- config.forumurl = value
-
- if ("rulesurl")
- config.rulesurl = value
-
- if ("mapurl")
- config.mapurl = value
-
- if ("githuburl")
- config.githuburl = value
-
- if ("discordurl")
- config.discordurl = value
-
- if ("patreonurl")
- config.patreonurl = value
-
- if ("guest_jobban")
- config.guest_jobban = 1
-
- if ("guest_ban")
- config.guests_allowed = 0
-
- if ("disable_ooc")
- config.ooc_allowed = 0
- config.looc_allowed = 0
-
- if ("disable_entry")
- config.enter_allowed = 0
-
- if ("disable_dead_ooc")
- config.dooc_allowed = 0
-
- if ("disable_dsay")
- config.dsay_allowed = 0
-
- if ("disable_respawn")
- config.abandon_allowed = 0
-
- if ("usewhitelist")
- config.usewhitelist = 1
-
- if ("feature_object_spell_system")
- config.feature_object_spell_system = 1
-
- if ("allow_metadata")
- config.allow_Metadata = 1
-
- if ("traitor_scaling")
- config.traitor_scaling = 1
-
- if ("aliens_allowed")
- config.aliens_allowed = 1
-
- if ("ninjas_allowed")
- config.ninjas_allowed = 1
-
- if ("objectives_disabled")
- config.objectives_disabled = 1
-
- if("protect_roles_from_antagonist")
- config.protect_roles_from_antagonist = 1
-
- if("persistence_disabled")
- config.persistence_disabled = TRUE // Previously this forcibly set persistence enabled in the saves.
-
- if("persistence_ignore_mapload")
- config.persistence_ignore_mapload = TRUE
-
- if ("probability")
- var/prob_pos = findtext(value, " ")
- var/prob_name = null
- var/prob_value = null
-
- if (prob_pos)
- prob_name = lowertext(copytext(value, 1, prob_pos))
- prob_value = copytext(value, prob_pos + 1)
- if (prob_name in config.modes)
- config.probabilities[prob_name] = text2num(prob_value)
- else
- log_misc("Unknown game mode probability configuration definition: [prob_name].")
- else
- log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].")
-
- if ("required_players", "required_players_secret")
- var/req_pos = findtext(value, " ")
- var/req_name = null
- var/req_value = null
- var/is_secret_override = findtext(name, "required_players_secret") // Being extra sure we're not picking up an override for Secret by accident.
-
- if(req_pos)
- req_name = lowertext(copytext(value, 1, req_pos))
- req_value = copytext(value, req_pos + 1)
- if(req_name in config.modes)
- if(is_secret_override)
- config.player_requirements_secret[req_name] = text2num(req_value)
- else
- config.player_requirements[req_name] = text2num(req_value)
- else
- log_misc("Unknown game mode player requirement configuration definition: [req_name].")
- else
- log_misc("Incorrect player requirement configuration definition: [req_name] [req_value].")
-
- if("allow_random_events")
- config.allow_random_events = 1
-
- if("enable_game_master")
- config.enable_game_master = 1
-
- if("kick_inactive")
- config.kick_inactive = text2num(value)
-
- if("show_mods")
- config.show_mods = 1
-
- if("show_devs")
- config.show_devs = 1
-
- if("show_mentors")
- config.show_mentors = 1
-
- if("show_event_managers")
- config.show_event_managers = 1
-
- if("mods_can_tempban")
- config.mods_can_tempban = 1
-
- if("mods_can_job_tempban")
- config.mods_can_job_tempban = 1
-
- if("mod_tempban_max")
- config.mod_tempban_max = text2num(value)
-
- if("mod_job_tempban_max")
- config.mod_job_tempban_max = text2num(value)
-
- if("load_jobs_from_txt")
- load_jobs_from_txt = 1
-
- if("alert_red_upto")
- config.alert_desc_red_upto = value
-
- if("alert_red_downto")
- config.alert_desc_red_downto = value
-
- if("alert_blue_downto")
- config.alert_desc_blue_downto = value
-
- if("alert_blue_upto")
- config.alert_desc_blue_upto = value
-
- if("alert_green")
- config.alert_desc_green = value
-
- if("alert_delta")
- config.alert_desc_delta = value
-
- if("forbid_singulo_possession")
- forbid_singulo_possession = 1
-
- if("popup_admin_pm")
- config.popup_admin_pm = 1
-
- if("allow_holidays")
- Holiday = 1
-
- if("use_irc_bot")
- use_irc_bot = 1
-
- if("use_node_bot")
- use_node_bot = 1
-
- if("irc_bot_port")
- config.irc_bot_port = value
-
- if("irc_bot_export")
- irc_bot_export = 1
-
- if("ticklag")
- var/ticklag = text2num(value)
- if(ticklag > 0)
- fps = 10 / ticklag
-
- if("tick_limit_mc_init")
- tick_limit_mc_init = text2num(value)
-
- if("allow_antag_hud")
- config.antag_hud_allowed = 1
- if("antag_hud_restricted")
- config.antag_hud_restricted = 1
-
- if("socket_talk")
- socket_talk = text2num(value)
-
- if("tickcomp")
- Tickcomp = 1
-
- if("humans_need_surnames")
- humans_need_surnames = 1
-
- if("tor_ban")
- ToRban = 1
-
- if("automute_on")
- automute_on = 1
-
- if("usealienwhitelist")
- usealienwhitelist = 1
-
- if("alien_player_ratio")
- limitalienplayers = 1
- alien_to_human_ratio = text2num(value)
-
- if("assistant_maint")
- config.assistant_maint = 1
-
- if("gateway_delay")
- config.gateway_delay = text2num(value)
-
- if("continuous_rounds")
- config.continous_rounds = 1
-
- if("ghost_interaction")
- config.ghost_interaction = 1
-
- if("disable_player_mice")
- config.disable_player_mice = 1
-
- if("uneducated_mice")
- config.uneducated_mice = 1
-
- if("comms_password")
- config.comms_password = value
-
- if("irc_bot_host")
- config.irc_bot_host = value
-
- if("main_irc")
- config.main_irc = value
-
- if("admin_irc")
- config.admin_irc = value
-
- if("python_path")
- if(value)
- config.python_path = value
-
- if("use_lib_nudge")
- config.use_lib_nudge = 1
-
- if("allow_cult_ghostwriter")
- config.cult_ghostwriter = 1
-
- if("req_cult_ghostwriter")
- config.cult_ghostwriter_req_cultists = text2num(value)
-
- if("character_slots")
- config.character_slots = text2num(value)
-
- if("loadout_slots")
- config.loadout_slots = text2num(value)
-
- if("allow_drone_spawn")
- config.allow_drone_spawn = text2num(value)
-
- if("drone_build_time")
- config.drone_build_time = text2num(value)
-
- if("max_maint_drones")
- config.max_maint_drones = text2num(value)
-
- if("use_overmap")
- config.use_overmap = 1
-
- if("engine_map")
- config.engine_map = splittext(value, ",")
-/*
- if("station_levels")
- using_map.station_levels = text2numlist(value, ";")
-
- if("admin_levels")
- using_map.admin_levels = text2numlist(value, ";")
-
- if("contact_levels")
- using_map.contact_levels = text2numlist(value, ";")
-
- if("player_levels")
- using_map.player_levels = text2numlist(value, ";")
-*/
- if("expected_round_length")
- config.expected_round_length = MinutesToTicks(text2num(value))
-
- if("disable_welder_vision")
- config.welder_vision = 0
-
- if("allow_extra_antags")
- config.allow_extra_antags = 1
-
- if("event_custom_start_mundane")
- var/values = text2numlist(value, ";")
- config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2]))
-
- if("event_custom_start_moderate")
- var/values = text2numlist(value, ";")
- config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2]))
-
- if("event_custom_start_major")
- var/values = text2numlist(value, ";")
- config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2]))
-
- if("event_delay_lower")
- var/values = text2numlist(value, ";")
- config.event_delay_lower[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1])
- config.event_delay_lower[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2])
- config.event_delay_lower[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3])
-
- if("event_delay_upper")
- var/values = text2numlist(value, ";")
- config.event_delay_upper[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1])
- config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2])
- config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3])
-
- if("starlight")
- value = text2num(value)
- config.starlight = value >= 0 ? value : 0
-
- if("ert_species")
- config.ert_species = splittext(value, ";")
- if(!config.ert_species.len)
- config.ert_species += SPECIES_HUMAN
-
- if("law_zero")
- law_zero = value
-
- if("aggressive_changelog")
- config.aggressive_changelog = 1
-
- if("default_language_prefixes")
- var/list/values = splittext(value, " ")
- if(values.len > 0)
- language_prefixes = values
-
- if("radiation_lower_limit")
- radiation_lower_limit = text2num(value)
-
- if("radiation_resistance_calc_divide")
- radiation_resistance_calc_mode = RAD_RESIST_CALC_DIV
-
- if("radiation_resistance_calc_subtract")
- radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB
-
- if("radiation_resistance_multiplier")
- radiation_resistance_multiplier = text2num(value)
-
- if("radiation_material_resistance_divisor")
- radiation_material_resistance_divisor = text2num(value)
-
- if("radiation_decay_rate")
- radiation_decay_rate = text2num(value)
-
- if ("panic_bunker")
- config.panic_bunker = 1
-
- if ("paranoia_logging")
- config.paranoia_logging = 1
-
- if("ip_reputation")
- config.ip_reputation = 1
-
- if("ipr_email")
- config.ipr_email = value
-
- if("ipr_block_bad_ips")
- config.ipr_block_bad_ips = 1
-
- if("ipr_bad_score")
- config.ipr_bad_score = text2num(value)
-
- if("ipr_allow_existing")
- config.ipr_allow_existing = 1
-
- if("ipr_minimum_age")
- config.ipr_minimum_age = text2num(value)
-
- if("autostart_solars")
- config.autostart_solars = TRUE
-
- if("sqlite_enabled")
- config.sqlite_enabled = TRUE
-
- if("sqlite_feedback")
- config.sqlite_feedback = TRUE
-
- if("sqlite_feedback_topics")
- config.sqlite_feedback_topics = splittext(value, ";")
- if(!config.sqlite_feedback_topics.len)
- config.sqlite_feedback_topics += "General"
-
- if("sqlite_feedback_privacy")
- config.sqlite_feedback_privacy = TRUE
-
- if("sqlite_feedback_cooldown")
- config.sqlite_feedback_cooldown = text2num(value)
-
- if("defib_timer")
- config.defib_timer = text2num(value)
-
- if("defib_braindamage_timer")
- config.defib_braindamage_timer = text2num(value)
-
- if("disable_cid_warn_popup")
- config.disable_cid_warn_popup = TRUE
-
- if("enable_night_shifts")
- config.enable_night_shifts = TRUE
-
- if("jukebox_track_files")
- config.jukebox_track_files = splittext(value, ";")
-
- if("suggested_byond_version")
- config.suggested_byond_version = text2num(value)
-
- if("suggested_byond_build")
- config.suggested_byond_build = text2num(value)
-
- // VOREStation Edit Start - Can't be in _vr file because it is loaded too late.
- if("vgs_access_identifier")
- config.vgs_access_identifier = value
- if("vgs_server_port")
- config.vgs_server_port = text2num(value)
- // VOREStation Edit End
-
- if("invoke_youtubedl")
- config.invoke_youtubedl = value
-
- if("asset_transport")
- config.asset_transport = value
-
- if("cache_assets")
- config.cache_assets = TRUE
-
- if("save_spritesheets")
- config.save_spritesheets = TRUE
-
- if("asset_simple_preload")
- config.asset_simple_preload = TRUE
-
- if("asset_cdn_webroot")
- config.asset_cdn_webroot = value
-
- if("asset_cdn_url")
- config.asset_cdn_url = value
-
- if("allow_robot_recolor")
- config.allow_robot_recolor = TRUE
-
- if("allow_simple_mob_recolor")
- config.allow_simple_mob_recolor = TRUE
-
- else
- log_misc("Unknown setting in configuration: '[name]'")
-
- else if(type == "game_options")
- if(!value)
- log_misc("Unknown value for setting [name] in [filename].")
- value = text2num(value)
-
- switch(name)
- if("health_threshold_crit")
- config.health_threshold_crit = value
- if("health_threshold_softcrit")
- config.health_threshold_softcrit = value
- if("health_threshold_dead")
- config.health_threshold_dead = value
- if("show_human_death_message")
- config.show_human_death_message = 1
- if("revival_pod_plants")
- config.revival_pod_plants = value
- if("revival_cloning")
- config.revival_cloning = value
- if("revival_brain_life")
- config.revival_brain_life = value
- if("organ_health_multiplier")
- config.organ_health_multiplier = value / 100
- if("organ_regeneration_multiplier")
- config.organ_regeneration_multiplier = value / 100
- if("organ_damage_spillover_multiplier")
- config.organ_damage_spillover_multiplier = value / 100
- if("organs_can_decay")
- config.organs_decay = 1
- if("default_brain_health")
- config.default_brain_health = text2num(value)
- if(!config.default_brain_health || config.default_brain_health < 1)
- config.default_brain_health = initial(config.default_brain_health)
- if("bones_can_break")
- config.bones_can_break = value
- if("limbs_can_break")
- config.limbs_can_break = value
- if("allow_headgibs")
- config.allow_headgibs = TRUE
-
- if("run_speed")
- config.run_speed = value
- if("walk_speed")
- config.walk_speed = value
-
- if("human_delay")
- config.human_delay = value
- if("robot_delay")
- config.robot_delay = value
- if("monkey_delay")
- config.monkey_delay = value
- if("alien_delay")
- config.alien_delay = value
- if("slime_delay")
- config.slime_delay = value
- if("animal_delay")
- config.animal_delay = value
-
- if("footstep_volume")
- config.footstep_volume = text2num(value)
-
- if("use_loyalty_implants")
- config.use_loyalty_implants = 1
-
- if("loadout_whitelist")
- config.loadout_whitelist = text2num(value)
-
- else
- log_misc("Unknown setting in configuration: '[name]'")
-
-/datum/configuration/proc/loadsql(filename) // -- TLE
- var/list/Lines = file2list(filename)
- for(var/t in Lines)
- if(!t) continue
-
- t = trim(t)
- if (length(t) == 0)
- continue
- else if (copytext(t, 1, 2) == "#")
- continue
-
- var/pos = findtext(t, " ")
- var/name = null
- var/value = null
-
- if (pos)
- name = lowertext(copytext(t, 1, pos))
- value = copytext(t, pos + 1)
- else
- name = lowertext(t)
-
- if (!name)
- continue
-
- switch (name)
- if ("address")
- sqladdress = value
- if ("port")
- sqlport = value
- if ("database")
- sqldb = value
- if ("login")
- sqllogin = value
- if ("password")
- sqlpass = value
- if ("feedback_database")
- sqlfdbkdb = value
- if ("feedback_login")
- sqlfdbklogin = value
- if ("feedback_password")
- sqlfdbkpass = value
- if ("enable_stat_tracking")
- sqllogging = 1
- else
- log_misc("Unknown setting in configuration: '[name]'")
-
-/datum/configuration/proc/loadforumsql(filename) // -- TLE
- var/list/Lines = file2list(filename)
- for(var/t in Lines)
- if(!t) continue
-
- t = trim(t)
- if (length(t) == 0)
- continue
- else if (copytext(t, 1, 2) == "#")
- continue
-
- var/pos = findtext(t, " ")
- var/name = null
- var/value = null
-
- if (pos)
- name = lowertext(copytext(t, 1, pos))
- value = copytext(t, pos + 1)
- else
- name = lowertext(t)
-
- if (!name)
- continue
-
- switch (name)
- if ("address")
- forumsqladdress = value
- if ("port")
- forumsqlport = value
- if ("database")
- forumsqldb = value
- if ("login")
- forumsqllogin = value
- if ("password")
- forumsqlpass = value
- if ("activatedgroup")
- forum_activated_group = value
- if ("authenticatedgroup")
- forum_authenticated_group = value
- else
- log_misc("Unknown setting in configuration: '[name]'")
-
-/datum/configuration/proc/pick_mode(mode_name)
- // I wish I didn't have to instance the game modes in order to look up
- // their information, but it is the only way (at least that I know of).
- for (var/game_mode in gamemode_cache)
- var/datum/game_mode/M = gamemode_cache[game_mode]
- if (M.config_tag && M.config_tag == mode_name)
- return M
- return gamemode_cache["extended"]
-
-/datum/configuration/proc/get_runnable_modes()
- var/list/runnable_modes = list()
- for(var/game_mode in gamemode_cache)
- var/datum/game_mode/M = gamemode_cache[game_mode]
- if(M && M.can_start() && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0)
- runnable_modes |= M
- return runnable_modes
-
-/datum/configuration/proc/post_load()
- //apply a default value to config.python_path, if needed
- if (!config.python_path)
- if(world.system_type == UNIX)
- config.python_path = "/usr/bin/env python2"
- else //probably windows, if not this should work anyway
- config.python_path = "python"
diff --git a/code/controllers/configuration_vr.dm b/code/controllers/configuration_vr.dm
deleted file mode 100644
index a1740212f0..0000000000
--- a/code/controllers/configuration_vr.dm
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// Lets read our settings from the configuration file on startup too!
-//
-
-/datum/configuration
- var/static/time_off = FALSE
- var/static/pto_job_change = FALSE
- var/static/limit_interns = -1 //Unlimited by default
- var/static/limit_visitors = -1 //Unlimited by default
- var/static/pto_cap = 100 //Hours
- var/static/require_flavor = FALSE
- var/static/ipqualityscore_apikey //API key for ipqualityscore.com
- var/static/use_playtime_restriction_for_jobs = FALSE
-
-/hook/startup/proc/read_vs_config()
- var/list/Lines = file2list("config/config.txt")
- for(var/t in Lines)
- if(!t) continue
-
- t = trim(t)
- if (length(t) == 0)
- continue
- else if (copytext(t, 1, 2) == "#")
- continue
-
- var/pos = findtext(t, " ")
- var/name = null
- var/value = null
-
- if (pos)
- name = lowertext(copytext(t, 1, pos))
- value = copytext(t, pos + 1)
- else
- name = lowertext(t)
-
- if (!name)
- continue
-
- switch (name)
- if ("chat_webhook_url")
- config.chat_webhook_url = value
- if ("chat_webhook_key")
- config.chat_webhook_key = value
- if ("fax_export_dir")
- config.fax_export_dir = value
- if ("items_survive_digestion")
- config.items_survive_digestion = 1
- if ("limit_interns")
- config.limit_interns = text2num(value)
- if ("limit_visitors")
- config.limit_visitors = text2num(value)
- if ("pto_cap")
- config.pto_cap = text2num(value)
- if ("time_off")
- config.time_off = TRUE
- if ("pto_job_change")
- config.pto_job_change = TRUE
- if ("require_flavor")
- config.require_flavor = TRUE
- if ("ipqualityscore_apikey")
- config.ipqualityscore_apikey = value
- if ("use_playtime_restriction_for_jobs")
- config.use_playtime_restriction_for_jobs = TRUE
- return 1
diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm
index dfe8bc7234..e92e30079b 100644
--- a/code/controllers/failsafe.dm
+++ b/code/controllers/failsafe.dm
@@ -1,10 +1,11 @@
- /**
- * Failsafe
- *
- * Pretty much pokes the MC to make sure it's still alive.
+/**
+ * Failsafe
+ *
+ * Pretty much pokes the MC to make sure it's still alive.
**/
-var/datum/controller/failsafe/Failsafe
+// See initialization order in /code/game/world.dm
+GLOBAL_REAL(Failsafe, /datum/controller/failsafe)
/datum/controller/failsafe // This thing pretty much just keeps poking the master controller
name = "Failsafe"
@@ -15,7 +16,7 @@ var/datum/controller/failsafe/Failsafe
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
var/defcon = 5
//the world.time of the last check, so the mc can restart US if we hang.
- // (Real friends look out for *eachother*)
+ // (Real friends look out for *each other*)
var/lasttick = 0
// Track the MC iteration to make sure its still on track.
@@ -31,8 +32,24 @@ var/datum/controller/failsafe/Failsafe
Initialize()
/datum/controller/failsafe/Initialize()
- set waitfor = 0
+ set waitfor = FALSE
Failsafe.Loop()
+ if (!Master || defcon == 0) //Master is gone/not responding and Failsafe just exited its loop
+ defcon = 3 //Reset defcon level as its used inside the emergency loop
+ while (defcon > 0)
+ var/recovery_result = emergency_loop()
+ if (recovery_result == 1) //Exit emergency loop and delete self if it was able to recover MC
+ break
+ else if (defcon == 1) //Exit Failsafe if we weren't able to recover the MC in the last stage
+ log_game("FailSafe: Failed to recover MC while in emergency state. Failsafe exiting.")
+ message_admins(span_boldannounce("Failsafe failed critically while trying to recreate broken MC. Please manually fix the MC or reboot the server. Failsafe exiting now."))
+ message_admins(span_boldannounce("You can try manually calling these two procs:."))
+ message_admins(span_boldannounce("/proc/recover_all_SS_and_recreate_master: Most stuff should still function but expect instability/runtimes/broken stuff."))
+ message_admins(span_boldannounce("/proc/delete_all_SS_and_recreate_master: Most stuff will be broken but basic stuff like movement and chat should still work."))
+ else if (recovery_result == -1) //Failed to recreate MC
+ defcon--
+ sleep(initial(processing_interval)) //Wait a bit until the next try
+
if(!QDELETED(src))
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
@@ -45,43 +62,56 @@ var/datum/controller/failsafe/Failsafe
while(running)
lasttick = world.time
if(!Master)
- // Replace the missing Master! This should never, ever happen.
- new /datum/controller/master()
+ // Break out of the main loop so we go into emergency state
+ break
// Only poke it if overrides are not in effect.
if(processing_interval > 0)
if(Master.processing && Master.iteration)
+ if (defcon > 1 && (!Master.stack_end_detector || !Master.stack_end_detector.check()))
+
+ to_chat(GLOB.admins, span_boldannounce("ERROR: The Master Controller code stack has exited unexpectedly, Restarting..."))
+ defcon = 0
+ var/rtn = Recreate_MC()
+ if(rtn > 0)
+ master_iteration = 0
+ to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
+ else if(rtn < 0)
+ log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
+ to_chat(GLOB.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
// Check if processing is done yet.
if(Master.iteration == master_iteration)
- log_debug("DEFCON [defcon]: Master.iteration=[Master.iteration] Master.last_run=[Master.last_run] world.time=[world.time]")
switch(defcon)
if(4,5)
--defcon
- if(3)
- log_and_message_admins(span_adminnotice("SSfailsafe Notice: DEFCON [defcon_pretty()]. The Master Controller (\ref[Master]) has not fired in the last [(5-defcon) * processing_interval] ticks."))
- --defcon
- if(2)
- log_and_message_admins(span_boldannounce("SSfailsafe Warning: DEFCON [defcon_pretty()]. The Master Controller (\ref[Master]) has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks."))
- --defcon
- if(1)
- log_and_message_admins(span_boldannounce("SSfailsafe Warning: DEFCON [defcon_pretty()]. The Master Controller (\ref[Master]) has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting..."))
+ if(3)
+ message_admins(span_adminnotice("Notice: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks."))
+ --defcon
+
+ if(2)
+ to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [(5-defcon) * processing_interval] ticks. Automatic restart in [processing_interval] ticks."))
+ --defcon
+
+ if(1)
+ to_chat(GLOB.admins, span_boldannounce("Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [(5-defcon) * processing_interval] ticks. Killing and restarting..."))
--defcon
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
- log_and_message_admins(span_adminnotice("SSfailsafe Notice: MC (New:\ref[Master]) restarted successfully"))
+ to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
else if(rtn < 0)
- log_game("SSfailsafe Notice: Could not restart MC (\ref[Master]), runtime encountered. Entering defcon 0")
- log_and_message_admins(span_boldannounce("SSFAILSAFE ERROR: DEFCON [defcon_pretty()]. Could not restart MC (\ref[Master]), runtime encountered. I will silently keep retrying."))
+ log_game("FailSafe: Could not restart MC, runtime encountered. Entering defcon 0")
+ to_chat(GLOB.admins, span_boldannounce("ERROR: DEFCON [defcon_pretty()]. Could not restart MC, runtime encountered. I will silently keep retrying."))
//if the return number was 0, it just means the mc was restarted too recently, and it just needs some time before we try again
//no need to handle that specially when defcon 0 can handle it
+
if(0) //DEFCON 0! (mc failed to restart)
var/rtn = Recreate_MC()
if(rtn > 0)
defcon = 4
master_iteration = 0
- log_and_message_admins(span_adminnotice("SSfailsafe Notice: MC (New:\ref[Master]) restarted successfully"))
+ to_chat(GLOB.admins, span_adminnotice("MC restarted successfully"))
else
defcon = min(defcon + 1,5)
master_iteration = Master.iteration
@@ -93,12 +123,60 @@ var/datum/controller/failsafe/Failsafe
defcon = 5
sleep(initial(processing_interval))
+//Emergency loop used when Master got deleted or the main loop exited while Defcon == 0
+//Loop is driven externally so runtimes only cancel the current recovery attempt
+/datum/controller/failsafe/proc/emergency_loop()
+ //The code in this proc should be kept as simple as possible, anything complicated like to_chat might rely on master existing and runtime
+ //The goal should always be to get a new Master up and running before anything else
+ . = -1
+ switch (defcon) //The lower defcon goes the harder we try to fix the MC
+ if (2 to 3) //Try to normally recreate the MC two times
+ . = Recreate_MC()
+ if (1) //Delete the old MC first so we don't transfer any info, in case that caused any issues
+ del(Master)
+ . = Recreate_MC()
+
+ if (. == 1) //We were able to create a new master
+ master_iteration = 0
+ SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
+ Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
+ to_chat(GLOB.admins, span_adminnotice("Failsafe recovered MC while in emergency state [defcon_pretty()]"))
+ else
+ log_game("FailSafe: Failsafe in emergency state and was unable to recreate MC while in defcon state [defcon_pretty()].")
+ message_admins(span_boldannounce("Failsafe in emergency state and master down, trying to recreate MC while in defcon level [defcon_pretty()] failed."))
+
+///Recreate all SSs which will still cause data survive due to Recover(), the new Master will then find and take them from global.vars
+/proc/recover_all_SS_and_recreate_master()
+ del(Master)
+ var/list/subsytem_types = subtypesof(/datum/controller/subsystem)
+ sortTim(subsytem_types, GLOBAL_PROC_REF(cmp_subsystem_init))
+ for(var/I in subsytem_types)
+ new I
+ . = Recreate_MC()
+ if (. == 1) //We were able to create a new master
+ SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
+ Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
+ to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after recovering all subsystems!"))
+ else
+ message_admins(span_boldannounce("Failed to create new MC!"))
+
+///Delete all existing SS to basically start over
+/proc/delete_all_SS_and_recreate_master()
+ del(Master)
+ for(var/global_var in global.vars)
+ if (istype(global.vars[global_var], /datum/controller/subsystem))
+ del(global.vars[global_var])
+ . = Recreate_MC()
+ if (. == 1) //We were able to create a new master
+ SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set
+ Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this
+ to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after deleting and recreating all subsystems!"))
+ else
+ message_admins(span_boldannounce("Failed to create new MC!"))
+
/datum/controller/failsafe/proc/defcon_pretty()
return defcon
/datum/controller/failsafe/stat_entry(msg)
- if(!statclick)
- statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
-
- msg = "Failsafe Controller: [statclick.update("Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])")]"
+ msg = "Defcon: [defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"
return msg
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index b68b4e01c0..35145d5a62 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -1,26 +1,23 @@
- /**
- * StonedMC
- *
- * Designed to properly split up a given tick among subsystems
- * Note: if you read parts of this code and think "why is it doing it that way"
- * Odds are, there is a reason
- *
+/**
+ * StonedMC
+ *
+ * Designed to properly split up a given tick among subsystems
+ * Note: if you read parts of this code and think "why is it doing it that way"
+ * Odds are, there is a reason
+ *
**/
-//This is the ABSOLUTE ONLY THING that should init globally like this
+// See initialization order in /code/game/world.dm
GLOBAL_REAL(Master, /datum/controller/master) = new
-
-//THIS IS THE INIT ORDER
-//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe
-//GOT IT MEMORIZED?
-
/datum/controller/master
name = "Master"
- // Are we processing (higher values increase the processing delay by n ticks)
+ /// Are we processing (higher values increase the processing delay by n ticks)
var/processing = TRUE
- // How many times have we ran
+ /// How many times have we ran
var/iteration = 0
+ /// Stack end detector to detect stack overflows that kill the mc's main loop
+ var/datum/stack_end_detector/stack_end_detector
// world.time of last fire, for tracking lag outside of the mc
var/last_run
@@ -291,8 +288,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/error_level = 0
var/sleep_delta = 1
var/list/subsystems_to_check
- //the actual loop.
+ //setup the stack overflow detector
+ stack_end_detector = new()
+ var/datum/stack_canary/canary = stack_end_detector.prime_canary()
+ canary.use_variable()
+ //the actual loop.
while (1)
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
var/starting_tick_usage = TICK_USAGE
diff --git a/code/controllers/subsystems/speech_controller.dm b/code/controllers/subsystems/speech_controller.dm
new file mode 100644
index 0000000000..e293c89a9b
--- /dev/null
+++ b/code/controllers/subsystems/speech_controller.dm
@@ -0,0 +1,5 @@
+/// verb_manager subsystem just for handling say's
+VERB_MANAGER_SUBSYSTEM_DEF(speech_controller)
+ name = "Speech Controller"
+ wait = 1
+ priority = FIRE_PRIORITY_SPEECH_CONTROLLER//has to be high priority, second in priority ONLY to SSinput
diff --git a/code/controllers/subsystems/verb_manager.dm b/code/controllers/subsystems/verb_manager.dm
new file mode 100644
index 0000000000..1e3cce0a9a
--- /dev/null
+++ b/code/controllers/subsystems/verb_manager.dm
@@ -0,0 +1,167 @@
+/**
+ * SSverb_manager, a subsystem that runs every tick and runs through its entire queue without yielding like SSinput.
+ * this exists because of how the byond tick works and where user inputted verbs are put within it.
+ *
+ * see TICK_ORDER.md for more info on how the byond tick is structured.
+ *
+ * The way the MC allots its time is via TICK_LIMIT_RUNNING, it simply subtracts the cost of SendMaps (MAPTICK_LAST_INTERNAL_TICK_USAGE)
+ * plus TICK_BYOND_RESERVE from the tick and uses up to that amount of time (minus the percentage of the tick used by the time it executes subsystems)
+ * on subsystems running cool things like atmospherics or Life or SSInput or whatever.
+ *
+ * Without this subsystem, verbs are likely to cause overtime if the MC uses all of the time it has allotted for itself in the tick, and SendMaps
+ * uses as much as its expected to, and an expensive verb ends up executing that tick. This is because the MC is completely blind to the cost of
+ * verbs, it can't account for it at all. The only chance for verbs to not cause overtime in a tick where the MC used as much of the tick
+ * as it allotted itself and where SendMaps costed as much as it was expected to is if the verb(s) take less than TICK_BYOND_RESERVE percent of
+ * the tick, which isn't much. Not to mention if SendMaps takes more than 30% of the tick and the MC forces itself to take at least 70% of the
+ * normal tick duration which causes ticks to naturally overrun even in the absence of verbs.
+ *
+ * With this subsystem, the MC can account for the cost of verbs and thus stop major overruns of ticks. This means that the most important subsystems
+ * like SSinput can start at the same time they were supposed to, leading to a smoother experience for the player since ticks aren't riddled with
+ * minor hangs over and over again.
+ */
+SUBSYSTEM_DEF(verb_manager)
+ name = "Verb Manager"
+ wait = 1
+ flags = SS_TICKER | SS_NO_INIT
+ priority = FIRE_PRIORITY_DELAYED_VERBS
+ runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
+
+ ///list of callbacks to procs called from verbs or verblike procs that were executed when the server was overloaded and had to delay to the next tick.
+ ///this list is ran through every tick, and the subsystem does not yield until this queue is finished.
+ var/list/datum/callback/verb_callback/verb_queue = list()
+
+ ///running average of how many verb callbacks are executed every second. used for the stat entry
+ var/verbs_executed_per_second = 0
+
+ ///if TRUE we treat usr's with holders just like usr's without holders. otherwise they always execute immediately
+ var/can_queue_admin_verbs = FALSE
+
+ ///if this is true all verbs immediately execute and don't queue. in case the mc is fucked or something
+ var/FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs = FALSE
+
+ ///used for subtypes to determine if they use their own stats for the stat entry
+ var/use_default_stats = TRUE
+
+ ///if TRUE this will... message admins every time a verb is queued to this subsystem for the next tick with stats.
+ ///for obvious reasons don't make this be TRUE on the code level this is for admins to turn on
+ var/message_admins_on_queue = FALSE
+
+ ///always queue if possible. overrides can_queue_admin_verbs but not FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs
+ var/always_queue = FALSE
+
+/**
+ * queue a callback for the given verb/verblike proc and any given arguments to the specified verb subsystem, so that they process in the next tick.
+ * intended to only work with verbs or verblike procs called directly from client input, use as part of TRY_QUEUE_VERB() and co.
+ *
+ * returns TRUE if the queuing was successful, FALSE otherwise.
+ */
+/proc/_queue_verb(datum/callback/verb_callback/incoming_callback, tick_check, datum/controller/subsystem/verb_manager/subsystem_to_use = SSverb_manager, ...)
+ if(QDELETED(incoming_callback))
+ var/destroyed_string
+ if(!incoming_callback)
+ destroyed_string = "callback is null."
+ else
+ destroyed_string = "callback was deleted [DS2TICKS(world.time - incoming_callback.gc_destroyed)] ticks ago. callback was created [DS2TICKS(world.time) - incoming_callback.creation_time] ticks ago."
+
+ stack_trace("_queue_verb() returned false because it was given a deleted callback! [destroyed_string]")
+ return FALSE
+
+ if(!istext(incoming_callback.object) && QDELETED(incoming_callback.object)) //just in case the object is GLOBAL_PROC
+ var/destroyed_string
+ if(!incoming_callback.object)
+ destroyed_string = "callback.object is null."
+ else
+ destroyed_string = "callback.object was deleted [DS2TICKS(world.time - incoming_callback.object.gc_destroyed)] ticks ago. callback was created [DS2TICKS(world.time) - incoming_callback.creation_time] ticks ago."
+
+ stack_trace("_queue_verb() returned false because it was given a callback acting on a qdeleted object! [destroyed_string]")
+ return FALSE
+
+ //we want unit tests to be able to directly call verbs that attempt to queue, and since unit tests should test internal behavior, we want the queue
+ //to happen as if it was actually from player input if its called on a mob.
+#ifdef UNIT_TESTS
+ if(QDELETED(usr) && ismob(incoming_callback.object))
+ incoming_callback.user = WEAKREF(incoming_callback.object)
+ var/datum/callback/new_us = CALLBACK(arglist(list(GLOBAL_PROC, GLOBAL_PROC_REF(_queue_verb)) + args.Copy()))
+ return world.push_usr(incoming_callback.object, new_us)
+
+#else
+
+ if(QDELETED(usr) || isnull(usr.client))
+ stack_trace("_queue_verb() returned false because it wasn't called from player input!")
+ return FALSE
+
+#endif
+
+ if(!istype(subsystem_to_use))
+ stack_trace("_queue_verb() returned false because it was given an invalid subsystem to queue for!")
+ return FALSE
+
+ if((TICK_USAGE < tick_check) && !subsystem_to_use.always_queue)
+ return FALSE
+
+ var/list/args_to_check = args.Copy()
+ args_to_check.Cut(2, 4)//cut out tick_check and subsystem_to_use
+
+ //any subsystem can use the additional arguments to refuse queuing
+ if(!subsystem_to_use.can_queue_verb(arglist(args_to_check)))
+ return FALSE
+
+ return subsystem_to_use.queue_verb(incoming_callback)
+
+/**
+ * subsystem-specific check for whether a callback can be queued.
+ * intended so that subsystem subtypes can verify whether
+ *
+ * subtypes may include additional arguments here if they need them! you just need to include them properly
+ * in TRY_QUEUE_VERB() and co.
+ */
+/datum/controller/subsystem/verb_manager/proc/can_queue_verb(datum/callback/verb_callback/incoming_callback)
+ if(always_queue && !FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs)
+ return TRUE
+
+ if((usr.client?.holder && !can_queue_admin_verbs) \
+ || (!subsystem_initialized && !(flags & SS_NO_INIT)) \
+ || FOR_ADMINS_IF_VERBS_FUCKED_immediately_execute_all_verbs \
+ || !(runlevels & Master.current_runlevel))
+ return FALSE
+
+ return TRUE
+
+/**
+ * queue a callback for the given proc, so that it is invoked in the next tick.
+ * intended to only work with verbs or verblike procs called directly from client input, use as part of TRY_QUEUE_VERB()
+ *
+ * returns TRUE if the queuing was successful, FALSE otherwise.
+ */
+/datum/controller/subsystem/verb_manager/proc/queue_verb(datum/callback/verb_callback/incoming_callback)
+ . = FALSE //errored
+ if(message_admins_on_queue)
+ message_admins("[name] verb queuing: tick usage: [TICK_USAGE]%, proc: [incoming_callback.delegate], object: [incoming_callback.object], usr: [usr]")
+ verb_queue += incoming_callback
+ return TRUE
+
+/datum/controller/subsystem/verb_manager/fire(resumed)
+ run_verb_queue()
+
+/// runs through all of this subsystems queue of verb callbacks.
+/// goes through the entire verb queue without yielding.
+/// used so you can flush the queue outside of fire() without interfering with anything else subtype subsystems might do in fire().
+/datum/controller/subsystem/verb_manager/proc/run_verb_queue()
+ var/executed_verbs = 0
+
+ for(var/datum/callback/verb_callback/verb_callback as anything in verb_queue)
+ if(!istype(verb_callback))
+ stack_trace("non /datum/callback/verb_callback inside [name]'s verb_queue!")
+ continue
+
+ verb_callback.InvokeAsync()
+ executed_verbs++
+
+ verb_queue.Cut()
+ verbs_executed_per_second = MC_AVG_SECONDS(verbs_executed_per_second, executed_verbs, wait SECONDS)
+ //note that wait SECONDS is incorrect if this is called outside of fire() but because byond is garbage i need to add a timer to rustg to find a valid solution
+
+/datum/controller/subsystem/verb_manager/stat_entry(msg)
+ . = ..()
+ if(use_default_stats)
+ . += "V/S: [round(verbs_executed_per_second, 0.01)]"
diff --git a/code/datums/colormate.dm b/code/datums/colormate.dm
index 49c7a88542..3bb625b7b1 100644
--- a/code/datums/colormate.dm
+++ b/code/datums/colormate.dm
@@ -43,7 +43,7 @@
/datum/ColorMate/tgui_state(mob/user)
return GLOB.tgui_conscious_state
-/datum/ColorMate/tgui_data()
+/datum/ColorMate/tgui_data(mob/user)
. = list()
.["activemode"] = active_mode
.["matrixcolors"] = list(
@@ -69,7 +69,7 @@
.["item"] = list()
.["item"]["name"] = inserted.name
.["item"]["sprite"] = icon2base64(get_flat_icon(inserted,dir=SOUTH,no_anim=TRUE))
- .["item"]["preview"] = icon2base64(build_preview())
+ .["item"]["preview"] = icon2base64(build_preview(user))
else
.["item"] = null
@@ -159,7 +159,7 @@
return TRUE
/// Produces the preview image of the item, used in the UI, the way the color is not stacking is a sin.
-/datum/ColorMate/proc/build_preview()
+/datum/ColorMate/proc/build_preview(mob/user)
if(inserted) //sanity
var/list/cm
switch(active_mode)
@@ -178,17 +178,17 @@
text2num(color_matrix_last[11]),
text2num(color_matrix_last[12]),
)
- if(!check_valid_color(cm, usr))
+ if(!check_valid_color(cm, user))
return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE)
if(COLORMATE_TINT)
- if(!check_valid_color(activecolor, usr))
+ if(!check_valid_color(activecolor, user))
return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE)
if(COLORMATE_HSV)
cm = color_matrix_hsv(build_hue, build_sat, build_val)
color_matrix_last = cm
- if(!check_valid_color(cm, usr))
+ if(!check_valid_color(cm, user))
return get_flat_icon(inserted, dir=SOUTH, no_anim=TRUE)
var/cur_color = inserted.color
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index edda32de87..3f482ea72e 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -452,26 +452,25 @@
data["crafting_recipes"] = crafting_recipes
return data
-/datum/component/personal_crafting/tgui_act(action, params)
+/datum/component/personal_crafting/tgui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("make")
- var/mob/user = usr
var/datum/crafting_recipe/TR = locate(params["recipe"]) in GLOB.crafting_recipes
busy = TRUE
- tgui_interact(user)
- var/atom/movable/result = construct_item(user, TR)
+ tgui_interact(ui.user)
+ var/atom/movable/result = construct_item(ui.user, TR)
if(!istext(result)) //We made an item and didn't get a fail message
- if(ismob(user) && isitem(result)) //In case the user is actually possessing a non mob like a machine
- user.put_in_hands(result)
+ if(ismob(ui.user) && isitem(result)) //In case the user is actually possessing a non mob like a machine
+ ui.user.put_in_hands(result)
else
- result.forceMove(user.drop_location())
- to_chat(user, span_notice("[TR.name] constructed."))
- TR.on_craft_completion(user, result)
+ result.forceMove(ui.user.drop_location())
+ to_chat(ui.user, span_notice("[TR.name] constructed."))
+ TR.on_craft_completion(ui.user, result)
else
- to_chat(user, span_warning("Construction failed[result]"))
+ to_chat(ui.user, span_warning("Construction failed[result]"))
busy = FALSE
if("toggle_recipes")
display_craftable_only = !display_craftable_only
diff --git a/code/datums/components/gargoyle.dm b/code/datums/components/gargoyle.dm
new file mode 100644
index 0000000000..618c2e97e0
--- /dev/null
+++ b/code/datums/components/gargoyle.dm
@@ -0,0 +1,101 @@
+/datum/component/gargoyle
+ var/energy = 100
+ var/transformed = FALSE
+ var/paused = FALSE
+ var/paused_loc
+ var/cooldown
+
+ var/mob/living/carbon/human/gargoyle //easy reference
+ var/obj/structure/gargoyle/statue //another easy ref
+
+ //Adjustable mod
+ var/identifier = "statue"
+ var/adjective = "hardens"
+ var/material = "stone"
+ var/tint = "#FFFFFF"
+
+/datum/component/gargoyle/Initialize()
+ if (!ishuman(parent))
+ return COMPONENT_INCOMPATIBLE
+ gargoyle = parent
+ add_verb(gargoyle,/mob/living/carbon/human/proc/gargoyle_transformation)
+ add_verb(gargoyle,/mob/living/carbon/human/proc/gargoyle_pause)
+ add_verb(gargoyle,/mob/living/carbon/human/proc/gargoyle_checkenergy)
+
+ START_PROCESSING(SSprocessing, src)
+
+/datum/component/gargoyle/process()
+ if (QDELETED(gargoyle))
+ return
+ if (paused && gargoyle.loc != paused_loc)
+ unpause()
+ if (energy > 0)
+ if (!transformed && !paused)
+ energy = max(0,energy-0.05)
+ else if (!transformed && isturf(gargoyle.loc))
+ gargoyle.gargoyle_transformation()
+ if (transformed)
+ if (!statue)
+ transformed = FALSE
+ statue.damage(-0.5)
+ energy = min(energy+0.3, 100)
+
+/datum/component/gargoyle/proc/unpause()
+ if (!paused || transformed)
+ paused = FALSE
+ paused_loc = null
+ UnregisterSignal(gargoyle, COMSIG_ATOM_ENTERING)
+ return
+ if (gargoyle?.loc != paused_loc)
+ paused = FALSE
+ paused_loc = null
+ energy = max(energy - 5, 0)
+ if (energy == 0)
+ gargoyle.gargoyle_transformation()
+ UnregisterSignal(gargoyle, COMSIG_ATOM_ENTERING)
+
+//verbs or action buttons...?
+/mob/living/carbon/human/proc/gargoyle_transformation()
+ set name = "Gargoyle - Petrification"
+ set category = "Abilities.Gargoyle"
+ set desc = "Turn yourself into (or back from) being a gargoyle."
+
+ if (stat == DEAD)
+ return
+
+ var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
+ if (comp)
+ if (comp.energy <= 0 && isturf(loc))
+ to_chat(src, span_danger("You suddenly turn into a [comp.identifier] as you run out of energy!"))
+ else if (comp.cooldown > world.time)
+ var/time_to_wait = (comp.cooldown - world.time) / (1 SECONDS)
+ to_chat(src, span_warning("You can't transform just yet again! Wait for another [round(time_to_wait,0.1)] seconds!"))
+ return
+ if (istype(loc, /obj/structure/gargoyle))
+ qdel(loc)
+ else if (isturf(loc))
+ new /obj/structure/gargoyle(loc, src)
+
+/mob/living/carbon/human/proc/gargoyle_pause()
+ set name = "Gargoyle - Pause"
+ set category = "Abilities.Gargoyle"
+ set desc = "Pause your energy while standing still, so you don't use up any more, though you will lose a small amount upon moving again."
+
+ if (stat)
+ return
+
+ var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
+ if (comp && !comp.transformed && !comp.paused)
+ comp.paused = TRUE
+ comp.paused_loc = loc
+ comp.RegisterSignal(src, COMSIG_ATOM_ENTERING, /datum/component/gargoyle/proc/unpause)
+ to_chat(src, span_notice("You start conserving your energy."))
+
+/mob/living/carbon/human/proc/gargoyle_checkenergy()
+ set name = "Gargoyle - Check Energy"
+ set category = "Abilities.Gargoyle"
+ set desc = "Check how much energy you have remaining as a gargoyle."
+
+ var/datum/component/gargoyle/comp = GetComponent(/datum/component/gargoyle)
+ if (comp)
+ to_chat(src, span_notice("You have [round(comp.energy,0.01)] energy remaining. It is currently [comp.paused ? "stable" : (comp.transformed ? "increasing" : "decreasing")]."))
diff --git a/code/datums/helper_datums/stack_end_detector.dm b/code/datums/helper_datums/stack_end_detector.dm
new file mode 100644
index 0000000000..0d621f51b3
--- /dev/null
+++ b/code/datums/helper_datums/stack_end_detector.dm
@@ -0,0 +1,32 @@
+/**
+ Stack End Detector.
+ Can detect if a given code stack has exited, used by the mc for stack overflow detection.
+
+ **/
+/datum/stack_end_detector
+ var/datum/weakref/_WF
+ var/datum/stack_canary/_canary
+
+/datum/stack_end_detector/New()
+ _canary = new()
+ _WF = WEAKREF(_canary)
+
+/** Prime the stack overflow detector.
+ Store the return value of this proc call in a proc level var.
+ Can only be called once.
+**/
+/datum/stack_end_detector/proc/prime_canary()
+ if (!_canary)
+ CRASH("Prime_canary called twice")
+ . = _canary
+ _canary = null
+
+/// Returns true if the stack is still going. Calling before the canary has been primed also returns true
+/datum/stack_end_detector/proc/check()
+ return !!_WF.resolve()
+
+/// Stack canary. Will go away if the stack it was primed by is ended by byond for return or stack overflow reasons.
+/datum/stack_canary
+
+/// empty proc to avoid warnings about unused variables. Call this proc on your canary in the stack it's watching.
+/datum/stack_canary/proc/use_variable()
diff --git a/code/datums/verb_callbacks.dm b/code/datums/verb_callbacks.dm
new file mode 100644
index 0000000000..77f817017d
--- /dev/null
+++ b/code/datums/verb_callbacks.dm
@@ -0,0 +1,27 @@
+///like normal callbacks but they also record their creation time for measurement purposes
+///they also require the same usr/user that made the callback to both still exist and to still have a client in order to execute
+/datum/callback/verb_callback
+ ///the tick this callback datum was created in. used for testing latency
+ var/creation_time = 0
+
+/datum/callback/verb_callback/New(thingtocall, proctocall, ...)
+ creation_time = DS2TICKS(world.time)
+ . = ..()
+
+#ifndef UNIT_TEST
+/datum/callback/verb_callback/Invoke(...)
+ var/mob/our_user = user?.resolve()
+ if(QDELETED(our_user) || isnull(our_user.client))
+ return
+ var/mob/temp = usr
+ . = ..()
+ usr = temp
+
+/datum/callback/verb_callback/InvokeAsync(...)
+ var/mob/our_user = user?.resolve()
+ if(QDELETED(our_user) || isnull(our_user.client))
+ return
+ var/mob/temp = usr
+ . = ..()
+ usr = temp
+#endif
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index 4e71b94630..03ffdb8ecb 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -153,24 +153,23 @@
data["status"] = status
return data
-/datum/wires/tgui_act(action, list/params)
+/datum/wires/tgui_act(action, list/params, datum/tgui/ui)
if(..())
return TRUE
- var/mob/user = usr
- if(!interactable(user))
+ if(!interactable(ui.user))
return
- var/obj/item/I = user.get_active_hand()
+ var/obj/item/I = ui.user.get_active_hand()
var/color = lowertext(params["wire"])
- holder.add_hiddenprint(user)
+ holder.add_hiddenprint(ui.user)
switch(action)
// Toggles the cut/mend status.
if("cut")
// if(!I.has_tool_quality(TOOL_WIRECUTTER) && !user.can_admin_interact())
if(!istype(I) || !I.has_tool_quality(TOOL_WIRECUTTER))
- to_chat(user, span_warning("You need wirecutters!"))
+ to_chat(ui.user, span_warning("You need wirecutters!"))
return
playsound(holder, I.usesound, 20, 1)
@@ -181,7 +180,7 @@
if("pulse")
// if(!I.has_tool_quality(TOOL_MULTITOOL) && !user.can_admin_interact())
if(!istype(I) || !I.has_tool_quality(TOOL_MULTITOOL))
- to_chat(user, span_warning("You need a multitool!"))
+ to_chat(ui.user, span_warning("You need a multitool!"))
return
playsound(holder, 'sound/weapons/empty.ogg', 20, 1)
@@ -189,7 +188,7 @@
// If they pulse the electrify wire, call interactable() and try to shock them.
if(get_wire(color) == WIRE_ELECTRIFY)
- interactable(user)
+ interactable(ui.user)
return TRUE
@@ -198,18 +197,18 @@
if(is_attached(color))
var/obj/item/O = detach_assembly(color)
if(O)
- user.put_in_hands(O)
+ ui.user.put_in_hands(O)
return TRUE
if(!istype(I, /obj/item/assembly/signaler))
- to_chat(user, span_warning("You need a remote signaller!"))
+ to_chat(ui.user, span_warning("You need a remote signaller!"))
return
- if(user.unEquip(I))
+ if(ui.user.unEquip(I))
attach_assembly(color, I)
return TRUE
else
- to_chat(user, span_warning("[I] is stuck to your hand!"))
+ to_chat(ui.user, span_warning("[I] is stuck to your hand!"))
/**
* Proc called to determine if the user can see wire define information, such as "Contraband", "Door Bolts", etc.
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 75855cec64..5a7f00f4a6 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -325,13 +325,13 @@
throw_speed = 4
throw_range = 20
-/obj/item/camera_bug/attack_self(mob/usr as mob)
+/obj/item/camera_bug/attack_self(mob/user as mob)
var/list/cameras = new/list()
for (var/obj/machinery/camera/C in cameranet.cameras)
if (C.bugged && C.status)
cameras.Add(C)
if (length(cameras) == 0)
- to_chat(usr, span_warning("No bugged functioning cameras found."))
+ to_chat(user, span_warning("No bugged functioning cameras found."))
return
var/list/friendly_cameras = new/list()
@@ -339,16 +339,16 @@
for (var/obj/machinery/camera/C in cameras)
friendly_cameras.Add(C.c_tag)
- var/target = tgui_input_list(usr, "Select the camera to observe", "Select Camera", friendly_cameras)
+ var/target = tgui_input_list(user, "Select the camera to observe", "Select Camera", friendly_cameras)
if (!target)
return
for (var/obj/machinery/camera/C in cameras)
if (C.c_tag == target)
target = C
break
- if (usr.stat == 2) return
+ if (user.stat == 2) return
- usr.client.eye = target
+ user.client.eye = target
/*
/obj/item/cigarpacket
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 7a0515abfc..47b29898af 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -56,6 +56,8 @@ GLOBAL_LIST_EMPTY(areas_by_type)
var/forbid_singulo = FALSE // If true singulo will not move in.
var/no_spoilers = FALSE // If true, makes it much more difficult to see what is inside an area with things like mesons.
var/soundproofed = FALSE // If true, blocks sounds from other areas and prevents hearers on other areas from hearing the sounds within.
+ var/block_phase_shift = FALSE //Stops phase shifted mobs from entering // RS Port #658
+ var/block_ghosts = FALSE //Stops ghosts from entering //RS Port #658
/area/New()
// Used by the maploader, this must be done in New, not init
@@ -398,6 +400,7 @@ var/list/mob/living/forced_ambiance_list = new
play_ambience(L, initial = TRUE)
if(no_spoilers)
L.disable_spoiler_vision()
+ check_phase_shift(M) //RS Port #658
/area/proc/play_ambience(var/mob/living/L, initial = TRUE)
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
@@ -554,3 +557,19 @@ GLOBAL_DATUM(spoiler_obfuscation_image, /image)
add_overlay(GLOB.spoiler_obfuscation_image)
else
cut_overlay(GLOB.spoiler_obfuscation_image)
+
+// RS Port #658 Start
+/area/proc/check_phase_shift(var/mob/ourmob)
+ if(!block_phase_shift || !ourmob.incorporeal_move)
+ return
+ if(!isliving(ourmob))
+ return
+ if(isanimal(ourmob))
+ var/mob/living/simple_mob/shadekin/SK = ourmob
+ if(SK.ability_flags & AB_PHASE_SHIFTED)
+ SK.phase_in(SK.loc)
+ if(ishuman(ourmob))
+ var/mob/living/carbon/human/SK = ourmob
+ if(SK.ability_flags & AB_PHASE_SHIFTED)
+ SK.phase_in(SK.loc)
+// RS Port #658 End
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 614eb7e981..0d0c0a9bbd 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -449,17 +449,17 @@
return data
-/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
+/obj/machinery/computer/scan_consolenew/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
- if(!istype(usr.loc, /turf))
+ if(!istype(ui.user.loc, /turf))
return TRUE
if(!src || !src.connected)
return TRUE
if(irradiating) // Make sure that it isn't already irradiating someone...
return TRUE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
if(tgui_act_modal(action, params))
return TRUE
diff --git a/code/game/gamemodes/changeling/powers/mimic_voice.dm b/code/game/gamemodes/changeling/powers/mimic_voice.dm
index b8a18ac6fc..f5d65b8ec2 100644
--- a/code/game/gamemodes/changeling/powers/mimic_voice.dm
+++ b/code/game/gamemodes/changeling/powers/mimic_voice.dm
@@ -22,7 +22,7 @@
to_chat(src, span_notice("We return our vocal glands to their original location."))
return
- var/mimic_voice = sanitize(tgui_input_text(usr, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN), MAX_NAME_LEN)
+ var/mimic_voice = sanitize(tgui_input_text(src, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN), MAX_NAME_LEN)
if(!mimic_voice)
return
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 6883220bac..27c0941144 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -315,8 +315,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
/obj/item/book/tome/attack_self(mob/living/user as mob)
- usr = user
- if(!usr.canmove || usr.stat || usr.restrained())
+ if(!user.canmove || user.stat || user.restrained())
return
if(!cultwords["travel"])
@@ -337,11 +336,11 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if("Cancel", null)
return
if("Read it")
- if(usr.get_active_hand() != src)
+ if(user.get_active_hand() != src)
return
user << browse("[tomedat]", "window=Arcane Tome")
return
- if(usr.get_active_hand() != src)
+ if(user.get_active_hand() != src)
return
var/list/dictionary = list (
@@ -386,7 +385,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
var/chosen_rune = null
- if(usr)
+ if(user)
chosen_rune = input ("Choose a rune to scribe.") in scribewords
if (!chosen_rune)
return
@@ -398,7 +397,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if (chosen_rune == "teleport other")
dictionary[chosen_rune] += input ("Choose a destination word") in english
- if(usr.get_active_hand() != src)
+ if(user.get_active_hand() != src)
return
for (var/mob/V in viewers(src))
@@ -408,7 +407,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if(do_after(user, 50))
var/area/A = get_area(user)
log_and_message_admins("created \an [chosen_rune] rune at \the [A.name] - [user.loc.x]-[user.loc.y]-[user.loc.z].")
- if(usr.get_active_hand() != src)
+ if(user.get_active_hand() != src)
return
var/mob/living/carbon/human/H = user
var/obj/effect/rune/R = new /obj/effect/rune(user.loc)
@@ -439,7 +438,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
w_class = ITEMSIZE_SMALL
var/cultistsonly = 1
/obj/item/book/tome/imbued/attack_self(mob/user as mob)
- if(src.cultistsonly && !iscultist(usr))
+ if(src.cultistsonly && !iscultist(user))
return
if(!cultwords["travel"])
runerandom()
@@ -448,7 +447,7 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if (!istype(user.loc,/turf))
to_chat(user, span_notice("You do not have enough space to write a proper rune."))
var/list/runes = list("teleport", "itemport", "tome", "armor", "convert", "tear in reality", "emp", "drain", "seer", "raise", "obscure", "reveal", "astral journey", "manifest", "imbue talisman", "sacrifice", "wall", "freedom", "cultsummon", "deafen", "blind", "bloodboil", "communicate", "stun")
- r = input(usr, "Choose a rune to scribe", "Rune Scribing") in runes // Remains input() for extreme blocking
+ r = input(user, "Choose a rune to scribe", "Rune Scribing") in runes // Remains input() for extreme blocking
var/obj/effect/rune/R = new /obj/effect/rune
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
@@ -460,8 +459,8 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if("teleport")
var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri")
var/beacon
- if(usr)
- beacon = input(usr, "Select the last rune", "Rune Scribing") in words // Remains input() for extreme blocking
+ if(user)
+ beacon = input(user, "Select the last rune", "Rune Scribing") in words // Remains input() for extreme blocking
R.word1=cultwords["travel"]
R.word2=cultwords["self"]
R.word3=beacon
@@ -470,8 +469,8 @@ var/global/list/rnwords = list("ire","ego","nahlizet","certum","veri","jatkaa","
if("itemport")
var/list/words = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri")
var/beacon
- if(usr)
- beacon = input(usr, "Select the last rune", "Rune Scribing") in words // Remains input() for extreme blocking
+ if(user)
+ beacon = input(user, "Select the last rune", "Rune Scribing") in words // Remains input() for extreme blocking
R.word1=cultwords["travel"]
R.word2=cultwords["other"]
R.word3=beacon
diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm
index 47add9a0ea..9b5c9968a6 100644
--- a/code/game/gamemodes/cult/talisman.dm
+++ b/code/game/gamemodes/cult/talisman.dm
@@ -14,7 +14,7 @@
if("armor")
call(/obj/effect/rune/proc/armor)()
if("emp")
- call(/obj/effect/rune/proc/emp)(usr.loc,3)
+ call(/obj/effect/rune/proc/emp)(user.loc,3)
if("conceal")
call(/obj/effect/rune/proc/obscure)(2)
if("revealrunes")
diff --git a/code/game/gamemodes/technomancer/spells/audible_deception.dm b/code/game/gamemodes/technomancer/spells/audible_deception.dm
index 8f32c6cc5b..1d1e90fb35 100644
--- a/code/game/gamemodes/technomancer/spells/audible_deception.dm
+++ b/code/game/gamemodes/technomancer/spells/audible_deception.dm
@@ -68,7 +68,7 @@
var/list/sound_options = available_sounds
if(check_for_scepter())
sound_options["!!AIR HORN!!"] = 'sound/items/AirHorn.ogg'
- var/new_sound = tgui_input_list(usr, "Select the sound you want to make.", "Sounds", sound_options)
+ var/new_sound = tgui_input_list(user, "Select the sound you want to make.", "Sounds", sound_options)
if(new_sound)
selected_sound = sound_options[new_sound]
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index c4a6b350f8..ed05478e97 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -74,7 +74,7 @@
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics)
minimal_access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction)
alt_titles = list(JOB_ALT_MAINTENANCE_TECHNICIAN = /datum/alt_title/maint_tech, JOB_ALT_ENGINE_TECHNICIAN = /datum/alt_title/engine_tech,
- JOB_ALT_ELECTRICIAN = /datum/alt_title/electrician, JOB_ALT_CONSTRUCTION_ENGINEER = /datum/alt_title/construction_engi, JOB_ALT_ENGINEERING_CONTRACTOR = /datum/alt_title/engineering_contractor, JOB_ALT_COMPUTER_TECHNICIAN = /datum/alt_title/computer_tech)
+ JOB_ALT_ELECTRICIAN = /datum/alt_title/electrician, JOB_ALT_CONSTRUCTION_ENGINEER = /datum/alt_title/construction_engi, JOB_ALT_ENGINEERING_CONTRACTOR = /datum/alt_title/engineering_contractor, JOB_ALT_COMPUTER_TECHNICIAN = /datum/alt_title/computer_tech, JOB_ALT_SALVAGE_TECHNICIAN = /datum/alt_title/salvage_tech)
minimal_player_age = 3
min_age_by_species = list(SPECIES_PROMETHEAN = 2)
diff --git a/code/game/machinery/CableLayer.dm b/code/game/machinery/CableLayer.dm
index 256e57bf18..e13944eb9a 100644
--- a/code/game/machinery/CableLayer.dm
+++ b/code/game/machinery/CableLayer.dm
@@ -36,7 +36,7 @@
if(O.has_tool_quality(TOOL_WIRECUTTER))
if(cable && cable.get_amount())
- var/m = round(input(usr, "Please specify the length of cable to cut", "Cut cable", min(cable.get_amount(), 30)) as num, 1)
+ var/m = round(input(user, "Please specify the length of cable to cut", "Cut cable", min(cable.get_amount(), 30)) as num, 1)
m = min(m, cable.get_amount())
m = min(m, 30)
if(m)
@@ -45,7 +45,7 @@
var/obj/item/stack/cable_coil/CC = new (get_turf(src))
CC.set_amount(m)
else
- to_chat(usr, span_warning("There's no more cable on the reel."))
+ to_chat(user, span_warning("There's no more cable on the reel."))
/obj/machinery/cablelayer/examine(mob/user)
. = ..()
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index d168286ee1..7d9d97acb7 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -43,8 +43,8 @@
return
/obj/machinery/optable/attack_hand(mob/user as mob)
- if(HULK in usr.mutations)
- visible_message(span_danger("\The [usr] destroys \the [src]!"))
+ if(HULK in user.mutations)
+ visible_message(span_danger("\The [user] destroys \the [src]!"))
density = FALSE
qdel(src)
return
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 5a14185d7c..180bebe532 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -296,10 +296,10 @@
/obj/machinery/sleeper/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
- if(!controls_inside && usr == occupant)
+ if(!controls_inside && ui.user == occupant)
return
if(panel_open)
- to_chat(usr, span_notice("Close the maintenance panel first."))
+ to_chat(ui.user, span_notice("Close the maintenance panel first."))
return
. = TRUE
@@ -309,16 +309,16 @@
return
if(occupant.stat == DEAD)
var/datum/gender/G = gender_datums[occupant.get_visible_gender()]
- to_chat(usr, span_danger("This person has no life to preserve anymore. Take [G.him] to a department capable of reanimating [G.him]."))
+ to_chat(ui.user, span_danger("This person has no life to preserve anymore. Take [G.him] to a department capable of reanimating [G.him]."))
return
var/chemical = params["chemid"]
var/amount = text2num(params["amount"])
if(!length(chemical) || amount <= 0)
return
if(occupant.health > min_health) //|| (chemical in emergency_chems))
- inject_chemical(usr, chemical, amount)
+ inject_chemical(ui.user, chemical, amount)
else
- to_chat(usr, span_danger("This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!"))
+ to_chat(ui.user, span_danger("This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!"))
if("removebeaker")
remove_beaker()
if("togglefilter")
@@ -328,7 +328,7 @@
if("ejectify")
go_out()
if("changestasis")
- var/new_stasis = tgui_input_list(usr, "Levels deeper than 50% stasis level will render the patient unconscious.","Stasis Level", stasis_choices)
+ var/new_stasis = tgui_input_list(ui.user, "Levels deeper than 50% stasis level will render the patient unconscious.","Stasis Level", stasis_choices)
if(new_stasis)
stasis_level = stasis_choices[new_stasis]
if("auto_eject_dead_on")
@@ -337,7 +337,7 @@
auto_eject_dead = FALSE
else
return FALSE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
/obj/machinery/sleeper/process()
if(stat & (NOPOWER|BROKEN))
diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm
index a891a03f82..cf1fc43839 100644
--- a/code/game/machinery/ai_slipper.dm
+++ b/code/game/machinery/ai_slipper.dm
@@ -39,7 +39,7 @@
if(istype(user, /mob/living/silicon))
return attack_hand(user)
else // trying to unlock the interface
- if(allowed(usr))
+ if(allowed(user))
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] the device.")
if(locked)
@@ -48,7 +48,7 @@
user << browse(null, "window=ai_slipper")
else
if(user.machine==src)
- attack_hand(usr)
+ attack_hand(user)
else
to_chat(user, span_warning("Access denied."))
return
diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm
index aff190e5e3..522a883efe 100644
--- a/code/game/machinery/air_alarm.dm
+++ b/code/game/machinery/air_alarm.dm
@@ -682,10 +682,10 @@
var/list/selected = TLV["temperature"]
var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE)
var/min_temperature = max(selected[2] - T0C, MIN_TEMPERATURE)
- var/input_temperature = tgui_input_number(usr, "What temperature would you like the system to mantain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C, max_temperature, min_temperature, round_value = FALSE)
+ var/input_temperature = tgui_input_number(ui.user, "What temperature would you like the system to mantain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C, max_temperature, min_temperature, round_value = FALSE)
if(isnum(input_temperature))
if(input_temperature > max_temperature || input_temperature < min_temperature)
- to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C")
+ to_chat(ui.user, "Temperature must be between [min_temperature]C and [max_temperature]C")
else
target_temperature = input_temperature + T0C
return TRUE
@@ -694,13 +694,13 @@
// Yes, this is kinda snowflaky; however, I would argue it would be far more snowflakey
// to include "custom hrefs" and all the other bullshit that nano states have just for the
// like, two UIs, that want remote access to other UIs.
- if((locked && !issilicon(usr) && !istype(state, /datum/tgui_state/air_alarm_remote)) || (issilicon(usr) && aidisabled))
+ if((locked && !issilicon(ui.user) && !istype(state, /datum/tgui_state/air_alarm_remote)) || (issilicon(ui.user) && aidisabled))
return
var/device_id = params["id_tag"]
switch(action)
if("lock")
- if(issilicon(usr) && !wires.is_cut(WIRE_IDSCAN))
+ if(issilicon(ui.user) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
. = TRUE
if( "power",
@@ -713,42 +713,42 @@
"panic_siphon",
"scrubbing",
"direction")
- send_signal(device_id, list("[action]" = text2num(params["val"])), usr)
+ send_signal(device_id, list("[action]" = text2num(params["val"])), ui.user)
. = TRUE
if("excheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^1), usr)
+ send_signal(device_id, list("checks" = text2num(params["val"])^1), ui.user)
. = TRUE
if("incheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^2), usr)
+ send_signal(device_id, list("checks" = text2num(params["val"])^2), ui.user)
. = TRUE
if("set_external_pressure", "set_internal_pressure")
var/target = params["value"]
if(!isnull(target))
- send_signal(device_id, list("[action]" = target), usr)
+ send_signal(device_id, list("[action]" = target), ui.user)
. = TRUE
if("reset_external_pressure")
- send_signal(device_id, list("reset_external_pressure"), usr)
+ send_signal(device_id, list("reset_external_pressure"), ui.user)
. = TRUE
if("reset_internal_pressure")
- send_signal(device_id, list("reset_internal_pressure"), usr)
+ send_signal(device_id, list("reset_internal_pressure"), ui.user)
. = TRUE
if("threshold")
var/env = params["env"]
var/name = params["var"]
- var/value = tgui_input_number(usr, "New [name] for [env]:", name, TLV[env][name], min_value=-1, round_value = FALSE)
+ var/value = tgui_input_number(ui.user, "New [name] for [env]:", name, TLV[env][name], min_value=-1, round_value = FALSE)
if(!isnull(value) && !..())
if(value < 0)
TLV[env][name] = -1
else
TLV[env][name] = round(value, 0.01)
clamp_tlv_values(env, name)
- // investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS)
+ // investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(ui.user)]",INVESTIGATE_ATMOS)
. = TRUE
if("mode")
mode = text2num(params["mode"])
- // investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS)
- apply_mode(usr)
+ // investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(ui.user)]",INVESTIGATE_ATMOS)
+ apply_mode(ui.user)
. = TRUE
if("alarm")
if(alarm_area.atmosalert(2, src))
@@ -817,7 +817,7 @@
to_chat(user, "It does nothing.")
return
else
- if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
+ if(allowed(user) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
to_chat(user, span_notice("You [locked ? "lock" : "unlock"] the Air Alarm interface."))
else
diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm
index 5c5db6ebb5..1c538eaf01 100644
--- a/code/game/machinery/atmoalter/area_atmos_computer.dm
+++ b/code/game/machinery/atmoalter/area_atmos_computer.dm
@@ -51,7 +51,7 @@
return list("scrubbers" = working)
-/obj/machinery/computer/area_atmos/tgui_act(action, params)
+/obj/machinery/computer/area_atmos/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -75,7 +75,7 @@
scanscrubbers()
. = TRUE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
/obj/machinery/computer/area_atmos/proc/toggle_all(on)
for(var/id in connectedscrubbers)
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index fa0900ac46..c3a323a896 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -315,7 +315,7 @@ update_flag
return data
-/obj/machinery/portable_atmospherics/canister/tgui_act(action, params)
+/obj/machinery/portable_atmospherics/canister/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -331,7 +331,7 @@ update_flag
"\[Air\]" = "grey", \
"\[CAUTION\]" = "yellow", \
)
- var/label = tgui_input_list(usr, "Choose canister label", "Gas canister", colors)
+ var/label = tgui_input_list(ui.user, "Choose canister label", "Gas canister", colors)
if(label)
canister_color = colors[label]
icon_state = colors[label]
@@ -348,7 +348,7 @@ update_flag
pressure = 10*ONE_ATMOSPHERE
. = TRUE
else if(pressure == "input")
- pressure = tgui_input_number(usr, "New release pressure ([ONE_ATMOSPHERE/10]-[10*ONE_ATMOSPHERE] kPa):", name, release_pressure, 10*ONE_ATMOSPHERE, ONE_ATMOSPHERE/10)
+ pressure = tgui_input_number(ui.user, "New release pressure ([ONE_ATMOSPHERE/10]-[10*ONE_ATMOSPHERE] kPa):", name, release_pressure, 10*ONE_ATMOSPHERE, ONE_ATMOSPHERE/10)
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
@@ -359,14 +359,14 @@ update_flag
if("valve")
if(valve_open)
if(holding)
- release_log += "Valve was " + span_bold("closed") + " by [usr] ([usr.ckey]), stopping the transfer into the [holding]
"
+ release_log += "Valve was " + span_bold("closed") + " by [ui.user] ([ui.user.ckey]), stopping the transfer into the [holding]
"
else
- release_log += "Valve was " + span_bold("closed") + " by [usr] ([usr.ckey]), stopping the transfer into the " + span_red(span_bold("air")) + "
"
+ release_log += "Valve was " + span_bold("closed") + " by [ui.user] ([ui.user.ckey]), stopping the transfer into the " + span_red(span_bold("air")) + "
"
else
if(holding)
- release_log += "Valve was " + span_bold("opened") + " by [usr] ([usr.ckey]), starting the transfer into the [holding]
"
+ release_log += "Valve was " + span_bold("opened") + " by [ui.user] ([ui.user.ckey]), starting the transfer into the [holding]
"
else
- release_log += "Valve was " + span_bold("opened") + " by [usr] ([usr.ckey]), starting the transfer into the " + span_red(span_bold("air")) + "
"
+ release_log += "Valve was " + span_bold("opened") + " by [ui.user] ([ui.user.ckey]), starting the transfer into the " + span_red(span_bold("air")) + "
"
log_open()
valve_open = !valve_open
. = TRUE
@@ -374,14 +374,14 @@ update_flag
if(holding)
if(valve_open)
valve_open = 0
- release_log += "Valve was " + span_bold("closed") + " by [usr] ([usr.ckey]), stopping the transfer into the [holding]
"
+ release_log += "Valve was " + span_bold("closed") + " by [ui.user] ([ui.user.ckey]), stopping the transfer into the [holding]
"
if(istype(holding, /obj/item/tank))
- holding.manipulated_by = usr.real_name
+ holding.manipulated_by = ui.user.real_name
holding.loc = loc
holding = null
. = TRUE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
update_icon()
/obj/machinery/portable_atmospherics/canister/phoron/New()
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 752f9305ac..c1b372e5ad 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -146,11 +146,11 @@
if(..())
return TRUE
- usr.set_machine(src)
- add_fingerprint(usr)
+ ui.user.set_machine(src)
+ add_fingerprint(ui.user)
if(busy)
- to_chat(usr, span_notice("The autolathe is busy. Please wait for completion of previous operation."))
+ to_chat(ui.user, span_notice("The autolathe is busy. Please wait for completion of previous operation."))
return
switch(action)
if("make")
@@ -176,8 +176,8 @@
if(!isnull(materials.get_material_amount(material)) && materials.get_material_amount(material) < round(making.resources[material] * coeff))
max_sheets = 0
//Build list of multipliers for sheets.
- multiplier = tgui_input_number(usr, "How many do you want to print? (0-[max_sheets])", null, null, max_sheets, 0)
- if(!multiplier || multiplier <= 0 || (multiplier != round(multiplier)) || multiplier > max_sheets || tgui_status(usr, state) != STATUS_INTERACTIVE)
+ multiplier = tgui_input_number(ui.user, "How many do you want to print? (0-[max_sheets])", null, null, max_sheets, 0)
+ if(!multiplier || multiplier <= 0 || (multiplier != round(multiplier)) || multiplier > max_sheets || tgui_status(ui.user, state) != STATUS_INTERACTIVE)
return FALSE
//Check if we still have the materials.
diff --git a/code/game/machinery/biogenerator.dm b/code/game/machinery/biogenerator.dm
index d9fe85fcbd..b3b41376ff 100644
--- a/code/game/machinery/biogenerator.dm
+++ b/code/game/machinery/biogenerator.dm
@@ -135,14 +135,14 @@
ui = new(user, src, "Biogenerator", name)
ui.open()
-/obj/machinery/biogenerator/tgui_act(action, params)
+/obj/machinery/biogenerator/tgui_act(action, params, datum/tgui/ui)
if(..())
return
. = TRUE
switch(action)
if("activate")
- INVOKE_ASYNC(src, PROC_REF(activate))
+ INVOKE_ASYNC(src, PROC_REF(activate), ui.user)
return TRUE
if("detach")
if(beaker)
@@ -166,11 +166,11 @@
return
var/cost = round(br.cost / build_eff)
if(cost > points)
- to_chat(usr, span_danger("Insufficient biomass."))
+ to_chat(ui.user, span_danger("Insufficient biomass."))
return
var/amt_to_actually_dispense = round(min(beaker.reagents.get_free_space(), br.reagent_amt))
if(amt_to_actually_dispense <= 0)
- to_chat(usr, span_danger("The loaded beaker is full!"))
+ to_chat(ui.user, span_danger("The loaded beaker is full!"))
return
points -= (cost * (amt_to_actually_dispense / br.reagent_amt))
beaker.reagents.add_reagent(br.reagent_id, amt_to_actually_dispense)
@@ -179,7 +179,7 @@
var/cost = round(bi.cost / build_eff)
if(cost > points)
- to_chat(usr, span_danger("Insufficient biomass."))
+ to_chat(ui.user, span_danger("Insufficient biomass."))
return
points -= cost
@@ -263,13 +263,13 @@
return
tgui_interact(user)
-/obj/machinery/biogenerator/proc/activate()
- if(usr.stat)
+/obj/machinery/biogenerator/proc/activate(mob/user)
+ if(user.stat)
return
if(stat) //NOPOWER etc
return
if(processing)
- to_chat(usr, span_notice("The biogenerator is in the process of working."))
+ to_chat(user, span_notice("The biogenerator is in the process of working."))
return
var/S = 0
for(var/obj/item/reagent_containers/food/snacks/grown/I in contents)
@@ -289,7 +289,7 @@
playsound(src, 'sound/machines/biogenerator_end.ogg', 40, 1)
update_icon()
else
- to_chat(usr, span_warning("Error: No growns inside. Please insert growns."))
+ to_chat(user, span_warning("Error: No growns inside. Please insert growns."))
return
/obj/machinery/biogenerator/RefreshParts()
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index 7a02d6115a..cc3e3fc755 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -150,7 +150,7 @@
if(anomalous_organs)
possible_list |= anomalous_products
- var/choice = tgui_input_list(usr, "What would you like to print?", "Print Choice", possible_list)
+ var/choice = tgui_input_list(user, "What would you like to print?", "Print Choice", possible_list)
if(!choice || printing || (stat & (BROKEN|NOPOWER)))
return
diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm
index e45c329f37..6e59c56844 100644
--- a/code/game/machinery/bomb_tester_vr.dm
+++ b/code/game/machinery/bomb_tester_vr.dm
@@ -149,26 +149,26 @@
text_mode = "tank transfer valve detonation"
if(MODE_CANISTER)
text_mode = "canister-assisted single gas tank detonation"
- to_chat(usr, span_notice("[src] set to simulate a [text_mode]."))
+ to_chat(ui.user, span_notice("[src] set to simulate a [text_mode]."))
return TRUE
if("add_tank")
- if(istype(usr.get_active_hand(), /obj/item/tank))
- var/obj/item/tank/T = usr.get_active_hand()
+ if(istype(ui.user.get_active_hand(), /obj/item/tank))
+ var/obj/item/tank/T = ui.user.get_active_hand()
var/slot = params["slot"]
if(slot == 1 && !tank1)
tank1 = T
else if(slot == 2 && !tank2)
tank2 = T
else
- to_chat(usr, span_warning("Slot [slot] is full."))
+ to_chat(ui.user, span_warning("Slot [slot] is full."))
return
- usr.drop_item(T)
+ ui.user.drop_item(T)
T.forceMove(src)
return TRUE
else
- to_chat(usr, span_warning("You must be wielding a tank to insert it!"))
+ to_chat(ui.user, span_warning("You must be wielding a tank to insert it!"))
if("remove_tank")
var/obj/item/tank/T = locate(params["ref"]) in list(tank1, tank2)
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index 67824ecb3f..6feae4eff2 100644
--- a/code/game/machinery/camera/camera_assembly.dm
+++ b/code/game/machinery/camera/camera_assembly.dm
@@ -80,19 +80,19 @@
if(W.has_tool_quality(TOOL_SCREWDRIVER))
playsound(src, W.usesound, 50, 1)
- var/input = sanitize(tgui_input_text(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: "+using_map.station_short+",Security,Secret ", "Set Network", camera_network ? camera_network : NETWORK_DEFAULT))
+ var/input = sanitize(tgui_input_text(user, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: "+using_map.station_short+",Security,Secret ", "Set Network", camera_network ? camera_network : NETWORK_DEFAULT))
if(!input)
- to_chat(usr, "No input found please hang up and try your call again.")
+ to_chat(user, "No input found please hang up and try your call again.")
return
var/list/tempnetwork = splittext(input, ",")
if(tempnetwork.len < 1)
- to_chat(usr, "No network found please hang up and try your call again.")
+ to_chat(user, "No network found please hang up and try your call again.")
return
var/area/camera_area = get_area(src)
var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])"
- input = sanitizeSafe(tgui_input_text(usr, "How would you like to name the camera?", "Set Camera Name", camera_name ? camera_name : temptag), MAX_NAME_LEN)
+ input = sanitizeSafe(tgui_input_text(user, "How would you like to name the camera?", "Set Camera Name", camera_name ? camera_name : temptag), MAX_NAME_LEN)
state = 4
var/obj/machinery/camera/C = new(src.loc)
diff --git a/code/game/machinery/clawmachine.dm b/code/game/machinery/clawmachine.dm
index 6b9298cf39..90c64d1031 100644
--- a/code/game/machinery/clawmachine.dm
+++ b/code/game/machinery/clawmachine.dm
@@ -158,7 +158,7 @@
cashmoney.update_icon()
if(cashmoney.worth <= 0)
- usr.drop_from_inventory(cashmoney)
+ user.drop_from_inventory(cashmoney)
qdel(cashmoney)
cashmoney.update_icon()
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index ed07a6158b..4f4722c559 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -127,11 +127,11 @@
return data
-/obj/machinery/computer/operating/tgui_act(action, params)
+/obj/machinery/computer/operating/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
- if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
+ if((ui.user.contents.Find(src) || (in_range(src, ui.user) && istype(src.loc, /turf))) || (istype(ui.user, /mob/living/silicon)))
+ ui.user.set_machine(src)
. = TRUE
switch(action)
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 2808be538a..aa3902c846 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -111,23 +111,23 @@
laws.add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
laws.add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
laws.add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
- to_chat(usr, "Law module applied.")
+ to_chat(user, "Law module applied.")
if(istype(P, /obj/item/aiModule/nanotrasen))
laws.add_inherent_law("Safeguard: Protect your assigned space station to the best of your ability. It is not something we can easily afford to replace.")
laws.add_inherent_law("Serve: Serve the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
laws.add_inherent_law("Protect: Protect the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
laws.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.")
- to_chat(usr, "Law module applied.")
+ to_chat(user, "Law module applied.")
if(istype(P, /obj/item/aiModule/purge))
laws.clear_inherent_laws()
- to_chat(usr, "Law module applied.")
+ to_chat(user, "Law module applied.")
if(istype(P, /obj/item/aiModule/freeform))
var/obj/item/aiModule/freeform/M = P
laws.add_inherent_law(M.newFreeFormLaw)
- to_chat(usr, "Added a freeform law.")
+ to_chat(user, "Added a freeform law.")
if(istype(P, /obj/item/mmi))
var/obj/item/mmi/M = P
@@ -148,7 +148,7 @@
user.drop_item()
P.loc = src
brain = P
- to_chat(usr, "Added [P].")
+ to_chat(user, "Added [P].")
icon_state = "3b"
if(P.has_tool_quality(TOOL_CROWBAR) && brain)
diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm
index 44600b9c69..70ec7f8717 100644
--- a/code/game/machinery/computer/aifixer.dm
+++ b/code/game/machinery/computer/aifixer.dm
@@ -80,7 +80,7 @@
return data
-/obj/machinery/computer/aifixer/tgui_act(action, params)
+/obj/machinery/computer/aifixer/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
if(!occupier)
@@ -92,7 +92,7 @@
switch(action)
if("PRG_beginReconstruction")
if(occupier?.health < 100)
- to_chat(usr, span_notice("Reconstruction in progress. This will take several minutes."))
+ to_chat(ui.user, span_notice("Reconstruction in progress. This will take several minutes."))
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
restoring = TRUE
var/mob/observer/dead/ghost = occupier.get_ghost()
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 8afe56476b..f6a50c3254 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -159,7 +159,7 @@
sleep(10)
enemy_hp -= attackamt
- arcade_action()
+ arcade_action(ui.user)
if("heal")
blocked = 1
@@ -173,7 +173,7 @@
player_mp -= pointamt
player_hp += healamt
blocked = 1
- arcade_action()
+ arcade_action(ui.user)
if("charge")
blocked = 1
@@ -185,7 +185,7 @@
turtle--
sleep(10)
- arcade_action()
+ arcade_action(ui.user)
if(action == "newgame") //Reset everything
@@ -201,10 +201,10 @@
randomize_characters()
emagged = 0
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
return TRUE
-/obj/machinery/computer/arcade/battle/proc/arcade_action()
+/obj/machinery/computer/arcade/battle/proc/arcade_action(var/mob/user)
if ((enemy_mp <= 0) || (enemy_hp <= 0))
if(!gameover)
gameover = 1
@@ -215,8 +215,8 @@
feedback_inc("arcade_win_emagged")
new /obj/effect/spawner/newbomb/timer/syndicate(src.loc)
new /obj/item/clothing/head/collectable/petehat(src.loc)
- message_admins("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.")
- log_game("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.")
+ message_admins("[key_name_admin(user)] has outbombed Cuban Pete and been awarded a bomb.")
+ log_game("[key_name_admin(user)] has outbombed Cuban Pete and been awarded a bomb.")
randomize_characters()
emagged = 0
else if(!contents.len)
@@ -245,7 +245,7 @@
temp = "You have been drained! GAME OVER"
if(emagged)
feedback_inc("arcade_loss_mana_emagged")
- usr.gib()
+ user.gib()
else
feedback_inc("arcade_loss_mana_normal")
@@ -267,7 +267,7 @@
playsound(src, 'sound/arcade/lose.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
if(emagged)
feedback_inc("arcade_loss_hp_emagged")
- usr.gib()
+ user.gib()
else
feedback_inc("arcade_loss_hp_normal")
@@ -367,12 +367,12 @@
"You have made it to Orion! Congratulations! Your crew is one of the few to start a new foothold for mankind!"
)
-/obj/machinery/computer/arcade/orion_trail/proc/newgame()
+/obj/machinery/computer/arcade/orion_trail/proc/newgame(var/mob/user)
// Set names of settlers in crew
settlers = list()
for(var/i = 1; i <= 3; i++)
add_crewmember()
- add_crewmember("[usr]")
+ add_crewmember("[user]")
// Re-set items to defaults
engine = 1
hull = 1
@@ -466,7 +466,7 @@
if (href_list["continue"]) //Continue your travels
if(gameStatus == ORION_STATUS_NORMAL && !event && turns != 7)
if(turns >= ORION_TRAIL_WINTURN)
- win()
+ win(usr)
else
food -= (alive+traitors_aboard)*2
fuel -= 5
@@ -535,7 +535,7 @@
else if(href_list["newgame"]) //Reset everything
if(gameStatus == ORION_STATUS_START)
playsound(src, 'sound/arcade/Ori_begin.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
- newgame()
+ newgame(usr)
else if(href_list["menu"]) //back to the main menu
if(gameStatus == ORION_STATUS_GAMEOVER)
gameStatus = ORION_STATUS_START
@@ -1006,14 +1006,14 @@
return removed
-/obj/machinery/computer/arcade/orion_trail/proc/win()
+/obj/machinery/computer/arcade/orion_trail/proc/win(var/mob/user)
gameStatus = ORION_STATUS_START
src.visible_message("\The [src] plays a triumpant tune, stating 'CONGRATULATIONS, YOU HAVE MADE IT TO ORION.'")
playsound(src, 'sound/arcade/Ori_win.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
if(emagged)
new /obj/item/orion_ship(src.loc)
- message_admins("[key_name_admin(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
- log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
+ message_admins("[key_name_admin(user)] made it to Orion on an emagged machine and got an explosive toy ship.")
+ log_game("[key_name(user)] made it to Orion on an emagged machine and got an explosive toy ship.")
else
prizevend()
emagged = 0
@@ -1025,7 +1025,7 @@
to_chat(user, span_notice("You override the cheat code menu and skip to Cheat #[rand(1, 50)]: Realism Mode."))
name = "The Orion Trail: Realism Edition"
desc = "Learn how our ancestors got to Orion, and try not to die in the process!"
- newgame()
+ newgame(user)
emagged = 1
return 1
@@ -1049,8 +1049,8 @@
if(active)
return
- message_admins("[key_name_admin(usr)] primed an explosive Orion ship for detonation.")
- log_game("[key_name(usr)] primed an explosive Orion ship for detonation.")
+ message_admins("[key_name_admin(user)] primed an explosive Orion ship for detonation.")
+ log_game("[key_name(user)] primed an explosive Orion ship for detonation.")
to_chat(user, span_warning("You flip the switch on the underside of [src]."))
active = 1
@@ -1112,10 +1112,10 @@
var/paid = 0
var/obj/item/card/id/W = I.GetID()
if(W) //for IDs and PDAs and wallets with IDs
- paid = pay_with_card(W,I)
+ paid = pay_with_card(W, I, user)
else if(istype(I, /obj/item/spacecash/ewallet))
var/obj/item/spacecash/ewallet/C = I
- paid = pay_with_ewallet(C)
+ paid = pay_with_ewallet(C, user)
else if(istype(I, /obj/item/spacecash))
var/obj/item/spacecash/C = I
paid = pay_with_cash(C, user)
@@ -1132,16 +1132,16 @@
// This is not a status display message, since it's something the character
// themselves is meant to see BEFORE putting the money in
- to_chat(usr, "[icon2html(cashmoney,user.client)] " + span_warning("That is not enough money."))
+ to_chat(user, "[icon2html(cashmoney,user.client)] " + span_warning("That is not enough money."))
return 0
if(istype(cashmoney, /obj/item/spacecash))
- visible_message(span_info("\The [usr] inserts some cash into \the [src]."))
+ visible_message(span_info("\The [user] inserts some cash into \the [src]."))
cashmoney.worth -= gameprice
if(cashmoney.worth <= 0)
- usr.drop_from_inventory(cashmoney)
+ user.drop_from_inventory(cashmoney)
qdel(cashmoney)
else
cashmoney.update_icon()
@@ -1155,9 +1155,9 @@
///// Ewallet
-/obj/machinery/computer/arcade/clawmachine/proc/pay_with_ewallet(var/obj/item/spacecash/ewallet/wallet)
+/obj/machinery/computer/arcade/clawmachine/proc/pay_with_ewallet(var/obj/item/spacecash/ewallet/wallet, var/mob/user)
if(!emagged)
- visible_message(span_info("\The [usr] swipes \the [wallet] through \the [src]."))
+ visible_message(span_info("\The [user] swipes \the [wallet] through \the [src]."))
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
if(gameprice > wallet.worth)
visible_message(span_info("Insufficient funds."))
@@ -1168,14 +1168,14 @@
return 1
if(emagged)
playsound(src, 'sound/arcade/steal.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
- to_chat(usr, span_info("It doesn't seem to accept that! Seem you'll need to swipe a valid ID."))
+ to_chat(user, span_info("It doesn't seem to accept that! Seem you'll need to swipe a valid ID."))
///// ID
-/obj/machinery/computer/arcade/clawmachine/proc/pay_with_card(var/obj/item/card/id/I, var/obj/item/ID_container)
+/obj/machinery/computer/arcade/clawmachine/proc/pay_with_card(var/obj/item/card/id/I, var/obj/item/ID_container, var/mob/user)
if(I==ID_container || ID_container == null)
- visible_message(span_info("\The [usr] swipes \the [I] through \the [src]."))
+ visible_message(span_info("\The [user] swipes \the [I] through \the [src]."))
else
- visible_message(span_info("\The [usr] swipes \the [ID_container] through \the [src]."))
+ visible_message(span_info("\The [user] swipes \the [ID_container] through \the [src]."))
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
var/datum/money_account/customer_account = get_account(I.associated_account_number)
if(!customer_account)
@@ -1189,7 +1189,7 @@
// Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
// empty at high security levels
if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
- var/attempt_pin = tgui_input_number(usr, "Enter pin code", "Vendor transaction")
+ var/attempt_pin = tgui_input_number(user, "Enter pin code", "Vendor transaction")
customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
if(!customer_account)
@@ -1268,7 +1268,7 @@
return data
-/obj/machinery/computer/arcade/clawmachine/tgui_act(action, params)
+/obj/machinery/computer/arcade/clawmachine/tgui_act(action, params, datum/tgui/ui)
if(..())
return
@@ -1289,9 +1289,9 @@
if(action == "pointless" && wintick >= 10)
instructions = "Insert 1 thaler or swipe a card to play!"
- clawvend()
+ clawvend(ui.user)
-/obj/machinery/computer/arcade/clawmachine/proc/clawvend() /// True to a real claw machine, it's NEARLY impossible to win.
+/obj/machinery/computer/arcade/clawmachine/proc/clawvend(var/mob/user) /// True to a real claw machine, it's NEARLY impossible to win.
winprob += 1 /// Yeah.
if(prob(winprob)) /// YEAH.
@@ -1304,7 +1304,7 @@
winscreen = "You won...?"
var/obj/item/grenade/G = new /obj/item/grenade/explosive(get_turf(src)) /// YEAAAAAAAAAAAAAAAAAAH!!!!!!!!!!
G.activate()
- G.throw_at(get_turf(usr),10,10) /// Play stupid games, win stupid prizes.
+ G.throw_at(get_turf(user),10,10) /// Play stupid games, win stupid prizes.
playsound(src, 'sound/arcade/Ori_win.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
winprob = 0
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index a566a6be1a..77f9ce12c0 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -158,35 +158,35 @@
if(modify)
data_core.manifest_modify(modify.registered_name, modify.assignment, modify.rank)
modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])"
- if(ishuman(usr))
+ if(ishuman(ui.user))
modify.forceMove(get_turf(src))
- if(!usr.get_active_hand())
- usr.put_in_hands(modify)
+ if(!ui.user.get_active_hand())
+ ui.user.put_in_hands(modify)
modify = null
else
modify.forceMove(get_turf(src))
modify = null
else
- var/obj/item/I = usr.get_active_hand()
- if(istype(I, /obj/item/card/id) && usr.unEquip(I))
+ var/obj/item/I = ui.user.get_active_hand()
+ if(istype(I, /obj/item/card/id) && ui.user.unEquip(I))
I.forceMove(src)
modify = I
. = TRUE
if("scan")
if(scan)
- if(ishuman(usr))
+ if(ishuman(ui.user))
scan.forceMove(get_turf(src))
- if(!usr.get_active_hand())
- usr.put_in_hands(scan)
+ if(!ui.user.get_active_hand())
+ ui.user.put_in_hands(scan)
scan = null
else
scan.forceMove(get_turf(src))
scan = null
else
- var/obj/item/I = usr.get_active_hand()
+ var/obj/item/I = ui.user.get_active_hand()
if(istype(I, /obj/item/card/id))
- usr.drop_item()
+ ui.user.drop_item()
I.forceMove(src)
scan = I
. = TRUE
@@ -205,7 +205,7 @@
if(is_authenticated() && modify)
var/t1 = params["assign_target"]
if(t1 == "Custom")
- var/temp_t = sanitize(tgui_input_text(usr, "Enter a custom job assignment.","Assignment"), 45)
+ var/temp_t = sanitize(tgui_input_text(ui.user, "Enter a custom job assignment.","Assignment"), 45)
//let custom jobs function as an impromptu alt title, mainly for sechuds
if(temp_t && modify)
modify.assignment = temp_t
@@ -216,7 +216,7 @@
else
var/datum/job/jobdatum = SSjob.get_job(t1)
if(!jobdatum)
- to_chat(usr, span_warning("No log exists for this job: [t1]"))
+ to_chat(ui.user, span_warning("No log exists for this job: [t1]"))
return
access = jobdatum.get_access()
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 9efcb48130..9175cb391a 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -196,7 +196,7 @@
return data
-/obj/machinery/computer/cloning/tgui_act(action, params)
+/obj/machinery/computer/cloning/tgui_act(action, params, datum/tgui/ui)
if(..())
return TRUE
@@ -204,7 +204,7 @@
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_ANSWER)
if(params["id"] == "del_rec" && active_record)
- var/obj/item/card/id/C = usr.get_active_hand()
+ var/obj/item/card/id/C = ui.user.get_active_hand()
if(!istype(C) && !istype(C, /obj/item/pda))
set_temp("ID not in hand.", "danger")
return
@@ -360,16 +360,16 @@
else
scan_mode = FALSE
if("eject")
- if(usr.incapacitated() || !scanner || loading)
+ if(ui.user.incapacitated() || !scanner || loading)
return
- scanner.eject_occupant(usr)
- scanner.add_fingerprint(usr)
+ scanner.eject_occupant(ui.user)
+ scanner.add_fingerprint(ui.user)
if("cleartemp")
temp = null
else
return FALSE
- add_fingerprint(usr)
+ add_fingerprint(ui.user)
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob, var/scan_brain = 0)
if(stat & NOPOWER)
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index 1d43173d5a..2ca39d0ebb 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -185,7 +185,7 @@
if (!can_climb(user))
return
- usr.visible_message(span_warning("[user] starts climbing onto \the [src]!"))
+ user.visible_message(span_warning("[user] starts climbing onto \the [src]!"))
LAZYDISTINCTADD(climbers, user)
if(!do_after(user,(issmall(user) ? climb_delay * 0.6 : climb_delay)))
@@ -196,10 +196,10 @@
LAZYREMOVE(climbers, user)
return
- usr.forceMove(climb_to(user))
+ user.forceMove(climb_to(user))
if (get_turf(user) == get_turf(src))
- usr.visible_message(span_warning("[user] climbs onto \the [src]!"))
+ user.visible_message(span_warning("[user] climbs onto \the [src]!"))
LAZYREMOVE(climbers, user)
/obj/machinery/computer/proc/climb_to(var/mob/living/user)
diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm
index 6bf5417f8d..ddb74b6ad6 100644
--- a/code/game/machinery/computer/guestpass.dm
+++ b/code/game/machinery/computer/guestpass.dm
@@ -49,7 +49,7 @@
to_chat(user, span_warning("This guest pass is already deactivated!"))
return
- var/confirm = tgui_alert(usr, "Do you really want to deactivate this guest pass? (you can't reactivate it)", "Confirm Deactivation", list("Yes", "No"))
+ var/confirm = tgui_alert(user, "Do you really want to deactivate this guest pass? (you can't reactivate it)", "Confirm Deactivation", list("Yes", "No"))
if(confirm == "Yes")
//rip guest pass 3
user.visible_message(span_infoplain(span_bold("\The [user]") + "deactivates \the [src]."))
@@ -193,20 +193,20 @@
mode = params["mode"]
if("giv_name")
- var/nam = sanitizeName(tgui_input_text(usr, "Person pass is issued to", "Name", giv_name))
+ var/nam = sanitizeName(tgui_input_text(ui.user, "Person pass is issued to", "Name", giv_name))
if(nam)
giv_name = nam
if("reason")
- var/reas = sanitize(tgui_input_text(usr, "Reason why pass is issued", "Reason", reason))
+ var/reas = sanitize(tgui_input_text(ui.user, "Reason why pass is issued", "Reason", reason))
if(reas)
reason = reas
if("duration")
- var/dur = tgui_input_number(usr, "Duration (in minutes) during which pass is valid (up to 360 minutes).", "Duration", null, 360, 0)
+ var/dur = tgui_input_number(ui.user, "Duration (in minutes) during which pass is valid (up to 360 minutes).", "Duration", null, 360, 0)
if(dur)
if(dur > 0 && dur <= 360) //VOREStation Edit
duration = dur
else
- to_chat(usr, span_warning("Invalid duration."))
+ to_chat(ui.user, span_warning("Invalid duration."))
if("access")
var/A = text2num(params["access"])
if(A in accesses)
@@ -215,22 +215,22 @@
if(A in giver.GetAccess()) //Let's make sure the ID card actually has the access.
accesses.Add(A)
else
- to_chat(usr, span_warning("Invalid selection, please consult technical support if there are any issues."))
- log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.")
+ to_chat(ui.user, span_warning("Invalid selection, please consult technical support if there are any issues."))
+ log_debug("[key_name_admin(ui.user)] tried selecting an invalid guest pass terminal option.")
if("id")
if(giver)
- if(ishuman(usr))
- giver.loc = usr.loc
- if(!usr.get_active_hand())
- usr.put_in_hands(giver)
+ if(ishuman(ui.user))
+ giver.loc = ui.user.loc
+ if(!ui.user.get_active_hand())
+ ui.user.put_in_hands(giver)
giver = null
else
giver.loc = src.loc
giver = null
accesses.Cut()
else
- var/obj/item/I = usr.get_active_hand()
- if(istype(I, /obj/item/card/id) && usr.unEquip(I))
+ var/obj/item/I = ui.user.get_active_hand()
+ if(istype(I, /obj/item/card/id) && ui.user.unEquip(I))
I.loc = src
giver = I
@@ -238,7 +238,7 @@
var/dat = "