diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md
index 3e5639a5217..abaf97a0b98 100644
--- a/ATTRIBUTIONS.md
+++ b/ATTRIBUTIONS.md
@@ -80,3 +80,9 @@
**Creator:** VerySoft (https://github.com/TS-Rogue-Star/Rogue-Star/pull/435)
**URL:** [Website](https://rogue-star.net/)
**License:** Permission granting in writing for use by Virgo and Chomp with proper attribution
+
+**File:** `icons/mob/turkey.dmi`
+**Title:** Turkey
+**Creator:** VerySoft (https://github.com/TS-Rogue-Star/Rogue-Star/pull/669)
+**URL:** [Website](https://rogue-star.net/)
+**License:** Permission granted in writing for use by Virgo and Chomp with proper attribution
diff --git a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
index 87c430c5d7a..84ba70f55f4 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 4a680494f78..fd1158f408a 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 4c1a0d0ad80..70b498722f2 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 4409482f507..4d442b772a6 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 02c701c91e8..9d0b9c78f7f 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 9201cee4a16..9e6613ebf2b 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 7517cbd7efc..2084b8c901c 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 31544ac1f72..f332afee61c 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 6397be2c59e..86ee7517622 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 0e051d9067d..9f0f220ec2a 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 9923078311b..5dd984a0ff8 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_exchanger.dm b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
index 7b6a5621eb1..078c97af8a1 100644
--- a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
+++ b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
@@ -36,11 +36,11 @@
if(!partner)
return 0
- if(!air_master || air_master.current_cycle <= update_cycle)
+ if(!SSair || SSair.current_cycle <= update_cycle)
return 0
- update_cycle = air_master.current_cycle
- partner.update_cycle = air_master.current_cycle
+ update_cycle = SSair.current_cycle
+ partner.update_cycle = SSair.current_cycle
var/air_heat_capacity = air_contents.heat_capacity()
var/other_air_heat_capacity = partner.air_contents.heat_capacity()
diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm
index 67839d7d3ae..2c1a22a825c 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 9139f96e749..d51a3695293 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/ZAS/Atom.dm b/code/ZAS/Atom.dm
index bfe6fa2ad4d..eeb01b42495 100644
--- a/code/ZAS/Atom.dm
+++ b/code/ZAS/Atom.dm
@@ -36,11 +36,11 @@
//Convenience function for atoms to update turfs they occupy
/atom/movable/proc/update_nearby_tiles(need_rebuild)
- if(!air_master)
+ if(!SSair)
return 0
for(var/turf/simulated/turf in locs)
- air_master.mark_for_update(turf)
+ SSair.mark_for_update(turf)
return 1
diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm
index 21be29d25e1..688eb129922 100644
--- a/code/ZAS/Connection.dm
+++ b/code/ZAS/Connection.dm
@@ -5,7 +5,7 @@
/*
Overview:
- Connections are made between turfs by air_master.connect(). They represent a single point where two zones converge.
+ Connections are made between turfs by SSair.connect(). They represent a single point where two zones converge.
Class Vars:
A - Always a simulated turf.
@@ -60,19 +60,19 @@ Class Procs:
/connection/New(turf/simulated/A, turf/simulated/B)
#ifdef ZASDBG
- ASSERT(air_master.has_valid_zone(A))
- //ASSERT(air_master.has_valid_zone(B))
+ ASSERT(HAS_VALID_ZONE(A))
+ //ASSERT(HAS_VALID_ZONE(B))
#endif
src.A = A
src.B = B
zoneA = A.zone
if(!istype(B))
mark_space()
- edge = air_master.get_edge(A.zone,B)
+ edge = SSair.get_edge(A.zone,B)
edge.add_connection(src)
else
zoneB = B.zone
- edge = air_master.get_edge(A.zone,B.zone)
+ edge = SSair.get_edge(A.zone,B.zone)
edge.add_connection(src)
/connection/proc/mark_direct()
@@ -108,7 +108,7 @@ Class Procs:
erase()
return
- var/block_status = air_master.air_blocked(A,B)
+ var/block_status = SSair.air_blocked(A,B)
if(block_status & AIR_BLOCKED)
//to_world("Blocked connection.")
erase()
@@ -133,7 +133,7 @@ Class Procs:
return
else
edge.remove_connection(src)
- edge = air_master.get_edge(A.zone, B)
+ edge = SSair.get_edge(A.zone, B)
edge.add_connection(src)
zoneA = A.zone
@@ -155,7 +155,7 @@ Class Procs:
//to_world("Zones changed, \...")
if(A.zone && B.zone)
edge.remove_connection(src)
- edge = air_master.get_edge(A.zone, B.zone)
+ edge = SSair.get_edge(A.zone, B.zone)
edge.add_connection(src)
zoneA = A.zone
zoneB = B.zone
diff --git a/code/ZAS/ConnectionGroup.dm b/code/ZAS/ConnectionGroup.dm
index 0be44bb3584..85b2545d36e 100644
--- a/code/ZAS/ConnectionGroup.dm
+++ b/code/ZAS/ConnectionGroup.dm
@@ -2,7 +2,7 @@
Overview:
These are what handle gas transfers between zones and into space.
- They are found in a zone's edges list and in air_master.edges.
+ They are found in a zone's edges list and in SSair.edges.
Each edge updates every air tick due to their role in gas transfer.
They come in two flavors, /connection_edge/zone and /connection_edge/unsimulated.
As the type names might suggest, they handle inter-zone and spacelike connections respectively.
@@ -82,7 +82,7 @@ Class Procs:
/connection_edge/proc/contains_zone(zone/Z)
/connection_edge/proc/erase()
- air_master.remove_edge(src)
+ SSair.remove_edge(src)
//to_world("[type] Erased.")
/connection_edge/proc/tick()
@@ -169,19 +169,19 @@ Class Procs:
if(equiv)
if(direct)
erase()
- air_master.merge(A, B)
+ SSair.merge(A, B)
return
else
A.air.equalize(B.air)
- air_master.mark_edge_sleeping(src)
+ SSair.mark_edge_sleeping(src)
- air_master.mark_zone_update(A)
- air_master.mark_zone_update(B)
+ SSair.mark_zone_update(A)
+ SSair.mark_zone_update(B)
/connection_edge/zone/recheck()
// Edges with only one side being vacuum need processing no matter how close.
if(!A.air.compare(B.air, vacuum_exception = 1))
- air_master.mark_edge_active(src)
+ SSair.mark_edge_active(src)
//Helper proc to get connections for a zone.
/connection_edge/zone/proc/get_connected_zone(zone/from)
@@ -233,16 +233,16 @@ Class Procs:
if(equiv)
A.air.copy_from(air)
- air_master.mark_edge_sleeping(src)
+ SSair.mark_edge_sleeping(src)
- air_master.mark_zone_update(A)
+ SSair.mark_zone_update(A)
/connection_edge/unsimulated/recheck()
// Edges with only one side being vacuum need processing no matter how close.
// Note: This handles the glaring flaw of a room holding pressure while exposed to space, but
// does not specially handle the less common case of a simulated room exposed to an unsimulated pressurized turf.
if(!A.air.compare(air, vacuum_exception = 1))
- air_master.mark_edge_active(src)
+ SSair.mark_edge_active(src)
/proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
//This implements a simplistic version of the Stefan-Boltzmann law.
diff --git a/code/ZAS/ConnectionManager.dm b/code/ZAS/ConnectionManager.dm
index 3890cd85f5c..8d7e270cde0 100644
--- a/code/ZAS/ConnectionManager.dm
+++ b/code/ZAS/ConnectionManager.dm
@@ -16,7 +16,7 @@ Class Procs:
Preferable to accessing the connection directly because it checks validity.
place(connection/c, d)
- Called by air_master.connect(). Sets the connection in the specified direction to c.
+ Called by SSair.connect(). Sets the connection in the specified direction to c.
update_all()
Called after turf/update_air_properties(). Updates the validity of all connections on this turf.
diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm
deleted file mode 100644
index 7f7b5752469..00000000000
--- a/code/ZAS/Controller.dm
+++ /dev/null
@@ -1,231 +0,0 @@
-var/datum/controller/subsystem/air/air_master
-
-var/tick_multiplier = 2
-
-/*
-
-Overview:
- The air controller does everything. There are tons of procs in here.
-
-Class Vars:
- zones - All zones currently holding one or more turfs.
- edges - All processing edges.
-
- tiles_to_update - Tiles scheduled to update next tick.
- zones_to_update - Zones which have had their air changed and need air archival.
- active_hotspots - All processing fire objects.
-
- active_zones - The number of zones which were archived last tick. Used in debug verbs.
- next_id - The next UID to be applied to a zone. Mostly useful for debugging purposes as zones do not need UIDs to function.
-
-Class Procs:
-
- mark_for_update(turf/T)
- Adds the turf to the update list. When updated, update_air_properties() will be called.
- When stuff changes that might affect airflow, call this. It's basically the only thing you need.
-
- add_zone(zone/Z) and remove_zone(zone/Z)
- Adds zones to the zones list. Does not mark them for update.
-
- air_blocked(turf/A, turf/B)
- Returns a bitflag consisting of:
- AIR_BLOCKED - The connection between turfs is physically blocked. No air can pass.
- ZONE_BLOCKED - There is a door between the turfs, so zones cannot cross. Air may or may not be permeable.
-
- has_valid_zone(turf/T)
- Checks the presence and validity of T's zone.
- May be called on unsimulated turfs, returning 0.
-
- merge(zone/A, zone/B)
- Called when zones have a direct connection and equivalent pressure and temperature.
- Merges the zones to create a single zone.
-
- connect(turf/simulated/A, turf/B)
- Called by turf/update_air_properties(). The first argument must be simulated.
- Creates a connection between A and B.
-
- mark_zone_update(zone/Z)
- Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever
- air is returned from a simulated turf.
-
- equivalent_pressure(zone/A, zone/B)
- Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged.
-
- get_edge(zone/A, zone/B)
- get_edge(zone/A, turf/B)
- Gets a valid connection_edge between A and B, creating a new one if necessary.
-
- has_same_air(turf/A, turf/B)
- Used to determine if an unsimulated edge represents a specific turf.
- Simulated edges use connection_edge/contains_zone() for the same purpose.
- Returns 1 if A has identical gases and temperature to B.
-
- remove_edge(connection_edge/edge)
- Called when an edge is erased. Removes it from processing.
-
-*/
-
-//
-// The rest of the air subsystem is defined in air.dm
-//
-
-/datum/controller/subsystem/air
- //Geometry lists
- var/list/zones = list()
- var/list/edges = list()
- //Geometry updates lists
- var/list/tiles_to_update = list()
- var/list/zones_to_update = list()
- var/list/active_fire_zones = list()
- var/list/active_hotspots = list()
- var/list/active_edges = list()
-
- var/active_zones = 0
- var/current_cycle = 0
- var/next_id = 1 //Used to keep track of zone UIDs.
-
-/datum/controller/subsystem/air/proc/add_zone(zone/z)
- zones.Add(z)
- z.name = "Zone [next_id++]"
- mark_zone_update(z)
-
-/datum/controller/subsystem/air/proc/remove_zone(zone/z)
- zones.Remove(z)
- zones_to_update.Remove(z)
-
-/datum/controller/subsystem/air/proc/air_blocked(turf/A, turf/B)
- #ifdef ZASDBG
- ASSERT(isturf(A))
- ASSERT(isturf(B))
- #endif
- var/ablock = A.c_airblock(B)
- if(ablock == BLOCKED) return BLOCKED
- return ablock | B.c_airblock(A)
-
-/datum/controller/subsystem/air/proc/has_valid_zone(turf/simulated/T)
- #ifdef ZASDBG
- ASSERT(istype(T))
- #endif
- return istype(T) && T.zone && !T.zone.invalid
-
-/datum/controller/subsystem/air/proc/merge(zone/A, zone/B)
- #ifdef ZASDBG
- ASSERT(istype(A))
- ASSERT(istype(B))
- ASSERT(!A.invalid)
- ASSERT(!B.invalid)
- ASSERT(A != B)
- #endif
- if(A.contents.len < B.contents.len)
- A.c_merge(B)
- mark_zone_update(B)
- else
- B.c_merge(A)
- mark_zone_update(A)
-
-/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B)
- #ifdef ZASDBG
- ASSERT(istype(A))
- ASSERT(isturf(B))
- ASSERT(A.zone)
- ASSERT(!A.zone.invalid)
- //ASSERT(B.zone)
- ASSERT(A != B)
- #endif
-
- var/block = air_master.air_blocked(A,B)
- if(block & AIR_BLOCKED) return
-
- var/direct = !(block & ZONE_BLOCKED)
- var/space = !istype(B)
-
- if(!space)
- if(min(A.zone.contents.len, B.zone.contents.len) < ZONE_MIN_SIZE || (direct && (equivalent_pressure(A.zone,B.zone) || current_cycle == 0)))
- merge(A.zone,B.zone)
- return
-
- var/a_to_b = get_dir(A,B)
- var/b_to_a = get_dir(B,A)
-
- if(!A.connections) A.connections = new
- if(!B.connections) B.connections = new
-
- if(A.connections.get(a_to_b)) return
- if(B.connections.get(b_to_a)) return
- if(!space)
- if(A.zone == B.zone) return
-
-
- var/connection/c = new /connection(A,B)
-
- A.connections.place(c, a_to_b)
- B.connections.place(c, b_to_a)
-
- if(direct) c.mark_direct()
-
-/datum/controller/subsystem/air/proc/mark_for_update(turf/T)
- #ifdef ZASDBG
- ASSERT(isturf(T))
- #endif
- if(T.needs_air_update) return
- tiles_to_update |= T
- #ifdef ZASDBG
- T.add_overlay(mark)
- #endif
- T.needs_air_update = 1
-
-/datum/controller/subsystem/air/proc/mark_zone_update(zone/Z)
- #ifdef ZASDBG
- ASSERT(istype(Z))
- #endif
- if(Z.needs_update) return
- zones_to_update.Add(Z)
- Z.needs_update = 1
-
-/datum/controller/subsystem/air/proc/mark_edge_sleeping(connection_edge/E)
- #ifdef ZASDBG
- ASSERT(istype(E))
- #endif
- if(E.sleeping) return
- active_edges.Remove(E)
- E.sleeping = 1
-
-/datum/controller/subsystem/air/proc/mark_edge_active(connection_edge/E)
- #ifdef ZASDBG
- ASSERT(istype(E))
- #endif
- if(!E.sleeping) return
- active_edges.Add(E)
- E.sleeping = 0
-
-/datum/controller/subsystem/air/proc/equivalent_pressure(zone/A, zone/B)
- return A.air.compare(B.air)
-
-/datum/controller/subsystem/air/proc/get_edge(zone/A, zone/B)
-
- if(istype(B))
- for(var/connection_edge/zone/edge in A.edges)
- if(edge.contains_zone(B)) return edge
- var/connection_edge/edge = new/connection_edge/zone(A,B)
- edges.Add(edge)
- edge.recheck()
- return edge
- else
- for(var/connection_edge/unsimulated/edge in A.edges)
- if(has_same_air(edge.B,B)) return edge
- var/connection_edge/edge = new/connection_edge/unsimulated(A,B)
- edges.Add(edge)
- edge.recheck()
- return edge
-
-/datum/controller/subsystem/air/proc/has_same_air(turf/A, turf/B)
- if(A.oxygen != B.oxygen) return 0
- if(A.nitrogen != B.nitrogen) return 0
- if(A.phoron != B.phoron) return 0
- if(A.carbon_dioxide != B.carbon_dioxide) return 0
- if(A.temperature != B.temperature) return 0
- return 1
-
-/datum/controller/subsystem/air/proc/remove_edge(connection_edge/E)
- edges.Remove(E)
- if(!E.sleeping) active_edges.Remove(E)
diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm
index 7126588a30f..15fcd893479 100644
--- a/code/ZAS/Diagnostic.dm
+++ b/code/ZAS/Diagnostic.dm
@@ -8,12 +8,12 @@
/*
if(!check_rights(R_DEBUG)) return
- var/result = air_master.Tick()
+ var/result = SSair.Tick()
if(result)
to_chat(src, "Successfully Processed.")
else
- to_chat(src, "Failed to process! ([air_master.tick_progress])")
+ to_chat(src, "Failed to process! ([SSair.tick_progress])")
*/
/client/proc/Zone_Info(turf/T as null|turf)
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index 46871cc785e..9cbf665f83b 100644
--- a/code/ZAS/Fire.dm
+++ b/code/ZAS/Fire.dm
@@ -58,7 +58,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
fuel_objs.Cut()
if(!fire_tiles.len)
- air_master.active_fire_zones.Remove(src)
+ SSair.active_fire_zones.Remove(src)
/zone/proc/remove_liquidfuel(var/used_liquid_fuel, var/remove_fire=0)
if(!fuel_objs.len)
@@ -94,7 +94,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
return 1
fire = new(src, fl)
- air_master.active_fire_zones |= zone
+ SSair.active_fire_zones |= zone
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in src
zone.fire_tiles |= src
@@ -191,7 +191,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
set_light(3, 1, color)
firelevel = fl
- air_master.active_hotspots.Add(src)
+ SSair.active_hotspots.Add(src)
/obj/fire/proc/fire_color(var/env_temperature)
var/temperature = max(4000*sqrt(firelevel/vsc.fire_firelevel_multiplier), env_temperature)
@@ -209,7 +209,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
T.fire = null
loc = null
- air_master.active_hotspots.Remove(src)
+ SSair.active_hotspots.Remove(src)
/turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again.
diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm
index c05e708036b..a67970c63aa 100644
--- a/code/ZAS/Turf.dm
+++ b/code/ZAS/Turf.dm
@@ -41,9 +41,8 @@
if(istype(unsim, /turf/simulated))
var/turf/simulated/sim = unsim
- if(air_master.has_valid_zone(sim))
-
- air_master.connect(sim, src)
+ if(HAS_VALID_ZONE(sim))
+ SSair.connect(sim, src)
/*
Simple heuristic for determining if removing the turf from it's zone will not partition the zone (A very bad thing).
@@ -162,7 +161,7 @@
var/turf/simulated/sim = unsim
sim.open_directions |= reverse_dir[d]
- if(air_master.has_valid_zone(sim))
+ if(HAS_VALID_ZONE(sim))
//Might have assigned a zone, since this happens for each direction.
if(!zone)
@@ -195,7 +194,7 @@
if(verbose) to_world("Connecting to [sim.zone]")
#endif
- air_master.connect(src, sim)
+ SSair.connect(src, sim)
#ifdef ZASDBG
@@ -210,7 +209,7 @@
if(!postponed) postponed = list()
postponed.Add(unsim)
- if(!air_master.has_valid_zone(src)) //Still no zone, make a new one.
+ if(!HAS_VALID_ZONE(src)) //Still no zone, make a new one.
var/zone/newzone = new/zone()
newzone.add(src)
@@ -223,7 +222,7 @@
//At this point, a zone should have happened. If it hasn't, don't add more checks, fix the bug.
for(var/turf/T in postponed)
- air_master.connect(src, T)
+ SSair.connect(src, T)
/turf/proc/post_update_air_properties()
if(connections) connections.update_all()
@@ -279,7 +278,7 @@
/turf/simulated/return_air()
if(zone)
if(!zone.invalid)
- air_master.mark_zone_update(zone)
+ SSair.mark_zone_update(zone)
return zone.air
else
if(!air)
diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm
index d07a280d040..b6d012afe7d 100644
--- a/code/ZAS/Zone.dm
+++ b/code/ZAS/Zone.dm
@@ -56,7 +56,7 @@ Class Procs:
/zone/var/list/graphic_remove = list()
/zone/New()
- air_master.add_zone(src)
+ SSair.add_zone(src)
air.temperature = TCMB
air.group_multiplier = 1
air.volume = CELL_VOLUME
@@ -65,7 +65,7 @@ Class Procs:
#ifdef ZASDBG
ASSERT(!invalid)
ASSERT(istype(T))
- ASSERT(!air_master.has_valid_zone(T))
+ ASSERT(!HAS_VALID_ZONE(T))
#endif
var/datum/gas_mixture/turf_air = T.return_air()
@@ -75,7 +75,7 @@ Class Procs:
if(T.fire)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T
fire_tiles.Add(T)
- air_master.active_fire_zones |= src
+ SSair.active_fire_zones |= src
if(fuel) fuel_objs += fuel
if(air.graphic)
T.update_graphic(air.graphic)
@@ -122,11 +122,11 @@ Class Procs:
if(E.contains_zone(into))
continue //don't need to rebuild this edge
for(var/turf/T in E.connecting_turfs)
- air_master.mark_for_update(T)
+ SSair.mark_for_update(T)
/zone/proc/c_invalidate()
invalid = 1
- air_master.remove_zone(src)
+ SSair.remove_zone(src)
#ifdef ZASDBG
for(var/turf/simulated/T in contents)
T.dbg(invalid_zone)
@@ -141,7 +141,7 @@ Class Procs:
T.update_graphic(graphic_remove = air_graphic) //we need to remove the overlays so they're not doubled when the zone is rebuilt
//T.dbg(invalid_zone)
T.needs_air_update = 0 //Reset the marker so that it will be added to the list.
- air_master.mark_for_update(T)
+ SSair.mark_for_update(T)
/zone/proc/add_tile_air(datum/gas_mixture/tile_air)
//air.volume += CELL_VOLUME
@@ -152,7 +152,7 @@ Class Procs:
air.group_multiplier = contents.len+1
/zone/proc/tick()
- if(air.temperature >= PHORON_FLASHPOINT && !(src in air_master.active_fire_zones) && air.check_combustability() && contents.len)
+ if(air.temperature >= PHORON_FLASHPOINT && !(src in SSair.active_fire_zones) && air.check_combustability() && contents.len)
var/turf/T = pick(contents)
if(istype(T))
T.create_fire(vsc.fire_firelevel_multiplier)
@@ -171,7 +171,7 @@ Class Procs:
to_chat(M,name)
for(var/g in air.gas)
to_chat(M, "[gas_data.name[g]]: [air.gas[g]]")
- to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)")
+ to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]�K ([air.temperature - T0C]�C)")
to_chat(M, "O2 per N2: [(air.gas["nitrogen"] ? air.gas["oxygen"]/air.gas["nitrogen"] : "N/A")] Moles: [air.total_moles]")
to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])")
//to_chat(M, "Unsimulated: [unsimulated_contents.len]")
@@ -192,4 +192,4 @@ Class Procs:
to_chat(M, "Space Edges: [space_edges] ([space_coefficient] connections)")
//for(var/turf/T in unsimulated_contents)
- // to_chat(M, "[T] at ([T.x],[T.y])")
\ No newline at end of file
+ // to_chat(M, "[T] at ([T.x],[T.y])")
diff --git a/code/ZAS/_docs.dm b/code/ZAS/_docs.dm
index 382f1f0abbf..822c8ac7b2a 100644
--- a/code/ZAS/_docs.dm
+++ b/code/ZAS/_docs.dm
@@ -15,7 +15,7 @@ Every air tick:
Important Functions:
-air_master.mark_for_update(turf)
+SSair.mark_for_update(turf)
When stuff happens, call this. It works on everything. You basically don't need to worry about any other
functions besides CanPass().
diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm
index 5173da844c6..2c4360add9c 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/ZAS.dm b/code/__defines/ZAS.dm
index ba2b4b73e76..c8289fdc271 100644
--- a/code/__defines/ZAS.dm
+++ b/code/__defines/ZAS.dm
@@ -11,3 +11,5 @@
#define ATMOS_PASS_NO 2 // Never blocks air or zones.
#define ATMOS_PASS_DENSITY 3 // Blocks air and zones if density = TRUE, allows both if density = FALSE
#define ATMOS_PASS_PROC 4 // Call CanZASPass() using c_airblock
+
+#define HAS_VALID_ZONE(T) (T.zone && !T.zone.invalid)
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index a06ef90f7a8..f8ee1c976ea 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 126ef1ea1cf..91d036b9441 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/chemistry.dm b/code/__defines/chemistry.dm
index 63ea0e136f6..8213aa200f5 100644
--- a/code/__defines/chemistry.dm
+++ b/code/__defines/chemistry.dm
@@ -41,6 +41,7 @@
#define CE_DARKSIGHT "darksight" // Gives perfect vision in dark
#define REAGENTS_PER_SHEET 20
+#define REAGENTS_PER_ORE 20
// Attached to CE_ANTIBIOTIC
#define ANTIBIO_NORM 1
diff --git a/code/__defines/faction.dm b/code/__defines/faction.dm
index 2d975b6cbb6..766c2d51aac 100644
--- a/code/__defines/faction.dm
+++ b/code/__defines/faction.dm
@@ -105,6 +105,7 @@
#define FACTION_SWARMER "swarmer"
#define FACTION_TEPPI "teppi"
#define FACTION_TUNNELCLOWN "tunnelclown"
+#define FACTION_TURKEY "turkey"
#define FACTION_WILD_ANIMAL "wild animal"
#define FACTION_WOLFGIRL "wolfgirl"
#define FACTION_WOLFTAUR "wolftaur"
diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm
index a7dba8be88c..2a0b2ce9dea 100644
--- a/code/__defines/items_clothing.dm
+++ b/code/__defines/items_clothing.dm
@@ -40,6 +40,9 @@
#define ACCESSORY_SLOT_ARMOR_M 0x8000
#define ACCESSORY_SLOT_HELM_C 0x10000 //24 bit - higher than 0x80000 will overflow
+#define ACCESSORY_SLOT_RING 0x20000 //rings, knuckledusters
+#define ACCESSORY_SLOT_WRIST 0x40000 //wristwatches, wrist PDA maybe?
+
// Bitmasks for the /obj/item/var/flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
// WARNING: The following flags apply only to the external suit!
#define HIDEGLOVES 0x1
diff --git a/code/__defines/jobs.dm b/code/__defines/jobs.dm
index c20f5e3cd98..70e38c6876d 100644
--- a/code/__defines/jobs.dm
+++ b/code/__defines/jobs.dm
@@ -201,6 +201,7 @@
#define JOB_ALT_CONSTRUCTION_ENGINEER "Construction Engineer"
#define JOB_ALT_ENGINEERING_CONTRACTOR "Engineering Contractor"
#define JOB_ALT_COMPUTER_TECHNICIAN "Computer Technician"
+ #define JOB_ALT_SALVAGE_TECHNICIAN "Salvage Technician"
#define JOB_ATMOSPHERIC_TECHNICIAN "Atmospheric Technician"
// Atmospheric Technician alt titles
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index 313da615bde..4d80021c0ff 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 4fa21751be5..7120edd1680 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 00000000000..11ea6ada4d8
--- /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/game.dm b/code/_helpers/game.dm
index 1f76dcac9a3..80d66f555da 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -172,7 +172,7 @@
if(ismob(I))
if(!sight_check || isInSight(I, O))
- L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
+ L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects, ignore_show_messages)
if(include_mobs)
if(client_check)
var/mob/M = I
@@ -185,7 +185,7 @@
var/obj/check_obj = I
if(ignore_show_messages || check_obj.show_messages)
if(!sight_check || isInSight(I, O))
- L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
+ L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects, ignore_show_messages)
if(include_objects)
L |= I
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index 72bed469c97..80abfae6522 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -52,8 +52,9 @@ GLOBAL_LIST_INIT(custom_species_bases, new) // Species that can be used for a Cu
//Underwear
var/datum/category_collection/underwear/global_underwear = new()
- //Backpacks
-var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Messenger Bag", "Sports Bag", "Strapless Satchel") //VOREStation edit
+ //Customizables
+GLOBAL_LIST_INIT(headsetlist, list("Standard","Bowman","Earbud"))
+var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Messenger Bag", "Sports Bag", "Strapless Satchel")
var/global/list/pdachoicelist = list("Default", "Slim", "Old", "Rugged", "Holographic", "Wrist-Bound","Slider", "Vintage")
var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg)
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 520b98d39ad..725335f267a 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -343,16 +343,17 @@
//The icon var could be local in the proc, but it's a waste of resources
// to always create it and then throw it out.
/var/icon/text_tag_icons = 'icons/chattags.dmi'
-/var/list/text_tag_cache = list()
+GLOBAL_LIST_EMPTY(text_tag_cache)
+
/proc/create_text_tag(var/tagname, var/tagdesc = tagname, var/client/C = null)
if(!(C && C.prefs?.read_preference(/datum/preference/toggle/chat_tags)))
return tagdesc
- if(!text_tag_cache[tagname])
- var/icon/tag = icon(text_tag_icons, tagname)
- text_tag_cache[tagname] = tag
+ if(!GLOB.text_tag_cache[tagname])
+ var/datum/asset/spritesheet/chatassets = get_asset_datum(/datum/asset/spritesheet/chat)
+ GLOB.text_tag_cache[tagname] = chatassets.icon_tag(tagname)
if(!C.tgui_panel.is_ready() || C.tgui_panel.oldchat)
return ""
- return icon2html(text_tag_cache[tagname], C, extra_classes = "text_tag")
+ return GLOB.text_tag_cache[tagname]
/proc/create_text_tag_old(var/tagname, var/tagdesc = tagname, var/client/C = null)
if(!(C && C.prefs?.read_preference(/datum/preference/toggle/chat_tags)))
@@ -620,3 +621,8 @@
return json_decode(data)
catch
return null
+
+/// Removes all non-alphanumerics from the text, keep in mind this can lead to id conflicts
+/proc/sanitize_css_class_name(name)
+ var/static/regex/regex = new(@"[^a-zA-Z0-9]","g")
+ return replacetext(name, regex, "")
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index 057f988dcb9..8b5c5d0325b 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 .
@@ -974,7 +974,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
if(toupdate.len)
for(var/turf/simulated/T1 in toupdate)
- air_master.mark_for_update(T1)
+ SSair.mark_for_update(T1)
return copiedobjs
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 15acd142c67..80d086a298c 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 774acba147f..518c3e03c57 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 32725ec5aed..b8032273250 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 06c93c37fb1..4b062a6b5fe 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 b741f129ede..00000000000
--- 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 a1740212f0f..00000000000
--- 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 dfe8bc7234d..e92e30079b8 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 b68b4e01c04..35145d5a624 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/master_controller.dm b/code/controllers/master_controller.dm
index 857ce225f62..2955d9d7213 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -11,8 +11,6 @@ var/global/datum/controller/game_controller/master_controller //Set in world.New
var/global/controller_iteration = 0
var/global/last_tick_duration = 0
-var/global/pipe_processing_killed = 0
-
/datum/controller/game_controller
var/list/shuttle_list // For debugging and VV
diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm
index 1e5f1506ec6..e008086d04b 100644
--- a/code/controllers/subsystems/air.dm
+++ b/code/controllers/subsystems/air.dm
@@ -1,3 +1,60 @@
+/*
+Overview:
+ SSair does everything. There are tons of procs in here.
+
+Class Vars:
+ zones - All zones currently holding one or more turfs.
+ edges - All processing edges.
+
+ tiles_to_update - Tiles scheduled to update next tick.
+ zones_to_update - Zones which have had their air changed and need air archival.
+ active_hotspots - All processing fire objects.
+
+ active_zones - The number of zones which were archived last tick. Used in debug verbs.
+ next_id - The next UID to be applied to a zone. Mostly useful for debugging purposes as zones do not need UIDs to function.
+
+Class Procs:
+
+ mark_for_update(turf/T)
+ Adds the turf to the update list. When updated, update_air_properties() will be called.
+ When stuff changes that might affect airflow, call this. It's basically the only thing you need.
+
+ add_zone(zone/Z) and remove_zone(zone/Z)
+ Adds zones to the zones list. Does not mark them for update.
+
+ air_blocked(turf/A, turf/B)
+ Returns a bitflag consisting of:
+ AIR_BLOCKED - The connection between turfs is physically blocked. No air can pass.
+ ZONE_BLOCKED - There is a door between the turfs, so zones cannot cross. Air may or may not be permeable.
+
+ merge(zone/A, zone/B)
+ Called when zones have a direct connection and equivalent pressure and temperature.
+ Merges the zones to create a single zone.
+
+ connect(turf/simulated/A, turf/B)
+ Called by turf/update_air_properties(). The first argument must be simulated.
+ Creates a connection between A and B.
+
+ mark_zone_update(zone/Z)
+ Adds zone to the update list. Unlike mark_for_update(), this one is called automatically whenever
+ air is returned from a simulated turf.
+
+ equivalent_pressure(zone/A, zone/B)
+ Currently identical to A.air.compare(B.air). Returns 1 when directly connected zones are ready to be merged.
+
+ get_edge(zone/A, zone/B)
+ get_edge(zone/A, turf/B)
+ Gets a valid connection_edge between A and B, creating a new one if necessary.
+
+ has_same_air(turf/A, turf/B)
+ Used to determine if an unsimulated edge represents a specific turf.
+ Simulated edges use connection_edge/contains_zone() for the same purpose.
+ Returns 1 if A has identical gases and temperature to B.
+
+ remove_edge(connection_edge/edge)
+ Called when an edge is erased. Removes it from processing.
+*/
+
// Air update stages
#define SSAIR_TURFS 1
#define SSAIR_EDGES 2
@@ -30,8 +87,19 @@ SUBSYSTEM_DEF(air)
// This is used to tell CI WHERE the edges are.
var/list/startup_active_edge_log = list()
-/datum/controller/subsystem/air/PreInit()
- air_master = src
+ //Geometry lists
+ var/list/zones = list()
+ var/list/edges = list()
+ //Geometry updates lists
+ var/list/tiles_to_update = list()
+ var/list/zones_to_update = list()
+ var/list/active_fire_zones = list()
+ var/list/active_hotspots = list()
+ var/list/active_edges = list()
+
+ var/active_zones = 0
+ var/current_cycle = 0
+ var/next_id = 1 //Used to keep track of zone UIDs.
/datum/controller/subsystem/air/Initialize(timeofday)
report_progress("Processing Geometry...")
@@ -109,7 +177,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
log_and_message_admins("SSair: Was told to start a new run, but the previous run wasn't finished! currentrun.len=[currentrun.len], current_step=[current_step]")
resumed = TRUE
else
- current_cycle++ // Begin a new air_master cycle!
+ current_cycle++ // Begin a new SSair cycle!
current_step = SSAIR_TURFS // Start with Step 1 of course
INTERNAL_PROCESS_STEP(SSAIR_TURFS, TRUE, process_tiles_to_update, cost_turfs, SSAIR_EDGES)
@@ -118,7 +186,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
INTERNAL_PROCESS_STEP(SSAIR_HOTSPOTS, FALSE, process_active_hotspots, cost_hotspots, SSAIR_ZONES)
INTERNAL_PROCESS_STEP(SSAIR_ZONES, FALSE, process_zones_to_update, cost_zones, SSAIR_DONE)
- // Okay, we're done! Woo! Got thru a whole air_master cycle!
+ // Okay, we're done! Woo! Got thru a whole SSair cycle!
if(LAZYLEN(currentrun) || current_step != SSAIR_DONE)
log_and_message_admins("SSair: Was not able to complete a full air cycle despite reaching the end of fire(). This shouldn't happen.")
else
@@ -305,9 +373,162 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
next_fire = world.time + wait
can_fire = TRUE // Unpause
-//
-// The procs from the ZAS Air Controller are in ZAS/Controller.dm
-//
+/datum/controller/subsystem/air/proc/add_zone(zone/z)
+ zones.Add(z)
+ z.name = "Zone [next_id++]"
+ mark_zone_update(z)
+
+/datum/controller/subsystem/air/proc/remove_zone(zone/z)
+ zones.Remove(z)
+ zones_to_update.Remove(z)
+
+/datum/controller/subsystem/air/proc/air_blocked(turf/A, turf/B)
+ #ifdef ZASDBG
+ ASSERT(isturf(A))
+ ASSERT(isturf(B))
+ #endif
+ var/ablock = A.c_airblock(B)
+ if(ablock == BLOCKED)
+ return BLOCKED
+ return ablock | B.c_airblock(A)
+
+/datum/controller/subsystem/air/proc/merge(zone/A, zone/B)
+ #ifdef ZASDBG
+ ASSERT(istype(A))
+ ASSERT(istype(B))
+ ASSERT(!A.invalid)
+ ASSERT(!B.invalid)
+ ASSERT(A != B)
+ #endif
+ if(A.contents.len < B.contents.len)
+ A.c_merge(B)
+ mark_zone_update(B)
+ else
+ B.c_merge(A)
+ mark_zone_update(A)
+
+/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B)
+ #ifdef ZASDBG
+ ASSERT(istype(A))
+ ASSERT(isturf(B))
+ ASSERT(A.zone)
+ ASSERT(!A.zone.invalid)
+ //ASSERT(B.zone)
+ ASSERT(A != B)
+ #endif
+
+ var/block = SSair.air_blocked(A,B)
+ if(block & AIR_BLOCKED) return
+
+ var/direct = !(block & ZONE_BLOCKED)
+ var/space = !istype(B)
+
+ if(!space)
+ if(min(A.zone.contents.len, B.zone.contents.len) < ZONE_MIN_SIZE || (direct && (equivalent_pressure(A.zone,B.zone) || current_cycle == 0)))
+ merge(A.zone,B.zone)
+ return
+
+ var/a_to_b = get_dir(A,B)
+ var/b_to_a = get_dir(B,A)
+
+ if(!A.connections)
+ A.connections = new
+ if(!B.connections)
+ B.connections = new
+
+ if(A.connections.get(a_to_b))
+ return
+ if(B.connections.get(b_to_a))
+ return
+ if(!space)
+ if(A.zone == B.zone)
+ return
+
+
+ var/connection/c = new /connection(A,B)
+
+ A.connections.place(c, a_to_b)
+ B.connections.place(c, b_to_a)
+
+ if(direct) c.mark_direct()
+
+/datum/controller/subsystem/air/proc/mark_for_update(turf/T)
+ #ifdef ZASDBG
+ ASSERT(isturf(T))
+ #endif
+ if(T.needs_air_update)
+ return
+ tiles_to_update |= T
+ #ifdef ZASDBG
+ T.add_overlay(mark)
+ #endif
+ T.needs_air_update = 1
+
+/datum/controller/subsystem/air/proc/mark_zone_update(zone/Z)
+ #ifdef ZASDBG
+ ASSERT(istype(Z))
+ #endif
+ if(Z.needs_update)
+ return
+ zones_to_update.Add(Z)
+ Z.needs_update = 1
+
+/datum/controller/subsystem/air/proc/mark_edge_sleeping(connection_edge/E)
+ #ifdef ZASDBG
+ ASSERT(istype(E))
+ #endif
+ if(E.sleeping)
+ return
+ active_edges.Remove(E)
+ E.sleeping = 1
+
+/datum/controller/subsystem/air/proc/mark_edge_active(connection_edge/E)
+ #ifdef ZASDBG
+ ASSERT(istype(E))
+ #endif
+ if(!E.sleeping)
+ return
+ active_edges.Add(E)
+ E.sleeping = 0
+
+/datum/controller/subsystem/air/proc/equivalent_pressure(zone/A, zone/B)
+ return A.air.compare(B.air)
+
+/datum/controller/subsystem/air/proc/get_edge(zone/A, zone/B)
+ if(istype(B))
+ for(var/connection_edge/zone/edge in A.edges)
+ if(edge.contains_zone(B))
+ return edge
+ var/connection_edge/edge = new /connection_edge/zone(A,B)
+ edges.Add(edge)
+ edge.recheck()
+ return edge
+ else
+ for(var/connection_edge/unsimulated/edge in A.edges)
+ if(has_same_air(edge.B,B))
+ return edge
+ var/connection_edge/edge = new /connection_edge/unsimulated(A,B)
+ edges.Add(edge)
+ edge.recheck()
+ return edge
+
+/datum/controller/subsystem/air/proc/has_same_air(turf/A, turf/B)
+ if(A.oxygen != B.oxygen)
+ return FALSE
+ if(A.nitrogen != B.nitrogen)
+ return FALSE
+ if(A.phoron != B.phoron)
+ return FALSE
+ if(A.carbon_dioxide != B.carbon_dioxide)
+ return FALSE
+ if(A.temperature != B.temperature)
+ return FALSE
+ return TRUE
+
+/datum/controller/subsystem/air/proc/remove_edge(connection_edge/E)
+ edges.Remove(E)
+ if(!E.sleeping)
+ active_edges.Remove(E)
#undef SSAIR_TURFS
#undef SSAIR_EDGES
diff --git a/code/controllers/subsystems/speech_controller.dm b/code/controllers/subsystems/speech_controller.dm
new file mode 100644
index 00000000000..e293c89a9bb
--- /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 00000000000..1e3cce0a9af
--- /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/controllers/verbs.dm b/code/controllers/verbs.dm
index 702dbfddaeb..165748c64b1 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -89,7 +89,6 @@
//Goon PS stuff, and other yet-to-be-subsystem things.
options["LEGACY: master_controller"] = master_controller
- options["LEGACY: air_master"] = air_master
options["LEGACY: job_master"] = job_master
options["LEGACY: radio_controller"] = radio_controller
options["LEGACY: emergency_shuttle"] = emergency_shuttle
diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm
index 9bceaf27e6d..41caf5a74d9 100644
--- a/code/datums/autolathe/arms.dm
+++ b/code/datums/autolathe/arms.dm
@@ -443,7 +443,7 @@
/datum/category_item/autolathe/arms/knuckledusters
name = "knuckle dusters"
- path =/obj/item/clothing/gloves/knuckledusters
+ path =/obj/item/clothing/accessory/knuckledusters
hidden = 1
/datum/category_item/autolathe/arms/tacknife
diff --git a/code/datums/colormate.dm b/code/datums/colormate.dm
index 49c7a88542f..3bb625b7b16 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 edda32de873..3f482ea72e2 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 00000000000..618c2e97e03
--- /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/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm
index a24fa9264f8..6505817fb55 100644
--- a/code/datums/diseases/_MobProcs.dm
+++ b/code/datums/diseases/_MobProcs.dm
@@ -80,7 +80,7 @@
if(prob(15/D.permeability_mod))
return
- if(nutrition > 300 && prob(nutrition/10))
+ if(nutrition > 300 && prob(nutrition/50))
return
var/list/zone_weights = list(
@@ -177,19 +177,18 @@
if(!is_admin())
return FALSE
- var/datum/disease/D = tgui_input_list(usr, "Choose virus", "Viruses", subtypesof(/datum/disease), subtypesof(/datum/disease))
- var/mob/living/carbon/human/H = null
+ var/disease = tgui_input_list(usr, "Choose virus", "Viruses", subtypesof(/datum/disease), subtypesof(/datum/disease))
+ var/mob/living/carbon/human/H = tgui_input_list(usr, "Choose infectee", "Characters", human_mob_list)
- if(isnull(D))
+ var/datum/disease/D = new disease
+
+ if(isnull(D) || isnull(H))
return FALSE
- for(var/thing in shuffle(human_mob_list))
- H = thing
- if(H.stat == DEAD)
- continue
- if(!H.HasDisease(D))
- H.ForceContractDisease(D)
- break
+ if(!H.HasDisease(D))
+ H.ForceContractDisease(D)
- message_admins("[key_name_admin(usr)] has triggered a virus outbreak of [D.name]! Affected mob: [key_name_admin(H)]")
- log_admin("[key_name_admin(usr)] infected [key_name_admin(H)] with [D.name]")
+ message_admins("[key_name_admin(usr)] has triggered a virus outbreak of [D.name]! Affected mob: [key_name_admin(H)]")
+ log_admin("[key_name_admin(usr)] infected [key_name_admin(H)] with [D.name]")
+
+ return TRUE
diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm
index 6ae5cdbb9e0..22cdabb1dd6 100644
--- a/code/datums/diseases/_disease.dm
+++ b/code/datums/diseases/_disease.dm
@@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(diseases, subtypesof(/datum/disease))
var/cures_found = 0
for(var/C_id in cures)
- if(affected_mob.reagents.has_reagent(C_id))
+ if(affected_mob.bloodstr.has_reagent(C_id) || affected_mob.ingested.has_reagent(C_id))
cures_found++
if(needs_all_cures && cures_found < length(cures))
@@ -106,7 +106,7 @@ GLOBAL_LIST_INIT(diseases, subtypesof(/datum/disease))
if((spread_flags & SPECIAL || spread_flags & NON_CONTAGIOUS || spread_flags & BLOOD) && !force_spread)
return
- if(affected_mob.reagents.has_reagent("spaceacilin") || (affected_mob.nutrition > 300 && prob(affected_mob.nutrition/10)))
+ if(affected_mob.bloodstr.has_reagent("spaceacillin") || (affected_mob.nutrition > 300 && prob(affected_mob.nutrition/50)))
return
var/spread_range = 1
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 73ef6649988..6eda375458b 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -2,7 +2,7 @@ GLOBAL_LIST_EMPTY(archive_diseases)
GLOBAL_LIST_INIT(advance_cures, list(
"sodiumchloride", "sugar", "orangejuice",
- "spaceacilin", "glucose", "ethanol",
+ "spaceacillin", "glucose", "ethanol",
"dyloteane", "impedrezene", "hepanephrodaxon",
"gold", "silver"
))
@@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(advance_cures, list(
spread_text = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human)
+ var/s_processing = FALSE
var/list/symptoms = list()
var/id = ""
@@ -36,7 +37,7 @@ GLOBAL_LIST_INIT(advance_cures, list(
return
/datum/disease/advance/Destroy()
- if(processing)
+ if(s_processing)
for(var/datum/symptom/S in symptoms)
S.End(src)
return ..()
@@ -46,8 +47,8 @@ GLOBAL_LIST_INIT(advance_cures, list(
return FALSE
if(symptoms && length(symptoms))
- if(!processing)
- processing = TRUE
+ if(!s_processing)
+ s_processing = TRUE
for(var/datum/symptom/S in symptoms)
S.Start(src)
@@ -354,20 +355,20 @@ GLOBAL_LIST_INIT(advance_cures, list(
var/new_name = tgui_input_text(usr, "Name your new disease.", "New Name")
if(!new_name)
- return
+ return FALSE
D.AssignName(new_name)
D.Refresh()
for(var/datum/disease/advance/AD in active_diseases)
AD.Refresh()
- for(var/thing in shuffle(human_mob_list))
- H = thing
- if(H.stat == DEAD)
- continue
- if(!H.HasDisease(D))
- H.ForceContractDisease(D)
- break
+ H = tgui_input_list(usr, "Choose infectee", "Infectees", human_mob_list)
+
+ if(isnull(H))
+ return FALSE
+
+ if(!H.HasDisease(D))
+ H.ForceContractDisease(D)
var/list/name_symptoms = list()
for(var/datum/symptom/S in D.symptoms)
@@ -375,6 +376,8 @@ GLOBAL_LIST_INIT(advance_cures, list(
message_admins("[key_name_admin(usr)] has triggered a custom virus outbreak of [D.name]! It has these symptoms: [english_list(name_symptoms)]")
log_admin("[key_name_admin(usr)] infected [key_name_admin(H)] with [D.name]. It has these symptoms: [english_list(name_symptoms)]")
+ return TRUE
+
/datum/disease/advance/proc/totalStageSpeed()
var/total_stage_speed = 0
for(var/i in symptoms)
diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm
index bdf04a9fdf4..00a33e9ce64 100644
--- a/code/datums/diseases/advance/symptoms/cough.dm
+++ b/code/datums/diseases/advance/symptoms/cough.dm
@@ -10,7 +10,8 @@ Coughing
Low Level.
BONUS
- Will force the affected mob to drop small items!
+ Will force the affected mob to drop small items.
+ Small spread if not wearing a mask
//////////////////////////////////////
*/
@@ -36,4 +37,6 @@ BONUS
var/obj/item/I = M.get_active_hand()
if(I && I.w_class == ITEMSIZE_SMALL)
M.drop_item()
+ if(!M.wear_mask) // Small spread if not wearing a mask
+ A.spread(2)
return
diff --git a/code/datums/diseases/advance/symptoms/fever.dm b/code/datums/diseases/advance/symptoms/fever.dm
index a9e027da9cd..6e252e56cd9 100644
--- a/code/datums/diseases/advance/symptoms/fever.dm
+++ b/code/datums/diseases/advance/symptoms/fever.dm
@@ -35,6 +35,6 @@ Bonus
return
/datum/symptom/fever/proc/Heat(var/mob/living/M, var/datum/disease/advance/A)
- var/get_heat = (sqrt(21+A.totalTransmittable()*2))+(sqrt(20+A.totalStageSpeed()*3))
+ var/get_heat = (sqrtor0(21+A.totalTransmittable()*2))+(sqrtor0(20+A.totalStageSpeed()*3))
M.bodytemperature = min(M.bodytemperature + (get_heat * A.stage), BODYTEMP_HEAT_DAMAGE_LIMIT - 1)
return TRUE
diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm
index 28c9002c3a1..e91efab1c7c 100644
--- a/code/datums/diseases/advance/symptoms/flesh_eating.dm
+++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm
@@ -37,6 +37,6 @@ Bonus
return
/datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A)
- var/get_damage = ((sqrt(16-A.totalStealth()))*5)
+ var/get_damage = ((sqrtor0(16-A.totalStealth()))*5)
M.adjustBruteLoss(get_damage)
return 1
diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm
index 1c219598722..1138d4adba9 100644
--- a/code/datums/diseases/advance/symptoms/heal.dm
+++ b/code/datums/diseases/advance/symptoms/heal.dm
@@ -33,7 +33,7 @@ Bonus
return
/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A)
- var/get_damage = (sqrt(20+A.totalStageSpeed())*(1+rand()))
+ var/get_damage = max(0, (sqrtor0(20+A.totalStageSpeed())*(1+rand())))
M.adjustToxLoss(-get_damage)
return TRUE
@@ -144,7 +144,7 @@ Bonus
level = 5
/datum/symptom/heal/dna/Heal(var/mob/living/carbon/M, var/datum/disease/advance/A)
- var/amt_healed = (sqrt(20+A.totalStageSpeed()*(3+rand())))-(sqrt(16+A.totalStealth()*rand()))
+ var/amt_healed = max(0, (sqrtor0(20+A.totalStageSpeed()*(3+rand())))-(sqrtor0(16+A.totalStealth()*rand())))
M.adjustBrainLoss(-amt_healed)
M.radiation = max(M.radiation - 3, 0)
return TRUE
diff --git a/code/datums/diseases/advance/symptoms/macrophage.dm b/code/datums/diseases/advance/symptoms/macrophage.dm
index 5769fadaa6c..a04a3fc50fe 100644
--- a/code/datums/diseases/advance/symptoms/macrophage.dm
+++ b/code/datums/diseases/advance/symptoms/macrophage.dm
@@ -70,4 +70,4 @@ BONUS
phage.viruses += D
M.visible_message(span_danger("A strange crearure bursts out of [M]!"), span_userdanger("A slimy creature bursts forth from your flesh!"))
- addtimer(CALLBACK(phage, TYPE_PROC_REF(/mob/living/simple_mob/vore/aggressive/macrophage, dust)), 3000)
+ addtimer(CALLBACK(phage, TYPE_PROC_REF(/mob/living/simple_mob/vore/aggressive/macrophage, deathcheck)), 3000)
diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm
index 6f1f3ac9d36..8e19382f94e 100644
--- a/code/datums/diseases/advance/symptoms/sensory.dm
+++ b/code/datums/diseases/advance/symptoms/sensory.dm
@@ -30,14 +30,14 @@ Bonus
var/mob/living/M = A.affected_mob
if(A.stage >= 3)
- M.slurring = min(0, M.slurring-4)
- M.druggy = min(0, M.druggy-4)
+ M.slurring = max(0, M.slurring-4)
+ M.druggy = max(0, M.druggy-4)
M.reagents.remove_reagent("ethanol", 3)
if(A.stage >= 4)
- M.drowsyness = min(0, M.drowsyness-4)
+ M.drowsyness = max(0, M.drowsyness-4)
if(M.reagents.has_reagent("bliss"))
M.reagents.del_reagent("bliss")
- M.hallucination = min(0, M.hallucination-4)
+ M.hallucination = max(0, M.hallucination-4)
if(A.stage >= 5)
if(M.reagents.get_reagent_amount("alkysine") < 10)
M.reagents.add_reagent("alkysine", 5)
diff --git a/code/datums/diseases/advance/symptoms/shivering.dm b/code/datums/diseases/advance/symptoms/shivering.dm
index 375850ef40f..f4a3059d7c9 100644
--- a/code/datums/diseases/advance/symptoms/shivering.dm
+++ b/code/datums/diseases/advance/symptoms/shivering.dm
@@ -34,6 +34,6 @@ Bonus
return
/datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A)
- var/get_cold = (sqrt(16+A.totalStealth()*2))+(sqrt(21+A.totalResistance()*2))
+ var/get_cold = (sqrtor0(16+A.totalStealth()*2))+(sqrtor0(21+A.totalResistance()*2))
M.bodytemperature = max(M.bodytemperature - (get_cold * A.stage), BODYTEMP_COLD_DAMAGE_LIMIT + 1)
return 1
diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm
index d60baaa11a2..63f2ab00e19 100644
--- a/code/datums/diseases/advance/symptoms/sneeze.dm
+++ b/code/datums/diseases/advance/symptoms/sneeze.dm
@@ -34,8 +34,10 @@ Bonus
M.emote("sniff")
else
M.emote("sneeze")
- A.spread(5)
- if(prob(30))
+ if(!M.wear_mask) // Spread only if they're not covering their face
+ A.spread(5)
+
+ if(prob(30) && !M.wear_mask) // Same for mucus
var/obj/effect/decal/cleanable/mucus/icky = new(get_turf(M))
icky.viruses |= A.Copy()
diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm
index c6b6cf0f17e..487f466761c 100644
--- a/code/datums/diseases/cold.dm
+++ b/code/datums/diseases/cold.dm
@@ -3,8 +3,9 @@
max_stages = 3
spread_text = "Airborne"
spread_flags = AIRBORNE
- cure_text = "Rest & Spaceacilin"
- cures = list("spaceacilin")
+ cure_text = "Rest & Spaceacillin"
+ cures = list("spaceacillin", "chicken_soup")
+ needs_all_cures = FALSE
agent = "XY-rhinovirus"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/human/monkey)
permeability_mod = 0.5
diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm
index 6a30af6f859..2962f48e9b4 100644
--- a/code/datums/diseases/flu.dm
+++ b/code/datums/diseases/flu.dm
@@ -2,8 +2,9 @@
name = "The Flu"
max_stages = 3
spread_text = "Airborne"
- cure_text = "Spaceacilin"
- cures = list("spaceacilin")
+ cure_text = "Spaceacillin"
+ cures = list("spaceacillin", "chicken_soup")
+ needs_all_cures = FALSE
cure_chance = 10
agent = "H13N1 flu virion"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/human/monkey)
diff --git a/code/datums/diseases/roanoake.dm b/code/datums/diseases/roanoake.dm
index 91d476b3c74..412ff16ae75 100644
--- a/code/datums/diseases/roanoake.dm
+++ b/code/datums/diseases/roanoake.dm
@@ -4,9 +4,9 @@
stage_prob = 2
spread_text = "Blood and close contact"
spread_flags = BLOOD
- cure_text = "Spaceacilin"
+ cure_text = "Spaceacillin"
agent = "Chimera cells"
- cures = list("spaceacilin")
+ cures = list("spaceacillin")
cure_chance = 10
viable_mobtypes = list(/mob/living/carbon/human)
desc = "If left untreated, subject will become a xenochimera upon perishing."
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 00000000000..0d621f51b36
--- /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/outfits/horror_killers.dm b/code/datums/outfits/horror_killers.dm
index aa45f4e23d8..6f38c18df0e 100644
--- a/code/datums/outfits/horror_killers.dm
+++ b/code/datums/outfits/horror_killers.dm
@@ -5,7 +5,6 @@
gloves = /obj/item/clothing/gloves/black
mask = /obj/item/clothing/mask/gas/clown_hat
head = /obj/item/clothing/head/chaplain_hood
- l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/thermal/plain/monocle
suit = /obj/item/clothing/suit/storage/hooded/chaplain_hoodie
r_pocket = /obj/item/bikehorn
@@ -15,6 +14,10 @@
id_type = /obj/item/card/id/syndicate/station_access
id_pda_assignment = "Tunnel Clown!"
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset/alt
+ headset_earbud = /obj/item/radio/headset/earbud
+
/decl/hierarchy/outfit/masked_killer
name = "Masked Killer"
uniform = /obj/item/clothing/under/overalls
@@ -22,13 +25,16 @@
gloves = /obj/item/clothing/gloves/sterile/latex
mask = /obj/item/clothing/mask/surgical
head = /obj/item/clothing/head/welding
- l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/thermal/plain/monocle
suit = /obj/item/clothing/suit/storage/apron
l_pocket = /obj/item/material/knife/tacknife
r_pocket = /obj/item/surgical/scalpel
r_hand = /obj/item/material/twohanded/fireaxe
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset/alt
+ headset_earbud = /obj/item/radio/headset/earbud
+
/decl/hierarchy/outfit/masked_killer/post_equip(var/mob/living/carbon/human/H)
var/victim = get_mannequin(H.ckey)
for(var/obj/item/carried_item in H.get_equipped_items(TRUE))
@@ -39,7 +45,6 @@
uniform = /obj/item/clothing/under/suit_jacket{ starting_accessories=list(/obj/item/clothing/accessory/wcoat) }
shoes = /obj/item/clothing/shoes/black
gloves = /obj/item/clothing/gloves/black
- l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/sunglasses
l_pocket = /obj/item/melee/energy/sword
mask = /obj/item/clothing/mask/gas/clown_hat
@@ -49,6 +54,10 @@
pda_slot = slot_belt
pda_type = /obj/item/pda/heads
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset/alt
+ headset_earbud = /obj/item/radio/headset/earbud
+
/decl/hierarchy/outfit/professional/post_equip(var/mob/living/carbon/human/H)
var/obj/item/storage/secure/briefcase/sec_briefcase = new(H)
for(var/obj/item/briefcase_item in sec_briefcase)
diff --git a/code/datums/outfits/jobs/cargo.dm b/code/datums/outfits/jobs/cargo.dm
index 30955983df4..bed1308f398 100644
--- a/code/datums/outfits/jobs/cargo.dm
+++ b/code/datums/outfits/jobs/cargo.dm
@@ -1,17 +1,23 @@
/decl/hierarchy/outfit/job/cargo
- l_ear = /obj/item/radio/headset/headset_cargo
hierarchy_type = /decl/hierarchy/outfit/job/cargo
+ headset = /obj/item/radio/headset/cargo
+ headset_alt = /obj/item/radio/headset/alt/cargo
+ headset_earbud = /obj/item/radio/headset/earbud/cargo
+
/decl/hierarchy/outfit/job/cargo/qm
name = OUTFIT_JOB_NAME("Cargo")
uniform = /obj/item/clothing/under/rank/cargo
- l_ear = /obj/item/radio/headset/headset_qm //VOREStation Add
shoes = /obj/item/clothing/shoes/brown
glasses = /obj/item/clothing/glasses/sunglasses
l_hand = /obj/item/clipboard
id_type = /obj/item/card/id/cargo/head
pda_type = /obj/item/pda/quartermaster
+ headset = /obj/item/radio/headset/qm
+ headset_alt = /obj/item/radio/headset/alt/qm
+ headset_earbud = /obj/item/radio/headset/earbud/qm
+
/decl/hierarchy/outfit/job/cargo/cargo_tech
name = OUTFIT_JOB_NAME("Cargo technician")
uniform = /obj/item/clothing/under/rank/cargotech
@@ -21,10 +27,13 @@
/decl/hierarchy/outfit/job/cargo/mining
name = OUTFIT_JOB_NAME("Shaft miner")
uniform = /obj/item/clothing/under/rank/miner
- l_ear = /obj/item/radio/headset/headset_mine
backpack = /obj/item/storage/backpack/industrial
satchel_one = /obj/item/storage/backpack/satchel/eng
id_type = /obj/item/card/id/cargo/miner
pda_type = /obj/item/pda/shaftminer
backpack_contents = list(/obj/item/tool/crowbar = 1, /obj/item/storage/bag/ore = 1)
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL
+
+ headset = /obj/item/radio/headset/miner
+ headset_alt = /obj/item/radio/headset/miner
+ headset_earbud = /obj/item/radio/headset/miner
diff --git a/code/datums/outfits/jobs/civilian.dm b/code/datums/outfits/jobs/civilian.dm
index a62600a6eef..829e6f9c649 100644
--- a/code/datums/outfits/jobs/civilian.dm
+++ b/code/datums/outfits/jobs/civilian.dm
@@ -19,9 +19,12 @@
uniform = /obj/item/clothing/under/color/white
/decl/hierarchy/outfit/job/service
- l_ear = /obj/item/radio/headset/headset_service
hierarchy_type = /decl/hierarchy/outfit/job/service
+ headset = /obj/item/radio/headset/service
+ headset_alt = /obj/item/radio/headset/alt/service
+ headset_earbud = /obj/item/radio/headset/earbud/service
+
/decl/hierarchy/outfit/job/service/bartender
name = OUTFIT_JOB_NAME(JOB_BARTENDER)
uniform = /obj/item/clothing/under/rank/bartender
@@ -91,7 +94,6 @@
/decl/hierarchy/outfit/job/internal_affairs_agent
name = OUTFIT_JOB_NAME("Internal affairs agent")
- l_ear = /obj/item/radio/headset/ia
uniform = /obj/item/clothing/under/rank/internalaffairs
suit = /obj/item/clothing/suit/storage/toggle/internalaffairs
shoes = /obj/item/clothing/shoes/brown
@@ -100,6 +102,10 @@
id_type = /obj/item/card/id/civilian/internal_affairs
pda_type = /obj/item/pda/lawyer
+ headset = /obj/item/radio/headset/ia
+ headset_alt = /obj/item/radio/headset/alt/ia
+ headset_earbud = /obj/item/radio/headset/earbud/ia
+
/decl/hierarchy/outfit/job/chaplain
name = OUTFIT_JOB_NAME(JOB_CHAPLAIN)
uniform = /obj/item/clothing/under/rank/chaplain
@@ -114,10 +120,13 @@
mask = /obj/item/clothing/mask/gas/explorer
suit = /obj/item/clothing/suit/storage/hooded/explorer
gloves = /obj/item/clothing/gloves/black
- l_ear = /obj/item/radio/headset
id_slot = slot_wear_id
id_type = /obj/item/card/id/exploration //VOREStation Edit
pda_slot = slot_belt
pda_type = /obj/item/pda/cargo // Brown looks more rugged
r_pocket = /obj/item/gps/explorer
id_pda_assignment = JOB_EXPLORER
+
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset/alt
+ headset_earbud = /obj/item/radio/headset/earbud
diff --git a/code/datums/outfits/jobs/command.dm b/code/datums/outfits/jobs/command.dm
index 149020e4fed..e5a869d9ddf 100644
--- a/code/datums/outfits/jobs/command.dm
+++ b/code/datums/outfits/jobs/command.dm
@@ -2,7 +2,7 @@
name = OUTFIT_JOB_NAME(JOB_ALT_CAPTAIN) // Keep Captain for now, not JOB_SITE_MANAGER
glasses = /obj/item/clothing/glasses/sunglasses
uniform = /obj/item/clothing/under/rank/captain
- l_ear = /obj/item/radio/headset/heads/captain
+
shoes = /obj/item/clothing/shoes/brown
backpack = /obj/item/storage/backpack/captain
satchel_one = /obj/item/storage/backpack/satchel/cap
@@ -10,6 +10,10 @@
id_type = /obj/item/card/id/gold
pda_type = /obj/item/pda/captain
+ headset = /obj/item/radio/headset/heads/captain
+ headset_alt = /obj/item/radio/headset/alt/heads/captain
+ headset_earbud = /obj/item/radio/headset/earbud/heads/captain
+
/decl/hierarchy/outfit/job/captain/post_equip(var/mob/living/carbon/human/H)
..()
if(H.age>49)
@@ -26,19 +30,25 @@
/decl/hierarchy/outfit/job/hop
name = OUTFIT_JOB_NAME(JOB_HEAD_OF_PERSONNEL)
uniform = /obj/item/clothing/under/rank/head_of_personnel
- l_ear = /obj/item/radio/headset/heads/hop
shoes = /obj/item/clothing/shoes/brown
id_type = /obj/item/card/id/silver/hop
pda_type = /obj/item/pda/heads/hop
+ headset = /obj/item/radio/headset/heads/hop
+ headset_alt = /obj/item/radio/headset/alt/heads/hop
+ headset_earbud = /obj/item/radio/headset/earbud/heads/hop
+
/decl/hierarchy/outfit/job/secretary
name = OUTFIT_JOB_NAME(JOB_COMMAND_SECRETARY)
- l_ear = /obj/item/radio/headset/headset_com
shoes = /obj/item/clothing/shoes/brown
id_type = /obj/item/card/id/silver/secretary
pda_type = /obj/item/pda/heads
r_hand = /obj/item/clipboard
+ headset = /obj/item/radio/headset/headset_com
+ headset_alt = /obj/item/radio/headset/alt/headset_com
+ headset_earbud = /obj/item/radio/headset/earbud/headset_com
+
/decl/hierarchy/outfit/job/secretary/pre_equip(mob/living/carbon/human/H)
..()
if(H.gender == FEMALE)
diff --git a/code/datums/outfits/jobs/engineering.dm b/code/datums/outfits/jobs/engineering.dm
index 16de1539c3d..11c4a4cd3ce 100644
--- a/code/datums/outfits/jobs/engineering.dm
+++ b/code/datums/outfits/jobs/engineering.dm
@@ -1,7 +1,6 @@
/decl/hierarchy/outfit/job/engineering
hierarchy_type = /decl/hierarchy/outfit/job/engineering
belt = /obj/item/storage/belt/utility/full/multitool
- l_ear = /obj/item/radio/headset/headset_eng
shoes = /obj/item/clothing/shoes/boots/workboots
r_pocket = /obj/item/t_scanner
backpack = /obj/item/storage/backpack/industrial
@@ -10,15 +9,23 @@
pda_slot = slot_l_store
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL
+ headset = /obj/item/radio/headset/headset_eng
+ headset_alt = /obj/item/radio/headset/alt/headset_eng
+ headset_earbud = /obj/item/radio/headset/earbud/headset_eng
+
/decl/hierarchy/outfit/job/engineering/chief_engineer
name = OUTFIT_JOB_NAME(JOB_CHIEF_ENGINEER)
head = /obj/item/clothing/head/hardhat/white
uniform = /obj/item/clothing/under/rank/chief_engineer
- l_ear = /obj/item/radio/headset/heads/ce
+
gloves = /obj/item/clothing/gloves/black
id_type = /obj/item/card/id/engineering/head
pda_type = /obj/item/pda/heads/ce
+ headset = /obj/item/radio/headset/heads/ce
+ headset_alt = /obj/item/radio/headset/alt/heads/ce
+ headset_earbud = /obj/item/radio/headset/earbud/heads/ce
+
/decl/hierarchy/outfit/job/engineering/engineer
name = OUTFIT_JOB_NAME(JOB_ENGINEER)
head = /obj/item/clothing/head/hardhat
diff --git a/code/datums/outfits/jobs/job.dm b/code/datums/outfits/jobs/job.dm
index adfa938bf33..fdb7af5dbed 100644
--- a/code/datums/outfits/jobs/job.dm
+++ b/code/datums/outfits/jobs/job.dm
@@ -3,7 +3,6 @@
hierarchy_type = /decl/hierarchy/outfit/job
uniform = /obj/item/clothing/under/color/grey
- l_ear = /obj/item/radio/headset
shoes = /obj/item/clothing/shoes/black
id_slot = slot_wear_id
@@ -13,6 +12,10 @@
flags = OUTFIT_HAS_BACKPACK
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset/alt
+ headset_earbud = /obj/item/radio/headset/earbud
+
/decl/hierarchy/outfit/job/equip_id(mob/living/carbon/human/H, rank, assignment)
var/obj/item/card/id/C = ..()
var/datum/job/J = job_master.GetJob(rank)
diff --git a/code/datums/outfits/jobs/medical.dm b/code/datums/outfits/jobs/medical.dm
index a78636ea630..6a4d120d37d 100644
--- a/code/datums/outfits/jobs/medical.dm
+++ b/code/datums/outfits/jobs/medical.dm
@@ -1,16 +1,19 @@
/decl/hierarchy/outfit/job/medical
hierarchy_type = /decl/hierarchy/outfit/job/medical
- l_ear = /obj/item/radio/headset/headset_med
shoes = /obj/item/clothing/shoes/white
pda_type = /obj/item/pda/medical
pda_slot = slot_l_store
+
backpack = /obj/item/storage/backpack/medic
satchel_one = /obj/item/storage/backpack/satchel/med
messenger_bag = /obj/item/storage/backpack/messenger/med
+ headset = /obj/item/radio/headset/headset_med
+ headset_alt = /obj/item/radio/headset/alt/headset_med
+ headset_earbud = /obj/item/radio/headset/earbud/headset_med
+
/decl/hierarchy/outfit/job/medical/cmo
name = OUTFIT_JOB_NAME(JOB_CHIEF_MEDICAL_OFFICER)
- l_ear =/obj/item/radio/headset/heads/cmo
uniform = /obj/item/clothing/under/rank/chief_medical_officer
suit = /obj/item/clothing/suit/storage/toggle/labcoat/cmo
shoes = /obj/item/clothing/shoes/brown
@@ -19,6 +22,10 @@
id_type = /obj/item/card/id/medical/head
pda_type = /obj/item/pda/heads/cmo
+ headset = /obj/item/radio/headset/heads/cmo
+ headset_alt = /obj/item/radio/headset/alt/heads/cmo
+ headset_earbud = /obj/item/radio/headset/earbud/heads/cmo
+
/decl/hierarchy/outfit/job/medical/doctor
name = OUTFIT_JOB_NAME(JOB_MEDICAL_DOCTOR)
uniform = /obj/item/clothing/under/rank/medical
diff --git a/code/datums/outfits/jobs/science.dm b/code/datums/outfits/jobs/science.dm
index a9fe8a44370..eeeb84951d0 100644
--- a/code/datums/outfits/jobs/science.dm
+++ b/code/datums/outfits/jobs/science.dm
@@ -1,23 +1,30 @@
/decl/hierarchy/outfit/job/science
hierarchy_type = /decl/hierarchy/outfit/job/science
- l_ear = /obj/item/radio/headset/headset_sci
suit = /obj/item/clothing/suit/storage/toggle/labcoat
shoes = /obj/item/clothing/shoes/white
pda_type = /obj/item/pda/science
+
backpack = /obj/item/storage/backpack/toxins
satchel_one = /obj/item/storage/backpack/satchel/tox
messenger_bag = /obj/item/storage/backpack/messenger/tox
sports_bag = /obj/item/storage/backpack/sport/tox
+ headset = /obj/item/radio/headset/headset_sci
+ headset_alt = /obj/item/radio/headset/alt/headset_sci
+ headset_earbud = /obj/item/radio/headset/earbud/headset_sci
+
/decl/hierarchy/outfit/job/science/rd
name = OUTFIT_JOB_NAME("Research Director")
- l_ear = /obj/item/radio/headset/heads/rd
uniform = /obj/item/clothing/under/rank/research_director
shoes = /obj/item/clothing/shoes/brown
l_hand = /obj/item/clipboard
id_type = /obj/item/card/id/science/head
pda_type = /obj/item/pda/heads/rd
+ headset = /obj/item/radio/headset/heads/rd
+ headset_alt = /obj/item/radio/headset/alt/heads/rd
+ headset_earbud = /obj/item/radio/headset/earbud/heads/rd
+
/decl/hierarchy/outfit/job/science/scientist
name = OUTFIT_JOB_NAME(JOB_SCIENTIST)
uniform = /obj/item/clothing/under/rank/scientist
diff --git a/code/datums/outfits/jobs/security.dm b/code/datums/outfits/jobs/security.dm
index e73b45e06bf..595601bbcdd 100644
--- a/code/datums/outfits/jobs/security.dm
+++ b/code/datums/outfits/jobs/security.dm
@@ -1,22 +1,29 @@
/decl/hierarchy/outfit/job/security
hierarchy_type = /decl/hierarchy/outfit/job/security
glasses = /obj/item/clothing/glasses/sunglasses/sechud
- l_ear = /obj/item/radio/headset/headset_sec
gloves = /obj/item/clothing/gloves/black
shoes = /obj/item/clothing/shoes/boots/jackboots
+
backpack = /obj/item/storage/backpack/security
satchel_one = /obj/item/storage/backpack/satchel/sec
backpack_contents = list(/obj/item/handcuffs = 1)
messenger_bag = /obj/item/storage/backpack/messenger/sec
sports_bag = /obj/item/storage/backpack/sport/sec
+ headset = /obj/item/radio/headset/headset_sec
+ headset_alt = /obj/item/radio/headset/alt/headset_sec
+ headset_earbud = /obj/item/radio/headset/earbud/headset_sec
+
/decl/hierarchy/outfit/job/security/hos
name = OUTFIT_JOB_NAME(JOB_HEAD_OF_SECURITY)
- l_ear = /obj/item/radio/headset/heads/hos
uniform = /obj/item/clothing/under/rank/head_of_security
id_type = /obj/item/card/id/security/head
pda_type = /obj/item/pda/heads/hos
+ headset = /obj/item/radio/headset/heads/hos
+ headset_alt = /obj/item/radio/headset/alt/heads/hos
+ headset_earbud = /obj/item/radio/headset/earbud/heads/hos
+
/decl/hierarchy/outfit/job/security/warden
name = OUTFIT_JOB_NAME(JOB_WARDEN)
uniform = /obj/item/clothing/under/rank/warden
diff --git a/code/datums/outfits/jobs/special_vr.dm b/code/datums/outfits/jobs/special_vr.dm
index bc88232d130..0e1fcf2a70e 100644
--- a/code/datums/outfits/jobs/special_vr.dm
+++ b/code/datums/outfits/jobs/special_vr.dm
@@ -4,24 +4,30 @@
gloves = /obj/item/clothing/gloves/white
shoes = /obj/item/clothing/shoes/laceup
head = /obj/item/clothing/head/beret/centcom/officer
- l_ear = /obj/item/radio/headset/centcom
glasses = /obj/item/clothing/glasses/omnihud/all
id_type = /obj/item/card/id/centcom
pda_type = /obj/item/pda/centcom
flags = OUTFIT_EXTENDED_SURVIVAL|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/centcom
+ headset_alt = /obj/item/radio/headset/centcom
+ headset_earbud = /obj/item/radio/headset/centcom
+
/decl/hierarchy/outfit/job/emergency_responder
name = OUTFIT_JOB_NAME("Emergency Responder")
uniform = /obj/item/clothing/under/ert
shoes = /obj/item/clothing/shoes/boots/swat
gloves = /obj/item/clothing/gloves/swat
- l_ear = /obj/item/radio/headset/ert
glasses = /obj/item/clothing/glasses/sunglasses
back = /obj/item/storage/backpack/satchel
id_type = /obj/item/card/id/centcom/ERT
pda_type = /obj/item/pda/centcom
flags = OUTFIT_EXTENDED_SURVIVAL|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/ert
+ headset_alt = /obj/item/radio/headset/ert
+ headset_earbud = /obj/item/radio/headset/ert
+
/decl/hierarchy/outfit/job/emergency_responder/post_equip(var/mob/living/carbon/human/H)
..()
ert.add_antagonist(H.mind)
diff --git a/code/datums/outfits/military/military.dm b/code/datums/outfits/military/military.dm
index d3f95557945..fb47db35f5a 100644
--- a/code/datums/outfits/military/military.dm
+++ b/code/datums/outfits/military/military.dm
@@ -2,4 +2,6 @@
name = "Military Uniform"
hierarchy_type = /decl/hierarchy/outfit/military
- l_ear = /obj/item/radio/headset
\ No newline at end of file
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset
+ headset_earbud = /obj/item/radio/headset
\ No newline at end of file
diff --git a/code/datums/outfits/misc.dm b/code/datums/outfits/misc.dm
index 556bf1d0521..ef36b85038f 100644
--- a/code/datums/outfits/misc.dm
+++ b/code/datums/outfits/misc.dm
@@ -29,7 +29,6 @@
/decl/hierarchy/outfit/soviet_soldier/admiral
name = "Soviet admiral"
head = /obj/item/clothing/head/hgpiratecap
- l_ear = /obj/item/radio/headset/heads/captain
glasses = /obj/item/clothing/glasses/thermal/plain/eyepatch
suit = /obj/item/clothing/suit/hgpirate
@@ -37,10 +36,13 @@
id_type = /obj/item/card/id/centcom //station
id_pda_assignment = "Admiral"
+ headset = /obj/item/radio/headset/heads/captain
+ headset_alt = /obj/item/radio/headset/heads/captain
+ headset_earbud = /obj/item/radio/headset/heads/captain
+
/decl/hierarchy/outfit/merchant
name = "Merchant"
shoes = /obj/item/clothing/shoes/black
- l_ear = /obj/item/radio/headset
uniform = /obj/item/clothing/under/color/grey
id_slot = slot_wear_id
id_type = /obj/item/card/id/civilian //merchant
@@ -48,6 +50,10 @@
pda_type = /obj/item/pda/chef //cause I like the look
id_pda_assignment = "Merchant"
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset
+ headset_earbud = /obj/item/radio/headset
+
/decl/hierarchy/outfit/merchant/vox
name = "Merchant - Vox"
shoes = /obj/item/clothing/shoes/boots/jackboots/toeless
diff --git a/code/datums/outfits/nanotrasen.dm b/code/datums/outfits/nanotrasen.dm
index 4bf6c4f8615..3fde80dd0bb 100644
--- a/code/datums/outfits/nanotrasen.dm
+++ b/code/datums/outfits/nanotrasen.dm
@@ -3,7 +3,6 @@
uniform = /obj/item/clothing/under/rank/centcom
shoes = /obj/item/clothing/shoes/laceup
gloves = /obj/item/clothing/gloves/white
- l_ear = /obj/item/radio/headset/heads/hop
glasses = /obj/item/clothing/glasses/sunglasses
id_slot = slot_wear_id
@@ -11,6 +10,10 @@
pda_slot = slot_r_store
pda_type = /obj/item/pda/heads
+ headset = /obj/item/radio/headset/heads/hop
+ headset_alt = /obj/item/radio/headset/heads/hop
+ headset_earbud = /obj/item/radio/headset/heads/hop
+
/decl/hierarchy/outfit/nanotrasen/representative
name = "Nanotrasen representative"
belt = /obj/item/clipboard
@@ -19,14 +22,20 @@
/decl/hierarchy/outfit/nanotrasen/officer
name = "Nanotrasen officer"
head = /obj/item/clothing/head/beret/centcom/officer
- l_ear = /obj/item/radio/headset/heads/captain
belt = /obj/item/gun/energy
id_pda_assignment = "NanoTrasen Navy Officer"
+ headset = /obj/item/radio/headset/heads/captain
+ headset_alt = /obj/item/radio/headset/heads/captain
+ headset_earbud = /obj/item/radio/headset/heads/captain
+
/decl/hierarchy/outfit/nanotrasen/captain
name = "Nanotrasen captain"
uniform = /obj/item/clothing/under/rank/centcom_captain
- l_ear = /obj/item/radio/headset/heads/captain
head = /obj/item/clothing/head/beret/centcom/captain
belt = /obj/item/gun/energy
id_pda_assignment = "NanoTrasen Navy Captain"
+
+ headset = /obj/item/radio/headset/heads/captain
+ headset_alt = /obj/item/radio/headset/heads/captain
+ headset_earbud = /obj/item/radio/headset/heads/captain
diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm
index ed8e81f9928..43fe69f0f22 100644
--- a/code/datums/outfits/outfit.dm
+++ b/code/datums/outfits/outfit.dm
@@ -52,6 +52,10 @@ var/list/outfits_decls_by_type_
var/id_pda_assignment
+ var/headset = /obj/item/radio/headset
+ var/headset_alt = /obj/item/radio/headset/alt
+ var/headset_earbud = /obj/item/radio/headset/earbud
+
var/backpack = /obj/item/storage/backpack
var/satchel_one = /obj/item/storage/backpack/satchel/norm
var/satchel_two = /obj/item/storage/backpack/satchel
@@ -72,7 +76,11 @@ var/list/outfits_decls_by_type_
dd_insertObjectList(outfits_decls_, src)
/decl/hierarchy/outfit/proc/pre_equip(mob/living/carbon/human/H)
- if(flags & OUTFIT_HAS_BACKPACK)
+ switch(H.headset)
+ if(1) l_ear = headset
+ if(2) l_ear = headset_alt
+ if(3) l_ear = headset_earbud
+ if(flags && OUTFIT_HAS_BACKPACK)
switch(H.backbag)
if(2) back = backpack
if(3) back = satchel_one
diff --git a/code/datums/outfits/outfit_vr.dm b/code/datums/outfits/outfit_vr.dm
index 97281f1a560..c343a36964c 100644
--- a/code/datums/outfits/outfit_vr.dm
+++ b/code/datums/outfits/outfit_vr.dm
@@ -3,7 +3,6 @@
uniform = /obj/item/clothing/under/solgov/utility/army/urban
shoes = /obj/item/clothing/shoes/boots/jackboots
gloves = /obj/item/clothing/gloves/combat
- l_ear = /obj/item/radio/headset/centcom
r_pocket = /obj/item/ammo_magazine/m95
l_pocket = /obj/item/ammo_magazine/m95
l_hand = /obj/item/ammo_magazine/m95
@@ -15,6 +14,10 @@
suit = /obj/item/clothing/suit/armor/combat/USDF
belt = /obj/item/storage/belt/security/tactical
+ headset = /obj/item/radio/headset/centcom
+ headset_alt = /obj/item/radio/headset/centcom
+ headset_earbud = /obj/item/radio/headset/centcom
+
/decl/hierarchy/outfit/USDF/Marine/equip_id(mob/living/carbon/human/H)
var/obj/item/card/id/C = ..()
C.name = "[H.real_name]'s military ID Card"
@@ -29,7 +32,6 @@
name = "USDF officer"
head = /obj/item/clothing/head/dress/army/command
shoes = /obj/item/clothing/shoes/boots/jackboots
- l_ear = /obj/item/radio/headset/centcom
uniform = /obj/item/clothing/under/solgov/mildress/army/command
back = /obj/item/storage/backpack/satchel
belt = /obj/item/gun/projectile/revolver/consul
@@ -38,6 +40,10 @@
r_hand = /obj/item/clothing/accessory/holster/hip
l_hand = /obj/item/clothing/accessory/tie/black
+ headset = /obj/item/radio/headset/centcom
+ headset_alt = /obj/item/radio/headset/centcom
+ headset_earbud = /obj/item/radio/headset/centcom
+
/decl/hierarchy/outfit/USDF/Officer/equip_id(mob/living/carbon/human/H)
var/obj/item/card/id/C = ..()
C.name = "[H.real_name]'s military ID Card"
@@ -51,7 +57,6 @@
/decl/hierarchy/outfit/solcom/representative
name = "SolCom Representative"
shoes = /obj/item/clothing/shoes/laceup
- l_ear = /obj/item/radio/headset/centcom
uniform = /obj/item/clothing/under/suit_jacket/navy
back = /obj/item/storage/backpack/satchel
l_pocket = /obj/item/pen/blue
@@ -59,6 +64,10 @@
r_hand = /obj/item/pda/centcom
l_hand = /obj/item/clipboard
+ headset = /obj/item/radio/headset/centcom
+ headset_alt = /obj/item/radio/headset/centcom
+ headset_earbud = /obj/item/radio/headset/centcom
+
/decl/hierarchy/outfit/solcom/representative/equip_id(mob/living/carbon/human/H)
var/obj/item/card/id/C = ..()
C.name = "[H.real_name]'s SolCom ID Card"
@@ -74,7 +83,6 @@
head = /obj/item/clothing/head/helmet/combat/imperial
shoes =/obj/item/clothing/shoes/leg_guard/combat/imperial
gloves = /obj/item/clothing/gloves/arm_guard/combat/imperial
- l_ear = /obj/item/radio/headset/syndicate
uniform = /obj/item/clothing/under/imperial
mask = /obj/item/clothing/mask/gas/imperial
suit = /obj/item/clothing/suit/armor/combat/imperial
@@ -86,12 +94,15 @@
l_hand = /obj/item/shield/energy/imperial
suit_store = /obj/item/gun/energy/imperial
+ headset = /obj/item/radio/headset/syndicate
+ headset_alt = /obj/item/radio/headset/syndicate
+ headset_earbud = /obj/item/radio/headset/syndicate
+
/decl/hierarchy/outfit/imperial/officer
name = "Imperial officer"
head = /obj/item/clothing/head/helmet/combat/imperial/centurion
shoes = /obj/item/clothing/shoes/leg_guard/combat/imperial
gloves = /obj/item/clothing/gloves/arm_guard/combat/imperial
- l_ear = /obj/item/radio/headset/syndicate
uniform = /obj/item/clothing/under/imperial
mask = /obj/item/clothing/mask/gas/imperial
suit = /obj/item/clothing/suit/armor/combat/imperial/centurion
@@ -102,6 +113,10 @@
l_hand = /obj/item/shield/energy/imperial
suit_store = /obj/item/gun/energy/imperial
+ headset = /obj/item/radio/headset/syndicate
+ headset_alt = /obj/item/radio/headset/syndicate
+ headset_earbud = /obj/item/radio/headset/syndicate
+
/*
SOUTHERN CROSS OUTFITS
Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead goes in lockers. Keep this in mind if editing.
@@ -112,7 +127,6 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
name = OUTFIT_JOB_NAME(JOB_EXPLORER)
shoes = /obj/item/clothing/shoes/boots/winter/explorer
uniform = /obj/item/clothing/under/explorer
- l_ear = /obj/item/radio/headset/explorer
id_slot = slot_wear_id
pda_slot = slot_l_store
pda_type = /obj/item/pda/explorer
@@ -123,6 +137,10 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
messenger_bag = /obj/item/storage/backpack/messenger/explorer
flags = OUTFIT_HAS_BACKPACK|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/explorer
+ headset_alt = /obj/item/radio/headset/alt/explorer
+ headset_earbud = /obj/item/radio/headset/explorer
+
/decl/hierarchy/outfit/job/pilot
name = OUTFIT_JOB_NAME(JOB_PILOT)
shoes = /obj/item/clothing/shoes/black
@@ -130,7 +148,6 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
suit = /obj/item/clothing/suit/storage/toggle/bomber/pilot
gloves = /obj/item/clothing/gloves/fingerless
glasses = /obj/item/clothing/glasses/fakesunglasses/aviator
- l_ear = /obj/item/radio/headset/pilot/alt
uniform_accessories = list(/obj/item/clothing/accessory/storage/webbing/pilot1 = 1)
id_slot = slot_wear_id
pda_slot = slot_belt
@@ -139,12 +156,15 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
id_pda_assignment = JOB_PILOT
flags = OUTFIT_HAS_BACKPACK|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/pilot
+ headset_alt = /obj/item/radio/headset/alt/pilot
+ headset_earbud = /obj/item/radio/headset/alt/pilot
+
/decl/hierarchy/outfit/job/medical/sar
name = OUTFIT_JOB_NAME(JOB_FIELD_MEDIC)
uniform = /obj/item/clothing/under/utility/blue
//suit = /obj/item/clothing/suit/storage/hooded/wintercoat/medical/sar
shoes = /obj/item/clothing/shoes/boots/winter/explorer
- l_ear = /obj/item/radio/headset/sar
l_hand = /obj/item/storage/firstaid/regular
belt = /obj/item/storage/belt/medical/emt
pda_slot = slot_l_store
@@ -156,11 +176,14 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
messenger_bag = /obj/item/storage/backpack/messenger/explorer
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/sar
+ headset_alt = /obj/item/radio/headset/alt/sar
+ headset_earbud = /obj/item/radio/headset/sar
+
/decl/hierarchy/outfit/job/pathfinder
name = OUTFIT_JOB_NAME(JOB_PATHFINDER)
shoes = /obj/item/clothing/shoes/boots/winter/explorer
uniform = /obj/item/clothing/under/explorer //TODO: Uniforms.
- l_ear = /obj/item/radio/headset/pathfinder
id_slot = slot_wear_id
pda_slot = slot_l_store
pda_type = /obj/item/pda/pathfinder
@@ -168,6 +191,10 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
id_pda_assignment = JOB_PATHFINDER
flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL|OUTFIT_COMPREHENSIVE_SURVIVAL
+ headset = /obj/item/radio/headset/pathfinder
+ headset_alt = /obj/item/radio/headset/alt/pathfinder
+ headset_earbud = /obj/item/radio/headset/pathfinder
+
/decl/hierarchy/outfit/job/assistant/explorer
id_type = /obj/item/card/id/exploration
flags = OUTFIT_HAS_BACKPACK|OUTFIT_COMPREHENSIVE_SURVIVAL
diff --git a/code/datums/outfits/spec_op.dm b/code/datums/outfits/spec_op.dm
index 8fd2cb6ae4c..22da415b98b 100644
--- a/code/datums/outfits/spec_op.dm
+++ b/code/datums/outfits/spec_op.dm
@@ -2,7 +2,6 @@
name = "Special ops - Officer"
uniform = /obj/item/clothing/under/syndicate/combat
suit = /obj/item/clothing/suit/armor/swat/officer
- l_ear = /obj/item/radio/headset/ert
glasses = /obj/item/clothing/glasses/thermal/plain/eyepatch
mask = /obj/item/clothing/mask/smokable/cigarette/cigar/havana
head = /obj/item/clothing/head/beret //deathsquad
@@ -16,6 +15,10 @@
id_desc = "Special operations ID."
id_pda_assignment = "Special Operations Officer"
+ headset = /obj/item/radio/headset/ert
+ headset_alt = /obj/item/radio/headset/ert
+ headset_earbud = /obj/item/radio/headset/ert
+
/decl/hierarchy/outfit/spec_op_officer/space
name = "Special ops - Officer in space"
suit = /obj/item/clothing/suit/armor/swat //obj/item/clothing/suit/space/void/swat
@@ -29,7 +32,6 @@
uniform = /obj/item/clothing/under/ert
shoes = /obj/item/clothing/shoes/boots/swat
gloves = /obj/item/clothing/gloves/swat
- l_ear = /obj/item/radio/headset/ert
belt = /obj/item/gun/energy/gun
glasses = /obj/item/clothing/glasses/sunglasses
back = /obj/item/storage/backpack/satchel
@@ -37,6 +39,10 @@
id_slot = slot_wear_id
id_type = /obj/item/card/id/centcom/ERT
+ headset = /obj/item/radio/headset/ert
+ headset_alt = /obj/item/radio/headset/ert
+ headset_earbud = /obj/item/radio/headset/ert
+
/decl/hierarchy/outfit/death_command
name = "Spec ops - Death commando"
@@ -55,7 +61,6 @@
name = "Spec ops - Mercenary"
uniform = /obj/item/clothing/under/syndicate
shoes = /obj/item/clothing/shoes/boots/combat
- l_ear = /obj/item/radio/headset/syndicate
belt = /obj/item/storage/belt/security
glasses = /obj/item/clothing/glasses/sunglasses
gloves = /obj/item/clothing/gloves/swat
@@ -66,4 +71,8 @@
id_type = /obj/item/card/id/syndicate
id_pda_assignment = "Mercenary"
+ headset = /obj/item/radio/headset/syndicate
+ headset_alt = /obj/item/radio/headset/alt/syndicate
+ headset_earbud = /obj/item/radio/headset/earbud/syndicate
+
flags = OUTFIT_HAS_BACKPACK
diff --git a/code/datums/outfits/wizardry.dm b/code/datums/outfits/wizardry.dm
index 96836b3edc2..0cb82f75f28 100644
--- a/code/datums/outfits/wizardry.dm
+++ b/code/datums/outfits/wizardry.dm
@@ -1,7 +1,6 @@
/decl/hierarchy/outfit/wizard
uniform = /obj/item/clothing/under/color/lightpurple
shoes = /obj/item/clothing/shoes/sandal
- l_ear = /obj/item/radio/headset
r_pocket = /obj/item/teleportation_scroll
l_hand = /obj/item/staff
r_hand = /obj/item/spellbook
@@ -9,6 +8,10 @@
backpack_contents = list(/obj/item/storage/box = 1)
hierarchy_type = /decl/hierarchy/outfit/wizard
+ headset = /obj/item/radio/headset
+ headset_alt = /obj/item/radio/headset
+ headset_earbud = /obj/item/radio/headset
+
/decl/hierarchy/outfit/wizard/blue
name = "Wizard - Blue"
head = /obj/item/clothing/head/wizard
diff --git a/code/datums/supplypacks/contraband.dm b/code/datums/supplypacks/contraband.dm
index bf763f33ec5..8bc4a190fae 100644
--- a/code/datums/supplypacks/contraband.dm
+++ b/code/datums/supplypacks/contraband.dm
@@ -97,7 +97,7 @@
/obj/item/clothing/glasses/thermal/syndi,
/obj/item/ammo_magazine/m45/ap,
/obj/item/material/knife/tacknife/combatknife,
- /obj/item/multitool/hacktool
+ /obj/item/multitool/hacktool/modified
),
list( //the professional,
/obj/item/gun/projectile/silenced,
diff --git a/code/datums/supplypacks/hydroponics.dm b/code/datums/supplypacks/hydroponics.dm
index 84712a9f74b..fad0054a36f 100644
--- a/code/datums/supplypacks/hydroponics.dm
+++ b/code/datums/supplypacks/hydroponics.dm
@@ -95,6 +95,13 @@
containername = "Chicken crate"
access = access_hydroponics
+/datum/supply_pack/hydro/turkey
+ name = "Turkey crate"
+ cost = 25
+ containertype = /obj/structure/largecrate/animal/turkey
+ containername = "Turkey crate"
+ access = access_hydroponics
+
/datum/supply_pack/hydro/seeds
name = "Seeds crate"
contains = list(
diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm
index 0c099b32318..2e498c92f10 100644
--- a/code/datums/supplypacks/medical.dm
+++ b/code/datums/supplypacks/medical.dm
@@ -112,7 +112,7 @@
contains = list(
/obj/item/storage/belt/medical = 3,
/obj/item/clothing/glasses/hud/health = 3,
- /obj/item/radio/headset/headset_med/alt = 3,
+ /obj/item/radio/headset/alt/headset_med = 3,
/obj/item/clothing/suit/storage/hooded/wintercoat/medical = 3
)
cost = 10
diff --git a/code/datums/supplypacks/misc.dm b/code/datums/supplypacks/misc.dm
index d03ab2b6207..bc1690c7d8c 100644
--- a/code/datums/supplypacks/misc.dm
+++ b/code/datums/supplypacks/misc.dm
@@ -80,6 +80,7 @@
/obj/item/toy/plushie/slimeplushie,
/obj/item/toy/plushie/box,
/obj/item/toy/plushie/borgplushie,
+ /obj/item/toy/plushie/borgplushie/drake/eng,
/obj/item/toy/plushie/borgplushie/medihound,
/obj/item/toy/plushie/borgplushie/scrubpuppy,
/obj/item/toy/plushie/foxbear,
diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm
index 1404b06e420..1f2cf06f89e 100644
--- a/code/datums/supplypacks/security.dm
+++ b/code/datums/supplypacks/security.dm
@@ -444,7 +444,7 @@
contains = list(
/obj/item/storage/belt/security = 3,
/obj/item/clothing/glasses/sunglasses/sechud = 3,
- /obj/item/radio/headset/headset_sec/alt = 3,
+ /obj/item/radio/headset/alt/headset_sec = 3,
/obj/item/clothing/suit/storage/hooded/wintercoat/security = 3,
/obj/item/clothing/glasses/sunglasses/sechud/tactical_sec_vis = 3
)
diff --git a/code/datums/supplypacks/supply.dm b/code/datums/supplypacks/supply.dm
index 0629a55d8ed..b8bcd3f7ba5 100644
--- a/code/datums/supplypacks/supply.dm
+++ b/code/datums/supplypacks/supply.dm
@@ -118,7 +118,7 @@
/obj/item/storage/backpack/industrial,
/obj/item/storage/backpack/satchel/eng,
/obj/item/clothing/suit/storage/hooded/wintercoat/miner,
- /obj/item/radio/headset/headset_cargo,
+ /obj/item/radio/headset/miner,
/obj/item/clothing/under/rank/miner,
/obj/item/clothing/gloves/black,
/obj/item/clothing/shoes/black,
@@ -175,7 +175,7 @@
/obj/item/material/knife/tacknife/survival,
/obj/item/material/knife/machete,
/obj/item/clothing/accessory/holster/machete,
- /obj/item/clothing/gloves/watch/survival
+ /obj/item/clothing/accessory/watch/survival
)
cost=25
containertype = /obj/structure/closet/crate/secure/xion
@@ -187,7 +187,7 @@
contains = list (
/obj/item/storage/backpack/parachute,
/obj/item/radio/headset/pilot,
- /obj/item/radio/headset/pilot/alt,
+ /obj/item/radio/headset/alt/pilot,
/obj/item/clothing/mask/gas/half,
/obj/item/flashlight/glowstick,
/obj/item/stack/marker_beacon/thirty,
@@ -200,7 +200,7 @@
/obj/item/clothing/head/pilot_vr,
/obj/item/clothing/under/rank/pilot1,
/obj/item/gun/energy/gun/protector/pilotgun/locked,
- /obj/item/clothing/gloves/watch/survival
+ /obj/item/clothing/accessory/watch/survival
)
cost=20
containertype = /obj/structure/closet/crate/secure/xion
@@ -236,7 +236,7 @@
/obj/item/clothing/accessory/holster/machete,
/obj/item/storage/box/explorerkeys,
/obj/item/mapping_unit,
- /obj/item/clothing/gloves/watch/survival
+ /obj/item/clothing/accessory/watch/survival
)
cost = 75
containertype = /obj/structure/closet/crate/secure/xion
diff --git a/code/datums/uplink/stealthy_weapons.dm b/code/datums/uplink/stealthy_weapons.dm
index 29c80092113..39cc3bf9ae2 100644
--- a/code/datums/uplink/stealthy_weapons.dm
+++ b/code/datums/uplink/stealthy_weapons.dm
@@ -58,12 +58,6 @@
item_cost = 20
path = /obj/item/pen/blade/fountain
-/datum/uplink_item/item/stealthy_weapons/angrybuzzer
- name = "Morphium Shock Ring"
- desc = "An enigmatic ring used to create powerful electric shocks when punching. Can be used as a brute-force method of defibrillation."
- item_cost = 40
- path = /obj/item/clothing/gloves/ring/buzzer
-
/datum/uplink_item/item/stealthy_weapons/huntingtrap
name = "Camonetted Beartraps"
desc = "A box of unique beartraps which will partially cloak when deployed, allowing for more effective hunting."
diff --git a/code/datums/verb_callbacks.dm b/code/datums/verb_callbacks.dm
new file mode 100644
index 00000000000..77f817017d2
--- /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 4e71b946309..03ffdb8ecbf 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 75855cec648..5a7f00f4a6b 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 7a0515abfc7..47b29898af2 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 614eb7e981c..0d0c0a9bbdd 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 b8a18ac6fc0..f5d65b8ec2e 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 6883220bac6..27c09411449 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 47add9a0ea6..9b5c9968a62 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 8f32c6cc5b3..1d1e90fb355 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/assistant.dm b/code/game/jobs/job/assistant.dm
index 6aa97533523..e3eca95cd38 100644
--- a/code/game/jobs/job/assistant.dm
+++ b/code/game/jobs/job/assistant.dm
@@ -57,3 +57,118 @@
title_blurb = "A " + JOB_ALT_RESIDENT + " is an individual who resides on the station, frequently in a different part of the station than what is seen. \
They are considered to be part of the crew for most purposes, but have no real authority."
title_outfit = /decl/hierarchy/outfit/job/assistant/resident
+
+//////////////////////////////////
+// Intern
+//////////////////////////////////
+
+/datum/job/intern
+ title = JOB_INTERN
+ flag = INTERN
+ departments = list(DEPARTMENT_CIVILIAN)
+ department_flag = ENGSEC // Ran out of bits
+ faction = FACTION_STATION
+ total_positions = -1
+ spawn_positions = -1
+ supervisors = "the staff from the department you're interning in"
+ selection_color = "#555555"
+ economic_modifier = 2
+ access = list() //See /datum/job/intern/get_access()
+ minimal_access = list() //See /datum/job/intern/get_access()
+ outfit_type = /decl/hierarchy/outfit/job/assistant/intern
+ alt_titles = list(JOB_ALT_APPRENTICE_ENGINEER = /datum/alt_title/intern_eng,
+ JOB_ALT_MEDICAL_INTERN = /datum/alt_title/intern_med,
+ JOB_ALT_RESEARCH_INTERN = /datum/alt_title/intern_sci,
+ JOB_ALT_SECURITY_CADET = /datum/alt_title/intern_sec,
+ JOB_ALT_JR_CARGO_TECH = /datum/alt_title/intern_crg,
+ JOB_ALT_SERVER = /datum/alt_title/server,
+ JOB_ALT_ASSISTANT = /datum/alt_title/assistant)
+ job_description = "An " + JOB_INTERN + " does whatever is requested of them, often doing so in process of learning \
+ another job. Though they are part of the crew, they have no real authority."
+ timeoff_factor = 0 // Interns, noh
+ requestable = FALSE
+
+/datum/alt_title/intern_eng
+ title = JOB_ALT_APPRENTICE_ENGINEER
+ title_blurb = "An " + JOB_ALT_APPRENTICE_ENGINEER + " attempts to provide whatever the Engineering department needs. They are not proper Engineers, and are \
+ often in training to become an Engineer. An " + JOB_ALT_APPRENTICE_ENGINEER + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/engineer
+
+/datum/alt_title/intern_med
+ title = JOB_ALT_MEDICAL_INTERN
+ title_blurb = "A " + JOB_ALT_MEDICAL_INTERN + " attempts to provide whatever the Medical department needs. They are not proper Doctors, and are \
+ often in training to become a Doctor. A " + JOB_ALT_MEDICAL_INTERN + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/medic
+
+/datum/alt_title/intern_sci
+ title = JOB_ALT_RESEARCH_INTERN
+ title_blurb = "A " + JOB_ALT_RESEARCH_INTERN + " attempts to provide whatever the Research department needs. They are not proper " + JOB_SCIENTIST + "s, and are \
+ often in training to become a " + JOB_SCIENTIST + ". A " + JOB_ALT_RESEARCH_INTERN + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/scientist
+
+/datum/alt_title/intern_sec
+ title = JOB_ALT_SECURITY_CADET
+ title_blurb = "A " + JOB_ALT_SECURITY_CADET + " attempts to provide whatever the Security department needs. They are not proper Officers, and are \
+ often in training to become an Officer. A " + JOB_ALT_SECURITY_CADET + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/officer
+
+/datum/alt_title/intern_crg
+ title = JOB_ALT_JR_CARGO_TECH
+ title_blurb = "A " + JOB_ALT_JR_CARGO_TECH + " attempts to provide whatever the Cargo department needs. They are not proper Cargo Technicians, and are \
+ often in training to become a " + JOB_CARGO_TECHNICIAN + ". A " + JOB_ALT_JR_CARGO_TECH + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/cargo
+/*
+/datum/alt_title/intern_exp
+ title = "Jr. " + JOB_EXPLORER + ""
+ title_blurb = "A Jr. " + JOB_EXPLORER + " attempts to provide whatever the Exploration department needs. They are not proper " + JOB_EXPLORER + "s, and are \
+ often in training to become an " + JOB_EXPLORER + ". A Jr. " + JOB_EXPLORER + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/explorer
+*/
+/datum/alt_title/server
+ title = JOB_ALT_SERVER
+ title_blurb = "A " + JOB_ALT_SERVER + " helps out kitchen and diner staff with various tasks, primarily food delivery. A " + JOB_ALT_SERVER + " has no real authority."
+ title_outfit = /decl/hierarchy/outfit/job/service/server
+
+/datum/alt_title/assistant
+ title = JOB_ALT_ASSISTANT
+ title_blurb = "An " + JOB_ALT_ASSISTANT + " helps out wherever they might be needed. They have no authority, but can volunteer to help if help is needed."
+ title_outfit = /decl/hierarchy/outfit/job/service/server
+
+/datum/job/intern/New()
+ ..()
+ if(config)
+ total_positions = CONFIG_GET(number/limit_interns)
+ spawn_positions = CONFIG_GET(number/limit_interns)
+
+/datum/job/intern/get_access()
+ if(CONFIG_GET(flag/assistant_maint))
+ return list(access_maint_tunnels)
+ else
+ return list()
+
+//////////////////////////////////
+// Visitor
+//////////////////////////////////
+
+/datum/job/assistant // Visitor
+ title = JOB_ALT_VISITOR
+ supervisors = "nobody! You don't work here"
+ job_description = "A " + JOB_ALT_VISITOR + " is just there to visit the place. They have no real authority or responsibility."
+ timeoff_factor = 0
+ requestable = FALSE
+ alt_titles = list("Guest" = /datum/alt_title/guest, "Traveler" = /datum/alt_title/traveler)
+
+/datum/job/assistant/New()
+ ..()
+ if(config)
+ total_positions = CONFIG_GET(number/limit_visitors)
+ spawn_positions = CONFIG_GET(number/limit_visitors)
+
+/datum/job/assistant/get_access()
+ return list()
+
+/datum/alt_title/guest
+ title = "Guest"
+
+/datum/alt_title/traveler
+ title = "Traveler"
diff --git a/code/game/jobs/job/assistant_vr.dm b/code/game/jobs/job/assistant_vr.dm
deleted file mode 100644
index c28d801acbd..00000000000
--- a/code/game/jobs/job/assistant_vr.dm
+++ /dev/null
@@ -1,115 +0,0 @@
-//////////////////////////////////
-// Intern
-//////////////////////////////////
-
-/datum/job/intern
- title = JOB_INTERN
- flag = INTERN
- departments = list(DEPARTMENT_CIVILIAN)
- department_flag = ENGSEC // Ran out of bits
- faction = FACTION_STATION
- total_positions = -1
- spawn_positions = -1
- supervisors = "the staff from the department you're interning in"
- selection_color = "#555555"
- economic_modifier = 2
- access = list() //See /datum/job/intern/get_access()
- minimal_access = list() //See /datum/job/intern/get_access()
- outfit_type = /decl/hierarchy/outfit/job/assistant/intern
- alt_titles = list(JOB_ALT_APPRENTICE_ENGINEER = /datum/alt_title/intern_eng,
- JOB_ALT_MEDICAL_INTERN = /datum/alt_title/intern_med,
- JOB_ALT_RESEARCH_INTERN = /datum/alt_title/intern_sci,
- JOB_ALT_SECURITY_CADET = /datum/alt_title/intern_sec,
- JOB_ALT_JR_CARGO_TECH = /datum/alt_title/intern_crg,
- JOB_ALT_SERVER = /datum/alt_title/server,
- JOB_ALT_ASSISTANT = /datum/alt_title/assistant)
- job_description = "An " + JOB_INTERN + " does whatever is requested of them, often doing so in process of learning \
- another job. Though they are part of the crew, they have no real authority."
- timeoff_factor = 0 // Interns, noh
- requestable = FALSE
-
-/datum/alt_title/intern_eng
- title = JOB_ALT_APPRENTICE_ENGINEER
- title_blurb = "An " + JOB_ALT_APPRENTICE_ENGINEER + " attempts to provide whatever the Engineering department needs. They are not proper Engineers, and are \
- often in training to become an Engineer. An " + JOB_ALT_APPRENTICE_ENGINEER + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/engineer
-
-/datum/alt_title/intern_med
- title = JOB_ALT_MEDICAL_INTERN
- title_blurb = "A " + JOB_ALT_MEDICAL_INTERN + " attempts to provide whatever the Medical department needs. They are not proper Doctors, and are \
- often in training to become a Doctor. A " + JOB_ALT_MEDICAL_INTERN + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/medic
-
-/datum/alt_title/intern_sci
- title = JOB_ALT_RESEARCH_INTERN
- title_blurb = "A " + JOB_ALT_RESEARCH_INTERN + " attempts to provide whatever the Research department needs. They are not proper " + JOB_SCIENTIST + "s, and are \
- often in training to become a " + JOB_SCIENTIST + ". A " + JOB_ALT_RESEARCH_INTERN + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/scientist
-
-/datum/alt_title/intern_sec
- title = JOB_ALT_SECURITY_CADET
- title_blurb = "A " + JOB_ALT_SECURITY_CADET + " attempts to provide whatever the Security department needs. They are not proper Officers, and are \
- often in training to become an Officer. A " + JOB_ALT_SECURITY_CADET + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/officer
-
-/datum/alt_title/intern_crg
- title = JOB_ALT_JR_CARGO_TECH
- title_blurb = "A " + JOB_ALT_JR_CARGO_TECH + " attempts to provide whatever the Cargo department needs. They are not proper Cargo Technicians, and are \
- often in training to become a " + JOB_CARGO_TECHNICIAN + ". A " + JOB_ALT_JR_CARGO_TECH + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/cargo
-/*
-/datum/alt_title/intern_exp
- title = "Jr. " + JOB_EXPLORER + ""
- title_blurb = "A Jr. " + JOB_EXPLORER + " attempts to provide whatever the Exploration department needs. They are not proper " + JOB_EXPLORER + "s, and are \
- often in training to become an " + JOB_EXPLORER + ". A Jr. " + JOB_EXPLORER + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/assistant/explorer
-*/
-/datum/alt_title/server
- title = JOB_ALT_SERVER
- title_blurb = "A " + JOB_ALT_SERVER + " helps out kitchen and diner staff with various tasks, primarily food delivery. A " + JOB_ALT_SERVER + " has no real authority."
- title_outfit = /decl/hierarchy/outfit/job/service/server
-
-/datum/alt_title/assistant
- title = JOB_ALT_ASSISTANT
- title_blurb = "An " + JOB_ALT_ASSISTANT + " helps out wherever they might be needed. They have no authority, but can volunteer to help if help is needed."
- title_outfit = /decl/hierarchy/outfit/job/service/server
-
-/datum/job/intern/New()
- ..()
- if(config)
- total_positions = CONFIG_GET(number/limit_interns)
- spawn_positions = CONFIG_GET(number/limit_interns)
-
-/datum/job/intern/get_access()
- if(CONFIG_GET(flag/assistant_maint))
- return list(access_maint_tunnels)
- else
- return list()
-
-
-//////////////////////////////////
-// Visitor
-//////////////////////////////////
-
-/datum/job/assistant // Visitor
- title = JOB_ALT_VISITOR
- supervisors = "nobody! You don't work here"
- job_description = "A " + JOB_ALT_VISITOR + " is just there to visit the place. They have no real authority or responsibility."
- timeoff_factor = 0
- requestable = FALSE
- alt_titles = list("Guest" = /datum/alt_title/guest, "Traveler" = /datum/alt_title/traveler)
-
-/datum/job/assistant/New()
- ..()
- if(config)
- total_positions = CONFIG_GET(number/limit_visitors)
- spawn_positions = CONFIG_GET(number/limit_visitors)
-
-/datum/job/assistant/get_access()
- return list()
-
-/datum/alt_title/guest
- title = "Guest"
-
-/datum/alt_title/traveler
- title = "Traveler"
diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm
index 6c16ac43760..767ac329236 100644
--- a/code/game/jobs/job/captain.dm
+++ b/code/game/jobs/job/captain.dm
@@ -28,11 +28,16 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
ideal_age_by_species = list(SPECIES_HUMAN_VATBORN = 55) /// Vatborn live shorter, no other race eligible for captain besides human/skrell
banned_job_species = list(SPECIES_UNATHI, SPECIES_TAJ, SPECIES_DIONA, SPECIES_PROMETHEAN, SPECIES_ZADDAT, "mechanical", "digital")
+ disallow_jobhop = TRUE
+ pto_type = PTO_CIVILIAN
+ dept_time_required = 80 //Pending something more complicated
+
outfit_type = /decl/hierarchy/outfit/job/captain
job_description = "The " + JOB_SITE_MANAGER + " manages the other Command Staff, and through them the rest of the station. Though they have access to everything, \
they do not understand everything, and are expected to delegate tasks to the appropriate crew member. The " + JOB_SITE_MANAGER + " is expected to \
have an understanding of Standard Operating Procedure, and is subject to it, and legal action, in the same way as every other crew member."
- alt_titles = list(JOB_ALT_OVERSEER= /datum/alt_title/overseer)
+ alt_titles = list(JOB_ALT_OVERSEER= /datum/alt_title/overseer, JOB_ALT_FACILITY_DIRECTOR = /datum/alt_title/facility_director, JOB_ALT_CHIEF_SUPERVISOR = /datum/alt_title/chief_supervisor,
+ JOB_ALT_CAPTAIN = /datum/alt_title/captain)
/*
@@ -45,11 +50,22 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
/datum/job/captain/get_access()
return get_all_station_access().Copy()
+/datum/job/captain/get_request_reasons()
+ return list("Training crew", "Assembling expedition team")
// Captain Alt Titles
/datum/alt_title/overseer
title = JOB_ALT_OVERSEER
+/datum/alt_title/facility_director
+ title = JOB_ALT_FACILITY_DIRECTOR
+
+/datum/alt_title/chief_supervisor
+ title = JOB_ALT_CHIEF_SUPERVISOR
+
+/datum/alt_title/captain
+ title = JOB_ALT_CAPTAIN
+
//////////////////////////////////
// Head of Personnel
//////////////////////////////////
@@ -75,29 +91,42 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
ideal_age_by_species = list(SPECIES_UNATHI = 140, SPECIES_TESHARI = 27, "mechanical" = 20, SPECIES_HUMAN_VATBORN = 20)
banned_job_species = list(SPECIES_PROMETHEAN, SPECIES_ZADDAT, "digital", SPECIES_DIONA)
+ disallow_jobhop = TRUE
+ pto_type = PTO_CIVILIAN
+ departments = list(DEPARTMENT_COMMAND, DEPARTMENT_CIVILIAN)
+ departments_managed = list(DEPARTMENT_CIVILIAN, DEPARTMENT_CARGO, DEPARTMENT_PLANET)
+ dept_time_required = 60
+
outfit_type = /decl/hierarchy/outfit/job/hop
job_description = "The " + JOB_HEAD_OF_PERSONNEL + " manages the Service department, the Exploration team, and most other civilians. They also \
manage the Supply department, through the " + JOB_QUARTERMASTER + ". In addition, the " + JOB_HEAD_OF_PERSONNEL + " oversees the personal accounts \
of the crew, including their money and access. If necessary, the " + JOB_HEAD_OF_PERSONNEL + " is first in line to assume Acting Command."
- alt_titles = list(JOB_ALT_CREW_RESOURCE_OFFICER = /datum/alt_title/cro)
- access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
- access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
- access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
- access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
- access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_keycard_auth, access_gateway)
- minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
- access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
- access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
- access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
- access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_keycard_auth, access_gateway)
+ access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers, access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads, access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer, access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station, access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
+ minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue, access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station, access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
+
+ alt_titles = list(JOB_ALT_CREW_RESOURCE_OFFICER = /datum/alt_title/cro, JOB_ALT_DEPUTY_MANAGER = /datum/alt_title/deputy_manager, JOB_ALT_STAFF_MANAGER = /datum/alt_title/staff_manager,
+ JOB_ALT_FACILITY_STEWARD = /datum/alt_title/facility_steward, JOB_ALT_FIRST_MATE = /datum/alt_title/first_mate)
+
+/datum/job/hop/get_request_reasons()
+ return list("ID modification", "Training crew", "Assembling expedition team")
// HOP Alt Titles
/datum/alt_title/cro
title = JOB_ALT_CREW_RESOURCE_OFFICER
+/datum/alt_title/deputy_manager
+ title = JOB_ALT_DEPUTY_MANAGER
+
+/datum/alt_title/staff_manager
+ title = JOB_ALT_STAFF_MANAGER
+
+/datum/alt_title/facility_steward
+ title = JOB_ALT_FACILITY_STEWARD
+
+/datum/alt_title/first_mate
+ title = JOB_ALT_FIRST_MATE
+
//////////////////////////////////
// Command Secretary
//////////////////////////////////
@@ -116,9 +145,29 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
minimal_player_age = 5
economic_modifier = 7
+ disallow_jobhop = TRUE
+ pto_type = PTO_CIVILIAN
+ alt_titles = list(JOB_ALT_COMMAND_LIAISON = /datum/alt_title/command_liaison, JOB_ALT_COMMAND_ASSISTANT = /datum/alt_title/command_assistant, JOB_ALT_COMMAND_INTERN = /datum/alt_title/command_intern,
+ JOB_ALT_BRIDGE_SECRETARY = /datum/alt_title/bridge_secretary, JOB_ALT_BRIDGE_ASSISTANT = /datum/alt_title/bridge_assistant)
+
access = list(access_heads, access_keycard_auth)
minimal_access = list(access_heads, access_keycard_auth)
outfit_type = /decl/hierarchy/outfit/job/secretary
job_description = "A " + JOB_COMMAND_SECRETARY + " handles paperwork duty for the Heads of Staff, so they can better focus on managing their departments. \
They are not Heads of Staff, and have no real authority."
+
+/datum/alt_title/command_liaison
+ title = JOB_ALT_COMMAND_LIAISON
+
+/datum/alt_title/command_assistant
+ title = JOB_ALT_COMMAND_ASSISTANT
+
+/datum/alt_title/command_intern
+ title = JOB_ALT_COMMAND_INTERN
+
+/datum/alt_title/bridge_secretary
+ title = JOB_ALT_BRIDGE_SECRETARY
+
+/datum/alt_title/bridge_assistant
+ title = JOB_ALT_BRIDGE_ASSISTANT
diff --git a/code/game/jobs/job/captain_vr.dm b/code/game/jobs/job/captain_vr.dm
deleted file mode 100644
index c127d8dfd43..00000000000
--- a/code/game/jobs/job/captain_vr.dm
+++ /dev/null
@@ -1,78 +0,0 @@
-/datum/job/captain
- disallow_jobhop = TRUE
- pto_type = PTO_CIVILIAN
- dept_time_required = 80 //Pending something more complicated
- alt_titles = list(JOB_ALT_OVERSEER= /datum/alt_title/overseer, JOB_ALT_FACILITY_DIRECTOR = /datum/alt_title/facility_director, JOB_ALT_CHIEF_SUPERVISOR = /datum/alt_title/chief_supervisor,
- JOB_ALT_CAPTAIN = /datum/alt_title/captain)
-
-/datum/alt_title/facility_director
- title = JOB_ALT_FACILITY_DIRECTOR
-
-/datum/alt_title/chief_supervisor
- title = JOB_ALT_CHIEF_SUPERVISOR
-
-/datum/alt_title/captain
- title = JOB_ALT_CAPTAIN
-
-/datum/job/captain/get_request_reasons()
- return list("Training crew", "Assembling expedition team")
-
-/datum/job/hop
- disallow_jobhop = TRUE
- pto_type = PTO_CIVILIAN
- departments = list(DEPARTMENT_COMMAND, DEPARTMENT_CIVILIAN)
- departments_managed = list(DEPARTMENT_CIVILIAN, DEPARTMENT_CARGO, DEPARTMENT_PLANET)
- dept_time_required = 60
-
- alt_titles = list(JOB_ALT_CREW_RESOURCE_OFFICER = /datum/alt_title/cro, JOB_ALT_DEPUTY_MANAGER = /datum/alt_title/deputy_manager, JOB_ALT_STAFF_MANAGER = /datum/alt_title/staff_manager,
- JOB_ALT_FACILITY_STEWARD = /datum/alt_title/facility_steward, JOB_ALT_FIRST_MATE = /datum/alt_title/first_mate)
-
- access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
- access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
- access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
- access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
- access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
- minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
- access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
- access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
- access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
- access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway, access_entertainment)
-
-/datum/alt_title/deputy_manager
- title = JOB_ALT_DEPUTY_MANAGER
-
-/datum/alt_title/staff_manager
- title = JOB_ALT_STAFF_MANAGER
-
-/datum/alt_title/facility_steward
- title = JOB_ALT_FACILITY_STEWARD
-
-/datum/alt_title/first_mate
- title = JOB_ALT_FIRST_MATE
-
-/datum/job/hop/get_request_reasons()
- return list("ID modification", "Training crew", "Assembling expedition team")
-
-
-/datum/job/secretary
- disallow_jobhop = TRUE
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_COMMAND_LIAISON = /datum/alt_title/command_liaison, JOB_ALT_COMMAND_ASSISTANT = /datum/alt_title/command_assistant, JOB_ALT_COMMAND_INTERN = /datum/alt_title/command_intern,
- JOB_ALT_BRIDGE_SECRETARY = /datum/alt_title/bridge_secretary, JOB_ALT_BRIDGE_ASSISTANT = /datum/alt_title/bridge_assistant)
-
-/datum/alt_title/command_liaison
- title = JOB_ALT_COMMAND_LIAISON
-
-/datum/alt_title/command_assistant
- title = JOB_ALT_COMMAND_ASSISTANT
-
-/datum/alt_title/command_intern
- title = JOB_ALT_COMMAND_INTERN
-
-/datum/alt_title/bridge_secretary
- title = JOB_ALT_BRIDGE_SECRETARY
-
-/datum/alt_title/bridge_assistant
- title = JOB_ALT_BRIDGE_ASSISTANT
diff --git a/code/game/jobs/job/cargo.dm b/code/game/jobs/job/cargo.dm
new file mode 100644
index 00000000000..ad56749de66
--- /dev/null
+++ b/code/game/jobs/job/cargo.dm
@@ -0,0 +1,122 @@
+//Cargo
+//////////////////////////////////
+// Quartermaster
+//////////////////////////////////
+/datum/job/qm
+ title = JOB_QUARTERMASTER
+ flag = QUARTERMASTER
+ departments = list(DEPARTMENT_CARGO)
+ sorting_order = 1 // QM is above the cargo techs, but below the HoP.
+ departments_managed = list(DEPARTMENT_CARGO)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 1
+ spawn_positions = 1
+ pto_type = PTO_CARGO
+ supervisors = "the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#9b633e"
+ economic_modifier = 5
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station, access_RC_announce)
+ minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station, access_RC_announce)
+ banned_job_species = list("digital", SPECIES_PROMETHEAN)
+
+ ideal_character_age = 40
+ dept_time_required = 20
+
+ outfit_type = /decl/hierarchy/outfit/job/cargo/qm
+ job_description = "The " + JOB_QUARTERMASTER + " manages the Supply department, checking cargo orders and ensuring supplies get to where they are needed."
+ alt_titles = list(JOB_ALT_SUPPLY_CHIEF = /datum/alt_title/supply_chief, JOB_ALT_LOGISTICS_MANAGER = /datum/alt_title/logistics_manager, JOB_ALT_CARGO_SUPERVISOR = /datum/alt_title/cargo_supervisor)
+
+/datum/job/qm/get_request_reasons()
+ return list("Training crew")
+
+// Quartermaster Alt Titles
+/datum/alt_title/supply_chief
+ title = JOB_ALT_SUPPLY_CHIEF
+
+/datum/alt_title/logistics_manager
+ title = JOB_ALT_LOGISTICS_MANAGER
+
+/datum/alt_title/cargo_supervisor
+ title = JOB_ALT_CARGO_SUPERVISOR
+
+//////////////////////////////////
+// Cargo Tech
+//////////////////////////////////
+/datum/job/cargo_tech
+ title = JOB_CARGO_TECHNICIAN
+ flag = CARGOTECH
+ departments = list(DEPARTMENT_CARGO)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 3
+ spawn_positions = 3
+ pto_type = PTO_CARGO
+ supervisors = "the " + JOB_QUARTERMASTER + " and the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#7a4f33"
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
+ minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting)
+
+ outfit_type = /decl/hierarchy/outfit/job/cargo/cargo_tech
+ job_description = "A " + JOB_CARGO_TECHNICIAN + " fills and delivers cargo orders. They are encouraged to return delivered crates to the Cargo Shuttle, \
+ because Central Command gives a partial refund."
+
+ alt_titles = list(JOB_ALT_CARGO_LOADER = /datum/alt_title/cargo_loader, JOB_ALT_CARGO_HANDLER = /datum/alt_title/cargo_handler, JOB_ALT_SUPPLY_COURIER = /datum/alt_title/supply_courier,
+ JOB_ALT_DISPOSALS_SORTER = /datum/alt_title/disposal_sorter)
+
+/datum/alt_title/supply_courier
+ title = JOB_ALT_SUPPLY_COURIER
+ title_blurb = "A " + JOB_ALT_SUPPLY_COURIER + " is usually tasked with delivering packages or cargo directly to whoever requires it."
+
+/datum/alt_title/cargo_loader
+ title = JOB_ALT_CARGO_LOADER
+ title_blurb = "A " + JOB_ALT_CARGO_LOADER + " is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
+
+/datum/alt_title/cargo_handler
+ title = JOB_ALT_CARGO_HANDLER
+ title_blurb = "A " + JOB_ALT_CARGO_HANDLER + " is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
+
+/datum/alt_title/disposal_sorter
+ title = JOB_ALT_DISPOSALS_SORTER
+ title_blurb = "A " + JOB_ALT_DISPOSALS_SORTER + " is usually tasked with operating disposals delivery system, sorting the trash and tagging parcels for delivery."
+
+//////////////////////////////////
+// Shaft Miner
+//////////////////////////////////
+
+/datum/job/mining
+ title = JOB_SHAFT_MINER
+ flag = MINER
+ departments = list(DEPARTMENT_CARGO)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 4
+ spawn_positions = 4
+ pto_type = PTO_CARGO
+ supervisors = "the " + JOB_QUARTERMASTER + " and the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#7a4f33"
+ economic_modifier = 5
+ access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
+ minimal_access = list(access_mining, access_mining_station, access_mailsorting)
+
+ outfit_type = /decl/hierarchy/outfit/job/cargo/mining
+ job_description = "A " + JOB_SHAFT_MINER + " mines and processes minerals to be delivered to departments that need them."
+ alt_titles = list(JOB_ALT_DEEP_SPACE_MINER = /datum/alt_title/deep_space_miner, JOB_ALT_DRILL_TECHNICIAN = /datum/alt_title/drill_tech, JOB_ALT_PROSPECTOR = /datum/alt_title/prospector,
+ JOB_ALT_EXCAVATOR = /datum/alt_title/excavator)
+
+/datum/job/mining/get_request_reasons()
+ return list("Assembling expedition team")
+
+/datum/alt_title/drill_tech
+ title = JOB_ALT_DRILL_TECHNICIAN
+ title_blurb = "A " + JOB_ALT_DRILL_TECHNICIAN + " specializes in operating and maintaining the machinery needed to extract ore from veins deep below the surface."
+
+/datum/alt_title/deep_space_miner
+ title = JOB_ALT_DEEP_SPACE_MINER
+ title_blurb = "A " + JOB_ALT_DEEP_SPACE_MINER + " specializes primarily in mining operations in zero-g environments, mostly in asteroid and debris fields."
+
+/datum/alt_title/prospector
+ title = JOB_ALT_PROSPECTOR
+
+/datum/alt_title/excavator
+ title = JOB_ALT_EXCAVATOR
diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm
index 663edab0a45..0604b872e4e 100644
--- a/code/game/jobs/job/civilian.dm
+++ b/code/game/jobs/job/civilian.dm
@@ -12,6 +12,7 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_CIVILIAN
supervisors = "the " + JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_hydroponics, access_bar, access_kitchen)
@@ -19,7 +20,7 @@
outfit_type = /decl/hierarchy/outfit/job/service/bartender
job_description = "A " + JOB_BARTENDER + " mixes drinks for the crew. They generally have permission to charge for drinks or deny service to unruly patrons."
- alt_titles = list(JOB_ALT_BARISTA = /datum/alt_title/barista)
+ alt_titles = list(JOB_ALT_BARKEEPR = /datum/alt_title/barkeeper, JOB_ALT_BARMAID = /datum/alt_title/barmaid, JOB_ALT_BARISTA = /datum/alt_title/barista, JOB_ALT_MIXOLOGIST = /datum/alt_title/mixologist)
// Bartender Alt Titles
/datum/alt_title/barista
@@ -28,6 +29,15 @@
or deny service to unruly patrons."
title_outfit = /decl/hierarchy/outfit/job/service/bartender/barista
+/datum/alt_title/barkeeper
+ title = JOB_ALT_BARKEEPR
+
+/datum/alt_title/barmaid
+ title = JOB_ALT_BARMAID
+
+/datum/alt_title/mixologist
+ title = JOB_ALT_MIXOLOGIST
+
//////////////////////////////////
// Chef
//////////////////////////////////
@@ -40,6 +50,7 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_CIVILIAN
supervisors = "the "+ JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_hydroponics, access_bar, access_kitchen)
@@ -47,13 +58,20 @@
outfit_type = /decl/hierarchy/outfit/job/service/chef
job_description = "A " + JOB_CHEF + " cooks food for the crew. They generally have permission to charge for food or deny service to unruly diners."
- alt_titles = list(JOB_ALT_COOK = /datum/alt_title/cook)
+ alt_titles = list(JOB_ALT_SOUSCHEF = /datum/alt_title/souschef, JOB_ALT_COOK = /datum/alt_title/cook, JOB_ALT_KITCHEN_WORKER = /datum/alt_title/kitchen_worker)
// Chef Alt Titles
/datum/alt_title/cook
title = JOB_ALT_COOK
title_blurb = "A " + JOB_ALT_COOK + " has the same duties, though they may be less experienced."
+/datum/alt_title/souschef
+ title = JOB_ALT_SOUSCHEF
+
+/datum/alt_title/kitchen_worker
+ title = JOB_ALT_KITCHEN_WORKER
+ title_blurb = "A " + JOB_ALT_KITCHEN_WORKER + " has the same duties, though they may be less experienced."
+
//////////////////////////////////
// Botanist
//////////////////////////////////
@@ -66,6 +84,7 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_CIVILIAN
supervisors = "the " + JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_hydroponics, access_bar, access_kitchen)
@@ -73,89 +92,30 @@
outfit_type = /decl/hierarchy/outfit/job/service/gardener
job_description = "A " + JOB_BOTANIST+ " grows plants for the " + JOB_CHEF + " and " + JOB_BARTENDER + "."
- alt_titles = list(JOB_ALT_GARDENER = /datum/alt_title/gardener)
+ alt_titles = list(JOB_ALT_HYDROPONICIST = /datum/alt_title/hydroponicist, JOB_ALT_CULTIVATOR = /datum/alt_title/cultivator, JOB_ALT_FARMER = /datum/alt_title/farmer,
+ JOB_ALT_GARDENER = /datum/alt_title/gardener, JOB_ALT_FLORIST = /datum/alt_title/florsit, JOB_ALT_RANCHER = /datum/alt_title/rancher)
//Botanist Alt Titles
/datum/alt_title/gardener
title = JOB_ALT_GARDENER
title_blurb = "A " + JOB_ALT_GARDENER + " may be less professional than their counterparts, and are more likely to tend to the public gardens if they aren't needed elsewhere."
-//Cargo
-//////////////////////////////////
-// Quartermaster
-//////////////////////////////////
-/datum/job/qm
- title = JOB_QUARTERMASTER
- flag = QUARTERMASTER
- departments = list(DEPARTMENT_CARGO)
- sorting_order = 1 // QM is above the cargo techs, but below the HoP.
- departments_managed = list(DEPARTMENT_CARGO)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 1
- spawn_positions = 1
- supervisors = "the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#9b633e"
- economic_modifier = 5
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station, access_RC_announce)
- minimal_access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station, access_RC_announce)
- banned_job_species = list("digital", SPECIES_PROMETHEAN)
+/datum/alt_title/hydroponicist
+ title = JOB_ALT_HYDROPONICIST
- ideal_character_age = 40
+/datum/alt_title/cultivator
+ title = JOB_ALT_CULTIVATOR
- outfit_type = /decl/hierarchy/outfit/job/cargo/qm
- job_description = "The " + JOB_QUARTERMASTER + " manages the Supply department, checking cargo orders and ensuring supplies get to where they are needed."
- alt_titles = list(JOB_ALT_SUPPLY_CHIEF = /datum/alt_title/supply_chief)
+/datum/alt_title/farmer
+ title = JOB_ALT_FARMER
-// Quartermaster Alt Titles
-/datum/alt_title/supply_chief
- title = JOB_ALT_SUPPLY_CHIEF
+/datum/alt_title/florsit
+ title = JOB_ALT_FLORIST
+ title_blurb = "A " + JOB_ALT_FLORIST + " may be less professional than their counterparts, and are more likely to tend to the public gardens if they aren't needed elsewhere."
-//////////////////////////////////
-// Cargo Tech
-//////////////////////////////////
-/datum/job/cargo_tech
- title = JOB_CARGO_TECHNICIAN
- flag = CARGOTECH
- departments = list(DEPARTMENT_CARGO)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
- supervisors = "the " + JOB_QUARTERMASTER + " and the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#7a4f33"
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
- minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting)
-
- outfit_type = /decl/hierarchy/outfit/job/cargo/cargo_tech
- job_description = "A " + JOB_CARGO_TECHNICIAN + " fills and delivers cargo orders. They are encouraged to return delivered crates to the Cargo Shuttle, \
- because Central Command gives a partial refund."
-
-//////////////////////////////////
-// Shaft Miner
-//////////////////////////////////
-
-/datum/job/mining
- title = JOB_SHAFT_MINER
- flag = MINER
- departments = list(DEPARTMENT_CARGO)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 3
- spawn_positions = 3
- supervisors = "the " + JOB_QUARTERMASTER + " and the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#7a4f33"
- economic_modifier = 5
- access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station)
- minimal_access = list(access_mining, access_mining_station, access_mailsorting)
-
- outfit_type = /decl/hierarchy/outfit/job/cargo/mining
- job_description = "A " + JOB_SHAFT_MINER + " mines and processes minerals to be delivered to departments that need them."
- alt_titles = list(JOB_ALT_DRILL_TECHNICIAN = /datum/alt_title/drill_tech)
-
-/datum/alt_title/drill_tech
- title = JOB_ALT_DRILL_TECHNICIAN
- title_blurb = "A " + JOB_ALT_DRILL_TECHNICIAN + " specializes in operating and maintaining the machinery needed to extract ore from veins deep below the surface."
+/datum/alt_title/rancher
+ title = JOB_ALT_RANCHER
+ title_blurb = "A " + JOB_ALT_RANCHER + " is tasked with the care, feeding, raising, and harvesting of livestock."
//Service
//////////////////////////////////
@@ -167,8 +127,9 @@
departments = list(DEPARTMENT_CIVILIAN)
department_flag = CIVILIAN
faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
+ total_positions = 3
+ spawn_positions = 3
+ pto_type = PTO_CIVILIAN
supervisors = "the " + JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_janitor, access_maint_tunnels)
@@ -176,12 +137,23 @@
outfit_type = /decl/hierarchy/outfit/job/service/janitor
job_description = "A " + JOB_JANITOR + " keeps the station clean, as long as it doesn't interfere with active crime scenes."
- alt_titles = list(JOB_ALT_CUSTODIAN = /datum/alt_title/custodian)
+ alt_titles = list(JOB_ALT_CUSTODIAN = /datum/alt_title/custodian, JOB_ALT_SANITATION_TECHNICIAN = /datum/alt_title/sanitation_tech,
+ JOB_ALT_MAID = /datum/alt_title/maid, JOB_ALT_GARBAGE_COLLECTOR = /datum/alt_title/garbage_collector)
// Janitor Alt Titles
/datum/alt_title/custodian
title = JOB_ALT_CUSTODIAN
+/datum/alt_title/sanitation_tech
+ title = JOB_ALT_SANITATION_TECHNICIAN
+
+/datum/alt_title/maid
+ title = JOB_ALT_MAID
+
+/datum/alt_title/garbage_collector
+ title = JOB_ALT_GARBAGE_COLLECTOR
+ title_blurb = "A " + JOB_ALT_GARBAGE_COLLECTOR + " keeps the station clean, though focuses moreso on collecting larger trash, with wet cleaning being secondary task."
+
//More or less assistants
//////////////////////////////////
// Librarian
@@ -192,8 +164,9 @@
departments = list(DEPARTMENT_CIVILIAN)
department_flag = CIVILIAN
faction = FACTION_STATION
- total_positions = 1
- spawn_positions = 1
+ total_positions = 2
+ spawn_positions = 2
+ pto_type = PTO_CIVILIAN
supervisors = "the " + JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_library, access_maint_tunnels)
@@ -201,7 +174,9 @@
outfit_type = /decl/hierarchy/outfit/job/librarian
job_description = "The " + JOB_LIBRARIAN + " curates the book selection in the Library, so the crew might enjoy it."
- alt_titles = list(JOB_ALT_JOURNALIST = /datum/alt_title/journalist, JOB_ALT_WRITER = /datum/alt_title/writer)
+ alt_titles = list(JOB_ALT_JOURNALIST = /datum/alt_title/journalist, JOB_ALT_REPORTER = /datum/alt_title/reporter, JOB_ALT_WRITER = /datum/alt_title/writer,
+ JOB_ALT_HISTORIAN = /datum/alt_title/historian, JOB_ALT_ARCHIVIST = /datum/alt_title/archivist, JOB_ALT_PROFESSOR = /datum/alt_title/professor,
+ JOB_ALT_ACADEMIC = /datum/alt_title/academic, JOB_ALT_PHILOSOPHER = /datum/alt_title/philosopher, JOB_ALT_CURATOR = /datum/alt_title/curator)
// Librarian Alt Titles
/datum/alt_title/journalist
@@ -213,6 +188,34 @@
title = JOB_ALT_WRITER
title_blurb = "The " + JOB_ALT_WRITER + " uses the Library as a quiet place to write whatever it is they choose to write."
+/datum/alt_title/reporter
+ title = JOB_ALT_REPORTER
+ title_blurb = "The " + JOB_ALT_REPORTER + " uses the Library as a base of operations, from which they can report the news and goings-on on the station with their camera."
+
+/datum/alt_title/historian
+ title = JOB_ALT_HISTORIAN
+ title_blurb = "The " + JOB_ALT_HISTORIAN + " uses the Library as a base of operation to record any important events occurring on station."
+
+/datum/alt_title/archivist
+ title = JOB_ALT_ARCHIVIST
+ title_blurb = "The " + JOB_ALT_ARCHIVIST + " uses the Library as a base of operation to record any important events occurring on station."
+
+/datum/alt_title/professor
+ title = JOB_ALT_PROFESSOR
+ title_blurb = "The " + JOB_ALT_PROFESSOR + " uses the Library as a base of operations to share their vast knowledge with the crew."
+
+/datum/alt_title/academic
+ title = JOB_ALT_ACADEMIC
+ title_blurb = "The " + JOB_ALT_ACADEMIC + " uses the Library as a base of operations to share their vast knowledge with the crew."
+
+/datum/alt_title/philosopher
+ title = JOB_ALT_PHILOSOPHER
+ title_blurb = "The " + JOB_ALT_PHILOSOPHER + " uses the Library as a base of operation to ruminate on nature of life and other great questions, and share their opinions with the crew."
+
+/datum/alt_title/curator
+ title = JOB_ALT_CURATOR
+ title_blurb = "The " + JOB_ALT_CURATOR + " uses the Library as a base of operation to gather the finest of art for display and preservation."
+
//////////////////////////////////
// Internal Affairs Agent
//////////////////////////////////
@@ -226,6 +229,8 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_CIVILIAN
+ disallow_jobhop = TRUE
supervisors = "company officials and Corporate Regulations"
selection_color = "#515151"
economic_modifier = 7
@@ -238,10 +243,233 @@
job_description = "An " + JOB_INTERNAL_AFFAIRS_AGENT + " makes sure that the crew is following Standard Operating Procedure. They also \
handle complaints against crew members, and can have issues brought to the attention of Central Command, \
assuming their paperwork is in order."
+ alt_titles = list(JOB_ALT_INTERNAL_AFFAIRS_LIAISON = /datum/alt_title/ia_liaison, JOB_ALT_INTERNAL_AFFAIRS_DELEGATE = /datum/alt_title/ia_delegate,
+ JOB_ALT_INTERNAL_AFFAIRS_INVESTIGATOR = /datum/alt_title/ia_investigator)
-/*
-/datum/job/lawyer/equip(var/mob/living/carbon/human/H)
- . = ..()
- if(.)
- H.implant_loyalty(H)
-*/
+/datum/alt_title/ia_liaison
+ title = JOB_ALT_INTERNAL_AFFAIRS_LIAISON
+
+/datum/alt_title/ia_delegate
+ title = JOB_ALT_INTERNAL_AFFAIRS_DELEGATE
+
+/datum/alt_title/ia_investigator
+ title = JOB_ALT_INTERNAL_AFFAIRS_INVESTIGATOR
+
+//////////////////////////////////
+// Pilot
+//////////////////////////////////
+
+/datum/job/pilot
+ title = JOB_PILOT
+ flag = PILOT
+ departments = list(DEPARTMENT_CIVILIAN)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#515151"
+ economic_modifier = 5
+ minimal_player_age = 3
+ pto_type = PTO_CIVILIAN
+ access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot)
+ minimal_access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot)
+ outfit_type = /decl/hierarchy/outfit/job/pilot
+ job_description = "A " + JOB_PILOT + " flies the various shuttles in the Virgo-Erigone System."
+ alt_titles = list(JOB_ALT_COPILOT = /datum/alt_title/co_pilot, JOB_ALT_NAVIGATOR = /datum/alt_title/navigator, JOB_ALT_HELMSMAN = /datum/alt_title/helmsman)
+
+/datum/alt_title/co_pilot
+ title = JOB_ALT_COPILOT
+ title_blurb = "A Co-" + JOB_ALT_COPILOT + " is there primarily to assist main pilot as well as learn from them"
+
+/datum/alt_title/navigator
+ title = JOB_ALT_NAVIGATOR
+
+/datum/alt_title/helmsman
+ title = JOB_ALT_HELMSMAN
+
+/datum/job/pilot/get_request_reasons()
+ return list("Assembling expedition team")
+
+//////////////////////////////////
+// Entertainer
+//////////////////////////////////
+
+/datum/job/entertainer
+ title = JOB_ENTERTAINER
+ flag = ENTERTAINER
+ departments = list(DEPARTMENT_CIVILIAN)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 4
+ spawn_positions = 4
+ supervisors = "the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#515151"
+ access = list(access_entertainment)
+ minimal_access = list(access_entertainment)
+ pto_type = PTO_CIVILIAN
+
+ outfit_type = /decl/hierarchy/outfit/job/assistant/entertainer
+ job_description = "An " + JOB_ENTERTAINER + " does just that, entertains! Put on plays, play music, sing songs, tell stories, or read your favorite fanfic."
+ alt_titles = list(JOB_ALT_PERFORMER = /datum/alt_title/performer, JOB_ALT_MUSICIAN = /datum/alt_title/musician, JOB_ALT_STAGEHAND = /datum/alt_title/stagehand,
+ JOB_ALT_ACTOR = /datum/alt_title/actor, JOB_ALT_DANCER = /datum/alt_title/dancer, JOB_ALT_SINGER = /datum/alt_title/singer,
+ JOB_ALT_MAGICIAN = /datum/alt_title/magician, JOB_ALT_COMEDIAN = /datum/alt_title/comedian, JOB_ALT_ARTIST = /datum/alt_title/tragedian,
+ JOB_ALT_ARTIST = /datum/alt_title/artist, JOB_ALT_GAME_MASTER = /datum/alt_title/game_master)
+
+// Entertainer Alt Titles
+/datum/alt_title/actor
+ title = JOB_ALT_ACTOR
+ title_blurb = "An " + JOB_ALT_ACTOR + " is someone who acts out a role! Whatever sort of character it is, get into it and impress people with power of comedy and tragedy!"
+
+/datum/alt_title/performer
+ title = JOB_ALT_PERFORMER
+ title_blurb = "A " + JOB_ALT_PERFORMER + " is someone who performs! Whatever sort of performance will come to your mind, the world's a stage!"
+
+/datum/alt_title/musician
+ title = JOB_ALT_MUSICIAN
+ title_blurb = "A " + JOB_ALT_MUSICIAN + " is someone who makes music with a wide variety of musical instruments!"
+
+/datum/alt_title/stagehand
+ title = JOB_ALT_STAGEHAND
+ title_blurb = "A " + JOB_ALT_STAGEHAND + " typically performs everything the rest of the entertainers don't. Operate lights, shutters, windows, or narrate through your voicebox!"
+
+/datum/alt_title/dancer
+ title = JOB_ALT_DANCER
+ title_blurb = "A " + JOB_ALT_DANCER + " is someone who impresses people through power of their own body! From waltz to breakdance, as long as crowd as cheering!"
+
+/datum/alt_title/singer
+ title = JOB_ALT_SINGER
+ title_blurb = "A " + JOB_ALT_SINGER + " is someone with gift of melodious voice! Impress people with your vocal range!"
+
+/datum/alt_title/magician
+ title = JOB_ALT_MAGICIAN
+ title_blurb = "A " + JOB_ALT_MAGICIAN + " is someone who awes those around them with impossible! Show off your repertoire of magic tricks, while keeping the secret hidden!"
+
+/datum/alt_title/comedian
+ title = JOB_ALT_COMEDIAN
+ title_blurb = "A " + JOB_ALT_COMEDIAN + " will focus on making people laugh with the power of wit! Telling jokes, stand-up comedy, you are here to make others smile!"
+
+/datum/alt_title/tragedian
+ title = JOB_ALT_ARTIST
+ title_blurb = "A " + JOB_ALT_ARTIST + " will focus on making people think about life and world around them! Life is a tragedy, and who's better to convey its emotions than you?"
+
+/datum/alt_title/artist
+ title = JOB_ALT_ARTIST
+ title_blurb = "An " + JOB_ALT_ARTIST + "'s calling is to create beautiful arts! Whatever form may they take, create and have people astonished with your creativity."
+
+/datum/alt_title/game_master
+ title = JOB_ALT_GAME_MASTER
+ title_blurb = "A " + JOB_ALT_GAME_MASTER + " provides recreation for the crew by hosting variety of games. From cards to roleplaying to something more personalized."
+
+//////////////////////////////////
+// Entrepreneur
+//////////////////////////////////
+
+/datum/job/entrepreneur
+ title = JOB_ENTREPRENEUR
+ flag = ENTREPRENEUR
+ departments = list(DEPARTMENT_CIVILIAN)
+ department_flag = CIVILIAN
+ faction = FACTION_STATION
+ total_positions = 4
+ spawn_positions = 4
+ supervisors = "the " + JOB_HEAD_OF_PERSONNEL
+ selection_color = "#515151"
+ access = list()
+ minimal_access = list()
+ pto_type = PTO_CIVILIAN
+
+ outfit_type = /decl/hierarchy/outfit/job/assistant/entrepreneur
+ job_description = "An " + JOB_ENTREPRENEUR + " is basically a visitor that obtained special permission to offer personal services to people on station. \
+ They will offer people these services and, potentially, even demand payment!"
+ alt_titles = list(JOB_ALT_LAWYER = /datum/alt_title/lawyer, JOB_ALT_PRIVATE_EYE = /datum/alt_title/private_eye, JOB_ALT_BODYGUARD = /datum/alt_title/bodyguard,
+ JOB_ALT_PERSONAL_PHYSICIAN = /datum/alt_title/personal_physician, JOB_ALT_DENTIST = /datum/alt_title/dentist, JOB_ALT_FITNESS_INSTRUCTOR = /datum/alt_title/fitness_instructor,
+ JOB_ALT_YOGA_TEACHER = /datum/alt_title/yoga_teacher, JOB_ALT_MASSEUSE = /datum/alt_title/masseuse, JOB_ALT_TRADESPERSON = /datum/alt_title/tradesperson,
+ JOB_ALT_STREAMER = /datum/alt_title/streamer, JOB_ALT_INFLUENCER = /datum/alt_title/influencer, JOB_ALT_PARANORMAL_INVESTIGATOR = /datum/alt_title/paranormal_investigator,
+ JOB_ALT_PERSONAL_SECRETARY = /datum/alt_title/personal_secretary, JOB_ALT_STYLIST = /datum/alt_title/stylist, JOB_ALT_FISHER = /datum/alt_title/fisher,
+ JOB_ALT_FORTUNE_TELLER = /datum/alt_title/fortune_teller, JOB_ALT_SPIRIT_HEALER = /datum/alt_title/spirit_healer)
+
+/datum/alt_title/lawyer
+ title = JOB_ALT_LAWYER
+ title_blurb = "A " + JOB_ALT_LAWYER + " is knowledgable in various legal systems, including station's operations. They can try to offer their legal counsel, although nobody is really obliged to listen."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_secretary
+
+/datum/alt_title/private_eye
+ title = JOB_ALT_PRIVATE_EYE
+ title_blurb = "A " + JOB_ALT_PRIVATE_EYE + " is a detective that has no credentials or equipment. But if someone wants something found without security's knowledge, they are the one to go to."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/private_eye
+
+/datum/alt_title/bodyguard
+ title = JOB_ALT_BODYGUARD
+ title_blurb = "A " + JOB_ALT_BODYGUARD + " offers service of personal protection. They may not be allowed any weapons, but their own body is weapon enough."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/bodyguard
+
+/datum/alt_title/personal_physician
+ title = JOB_ALT_PERSONAL_PHYSICIAN
+ title_blurb = "A " + JOB_ALT_PERSONAL_PHYSICIAN + " is a doctor dedicated less to Hippocratic Oath and more to the moneymaking grind. Their license may be expired, but the grindset never will be."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_physician
+
+/datum/alt_title/dentist
+ title = JOB_ALT_DENTIST
+ title_blurb = "A " + JOB_ALT_DENTIST + " is a doctor that specializes in oral care. Company may not recognize them as a proper doctor, but surely their customers will."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/dentist
+
+/datum/alt_title/fitness_instructor
+ title = JOB_ALT_FITNESS_INSTRUCTOR
+ title_blurb = "A " + JOB_ALT_FITNESS_INSTRUCTOR + " dedicates themselves to improving the health of the crew through physical activity, and boy, do they need the help."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fitness_instructor
+
+/datum/alt_title/yoga_teacher
+ title = JOB_ALT_YOGA_TEACHER
+ title_blurb = "A " + JOB_ALT_YOGA_TEACHER + " is similar to a fitness instructor, but rather than turning the round bodies into firm ones, they focus on helping people find balance and harmony."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/yoga_teacher
+
+/datum/alt_title/masseuse
+ title = JOB_ALT_MASSEUSE
+ title_blurb = "A " + JOB_ALT_MASSEUSE + " is master of physical therapy and working others' bodies with their hands."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/masseuse
+
+/datum/alt_title/tradesperson
+ title = JOB_ALT_TRADESPERSON
+ title_blurb = "A " + JOB_ALT_TRADESPERSON + " is someone attempting to make money via the most obvious act of all - buying and selling. Now if only customs allowed you to bring your goods along..."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/tradesperson
+
+/datum/alt_title/streamer
+ title = JOB_ALT_STREAMER
+ title_blurb = "A " + JOB_ALT_STREAMER + " is here to entertain. Not the crew! Their audience across exonet!"
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/streamer
+
+/datum/alt_title/influencer
+ title = JOB_ALT_INFLUENCER
+ title_blurb = "An " + JOB_ALT_INFLUENCER + " has lucked out with some exonet following, and was given permission to go onstation to provide free exposure. Don't let it go to your head."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/influencer
+
+/datum/alt_title/paranormal_investigator
+ title = JOB_ALT_PARANORMAL_INVESTIGATOR
+ title_blurb = "A " + JOB_ALT_PARANORMAL_INVESTIGATOR + " looks beyond what is accepted by modern science, and searches for the true unknown. Aliens, alternate dimensions, ghosts... The truth is out there!"
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/paranormal_investigator
+
+/datum/alt_title/personal_secretary
+ title = JOB_ALT_PERSONAL_SECRETARY
+ title_blurb = "A " + JOB_ALT_PERSONAL_SECRETARY + " offers services of general assistance. Although it's doubtful anyone will ever actually need those."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_secretary
+
+/datum/alt_title/stylist
+ title = JOB_ALT_STYLIST
+ title_blurb = "A " + JOB_ALT_STYLIST + " offers fashion advice, as well as helps with adjusting appearance of the crew to better suit their beauty standards."
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/stylist
+
+/datum/alt_title/fisher
+ title = JOB_ALT_FISHER
+ title_blurb = "A " + JOB_ALT_FISHER + " is a capable angler, who is good at obtaining large amounts of marine goods. Whether you generously give them to station or attempt to make a quick thaler by selling, it's up to you!"
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fisher
+
+/datum/alt_title/fortune_teller
+ title = JOB_ALT_FORTUNE_TELLER
+ title_blurb = "A " + JOB_ALT_FORTUNE_TELLER + " peers into the future, and offers these visions to others. Occasionally those visions may even come true!"
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fortune_teller
+
+/datum/alt_title/spirit_healer
+ title = JOB_ALT_SPIRIT_HEALER
+ title_blurb = "A " + JOB_ALT_SPIRIT_HEALER + " offers alternative forms of medicine. Rituals, magic rocks, seances... It totally works. What's that about placebo?"
+ title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/spirit_healer
diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm
index 1220e3ee88f..a980fd2325f 100644
--- a/code/game/jobs/job/civilian_chaplain.dm
+++ b/code/game/jobs/job/civilian_chaplain.dm
@@ -7,6 +7,7 @@
faction = FACTION_STATION
total_positions = 1
spawn_positions = 1
+ pto_type = PTO_CIVILIAN
supervisors = "the " + JOB_HEAD_OF_PERSONNEL
selection_color = "#515151"
access = list(access_morgue, access_chapel_office, access_crematorium, access_maint_tunnels)
@@ -14,13 +15,34 @@
outfit_type = /decl/hierarchy/outfit/job/chaplain
job_description = "The " + JOB_CHAPLAIN + " ministers to the spiritual needs of the crew."
- alt_titles = list(JOB_ALT_COUNSELOR = /datum/alt_title/counselor)
+ alt_titles = list(JOB_ALT_MISSIONARY = /datum/alt_title/missionary, JOB_ALT_PREACHER = /datum/alt_title/preacher, JOB_ALT_PRIEST = /datum/alt_title/priest,
+ JOB_ALT_NUN = /datum/alt_title/nun, JOB_ALT_MONK = /datum/alt_title/monk, JOB_ALT_COUNSELOR = /datum/alt_title/counselor,
+ JOB_ALT_GURU = /datum/alt_title/guru)
// Chaplain Alt Titles
/datum/alt_title/counselor
title = JOB_ALT_COUNSELOR
title_blurb = "The " + JOB_ALT_COUNSELOR + " attends to the emotional needs of the crew, without a specific medicinal or spiritual focus."
+/datum/alt_title/guru
+ title = JOB_ALT_GURU
+ title_blurb = "The " + JOB_ALT_GURU + " primarily tries to offer spiritual guidance to those who come seeking it."
+
+/datum/alt_title/missionary
+ title = JOB_ALT_MISSIONARY
+
+/datum/alt_title/preacher
+ title = JOB_ALT_PREACHER
+
+/datum/alt_title/priest
+ title = JOB_ALT_PRIEST
+
+/datum/alt_title/nun
+ title = JOB_ALT_NUN
+
+/datum/alt_title/monk
+ title = JOB_ALT_MONK
+
/datum/job/chaplain/equip(var/mob/living/carbon/human/H, var/alt_title, var/ask_questions = TRUE)
. = ..()
if(!.)
diff --git a/code/game/jobs/job/civilian_vr.dm b/code/game/jobs/job/civilian_vr.dm
deleted file mode 100644
index bd4093e4033..00000000000
--- a/code/game/jobs/job/civilian_vr.dm
+++ /dev/null
@@ -1,426 +0,0 @@
-/datum/job/bartender
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_BARKEEPR = /datum/alt_title/barkeeper, JOB_ALT_BARMAID = /datum/alt_title/barmaid, JOB_ALT_BARISTA = /datum/alt_title/barista, JOB_ALT_MIXOLOGIST = /datum/alt_title/mixologist)
-
-/datum/alt_title/barkeeper
- title = JOB_ALT_BARKEEPR
-
-/datum/alt_title/barmaid
- title = JOB_ALT_BARMAID
-
-/datum/alt_title/mixologist
- title = JOB_ALT_MIXOLOGIST
-
-
-/datum/job/chef
- total_positions = 2 //IT TAKES A LOT TO MAKE A STEW
- spawn_positions = 2 //A PINCH OF SALT AND LAUGHTER, TOO
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_SOUSCHEF = /datum/alt_title/souschef, JOB_ALT_COOK = /datum/alt_title/cook, JOB_ALT_KITCHEN_WORKER = /datum/alt_title/kitchen_worker)
-
-/datum/alt_title/souschef
- title = JOB_ALT_SOUSCHEF
-
-/datum/alt_title/kitchen_worker
- title = JOB_ALT_KITCHEN_WORKER
- title_blurb = "A " + JOB_ALT_KITCHEN_WORKER + " has the same duties, though they may be less experienced."
-
-
-/datum/job/hydro
- spawn_positions = 2
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_HYDROPONICIST = /datum/alt_title/hydroponicist, JOB_ALT_CULTIVATOR = /datum/alt_title/cultivator, JOB_ALT_FARMER = /datum/alt_title/farmer,
- JOB_ALT_GARDENER = /datum/alt_title/gardener, JOB_ALT_FLORIST = /datum/alt_title/florsit, JOB_ALT_RANCHER = /datum/alt_title/rancher)
-
-/datum/alt_title/hydroponicist
- title = JOB_ALT_HYDROPONICIST
-
-/datum/alt_title/cultivator
- title = JOB_ALT_CULTIVATOR
-
-/datum/alt_title/farmer
- title = JOB_ALT_FARMER
-
-/datum/alt_title/florsit
- title = JOB_ALT_FLORIST
- title_blurb = "A " + JOB_ALT_FLORIST + " may be less professional than their counterparts, and are more likely to tend to the public gardens if they aren't needed elsewhere."
-
-/datum/alt_title/rancher
- title = JOB_ALT_RANCHER
- title_blurb = "A " + JOB_ALT_RANCHER + " is tasked with the care, feeding, raising, and harvesting of livestock."
-
-
-/datum/job/qm
- pto_type = PTO_CARGO
- dept_time_required = 20
- alt_titles = list(JOB_ALT_SUPPLY_CHIEF = /datum/alt_title/supply_chief, JOB_ALT_LOGISTICS_MANAGER = /datum/alt_title/logistics_manager, JOB_ALT_CARGO_SUPERVISOR = /datum/alt_title/cargo_supervisor)
-
-/datum/alt_title/logistics_manager
- title = JOB_ALT_LOGISTICS_MANAGER
-
-/datum/alt_title/cargo_supervisor
- title = JOB_ALT_CARGO_SUPERVISOR
-
-/datum/job/qm/get_request_reasons()
- return list("Training crew")
-
-
-/datum/job/cargo_tech
- total_positions = 3
- spawn_positions = 3
- pto_type = PTO_CARGO
- alt_titles = list(JOB_ALT_CARGO_LOADER = /datum/alt_title/cargo_loader, JOB_ALT_CARGO_HANDLER = /datum/alt_title/cargo_handler, JOB_ALT_SUPPLY_COURIER = /datum/alt_title/supply_courier,
- JOB_ALT_DISPOSALS_SORTER = /datum/alt_title/disposal_sorter)
-
-/datum/alt_title/supply_courier
- title = JOB_ALT_SUPPLY_COURIER
- title_blurb = "A " + JOB_ALT_SUPPLY_COURIER + " is usually tasked with delivering packages or cargo directly to whoever requires it."
-
-/datum/alt_title/cargo_loader
- title = JOB_ALT_CARGO_LOADER
- title_blurb = "A " + JOB_ALT_CARGO_LOADER + " is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
-
-/datum/alt_title/cargo_handler
- title = JOB_ALT_CARGO_HANDLER
- title_blurb = "A " + JOB_ALT_CARGO_HANDLER + " is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
-
-/datum/alt_title/disposal_sorter
- title = JOB_ALT_DISPOSALS_SORTER
- title_blurb = "A " + JOB_ALT_DISPOSALS_SORTER + " is usually tasked with operating disposals delivery system, sorting the trash and tagging parcels for delivery."
-
-
-/datum/job/mining
- total_positions = 4
- spawn_positions = 4
- pto_type = PTO_CARGO
- alt_titles = list(JOB_ALT_DEEP_SPACE_MINER = /datum/alt_title/deep_space_miner, JOB_ALT_DRILL_TECHNICIAN = /datum/alt_title/drill_tech, JOB_ALT_PROSPECTOR = /datum/alt_title/prospector,
- JOB_ALT_EXCAVATOR = /datum/alt_title/excavator)
-
-/datum/alt_title/deep_space_miner
- title = JOB_ALT_DEEP_SPACE_MINER
- title_blurb = "A " + JOB_ALT_DEEP_SPACE_MINER + " specializes primarily in mining operations in zero-g environments, mostly in asteroid and debris fields."
-
-/datum/alt_title/prospector
- title = JOB_ALT_PROSPECTOR
-
-/datum/alt_title/excavator
- title = JOB_ALT_EXCAVATOR
-
-/datum/job/mining/get_request_reasons()
- return list("Assembling expedition team")
-
-
-/datum/job/janitor //Lots of janitor substations on station.
- total_positions = 3
- spawn_positions = 3
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_CUSTODIAN = /datum/alt_title/custodian, JOB_ALT_SANITATION_TECHNICIAN = /datum/alt_title/sanitation_tech,
- JOB_ALT_MAID = /datum/alt_title/maid, JOB_ALT_GARBAGE_COLLECTOR = /datum/alt_title/garbage_collector)
-
-/datum/alt_title/sanitation_tech
- title = JOB_ALT_SANITATION_TECHNICIAN
-
-/datum/alt_title/maid
- title = JOB_ALT_MAID
-
-/datum/alt_title/garbage_collector
- title = JOB_ALT_GARBAGE_COLLECTOR
- title_blurb = "A " + JOB_ALT_GARBAGE_COLLECTOR + " keeps the station clean, though focuses moreso on collecting larger trash, with wet cleaning being secondary task."
-
-
-/datum/job/librarian
- total_positions = 2
- spawn_positions = 2
- alt_titles = list(JOB_ALT_JOURNALIST = /datum/alt_title/journalist, JOB_ALT_REPORTER = /datum/alt_title/reporter, JOB_ALT_WRITER = /datum/alt_title/writer,
- JOB_ALT_HISTORIAN = /datum/alt_title/historian, JOB_ALT_ARCHIVIST = /datum/alt_title/archivist, JOB_ALT_PROFESSOR = /datum/alt_title/professor,
- JOB_ALT_ACADEMIC = /datum/alt_title/academic, JOB_ALT_PHILOSOPHER = /datum/alt_title/philosopher, JOB_ALT_CURATOR = /datum/alt_title/curator)
- pto_type = PTO_CIVILIAN
-
-/datum/alt_title/reporter
- title = JOB_ALT_REPORTER
- title_blurb = "The " + JOB_ALT_REPORTER + " uses the Library as a base of operations, from which they can report the news and goings-on on the station with their camera."
-
-/datum/alt_title/historian
- title = JOB_ALT_HISTORIAN
- title_blurb = "The " + JOB_ALT_HISTORIAN + " uses the Library as a base of operation to record any important events occurring on station."
-
-/datum/alt_title/archivist
- title = JOB_ALT_ARCHIVIST
- title_blurb = "The " + JOB_ALT_ARCHIVIST + " uses the Library as a base of operation to record any important events occurring on station."
-
-/datum/alt_title/professor
- title = JOB_ALT_PROFESSOR
- title_blurb = "The " + JOB_ALT_PROFESSOR + " uses the Library as a base of operations to share their vast knowledge with the crew."
-
-/datum/alt_title/academic
- title = JOB_ALT_ACADEMIC
- title_blurb = "The " + JOB_ALT_ACADEMIC + " uses the Library as a base of operations to share their vast knowledge with the crew."
-
-/datum/alt_title/philosopher
- title = JOB_ALT_PHILOSOPHER
- title_blurb = "The " + JOB_ALT_PHILOSOPHER + " uses the Library as a base of operation to ruminate on nature of life and other great questions, and share their opinions with the crew."
-
-/datum/alt_title/curator
- title = JOB_ALT_CURATOR
- title_blurb = "The " + JOB_ALT_CURATOR + " uses the Library as a base of operation to gather the finest of art for display and preservation."
-
-/datum/job/lawyer
- disallow_jobhop = TRUE
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_INTERNAL_AFFAIRS_LIAISON = /datum/alt_title/ia_liaison, JOB_ALT_INTERNAL_AFFAIRS_DELEGATE = /datum/alt_title/ia_delegate,
- JOB_ALT_INTERNAL_AFFAIRS_INVESTIGATOR = /datum/alt_title/ia_investigator)
-
-/datum/alt_title/ia_liaison
- title = JOB_ALT_INTERNAL_AFFAIRS_LIAISON
-
-/datum/alt_title/ia_delegate
- title = JOB_ALT_INTERNAL_AFFAIRS_DELEGATE
-
-/datum/alt_title/ia_investigator
- title = JOB_ALT_INTERNAL_AFFAIRS_INVESTIGATOR
-
-
-/datum/job/chaplain
- pto_type = PTO_CIVILIAN
- alt_titles = list(JOB_ALT_MISSIONARY = /datum/alt_title/missionary, JOB_ALT_PREACHER = /datum/alt_title/preacher, JOB_ALT_PRIEST = /datum/alt_title/priest,
- JOB_ALT_NUN = /datum/alt_title/nun, JOB_ALT_MONK = /datum/alt_title/monk, JOB_ALT_COUNSELOR = /datum/alt_title/counselor,
- JOB_ALT_GURU = /datum/alt_title/guru)
-
-/datum/alt_title/guru
- title = JOB_ALT_GURU
- title_blurb = "The " + JOB_ALT_GURU + " primarily tries to offer spiritual guidance to those who come seeking it."
-
-/datum/alt_title/missionary
- title = JOB_ALT_MISSIONARY
-
-/datum/alt_title/preacher
- title = JOB_ALT_PREACHER
-
-/datum/alt_title/priest
- title = JOB_ALT_PRIEST
-
-/datum/alt_title/nun
- title = JOB_ALT_NUN
-
-/datum/alt_title/monk
- title = JOB_ALT_MONK
-
-
-//////////////////////////////////
-// Pilot
-//////////////////////////////////
-
-/datum/job/pilot
- title = JOB_PILOT
- flag = PILOT
- departments = list(DEPARTMENT_CIVILIAN)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
- supervisors = "the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#515151"
- economic_modifier = 5
- minimal_player_age = 3
- pto_type = PTO_CIVILIAN
- access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot)
- minimal_access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot)
- outfit_type = /decl/hierarchy/outfit/job/pilot
- job_description = "A " + JOB_PILOT + " flies the various shuttles in the Virgo-Erigone System."
- alt_titles = list(JOB_ALT_COPILOT = /datum/alt_title/co_pilot, JOB_ALT_NAVIGATOR = /datum/alt_title/navigator, JOB_ALT_HELMSMAN = /datum/alt_title/helmsman)
-
-/datum/alt_title/co_pilot
- title = JOB_ALT_COPILOT
- title_blurb = "A Co-" + JOB_ALT_COPILOT + " is there primarily to assist main pilot as well as learn from them"
-
-/datum/alt_title/navigator
- title = JOB_ALT_NAVIGATOR
-
-/datum/alt_title/helmsman
- title = JOB_ALT_HELMSMAN
-
-/datum/job/pilot/get_request_reasons()
- return list("Assembling expedition team")
-
-//////////////////////////////////
-// Entertainer
-//////////////////////////////////
-
-/datum/job/entertainer
- title = JOB_ENTERTAINER
- flag = ENTERTAINER
- departments = list(DEPARTMENT_CIVILIAN)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 4
- spawn_positions = 4
- supervisors = "the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#515151"
- access = list(access_entertainment)
- minimal_access = list(access_entertainment)
- pto_type = PTO_CIVILIAN
-
- outfit_type = /decl/hierarchy/outfit/job/assistant/entertainer
- job_description = "An " + JOB_ENTERTAINER + " does just that, entertains! Put on plays, play music, sing songs, tell stories, or read your favorite fanfic."
- alt_titles = list(JOB_ALT_PERFORMER = /datum/alt_title/performer, JOB_ALT_MUSICIAN = /datum/alt_title/musician, JOB_ALT_STAGEHAND = /datum/alt_title/stagehand,
- JOB_ALT_ACTOR = /datum/alt_title/actor, JOB_ALT_DANCER = /datum/alt_title/dancer, JOB_ALT_SINGER = /datum/alt_title/singer,
- JOB_ALT_MAGICIAN = /datum/alt_title/magician, JOB_ALT_COMEDIAN = /datum/alt_title/comedian, JOB_ALT_ARTIST = /datum/alt_title/tragedian,
- JOB_ALT_ARTIST = /datum/alt_title/artist, JOB_ALT_GAME_MASTER = /datum/alt_title/game_master)
-
-// Entertainer Alt Titles
-/datum/alt_title/actor
- title = JOB_ALT_ACTOR
- title_blurb = "An " + JOB_ALT_ACTOR + " is someone who acts out a role! Whatever sort of character it is, get into it and impress people with power of comedy and tragedy!"
-
-/datum/alt_title/performer
- title = JOB_ALT_PERFORMER
- title_blurb = "A " + JOB_ALT_PERFORMER + " is someone who performs! Whatever sort of performance will come to your mind, the world's a stage!"
-
-/datum/alt_title/musician
- title = JOB_ALT_MUSICIAN
- title_blurb = "A " + JOB_ALT_MUSICIAN + " is someone who makes music with a wide variety of musical instruments!"
-
-/datum/alt_title/stagehand
- title = JOB_ALT_STAGEHAND
- title_blurb = "A " + JOB_ALT_STAGEHAND + " typically performs everything the rest of the entertainers don't. Operate lights, shutters, windows, or narrate through your voicebox!"
-
-/datum/alt_title/dancer
- title = JOB_ALT_DANCER
- title_blurb = "A " + JOB_ALT_DANCER + " is someone who impresses people through power of their own body! From waltz to breakdance, as long as crowd as cheering!"
-
-/datum/alt_title/singer
- title = JOB_ALT_SINGER
- title_blurb = "A " + JOB_ALT_SINGER + " is someone with gift of melodious voice! Impress people with your vocal range!"
-
-/datum/alt_title/magician
- title = JOB_ALT_MAGICIAN
- title_blurb = "A " + JOB_ALT_MAGICIAN + " is someone who awes those around them with impossible! Show off your repertoire of magic tricks, while keeping the secret hidden!"
-
-/datum/alt_title/comedian
- title = JOB_ALT_COMEDIAN
- title_blurb = "A " + JOB_ALT_COMEDIAN + " will focus on making people laugh with the power of wit! Telling jokes, stand-up comedy, you are here to make others smile!"
-
-/datum/alt_title/tragedian
- title = JOB_ALT_ARTIST
- title_blurb = "A " + JOB_ALT_ARTIST + " will focus on making people think about life and world around them! Life is a tragedy, and who's better to convey its emotions than you?"
-
-/datum/alt_title/artist
- title = JOB_ALT_ARTIST
- title_blurb = "An " + JOB_ALT_ARTIST + "'s calling is to create beautiful arts! Whatever form may they take, create and have people astonished with your creativity."
-
-/datum/alt_title/game_master
- title = JOB_ALT_GAME_MASTER
- title_blurb = "A " + JOB_ALT_GAME_MASTER + " provides recreation for the crew by hosting variety of games. From cards to roleplaying to something more personalized."
-
-//////////////////////////////////
-// Entrepreneur
-//////////////////////////////////
-
-/datum/job/entrepreneur
- title = JOB_ENTREPRENEUR
- flag = ENTREPRENEUR
- departments = list(DEPARTMENT_CIVILIAN)
- department_flag = CIVILIAN
- faction = FACTION_STATION
- total_positions = 4
- spawn_positions = 4
- supervisors = "the " + JOB_HEAD_OF_PERSONNEL
- selection_color = "#515151"
- access = list()
- minimal_access = list()
- pto_type = PTO_CIVILIAN
-
- outfit_type = /decl/hierarchy/outfit/job/assistant/entrepreneur
- job_description = "An " + JOB_ENTREPRENEUR + " is basically a visitor that obtained special permission to offer personal services to people on station. \
- They will offer people these services and, potentially, even demand payment!"
- alt_titles = list(JOB_ALT_LAWYER = /datum/alt_title/lawyer, JOB_ALT_PRIVATE_EYE = /datum/alt_title/private_eye, JOB_ALT_BODYGUARD = /datum/alt_title/bodyguard,
- JOB_ALT_PERSONAL_PHYSICIAN = /datum/alt_title/personal_physician, JOB_ALT_DENTIST = /datum/alt_title/dentist, JOB_ALT_FITNESS_INSTRUCTOR = /datum/alt_title/fitness_instructor,
- JOB_ALT_YOGA_TEACHER = /datum/alt_title/yoga_teacher, JOB_ALT_MASSEUSE = /datum/alt_title/masseuse, JOB_ALT_TRADESPERSON = /datum/alt_title/tradesperson,
- JOB_ALT_STREAMER = /datum/alt_title/streamer, JOB_ALT_INFLUENCER = /datum/alt_title/influencer, JOB_ALT_PARANORMAL_INVESTIGATOR = /datum/alt_title/paranormal_investigator,
- JOB_ALT_PERSONAL_SECRETARY = /datum/alt_title/personal_secretary, JOB_ALT_STYLIST = /datum/alt_title/stylist, JOB_ALT_FISHER = /datum/alt_title/fisher,
- JOB_ALT_FORTUNE_TELLER = /datum/alt_title/fortune_teller, JOB_ALT_SPIRIT_HEALER = /datum/alt_title/spirit_healer)
-
-/datum/alt_title/lawyer
- title = JOB_ALT_LAWYER
- title_blurb = "A " + JOB_ALT_LAWYER + " is knowledgable in various legal systems, including station's operations. They can try to offer their legal counsel, although nobody is really obliged to listen."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_secretary
-
-/datum/alt_title/private_eye
- title = JOB_ALT_PRIVATE_EYE
- title_blurb = "A " + JOB_ALT_PRIVATE_EYE + " is a detective that has no credentials or equipment. But if someone wants something found without security's knowledge, they are the one to go to."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/private_eye
-
-/datum/alt_title/bodyguard
- title = JOB_ALT_BODYGUARD
- title_blurb = "A " + JOB_ALT_BODYGUARD + " offers service of personal protection. They may not be allowed any weapons, but their own body is weapon enough."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/bodyguard
-
-/datum/alt_title/personal_physician
- title = JOB_ALT_PERSONAL_PHYSICIAN
- title_blurb = "A " + JOB_ALT_PERSONAL_PHYSICIAN + " is a doctor dedicated less to Hippocratic Oath and more to the moneymaking grind. Their license may be expired, but the grindset never will be."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_physician
-
-/datum/alt_title/dentist
- title = JOB_ALT_DENTIST
- title_blurb = "A " + JOB_ALT_DENTIST + " is a doctor that specializes in oral care. Company may not recognize them as a proper doctor, but surely their customers will."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/dentist
-
-/datum/alt_title/fitness_instructor
- title = JOB_ALT_FITNESS_INSTRUCTOR
- title_blurb = "A " + JOB_ALT_FITNESS_INSTRUCTOR + " dedicates themselves to improving the health of the crew through physical activity, and boy, do they need the help."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fitness_instructor
-
-/datum/alt_title/yoga_teacher
- title = JOB_ALT_YOGA_TEACHER
- title_blurb = "A " + JOB_ALT_YOGA_TEACHER + " is similar to a fitness instructor, but rather than turning the round bodies into firm ones, they focus on helping people find balance and harmony."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/yoga_teacher
-
-/datum/alt_title/masseuse
- title = JOB_ALT_MASSEUSE
- title_blurb = "A " + JOB_ALT_MASSEUSE + " is master of physical therapy and working others' bodies with their hands."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/masseuse
-
-/datum/alt_title/tradesperson
- title = JOB_ALT_TRADESPERSON
- title_blurb = "A " + JOB_ALT_TRADESPERSON + " is someone attempting to make money via the most obvious act of all - buying and selling. Now if only customs allowed you to bring your goods along..."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/tradesperson
-
-/datum/alt_title/streamer
- title = JOB_ALT_STREAMER
- title_blurb = "A " + JOB_ALT_STREAMER + " is here to entertain. Not the crew! Their audience across exonet!"
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/streamer
-
-/datum/alt_title/influencer
- title = JOB_ALT_INFLUENCER
- title_blurb = "An " + JOB_ALT_INFLUENCER + " has lucked out with some exonet following, and was given permission to go onstation to provide free exposure. Don't let it go to your head."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/influencer
-
-/datum/alt_title/paranormal_investigator
- title = JOB_ALT_PARANORMAL_INVESTIGATOR
- title_blurb = "A " + JOB_ALT_PARANORMAL_INVESTIGATOR + " looks beyond what is accepted by modern science, and searches for the true unknown. Aliens, alternate dimensions, ghosts... The truth is out there!"
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/paranormal_investigator
-
-/datum/alt_title/personal_secretary
- title = JOB_ALT_PERSONAL_SECRETARY
- title_blurb = "A " + JOB_ALT_PERSONAL_SECRETARY + " offers services of general assistance. Although it's doubtful anyone will ever actually need those."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/personal_secretary
-
-/datum/alt_title/stylist
- title = JOB_ALT_STYLIST
- title_blurb = "A " + JOB_ALT_STYLIST + " offers fashion advice, as well as helps with adjusting appearance of the crew to better suit their beauty standards."
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/stylist
-
-/datum/alt_title/fisher
- title = JOB_ALT_FISHER
- title_blurb = "A " + JOB_ALT_FISHER + " is a capable angler, who is good at obtaining large amounts of marine goods. Whether you generously give them to station or attempt to make a quick thaler by selling, it's up to you!"
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fisher
-
-/datum/alt_title/fortune_teller
- title = JOB_ALT_FORTUNE_TELLER
- title_blurb = "A " + JOB_ALT_FORTUNE_TELLER + " peers into the future, and offers these visions to others. Occasionally those visions may even come true!"
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/fortune_teller
-
-/datum/alt_title/spirit_healer
- title = JOB_ALT_SPIRIT_HEALER
- title_blurb = "A " + JOB_ALT_SPIRIT_HEALER + " offers alternative forms of medicine. Rituals, magic rocks, seances... It totally works. What's that about placebo?"
- title_outfit = /decl/hierarchy/outfit/job/assistant/entrepreneur/spirit_healer
diff --git a/code/game/jobs/job/department.dm b/code/game/jobs/job/department.dm
index 47d6de97ad1..87ad819e242 100644
--- a/code/game/jobs/job/department.dm
+++ b/code/game/jobs/job/department.dm
@@ -60,7 +60,7 @@
name = "Miscellaneous"
short_name = "Misc"
color = "#666666"
- sorting_order = 0
+ sorting_order = -5
assignable = FALSE
/datum/department/synthetic
diff --git a/code/game/jobs/job/department_vr.dm b/code/game/jobs/job/department_vr.dm
deleted file mode 100644
index 2af1d8e94fe..00000000000
--- a/code/game/jobs/job/department_vr.dm
+++ /dev/null
@@ -1,6 +0,0 @@
-/datum/department/misc
- name = "Off-Duty"
- short_name = "Offduty"
- color = "#666666"
- sorting_order = -5
- assignable = FALSE
\ No newline at end of file
diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm
index 576739d659b..ed05478e97d 100644
--- a/code/game/jobs/job/engineering.dm
+++ b/code/game/jobs/job/engineering.dm
@@ -22,15 +22,20 @@
ideal_age_by_species = list(SPECIES_UNATHI = 140, "mechanical" = 20, SPECIES_HUMAN_VATBORN = 20)
banned_job_species = list(SPECIES_TESHARI, SPECIES_DIONA, SPECIES_PROMETHEAN, SPECIES_ZADDAT, "digital")
+ disallow_jobhop = TRUE
+ pto_type = PTO_ENGINEERING
+ dept_time_required = 60
access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
- access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
- access_heads, access_construction, access_sec_doors,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload)
+ access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
+ access_heads, access_construction,
+ access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
+
minimal_access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
- access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
- access_heads, access_construction, access_sec_doors,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload)
+ access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
+ access_heads, access_construction,
+ access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
+ alt_titles = list(JOB_ALT_HEAD_ENGINEER = /datum/alt_title/head_engineer, JOB_ALT_FOREMAN = /datum/alt_title/foreman, JOB_ALT_MAINTENANCE_MANAGER = /datum/alt_title/maintenance_manager)
minimal_player_age = 7
outfit_type = /decl/hierarchy/outfit/job/engineering/chief_engineer
@@ -38,6 +43,18 @@
of manpower as much as they handle hands-on operations and repairs. They are also expected to keep the rest of the station informed of \
any structural threats to the station that may be hazardous to health or disruptive to work."
+/datum/job/chief_engineer/get_request_reasons()
+ return list("Engine setup", "Construction project", "Repairs necessary", "Training crew", "Assembling expedition team")
+
+/datum/alt_title/head_engineer
+ title = JOB_ALT_HEAD_ENGINEER
+
+/datum/alt_title/foreman
+ title = JOB_ALT_FOREMAN
+
+/datum/alt_title/maintenance_manager
+ title = JOB_ALT_MAINTENANCE_MANAGER
+
//////////////////////////////////
// Engineer
//////////////////////////////////
@@ -52,10 +69,12 @@
supervisors = "the "+ JOB_CHIEF_ENGINEER
selection_color = "#5B4D20"
economic_modifier = 5
+ pto_type = PTO_ENGINEERING
+
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)
+ 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_SALVAGE_TECHNICIAN = /datum/alt_title/salvage_tech)
minimal_player_age = 3
min_age_by_species = list(SPECIES_PROMETHEAN = 2)
@@ -64,6 +83,9 @@
job_description = "An " + JOB_ENGINEER + " keeps the station running. They repair damages, keep the atmosphere stable, and ensure that power is being \
generated and distributed. On quiet shifts, they may be called upon to make cosmetic alterations to the station."
+/datum/job/engineer/get_request_reasons()
+ return list("Engine setup", "Construction project", "Repairs necessary", "Assembling expedition team")
+
// Engineer Alt Titles
/datum/alt_title/maint_tech
title = JOB_ALT_MAINTENANCE_TECHNICIAN
@@ -80,6 +102,23 @@
title_blurb = "An " + JOB_ALT_ELECTRICIAN + "'s primary duty is making sure power is properly distributed thoughout the station, utilizing solars, substations, and other \
methods to ensure every department has power in an emergency."
+/datum/alt_title/construction_engi
+ title = JOB_ALT_CONSTRUCTION_ENGINEER
+ title_blurb = "A " + JOB_ALT_CONSTRUCTION_ENGINEER + " fulfills similar duties to other engineers, but usually occupies spare time with construction of extra facilities in dedicated areas or \
+ as additions to station layout."
+
+/datum/alt_title/engineering_contractor
+ title = JOB_ALT_ENGINEERING_CONTRACTOR
+ title_blurb = "An " + JOB_ALT_ENGINEERING_CONTRACTOR + " fulfills similar duties to other engineers, but isn't directly employed by NT proper."
+
+/datum/alt_title/computer_tech
+ title = JOB_ALT_COMPUTER_TECHNICIAN
+ title_blurb = "A " + JOB_ALT_COMPUTER_TECHNICIAN + " fulfills similar duties to other engineers, but specializes in working with software and computers. They also often deal with integrated circuits."
+
+/datum/alt_title/salvage_tech
+ title = JOB_ALT_SALVAGE_TECHNICIAN
+ title_blurb = "A " + JOB_ALT_SALVAGE_TECHNICIAN + " is responsible for breaking down debris and obsolete equipment to recover useful components and materials."
+
//////////////////////////////////
// Atmos Tech
//////////////////////////////////
@@ -90,16 +129,36 @@
department_flag = ENGSEC
faction = FACTION_STATION
total_positions = 3
- spawn_positions = 2
+ spawn_positions = 3
+ pto_type = PTO_ENGINEERING
supervisors = "the " + JOB_CHIEF_ENGINEER
selection_color = "#5B4D20"
economic_modifier = 5
access = list(access_eva, access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels, access_external_airlocks, access_construction, access_atmospherics, access_external_airlocks)
minimal_access = list(access_eva, access_engine, access_atmospherics, access_maint_tunnels, access_emergency_storage, access_construction, access_external_airlocks)
+ alt_titles = list(JOB_ALT_ATMOSPHERIC_ENGINEER = /datum/alt_title/atmos_engi, JOB_ALT_ATMOSPHERIC_MAINTAINER = /datum/alt_title/atmos_maint, JOB_ALT_DISPOSALS_TECHNICIAN = /datum/alt_title/disposals_tech,
+ JOB_ALT_FUEL_TECHNICIAN = /datum/alt_title/refuel_tech)
+
minimal_player_age = 3
min_age_by_species = list(SPECIES_PROMETHEAN = 2)
outfit_type = /decl/hierarchy/outfit/job/engineering/atmos
job_description = "An " + JOB_ATMOSPHERIC_TECHNICIAN + " is primarily concerned with keeping the station's atmosphere breathable. They are expected to have a good \
understanding of the pipes, vents, and scrubbers that move gasses around the station, and to be familiar with proper firefighting procedure."
+
+/datum/job/atmos/get_request_reasons()
+ return list("Construction project", "Repairs necessary", "Assembling expedition team")
+
+/datum/alt_title/refuel_tech
+ title = JOB_ALT_FUEL_TECHNICIAN
+
+/datum/alt_title/atmos_maint
+ title = JOB_ALT_ATMOSPHERIC_MAINTAINER
+
+/datum/alt_title/atmos_engi
+ title = JOB_ALT_ATMOSPHERIC_ENGINEER
+
+/datum/alt_title/disposals_tech
+ title = JOB_ALT_DISPOSALS_TECHNICIAN
+ title_blurb = "A " + JOB_ALT_DISPOSALS_TECHNICIAN + " is an " + JOB_ATMOSPHERIC_TECHNICIAN + " still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."
diff --git a/code/game/jobs/job/engineering_vr.dm b/code/game/jobs/job/engineering_vr.dm
deleted file mode 100644
index 17b70731dbd..00000000000
--- a/code/game/jobs/job/engineering_vr.dm
+++ /dev/null
@@ -1,71 +0,0 @@
-/datum/job/chief_engineer
- disallow_jobhop = TRUE
- pto_type = PTO_ENGINEERING
- dept_time_required = 60
-
- access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
- access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
- access_heads, access_construction,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
-
- minimal_access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
- access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
- access_heads, access_construction,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
- alt_titles = list(JOB_ALT_HEAD_ENGINEER = /datum/alt_title/head_engineer, JOB_ALT_FOREMAN = /datum/alt_title/foreman, JOB_ALT_MAINTENANCE_MANAGER = /datum/alt_title/maintenance_manager)
-
-/datum/alt_title/head_engineer
- title = JOB_ALT_HEAD_ENGINEER
-
-/datum/alt_title/foreman
- title = JOB_ALT_FOREMAN
-
-/datum/alt_title/maintenance_manager
- title = JOB_ALT_MAINTENANCE_MANAGER
-
-/datum/job/chief_engineer/get_request_reasons()
- return list("Engine setup", "Construction project", "Repairs necessary", "Training crew", "Assembling expedition team")
-
-
-/datum/job/engineer
- pto_type = PTO_ENGINEERING
- 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)
-
-/datum/alt_title/construction_engi
- title = JOB_ALT_CONSTRUCTION_ENGINEER
- title_blurb = "A " + JOB_ALT_CONSTRUCTION_ENGINEER + " fulfills similar duties to other engineers, but usually occupies spare time with construction of extra facilities in dedicated areas or \
- as additions to station layout."
-
-/datum/alt_title/engineering_contractor
- title = JOB_ALT_ENGINEERING_CONTRACTOR
- title_blurb = "An " + JOB_ALT_ENGINEERING_CONTRACTOR + " fulfills similar duties to other engineers, but isn't directly employed by NT proper."
-
-/datum/job/engineer/get_request_reasons()
- return list("Engine setup", "Construction project", "Repairs necessary", "Assembling expedition team")
-
-/datum/alt_title/computer_tech
- title = JOB_ALT_COMPUTER_TECHNICIAN
- title_blurb = "A " + JOB_ALT_COMPUTER_TECHNICIAN + " fulfills similar duties to other engineers, but specializes in working with software and computers. They also often deal with integrated circuits."
-
-/datum/job/atmos
- spawn_positions = 3
- pto_type = PTO_ENGINEERING
- alt_titles = list(JOB_ALT_ATMOSPHERIC_ENGINEER = /datum/alt_title/atmos_engi, JOB_ALT_ATMOSPHERIC_MAINTAINER = /datum/alt_title/atmos_maint, JOB_ALT_DISPOSALS_TECHNICIAN = /datum/alt_title/disposals_tech,
- JOB_ALT_FUEL_TECHNICIAN = /datum/alt_title/refuel_tech)
-
-/datum/alt_title/atmos_maint
- title = JOB_ALT_ATMOSPHERIC_MAINTAINER
-
-/datum/alt_title/atmos_engi
- title = JOB_ALT_ATMOSPHERIC_ENGINEER
-
-/datum/alt_title/disposals_tech
- title = JOB_ALT_DISPOSALS_TECHNICIAN
- title_blurb = "A " + JOB_ALT_DISPOSALS_TECHNICIAN + " is an " + JOB_ATMOSPHERIC_TECHNICIAN + " still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."
-
-/datum/alt_title/refuel_tech
- title = JOB_ALT_FUEL_TECHNICIAN
-
-/datum/job/atmos/get_request_reasons()
- return list("Construction project", "Repairs necessary", "Assembling expedition team")
diff --git a/code/game/jobs/job/exploration_vr.dm b/code/game/jobs/job/exploration.dm
similarity index 100%
rename from code/game/jobs/job/exploration_vr.dm
rename to code/game/jobs/job/exploration.dm
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index b191d670722..d01d60e4be9 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -39,6 +39,29 @@
// Description of the job's role and minimum responsibilities.
var/job_description = "This Job doesn't have a description! Please report it!"
+ //Requires a ckey to be whitelisted in jobwhitelist.txt
+ var/whitelist_only = 0
+
+ //Does not display this job on the occupation setup screen
+ var/latejoin_only = 0
+
+ //Every hour playing this role gains this much time off. (Can be negative for off duty jobs!)
+ var/timeoff_factor = 3
+
+ //What type of PTO is that job earning?
+ var/pto_type
+
+ //Disallow joining as this job midround from off-duty position via going on-duty
+ var/disallow_jobhop = FALSE
+
+ //Time required in the department as other jobs before playing this one (in hours)
+ var/dept_time_required = 0
+
+ //Do we forbid ourselves from earning PTO?
+ var/playtime_only = FALSE
+
+ var/requestable = TRUE
+
/datum/job/New()
. = ..()
department_accounts = department_accounts || departments_managed
@@ -184,3 +207,47 @@
if(brain_type in banned_job_species)
return TRUE
*/
+
+
+// Check client-specific availability rules.
+/datum/job/proc/player_has_enough_pto(client/C)
+ return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, pto_type) > 0)
+
+/datum/job/proc/player_has_enough_playtime(client/C)
+ return (available_in_playhours(C) == 0)
+
+/datum/job/proc/available_in_playhours(client/C)
+ if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
+ if(isnum(C.play_hours[pto_type])) // Has played that department before
+ return max(0, dept_time_required - C.play_hours[pto_type])
+ else // List doesn't have that entry, maybe never played, maybe invalid PTO type (you should fix that...)
+ return dept_time_required // Could be 0, too, which is fine! They can play that
+ return 0
+
+// Special treatment for some the more complicated heads
+
+// Captain gets every department combined
+/datum/job/captain/available_in_playhours(client/C)
+ if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
+ var/remaining_time_needed = dept_time_required
+ for(var/key in C.play_hours)
+ if(isnum(C.play_hours[key]) && !(key == PTO_TALON))
+ remaining_time_needed = max(0, remaining_time_needed - C.play_hours[key])
+ return remaining_time_needed
+ return 0
+
+// HoP gets civilian, cargo, and exploration combined
+/datum/job/hop/available_in_playhours(client/C)
+ if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
+ var/remaining_time_needed = dept_time_required
+ if(isnum(C.play_hours[PTO_CIVILIAN]))
+ remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_CIVILIAN])
+ if(isnum(C.play_hours[PTO_CARGO]))
+ remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_CARGO])
+ if(isnum(C.play_hours[PTO_EXPLORATION]))
+ remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_EXPLORATION])
+ return remaining_time_needed
+ return 0
+
+/datum/job/proc/get_request_reasons()
+ return list()
diff --git a/code/game/jobs/job/job_vr.dm b/code/game/jobs/job/job_vr.dm
deleted file mode 100644
index 3796714b5ea..00000000000
--- a/code/game/jobs/job/job_vr.dm
+++ /dev/null
@@ -1,66 +0,0 @@
-/datum/job
- //Requires a ckey to be whitelisted in jobwhitelist.txt
- var/whitelist_only = 0
-
- //Does not display this job on the occupation setup screen
- var/latejoin_only = 0
-
- //Every hour playing this role gains this much time off. (Can be negative for off duty jobs!)
- var/timeoff_factor = 3
-
- //What type of PTO is that job earning?
- var/pto_type
-
- //Disallow joining as this job midround from off-duty position via going on-duty
- var/disallow_jobhop = FALSE
-
- //Time required in the department as other jobs before playing this one (in hours)
- var/dept_time_required = 0
-
- //Do we forbid ourselves from earning PTO?
- var/playtime_only = FALSE
-
- var/requestable = TRUE
-
-// Check client-specific availability rules.
-/datum/job/proc/player_has_enough_pto(client/C)
- return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, pto_type) > 0)
-
-/datum/job/proc/player_has_enough_playtime(client/C)
- return (available_in_playhours(C) == 0)
-
-/datum/job/proc/available_in_playhours(client/C)
- if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
- if(isnum(C.play_hours[pto_type])) // Has played that department before
- return max(0, dept_time_required - C.play_hours[pto_type])
- else // List doesn't have that entry, maybe never played, maybe invalid PTO type (you should fix that...)
- return dept_time_required // Could be 0, too, which is fine! They can play that
- return 0
-
-// Special treatment for some the more complicated heads
-
-// Captain gets every department combined
-/datum/job/captain/available_in_playhours(client/C)
- if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
- var/remaining_time_needed = dept_time_required
- for(var/key in C.play_hours)
- if(isnum(C.play_hours[key]) && !(key == PTO_TALON))
- remaining_time_needed = max(0, remaining_time_needed - C.play_hours[key])
- return remaining_time_needed
- return 0
-
-// HoP gets civilian, cargo, and exploration combined
-/datum/job/hop/available_in_playhours(client/C)
- if(C && CONFIG_GET(flag/use_playtime_restriction_for_jobs) && dept_time_required)
- var/remaining_time_needed = dept_time_required
- if(isnum(C.play_hours[PTO_CIVILIAN]))
- remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_CIVILIAN])
- if(isnum(C.play_hours[PTO_CARGO]))
- remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_CARGO])
- if(isnum(C.play_hours[PTO_EXPLORATION]))
- remaining_time_needed = max(0, remaining_time_needed - C.play_hours[PTO_EXPLORATION])
- return remaining_time_needed
- return 0
-
-/datum/job/proc/get_request_reasons()
- return list()
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index 9298028eb96..c8a96efad98 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -16,11 +16,13 @@
req_admin_notify = 1
economic_modifier = 10
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
- access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
+ access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
+ access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
+
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
- access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
+ access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
+ access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
+ alt_titles = list(JOB_ALT_CHIEF_PHYSICIAN = /datum/alt_title/chief_physician, JOB_ALT_MEDICAL_DIRECTOR = /datum/alt_title/medical_director, JOB_ALT_HEALTHCARE_MANAGER = /datum/alt_title/healthcare_manager)
minimum_character_age = 25
min_age_by_species = list(SPECIES_UNATHI = 70, "mechanical" = 10, SPECIES_HUMAN_VATBORN = 14)
@@ -29,12 +31,28 @@
ideal_age_by_species = list(SPECIES_UNATHI = 140, "mechanical" = 20, SPECIES_HUMAN_VATBORN = 20)
banned_job_species = list(SPECIES_TESHARI, SPECIES_DIONA, SPECIES_PROMETHEAN, SPECIES_ZADDAT, "digital")
+ disallow_jobhop = TRUE
+ pto_type = PTO_MEDICAL
+ dept_time_required = 60
+
outfit_type = /decl/hierarchy/outfit/job/medical/cmo
job_description = "The CMO manages the Medical department and is a position requiring experience and skill; their goal is to ensure that their \
staff keep the station's crew healthy and whole. They are primarily interested in making sure that patients are safely found and \
transported to Medical for treatment. They are expected to keep the crew informed about threats to their health and safety, and \
about the importance of Suit Sensors."
+/datum/job/cmo/get_request_reasons()
+ return list("Surgery pending", "Viral outbreak", "Training crew", "Assembling expedition team")
+
+/datum/alt_title/chief_physician
+ title = JOB_ALT_CHIEF_PHYSICIAN
+
+/datum/alt_title/medical_director
+ title = JOB_ALT_MEDICAL_DIRECTOR
+
+/datum/alt_title/healthcare_manager
+ title = JOB_ALT_HEALTHCARE_MANAGER
+
//////////////////////////////////
// Medical Doctor
//////////////////////////////////
@@ -45,7 +63,8 @@
department_flag = MEDSCI
faction = FACTION_STATION
total_positions = 5
- spawn_positions = 3
+ spawn_positions = 5
+ pto_type = PTO_MEDICAL
supervisors = "the " + JOB_CHIEF_MEDICAL_OFFICER
selection_color = "#013D3B"
economic_modifier = 7
@@ -55,14 +74,15 @@
job_description = "A " + JOB_MEDICAL_DOCTOR + " is a Jack-of-All-Trades Medical title, covering a variety of skill levels and minor specializations. They are likely \
familiar with basic first aid, and a number of accompanying medications, and can generally save, if not cure, a majority of the \
patients they encounter."
- alt_titles = list(
- JOB_ALT_SURGEON = /datum/alt_title/surgeon,
- JOB_ALT_EMERGENCY_PHYSICIAN = /datum/alt_title/emergency_physician,
- JOB_ALT_NURSE = /datum/alt_title/nurse,
- JOB_ALT_VIROLOGIST = /datum/alt_title/virologist)
+ alt_titles = list(JOB_ALT_PHYSICIAN = /datum/alt_title/physician, JOB_ALT_MEDICAL_PRACTITIONER = /datum/alt_title/medical_practitioner, JOB_ALT_SURGEON = /datum/alt_title/surgeon,
+ JOB_ALT_EMERGENCY_PHYSICIAN = /datum/alt_title/emergency_physician, JOB_ALT_NURSE = /datum/alt_title/nurse, JOB_ALT_ORDERLY = /datum/alt_title/orderly,
+ JOB_ALT_VIROLOGIST = /datum/alt_title/virologist, JOB_ALT_MEDICAL_CONTRACTOR = /datum/alt_title/medical_contractor)
min_age_by_species = list(SPECIES_PROMETHEAN = 3)
+/datum/job/doctor/get_request_reasons()
+ return list("Surgery pending", "Viral outbreak", "Assembling expedition team")
+
//Medical Doctor Alt Titles
/datum/alt_title/surgeon
title = JOB_ALT_SURGEON
@@ -90,7 +110,22 @@
to produce the various types of virus foods or mutagens."
title_outfit = /decl/hierarchy/outfit/job/medical/doctor/virologist
-//Chemist is a medical job damnit //YEAH FUCK YOU SCIENCE -Pete //Guys, behave -Erro
+/datum/alt_title/physician
+ title = JOB_ALT_PHYSICIAN
+
+/datum/alt_title/medical_practitioner
+ title = JOB_ALT_MEDICAL_PRACTITIONER
+
+/datum/alt_title/orderly
+ title = JOB_ALT_ORDERLY
+ title_blurb = "An " + JOB_ALT_ORDERLY + " acts as Medbay's general helping hand, assisting any doctor that might need some form of help, as well as handling manual \
+ and dirty labor around the department."
+ title_outfit = /decl/hierarchy/outfit/job/medical/doctor/nurse
+
+/datum/alt_title/medical_contractor
+ title = JOB_ALT_MEDICAL_CONTRACTOR
+ title_blurb = "A " + JOB_ALT_MEDICAL_CONTRACTOR + " can be anything from a full-blown doctor to the likes of a nurse or orderly, but isn't directly employed by NT proper."
+
//////////////////////////////////
// Chemist
//////////////////////////////////
@@ -102,6 +137,7 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_MEDICAL
supervisors = "the " + JOB_CHIEF_MEDICAL_OFFICER
selection_color = "#013D3B"
economic_modifier = 5
@@ -113,13 +149,17 @@
outfit_type = /decl/hierarchy/outfit/job/medical/chemist
job_description = "A " + JOB_CHEMIST + " produces and maintains a stock of basic to advanced chemicals for medical and occasionally research use. \
They are likely to know the use and dangers of many lab-produced chemicals."
- alt_titles = list(JOB_ALT_PHARMACIST = /datum/alt_title/pharmacist)
+ alt_titles = list(JOB_ALT_PHARMACIST = /datum/alt_title/pharmacist, JOB_ALT_PHARMACOLOGIST = /datum/alt_title/pharmacologist)
// Chemist Alt Titles
/datum/alt_title/pharmacist
title = JOB_ALT_PHARMACIST
title_blurb = "A " + JOB_ALT_PHARMACIST + " focuses on the chemical needs of the Medical Department, and often offers to fill crew prescriptions at their discretion."
+/datum/alt_title/pharmacologist
+ title = JOB_ALT_PHARMACOLOGIST
+ title_blurb = "A " + JOB_ALT_PHARMACOLOGIST + " focuses on the chemical needs of the Medical Department, primarily specializing in producing more advanced forms of medicine."
+
/* I'm commenting out Geneticist so you can't actually see it in the job menu, given that you can't play as one - Jon.
//////////////////////////////////
// Geneticist
@@ -154,6 +194,7 @@
faction = FACTION_STATION
total_positions = 1
spawn_positions = 1
+ pto_type = PTO_MEDICAL
economic_modifier = 5
supervisors = "the " + JOB_CHIEF_MEDICAL_OFFICER
selection_color = "#013D3B"
@@ -162,7 +203,7 @@
outfit_type = /decl/hierarchy/outfit/job/medical/psychiatrist
job_description = "A " + JOB_PSYCHIATRIST + " provides mental health services to crew members in need. They may also be called upon to determine whatever \
ails the mentally unwell, frequently under Security supervision. They understand the effects of various psychoactive drugs."
- alt_titles = list(JOB_ALT_PSYCHOLOGIST = /datum/alt_title/psychologist)
+ alt_titles = list(JOB_ALT_PSYCHOLOGIST = /datum/alt_title/psychologist, JOB_ALT_PSYCHOANALYST = /datum/alt_title/psychoanalyst, JOB_ALT_PSYCHOTHERAPIST = /datum/alt_title/psychotherapist)
banned_job_species = list(SPECIES_PROMETHEAN, SPECIES_DIONA)
//Psychiatrist Alt Titles
@@ -172,6 +213,18 @@
called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
+/datum/alt_title/psychoanalyst
+ title = JOB_ALT_PSYCHOANALYST
+ title_blurb = "A " + JOB_ALT_PSYCHOANALYST + " provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
+ called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
+ title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
+
+/datum/alt_title/psychotherapist
+ title = JOB_ALT_PSYCHOTHERAPIST
+ title_blurb = "A " + JOB_ALT_PSYCHOTHERAPIST + " provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
+ called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
+ title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
+
//////////////////////////////////
// Paramedic
//////////////////////////////////
@@ -181,8 +234,9 @@
departments = list(DEPARTMENT_MEDICAL)
department_flag = MEDSCI
faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
+ total_positions = 3
+ spawn_positions = 3
+ pto_type = PTO_MEDICAL
supervisors = "the " + JOB_CHIEF_MEDICAL_OFFICER
selection_color = "#013D3B"
economic_modifier = 4
@@ -191,14 +245,26 @@
outfit_type = /decl/hierarchy/outfit/job/medical/paramedic
job_description = "A " + JOB_PARAMEDIC + " is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their own. \
They may also be called upon to keep patients stable when Medical is busy or understaffed."
- alt_titles = list(JOB_ALT_EMERGENCY_MEDICAL_TECHNICIAN = /datum/alt_title/emt)
+ alt_titles = list(JOB_ALT_EMERGENCY_MEDICAL_TECHNICIAN = /datum/alt_title/emt, JOB_ALT_MEDICAL_RESPONDER = /datum/alt_title/medical_responder, JOB_ALT_SEARCH_AND_RESCUE = /datum/alt_title/sar)
banned_job_species = list(SPECIES_DIONA)
min_age_by_species = list(SPECIES_PROMETHEAN = 2)
+/datum/job/paramedic/get_request_reasons()
+ return list("Assembling expedition team")
+
// Paramedic Alt Titles
/datum/alt_title/emt
title = JOB_ALT_EMERGENCY_MEDICAL_TECHNICIAN
title_blurb = "An " + JOB_ALT_EMERGENCY_MEDICAL_TECHNICIAN + " is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their \
own. They are capable of keeping a patient stabilized until they reach the hands of someone with more training."
title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt
+
+/datum/alt_title/medical_responder
+ title = JOB_ALT_MEDICAL_RESPONDER
+ title_blurb = "A " + JOB_ALT_MEDICAL_RESPONDER + " is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their \
+ own. They are capable of keeping a patient stabilized until they reach the hands of someone with more training."
+ title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt
+
+/datum/alt_title/sar
+ title = JOB_ALT_SEARCH_AND_RESCUE
diff --git a/code/game/jobs/job/medical_vr.dm b/code/game/jobs/job/medical_vr.dm
deleted file mode 100644
index 9d08fdfcf29..00000000000
--- a/code/game/jobs/job/medical_vr.dm
+++ /dev/null
@@ -1,97 +0,0 @@
-/datum/job/cmo
- disallow_jobhop = TRUE
- pto_type = PTO_MEDICAL
- dept_time_required = 60
-
- access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
- access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
-
- minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
- access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
- alt_titles = list(JOB_ALT_CHIEF_PHYSICIAN = /datum/alt_title/chief_physician, JOB_ALT_MEDICAL_DIRECTOR = /datum/alt_title/medical_director, JOB_ALT_HEALTHCARE_MANAGER = /datum/alt_title/healthcare_manager)
-
-/datum/alt_title/chief_physician
- title = JOB_ALT_CHIEF_PHYSICIAN
-
-/datum/alt_title/medical_director
- title = JOB_ALT_MEDICAL_DIRECTOR
-
-/datum/alt_title/healthcare_manager
- title = JOB_ALT_HEALTHCARE_MANAGER
-
-/datum/job/cmo/get_request_reasons()
- return list("Surgery pending", "Viral outbreak", "Training crew", "Assembling expedition team")
-
-
-/datum/job/doctor
- spawn_positions = 5
- pto_type = PTO_MEDICAL
- alt_titles = list(JOB_ALT_PHYSICIAN = /datum/alt_title/physician, JOB_ALT_MEDICAL_PRACTITIONER = /datum/alt_title/medical_practitioner, JOB_ALT_SURGEON = /datum/alt_title/surgeon,
- JOB_ALT_EMERGENCY_PHYSICIAN = /datum/alt_title/emergency_physician, JOB_ALT_NURSE = /datum/alt_title/nurse, JOB_ALT_ORDERLY = /datum/alt_title/orderly,
- JOB_ALT_VIROLOGIST = /datum/alt_title/virologist, JOB_ALT_MEDICAL_CONTRACTOR = /datum/alt_title/medical_contractor)
-
-/datum/alt_title/physician
- title = JOB_ALT_PHYSICIAN
-
-/datum/alt_title/medical_practitioner
- title = JOB_ALT_MEDICAL_PRACTITIONER
-
-/datum/alt_title/orderly
- title = JOB_ALT_ORDERLY
- title_blurb = "An " + JOB_ALT_ORDERLY + " acts as Medbay's general helping hand, assisting any doctor that might need some form of help, as well as handling manual \
- and dirty labor around the department."
- title_outfit = /decl/hierarchy/outfit/job/medical/doctor/nurse
-
-/datum/alt_title/medical_contractor
- title = JOB_ALT_MEDICAL_CONTRACTOR
- title_blurb = "A " + JOB_ALT_MEDICAL_CONTRACTOR + " can be anything from a full-blown doctor to the likes of a nurse or orderly, but isn't directly employed by NT proper."
-
-/datum/job/doctor/get_request_reasons()
- return list("Surgery pending", "Viral outbreak", "Assembling expedition team")
-
-
-/datum/job/chemist
- pto_type = PTO_MEDICAL
- alt_titles = list(JOB_ALT_PHARMACIST = /datum/alt_title/pharmacist, JOB_ALT_PHARMACOLOGIST = /datum/alt_title/pharmacologist)
-
-/datum/alt_title/pharmacologist
- title = JOB_ALT_PHARMACOLOGIST
- title_blurb = "A " + JOB_ALT_PHARMACOLOGIST + " focuses on the chemical needs of the Medical Department, primarily specializing in producing more advanced forms of medicine."
-
-
-/datum/job/psychiatrist
- pto_type = PTO_MEDICAL
- alt_titles = list(JOB_ALT_PSYCHOLOGIST = /datum/alt_title/psychologist, JOB_ALT_PSYCHOANALYST = /datum/alt_title/psychoanalyst, JOB_ALT_PSYCHOTHERAPIST = /datum/alt_title/psychotherapist)
-
-/datum/alt_title/psychoanalyst
- title = JOB_ALT_PSYCHOANALYST
- title_blurb = "A " + JOB_ALT_PSYCHOANALYST + " provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
- called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
- title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
-
-/datum/alt_title/psychotherapist
- title = JOB_ALT_PSYCHOTHERAPIST
- title_blurb = "A " + JOB_ALT_PSYCHOTHERAPIST + " provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
- called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
- title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
-
-
-/datum/job/paramedic
- pto_type = PTO_MEDICAL
- alt_titles = list(JOB_ALT_EMERGENCY_MEDICAL_TECHNICIAN = /datum/alt_title/emt, JOB_ALT_MEDICAL_RESPONDER = /datum/alt_title/medical_responder, JOB_ALT_SEARCH_AND_RESCUE = /datum/alt_title/sar)
- total_positions = 3
- spawn_positions = 3
-
-/datum/alt_title/medical_responder
- title = JOB_ALT_MEDICAL_RESPONDER
- title_blurb = "A " + JOB_ALT_MEDICAL_RESPONDER + " is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their \
- own. They are capable of keeping a patient stabilized until they reach the hands of someone with more training."
- title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt
-
-/datum/alt_title/sar
- title = JOB_ALT_SEARCH_AND_RESCUE
-
-/datum/job/paramedic/get_request_reasons()
- return list("Assembling expedition team")
diff --git a/code/game/jobs/job/offduty_vr.dm b/code/game/jobs/job/offduty.dm
similarity index 100%
rename from code/game/jobs/job/offduty_vr.dm
rename to code/game/jobs/job/offduty.dm
diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm
index c67dbe59ad3..a7d158ec30b 100644
--- a/code/game/jobs/job/science.dm
+++ b/code/game/jobs/job/science.dm
@@ -16,13 +16,13 @@
req_admin_notify = 1
economic_modifier = 15
access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
- access_tox_storage, access_teleporter, access_sec_doors,
+ access_tox_storage, access_teleporter,
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
- access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_network)
+ access_RC_announce, access_keycard_auth, access_tcomsat, access_xenoarch, access_eva, access_network, access_xenobotany)
minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
- access_tox_storage, access_teleporter, access_sec_doors,
+ access_tox_storage, access_teleporter,
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
- access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_network)
+ access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_eva, access_network, access_xenobotany)
minimum_character_age = 25
minimal_player_age = 14
@@ -30,19 +30,34 @@
ideal_character_age = 50
ideal_age_by_species = list(SPECIES_UNATHI = 140, "mechanical" = 20, SPECIES_HUMAN_VATBORN = 20)
banned_job_species = list(SPECIES_TESHARI, SPECIES_DIONA, SPECIES_PROMETHEAN, SPECIES_ZADDAT, "digital")
+ disallow_jobhop = TRUE
+ pto_type = PTO_SCIENCE
+ dept_time_required = 60
outfit_type = /decl/hierarchy/outfit/job/science/rd
job_description = "The " + JOB_RESEARCH_DIRECTOR + " manages and maintains the Research department. They are required to ensure the safety of the entire crew, \
at least with regards to anything occurring in the Research department, and to inform the crew of any disruptions that \
might originate from Research. The " + JOB_RESEARCH_DIRECTOR + " often has at least passing knowledge of most of the Research department, but \
are encouraged to allow their staff to perform their own duties."
- alt_titles = list(JOB_ALT_RESEARCH_SUPERVISOR = /datum/alt_title/research_supervisor)
+ alt_titles = list(JOB_ALT_RESEARCH_SUPERVISOR = /datum/alt_title/research_supervisor, JOB_ALT_RESEARCH_MANAGER = /datum/alt_title/research_manager,
+ JOB_ALT_HEAD_OF_DEVELOPMENT = /datum/alt_title/head_of_development,JOB_ALT_HEAD_SCIENTIST = /datum/alt_title/head_scientist)
+/datum/job/rd/get_request_reasons()
+ return list("Repairs needed", "Training crew", "Assembling expedition team")
// " + JOB_RESEARCH_DIRECTOR + " Alt Titles
/datum/alt_title/research_supervisor
title = JOB_ALT_RESEARCH_SUPERVISOR
+/datum/alt_title/research_manager
+ title = JOB_ALT_RESEARCH_MANAGER
+
+/datum/alt_title/head_of_development
+ title = JOB_ALT_HEAD_OF_DEVELOPMENT
+
+/datum/alt_title/head_scientist
+ title = JOB_ALT_HEAD_SCIENTIST
+
//////////////////////////////////
// Scientist
//////////////////////////////////
@@ -53,11 +68,12 @@
department_flag = MEDSCI
faction = FACTION_STATION
total_positions = 5
- spawn_positions = 3
+ spawn_positions = 5
+ pto_type = PTO_SCIENCE
supervisors = "the " + JOB_RESEARCH_DIRECTOR
selection_color = "#633D63"
economic_modifier = 7
- access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch)
+ access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_xenobotany)
minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch)
min_age_by_species = list(SPECIES_PROMETHEAN = 2)
banned_job_species = list("digital")
@@ -68,8 +84,12 @@
job_description = "A " + JOB_SCIENTIST + " is a generalist working in the Research department, with general knowledge of the scientific process, as well as \
the principles and requirements of Research and Development. They may also formulate experiments of their own devising, if \
they find an appropriate topic."
- alt_titles = list(JOB_ALT_XENOARCHAEOLOGIST = /datum/alt_title/xenoarch, JOB_ALT_ANOMALIST = /datum/alt_title/anomalist, \
- JOB_ALT_PHORON_RESEARCHER = /datum/alt_title/phoron_research)
+ alt_titles = list(JOB_ALT_RESEARCHER = /datum/alt_title/researcher, JOB_ALT_LAB_ASSISTANT = /datum/alt_title/lab_assistant, JOB_ALT_XENOARCHAEOLOGIST = /datum/alt_title/xenoarch,
+ JOB_ALT_XENOPALEONTOLOGIST = /datum/alt_title/xenopaleontologist, JOB_ALT_ANOMALIST = /datum/alt_title/anomalist, JOB_ALT_PHORON_RESEARCHER = /datum/alt_title/phoron_research,
+ JOB_ALT_GAS_PHYSICIST = /datum/alt_title/gas_physicist, JOB_ALT_CIRCUIT_DESIGNER = /datum/alt_title/circuit_designer, JOB_ALT_CIRCUIT_PROGRAMMER = /datum/alt_title/circuit_programmer)
+
+/datum/job/scientist/get_request_reasons()
+ return list("Assembling expedition team")
// Scientist Alt Titles
/datum/alt_title/xenoarch
@@ -88,6 +108,35 @@
Many " + JOB_ALT_PHORON_RESEARCHER + "s are interested in the combustability and explosive properties of gaseous phoron, as well as the specific hazards \
of working with the substance in that state."
+/datum/alt_title/researcher
+ title = JOB_ALT_RESEARCHER
+
+/datum/alt_title/lab_assistant
+ title = JOB_ALT_LAB_ASSISTANT
+ title_blurb = "A " + JOB_ALT_LAB_ASSISTANT + " is a lower-level member of research staff, whose main purpose is to help scientists with their specialized work in more menial fashion, while also \
+ learning the specializations in process."
+
+/datum/alt_title/xenopaleontologist
+ title = JOB_ALT_XENOPALEONTOLOGIST
+ title_blurb = "A " + JOB_ALT_XENOPALEONTOLOGIST + " enters digsites in search of fossils and other ancient remants of alien life. These digsites are frequently in vacuum or other inhospitable \
+ locations, and as such a " + JOB_ALT_XENOPALEONTOLOGIST + " should be prepared to handle hostile evironmental conditions."
+
+/datum/alt_title/gas_physicist
+ title = JOB_ALT_GAS_PHYSICIST
+ title_blurb = "A " + JOB_ALT_GAS_PHYSICIST + " is a specialist in various practical applications of gasses, but currently focuses their attention on phoron, and has knowledge of its practical uses and dangers. \
+ Many " + JOB_ALT_GAS_PHYSICIST + "s are interested in the combustability and explosive properties of gaseous phoron, as well as the specific hazards \
+ of working with the substance in that state."
+
+/datum/alt_title/circuit_designer
+ title = JOB_ALT_CIRCUIT_DESIGNER
+ title_blurb = "A " + JOB_ALT_CIRCUIT_DESIGNER + " is a " + JOB_SCIENTIST + " whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
+ They work to create various useful devices using the capabilities of integrated circuitry."
+
+/datum/alt_title/circuit_programmer
+ title = JOB_ALT_CIRCUIT_PROGRAMMER
+ title_blurb = "A " + JOB_ALT_CIRCUIT_PROGRAMMER + " is a " + JOB_SCIENTIST + " whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
+ They work to create various useful devices using the capabilities of integrated circuitry."
+
//////////////////////////////////
// Xenobiologist
//////////////////////////////////
@@ -98,7 +147,8 @@
department_flag = MEDSCI
faction = FACTION_STATION
total_positions = 3
- spawn_positions = 2
+ spawn_positions = 3
+ pto_type = PTO_SCIENCE
supervisors = "the " + JOB_RESEARCH_DIRECTOR
selection_color = "#633D63"
economic_modifier = 7
@@ -112,15 +162,21 @@
outfit_type = /decl/hierarchy/outfit/job/science/xenobiologist
job_description = "A " + JOB_XENOBIOLOGIST + " studies esoteric lifeforms, usually in the relative safety of their lab. They attempt to find ways to benefit \
from the byproducts of these lifeforms, and their main subject at present is the Giant Slime."
-/*VR edit start
- alt_titles = list(JOB_XENOBOTANIST = /datum/alt_title/xenobot)
- Xenibiologist Alt Titles
+ alt_titles = list(JOB_ALT_XENOZOOLOGIST = /datum/alt_title/xenozoologist, JOB_ALT_XENOANTHROPOLOGIST = /datum/alt_title/xenoanthropologist)
+
+// Xenobiologist Alt Titles
/datum/alt_title/xenobot
title = JOB_XENOBOTANIST
title_blurb = "A " + JOB_XENOBOTANIST + " grows and cares for a variety of abnormal, custom made, and frequently dangerous plant life. When the products of these plants \
is both safe and beneficial to the station, they may choose to introduce it to the rest of the crew."
-VR edit end*/
+
+/datum/alt_title/xenozoologist
+ title = JOB_ALT_XENOZOOLOGIST
+
+/datum/alt_title/xenoanthropologist
+ title = JOB_ALT_XENOANTHROPOLOGIST
+ title_blurb = JOB_ALT_XENOANTHROPOLOGIST + " still heavily focuses their study on alien lifeforms, but their specialty leans more towards fellow sapient beings than simple animals."
//////////////////////////////////
// Roboticist
@@ -131,8 +187,9 @@ VR edit end*/
departments = list(DEPARTMENT_RESEARCH)
department_flag = MEDSCI
faction = FACTION_STATION
- total_positions = 2
+ total_positions = 3
spawn_positions = 2
+ pto_type = PTO_SCIENCE
supervisors = "the " + JOB_RESEARCH_DIRECTOR
selection_color = "#633D63"
economic_modifier = 5
@@ -145,7 +202,14 @@ VR edit end*/
outfit_type = /decl/hierarchy/outfit/job/science/roboticist
job_description = "A " + JOB_ROBOTICIST + " maintains and repairs the station's synthetics, including crew with prosthetic limbs. \
They can also assist the station by producing simple robots and even pilotable exosuits."
- alt_titles = list(JOB_ALT_BIOMECHANICAL_ENGINEER = /datum/alt_title/biomech, JOB_ALT_MECHATRONIC_ENGINEER = /datum/alt_title/mech_tech)
+ alt_titles = list(
+ JOB_ALT_ASSEMBLY_TECHNICIAN = /datum/alt_title/assembly_tech,
+ JOB_ALT_BIOMECHANICAL_ENGINEER = /datum/alt_title/biomech,
+ JOB_ALT_MECHATRONIC_ENGINEER = /datum/alt_title/mech_tech,
+ JOB_ALT_SOFTWARE_ENGINEER = /datum/alt_title/software_engi)
+
+/datum/job/roboticist/get_request_reasons()
+ return list("Repairs needed")
// Roboticist Alt Titles
/datum/alt_title/biomech
@@ -157,3 +221,41 @@ VR edit end*/
title = JOB_ALT_MECHATRONIC_ENGINEER
title_blurb = "A " + JOB_ALT_MECHATRONIC_ENGINEER + " focuses on the construction and maintenance of Exosuits, and should be well versed in their use. \
They may also be called upon to work on synthetics and prosthetics, if needed."
+
+/datum/alt_title/software_engi
+ title = JOB_ALT_SOFTWARE_ENGINEER
+ title_blurb = "A " + JOB_ALT_SOFTWARE_ENGINEER + " specializes in working with software and firmware. They also often deal with integrated circuits."
+
+/datum/alt_title/assembly_tech
+ title = JOB_ALT_ASSEMBLY_TECHNICIAN
+
+//////////////////////////////////
+// Xenobotanist
+//////////////////////////////////
+/datum/job/xenobotanist
+ title = JOB_XENOBOTANIST
+ flag = XENOBOTANIST
+ departments = list(DEPARTMENT_RESEARCH)
+ department_flag = MEDSCI
+ faction = FACTION_STATION
+ total_positions = 2
+ spawn_positions = 2
+ supervisors = "the " + JOB_RESEARCH_DIRECTOR
+ selection_color = "#633D63"
+ economic_modifier = 7
+ access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobotany, access_hydroponics)
+ minimal_access = list(access_research, access_xenobotany, access_hydroponics, access_tox_storage)
+ pto_type = PTO_SCIENCE
+
+ minimal_player_age = 14
+
+ outfit_type = /decl/hierarchy/outfit/job/science/xenobiologist
+ job_description = "A " + JOB_XENOBOTANIST + " grows and cares for a variety of abnormal, custom made, and frequently dangerous plant life. When the products of these plants \
+ are both safe and beneficial to the station, they may choose to introduce it to the rest of the crew."
+ alt_titles = list(JOB_ALT_XENOHYDROPONICIST = /datum/alt_title/xenohydroponicist, JOB_ALT_XENOFLORIST = /datum/alt_title/xenoflorist)
+
+/datum/alt_title/xenoflorist
+ title = JOB_ALT_XENOFLORIST
+
+/datum/alt_title/xenohydroponicist
+ title = JOB_ALT_XENOHYDROPONICIST
\ No newline at end of file
diff --git a/code/game/jobs/job/science_vr.dm b/code/game/jobs/job/science_vr.dm
deleted file mode 100644
index c0505e4109e..00000000000
--- a/code/game/jobs/job/science_vr.dm
+++ /dev/null
@@ -1,134 +0,0 @@
-/datum/job/rd
- disallow_jobhop = TRUE
- pto_type = PTO_SCIENCE
- dept_time_required = 60
-
- access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
- access_tox_storage, access_teleporter,
- access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
- access_RC_announce, access_keycard_auth, access_tcomsat, access_xenoarch, access_eva, access_network, access_xenobotany)
- minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
- access_tox_storage, access_teleporter,
- access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
- access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_eva, access_network, access_xenobotany)
- alt_titles = list(JOB_ALT_RESEARCH_SUPERVISOR = /datum/alt_title/research_supervisor, JOB_ALT_RESEARCH_MANAGER = /datum/alt_title/research_manager,
- JOB_ALT_HEAD_OF_DEVELOPMENT = /datum/alt_title/head_of_development,JOB_ALT_HEAD_SCIENTIST = /datum/alt_title/head_scientist)
-
-/datum/alt_title/research_manager
- title = JOB_ALT_RESEARCH_MANAGER
-
-/datum/alt_title/head_of_development
- title = JOB_ALT_HEAD_OF_DEVELOPMENT
-
-/datum/alt_title/head_scientist
- title = JOB_ALT_HEAD_SCIENTIST
-
-/datum/job/rd/get_request_reasons()
- return list("Repairs needed", "Training crew", "Assembling expedition team")
-
-
-/datum/job/scientist
- spawn_positions = 5
- pto_type = PTO_SCIENCE
- alt_titles = list(JOB_ALT_RESEARCHER = /datum/alt_title/researcher, JOB_ALT_LAB_ASSISTANT = /datum/alt_title/lab_assistant, JOB_ALT_XENOARCHAEOLOGIST = /datum/alt_title/xenoarch,
- JOB_ALT_XENOPALEONTOLOGIST = /datum/alt_title/xenopaleontologist, JOB_ALT_ANOMALIST = /datum/alt_title/anomalist, JOB_ALT_PHORON_RESEARCHER = /datum/alt_title/phoron_research,
- JOB_ALT_GAS_PHYSICIST = /datum/alt_title/gas_physicist, JOB_ALT_CIRCUIT_DESIGNER = /datum/alt_title/circuit_designer, JOB_ALT_CIRCUIT_PROGRAMMER = /datum/alt_title/circuit_programmer)
-
-
- access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_xenobotany)
- minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch) // Unchanged (for now?), mostly here for reference
-
-/datum/alt_title/researcher
- title = JOB_ALT_RESEARCHER
-
-/datum/alt_title/lab_assistant
- title = JOB_ALT_LAB_ASSISTANT
- title_blurb = "A " + JOB_ALT_LAB_ASSISTANT + " is a lower-level member of research staff, whose main purpose is to help scientists with their specialized work in more menial fashion, while also \
- learning the specializations in process."
-
-/datum/alt_title/xenopaleontologist
- title = JOB_ALT_XENOPALEONTOLOGIST
- title_blurb = "A " + JOB_ALT_XENOPALEONTOLOGIST + " enters digsites in search of fossils and other ancient remants of alien life. These digsites are frequently in vacuum or other inhospitable \
- locations, and as such a " + JOB_ALT_XENOPALEONTOLOGIST + " should be prepared to handle hostile evironmental conditions."
-
-/datum/alt_title/gas_physicist
- title = JOB_ALT_GAS_PHYSICIST
- title_blurb = "A " + JOB_ALT_GAS_PHYSICIST + " is a specialist in various practical applications of gasses, but currently focuses their attention on phoron, and has knowledge of its practical uses and dangers. \
- Many " + JOB_ALT_GAS_PHYSICIST + "s are interested in the combustability and explosive properties of gaseous phoron, as well as the specific hazards \
- of working with the substance in that state."
-
-/datum/alt_title/circuit_designer
- title = JOB_ALT_CIRCUIT_DESIGNER
- title_blurb = "A " + JOB_ALT_CIRCUIT_DESIGNER + " is a " + JOB_SCIENTIST + " whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
- They work to create various useful devices using the capabilities of integrated circuitry."
-
-/datum/alt_title/circuit_programmer
- title = JOB_ALT_CIRCUIT_PROGRAMMER
- title_blurb = "A " + JOB_ALT_CIRCUIT_PROGRAMMER + " is a " + JOB_SCIENTIST + " whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
- They work to create various useful devices using the capabilities of integrated circuitry."
-
-/datum/job/scientist/get_request_reasons()
- return list("Assembling expedition team")
-
-/datum/job/xenobiologist
- spawn_positions = 3
- pto_type = PTO_SCIENCE
- alt_titles = list(JOB_ALT_XENOZOOLOGIST = /datum/alt_title/xenozoologist, JOB_ALT_XENOANTHROPOLOGIST = /datum/alt_title/xenoanthropologist)
-
-/datum/alt_title/xenozoologist
- title = JOB_ALT_XENOZOOLOGIST
-
-/datum/alt_title/xenoanthropologist
- title = JOB_ALT_XENOANTHROPOLOGIST
- title_blurb = JOB_ALT_XENOANTHROPOLOGIST + " still heavily focuses their study on alien lifeforms, but their specialty leans more towards fellow sapient beings than simple animals."
-
-
-/datum/job/roboticist
- total_positions = 3
- pto_type = PTO_SCIENCE
- alt_titles = list(
- JOB_ALT_ASSEMBLY_TECHNICIAN = /datum/alt_title/assembly_tech,
- JOB_ALT_BIOMECHANICAL_ENGINEER = /datum/alt_title/biomech,
- JOB_ALT_MECHATRONIC_ENGINEER = /datum/alt_title/mech_tech,
- JOB_ALT_SOFTWARE_ENGINEER = /datum/alt_title/software_engi)
-
-/datum/alt_title/software_engi
- title = JOB_ALT_SOFTWARE_ENGINEER
- title_blurb = "A " + JOB_ALT_SOFTWARE_ENGINEER + " specializes in working with software and firmware. They also often deal with integrated circuits."
-
-/datum/alt_title/assembly_tech
- title = JOB_ALT_ASSEMBLY_TECHNICIAN
-
-/datum/job/roboticist/get_request_reasons()
- return list("Repairs needed")
-
-//////////////////////////////////
-// Xenobotanist
-//////////////////////////////////
-/datum/job/xenobotanist
- title = JOB_XENOBOTANIST
- flag = XENOBOTANIST
- departments = list(DEPARTMENT_RESEARCH)
- department_flag = MEDSCI
- faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
- supervisors = "the " + JOB_RESEARCH_DIRECTOR
- selection_color = "#633D63"
- economic_modifier = 7
- access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobotany, access_hydroponics)
- minimal_access = list(access_research, access_xenobotany, access_hydroponics, access_tox_storage)
- pto_type = PTO_SCIENCE
-
- minimal_player_age = 14
-
- outfit_type = /decl/hierarchy/outfit/job/science/xenobiologist
- job_description = "A " + JOB_XENOBOTANIST + " grows and cares for a variety of abnormal, custom made, and frequently dangerous plant life. When the products of these plants \
- are both safe and beneficial to the station, they may choose to introduce it to the rest of the crew."
- alt_titles = list(JOB_ALT_XENOHYDROPONICIST = /datum/alt_title/xenohydroponicist, JOB_ALT_XENOFLORIST = /datum/alt_title/xenoflorist)
-
-/datum/alt_title/xenoflorist
- title = JOB_ALT_XENOFLORIST
-
-/datum/alt_title/xenohydroponicist
- title = JOB_ALT_XENOHYDROPONICIST
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 372d459e620..db2a0e051ce 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -16,26 +16,31 @@
req_admin_notify = 1
economic_modifier = 10
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
- access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
- access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
+ access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
+ access_construction,
+ access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
- access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
- access_research, access_engine, access_mining, access_medical, access_construction, access_mailsorting,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
+ access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
+ access_construction,
+ access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
minimum_character_age = 25
min_age_by_species = list(SPECIES_HUMAN_VATBORN = 14)
minimal_player_age = 14
ideal_character_age = 50
ideal_age_by_species = list(SPECIES_HUMAN_VATBORN = 20)
banned_job_species = list(SPECIES_TESHARI, SPECIES_DIONA, SPECIES_PROMETHEAN, SPECIES_ZADDAT, "digital", SPECIES_UNATHI, "mechanical")
+ disallow_jobhop = TRUE
+ pto_type = PTO_SECURITY
+ dept_time_required = 60
outfit_type = /decl/hierarchy/outfit/job/security/hos
job_description = " The " + JOB_HEAD_OF_SECURITY + " manages the Security Department, keeping the station safe and making sure the rules are followed. They are expected to \
keep the other Department Heads, and the rest of the crew, aware of developing situations that may be a threat. If necessary, the HoS may \
perform the duties of absent Security roles, such as distributing gear from the Armory."
- alt_titles = list(JOB_ALT_SECURITY_COMMANDER = /datum/alt_title/sec_commander, JOB_ALT_CHIEF_OF_SECURITY = /datum/alt_title/sec_chief)
+ alt_titles = list(JOB_ALT_SECURITY_COMMANDER = /datum/alt_title/sec_commander, JOB_ALT_CHIEF_OF_SECURITY = /datum/alt_title/sec_chief, JOB_ALT_SECURITY_MANAGER = /datum/alt_title/security_manager)
+/datum/job/hos/get_request_reasons()
+ return list("Wildlife management", "Forensic investigation", "Training crew", "Assembling expedition team")
// Head of Security Alt Titles
/datum/alt_title/sec_commander
@@ -44,6 +49,9 @@
/datum/alt_title/sec_chief
title = JOB_ALT_CHIEF_OF_SECURITY
+/datum/alt_title/security_manager
+ title = JOB_ALT_SECURITY_MANAGER
+
//////////////////////////////////
// Warden
//////////////////////////////////
@@ -59,17 +67,32 @@
supervisors = "the " + JOB_HEAD_OF_SECURITY
selection_color = "#601C1C"
economic_modifier = 5
+ pto_type = PTO_SECURITY
+ dept_time_required = 20
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_morgue, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_maint_tunnels, access_external_airlocks)
minimal_player_age = 5
banned_job_species = list(SPECIES_ZADDAT, SPECIES_PROMETHEAN, SPECIES_TESHARI, SPECIES_DIONA)
-
+ alt_titles = list(JOB_ALT_BRIG_SENTRY = /datum/alt_title/brig_sentry, JOB_ALT_ARMORY_SUPERINTENDENT = /datum/alt_title/armory_superintendent, JOB_ALT_MASTERATARMS = /datum/alt_title/master_at_arms)
outfit_type = /decl/hierarchy/outfit/job/security/warden
job_description = "The " + JOB_WARDEN + " watches over the physical Security Department, making sure the Brig and Armoury are secure and in order at all times. They oversee \
prisoners that have been processed and brigged, and are responsible for their well being. The " + JOB_WARDEN + " is also in charge of distributing \
Armoury gear in a crisis, and retrieving it when the crisis has passed. In an emergency, the " + JOB_WARDEN + " may be called upon to direct the \
Security Department as a whole."
+/datum/job/warden/get_request_reasons()
+ return list("Wildlife management")
+
+//Warden Alt Titles
+/datum/alt_title/brig_sentry
+ title = JOB_ALT_BRIG_SENTRY
+
+/datum/alt_title/armory_superintendent
+ title = JOB_ALT_ARMORY_SUPERINTENDENT
+
+/datum/alt_title/master_at_arms
+ title = JOB_ALT_MASTERATARMS
+
//////////////////////////////////
// Detective
//////////////////////////////////
@@ -81,6 +104,7 @@
faction = FACTION_STATION
total_positions = 2
spawn_positions = 2
+ pto_type = PTO_SECURITY
supervisors = "the " + JOB_HEAD_OF_SECURITY
selection_color = "#601C1C"
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_eva, access_external_airlocks, access_brig) //Vorestation edit - access_brig
@@ -92,7 +116,10 @@
outfit_type = /decl/hierarchy/outfit/job/security/detective
job_description = "A " + JOB_DETECTIVE + " works to help Security find criminals who have not properly been identified, through interviews and forensic work. \
For crimes only witnessed after the fact, or those with no survivors, they attempt to piece together what they can from pure evidence."
- alt_titles = list(JOB_ALT_FORENSIC_TECHNICIAN = /datum/alt_title/forensic_tech)
+ alt_titles = list(JOB_ALT_INVESTIGATOR = /datum/alt_title/investigator, JOB_ALT_SECURITY_INSPECTOR = /datum/alt_title/security_inspector, JOB_ALT_FORENSIC_TECHNICIAN = /datum/alt_title/forensic_tech)
+
+/datum/job/detective/get_request_reasons()
+ return list("Forensic investigation")
// Detective Alt Titles
/datum/alt_title/forensic_tech
@@ -100,6 +127,12 @@
title_blurb = "A " + JOB_ALT_FORENSIC_TECHNICIAN + " works more with hard evidence and labwork than a " + JOB_DETECTIVE + ", but they share the purpose of solving crimes."
title_outfit = /decl/hierarchy/outfit/job/security/detective/forensic
+/datum/alt_title/investigator
+ title = JOB_ALT_INVESTIGATOR
+
+/datum/alt_title/security_inspector
+ title = JOB_ALT_SECURITY_INSPECTOR
+
//////////////////////////////////
// Security Officer
//////////////////////////////////
@@ -109,8 +142,9 @@
departments = list(DEPARTMENT_SECURITY)
department_flag = ENGSEC
faction = FACTION_STATION
- total_positions = 4
- spawn_positions = 4
+ total_positions = 5
+ spawn_positions = 5
+ pto_type = PTO_SECURITY
supervisors = "the " + JOB_HEAD_OF_SECURITY
selection_color = "#601C1C"
economic_modifier = 4
@@ -123,13 +157,29 @@
job_description = "A " + JOB_SECURITY_OFFICER + " is concerned with maintaining the safety and security of the station as a whole, dealing with external threats and \
apprehending criminals. A " + JOB_SECURITY_OFFICER + " is responsible for the health, safety, and processing of any prisoner they arrest. \
No one is above the Law, not Security or Command."
- alt_titles = list(JOB_ALT_JUNIOR_OFFICER = /datum/alt_title/junior_officer)
+ alt_titles = list(JOB_ALT_PATROL_OFFICER = /datum/alt_title/patrol_officer, JOB_ALT_SECURITY_GUARD = /datum/alt_title/security_guard,
+ JOB_ALT_SECURITY_DEPUTY = /datum/alt_title/security_guard, JOB_ALT_JUNIOR_OFFICER = /datum/alt_title/junior_officer, JOB_ALT_SECURITY_CONTRACTOR = /datum/alt_title/security_contractor)
min_age_by_species = list(SPECIES_PROMETHEAN = 3)
+/datum/job/officer/get_request_reasons()
+ return list("Wildlife management", "Assembling expedition team")
+
// Security Officer Alt Titles
/datum/alt_title/junior_officer
title = JOB_ALT_JUNIOR_OFFICER
title_blurb = "A " + JOB_ALT_JUNIOR_OFFICER + " is an inexperienced " + JOB_SECURITY_OFFICER + ". They likely have training, but not experience, and are frequently \
paired off with a more senior co-worker. Junior Officers may also be expected to take over the boring duties of other Officers \
including patrolling the station or maintaining specific posts."
+
+/datum/alt_title/patrol_officer
+ title = JOB_ALT_PATROL_OFFICER
+
+/datum/alt_title/security_guard
+ title = JOB_ALT_SECURITY_GUARD
+
+/datum/alt_title/security_deputy
+ title = JOB_ALT_SECURITY_DEPUTY
+
+/datum/alt_title/security_contractor
+ title = JOB_ALT_SECURITY_CONTRACTOR
diff --git a/code/game/jobs/job/security_vr.dm b/code/game/jobs/job/security_vr.dm
deleted file mode 100644
index b7c196b3345..00000000000
--- a/code/game/jobs/job/security_vr.dm
+++ /dev/null
@@ -1,75 +0,0 @@
-/datum/job/hos
- disallow_jobhop = TRUE
- pto_type = PTO_SECURITY
- dept_time_required = 60
-
- access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
- access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
- access_construction,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
- minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
- access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
- access_construction,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
- alt_titles = list(JOB_ALT_SECURITY_COMMANDER = /datum/alt_title/sec_commander, JOB_ALT_CHIEF_OF_SECURITY = /datum/alt_title/sec_chief, JOB_ALT_SECURITY_MANAGER = /datum/alt_title/security_manager)
-
-/datum/alt_title/security_manager
- title = JOB_ALT_SECURITY_MANAGER
-
-/datum/job/hos/get_request_reasons()
- return list("Wildlife management", "Forensic investigation", "Training crew", "Assembling expedition team")
-
-
-/datum/job/warden
- pto_type = PTO_SECURITY
- dept_time_required = 20
- alt_titles = list(JOB_ALT_BRIG_SENTRY = /datum/alt_title/brig_sentry, JOB_ALT_ARMORY_SUPERINTENDENT = /datum/alt_title/armory_superintendent, JOB_ALT_MASTERATARMS = /datum/alt_title/master_at_arms)
-
-/datum/alt_title/brig_sentry
- title = JOB_ALT_BRIG_SENTRY
-
-/datum/alt_title/armory_superintendent
- title = JOB_ALT_ARMORY_SUPERINTENDENT
-
-/datum/alt_title/master_at_arms
- title = JOB_ALT_MASTERATARMS
-
-/datum/job/warden/get_request_reasons()
- return list("Wildlife management")
-
-
-/datum/job/detective
- pto_type = PTO_SECURITY
- alt_titles = list(JOB_ALT_INVESTIGATOR = /datum/alt_title/investigator, JOB_ALT_SECURITY_INSPECTOR = /datum/alt_title/security_inspector, JOB_ALT_FORENSIC_TECHNICIAN = /datum/alt_title/forensic_tech)
-
-/datum/alt_title/investigator
- title = JOB_ALT_INVESTIGATOR
-
-/datum/alt_title/security_inspector
- title = JOB_ALT_SECURITY_INSPECTOR
-
-/datum/job/detective/get_request_reasons()
- return list("Forensic investigation")
-
-
-/datum/job/officer
- total_positions = 5
- spawn_positions = 5
- pto_type = PTO_SECURITY
- alt_titles = list(JOB_ALT_PATROL_OFFICER = /datum/alt_title/patrol_officer, JOB_ALT_SECURITY_GUARD = /datum/alt_title/security_guard,
- JOB_ALT_SECURITY_DEPUTY = /datum/alt_title/security_guard, JOB_ALT_JUNIOR_OFFICER = /datum/alt_title/junior_officer, JOB_ALT_SECURITY_CONTRACTOR = /datum/alt_title/security_contractor)
-
-/datum/alt_title/patrol_officer
- title = JOB_ALT_PATROL_OFFICER
-
-/datum/alt_title/security_guard
- title = JOB_ALT_SECURITY_GUARD
-
-/datum/alt_title/security_deputy
- title = JOB_ALT_SECURITY_DEPUTY
-
-/datum/alt_title/security_contractor
- title = JOB_ALT_SECURITY_CONTRACTOR
-
-/datum/job/officer/get_request_reasons()
- return list("Wildlife management", "Assembling expedition team")
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index 6a5812af073..cce3f69603c 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -19,6 +19,8 @@
has_headset = FALSE
assignable = FALSE
mob_type = JOB_SILICON_AI
+ disallow_jobhop = TRUE
+ pto_type = PTO_CIVILIAN
outfit_type = /decl/hierarchy/outfit/job/silicon/ai
job_description = "The " + JOB_AI + " oversees the operation of the station and its crew, but has no real authority over them. \
The " + JOB_AI + " is required to follow its Laws, and Lawbound Synthetics that are linked to it are expected to follow \
@@ -46,8 +48,10 @@
departments = list(DEPARTMENT_SYNTHETIC)
department_flag = ENGSEC
faction = FACTION_STATION
- total_positions = 2
- spawn_positions = 2
+ pto_type = PTO_CYBORG
+ minimal_player_age = 3 //1 day is a little too little time
+ total_positions = 4 //Along with one able to spawn later in the round.
+ spawn_positions = 3 //Let's have 3 able to spawn in roundstart
supervisors = "your Laws and the " + JOB_AI //Nodrak
selection_color = "#254C25"
minimal_player_age = 1
diff --git a/code/game/jobs/job/silicon_vr.dm b/code/game/jobs/job/silicon_vr.dm
deleted file mode 100644
index f5df1e3acfc..00000000000
--- a/code/game/jobs/job/silicon_vr.dm
+++ /dev/null
@@ -1,9 +0,0 @@
-/datum/job/ai
- disallow_jobhop = TRUE
- pto_type = PTO_CIVILIAN
-
-/datum/job/cyborg
- pto_type = PTO_CYBORG
- minimal_player_age = 3 //1 day is a little too little time
- total_positions = 4 //Along with one able to spawn later in the round.
- spawn_positions = 3 //Let's have 3 able to spawn in roundstart
\ No newline at end of file
diff --git a/code/game/jobs/job/special_vr.dm b/code/game/jobs/job/special.dm
similarity index 100%
rename from code/game/jobs/job/special_vr.dm
rename to code/game/jobs/job/special.dm
diff --git a/code/game/machinery/CableLayer.dm b/code/game/machinery/CableLayer.dm
index 256e57bf183..e13944eb9a6 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 d168286ee19..7d9d97acb72 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 5a14185d7c6..180bebe532d 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 a891a03f826..cf1fc43839f 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 aff190e5e3a..522a883efee 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 5c5db6ebb59..1c538eaf01c 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 fa0900ac461..c3a323a896c 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 752f9305acb..c1b372e5ad4 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 d9fe85fcbd9..b3b41376ff6 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 7a02d6115a3..cc3e3fc7556 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 e45c329f37a..6e59c568440 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.dm b/code/game/machinery/camera/camera.dm
index 383a96868b5..1f89fdbe980 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -254,19 +254,19 @@
if (!(src.status))
if(user)
visible_message(span_notice(" [user] has deactivated [src]!"))
+ add_hiddenprint(user)
else
visible_message(span_notice(" [src] clicks and shuts down. "))
playsound(src, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = "[initial(icon_state)]1"
- add_hiddenprint(user)
else
if(user)
visible_message(span_notice(" [user] has reactivated [src]!"))
+ add_hiddenprint(user)
else
visible_message(span_notice(" [src] clicks and reactivates itself. "))
playsound(src, 'sound/items/Wirecutter.ogg', 100, 1)
icon_state = initial(icon_state)
- add_hiddenprint(user)
/obj/machinery/camera/take_damage(var/force, var/message)
//prob(25) gives an average of 3-4 hits
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index 67824ecb3f5..6feae4eff23 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 6b9298cf399..90c64d1031e 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 ed07a6158bd..4f4722c559f 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 2808be538a9..aa3902c8467 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 44600b9c69b..70ec7f8717c 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 8afe56476bd..f6a50c32548 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/arcade_vr.dm b/code/game/machinery/computer/arcade_vr.dm
index a1d4ebb069e..80daaceb524 100644
--- a/code/game/machinery/computer/arcade_vr.dm
+++ b/code/game/machinery/computer/arcade_vr.dm
@@ -22,7 +22,6 @@
/obj/item/toy/redbutton = 2,
/obj/item/toy/gnome = 2,
/obj/item/toy/AI = 2,
- /obj/item/clothing/gloves/ring/buzzer/toy = 2,
/obj/item/storage/box/handcuffs/fake = 2,
/obj/item/toy/nuke = 2,
/obj/item/toy/minigibber = 2,
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index a566a6be1a3..77f9ce12c00 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 9efcb481305..9175cb391ad 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 1d43173d5af..2ca39d0ebb7 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 6bf5417f8dd..ddb74b6ad69 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 = "