"}
/obj/machinery/atmospherics/unary/vent_scrubber/multitool_topic(var/mob/user, var/list/href_list, var/obj/O)
- if("toggleadvcontrol" in href_list)
- advcontrol = !advcontrol
- return TRUE
-
if("set_id" in href_list)
var/newid = copytext(reject_bad_text(input(usr, "Specify the new ID tag for this machine", src, src:id_tag) as null|text),1,MAX_MESSAGE_LEN)
if(!newid)
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index 2cf3edfb275..ff9fb9a4ab1 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -127,20 +127,15 @@ GLOBAL_VAR_INIT(pipenetwarnings, 10)
member.air_temporary = new
member.air_temporary.volume = member.volume
- member.air_temporary.oxygen = air.oxygen*member.volume/air.volume
- member.air_temporary.nitrogen = air.nitrogen*member.volume/air.volume
- member.air_temporary.toxins = air.toxins*member.volume/air.volume
- member.air_temporary.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume
+ member.air_temporary.oxygen = air.oxygen * member.volume / air.volume
+ member.air_temporary.nitrogen = air.nitrogen * member.volume / air.volume
+ member.air_temporary.toxins = air.toxins * member.volume / air.volume
+ member.air_temporary.carbon_dioxide = air.carbon_dioxide * member.volume / air.volume
+ member.air_temporary.sleeping_agent = air.sleeping_agent * member.volume / air.volume
+ member.air_temporary.agent_b = air.agent_b * member.volume / air.volume
member.air_temporary.temperature = air.temperature
- if(air.trace_gases.len)
- for(var/datum/gas/trace_gas in air.trace_gases)
- var/datum/gas/corresponding = new trace_gas.type()
- member.air_temporary.trace_gases += corresponding
-
- corresponding.moles = trace_gas.moles*member.volume/air.volume
-
/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
var/total_heat_capacity = air.heat_capacity()
var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
@@ -228,7 +223,8 @@ GLOBAL_VAR_INIT(pipenetwarnings, 10)
var/total_nitrogen = 0
var/total_toxins = 0
var/total_carbon_dioxide = 0
- var/list/total_trace_gases = list()
+ var/total_sleeping_agent = 0
+ var/total_agent_b = 0
for(var/datum/gas_mixture/G in GL)
total_volume += G.volume
@@ -239,15 +235,8 @@ GLOBAL_VAR_INIT(pipenetwarnings, 10)
total_nitrogen += G.nitrogen
total_toxins += G.toxins
total_carbon_dioxide += G.carbon_dioxide
-
- if(G.trace_gases.len)
- for(var/datum/gas/trace_gas in G.trace_gases)
- var/datum/gas/corresponding = locate(trace_gas.type) in total_trace_gases
- if(!corresponding)
- corresponding = new trace_gas.type()
- total_trace_gases += corresponding
-
- corresponding.moles += trace_gas.moles
+ total_sleeping_agent += G.sleeping_agent
+ total_agent_b += G.agent_b
if(total_volume > 0)
@@ -259,18 +248,11 @@ GLOBAL_VAR_INIT(pipenetwarnings, 10)
//Update individual gas_mixtures by volume ratio
for(var/datum/gas_mixture/G in GL)
- G.oxygen = total_oxygen*G.volume/total_volume
- G.nitrogen = total_nitrogen*G.volume/total_volume
- G.toxins = total_toxins*G.volume/total_volume
- G.carbon_dioxide = total_carbon_dioxide*G.volume/total_volume
+ G.oxygen = total_oxygen * G.volume / total_volume
+ G.nitrogen = total_nitrogen * G.volume / total_volume
+ G.toxins = total_toxins * G.volume / total_volume
+ G.carbon_dioxide = total_carbon_dioxide * G.volume / total_volume
+ G.sleeping_agent = total_sleeping_agent * G.volume / total_volume
+ G.agent_b = total_agent_b * G.volume / total_volume
G.temperature = temperature
-
- if(total_trace_gases.len)
- for(var/datum/gas/trace_gas in total_trace_gases)
- var/datum/gas/corresponding = locate(trace_gas.type) in G.trace_gases
- if(!corresponding)
- corresponding = new trace_gas.type()
- G.trace_gases += corresponding
-
- corresponding.moles = trace_gas.moles*G.volume/total_volume
diff --git a/code/LINDA/LINDA_fire.dm b/code/LINDA/LINDA_fire.dm
index 6ec505d9f9a..30c56f93cc8 100644
--- a/code/LINDA/LINDA_fire.dm
+++ b/code/LINDA/LINDA_fire.dm
@@ -176,7 +176,7 @@
if(istype(loc, /turf/simulated))
var/turf/simulated/T = loc
- if(T.to_be_destroyed)
+ if(T.to_be_destroyed && !T.changing_turf)
var/chance_of_deletion
if(T.heat_capacity) //beware of division by zero
chance_of_deletion = T.max_fire_temperature_sustained / T.heat_capacity * 8 //there is no problem with prob(23456), min() was redundant --rastaf0
diff --git a/code/LINDA/LINDA_system.dm b/code/LINDA/LINDA_system.dm
index c5bc65d3bf7..3c8633c2b91 100644
--- a/code/LINDA/LINDA_system.dm
+++ b/code/LINDA/LINDA_system.dm
@@ -142,7 +142,7 @@ turf/CanPass(atom/movable/mover, turf/target, height=1.5)
return
T.atmos_spawn_air(text, amount)
-/turf/simulated/proc/atmos_spawn_air(var/flag, var/amount)
+/turf/simulated/proc/atmos_spawn_air(flag, amount)
if(!text || !amount || !air)
return
@@ -156,17 +156,21 @@ turf/CanPass(atom/movable/mover, turf/target, height=1.5)
if(flag & LINDA_SPAWN_TOXINS)
G.toxins += amount
+
if(flag & LINDA_SPAWN_OXYGEN)
G.oxygen += amount
+
if(flag & LINDA_SPAWN_CO2)
G.carbon_dioxide += amount
+
if(flag & LINDA_SPAWN_NITROGEN)
G.nitrogen += amount
if(flag & LINDA_SPAWN_N2O)
- var/datum/gas/sleeping_agent/T = new
- T.moles += amount
- G.trace_gases += T
+ G.sleeping_agent += amount
+
+ if(flag & LINDA_SPAWN_AGENT_B)
+ G.agent_b += amount
if(flag & LINDA_SPAWN_AIR)
G.oxygen += MOLES_O2STANDARD * amount
diff --git a/code/LINDA/LINDA_turf_tile.dm b/code/LINDA/LINDA_turf_tile.dm
index 72f77d2440f..acfa1983f72 100644
--- a/code/LINDA/LINDA_turf_tile.dm
+++ b/code/LINDA/LINDA_turf_tile.dm
@@ -19,20 +19,24 @@
GM.carbon_dioxide = carbon_dioxide
GM.nitrogen = nitrogen
GM.toxins = toxins
+ GM.sleeping_agent = sleeping_agent
+ GM.agent_b = agent_b
GM.temperature = temperature
return GM
-/turf/remove_air(amount as num)
+/turf/remove_air(amount)
var/datum/gas_mixture/GM = new
- var/sum = oxygen + carbon_dioxide + nitrogen + toxins
- if(sum>0)
- GM.oxygen = (oxygen/sum)*amount
- GM.carbon_dioxide = (carbon_dioxide/sum)*amount
- GM.nitrogen = (nitrogen/sum)*amount
- GM.toxins = (toxins/sum)*amount
+ var/sum = oxygen + carbon_dioxide + nitrogen + toxins + sleeping_agent + agent_b
+ if(sum > 0)
+ GM.oxygen = (oxygen / sum) * amount
+ GM.carbon_dioxide = (carbon_dioxide / sum) * amount
+ GM.nitrogen = (nitrogen / sum) * amount
+ GM.toxins = (toxins / sum) * amount
+ GM.sleeping_agent = (sleeping_agent / sum) * amount
+ GM.agent_b = (agent_b / sum) * amount
GM.temperature = temperature
@@ -53,7 +57,7 @@
var/temperature_archived //USED ONLY FOR SOLIDS
- var/atmos_overlay_type = "" //current active overlay
+ var/atmos_overlay_type = null //current active overlay
/turf/simulated/New()
..()
@@ -64,12 +68,14 @@
air.carbon_dioxide = carbon_dioxide
air.nitrogen = nitrogen
air.toxins = toxins
+ air.sleeping_agent = sleeping_agent
+ air.agent_b = agent_b
air.temperature = temperature
/turf/simulated/Destroy()
- visibilityChanged()
QDEL_NULL(active_hotspot)
+ QDEL_NULL(wet_overlay)
return ..()
/turf/simulated/assume_air(datum/gas_mixture/giver)
@@ -100,7 +106,7 @@
else
return ..()
-/turf/simulated/remove_air(amount as num)
+/turf/simulated/remove_air(amount)
if(air)
var/datum/gas_mixture/removed = null
@@ -155,7 +161,7 @@
var/turf/enemy_tile = get_step(src, direction)
- if(istype(enemy_tile,/turf/simulated))
+ if(istype(enemy_tile, /turf/simulated))
var/turf/simulated/enemy_simulated = enemy_tile
if(current_cycle > enemy_simulated.current_cycle)
@@ -211,7 +217,13 @@
if(planet_atmos) //share our air with the "atmosphere" "above" the turf
var/datum/gas_mixture/G = new
- G.copy_from_turf(src)
+ G.oxygen = oxygen
+ G.carbon_dioxide = carbon_dioxide
+ G.nitrogen = nitrogen
+ G.toxins = toxins
+ G.sleeping_agent = sleeping_agent
+ G.agent_b = agent_b
+ G.temperature = initial(temperature) // Temperature is modified at runtime; we only care about the turf's initial temperature
G.archive()
if(!air.compare(G))
if(!excited_group)
@@ -271,8 +283,7 @@
if(air.toxins > MOLES_PLASMA_VISIBLE)
return "plasma"
- var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air.trace_gases
- if(sleeping_agent && (sleeping_agent.moles > 1))
+ if(air.sleeping_agent > 1)
return "sleeping_agent"
return null
@@ -340,7 +351,7 @@
reset_cooldowns()
/datum/excited_group/proc/merge_groups(var/datum/excited_group/E)
- if(turf_list.len > E.turf_list.len)
+ if(length(turf_list) > length(E.turf_list))
SSair.excited_groups -= E
for(var/turf/simulated/T in E.turf_list)
T.excited_group = src
@@ -358,32 +369,26 @@
/datum/excited_group/proc/self_breakdown()
var/datum/gas_mixture/A = new
- var/datum/gas/sleeping_agent/S = new
- A.trace_gases += S
- for(var/turf/simulated/T in turf_list)
- A.oxygen += T.air.oxygen
- A.carbon_dioxide+= T.air.carbon_dioxide
- A.nitrogen += T.air.nitrogen
- A.toxins += T.air.toxins
- if(T.air.trace_gases.len)
- for(var/datum/gas/N in T.air.trace_gases)
- S.moles += N.moles
+ var/list/cached_turf_list = turf_list // cache for super speed
- for(var/turf/simulated/T in turf_list)
- T.air.oxygen = A.oxygen/turf_list.len
- T.air.carbon_dioxide= A.carbon_dioxide/turf_list.len
- T.air.nitrogen = A.nitrogen/turf_list.len
- T.air.toxins = A.toxins/turf_list.len
+ for(var/turf/simulated/T in cached_turf_list)
+ A.oxygen += T.air.oxygen
+ A.carbon_dioxide += T.air.carbon_dioxide
+ A.nitrogen += T.air.nitrogen
+ A.toxins += T.air.toxins
+ A.sleeping_agent += T.air.sleeping_agent
+ A.agent_b += T.air.agent_b
- if(S.moles > 0)
- if(T.air.trace_gases.len)
- for(var/datum/gas/G in T.air.trace_gases)
- G.moles = S.moles/turf_list.len
- else
- var/datum/gas/sleeping_agent/G = new
- G.moles = S.moles/turf_list.len
- T.air.trace_gases += G
+ var/turflen = length(cached_turf_list)
+
+ for(var/turf/simulated/T in cached_turf_list)
+ T.air.oxygen = A.oxygen / turflen
+ T.air.carbon_dioxide = A.carbon_dioxide / turflen
+ T.air.nitrogen = A.nitrogen / turflen
+ T.air.toxins = A.toxins / turflen
+ T.air.sleeping_agent = A.sleeping_agent / turflen
+ T.air.agent_b = A.agent_b / turflen
T.update_visuals()
diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm
index cbcf2c1dd90..e2068cecb89 100644
--- a/code/__DEFINES/MC.dm
+++ b/code/__DEFINES/MC.dm
@@ -32,17 +32,16 @@
// (Requires a MC restart to change)
#define SS_NO_FIRE 2
-//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
-// SS_BACKGROUND has its own priority bracket
+/** Subsystem only runs on spare cpu (after all non-background subsystems have ran that tick) */
+/// SS_BACKGROUND has its own priority bracket, this overrides SS_TICKER's priority bump
#define SS_BACKGROUND 4
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
#define SS_NO_TICK_CHECK 8
//Treat wait as a tick count, not DS, run every wait ticks.
-// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
+/// (also forces it to run first in the tick (unless SS_BACKGROUND))
// (implies all runlevels because of how it works)
-// (overrides SS_BACKGROUND)
// This is designed for basically anything that works as a mini-mc (like SStimer)
#define SS_TICKER 16
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
deleted file mode 100644
index c9691c195b8..00000000000
--- a/code/__DEFINES/components.dm
+++ /dev/null
@@ -1,291 +0,0 @@
-#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
-
-#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
-
-//shorthand
-#define GET_COMPONENT_FROM(varname, path, target) var##path/##varname = ##target.GetComponent(##path)
-#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src)
-
-#define COMPONENT_INCOMPATIBLE 1
-
-// How multiple components of the exact same type are handled in the same datum
-
-#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
-#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
-#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
-#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
-
-// All signals. Format:
-// When the signal is called: (signal arguments)
-// All signals send the source datum of the signal as the first argument
-
-// global signals
-// These are signals which can be listened to by any component on any parent
-// start global signals with "!", this used to be necessary but now it's just a formatting choice
-#define COMSIG_GLOB_NEW_Z "!new_z" //from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
-#define COMSIG_GLOB_VAR_EDIT "!var_edit" //called after a successful var edit somewhere in the world: (list/args)
-#define COMSIG_GLOB_MOB_CREATED "!mob_created" //mob was created somewhere : (mob)
-#define COMSIG_GLOB_MOB_DEATH "!mob_death" //mob died somewhere : (mob , gibbed)
-
-//////////////////////////////////////////////////////////////////
-
-// /datum signals
-#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
-#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
-#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
-#define COMSIG_PARENT_QDELETING "parent_qdeleting" //just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
-#define COMSIG_TOPIC "handle_topic" //generic topic handler (usr, href_list)
-
-// /atom signals
-#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
- #define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
-#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
-#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, result)
-#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
- //Positions for overrides list
- #define EXAMINE_POSITION_ARTICLE 1
- #define EXAMINE_POSITION_BEFORE 2
- //End positions
- #define COMPONENT_EXNAME_CHANGED 1
-#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable/entering, /atom)
-#define COMSIG_ATOM_EXITED "atom_exited" //from base of atom/Exited(): (atom/movable/exiting, atom/newloc)
-#define COMSIG_ATOM_EXIT "atom_exit" //from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc)
- #define COMPONENT_ATOM_BLOCK_EXIT 1
-#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target)
-#define COMSIG_ATOM_EMP_ACT "atom_emp_act" //from base of atom/emp_act(): (severity)
-#define COMSIG_ATOM_FIRE_ACT "atom_fire_act" //from base of atom/fire_act(): (exposed_temperature, exposed_volume)
-#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" //from base of atom/bullet_act(): (/obj/item/projectile, def_zone)
-#define COMSIG_ATOM_BLOB_ACT "atom_blob_act" //from base of atom/blob_act(): (/obj/structure/blob)
-#define COMSIG_ATOM_ACID_ACT "atom_acid_act" //from base of atom/acid_act(): (acidpwr, acid_volume)
-#define COMSIG_ATOM_EMAG_ACT "atom_emag_act" //from base of atom/emag_act(): ()
-#define COMSIG_ATOM_RAD_ACT "atom_rad_act" //from base of atom/rad_act(intensity)
-#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act" //from base of atom/narsie_act(): ()
-#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act" //from base of atom/ratvar_act(): ()
-#define COMSIG_ATOM_RCD_ACT "atom_rcd_act" //from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode)
-#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size)
-#define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color)
-#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" //from base of atom/setDir(): (old_dir, new_dir)
-#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" //from base of atom/handle_atom_del(): (atom/deleted)
-#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" //from base of atom/has_gravity(): (turf/location, list/forced_gravities)
-#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe" //from proc/get_rad_contents(): ()
- #define COMPONENT_BLOCK_RADIATION 1
-#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam" //from base of datum/radiation_wave/radiate(): (strength)
- #define COMPONENT_BLOCK_CONTAMINATION 1
-#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass" //from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width)
- #define COMPONENT_RAD_WAVE_HANDLED 1
-#define COMSIG_ATOM_CANREACH "atom_can_reach" //from internal loop in atom/movable/proc/CanReach(): (list/next)
- #define COMPONENT_BLOCK_REACH 1
-#define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act" //from base of atom/screwdriver_act(): (mob/living/user, obj/item/I)
-/////////////////
-#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost)
-#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
-#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw" //from base of atom/attack_paw(): (mob/user)
- #define COMPONENT_NO_ATTACK_HAND 1 //works on all 3.
-/////////////////
-
-#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area)
-#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area)
-
-#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params, mob/user)
-#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob)
-#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob)
-#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob)
-#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" //from base of atom/CtrlShiftClick(/mob)
-#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" //from base of atom/MouseDrop(): (/atom/over, /mob/user)
- #define COMPONENT_NO_MOUSEDROP 1
-#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user)
-
-// /area signals
-#define COMSIG_AREA_ENTERED "area_entered" //from base of area/Entered(): (atom/movable/M)
-#define COMSIG_AREA_EXITED "area_exited" //from base of area/Exited(): (atom/movable/M)
-
-// /turf signals
-#define COMSIG_TURF_CHANGE "turf_change" //from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
-#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" //from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
-
-// /atom/movable signals
-#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
-#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
-#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
-#define COMSIG_CROSSED_MOVABLE "crossed_movable" //when we cross over something (calling Crossed() on that atom)
-#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed" //from base of atom/movable/Uncrossed(): (/atom/movable)
-#define COMSIG_MOVABLE_UNCROSS "movable_uncross" //from base of atom/movable/Uncross(): (/atom/movable)
- #define COMPONENT_MOVABLE_BLOCK_UNCROSS 1
-#define COMSIG_MOVABLE_BUMP "movable_bump" //from base of atom/movable/Bump(): (/atom)
-#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
-#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
-#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
-#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
-#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw" //from base of atom/movable/throw_at(): (list/args)
- #define COMPONENT_CANCEL_THROW 1
-#define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
-#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" //from base of atom/movable/onTransitZ(): (old_z, new_z)
-#define COMSIG_MOVABLE_HEAR "movable_hear" //from base of atom/movable/Hear(): (message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
-#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
-
-// /mob signals
-#define COMSIG_MOB_DEATH "mob_death" //from base of mob/death(): (gibbed)
-#define COMSIG_MOB_CLICKON "mob_clickon" //from base of mob/clickon(): (atom/A, params)
- #define COMSIG_MOB_CANCEL_CLICKON 1
-#define COMSIG_MOB_ALLOWED "mob_allowed" //from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
-#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //from base of mob/anti_magic_check(): (magic, holy, protection_sources)
- #define COMPONENT_BLOCK_MAGIC 1
-#define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): ()
-#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand" //from base of
-#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack" //from base of /obj/item/attack(): (mob/M, mob/user)
-#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
-#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
-#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
-#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): ()
-
-// /mob/living signals
-#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
-#define COMSIG_LIVING_IGNITED "living_ignite" //from base of mob/living/IgniteMob() (/mob/living)
-#define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living)
-#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage)
-#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: ()
-
-//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
-#define COMSIG_LIVING_STATUS_STUN "living_stun" //from base of mob/living/Stun() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown" //from base of mob/living/Knockdown() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_PARALYZE "living_paralyze" //from base of mob/living/Paralyze() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_IMMOBILIZE "living_immobilize" //from base of mob/living/Immobilize() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_UNCONSCIOUS "living_unconscious" //from base of mob/living/Unconscious() (amount, update, ignore)
-#define COMSIG_LIVING_STATUS_SLEEP "living_sleeping" //from base of mob/living/Sleeping() (amount, update, ignore)
- #define COMPONENT_NO_STUN 1 //For all of them
-
-// /mob/living/carbon signals
-#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
-
-// /mob/living/simple_animal/hostile signals
-#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
- #define COMPONENT_HOSTILE_NO_ATTACK 1
-
-// /obj signals
-#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
-#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
-#define COMSIG_OBJ_UPDATE_ICON "obj_update_icon" //called in /obj/update_icon()
-
-
-// /obj/item signals
-#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
-#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
- #define COMPONENT_NO_INTERACT 1
-#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
- #define COMPONENT_NO_ATTACK_OBJ 1
-#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
- #define COMPONENT_NO_ATTACK 1
-#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
-#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
-#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
-#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
-#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
-#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
-#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
-
-// /obj/item/clothing signals
-#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
-
-// /obj/item/implant signals
-#define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): ()
-#define COMSIG_IMPLANT_IMPLANTING "implant_implanting" //from base of /obj/item/implant/proc/implant(): (list/args)
- #define COMPONENT_STOP_IMPLANTING 1
-#define COMSIG_IMPLANT_OTHER "implant_other" //called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
- //#define COMPONENT_STOP_IMPLANTING 1 //The name makes sense for both
- #define COMPONENT_DELETE_NEW_IMPLANT 2
- #define COMPONENT_DELETE_OLD_IMPLANT 4
-#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
- //This uses all return values of COMSIG_IMPLANT_OTHER
-
-// /obj/item/pda signals
-#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" //called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
- #define COMPONENT_STOP_RINGTONE_CHANGE 1
-
-// /obj/item/radio signals
-#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" //called from base of /obj/item/radio/proc/set_frequency(): (list/args)
-
-// /obj/item/pen signals
-#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
-
-
-// /mob/living/carbon/human signals
-#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
-#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
-#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
-
-// /datum/species signals
-#define COMSIG_SPECIES_GAIN "species_gain" //from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
-#define COMSIG_SPECIES_LOSS "species_loss" //from datum/species/on_species_loss(): (datum/species/lost_species)
-
-/*******Component Specific Signals*******/
-//Janitor
-#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
-#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
-#define COMSIG_COMPONENT_CLEAN_ACT "clean_act" //called on an object to clean it of cleanables. Usualy with soap: (num/strength)
-
-//Food
-#define COMSIG_FOOD_EATEN "food_eaten" //from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
-
-//Mood
-#define COMSIG_ADD_MOOD_EVENT "add_mood" //Called when you send a mood event from anywhere in the code.
-#define COMSIG_CLEAR_MOOD_EVENT "clear_mood" //Called when you clear a mood event from anywhere in the code.
-
-//NTnet
-#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive" //called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
-
-//Nanites
-#define COMSIG_HAS_NANITES "has_nanites" //() returns TRUE if nanites are found
-#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs" //(list/nanite_programs) - makes the input list a copy the nanites' program list
-#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume" //(amount) Sets current nanite volume to the given amount
-#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust" //(amount) Adjusts nanite volume by the given amount
-#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume" //(amount) Sets maximum nanite volume to the given amount
-#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud" //(amount(0-100)) Sets cloud ID to the given amount
-#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety" //(amount) Sets safety threshold to the given amount
-#define COMSIG_NANITE_SET_REGEN "nanite_set_regen" //(amount) Sets regeneration rate to the given amount
-#define COMSIG_NANITE_SIGNAL "nanite_signal" //(code(1-9999)) Called when sending a nanite signal to a mob.
-#define COMSIG_NANITE_SCAN "nanite_scan" //(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
-#define COMSIG_NANITE_UI_DATA "nanite_ui_data" //(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
-#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program" //(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
- #define COMPONENT_PROGRAM_INSTALLED 1 //Installation successful
- #define COMPONENT_PROGRAM_NOT_INSTALLED 2 //Installation failed, but there are still nanites
-#define COMSIG_NANITE_SYNC "nanite_sync" //(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
-
-// /datum/component/storage signals
-#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.
-#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert" //(obj/item/inserting, mob/user, silent, force) - returns bool
-#define COMSIG_TRY_STORAGE_SHOW "storage_show_to" //(mob/show_to, force) - returns bool.
-#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from" //(mob/hide_from) - returns bool
-#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all" //returns bool
-#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state" //(newstate)
-#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate" //() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
-#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type" //(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
-#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type" //(type, amount = INFINITY, force = FALSE) //don't fuck this up. Force will ignore max_items, and amount is normally clamped to max_items.
-#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj" //(obj, new_loc, force = FALSE) - returns bool
-#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty" //(loc) - returns bool - if loc is null it will dump at parent location.
-#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory" //(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
-#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip" //(obj/item/insertion_candidate, mob/user, silent) - returns bool
-
-// /datum/action signals
-#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
- #define COMPONENT_ACTION_BLOCK_TRIGGER 1
-
-/*******Non-Signal Component Related Defines*******/
-
-//Redirection component init flags
-#define REDIRECT_TRANSFER_WITH_TURF 1
-
-//Arch
-#define ARCH_PROB "probability" //Probability for each item
-#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
-
-//Ouch my toes!
-#define CALTROP_BYPASS_SHOES 1
-#define CALTROP_IGNORE_WALKERS 2
-
-//Xenobio hotkeys
-#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl" //from slime CtrlClickOn(): (/mob)
-#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt" //from slime AltClickOn(): (/mob)
-#define COMSIG_XENO_SLIME_CLICK_SHIFT "xeno_slime_click_shift" //from slime ShiftClickOn(): (/mob)
-#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift" //from turf ShiftClickOn(): (/mob)
-#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt" //from turf AltClickOn(): (/mob)
-#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl" //from monkey CtrlClickOn(): (/mob)
diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm
new file mode 100644
index 00000000000..128c9f19387
--- /dev/null
+++ b/code/__DEFINES/dcs/flags.dm
@@ -0,0 +1,41 @@
+/// Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type.
+/// `parent` must not be modified if this is to be returned.
+/// This will be noted in the runtime logs
+#define COMPONENT_INCOMPATIBLE 1
+/// Returned in PostTransfer to prevent transfer, similar to `COMPONENT_INCOMPATIBLE`
+#define COMPONENT_NOTRANSFER 2
+
+/// Return value to cancel attaching
+#define ELEMENT_INCOMPATIBLE 1
+
+// /datum/element flags
+/// Causes the detach proc to be called when the host object is being deleted
+#define ELEMENT_DETACH (1 << 0)
+/**
+ * Only elements created with the same arguments given after `id_arg_index` share an element instance
+ * The arguments are the same when the text and number values are the same and all other values have the same ref
+ */
+#define ELEMENT_BESPOKE (1 << 1)
+
+// How multiple components of the exact same type are handled in the same datum
+/// old component is deleted (default)
+#define COMPONENT_DUPE_HIGHLANDER 0
+/// duplicates allowed
+#define COMPONENT_DUPE_ALLOWED 1
+/// new component is deleted
+#define COMPONENT_DUPE_UNIQUE 2
+/// old component is given the initialization args of the new
+#define COMPONENT_DUPE_UNIQUE_PASSARGS 4
+/// each component of the same type is consulted as to whether the duplicate should be allowed
+#define COMPONENT_DUPE_SELECTIVE 5
+
+//Redirection component init flags
+#define REDIRECT_TRANSFER_WITH_TURF 1
+
+//Arch
+#define ARCH_PROB "probability" //Probability for each item
+#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
+
+//Ouch my toes!
+#define CALTROP_BYPASS_SHOES 1
+#define CALTROP_IGNORE_WALKERS 2
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
new file mode 100644
index 00000000000..144e94f1fe0
--- /dev/null
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -0,0 +1,15 @@
+/// Used to trigger signals and call procs registered for that signal
+/// The datum hosting the signal is automaticaly added as the first argument
+/// Returns a bitfield gathered from all registered procs
+/// Arguments given here are packaged in a list and given to _SendSignal
+#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
+
+#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
+
+/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
+#define AddElement(arguments...) _AddElement(list(##arguments))
+/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
+#define RemoveElement(arguments...) _RemoveElement(list(##arguments))
+
+/// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments
+#define AddComponent(arguments...) _AddComponent(list(##arguments))
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
new file mode 100644
index 00000000000..10aa1718dda
--- /dev/null
+++ b/code/__DEFINES/dcs/signals.dm
@@ -0,0 +1,728 @@
+// All signals. Format:
+// When the signal is called: (signal arguments)
+// All signals send the source datum of the signal as the first argument
+
+// global signals
+// These are signals which can be listened to by any component on any parent
+// start global signals with "!", this used to be necessary but now it's just a formatting choice
+
+///from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args)
+#define COMSIG_GLOB_NEW_Z "!new_z"
+/// called after a successful var edit somewhere in the world: (list/args)
+#define COMSIG_GLOB_VAR_EDIT "!var_edit"
+/// called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
+#define COMSIG_GLOB_EXPLOSION "!explosion"
+/// mob was created somewhere : (mob)
+#define COMSIG_GLOB_MOB_CREATED "!mob_created"
+/// mob died somewhere : (mob , gibbed)
+#define COMSIG_GLOB_MOB_DEATH "!mob_death"
+/// global living say plug - use sparingly: (mob/speaker , message)
+#define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special"
+/// called by datum/cinematic/play() : (datum/cinematic/new_cinematic)
+#define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic"
+ #define COMPONENT_GLOB_BLOCK_CINEMATIC (1<<0)
+/// ingame button pressed (/obj/machinery/button/button)
+#define COMSIG_GLOB_BUTTON_PRESSED "!button_pressed"
+
+/// signals from globally accessible objects
+
+///from SSsun when the sun changes position : (azimuth)
+#define COMSIG_SUN_MOVED "sun_moved"
+
+//////////////////////////////////////////////////////////////////
+
+// /datum signals
+/// when a component is added to a datum: (/datum/component)
+#define COMSIG_COMPONENT_ADDED "component_added"
+/// before a component is removed from a datum because of RemoveComponent: (/datum/component)
+#define COMSIG_COMPONENT_REMOVING "component_removing"
+/// before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
+#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted"
+/// just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
+#define COMSIG_PARENT_QDELETING "parent_qdeleting"
+/// generic topic handler (usr, href_list)
+#define COMSIG_TOPIC "handle_topic"
+
+/// fires on the target datum when an element is attached to it (/datum/element)
+#define COMSIG_ELEMENT_ATTACH "element_attach"
+/// fires on the target datum when an element is attached to it (/datum/element)
+#define COMSIG_ELEMENT_DETACH "element_detach"
+
+// /atom signals
+///from base of atom/proc/Initialize(): sent any time a new atom is created
+#define COMSIG_ATOM_CREATED "atom_created"
+//from SSatoms InitAtom - Only if the atom was not deleted or failed initialization
+#define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success"
+///from base of atom/attackby(): (/obj/item, /mob/living, params)
+#define COMSIG_PARENT_ATTACKBY "atom_attackby"
+///Return this in response if you don't want afterattack to be called
+ #define COMPONENT_NO_AFTERATTACK (1<<0)
+///from base of atom/attack_hulk(): (/mob/living/carbon/human)
+#define COMSIG_ATOM_HULK_ATTACK "hulk_attack"
+///from base of atom/animal_attack(): (/mob/user)
+#define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal"
+///from base of atom/examine(): (/mob)
+#define COMSIG_PARENT_EXAMINE "atom_examine"
+///from base of atom/get_examine_name(): (/mob, list/overrides)
+#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name"
+ //Positions for overrides list
+ #define EXAMINE_POSITION_ARTICLE (1<<0)
+ #define EXAMINE_POSITION_BEFORE (1<<1)
+ //End positions
+ #define COMPONENT_EXNAME_CHANGED (1<<0)
+///from base of atom/update_icon(): ()
+#define COMSIG_ATOM_UPDATE_ICON "atom_update_icon"
+ #define COMSIG_ATOM_NO_UPDATE_ICON_STATE (1<<0)
+ #define COMSIG_ATOM_NO_UPDATE_OVERLAYS (1<<1)
+///from base of atom/update_overlays(): (list/new_overlays)
+#define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays"
+///from base of atom/update_icon(): (signalOut, did_anything)
+#define COMSIG_ATOM_UPDATED_ICON "atom_updated_icon"
+///from base of atom/Entered(): (atom/movable/entering, /atom)
+#define COMSIG_ATOM_ENTERED "atom_entered"
+///from base of atom/Exit(): (/atom/movable/exiting, /atom/newloc)
+#define COMSIG_ATOM_EXIT "atom_exit"
+ #define COMPONENT_ATOM_BLOCK_EXIT (1<<0)
+///from base of atom/Exited(): (atom/movable/exiting, atom/newloc)
+#define COMSIG_ATOM_EXITED "atom_exited"
+///from base of atom/Bumped(): (/atom/movable)
+#define COMSIG_ATOM_BUMPED "atom_bumped"
+///from base of atom/ex_act(): (severity, target)
+#define COMSIG_ATOM_EX_ACT "atom_ex_act"
+///from base of atom/emp_act(): (severity)
+#define COMSIG_ATOM_EMP_ACT "atom_emp_act"
+///from base of atom/fire_act(): (exposed_temperature, exposed_volume)
+#define COMSIG_ATOM_FIRE_ACT "atom_fire_act"
+///from base of atom/bullet_act(): (/obj/projectile, def_zone)
+#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act"
+///from base of atom/blob_act(): (/obj/structure/blob)
+#define COMSIG_ATOM_BLOB_ACT "atom_blob_act"
+///from base of atom/acid_act(): (acidpwr, acid_volume)
+#define COMSIG_ATOM_ACID_ACT "atom_acid_act"
+///from base of atom/emag_act(): (/mob/user)
+#define COMSIG_ATOM_EMAG_ACT "atom_emag_act"
+///from base of atom/rad_act(intensity)
+#define COMSIG_ATOM_RAD_ACT "atom_rad_act"
+///from base of atom/narsie_act(): ()
+#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act"
+///from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode)
+#define COMSIG_ATOM_RCD_ACT "atom_rcd_act"
+///from base of atom/singularity_pull(): (S, current_size)
+#define COMSIG_ATOM_SING_PULL "atom_sing_pull"
+///from obj/machinery/bsa/full/proc/fire(): ()
+#define COMSIG_ATOM_BSA_BEAM "atom_bsa_beam_pass"
+ #define COMSIG_ATOM_BLOCKS_BSA_BEAM (1<<0)
+///from base of atom/set_light(): (l_range, l_power, l_color)
+#define COMSIG_ATOM_SET_LIGHT "atom_set_light"
+///from base of atom/setDir(): (old_dir, new_dir)
+#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change"
+///from base of atom/handle_atom_del(): (atom/deleted)
+#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del"
+///from base of atom/has_gravity(): (turf/location, list/forced_gravities)
+#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity"
+///from proc/get_rad_contents(): ()
+#define COMSIG_ATOM_RAD_PROBE "atom_rad_probe"
+ #define COMPONENT_BLOCK_RADIATION (1<<0)
+///from base of datum/radiation_wave/radiate(): (strength)
+#define COMSIG_ATOM_RAD_CONTAMINATING "atom_rad_contam"
+ #define COMPONENT_BLOCK_CONTAMINATION (1<<0)
+///from base of datum/radiation_wave/check_obstructions(): (datum/radiation_wave, width)
+#define COMSIG_ATOM_RAD_WAVE_PASSING "atom_rad_wave_pass"
+ #define COMPONENT_RAD_WAVE_HANDLED (1<<0)
+///from internal loop in atom/movable/proc/CanReach(): (list/next)
+#define COMSIG_ATOM_CANREACH "atom_can_reach"
+ #define COMPONENT_BLOCK_REACH (1<<0)
+///from base of atom/screwdriver_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_SCREWDRIVER_ACT "atom_screwdriver_act"
+///from base of atom/wrench_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WRENCH_ACT "atom_wrench_act"
+///from base of atom/multitool_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_MULTITOOL_ACT "atom_multitool_act"
+///from base of atom/welder_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WELDER_ACT "atom_welder_act"
+///from base of atom/wirecutter_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_WIRECUTTER_ACT "atom_wirecutter_act"
+///from base of atom/crowbar_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_CROWBAR_ACT "atom_crowbar_act"
+///from base of atom/analyser_act(): (mob/living/user, obj/item/I)
+#define COMSIG_ATOM_ANALYSER_ACT "atom_analyser_act"
+ #define COMPONENT_BLOCK_TOOL_ATTACK (1<<0)
+///called when teleporting into a protected turf: (channel, turf/origin)
+#define COMSIG_ATOM_INTERCEPT_TELEPORT "intercept_teleport"
+ #define COMPONENT_BLOCK_TELEPORT (1<<0)
+///called when an atom is added to the hearers on get_hearers_in_view(): (list/processing_list, list/hearers)
+#define COMSIG_ATOM_HEARER_IN_VIEW "atom_hearer_in_view"
+///called when an atom starts orbiting another atom: (atom)
+#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
+///called when an atom stops orbiting another atom: (atom)
+#define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop"
+/////////////////
+///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
+#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
+///from base of atom/attack_hand(): (mob/user)
+#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand"
+///from base of atom/attack_paw(): (mob/user)
+#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw"
+ #define COMPONENT_NO_ATTACK_HAND (1<<0) //works on all 3.
+//This signal return value bitflags can be found in __DEFINES/misc.dm
+
+///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
+#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact"
+///called on a movable (NOT living) when someone starts pulling it (atom/movable/puller, state, force)
+#define COMSIG_ATOM_START_PULL "movable_start_pull"
+///called on /living when someone starts pulling it (atom/movable/puller, state, force)
+#define COMSIG_LIVING_START_PULL "living_start_pull"
+
+/////////////////
+
+///from base of area/Entered(): (/area)
+#define COMSIG_ENTER_AREA "enter_area"
+///from base of area/Exited(): (/area)
+#define COMSIG_EXIT_AREA "exit_area"
+///from base of atom/Click(): (location, control, params, mob/user)
+#define COMSIG_CLICK "atom_click"
+///from base of atom/ShiftClick(): (/mob)
+#define COMSIG_CLICK_SHIFT "shift_click"
+ #define COMPONENT_ALLOW_EXAMINATE (1<<0) //Allows the user to examinate regardless of client.eye.
+///from base of atom/CtrlClickOn(): (/mob)
+#define COMSIG_CLICK_CTRL "ctrl_click"
+///from base of atom/AltClick(): (/mob)
+#define COMSIG_CLICK_ALT "alt_click"
+///from base of atom/CtrlShiftClick(/mob)
+#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click"
+///from base of atom/MouseDrop(): (/atom/over, /mob/user)
+#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto"
+ #define COMPONENT_NO_MOUSEDROP (1<<0)
+///from base of atom/MouseDrop_T: (/atom/from, /mob/user)
+#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto"
+
+// /area signals
+
+///from base of area/Entered(): (atom/movable/M)
+#define COMSIG_AREA_ENTERED "area_entered"
+///from base of area/Exited(): (atom/movable/M)
+#define COMSIG_AREA_EXITED "area_exited"
+
+// /turf signals
+
+///from base of turf/ChangeTurf(): (path, list/new_baseturfs, flags, list/transferring_comps)
+#define COMSIG_TURF_CHANGE "turf_change"
+///from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
+#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity"
+///from base of turf/New(): (turf/source, direction)
+#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new"
+
+// /atom/movable signals
+
+///from base of atom/movable/Moved(): (/atom)
+#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move"
+ #define COMPONENT_MOVABLE_BLOCK_PRE_MOVE (1<<0)
+///from base of atom/movable/Moved(): (/atom, dir)
+#define COMSIG_MOVABLE_MOVED "movable_moved"
+///from base of atom/movable/Cross(): (/atom/movable)
+#define COMSIG_MOVABLE_CROSS "movable_cross"
+///from base of atom/movable/Crossed(): (/atom/movable)
+#define COMSIG_MOVABLE_CROSSED "movable_crossed"
+///when we cross over something (calling Crossed() on that atom)
+#define COMSIG_CROSSED_MOVABLE "crossed_movable"
+///from base of atom/movable/Uncross(): (/atom/movable)
+#define COMSIG_MOVABLE_UNCROSS "movable_uncross"
+ #define COMPONENT_MOVABLE_BLOCK_UNCROSS (1<<0)
+///from base of atom/movable/Uncrossed(): (/atom/movable)
+#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed"
+///from base of atom/movable/Bump(): (/atom)
+#define COMSIG_MOVABLE_BUMP "movable_bump"
+///from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
+#define COMSIG_MOVABLE_IMPACT "movable_impact"
+ #define COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH (1<<0) //if true, flip if the impact will push what it hits
+ #define COMPONENT_MOVABLE_IMPACT_NEVERMIND (1<<1) //return true if you destroyed whatever it was you're impacting and there won't be anything for hitby() to run on
+///from base of mob/living/hitby(): (mob/living/target, hit_zone)
+#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone"
+///from base of atom/movable/buckle_mob(): (mob, force)
+#define COMSIG_MOVABLE_BUCKLE "buckle"
+///from base of atom/movable/unbuckle_mob(): (mob, force)
+#define COMSIG_MOVABLE_UNBUCKLE "unbuckle"
+///from base of atom/movable/throw_at(): (list/args)
+#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw"
+ #define COMPONENT_CANCEL_THROW (1<<0)
+///from base of atom/movable/throw_at(): (datum/thrownthing, spin)
+#define COMSIG_MOVABLE_POST_THROW "movable_post_throw"
+///from base of atom/movable/onTransitZ(): (old_z, new_z)
+#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit"
+///called when the movable is placed in an unaccessible area, used for stationloving: ()
+#define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded"
+///from base of atom/movable/Hear(): (proc args list(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode))
+#define COMSIG_MOVABLE_HEAR "movable_hear"
+ #define HEARING_MESSAGE 1
+ #define HEARING_SPEAKER 2
+// #define HEARING_LANGUAGE 3
+ #define HEARING_RAW_MESSAGE 4
+ /* #define HEARING_RADIO_FREQ 5
+ #define HEARING_SPANS 6
+ #define HEARING_MESSAGE_MODE 7 */
+
+///called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source)
+#define COMSIG_MOVABLE_DISPOSING "movable_disposing"
+
+// /mob signals
+
+///from base of /mob/Login(): ()
+#define COMSIG_MOB_LOGIN "mob_login"
+///from base of /mob/Logout(): ()
+#define COMSIG_MOB_LOGOUT "mob_logout"
+///from base of mob/death(): (gibbed)
+#define COMSIG_MOB_DEATH "mob_death"
+///from base of mob/set_stat(): (new_stat)
+#define COMSIG_MOB_STATCHANGE "mob_statchange"
+///from base of mob/clickon(): (atom/A, params)
+#define COMSIG_MOB_CLICKON "mob_clickon"
+///from base of mob/MiddleClickOn(): (atom/A)
+#define COMSIG_MOB_MIDDLECLICKON "mob_middleclickon"
+///from base of mob/AltClickOn(): (atom/A)
+#define COMSIG_MOB_ALTCLICKON "mob_altclickon"
+ #define COMSIG_MOB_CANCEL_CLICKON (1<<0)
+
+///from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
+#define COMSIG_MOB_ALLOWED "mob_allowed"
+///from base of mob/anti_magic_check(): (mob/user, magic, holy, tinfoil, chargecost, self, protection_sources)
+#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic"
+ #define COMPONENT_BLOCK_MAGIC (1<<0)
+///from base of mob/create_mob_hud(): ()
+#define COMSIG_MOB_HUD_CREATED "mob_hud_created"
+///from base of atom/attack_hand(): (mob/user)
+#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand"
+///from base of /obj/item/attack(): (mob/M, mob/user)
+#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack"
+ #define COMPONENT_ITEM_NO_ATTACK (1<<0)
+///from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
+#define COMSIG_MOB_APPLY_DAMGE "mob_apply_damage"
+///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
+#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
+///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proxiumity_flag, click_parameters)
+#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted"
+///from base of mob/RangedAttack(): (atom/A, params)
+#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
+///from base of /mob/throw_item(): (atom/target)
+#define COMSIG_MOB_THROW "mob_throw"
+///from base of /mob/verb/examinate(): (atom/target)
+#define COMSIG_MOB_EXAMINATE "mob_examinate"
+///from base of /mob/update_sight(): ()
+#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight"
+////from /mob/living/say(): ()
+#define COMSIG_MOB_SAY "mob_say"
+ #define COMPONENT_UPPERCASE_SPEECH (1<<0)
+ // used to access COMSIG_MOB_SAY argslist
+ #define SPEECH_MESSAGE 1
+ // #define SPEECH_BUBBLE_TYPE 2
+ #define SPEECH_SPANS 3
+ /* #define SPEECH_SANITIZE 4
+ #define SPEECH_LANGUAGE 5
+ #define SPEECH_IGNORE_SPAM 6
+ #define SPEECH_FORCED 7 */
+
+///from /mob/say_dead(): (mob/speaker, message)
+#define COMSIG_MOB_DEADSAY "mob_deadsay"
+ #define MOB_DEADSAY_SIGNAL_INTERCEPT (1<<0)
+///from /mob/living/emote(): ()
+#define COMSIG_MOB_EMOTE "mob_emote"
+///from base of mob/swap_hand(): (obj/item)
+#define COMSIG_MOB_SWAP_HANDS "mob_swap_hands"
+ #define COMPONENT_BLOCK_SWAP (1<<0)
+
+// /mob/living signals
+
+///from base of mob/living/resist() (/mob/living)
+#define COMSIG_LIVING_RESIST "living_resist"
+///from base of mob/living/IgniteMob() (/mob/living)
+#define COMSIG_LIVING_IGNITED "living_ignite"
+///from base of mob/living/ExtinguishMob() (/mob/living)
+#define COMSIG_LIVING_EXTINGUISHED "living_extinguished"
+///from base of mob/living/electrocute_act(): (shock_damage, source, siemens_coeff, flags)
+#define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act"
+///sent when items with siemen coeff. of 0 block a shock: (power_source, source, siemens_coeff, dist_check)
+#define COMSIG_LIVING_SHOCK_PREVENTED "living_shock_prevented"
+///sent by stuff like stunbatons and tasers: ()
+#define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock"
+///from base of mob/living/revive() (full_heal, admin_revive)
+#define COMSIG_LIVING_REVIVE "living_revive"
+///from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs)
+#define COMSIG_LIVING_REGENERATE_LIMBS "living_regen_limbs"
+///from base of /obj/item/bodypart/proc/attach_limb(): (new_limb, special) allows you to fail limb attachment
+#define COMSIG_LIVING_ATTACH_LIMB "living_attach_limb"
+ #define COMPONENT_NO_ATTACH (1<<0)
+///sent from borg recharge stations: (amount, repairs)
+#define COMSIG_PROCESS_BORGCHARGER_OCCUPANT "living_charge"
+///sent when a mob/login() finishes: (client)
+#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login"
+///sent from borg mobs to itself, for tools to catch an upcoming destroy() due to safe decon (rather than detonation)
+#define COMSIG_BORG_SAFE_DECONSTRUCT "borg_safe_decon"
+
+//ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS!
+
+///from base of mob/living/Stun() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_STUN "living_stun"
+///from base of mob/living/Knockdown() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_KNOCKDOWN "living_knockdown"
+///from base of mob/living/Paralyze() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_PARALYZE "living_paralyze"
+///from base of mob/living/Immobilize() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_IMMOBILIZE "living_immobilize"
+///from base of mob/living/Unconscious() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_UNCONSCIOUS "living_unconscious"
+///from base of mob/living/Sleeping() (amount, update, ignore)
+#define COMSIG_LIVING_STATUS_SLEEP "living_sleeping"
+ #define COMPONENT_NO_STUN (1<<0) //For all of them
+///from base of /mob/living/can_track(): (mob/user)
+#define COMSIG_LIVING_CAN_TRACK "mob_cantrack"
+ #define COMPONENT_CANT_TRACK (1<<0)
+
+// /mob/living/carbon signals
+
+///from base of mob/living/carbon/soundbang_act(): (list(intensity))
+#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang"
+///from /item/organ/proc/Insert() (/obj/item/organ/)
+#define COMSIG_CARBON_GAIN_ORGAN "carbon_gain_organ"
+///from /item/organ/proc/Remove() (/obj/item/organ/)
+#define COMSIG_CARBON_LOSE_ORGAN "carbon_lose_organ"
+///from /mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop, silent)
+#define COMSIG_CARBON_EQUIP_HAT "carbon_equip_hat"
+///from /mob/living/carbon/doUnEquip(obj/item/I, force, newloc, no_move, invdrop, silent)
+#define COMSIG_CARBON_UNEQUIP_HAT "carbon_unequip_hat"
+///defined twice, in carbon and human's topics, fired when interacting with a valid embedded_object to pull it out (mob/living/carbon/target, /obj/item, /obj/item/bodypart/L)
+#define COMSIG_CARBON_EMBED_RIP "item_embed_start_rip"
+///called when removing a given item from a mob, from mob/living/carbon/remove_embedded_object(mob/living/carbon/target, /obj/item)
+#define COMSIG_CARBON_EMBED_REMOVAL "item_embed_remove_safe"
+
+// /mob/living/simple_animal/hostile signals
+#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
+ #define COMPONENT_HOSTILE_NO_ATTACK (1<<0)
+
+// /obj signals
+
+///from base of obj/deconstruct(): (disassembled)
+#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct"
+///called in /obj/structure/setAnchored(): (value)
+#define COMSIG_OBJ_SETANCHORED "obj_setanchored"
+///from base of code/game/machinery
+#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench"
+///from base of /turf/proc/levelupdate(). (intact) true to hide and false to unhide
+#define COMSIG_OBJ_HIDE "obj_hide"
+///called in /obj/update_icon()
+#define COMSIG_OBJ_UPDATE_ICON "obj_update_icon"
+
+// /obj/machinery signals
+
+///from /obj/machinery/obj_break(damage_flag): (damage_flag)
+#define COMSIG_MACHINERY_BROKEN "machinery_broken"
+///from base power_change() when power is lost
+#define COMSIG_MACHINERY_POWER_LOST "machinery_power_lost"
+///from base power_change() when power is restored
+#define COMSIG_MACHINERY_POWER_RESTORED "machinery_power_restored"
+
+// /obj/item signals
+
+///from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
+#define COMSIG_ITEM_ATTACK "item_attack"
+///from base of obj/item/attack_self(): (/mob)
+#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
+ #define COMPONENT_NO_INTERACT (1<<0)
+///from base of obj/item/attack_obj(): (/obj, /mob)
+#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj"
+ #define COMPONENT_NO_ATTACK_OBJ (1<<0)
+///from base of obj/item/pre_attack(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack"
+ #define COMPONENT_NO_ATTACK (1<<0)
+///from base of obj/item/afterattack(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_AFTERATTACK "item_afterattack"
+///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted"
+///from base of obj/item/equipped(): (/mob/equipper, slot)
+#define COMSIG_ITEM_EQUIPPED "item_equip"
+///from base of obj/item/dropped(): (mob/user)
+#define COMSIG_ITEM_DROPPED "item_drop"
+///from base of obj/item/pickup(): (/mob/taker)
+#define COMSIG_ITEM_PICKUP "item_pickup"
+///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
+#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
+///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
+#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul"
+///called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/targeted/summonitem/cast() : (mob/user)
+#define COMSIG_ITEM_MARK_RETRIEVAL "item_mark_retrieval"
+ #define COMPONENT_BLOCK_MARK_RETRIEVAL (1<<0)
+///from base of obj/item/hit_reaction(): (list/args)
+#define COMSIG_ITEM_HIT_REACT "item_hit_react"
+///called on item when crossed by something (): (/atom/movable, mob/living/crossed)
+#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed"
+///called on item when microwaved (): (obj/machinery/microwave/M)
+#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act"
+///from base of item/sharpener/attackby(): (amount, max)
+#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act"
+ #define COMPONENT_BLOCK_SHARPEN_APPLIED (1<<0)
+ #define COMPONENT_BLOCK_SHARPEN_BLOCKED (1<<1)
+ #define COMPONENT_BLOCK_SHARPEN_ALREADY (1<<2)
+ #define COMPONENT_BLOCK_SHARPEN_MAXED (1<<3)
+///from base of [/obj/item/proc/tool_check_callback]: (mob/living/user)
+#define COMSIG_TOOL_IN_USE "tool_in_use"
+///from base of [/obj/item/proc/tool_start_check]: (mob/living/user)
+#define COMSIG_TOOL_START_USE "tool_start_use"
+///from [/obj/item/proc/disableEmbedding]:
+#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed"
+///from [/obj/effect/mine/proc/triggermine]:
+#define COMSIG_MINE_TRIGGERED "minegoboom"
+
+// /obj/item signals for economy
+///called when an item is sold by the exports subsystem
+#define COMSIG_ITEM_SOLD "item_sold"
+///called when a wrapped up structure is opened by hand
+#define COMSIG_STRUCTURE_UNWRAPPED "structure_unwrapped"
+#define COMSIG_ITEM_UNWRAPPED "item_unwrapped"
+///called when a wrapped up item is opened by hand
+ #define COMSIG_ITEM_SPLIT_VALUE (1<<0)
+///called when getting the item's exact ratio for cargo's profit.
+#define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits"
+///called when getting the item's exact ratio for cargo's profit, without selling the item.
+#define COMSIG_ITEM_SPLIT_PROFIT_DRY "item_split_profits_dry"
+
+// /obj/item/clothing signals
+
+///from base of obj/item/clothing/shoes/proc/step_action(): ()
+#define COMSIG_SHOES_STEP_ACTION "shoes_step_action"
+///from base of /obj/item/clothing/suit/space/proc/toggle_spacesuit(): (obj/item/clothing/suit/space/suit)
+#define COMSIG_SUIT_SPACE_TOGGLE "suit_space_toggle"
+
+// /obj/item/implant signals
+///from base of /obj/item/implant/proc/activate(): ()
+#define COMSIG_IMPLANT_ACTIVATED "implant_activated"
+///from base of /obj/item/implant/proc/implant(): (list/args)
+#define COMSIG_IMPLANT_IMPLANTING "implant_implanting"
+ #define COMPONENT_STOP_IMPLANTING (1<<0)
+///called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
+#define COMSIG_IMPLANT_OTHER "implant_other"
+ //#define COMPONENT_STOP_IMPLANTING (1<<0) //The name makes sense for both
+ #define COMPONENT_DELETE_NEW_IMPLANT (1<<1)
+ #define COMPONENT_DELETE_OLD_IMPLANT (1<<2)
+///called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
+#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists"
+ //This uses all return values of COMSIG_IMPLANT_OTHER
+
+// /obj/item/pda signals
+
+///called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
+#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone"
+ #define COMPONENT_STOP_RINGTONE_CHANGE (1<<0)
+#define COMSIG_PDA_CHECK_DETONATE "pda_check_detonate"
+ #define COMPONENT_PDA_NO_DETONATE (1<<0)
+
+// /obj/item/radio signals
+
+///called from base of /obj/item/radio/proc/set_frequency(): (list/args)
+#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency"
+
+// /obj/item/pen signals
+
+///called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
+#define COMSIG_PEN_ROTATED "pen_rotated"
+
+// /obj/item/gun signals
+
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_MOB_FIRED_GUN "mob_fired_gun"
+
+// /obj/item/grenade signals
+
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_GRENADE_PRIME "grenade_prime"
+///called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_GRENADE_ARMED "grenade_armed"
+
+// /obj/projectile signals (sent to the firer)
+
+///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
+#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit"
+///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle)
+#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit"
+///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target)
+#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire"
+///from the base of /obj/projectile/proc/fire(): ()
+#define COMSIG_PROJECTILE_FIRE "projectile_fire"
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit"
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out"
+///sent when trying to force an embed (mainly for projectiles, only used in the embed element)
+#define COMSIG_EMBED_TRY_FORCE "item_try_embed"
+
+///sent to targets during the process_hit proc of projectiles
+#define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init"
+
+// /obj/mecha signals
+
+///sent from mecha action buttons to the mecha they're linked to
+#define COMSIG_MECHA_ACTION_ACTIVATE "mecha_action_activate"
+
+// /mob/living/carbon/human signals
+
+///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
+#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
+///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
+#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack"
+///from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
+#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby"
+///Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
+#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit"
+///Whenever EquipRanked is called, called after job is set
+#define COMSIG_JOB_RECEIVED "job_received"
+
+// /datum/species signals
+
+///from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species)
+#define COMSIG_SPECIES_GAIN "species_gain"
+///from datum/species/on_species_loss(): (datum/species/lost_species)
+#define COMSIG_SPECIES_LOSS "species_loss"
+
+// /datum/song signals
+
+///sent to the instrument when a song starts playing
+#define COMSIG_SONG_START "song_start"
+///sent to the instrument when a song stops playing
+#define COMSIG_SONG_END "song_end"
+
+/*******Component Specific Signals*******/
+//Janitor
+
+///(): Returns bitflags of wet values.
+#define COMSIG_TURF_IS_WET "check_turf_wet"
+///(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
+#define COMSIG_TURF_MAKE_DRY "make_turf_try"
+///called on an object to clean it of cleanables. Usualy with soap: (num/strength)
+#define COMSIG_COMPONENT_CLEAN_ACT "clean_act"
+
+//Creamed
+
+///called when you wash your face at a sink: (num/strength)
+#define COMSIG_COMPONENT_CLEAN_FACE_ACT "clean_face_act"
+
+//Food
+
+///from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
+#define COMSIG_FOOD_EATEN "food_eaten"
+
+//Gibs
+
+///from base of /obj/effect/decal/cleanable/blood/gibs/streak(): (list/directions, list/diseases)
+#define COMSIG_GIBS_STREAK "gibs_streak"
+
+//Mood
+
+///called when you send a mood event from anywhere in the code.
+#define COMSIG_ADD_MOOD_EVENT "add_mood"
+///Mood event that only RnD members listen for
+#define COMSIG_ADD_MOOD_EVENT_RND "RND_add_mood"
+///called when you clear a mood event from anywhere in the code.
+#define COMSIG_CLEAR_MOOD_EVENT "clear_mood"
+
+//NTnet
+
+///called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
+#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive"
+
+//Nanites
+
+///() returns TRUE if nanites are found
+#define COMSIG_HAS_NANITES "has_nanites"
+///() returns TRUE if nanites have stealth
+#define COMSIG_NANITE_IS_STEALTHY "nanite_is_stealthy"
+///() deletes the nanite component
+#define COMSIG_NANITE_DELETE "nanite_delete"
+///(list/nanite_programs) - makes the input list a copy the nanites' program list
+#define COMSIG_NANITE_GET_PROGRAMS "nanite_get_programs"
+///(amount) Returns nanite amount
+#define COMSIG_NANITE_GET_VOLUME "nanite_get_volume"
+///(amount) Sets current nanite volume to the given amount
+#define COMSIG_NANITE_SET_VOLUME "nanite_set_volume"
+///(amount) Adjusts nanite volume by the given amount
+#define COMSIG_NANITE_ADJUST_VOLUME "nanite_adjust"
+///(amount) Sets maximum nanite volume to the given amount
+#define COMSIG_NANITE_SET_MAX_VOLUME "nanite_set_max_volume"
+///(amount(0-100)) Sets cloud ID to the given amount
+#define COMSIG_NANITE_SET_CLOUD "nanite_set_cloud"
+///(method) Modify cloud sync status. Method can be toggle, enable or disable
+#define COMSIG_NANITE_SET_CLOUD_SYNC "nanite_set_cloud_sync"
+///(amount) Sets safety threshold to the given amount
+#define COMSIG_NANITE_SET_SAFETY "nanite_set_safety"
+///(amount) Sets regeneration rate to the given amount
+#define COMSIG_NANITE_SET_REGEN "nanite_set_regen"
+///(code(1-9999)) Called when sending a nanite signal to a mob.
+#define COMSIG_NANITE_SIGNAL "nanite_signal"
+///(comm_code(1-9999), comm_message) Called when sending a nanite comm signal to a mob.
+#define COMSIG_NANITE_COMM_SIGNAL "nanite_comm_signal"
+///(mob/user, full_scan) - sends to chat a scan of the nanites to the user, returns TRUE if nanites are detected
+#define COMSIG_NANITE_SCAN "nanite_scan"
+///(list/data, scan_level) - adds nanite data to the given data list - made for ui_data procs
+#define COMSIG_NANITE_UI_DATA "nanite_ui_data"
+///(datum/nanite_program/new_program, datum/nanite_program/source_program) Called when adding a program to a nanite component
+#define COMSIG_NANITE_ADD_PROGRAM "nanite_add_program"
+ ///Installation successful
+ #define COMPONENT_PROGRAM_INSTALLED (1<<0)
+ ///Installation failed, but there are still nanites
+ #define COMPONENT_PROGRAM_NOT_INSTALLED (1<<1)
+///(datum/component/nanites, full_overwrite, copy_activation) Called to sync the target's nanites to a given nanite component
+#define COMSIG_NANITE_SYNC "nanite_sync"
+
+// /datum/component/storage signals
+
+///() - returns bool.
+#define COMSIG_CONTAINS_STORAGE "is_storage"
+///(obj/item/inserting, mob/user, silent, force) - returns bool
+#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert"
+///(mob/show_to, force) - returns bool.
+#define COMSIG_TRY_STORAGE_SHOW "storage_show_to"
+///(mob/hide_from) - returns bool
+#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from"
+///returns bool
+#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all"
+///(newstate)
+#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state"
+///() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
+#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate"
+///(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
+#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type"
+///(type, amount = INFINITY, force = FALSE). Force will ignore max_items, and amount is normally clamped to max_items.
+#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type"
+///(obj, new_loc, force = FALSE) - returns bool
+#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj"
+///(loc) - returns bool - if loc is null it will dump at parent location.
+#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty"
+///(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
+#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory"
+///(obj/item/insertion_candidate, mob/user, silent) - returns bool
+#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip"
+
+// /datum/component/two_handed signals
+
+///from base of datum/component/two_handed/proc/wield(mob/living/carbon/user): (/mob/user)
+#define COMSIG_TWOHANDED_WIELD "twohanded_wield"
+ #define COMPONENT_TWOHANDED_BLOCK_WIELD (1<<0)
+///from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
+#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield"
+
+// /datum/action signals
+
+///from base of datum/action/proc/Trigger(): (datum/action)
+#define COMSIG_ACTION_TRIGGER "action_trigger"
+ #define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0)
+
+//Xenobio hotkeys
+
+///from slime CtrlClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl"
+///from slime AltClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt"
+///from slime ShiftClickOn(): (/mob)
+#define COMSIG_XENO_SLIME_CLICK_SHIFT "xeno_slime_click_shift"
+///from turf ShiftClickOn(): (/mob)
+#define COMSIG_XENO_TURF_CLICK_SHIFT "xeno_turf_click_shift"
+///from turf AltClickOn(): (/mob)
+#define COMSIG_XENO_TURF_CLICK_CTRL "xeno_turf_click_alt"
+///from monkey CtrlClickOn(): (/mob)
+#define COMSIG_XENO_MONKEY_CLICK_CTRL "xeno_monkey_click_ctrl"
diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm
index 58571e8b1ca..5fd85513501 100644
--- a/code/__DEFINES/genetics.dm
+++ b/code/__DEFINES/genetics.dm
@@ -145,7 +145,6 @@
#define RESISTCOLD "resist_cold"
#define NO_EXAMINE "no_examine"
#define CAN_WINGDINGS "can_wingdings"
-#define NOZOMBIE "no_zombie"
#define NO_GERMS "no_germs"
#define NO_DECAY "no_decay"
#define PIERCEIMMUNE "pierce_immunity"
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 671897b612d..2b8c515e81a 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -1,10 +1,8 @@
// Atoms
-#define isatom(A) istype(A, /atom)
-#define ismovableatom(A) istype(A, /atom/movable)
+#define isatom(A) (isloc(A))
// Mobs
#define ismegafauna(A) istype(A, /mob/living/simple_animal/hostile/megafauna)
-#define iszombie(A) (is_species(A, /datum/species/zombie))
//Simple animals
#define isshade(A) (istype(A, /mob/living/simple_animal/shade))
diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm
index d72628e2cb7..349d1b246be 100644
--- a/code/__DEFINES/job.dm
+++ b/code/__DEFINES/job.dm
@@ -51,7 +51,7 @@
#define JOB_CLOWN (1<<11)
#define JOB_MIME (1<<12)
#define JOB_CIVILIAN (1<<13)
-
+#define JOB_EXPLORER (1<<14)
#define JOBCAT_KARMA (1<<3)
diff --git a/code/__DEFINES/math.dm b/code/__DEFINES/math.dm
index 2f2968561da..433d1c55b56 100644
--- a/code/__DEFINES/math.dm
+++ b/code/__DEFINES/math.dm
@@ -1,59 +1,238 @@
+#define NUM_E 2.71828183
+
#define PI 3.1415
-#define SPEED_OF_LIGHT 3e8 //not exact but hey!
-#define SPEED_OF_LIGHT_SQ 9e+16
#define INFINITY 1e31 //closer than enough
-#define Clamp(x, y, z) ((x) <= (y) ? (y) : ((x) >= (z) ? (z) : (x)))
-#define CLAMP01(x) (Clamp((x), 0, 1))
-
-// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
-#define WRAP(val, min, max) ( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) )
-
-#define SIMPLE_SIGN(X) ((X) < 0 ? -1 : 1)
-#define SIGN(X) ((X) ? SIMPLE_SIGN(X) : 0)
-#define hypotenuse(Ax, Ay, Bx, By) (sqrt(((Ax) - (Bx))**2 + ((Ay) - (By))**2))
-#define Ceiling(x) (-round(-(x)))
-#define Tan(x) (sin(x) / cos(x))
-#define Cot(x) (1 / Tan(x))
-#define Csc(x) (1 / sin(x))
-#define Sec(x) (1 / cos(x))
-#define Floor(x) (round(x))
-#define Inverse(x) (1 / (x))
-#define IsEven(x) ((x) % 2 == 0)
-#define IsOdd(x) ((x) % 2 == 1)
-#define IsInRange(val, min, max) ((min) <= (val) && (val) <= (max))
-#define IsInteger(x) (Floor(x) == (x))
-#define IsMultiple(x, y) ((x) % (y) == 0)
-#define Lcm(a, b) (abs(a) / Gcd((a), (b)) * abs(b))
-#define Root(n, x) ((x) ** (1 / (n)))
-#define ToDegrees(radians) ((radians) * 57.2957795) // 180 / Pi
-#define ToRadians(degrees) ((degrees) * 0.0174532925) // Pi / 180
-
#define SHORT_REAL_LIMIT 16777216
-// Real modulus that handles decimals
-#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
-
-
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(TICK_USAGE_REAL - starting_tickusage))
+#define PERCENT(val) (round((val)*100, 0.1))
+#define CLAMP01(x) (clamp(x, 0, 1))
+
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers )
+#define SIMPLE_SIGN(X) ((X) < 0 ? -1 : 1)
+
+#define SIGN(x) ( (x)!=0 ? (x) / abs(x) : 0 )
+
#define CEILING(x, y) ( -round(-(x) / (y)) * (y) )
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
+// Similar to clamp but the bottom rolls around to the top and vice versa. min is inclusive, max is exclusive
+#define WRAP(val, min, max) clamp(( min == max ? min : (val) - (round(((val) - (min))/((max) - (min))) * ((max) - (min))) ),min,max)
+
+// Real modulus that handles decimals
+#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
+
+// Cotangent
+#define COT(x) (1 / tan(x))
+
+// Secant
+#define SEC(x) (1 / cos(x))
+
+// Cosecant
+#define CSC(x) (1 / sin(x))
+
+#define ATAN2(x, y) ( !(x) && !(y) ? 0 : (y) >= 0 ? arccos((x) / sqrt((x)*(x) + (y)*(y))) : -arccos((x) / sqrt((x)*(x) + (y)*(y))) )
+
+#define HYPOTENUSE(Ax, Ay, Bx, By) (sqrt(((Ax) - (Bx))**2 + ((Ay) - (By))**2))
+
+// Greatest Common Divisor - Euclid's algorithm
+/proc/Gcd(a, b)
+ return b ? Gcd(b, (a) % (b)) : a
+
+// Least Common Multiple
+#define Lcm(a, b) (abs(a) / Gcd(a, b) * abs(b))
+
+#define INVERSE(x) ( 1/(x) )
+
+// Used for calculating the radioactive strength falloff
+#define INVERSE_SQUARE(initial_strength,cur_distance,initial_distance) ( (initial_strength)*((initial_distance)**2/(cur_distance)**2) )
+
+#define ISABOUTEQUAL(a, b, deviation) (deviation ? abs((a) - (b)) <= deviation : abs((a) - (b)) <= 0.1)
+
+#define ISEVEN(x) (x % 2 == 0)
+
+#define ISODD(x) (x % 2 != 0)
+
+// Returns true if val is from min to max, inclusive.
+#define ISINRANGE(val, min, max) (min <= val && val <= max)
+
+// Same as above, exclusive.
+#define ISINRANGE_EX(val, min, max) (min < val && val < max)
+
+#define ISINTEGER(x) (round(x) == x)
+
+#define ISMULTIPLE(x, y) ((x) % (y) == 0)
+
+// Performs a linear interpolation between a and b.
+// Note that amount=0 returns a, amount=1 returns b, and
+// amount=0.5 returns the mean of a and b.
+#define LERP(a, b, amount) ( amount ? ((a) + ((b) - (a)) * (amount)) : a )
+
+// Returns the nth root of x.
+#define ROOT(n, x) ((x) ** (1 / (n)))
+
+// The quadratic formula. Returns a list with the solutions, or an empty list
+// if they are imaginary.
+/proc/SolveQuadratic(a, b, c)
+ ASSERT(a)
+ . = list()
+ var/d = b*b - 4 * a * c
+ var/bottom = 2 * a
+ if(d < 0)
+ return
+ var/root = sqrt(d)
+ . += (-b + root) / bottom
+ if(!d)
+ return
+ . += (-b - root) / bottom
+
+#define TODEGREES(radians) ((radians) * 57.2957795)
+
+#define TORADIANS(degrees) ((degrees) * 0.0174532925)
+
+/// Gets shift x that would be required the bitflag (1< dec? -dec : inc
+
+//A logarithm that converts an integer to a number scaled between 0 and 1.
+//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
+#define TRANSFORM_USING_VARIABLE(input, max) ( sin((90*(input))/(max))**2 )
+
+//converts a uniform distributed random number into a normal distributed one
+//since this method produces two random numbers, one is saved for subsequent calls
+//(making the cost negligble for every second call)
+//This will return +/- decimals, situated about mean with standard deviation stddev
+//68% chance that the number is within 1stddev
+//95% chance that the number is within 2stddev
+//98% chance that the number is within 3stddev...etc
+#define ACCURACY 10000
+/proc/gaussian(mean, stddev)
+ var/static/gaussian_next
+ var/R1;var/R2;var/working
+ if(gaussian_next != null)
+ R1 = gaussian_next
+ gaussian_next = null
+ else
+ do
+ R1 = rand(-ACCURACY,ACCURACY)/ACCURACY
+ R2 = rand(-ACCURACY,ACCURACY)/ACCURACY
+ working = R1*R1 + R2*R2
+ while(working >= 1 || working==0)
+ working = sqrt(-2 * log(working) / working)
+ R1 *= working
+ gaussian_next = R2 * working
+ return (mean + stddev * R1)
+#undef ACCURACY
+
+/proc/get_turf_in_angle(angle, turf/starting, increments)
+ var/pixel_x = 0
+ var/pixel_y = 0
+ for(var/i in 1 to increments)
+ pixel_x += sin(angle)+16*sin(angle)*2
+ pixel_y += cos(angle)+16*cos(angle)*2
+ var/new_x = starting.x
+ var/new_y = starting.y
+ while(pixel_x > 16)
+ pixel_x -= 32
+ new_x++
+ while(pixel_x < -16)
+ pixel_x += 32
+ new_x--
+ while(pixel_y > 16)
+ pixel_y -= 32
+ new_y++
+ while(pixel_y < -16)
+ pixel_y += 32
+ new_y--
+ new_x = clamp(new_x, 0, world.maxx)
+ new_y = clamp(new_y, 0, world.maxy)
+ return locate(new_x, new_y, starting.z)
+
+// Returns a list where [1] is all x values and [2] is all y values that overlap between the given pair of rectangles
+/proc/get_overlap(x1, y1, x2, y2, x3, y3, x4, y4)
+ var/list/region_x1 = list()
+ var/list/region_y1 = list()
+ var/list/region_x2 = list()
+ var/list/region_y2 = list()
+
+ // These loops create loops filled with x/y values that the boundaries inhabit
+ // ex: list(5, 6, 7, 8, 9)
+ for(var/i in min(x1, x2) to max(x1, x2))
+ region_x1["[i]"] = TRUE
+ for(var/i in min(y1, y2) to max(y1, y2))
+ region_y1["[i]"] = TRUE
+ for(var/i in min(x3, x4) to max(x3, x4))
+ region_x2["[i]"] = TRUE
+ for(var/i in min(y3, y4) to max(y3, y4))
+ region_y2["[i]"] = TRUE
+
+ return list(region_x1 & region_x2, region_y1 & region_y2)
+
+#define EXP_DISTRIBUTION(desired_mean) ( -(1/(1/desired_mean)) * log(rand(1, 1000) * 0.001) )
+
+#define LORENTZ_DISTRIBUTION(x, s) ( s*tan(TODEGREES(PI*(rand()-0.5))) + x )
+#define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 )
+
+#define RULE_OF_THREE(a, b, x) ((a*x)/b)
+// )
+
+/proc/RaiseToPower(num, power)
+ if(!power)
+ return 1
+ return (power-- > 1 ? num * RaiseToPower(num, power) : num)
+
+// oof, what a mouthful
+// Used in status_procs' "adjust" to let them modify a status effect by a given
+// amount, without inadverdently increasing it in the wrong direction
+/proc/directional_bounded_sum(orig_val, modifier, bound_lower, bound_upper)
+ var/new_val = orig_val + modifier
+ if(modifier > 0)
+ if(new_val > bound_upper)
+ new_val = max(orig_val, bound_upper)
+ else if(modifier < 0)
+ if(new_val < bound_lower)
+ new_val = min(orig_val, bound_lower)
+ return new_val
+
+// sqrt, but if you give it a negative number, you get 0 instead of a runtime
+/proc/sqrtor0(num)
+ if(num < 0)
+ return 0
+ return sqrt(num)
+
+/proc/round_down(num)
+ if(round(num) != num)
+ return round(num--)
+ else
+ return num
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index cf27ec09143..ad5e5df7583 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -431,7 +431,6 @@
#define LINDA_SPAWN_OXYGEN 8
#define LINDA_SPAWN_CO2 16
#define LINDA_SPAWN_NITROGEN 32
-
#define LINDA_SPAWN_N2O 64
-
+#define LINDA_SPAWN_AGENT_B 128
#define LINDA_SPAWN_AIR 256
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index e1e15a926d6..719274857ec 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -196,7 +196,7 @@
#define isslimeperson(A) (is_species(A, /datum/species/slime))
#define isgrey(A) (is_species(A, /datum/species/grey))
#define isdiona(A) (is_species(A, /datum/species/diona))
-#define ismachine(A) (is_species(A, /datum/species/machine))
+#define ismachineperson(A) (is_species(A, /datum/species/machine))
#define isdrask(A) (is_species(A, /datum/species/drask))
#define isanimal(A) (istype((A), /mob/living/simple_animal))
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index b0274e9d802..c15dfd78b0f 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -15,3 +15,57 @@
#define SOUND_MINIMUM_PRESSURE 10
#define FALLOFF_SOUNDS 0.5
+
+//Ambience types
+
+#define GENERIC_SOUNDS list('sound/ambience/ambigen1.ogg', 'sound/ambience/ambigen3.ogg',\
+ 'sound/ambience/ambigen4.ogg', 'sound/ambience/ambigen5.ogg',\
+ 'sound/ambience/ambigen6.ogg', 'sound/ambience/ambigen7.ogg',\
+ 'sound/ambience/ambigen8.ogg', 'sound/ambience/ambigen9.ogg',\
+ 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambigen11.ogg',\
+ 'sound/ambience/ambigen12.ogg', 'sound/ambience/ambigen14.ogg', 'sound/ambience/ambigen15.ogg')
+
+#define HOLY_SOUNDS list('sound/ambience/ambicha1.ogg', 'sound/ambience/ambicha2.ogg', 'sound/ambience/ambicha3.ogg',\
+ 'sound/ambience/ambicha4.ogg', 'sound/ambience/ambiholy.ogg', 'sound/ambience/ambiholy2.ogg',\
+ 'sound/ambience/ambiholy3.ogg')
+
+#define HIGHSEC_SOUNDS list('sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg')
+
+#define RUINS_SOUNDS list('sound/ambience/ambimine.ogg', 'sound/ambience/ambicave.ogg', 'sound/ambience/ambiruin.ogg',\
+ 'sound/ambience/ambiruin2.ogg', 'sound/ambience/ambiruin3.ogg', 'sound/ambience/ambiruin4.ogg',\
+ 'sound/ambience/ambiruin5.ogg', 'sound/ambience/ambiruin6.ogg', 'sound/ambience/ambiruin7.ogg',\
+ 'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambitech3.ogg',\
+ 'sound/ambience/ambimystery.ogg', 'sound/ambience/ambimaint1.ogg')
+
+#define ENGINEERING_SOUNDS list('sound/ambience/ambisin1.ogg', 'sound/ambience/ambisin2.ogg', 'sound/ambience/ambisin3.ogg', 'sound/ambience/ambisin4.ogg',\
+ 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg', 'sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg')
+
+#define MINING_SOUNDS list('sound/ambience/ambimine.ogg', 'sound/ambience/ambicave.ogg', 'sound/ambience/ambiruin.ogg',\
+ 'sound/ambience/ambiruin2.ogg', 'sound/ambience/ambiruin3.ogg', 'sound/ambience/ambiruin4.ogg',\
+ 'sound/ambience/ambiruin5.ogg', 'sound/ambience/ambiruin6.ogg', 'sound/ambience/ambiruin7.ogg',\
+ 'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint1.ogg',\
+ 'sound/ambience/ambilava1.ogg', 'sound/ambience/ambilava2.ogg', 'sound/ambience/ambilava3.ogg')
+
+#define MEDICAL_SOUNDS list('sound/ambience/ambinice.ogg')
+
+#define SPOOKY_SOUNDS list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/ambience/ambiruin7.ogg','sound/ambience/ambiruin6.ogg',\
+ 'sound/ambience/ambiodd.ogg', 'sound/ambience/ambimystery.ogg')
+
+#define SPACE_SOUNDS list('sound/ambience/ambispace.ogg', 'sound/ambience/ambispace2.ogg', 'sound/music/title2.ogg', 'sound/ambience/ambiatmos.ogg')
+
+#define MAINTENANCE_SOUNDS list('sound/ambience/ambimaint1.ogg', 'sound/ambience/ambimaint2.ogg', 'sound/ambience/ambimaint3.ogg', 'sound/ambience/ambimaint4.ogg',\
+ 'sound/ambience/ambimaint5.ogg', 'sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg', 'sound/ambience/ambitech2.ogg' )
+
+#define AWAY_MISSION_SOUNDS list('sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiruin.ogg',\
+ 'sound/ambience/ambiruin2.ogg', 'sound/ambience/ambiruin3.ogg', 'sound/ambience/ambiruin4.ogg',\
+ 'sound/ambience/ambiruin5.ogg', 'sound/ambience/ambiruin6.ogg', 'sound/ambience/ambiruin7.ogg',\
+ 'sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg', 'sound/ambience/ambimaint.ogg',\
+ 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg', 'sound/ambience/ambiodd.ogg')
+
+
+
+#define CREEPY_SOUNDS list('sound/effects/ghost.ogg', 'sound/effects/ghost2.ogg', 'sound/effects/heart_beat.ogg', 'sound/effects/screech.ogg',\
+ 'sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', 'sound/hallucinations/far_noise.ogg', 'sound/hallucinations/growl1.ogg', 'sound/hallucinations/growl2.ogg',\
+ 'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg', 'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
+ 'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
+ 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg', 'sound/hallucinations/veryfar_noise.ogg', 'sound/hallucinations/wail.ogg')
diff --git a/code/__DEFINES/stat.dm b/code/__DEFINES/stat.dm
index b0a74b6c702..c9763e4836c 100644
--- a/code/__DEFINES/stat.dm
+++ b/code/__DEFINES/stat.dm
@@ -3,7 +3,7 @@
#define UNCONSCIOUS 1
#define DEAD 2
-// NanoUI flags
+// NanoUI & TGUI flags
#define STATUS_INTERACTIVE 2 // GREEN Visability
#define STATUS_UPDATE 1 // ORANGE Visability
#define STATUS_DISABLED 0 // RED Visability
diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm
index f5d582f5e42..a3154834fe4 100644
--- a/code/__HELPERS/_logging.dm
+++ b/code/__HELPERS/_logging.dm
@@ -143,6 +143,9 @@ GLOBAL_VAR_INIT(log_end, (world.system_type == UNIX ? ascii2text(13) : ""))
/proc/log_runtime_summary(text)
WRITE_LOG(GLOB.runtime_summary_log, "[text]")
+/proc/log_tgui(text)
+ WRITE_LOG(GLOB.tgui_log, "[text]")
+
/**
* Standardized method for tracking startup times.
*/
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 366b8b3bcd9..bd077204f00 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -183,9 +183,6 @@
/proc/get_mobs_in_radio_ranges(var/list/obj/item/radio/radios)
-
- set background = 1
-
. = list()
// Returns a list of mobs who can hear any of the radios given in @radios
var/list/speaker_coverage = list()
@@ -347,7 +344,7 @@
for(var/i = 1; i <= GLOB.player_list.len; i++)
var/mob/M = GLOB.player_list[i]
if(M && M.client)
- if(istype(M, /mob/new_player)) // exclude people in the lobby
+ if(isnewplayer(M)) // exclude people in the lobby
continue
else if(isobserver(M)) // Ghosts are fine if they were playing once (didn't start as observers)
var/mob/dead/observer/O = M
@@ -428,12 +425,6 @@
if(pressure <= LAVALAND_EQUIPMENT_EFFECT_PRESSURE)
. = TRUE
-/proc/MinutesToTicks(var/minutes as num)
- return minutes * 60 * 10
-
-/proc/SecondsToTicks(var/seconds)
- return seconds * 10
-
proc/pollCandidates(Question, be_special_type, antag_age_check = FALSE, poll_time = 300, ignore_respawnability = FALSE, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
var/roletext = be_special_type ? get_roletext(be_special_type) : null
var/list/mob/dead/observer/candidates = list()
diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm
index dc256a93478..caa8291b4bb 100644
--- a/code/__HELPERS/icon_smoothing.dm
+++ b/code/__HELPERS/icon_smoothing.dm
@@ -61,7 +61,7 @@
var/adjacencies = 0
var/atom/movable/AM
- if(ismovableatom(A))
+ if(ismovable(A))
AM = A
if(AM.can_be_unanchored && !AM.anchored)
return 0
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 4e11dbf4140..ef0f47b2f9c 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -580,7 +580,7 @@ world
var/B = RGB[2]
var/Y = (0.2126 * R) + (0.7152 * G) + (0.0722 * B)
- return Clamp((Y * 0.01), 0, 1) //Returns the brightness of a color in decimal percentage format. Can multiply light_power by this to receive 100% brightness or a lower brightness. Not a higher brightness.
+ return clamp((Y * 0.01), 0, 1) //Returns the brightness of a color in decimal percentage format. Can multiply light_power by this to receive 100% brightness or a lower brightness. Not a higher brightness.
/proc/HueToAngle(hue)
// normalize hsv in case anything is screwy
@@ -899,9 +899,9 @@ The _flatIcons list is a cache for generated icon files.
if(!value) return color
var/list/RGB = ReadRGB(color)
- RGB[1] = Clamp(RGB[1]+value,0,255)
- RGB[2] = Clamp(RGB[2]+value,0,255)
- RGB[3] = Clamp(RGB[3]+value,0,255)
+ RGB[1] = clamp(RGB[1]+value,0,255)
+ RGB[2] = clamp(RGB[2]+value,0,255)
+ RGB[3] = clamp(RGB[3]+value,0,255)
return rgb(RGB[1],RGB[2],RGB[3])
/proc/sort_atoms_by_layer(var/list/atoms)
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index 7d1b8ee6ebc..f9b9850bd2d 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -690,6 +690,8 @@ proc/dd_sortedObjectList(list/incoming)
// LAZYING PT 2: THE LAZENING
#define LAZYREINITLIST(L) LAZYCLEARLIST(L); LAZYINITLIST(L);
+// Lazying Episode 3
+#define LAZYSET(L, K, V) LAZYINITLIST(L); L[K] = V;
//same, but returns nothing and acts on list in place
/proc/shuffle_inplace(list/L)
diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm
deleted file mode 100644
index 76d422e3d82..00000000000
--- a/code/__HELPERS/maths.dm
+++ /dev/null
@@ -1,143 +0,0 @@
-// Credits to Nickr5 for the useful procs I've taken from his library resource.
-
-#define MATH_E 2.71828183
-#define SQRT2 1.41421356
-
-/proc/Atan2(x, y)
- if(!x && !y) return 0
- var/a = arccos(x / sqrt(x*x + y*y))
- return y >= 0 ? a : -a
-
-// Greatest Common Divisor - Euclid's algorithm
-/proc/Gcd(a, b)
- return b ? Gcd(b, a % b) : a
-
-/proc/IsAboutEqual(a, b, deviation = 0.1)
- return abs(a - b) <= deviation
-
-// Performs a linear interpolation between a and b.
-// Note that amount=0 returns a, amount=1 returns b, and
-// amount=0.5 returns the mean of a and b.
-/proc/Lerp(a, b, amount = 0.5)
- return a + (b - a) * amount
-
-/proc/Mean(...)
- var/values = 0
- var/sum = 0
- for(var/val in args)
- values++
- sum += val
- return sum / values
-
-// The quadratic formula. Returns a list with the solutions, or an empty list
-// if they are imaginary.
-/proc/SolveQuadratic(a, b, c)
- ASSERT(a)
- . = list()
- var/d = b*b - 4 * a * c
- var/bottom = 2 * a
- if(d < 0) return
- var/root = sqrt(d)
- . += (-b + root) / bottom
- if(!d) return
- . += (-b - root) / bottom
-
-// Will filter out extra rotations and negative rotations
-// E.g: 540 becomes 180. -180 becomes 180.
-/proc/SimplifyDegrees(degrees)
- degrees = degrees % 360
- if(degrees < 0)
- degrees += 360
- return degrees
-
-// min is inclusive, max is exclusive
-/proc/Wrap(val, min, max)
- var/d = max - min
- var/t = Floor((val - min) / d)
- return val - (t * d)
-
-//A logarithm that converts an integer to a number scaled between 0 and 1 (can be tweaked to be higher).
-//Currently, this is used for hydroponics-produce sprite transforming, but could be useful for other transform functions.
-/proc/TransformUsingVariable(input, inputmaximum, scaling_modifier = 0)
-
- var/inputToDegrees = (input/inputmaximum)*180 //Converting from a 0 -> 100 scale to a 0 -> 180 scale. The 0 -> 180 scale corresponds to degrees
- var/size_factor = ((-cos(inputToDegrees) +1) /2) //returns a value from 0 to 1
-
- return size_factor + scaling_modifier //scale mod of 0 results in a number from 0 to 1. A scale modifier of +0.5 returns 0.5 to 1.5
- //world<< "Transform multiplier of [src] is [size_factor + scaling_modifer]"
-
-/proc/RaiseToPower(num, power)
- if(!power) return 1
- return (power-- > 1 ? num * RaiseToPower(num, power) : num)
-
-//converts a uniform distributed random number into a normal distributed one
-//since this method produces two random numbers, one is saved for subsequent calls
-//(making the cost negligble for every second call)
-//This will return +/- decimals, situated about mean with standard deviation stddev
-//68% chance that the number is within 1stddev
-//95% chance that the number is within 2stddev
-//98% chance that the number is within 3stddev...etc
-GLOBAL_VAR(gaussian_next)
-#define ACCURACY 10000
-/proc/gaussian(mean, stddev)
- var/R1;var/R2;var/working
- if(GLOB.gaussian_next != null)
- R1 = GLOB.gaussian_next
- GLOB.gaussian_next = null
- else
- do
- R1 = rand(-ACCURACY,ACCURACY)/ACCURACY
- R2 = rand(-ACCURACY,ACCURACY)/ACCURACY
- working = R1*R1 + R2*R2
- while(working >= 1 || working==0)
- working = sqrt(-2 * log(working) / working)
- R1 *= working
- GLOB.gaussian_next = R2 * working
- return (mean + stddev * R1)
-#undef ACCURACY
-
-
-
-// oof, what a mouthful
-// Used in status_procs' "adjust" to let them modify a status effect by a given
-// amount, without inadverdently increasing it in the wrong direction
-/proc/directional_bounded_sum(orig_val, modifier, bound_lower, bound_upper)
- var/new_val = orig_val + modifier
- if(modifier > 0)
- if(new_val > bound_upper)
- new_val = max(orig_val, bound_upper)
- else if(modifier < 0)
- if(new_val < bound_lower)
- new_val = min(orig_val, bound_lower)
- return new_val
-
-// sqrt, but if you give it a negative number, you get 0 instead of a runtime
-/proc/sqrtor0(num)
- if(num < 0)
- return 0
- return sqrt(num)
-
-/proc/round_down(num)
- if(round(num) != num)
- return round(num--)
- else return num
-
-// Returns a list where [1] is all x values and [2] is all y values that overlap between the given pair of rectangles
-/proc/get_overlap(x1, y1, x2, y2, x3, y3, x4, y4)
- var/list/region_x1 = list()
- var/list/region_y1 = list()
- var/list/region_x2 = list()
- var/list/region_y2 = list()
-
- // These loops create loops filled with x/y values that the boundaries inhabit
- // ex: list(5, 6, 7, 8, 9)
- for(var/i in min(x1, x2) to max(x1, x2))
- region_x1["[i]"] = TRUE
- for(var/i in min(y1, y2) to max(y1, y2))
- region_y1["[i]"] = TRUE
- for(var/i in min(x3, x4) to max(x3, x4))
- region_x2["[i]"] = TRUE
- for(var/i in min(y3, y4) to max(y3, y4))
- region_y2["[i]"] = TRUE
-
- return list(region_x1 & region_x2, region_y1 & region_y2)
diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
index ee6c5d10fe0..352a6fa3680 100644
--- a/code/__HELPERS/traits.dm
+++ b/code/__HELPERS/traits.dm
@@ -65,6 +65,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_WATERBREATH "waterbreathing"
#define TRAIT_BLOODCRAWL "bloodcrawl"
#define TRAIT_BLOODCRAWL_EAT "bloodcrawl_eat"
+#define TRAIT_JESTER "jester"
// common trait sources
#define ROUNDSTART_TRAIT "roundstart" //cannot be removed without admin intervention
diff --git a/code/__HELPERS/unique_ids.dm b/code/__HELPERS/unique_ids.dm
index 549f5c71016..b66b1a11b90 100644
--- a/code/__HELPERS/unique_ids.dm
+++ b/code/__HELPERS/unique_ids.dm
@@ -16,8 +16,6 @@
GLOBAL_VAR_INIT(next_unique_datum_id, 1)
-// /client/var/tmp/unique_datum_id = null
-
/datum/proc/UID()
if(!unique_datum_id)
var/tag_backup = tag
@@ -37,8 +35,6 @@ GLOBAL_VAR_INIT(next_unique_datum_id, 1)
var/datum/D = locate(copytext(uid, 1, splitat))
- // We might locate a client instead of a datum, but just using : is easier
- // than actually checking and typecasting
- if(D && D:unique_datum_id == uid)
+ if(D && D.unique_datum_id == uid)
return D
return null
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index aa130bb3ca9..63d9f7c85ef 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -25,11 +25,9 @@
if(!( istext(HTMLstring) ))
CRASH("Given non-text argument!")
- return
else
if(length(HTMLstring) != 7)
CRASH("Given non-HTML argument!")
- return
var/textr = copytext(HTMLstring, 2, 4)
var/textg = copytext(HTMLstring, 4, 6)
var/textb = copytext(HTMLstring, 6, 8)
@@ -46,7 +44,6 @@
if(length(textb) < 2)
textr = text("0[]", textb)
return text("#[][][]", textr, textg, textb)
- return
//Returns the middle-most value
/proc/dd_range(var/low, var/high, var/num)
@@ -332,8 +329,9 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/select_active_ai_with_fewest_borgs()
var/mob/living/silicon/ai/selected
var/list/active = active_ais()
- for(var/mob/living/silicon/ai/A in active)
- if(!selected || (selected.connected_robots > A.connected_robots))
+ for(var/thing in active)
+ var/mob/living/silicon/ai/A = thing
+ if(!selected || (length(selected.connected_robots) > length(A.connected_robots)))
selected = A
return selected
@@ -437,16 +435,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
return "[round((powerused * 0.000001), 0.001)] MW"
return "[round((powerused * 0.000000001), 0.0001)] GW"
-//E = MC^2
-/proc/convert2energy(var/M)
- var/E = M*(SPEED_OF_LIGHT_SQ)
- return E
-
-//M = E/C^2
-/proc/convert2mass(var/E)
- var/M = E/(SPEED_OF_LIGHT_SQ)
- return M
-
//Forces a variable to be posative
/proc/modulus(var/M)
if(M >= 0)
@@ -540,21 +528,6 @@ Returns 1 if the chain up to the area contains the given typepath
/proc/between(var/low, var/middle, var/high)
return max(min(middle, high), low)
-
-
-#if DM_VERSION > 513
-#warn 513 is definitely stable now, remove this
-#endif
-#if DM_VERSION < 513
-/proc/arctan(x)
- var/y=arcsin(x/sqrt(1+x*x))
- return y
-/proc/islist(list/list)
- if(istype(list))
- return 1
- return 0
-#endif
-
//returns random gauss number
proc/GaussRand(var/sigma)
var/x,y,rsq
@@ -1520,7 +1493,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//orbit() can run without it (swap orbiting for A)
//but then you can never stop it and that's just silly.
/atom/movable/var/atom/orbiting = null
-
+/atom/movable/var/cached_transform = null
//A: atom to orbit
//radius: range to orbit at, radius of the circle formed by orbiting
//clockwise: whether you orbit clockwise or anti clockwise
@@ -1538,6 +1511,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
orbiting = A
var/matrix/initial_transform = matrix(transform)
+ cached_transform = initial_transform
var/lastloc = loc
//Head first!
@@ -1555,8 +1529,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
- //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
- transform = initial_transform
while(orbiting && orbiting == A && A.loc)
var/targetloc = get_turf(A)
if(!lockinorbit && loc != lastloc && loc != targetloc)
@@ -1570,12 +1542,14 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
if(orbiting == A) //make sure we haven't started orbiting something else.
orbiting = null
- SpinAnimation(0,0)
+ SpinAnimation(0, 0)
+ transform = cached_transform
/atom/movable/proc/stop_orbit()
orbiting = null
+ transform = cached_transform
//Centers an image.
//Requires:
@@ -2035,6 +2009,10 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
tX = splittext(tX[1], ":")
tX = tX[1]
var/list/actual_view = getviewsize(C ? C.view : world.view)
- tX = Clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
- tY = Clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
+ tX = clamp(origin.x + text2num(tX) - round(actual_view[1] / 2) - 1, 1, world.maxx)
+ tY = clamp(origin.y + text2num(tY) - round(actual_view[2] / 2) - 1, 1, world.maxy)
return locate(tX, tY, tZ)
+
+/proc/CallAsync(datum/source, proctype, list/arguments)
+ set waitfor = FALSE
+ return call(source, proctype)(arglist(arguments))
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 536ea01cc96..342e572177a 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -1,6 +1,14 @@
#define DEBUG
//#define TESTING
+// Uncomment the following line to compile unit tests.
+// #define UNIT_TESTS
+
+
+#ifdef TRAVISBUILDING
+#define UNIT_TESTS
+#endif
+
#ifdef TESTING
//#define GC_FAILURE_HARD_LOOKUP //makes paths that fail to GC call find_references before del'ing.
//implies FIND_REF_NO_CHECK_TICK
@@ -11,8 +19,6 @@
#define IS_MODE_COMPILED(MODE) (ispath(text2path("/datum/game_mode/"+(MODE))))
-#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary.
-
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
#define MAX_MESSAGE_LEN 1024
#define MAX_PAPER_MESSAGE_LEN 3072
@@ -20,11 +26,13 @@
#define MAX_BOOK_MESSAGE_LEN 9216
#define MAX_NAME_LEN 50 //diona names can get loooooooong
-// Version check, terminates compilation if someone is using a version of BYOND that's too old
-#if DM_VERSION < 510
-#error OUTDATED VERSION ERROR - \
-Due to BYOND features used in this codebase, you must update to version 510 or later to compile. \
-This may require updating to a beta release.
+//Update this whenever you need to take advantage of more recent byond features
+#define MIN_COMPILER_VERSION 513
+#define MIN_COMPILER_BUILD 1514
+#if DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD
+//Don't forget to update this part
+#error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update.
+#error You need version 513.1514 or higher
#endif
// Macros that must exist before world.dm
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 2caa158757c..17444f66207 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -18,6 +18,8 @@ GLOBAL_LIST_EMPTY(player_list) //List of all mobs **with clients attached**.
GLOBAL_LIST_EMPTY(mob_list) //List of all mobs, including clientless
GLOBAL_LIST_EMPTY(silicon_mob_list) //List of all silicon mobs, including clientless
GLOBAL_LIST_EMPTY(mob_living_list) //all instances of /mob/living and subtypes
+GLOBAL_LIST_EMPTY(carbon_list) //all instances of /mob/living/carbon and subtypes, notably does not contain simple animals
+GLOBAL_LIST_EMPTY(human_list) //all instances of /mob/living/carbon/human and subtypes
GLOBAL_LIST_EMPTY(spirits) //List of all the spirits, including Masks
GLOBAL_LIST_EMPTY(alive_mob_list) //List of all alive mobs, including clientless. Excludes /mob/new_player
GLOBAL_LIST_EMPTY(dead_mob_list) //List of all dead mobs, including clientless. Excludes /mob/new_player
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 931a0e394e8..21af95cab48 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -16,7 +16,6 @@ GLOBAL_LIST_INIT(prisoncomputer_list, list())
GLOBAL_LIST_INIT(celltimers_list, list()) // list of all cell timers
GLOBAL_LIST_INIT(cell_logs, list())
GLOBAL_LIST_INIT(navigation_computers, list())
-GLOBAL_LIST_INIT(zombie_infection_list, list())
GLOBAL_LIST_INIT(all_areas, list())
GLOBAL_LIST_INIT(machines, list())
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index 0ea513708a1..f5f71e65c57 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -15,6 +15,8 @@ GLOBAL_VAR(world_asset_log)
GLOBAL_PROTECT(world_asset_log)
GLOBAL_VAR(runtime_summary_log)
GLOBAL_PROTECT(runtime_summary_log)
+GLOBAL_VAR(tgui_log)
+GLOBAL_PROTECT(tgui_log)
GLOBAL_LIST_EMPTY(jobMax)
GLOBAL_PROTECT(jobMax)
diff --git a/code/_globalvars/mapping.dm b/code/_globalvars/mapping.dm
index ca1c899e301..d67875db2de 100644
--- a/code/_globalvars/mapping.dm
+++ b/code/_globalvars/mapping.dm
@@ -3,8 +3,9 @@
#define Z_SOUTH 3
#define Z_WEST 4
-GLOBAL_LIST_INIT(cardinal, list( NORTH, SOUTH, EAST, WEST ))
+GLOBAL_LIST_INIT(cardinal, list(NORTH, SOUTH, EAST, WEST))
GLOBAL_LIST_INIT(alldirs, list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
+GLOBAL_LIST_INIT(alldirs2, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST, NORTH, SOUTH, EAST, WEST))
GLOBAL_LIST_INIT(diagonals, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
// This must exist early on or shit breaks bad
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index 32d6370f3d0..c541e40768a 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -4,7 +4,7 @@ GLOBAL_DATUM(slmaster, /obj/effect/overlay)
GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule
GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
-// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
+// Announcer intercom, because too much stuff creates an intercom for one message then qdel()s it.
GLOBAL_DATUM_INIT(global_announcer, /obj/item/radio/intercom, create_global_announcer())
GLOBAL_DATUM_INIT(command_announcer, /obj/item/radio/intercom/command, create_command_announcer())
@@ -101,3 +101,4 @@ GLOBAL_PROTECT(dbcon)
GLOBAL_LIST_EMPTY(ability_verbs) // Create-level abilities
GLOBAL_LIST_INIT(pipe_colors, list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE))
+
diff --git a/code/_globalvars/sensitive.dm b/code/_globalvars/sensitive.dm
index b1e6751c4dd..4c04b2d480b 100644
--- a/code/_globalvars/sensitive.dm
+++ b/code/_globalvars/sensitive.dm
@@ -9,4 +9,4 @@ GLOBAL_REAL_VAR(sqlfdbkdb) = "test"
GLOBAL_REAL_VAR(sqlfdbklogin) = "root"
GLOBAL_REAL_VAR(sqlfdbkpass) = ""
GLOBAL_REAL_VAR(sqlfdbktableprefix) = "erro_"
-
+GLOBAL_REAL_VAR(sql_version) = 0
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index d49c0ee59eb..a93e65c762b 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -19,9 +19,8 @@
if(!category)
return
- var/obj/screen/alert/alert
- if(alerts[category])
- alert = alerts[category]
+ var/obj/screen/alert/alert = LAZYACCESS(alerts, category)
+ if(alert)
if(alert.override_alerts)
return 0
if(new_master && new_master != alert.master)
@@ -57,7 +56,7 @@
alert.icon_state = "[initial(alert.icon_state)][severity]"
alert.severity = severity
- alerts[category] = alert
+ LAZYSET(alerts, category, alert) // This also creates the list if it doesn't exist
if(client && hud_used)
hud_used.reorganize_alerts()
alert.transform = matrix(32, 6, MATRIX_TRANSLATE)
@@ -72,7 +71,7 @@
// Proc to clear an existing alert.
/mob/proc/clear_alert(category, clear_override = FALSE)
- var/obj/screen/alert/alert = alerts[category]
+ var/obj/screen/alert/alert = LAZYACCESS(alerts, category)
if(!alert)
return 0
if(alert.override_alerts && !clear_override)
@@ -585,12 +584,14 @@ so as to remain in compliance with the most up-to-date laws."
// Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
/datum/hud/proc/reorganize_alerts()
var/list/alerts = mymob.alerts
+ if(!alerts)
+ return FALSE
var/icon_pref
if(!hud_shown)
- for(var/i = 1, i <= alerts.len, i++)
+ for(var/i in 1 to alerts.len)
mymob.client.screen -= alerts[alerts[i]]
- return 1
- for(var/i = 1, i <= alerts.len, i++)
+ return TRUE
+ for(var/i in 1 to alerts.len)
var/obj/screen/alert/alert = alerts[alerts[i]]
if(alert.icon_state == "template")
if(!icon_pref)
@@ -611,10 +612,10 @@ so as to remain in compliance with the most up-to-date laws."
. = ""
alert.screen_loc = .
mymob.client.screen |= alert
- return 1
+ return TRUE
/mob
- var/list/alerts = list() // contains /obj/screen/alert only // On /mob so clientless mobs will throw alerts properly
+ var/list/alerts // lazy list. contains /obj/screen/alert only // On /mob so clientless mobs will throw alerts properly
/obj/screen/alert/Click(location, control, params)
if(!usr || !usr.client)
diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm
index 68847cbd97d..d5fb5cad4fa 100644
--- a/code/_onclick/hud/parallax.dm
+++ b/code/_onclick/hud/parallax.dm
@@ -246,7 +246,7 @@
if(!view)
view = world.view
var/list/new_overlays = list()
- var/count = Ceiling(view/(480/world.icon_size))+1
+ var/count = CEILING(view/(480/world.icon_size), 1)+1
for(var/x in -count to count)
for(var/y in -count to count)
if(x == 0 && y == 0)
diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm
index 872659d714b..eda0cc5640d 100644
--- a/code/_onclick/hud/picture_in_picture.dm
+++ b/code/_onclick/hud/picture_in_picture.dm
@@ -102,8 +102,8 @@
overlays += standard_background
/obj/screen/movable/pic_in_pic/proc/set_view_size(width, height, do_refresh = TRUE)
- width = Clamp(width, 0, max_dimensions)
- height = Clamp(height, 0, max_dimensions)
+ width = clamp(width, 0, max_dimensions)
+ height = clamp(height, 0, max_dimensions)
src.width = width
src.height = height
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 14080274617..f048c3c393d 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -201,7 +201,7 @@
if(!R.robot_modules_background)
return
- var/display_rows = Ceiling(R.module.modules.len / 8)
+ var/display_rows = CEILING(R.module.modules.len / 8, 1)
R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7"
R.client.screen += R.robot_modules_background
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index e27002cf118..f88244c0cd8 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -75,8 +75,8 @@
if(hitsound)
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
- user.lastattacked = M
- M.lastattacker = user
+ M.lastattacker = user.real_name
+ M.lastattackerckey = user.ckey
user.do_attack_animation(M)
. = M.attacked_by(src, user, def_zone)
@@ -135,9 +135,9 @@
/obj/item/proc/get_clamped_volume()
if(w_class)
if(force)
- return Clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
+ return clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
else
- return Clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
+ return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
if(I.discrete)
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index 460bc0193f6..3452400edbb 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -15,7 +15,6 @@
// Otherwise jump
else
- following = null
forceMove(get_turf(A))
update_parallax_contents()
@@ -64,7 +63,7 @@
if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the health_scan var.
return
if(user.client && user.health_scan)
- if(issilicon(src) || ismachine(src))
+ if(issilicon(src) || ismachineperson(src))
robot_healthscan(user, src)
else if(ishuman(src))
healthscan(user, src, 1, TRUE)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 2f4811de380..083b347e52c 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -36,7 +36,7 @@
var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi)
var/vote_no_dead = 0 // dead people can't vote (tbi)
// var/enable_authentication = 0 // goon authentication
- var/del_new_on_log = 1 // del's new players if they log before they spawn in
+ var/del_new_on_log = 1 // qdel's new players if they log before they spawn in
var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard
var/traitor_scaling = 0 //if amount of traitors scales based on amount of players
var/protect_roles_from_antagonist = 0// If security and such can be tratior/cult/other
@@ -641,31 +641,31 @@
config.max_maint_drones = text2num(value)
if("expected_round_length")
- config.expected_round_length = MinutesToTicks(text2num(value))
+ config.expected_round_length = text2num(value) MINUTES
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]))
+ config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = values[1] MINUTES, "upper" = values[2] MINUTES)
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]))
+ config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = values[1] MINUTES, "upper" = values[2] MINUTES)
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]))
+ config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = values[1] MINUTES, "upper" = values[2] MINUTES)
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])
+ config.event_delay_lower[EVENT_LEVEL_MUNDANE] = values[1] MINUTES
+ config.event_delay_lower[EVENT_LEVEL_MODERATE] = values[2] MINUTES
+ config.event_delay_lower[EVENT_LEVEL_MAJOR] = values[3] MINUTES
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])
+ config.event_delay_upper[EVENT_LEVEL_MUNDANE] = values[1] MINUTES
+ config.event_delay_upper[EVENT_LEVEL_MODERATE] = values[2] MINUTES
+ config.event_delay_upper[EVENT_LEVEL_MAJOR] = values[3] MINUTES
if("starlight")
config.starlight = 1
@@ -701,7 +701,7 @@
config.max_loadout_points = text2num(value)
if("round_abandon_penalty_period")
- config.round_abandon_penalty_period = MinutesToTicks(text2num(value))
+ config.round_abandon_penalty_period = text2num(value) MINUTES
if("medal_hub_address")
config.medal_hub_address = value
@@ -809,7 +809,6 @@
/datum/configuration/proc/loadsql(filename) // -- TLE
var/list/Lines = file2list(filename)
- var/db_version = 0
for(var/t in Lines)
if(!t) continue
@@ -848,10 +847,13 @@
if("feedback_tableprefix")
sqlfdbktableprefix = value
if("db_version")
- db_version = text2num(value)
+ sql_version = text2num(value)
else
log_config("Unknown setting in configuration: '[name]'")
- if(config.sql_enabled && db_version != SQL_VERSION)
+
+ // The unit tests have their own version of this check, which wont hold the server up infinitely, so this is disabled if we are running unit tests
+ #ifndef UNIT_TESTS
+ if(config.sql_enabled && sql_version != SQL_VERSION)
config.sql_enabled = 0
log_config("WARNING: DB_CONFIG DEFINITION MISMATCH!")
spawn(60)
@@ -859,6 +861,7 @@
SSticker.ticker_going = FALSE
spawn(600)
to_chat(world, "DB_CONFIG MISMATCH, ROUND START DELAYED. Please check database version for recent upstream changes!")
+ #endif
/datum/configuration/proc/loadoverflowwhitelist(filename)
var/list/Lines = file2list(filename)
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index 5a520b547e1..691f19201f6 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -14,7 +14,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
var/datum/controller/exclude_these = new
gvars_datum_in_built_vars = exclude_these.vars + list("gvars_datum_protected_varlist", "gvars_datum_in_built_vars", "gvars_datum_init_order")
- qdel(exclude_these)
+ QDEL_IN(exclude_these, 0) //signal logging isn't ready
Initialize()
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index fea79c2f7a5..b8c3cdbf1e2 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -451,14 +451,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// in those cases, so we just let them run)
if(queue_node_flags & SS_NO_TICK_CHECK)
if(queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker)
- queue_node.queued_priority += queue_priority_count * 0.1
- queue_priority_count -= queue_node_priority
- queue_priority_count += queue_node.queued_priority
- current_tick_budget -= queue_node_priority
- queue_node = queue_node.queue_next
+ if(!(queue_node_flags & SS_BACKGROUND))
+ queue_node.queued_priority += queue_priority_count * 0.1
+ queue_priority_count -= queue_node_priority
+ queue_priority_count += queue_node.queued_priority
+ current_tick_budget -= queue_node_priority
+ queue_node = queue_node.queue_next
continue
- if((queue_node_flags & SS_BACKGROUND) && !bg_calc)
+ if(!bg_calc && (queue_node_flags & SS_BACKGROUND))
current_tick_budget = queue_priority_count_bg
bg_calc = TRUE
@@ -511,7 +512,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
queue_node.paused_ticks = 0
queue_node.paused_tick_usage = 0
- if(queue_node_flags & SS_BACKGROUND) //update our running total
+ if(bg_calc) //update our running total
queue_priority_count_bg -= queue_node_priority
else
queue_priority_count -= queue_node_priority
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index 68ee4bfeace..03e54df61c5 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -89,7 +89,7 @@
queue_node_flags = queue_node.flags
if(queue_node_flags & SS_TICKER)
- if(!(SS_flags & SS_TICKER))
+ if((SS_flags & (SS_TICKER|SS_BACKGROUND)) != SS_TICKER)
continue
if(queue_node_priority < SS_priority)
break
diff --git a/code/controllers/subsystem/afk.dm b/code/controllers/subsystem/afk.dm
index 037b9a2bd0a..951a7fb1786 100644
--- a/code/controllers/subsystem/afk.dm
+++ b/code/controllers/subsystem/afk.dm
@@ -49,7 +49,7 @@ SUBSYSTEM_DEF(afk)
if(mins_afk >= config.auto_cryo_afk && A.can_get_auto_cryod)
if(A.fast_despawn)
toRemove += H.ckey
- warn(H, "You are have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.")
+ warn(H, "You have been despawned after being AFK for [mins_afk] minutes. You have been despawned instantly due to you being in a secure area.")
log_afk_action(H, mins_afk, T, "despawned", "AFK in a fast despawn area")
force_cryo_human(H)
else
@@ -67,7 +67,7 @@ SUBSYSTEM_DEF(afk)
else if(afk_players[H.ckey] != AFK_ADMINS_WARNED && mins_afk >= config.auto_despawn_afk)
log_afk_action(H, mins_afk, T, "despawned")
- warn(H, "You are have been despawned after being AFK for [mins_afk] minutes.")
+ warn(H, "You have been despawned after being AFK for [mins_afk] minutes.")
toRemove += H.ckey
force_cryo_human(H)
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
new file mode 100644
index 00000000000..09dea24071f
--- /dev/null
+++ b/code/controllers/subsystem/dcs.dm
@@ -0,0 +1,53 @@
+PROCESSING_SUBSYSTEM_DEF(dcs)
+ name = "Datum Component System"
+ flags = SS_NO_INIT
+
+ var/list/elements_by_type = list()
+
+/datum/controller/subsystem/processing/dcs/Recover()
+ comp_lookup = SSdcs.comp_lookup
+
+/datum/controller/subsystem/processing/dcs/proc/GetElement(list/arguments)
+ var/datum/element/eletype = arguments[1]
+ var/element_id = eletype
+
+ if(!ispath(eletype, /datum/element))
+ CRASH("Attempted to instantiate [eletype] as a /datum/element")
+
+ if(initial(eletype.element_flags) & ELEMENT_BESPOKE)
+ element_id = GetIdFromArguments(arguments)
+
+ . = elements_by_type[element_id]
+ if(.)
+ return
+ . = elements_by_type[element_id] = new eletype
+
+/****
+ * Generates an id for bespoke elements when given the argument list
+ * Generating the id here is a bit complex because we need to support named arguments
+ * Named arguments can appear in any order and we need them to appear after ordered arguments
+ * We assume that no one will pass in a named argument with a value of null
+ **/
+/datum/controller/subsystem/processing/dcs/proc/GetIdFromArguments(list/arguments)
+ var/datum/element/eletype = arguments[1]
+ var/list/fullid = list("[eletype]")
+ var/list/named_arguments = list()
+ for(var/i in initial(eletype.id_arg_index) to length(arguments))
+ var/key = arguments[i]
+ var/value
+ if(istext(key))
+ value = arguments[key]
+ if(!(istext(key) || isnum(key)))
+ key = "\ref[key]"
+ key = "[key]" // Key is stringified so numbers dont break things
+ if(!isnull(value))
+ if(!(istext(value) || isnum(value)))
+ value = "\ref[value]"
+ named_arguments["[key]"] = value
+ else
+ fullid += "[key]"
+
+ if(length(named_arguments))
+ named_arguments = sortList(named_arguments)
+ fullid += named_arguments
+ return list2params(fullid)
diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm
index ad77904bac7..1a6e073c808 100644
--- a/code/controllers/subsystem/events.dm
+++ b/code/controllers/subsystem/events.dm
@@ -90,7 +90,7 @@ SUBSYSTEM_DEF(events)
if(E.isRunning)
message += "and is still running."
else
- if(E.endedAt - E.startedAt > MinutesToTicks(5)) // Only mention end time if the entire duration was more than 5 minutes
+ if(E.endedAt - E.startedAt > 5 MINUTES) // Only mention end time if the entire duration was more than 5 minutes
message += "and ended at [station_time_timestamp("hh:mm:ss", E.endedAt)]."
else
message += "and ran to completion."
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index cbf17d05fbf..619508544a6 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -7,7 +7,7 @@ SUBSYSTEM_DEF(garbage)
init_order = INIT_ORDER_GARBAGE
offline_implications = "Garbage collection is no longer functional, and objects will not be qdel'd. Immediate server restart recommended."
- var/list/collection_timeout = list(0, 2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
+ var/list/collection_timeout = list(2 MINUTES, 10 SECONDS) // deciseconds to wait before moving something up in the queue to the next level
//Stat tracking
var/delslasttick = 0 // number of del()'s we've done this tick
diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm
index 9dd6fce1554..ecbf1471993 100644
--- a/code/controllers/subsystem/input.dm
+++ b/code/controllers/subsystem/input.dm
@@ -121,3 +121,8 @@ SUBSYSTEM_DEF(input)
for(var/i in 1 to clients.len)
var/client/C = clients[i]
C.keyLoop()
+
+/datum/controller/subsystem/input/Recover()
+ macro_sets = SSinput.macro_sets
+ movement_keys = SSinput.movement_keys
+ alt_movement_keys = SSinput.alt_movement_keys
diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm
index 3fc92a3346a..6761e9647d9 100644
--- a/code/controllers/subsystem/lighting.dm
+++ b/code/controllers/subsystem/lighting.dm
@@ -1,16 +1,15 @@
-GLOBAL_LIST_EMPTY(lighting_update_lights) // List of lighting sources queued for update.
-GLOBAL_LIST_EMPTY(lighting_update_corners) // List of lighting corners queued for update.
-GLOBAL_LIST_EMPTY(lighting_update_objects) // List of lighting objects queued for update.
-
SUBSYSTEM_DEF(lighting)
name = "Lighting"
wait = 2
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
offline_implications = "Lighting will no longer update. Shuttle call recommended."
+ var/static/list/sources_queue = list() // List of lighting sources queued for update.
+ var/static/list/corners_queue = list() // List of lighting corners queued for update.
+ var/static/list/objects_queue = list() // List of lighting objects queued for update.
/datum/controller/subsystem/lighting/stat_entry()
- ..("L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]")
+ ..("L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]")
/datum/controller/subsystem/lighting/Initialize(timeofday)
if(!initialized)
@@ -31,9 +30,10 @@ SUBSYSTEM_DEF(lighting)
MC_SPLIT_TICK_INIT(3)
if(!init_tick_checks)
MC_SPLIT_TICK
+ var/list/queue = sources_queue
var/i = 0
- for(i in 1 to GLOB.lighting_update_lights.len)
- var/datum/light_source/L = GLOB.lighting_update_lights[i]
+ for(i in 1 to length(queue))
+ var/datum/light_source/L = queue[i]
L.update_corners()
@@ -44,14 +44,15 @@ SUBSYSTEM_DEF(lighting)
else if(MC_TICK_CHECK)
break
if(i)
- GLOB.lighting_update_lights.Cut(1, i+1)
+ queue.Cut(1, i + 1)
i = 0
if(!init_tick_checks)
MC_SPLIT_TICK
- for (i in 1 to GLOB.lighting_update_corners.len)
- var/datum/lighting_corner/C = GLOB.lighting_update_corners[i]
+ queue = corners_queue
+ for(i in 1 to length(queue))
+ var/datum/lighting_corner/C = queue[i]
C.update_objects()
C.needs_update = FALSE
@@ -60,15 +61,16 @@ SUBSYSTEM_DEF(lighting)
else if(MC_TICK_CHECK)
break
if(i)
- GLOB.lighting_update_corners.Cut(1, i+1)
+ queue.Cut(1, i + 1)
i = 0
if(!init_tick_checks)
MC_SPLIT_TICK
- for (i in 1 to GLOB.lighting_update_objects.len)
- var/atom/movable/lighting_object/O = GLOB.lighting_update_objects[i]
+ queue = objects_queue
+ for(i in 1 to length(queue))
+ var/atom/movable/lighting_object/O = queue[i]
if(QDELETED(O))
continue
@@ -80,7 +82,7 @@ SUBSYSTEM_DEF(lighting)
else if(MC_TICK_CHECK)
break
if(i)
- GLOB.lighting_update_objects.Cut(1, i+1)
+ queue.Cut(1, i + 1)
/datum/controller/subsystem/lighting/Recover()
diff --git a/code/controllers/subsystem/nano_mob_hunter.dm b/code/controllers/subsystem/nano_mob_hunter.dm
index 9094bf9fe2b..19b57f59a70 100644
--- a/code/controllers/subsystem/nano_mob_hunter.dm
+++ b/code/controllers/subsystem/nano_mob_hunter.dm
@@ -103,12 +103,12 @@ SUBSYSTEM_DEF(mob_hunt)
return
if(red_terminal && red_terminal.ready && blue_terminal && blue_terminal.ready)
battle_turn = pick("Red", "Blue")
- red_terminal.audible_message("Battle starting!", null, 5)
- blue_terminal.audible_message("Battle starting!", null, 5)
+ red_terminal.atom_say("Battle starting!")
+ blue_terminal.atom_say("Battle starting!")
if(battle_turn == "Red")
- red_terminal.audible_message("Red Player's Turn!", null, 5)
+ red_terminal.atom_say("Red Player's Turn!")
else if(battle_turn == "Blue")
- blue_terminal.audible_message("Blue Player's Turn!", null, 5)
+ blue_terminal.atom_say("Blue Player's Turn!")
/datum/controller/subsystem/mob_hunt/proc/launch_attack(team, raw_damage, datum/mob_type/attack_type)
if(!team || !raw_damage)
@@ -135,11 +135,11 @@ SUBSYSTEM_DEF(mob_hunt)
winner_terminal.ready = 0
loser_terminal.ready = 0
if(surrender) //surrender doesn't give exp, to avoid people just farming exp without actually doing a battle
- winner_terminal.audible_message("Your rival surrendered!", null, 2)
+ winner_terminal.atom_say("Your rival surrendered!")
else
var/progress_message = winner_terminal.mob_info.gain_exp()
- winner_terminal.audible_message("[winner_terminal.team] Player wins!", null, 5)
- winner_terminal.audible_message(progress_message, null, 2)
+ winner_terminal.atom_say("[winner_terminal.team] Player wins!")
+ winner_terminal.atom_say(progress_message)
/datum/controller/subsystem/mob_hunt/proc/end_turn()
red_terminal.updateUsrDialog()
@@ -148,7 +148,7 @@ SUBSYSTEM_DEF(mob_hunt)
return
if(battle_turn == "Red")
battle_turn = "Blue"
- blue_terminal.audible_message("Blue's turn.", null, 5)
+ blue_terminal.atom_say("Blue's turn.")
else if(battle_turn == "Blue")
battle_turn = "Red"
- blue_terminal.audible_message("Red's turn.", null, 5)
+ blue_terminal.atom_say("Red's turn.")
diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm
new file mode 100644
index 00000000000..c4240021137
--- /dev/null
+++ b/code/controllers/subsystem/tgui.dm
@@ -0,0 +1,286 @@
+ /**
+ * tgui subsystem
+ *
+ * Contains all tgui state and subsystem code.
+ **/
+
+
+SUBSYSTEM_DEF(tgui)
+ name = "TGUI"
+ wait = 9
+ flags = SS_NO_INIT
+ priority = FIRE_PRIORITY_NANOUI // Yes I am aware that this is TGUI and I used the nanoUI fire priority. Dont @ me.
+ runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
+ offline_implications = "All TGUIs will no longer process. Shuttle call recommended."
+
+ var/list/currentrun = list()
+ var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
+ var/list/processing_uis = list() // A list of processing UIs, ungrouped.
+ var/basehtml // The HTML base used for all UIs.
+
+/datum/controller/subsystem/tgui/PreInit()
+ basehtml = file2text('tgui/packages/tgui/public/tgui.html')
+
+/datum/controller/subsystem/tgui/Shutdown()
+ close_all_uis()
+
+/datum/controller/subsystem/tgui/stat_entry()
+ ..("P:[processing_uis.len]")
+
+/datum/controller/subsystem/tgui/fire(resumed = 0)
+ if (!resumed)
+ src.currentrun = processing_uis.Copy()
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+
+ while(currentrun.len)
+ var/datum/tgui/ui = currentrun[currentrun.len]
+ currentrun.len--
+ if(ui && ui.user && ui.src_object)
+ ui.process()
+ else
+ processing_uis.Remove(ui)
+ if (MC_TICK_CHECK)
+ return
+
+ /**
+ * public
+ *
+ * Get a open UI given a user, src_object, and ui_key and try to update it with data.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required src_object datum The object/datum which owns the UI.
+ * required ui_key string The ui_key of the UI.
+ * optional ui datum/tgui The UI to be updated, if it exists.
+ * optional force_open bool If the UI should be re-opened instead of updated.
+ *
+ * return datum/tgui The found UI.
+ **/
+/datum/controller/subsystem/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = FALSE)
+ if(isnull(ui)) // No UI was passed, so look for one.
+ ui = get_open_ui(user, src_object, ui_key)
+
+ if(!isnull(ui))
+ var/data = src_object.tgui_data(user) // Get data from the src_object.
+ if(!force_open) // UI is already open; update it.
+ ui.push_data(data)
+ else // Re-open it anyways.
+ ui.reinitialize(null, data)
+ return ui // We found the UI, return it.
+ else
+ return null // We couldn't find a UI.
+
+ /**
+ * private
+ *
+ * Get a open UI given a user, src_object, and ui_key.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * required src_object datum The object/datum which owns the UI.
+ * required ui_key string The ui_key of the UI.
+ *
+ * return datum/tgui The found UI.
+ **/
+/datum/controller/subsystem/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key)
+ var/src_object_key = "[src_object.UID()]"
+ if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return null // No UIs open.
+ else if(isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
+ return null // No UIs open for this object.
+
+ for(var/datum/tgui/ui in open_uis[src_object_key][ui_key]) // Find UIs for this object.
+ if(ui.user == user) // Make sure we have the right user
+ return ui
+
+ return null // Couldn't find a UI!
+
+ /**
+ * private
+ *
+ * Update all UIs attached to src_object.
+ *
+ * required src_object datum The object/datum which owns the UIs.
+ *
+ * return int The number of UIs updated.
+ **/
+/datum/controller/subsystem/tgui/proc/update_uis(datum/src_object)
+ var/src_object_key = "[src_object.UID()]"
+ if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return 0 // Couldn't find any UIs for this object.
+
+ var/update_count = 0
+ for(var/ui_key in open_uis[src_object_key])
+ for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
+ if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
+ ui.process(force = 1) // Update the UI.
+ update_count++ // Count each UI we update.
+ return update_count
+
+ /**
+ * private
+ *
+ * Close all UIs attached to src_object.
+ *
+ * required src_object datum The object/datum which owns the UIs.
+ *
+ * return int The number of UIs closed.
+ **/
+/datum/controller/subsystem/tgui/proc/close_uis(datum/src_object)
+ var/src_object_key = "[src_object.UID()]"
+ if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return 0 // Couldn't find any UIs for this object.
+
+ var/close_count = 0
+ for(var/ui_key in open_uis[src_object_key])
+ for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
+ if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
+ ui.close() // Close the UI.
+ close_count++ // Count each UI we close.
+ return close_count
+
+ /**
+ * private
+ *
+ * Close *ALL* UIs
+ *
+ * return int The number of UIs closed.
+ **/
+/datum/controller/subsystem/tgui/proc/close_all_uis()
+ var/close_count = 0
+ for(var/src_object_key in open_uis)
+ for(var/ui_key in open_uis[src_object_key])
+ for(var/datum/tgui/ui in open_uis[src_object_key][ui_key])
+ if(ui && ui.src_object && ui.user && ui.src_object.tgui_host(ui.user)) // Check the UI is valid.
+ ui.close() // Close the UI.
+ close_count++ // Count each UI we close.
+ return close_count
+
+ /**
+ * private
+ *
+ * Update all UIs belonging to a user.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * optional src_object datum If provided, only update UIs belonging this src_object.
+ * optional ui_key string If provided, only update UIs with this UI key.
+ *
+ * return int The number of UIs updated.
+ **/
+/datum/controller/subsystem/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null)
+ if(isnull(user.open_tguis) || !istype(user.open_tguis, /list) || open_uis.len == 0)
+ return 0 // Couldn't find any UIs for this user.
+
+ var/update_count = 0
+ for(var/datum/tgui/ui in user.open_tguis)
+ if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.process(force = 1) // Update the UI.
+ update_count++ // Count each UI we upadte.
+ return update_count
+
+ /**
+ * private
+ *
+ * Close all UIs belonging to a user.
+ *
+ * required user mob The mob who opened/is using the UI.
+ * optional src_object datum If provided, only close UIs belonging this src_object.
+ * optional ui_key string If provided, only close UIs with this UI key.
+ *
+ * return int The number of UIs closed.
+ **/
+/datum/controller/subsystem/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null)
+ if(isnull(user.open_tguis) || !istype(user.open_tguis, /list) || open_uis.len == 0)
+ return 0 // Couldn't find any UIs for this user.
+
+ var/close_count = 0
+ for(var/datum/tgui/ui in user.open_tguis)
+ if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.close() // Close the UI.
+ close_count++ // Count each UI we close.
+ return close_count
+
+ /**
+ * private
+ *
+ * Add a UI to the list of open UIs.
+ *
+ * required ui datum/tgui The UI to be added.
+ **/
+/datum/controller/subsystem/tgui/proc/on_open(datum/tgui/ui)
+ var/src_object_key = "[ui.src_object.UID()]"
+ if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object.
+ else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
+ open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key.
+
+ // Append the UI to all the lists.
+ ui.user.open_tguis |= ui
+ var/list/uis = open_uis[src_object_key][ui.ui_key]
+ uis |= ui
+ processing_uis |= ui
+
+ /**
+ * private
+ *
+ * Remove a UI from the list of open UIs.
+ *
+ * required ui datum/tgui The UI to be removed.
+ *
+ * return bool If the UI was removed or not.
+ **/
+/datum/controller/subsystem/tgui/proc/on_close(datum/tgui/ui)
+ var/src_object_key = "[ui.src_object.UID()]"
+ if(isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
+ return FALSE // It wasn't open.
+ else if(isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
+ return FALSE // It wasn't open.
+
+ processing_uis.Remove(ui) // Remove it from the list of processing UIs.
+ if(ui.user) // If the user exists, remove it from them too.
+ ui.user.open_tguis.Remove(ui)
+ var/Ukey = ui.ui_key
+ var/list/uis = open_uis[src_object_key][Ukey] // Remove it from the list of open UIs.
+ uis.Remove(ui)
+ if(!uis.len)
+ var/list/uiobj = open_uis[src_object_key]
+ uiobj.Remove(Ukey)
+ if(!uiobj.len)
+ open_uis.Remove(src_object_key)
+
+ return TRUE // Let the caller know we did it.
+
+ /**
+ * private
+ *
+ * Handle client logout, by closing all their UIs.
+ *
+ * required user mob The mob which logged out.
+ *
+ * return int The number of UIs closed.
+ **/
+/datum/controller/subsystem/tgui/proc/on_logout(mob/user)
+ return close_user_uis(user)
+
+ /**
+ * private
+ *
+ * Handle clients switching mobs, by transferring their UIs.
+ *
+ * required user source The client's original mob.
+ * required user target The client's new mob.
+ *
+ * return bool If the UIs were transferred.
+ **/
+/datum/controller/subsystem/tgui/proc/on_transfer(mob/source, mob/target)
+ if(!source || isnull(source.open_tguis) || !istype(source.open_tguis, /list) || open_uis.len == 0)
+ return FALSE // The old mob had no open UIs.
+
+ if(isnull(target.open_tguis) || !istype(target.open_tguis, /list))
+ target.open_tguis = list() // Create a list for the new mob if needed.
+
+ for(var/datum/tgui/ui in source.open_tguis)
+ ui.user = target // Inform the UIs of their new owner.
+ target.open_tguis.Add(ui) // Transfer all the UIs.
+
+ source.open_tguis.Cut() // Clear the old list.
+ return TRUE // Let the caller know we did it.
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 228f1a7c528..6f8dd85b79b 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -279,7 +279,9 @@ SUBSYSTEM_DEF(ticker)
for(var/mob/new_player/N in GLOB.mob_list)
if(N.client)
N.new_player_panel_proc()
-
+ #ifdef UNIT_TESTS
+ RunUnitTests()
+ #endif
return 1
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(station_missed = 0, override = null)
@@ -405,7 +407,7 @@ SUBSYSTEM_DEF(ticker)
EquipCustomItems(player)
if(captainless)
for(var/mob/M in GLOB.player_list)
- if(!istype(M,/mob/new_player))
+ if(!isnewplayer(M))
to_chat(M, "Captainship not forced on anyone.")
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index 7bb6a496274..53d77e8fad6 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -160,7 +160,7 @@ SUBSYSTEM_DEF(timer)
if(timer.timeToRun < head_offset)
bucket_resolution = null //force bucket recreation
- CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ stack_trace("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
@@ -172,7 +172,7 @@ SUBSYSTEM_DEF(timer)
if(timer.timeToRun < head_offset + TICKS2DS(practical_offset-1))
bucket_resolution = null //force bucket recreation
- CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
+ stack_trace("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm
index bf405444110..30186f80ad1 100644
--- a/code/controllers/subsystem/weather.dm
+++ b/code/controllers/subsystem/weather.dm
@@ -57,7 +57,6 @@ SUBSYSTEM_DEF(weather)
break
if(!ispath(weather_datum_type, /datum/weather))
CRASH("run_weather called with invalid weather_datum_type: [weather_datum_type || "null"]")
- return
if(isnull(z_levels))
z_levels = levels_by_trait(initial(weather_datum_type.target_trait))
@@ -65,7 +64,6 @@ SUBSYSTEM_DEF(weather)
z_levels = list(z_levels)
else if(!islist(z_levels))
CRASH("run_weather called with invalid z_levels: [z_levels || "null"]")
- return
var/datum/weather/W = new weather_datum_type(z_levels)
W.telegraph()
diff --git a/code/datums/action.dm b/code/datums/action.dm
index b7af84e9ddf..c1802da47c1 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -339,7 +339,7 @@
/datum/action/item_action/remove_tape/Trigger(attack_self = FALSE)
if(..())
- GET_COMPONENT_FROM(DT, /datum/component/ducttape, target)
+ var/datum/component/ducttape/DT = target.GetComponent(/datum/component/ducttape)
DT.remove_tape(target, usr)
/datum/action/item_action/toggle_jetpack
diff --git a/code/datums/armor.dm b/code/datums/armor.dm
new file mode 100644
index 00000000000..0de7dde1ee7
--- /dev/null
+++ b/code/datums/armor.dm
@@ -0,0 +1,69 @@
+#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]"
+
+/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
+ . = locate(ARMORID)
+ if (!.)
+ . = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
+
+/datum/armor
+ var/melee
+ var/bullet
+ var/laser
+ var/energy
+ var/bomb
+ var/bio
+ var/rad
+ var/fire
+ var/acid
+ var/magic
+
+/datum/armor/New(melee_value = 0, bullet_value = 0, laser_value = 0, energy_value = 0, bomb_value = 0, bio_value = 0, rad_value = 0, fire_value = 0, acid_value = 0, magic_value = 0)
+ melee = melee_value
+ bullet = bullet_value
+ laser = laser_value
+ energy = energy_value
+ bomb = bomb_value
+ bio = bio_value
+ rad = rad_value
+ fire = fire_value
+ acid = acid_value
+ magic = magic_value
+ tag = ARMORID
+
+/datum/armor/proc/modifyRating(melee_value = 0, bullet_value = 0, laser_value = 0, energy_value = 0, bomb_value = 0, bio_value = 0, rad_value = 0, fire_value = 0, acid_value = 0, magic_value = 0)
+ return getArmor(melee + melee_value, bullet + bullet_value, laser + laser_value, energy + energy_value, bomb + bomb_value, bio + bio_value, rad + rad_value, fire + fire_value, acid + acid_value, magic + magic_value)
+
+/datum/armor/proc/modifyAllRatings(modifier = 0)
+ return getArmor(melee + modifier, bullet + modifier, laser + modifier, energy + modifier, bomb + modifier, bio + modifier, rad + modifier, fire + modifier, acid + modifier, magic + modifier)
+
+/datum/armor/proc/setRating(melee_value, bullet_value, laser_value, energy_value, bomb_value, bio_value, rad_value, fire_value, acid_value, magic_value)
+ return getArmor((isnull(melee_value) ? melee : melee_value),\
+ (isnull(bullet_value) ? bullet : bullet_value),\
+ (isnull(laser_value) ? laser : laser_value),\
+ (isnull(energy_value) ? energy : energy_value),\
+ (isnull(bomb_value) ? bomb : bomb_value),\
+ (isnull(bio_value) ? bio : bio_value),\
+ (isnull(rad_value) ? rad : rad_value),\
+ (isnull(fire_value) ? fire : fire_value),\
+ (isnull(acid_value) ? acid : acid_value),\
+ (isnull(magic_value) ? magic : magic_value))
+
+/datum/armor/proc/getRating(rating)
+ return vars[rating]
+
+/datum/armor/proc/getList()
+ return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic)
+
+/datum/armor/proc/attachArmor(datum/armor/AA)
+ return getArmor(melee + AA.melee, bullet + AA.bullet, laser + AA.laser, energy + AA.energy, bomb + AA.bomb, bio + AA.bio, rad + AA.rad, fire + AA.fire, acid + AA.acid, magic + AA.magic)
+
+/datum/armor/proc/detachArmor(datum/armor/AA)
+ return getArmor(melee - AA.melee, bullet - AA.bullet, laser - AA.laser, energy - AA.energy, bomb - AA.bomb, bio - AA.bio, rad - AA.rad, fire - AA.fire, acid - AA.acid, magic - AA.magic)
+
+/datum/armor/vv_edit_var(var_name, var_value)
+ if (var_name == NAMEOF(src, tag))
+ return FALSE
+ . = ..()
+ tag = ARMORID // update tag in case armor values were edited
+
+#undef ARMORID
diff --git a/code/datums/beam.dm b/code/datums/beam.dm
index 86f816662c0..19935bda130 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -99,11 +99,11 @@
//Position the effect so the beam is one continous line
var/a
if(abs(Pixel_x)>32)
- a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
+ a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
X.x += a
Pixel_x %= 32
if(abs(Pixel_y)>32)
- a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
+ a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
X.y += a
Pixel_y %= 32
diff --git a/code/datums/cache/crew.dm b/code/datums/cache/crew.dm
index 21ec5ebcc79..f92bab9cf7a 100644
--- a/code/datums/cache/crew.dm
+++ b/code/datums/cache/crew.dm
@@ -4,7 +4,7 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
cache_data = list()
..()
-/datum/repository/crew/proc/health_data(var/turf/T)
+/datum/repository/crew/proc/health_data(turf/T)
var/list/crewmembers = list()
if(!T)
return crewmembers
@@ -18,50 +18,40 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
if(world.time < cache_entry.timestamp)
return cache_entry.data
- var/tracked = scan()
- for(var/obj/item/clothing/under/C in tracked)
+ for(var/thing in GLOB.human_list)
+ var/mob/living/carbon/human/H = thing
+ var/obj/item/clothing/under/C = H.w_uniform
+ if(!C || C.sensor_mode == SUIT_SENSOR_OFF || !C.has_sensor)
+ continue
var/turf/pos = get_turf(C)
- if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
- if(istype(C.loc, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = C.loc
- if(H.w_uniform != C)
- continue
+ if(!T || pos.z != T.z)
+ continue
+ var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
- var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
+ crewmemberData["sensor_type"] = C.sensor_mode
+ crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
+ crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
+ crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
- crewmemberData["sensor_type"] = C.sensor_mode
- crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
- crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
- crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
+ if(C.sensor_mode >= SUIT_SENSOR_BINARY)
+ crewmemberData["dead"] = H.stat > UNCONSCIOUS
- if(C.sensor_mode >= SUIT_SENSOR_BINARY)
- crewmemberData["dead"] = H.stat > UNCONSCIOUS
+ if(C.sensor_mode >= SUIT_SENSOR_VITAL)
+ crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
+ crewmemberData["tox"] = round(H.getToxLoss(), 1)
+ crewmemberData["fire"] = round(H.getFireLoss(), 1)
+ crewmemberData["brute"] = round(H.getBruteLoss(), 1)
- if(C.sensor_mode >= SUIT_SENSOR_VITAL)
- crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
- crewmemberData["tox"] = round(H.getToxLoss(), 1)
- crewmemberData["fire"] = round(H.getFireLoss(), 1)
- crewmemberData["brute"] = round(H.getBruteLoss(), 1)
+ if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
+ var/area/A = get_area(H)
+ crewmemberData["area"] = sanitize(A.name)
+ crewmemberData["x"] = pos.x
+ crewmemberData["y"] = pos.y
- if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
- var/area/A = get_area(H)
- crewmemberData["area"] = sanitize(A.name)
- crewmemberData["x"] = pos.x
- crewmemberData["y"] = pos.y
-
- crewmembers[++crewmembers.len] = crewmemberData
+ crewmembers[++crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name")
cache_entry.timestamp = world.time + 5 SECONDS
cache_entry.data = crewmembers
return crewmembers
-
-/datum/repository/crew/proc/scan()
- var/list/tracked = list()
- for(var/mob/living/carbon/human/H in GLOB.mob_list)
- if(istype(H.w_uniform, /obj/item/clothing/under))
- var/obj/item/clothing/under/C = H.w_uniform
- if(C.has_sensor)
- tracked |= C
- return tracked
diff --git a/code/datums/components/README.md b/code/datums/components/README.md
index 9d06a255dd7..03f7d3a5875 100644
--- a/code/datums/components/README.md
+++ b/code/datums/components/README.md
@@ -2,134 +2,8 @@
## Concept
-Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SEND_SIGNAL` call. Now every component that want's to can also know about this happening.
+Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
-### In the code
+See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
-#### Slippery things
-
-At the time of this writing, every object that is slippery overrides atom/Crossed does some checks, then slips the mob. Instead of all those Crossed overrides they could add a slippery component to all these objects. And have the checks in one proc that is run by the Crossed event
-
-#### Powercells
-
-A lot of objects have powercells. The `get_cell()` proc was added to give generic access to the cell var if it had one. This is just a specific use case of `GetComponent()`
-
-#### Radios
-
-The radio object as it is should not exist, given that more things use the _concept_ of radios rather than the object itself. The actual function of the radio can exist in a component which all the things that use it (Request consoles, actual radios, the SM shard) can add to themselves.
-
-#### Standos
-
-Stands have a lot of procs which mimic mob procs. Rather than inserting hooks for all these procs in overrides, the same can be accomplished with signals
-
-## API
-
-### Defines
-
-1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned. This will be noted in the runtime logs
-
-### Vars
-
-1. `/datum/var/list/datum_components` (private)
- * Lazy associated list of type -> component/list of components.
-1. `/datum/var/list/comp_lookup` (private)
- * Lazy associated list of signal -> registree/list of registrees
-1. `/datum/var/list/signal_procs` (private)
- * Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum receives that signal
-1. `/datum/var/signal_enabled` (protected, boolean)
- * If the datum is signal enabled. If not, it will not react to signals
- * `FALSE` by default, set to `TRUE` when a signal is registered
-1. `/datum/component/var/dupe_mode` (protected, enum)
- * How duplicate component types are handled when added to the datum.
- * `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
- * `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
- * `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
- * `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
-1. `/datum/component/var/dupe_type` (protected, type)
- * Definition of a duplicate component type
- * `null` means exact match on `type` (default)
- * Any other type means that and all subtypes
-1. `/datum/component/var/datum/parent` (protected, read-only)
- * The datum this component belongs to
- * Never `null` in child procs
-1. `report_signal_origin` (protected, boolean)
- * If `TRUE`, will invoke the callback when signalled with the signal type as the first argument.
- * `FALSE` by default.
-
-### Procs
-
-1. `/datum/proc/GetComponent(component_type(type)) -> datum/component?` (public, final)
- * Returns a reference to a component of component_type if it exists in the datum, null otherwise
-1. `/datum/proc/GetComponents(component_type(type)) -> list` (public, final)
- * Returns a list of references to all components of component_type that exist in the datum
-1. `/datum/proc/GetExactComponent(component_type(type)) -> datum/component?` (public, final)
- * Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
-1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
- * Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
-1. `SEND_SIGNAL(target, sigtype, ...)` (public, final)
- * Use to send signals to target datum
- * Extra arguments are to be specified in the signal definition
- * Returns a bitflag with signal specific information assembled from all activated components
- * Arguments are packaged in a list and handed off to _SendSignal()
-1. `/datum/proc/AddComponent(component_type(type), ...) -> datum/component` (public, final)
- * Creates an instance of `component_type` in the datum and passes `...` to its `Initialize()` call
- * Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
- * All components a datum owns are deleted with the datum
- * Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
- * If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
- * Properly handles duplicate situations based on the `dupe_mode` var
-1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
- * Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
-1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
- * Called on a component's `parent` after a signal received causes it to activate. `src` is the parameter
- * Will only be called if a component's callback returns `TRUE`
-1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
- * Properly transfers ownership of a component from one datum to another
- * Signals `COMSIG_COMPONENT_REMOVING` on the parent
- * Called on the datum you want to own the component with another datum's component
-1. `/datum/proc/_SendSignal(signal, list/arguments)` (private, final)
- * Handles most of the actual signaling procedure
- * Will runtime if used on datums with an empty component list
-1. `/datum/proc/RegisterSignal(datum/target, signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final)
- * If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
- * Makes the datum listen for the specified `signal` on it's `parent` datum.
- * When that signal is received `proc_ref` will be called on the component, along with associated arguments
- * Example proc ref: `.proc/OnEvent`
- * If a previous registration is overwritten by the call, a runtime occurs. Setting `override` to TRUE prevents this
- * These callbacks run asyncronously
- * Returning `TRUE` from these callbacks will trigger a `TRUE` return from the `SendSignal()` that initiated it
-1. `/datum/component/New(datum/parent, ...)` (private, final)
- * Runs internal setup for the component
- * Extra arguments are passed to `Initialize()`
-1. `/datum/component/Initialize(...)` (abstract, no-sleep)
- * Called by `New()` with the same argments excluding `parent`
- * Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
- * Signals will not be received while this function is running
- * Component may be deleted after this function completes without being attached
- * Do not call `qdel(src)` from this function
-1. `/datum/component/Destroy(force(bool), silent(bool))` (virtual, no-sleep)
- * Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted
- * Properly removes the component from `parent` and cleans up references
- * Setting `force` makes it not check for and remove the component from the parent
- * Setting `silent` deletes the component without sending a `COMSIG_COMPONENT_REMOVING` signal
-1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract, no-sleep)
- * Called on a component when a component of the same type was added to the same parent
- * See `/datum/component/var/dupe_mode`
- * `C`'s type will always be the same of the called component
-1. `/datum/component/proc/AfterComponentActivated()` (abstract, async)
- * Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called
-1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep)
- * Called before `new_parent` is assigned to `parent` in `TakeComponent()`
- * Allows the component to react to ownership transfers
-1. `/datum/component/proc/_RemoveFromParent()` (private, final)
- * Clears `parent` and removes the component from it's component list
-1. `/datum/component/proc/_JoinParent` (private, final)
- * Tries to add the component to it's `parent`s `datum_components` list
-1. `/datum/component/proc/RegisterWithParent` (abstract, no-sleep)
- * Used to register the signals that should be on the `parent` object
- * Use this if you plan on the component transfering between parents
-1. `/datum/component/proc/UnregisterFromParent` (abstract, no-sleep)
- * Counterpart to `RegisterWithParent()`
- * Used to unregister the signals that should only be on the `parent` object
-
-### See/Define signals and their arguments in __DEFINES\components.dm
+### See/Define signals and their arguments in [__DEFINES\dcs\signals.dm](../../__DEFINES/dcs/signals.dm)
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index e733ca78d2b..f895b8d81b1 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -1,21 +1,87 @@
+/**
+ * # Component
+ *
+ * The component datum
+ *
+ * A component should be a single standalone unit
+ * of functionality, that works by receiving signals from it's parent
+ * object to provide some single functionality (i.e a slippery component)
+ * that makes the object it's attached to cause people to slip over.
+ * Useful when you want shared behaviour independent of type inheritance
+ */
/datum/component
+ /**
+ * Defines how duplicate existing components are handled when added to a datum
+ *
+ * See [COMPONENT_DUPE_*][COMPONENT_DUPE_ALLOWED] definitions for available options
+ */
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
+
+ /**
+ * The type to check for duplication
+ *
+ * `null` means exact match on `type` (default)
+ *
+ * Any other type means that and all subtypes
+ */
var/dupe_type
+
+ /// The datum this components belongs to
var/datum/parent
- //only set to true if you are able to properly transfer this component
- //At a minimum RegisterWithParent and UnregisterFromParent should be used
- //Make sure you also implement PostTransfer for any post transfer handling
+
+ /**
+ * Only set to true if you are able to properly transfer this component
+ *
+ * At a minimum [RegisterWithParent][/datum/component/proc/RegisterWithParent] and [UnregisterFromParent][/datum/component/proc/UnregisterFromParent] should be used
+ *
+ * Make sure you also implement [PostTransfer][/datum/component/proc/PostTransfer] for any post transfer handling
+ */
var/can_transfer = FALSE
-/datum/component/New(datum/P, ...)
- parent = P
- var/list/arguments = args.Copy(2)
+/**
+ * Create a new component.
+ *
+ * Additional arguments are passed to [Initialize()][/datum/component/proc/Initialize]
+ *
+ * Arguments:
+ * * datum/P the parent datum this component reacts to signals from
+ */
+/datum/component/New(list/raw_args)
+ parent = raw_args[1]
+ var/list/arguments = raw_args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
+ stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
qdel(src, TRUE, TRUE)
- CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
+ return
- _JoinParent(P)
+ _JoinParent(parent)
+/**
+ * Called during component creation with the same arguments as in new excluding parent.
+ *
+ * Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
+ */
+/datum/component/proc/Initialize(...)
+ return
+
+/**
+ * Properly removes the component from `parent` and cleans up references
+ *
+ * Arguments:
+ * * force - makes it not check for and remove the component from the parent
+ * * silent - deletes the component without sending a [COMSIG_COMPONENT_REMOVING] signal
+ */
+/datum/component/Destroy(force=FALSE, silent=FALSE)
+ if(!force && parent)
+ _RemoveFromParent()
+ if(!silent)
+ SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
+ parent = null
+ return ..()
+
+/**
+ * Internal proc to handle behaviour of components when joining a parent
+ */
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
@@ -51,21 +117,9 @@
RegisterWithParent()
-// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
-/datum/component/proc/RegisterWithParent()
- return
-
-/datum/component/proc/Initialize(...)
- return
-
-/datum/component/Destroy(force=FALSE, silent=FALSE)
- if(!force && parent)
- _RemoveFromParent()
- if(!silent)
- SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
- parent = null
- return ..()
-
+/**
+ * Internal proc to handle behaviour when being removed from a parent
+ */
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
@@ -84,10 +138,41 @@
UnregisterFromParent()
+/**
+ * Register the component with the parent object
+ *
+ * Use this proc to register with your parent object
+ *
+ * Overridable proc that's called when added to a new parent
+ */
+/datum/component/proc/RegisterWithParent()
+ return
+
+/**
+ * Unregister from our parent object
+ *
+ * Use this proc to unregister from your parent object
+ *
+ * Overridable proc that's called when removed from a parent
+ * *
+ */
/datum/component/proc/UnregisterFromParent()
return
-/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proc_or_callback, override = FALSE)
+/**
+ * Register to listen for a signal from the passed in target
+ *
+ * This sets up a listening relationship such that when the target object emits a signal
+ * the source datum this proc is called upon, will recieve a callback to the given proctype
+ * Return values from procs registered must be a bitfield
+ *
+ * Arguments:
+ * * datum/target The target to listen for signals from
+ * * sig_type_or_types Either a string signal name, or a list of signal names (strings)
+ * * proctype The proc to call back when the signal is emitted
+ * * override If a previous registration exists you must explicitly set this
+ */
+/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
@@ -100,15 +185,12 @@
if(!lookup)
target.comp_lookup = lookup = list()
- if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
- proc_or_callback = CALLBACK(src, proc_or_callback)
-
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
- procs[target][sig_type] = proc_or_callback
+ procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
@@ -122,6 +204,17 @@
signal_enabled = TRUE
+/**
+ * Stop listening to a given signal from target
+ *
+ * Breaks the relationship between target and source datum, removing the callback when the signal fires
+ *
+ * Doesn't care if a registration exists or not
+ *
+ * Arguments:
+ * * datum/target Datum to stop listening to signals from
+ * * sig_typeor_types Signal string key or list of signal keys to stop listening to specifically
+ */
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
@@ -129,6 +222,8 @@
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
+ if(!signal_procs[target][sig])
+ continue
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
@@ -151,41 +246,96 @@
if(!signal_procs[target].len)
signal_procs -= target
+/**
+ * Called on a component when a component of the same type was added to the same parent
+ *
+ * See [/datum/component/var/dupe_mode]
+ *
+ * `C`'s type will always be the same of the called component
+ */
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
+
+/**
+ * Called on a component when a component of the same type was added to the same parent with [COMPONENT_DUPE_SELECTIVE]
+ *
+ * See [/datum/component/var/dupe_mode]
+ *
+ * `C`'s type will always be the same of the called component
+ *
+ * return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
+ */
+/datum/component/proc/CheckDupeComponent(datum/component/C, ...)
+ return
+
+
+/**
+ * Callback Just before this component is transferred
+ *
+ * Use this to do any special cleanup you might need to do before being deregged from an object
+ */
/datum/component/proc/PreTransfer()
return
+/**
+ * Callback Just after a component is transferred
+ *
+ * Use this to do any special setup you need to do after being moved to a new object
+ *
+ * Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
+ */
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
+/**
+ * Internal proc to create a list of our type and all parent types
+ */
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
- while(current_type != /datum/component)
+ while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
+/**
+ * Internal proc to handle most all of the signaling procedure
+ *
+ * Will runtime if used on datums with an empty component list
+ *
+ * Use the [SEND_SIGNAL] define instead
+ */
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
- var/datum/callback/CB = C.signal_procs[src][sigtype]
- return CB.InvokeAsync(arglist(arguments))
+ var/proctype = C.signal_procs[src][sigtype]
+ return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
- var/datum/callback/CB = C.signal_procs[src][sigtype]
- . |= CB.InvokeAsync(arglist(arguments))
+ var/proctype = C.signal_procs[src][sigtype]
+ . |= CallAsync(C, proctype, arguments)
-/datum/proc/GetComponent(c_type)
+// The type arg is casted so initial works, you shouldn't be passing a real instance into this
+/**
+ * Return any component assigned to this datum of the given type
+ *
+ * This will throw an error if it's possible to have more than one component of that type on the parent
+ *
+ * Arguments:
+ * * datum/component/c_type The typepath of the component you want to get a reference to
+ */
+/datum/proc/GetComponent(datum/component/c_type)
+ RETURN_TYPE(c_type)
+ if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
+ stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -193,7 +343,19 @@
if(length(.))
return .[1]
-/datum/proc/GetExactComponent(c_type)
+// The type arg is casted so initial works, you shouldn't be passing a real instance into this
+/**
+ * Return any component assigned to this datum of the exact given type
+ *
+ * This will throw an error if it's possible to have more than one component of that type on the parent
+ *
+ * Arguments:
+ * * datum/component/c_type The typepath of the component you want to get a reference to
+ */
+/datum/proc/GetExactComponent(datum/component/c_type)
+ RETURN_TYPE(c_type)
+ if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
+ stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
@@ -205,6 +367,12 @@
return C
return null
+/**
+ * Get all components of a given type that are attached to this datum
+ *
+ * Arguments:
+ * * c_type The component type path
+ */
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
@@ -213,7 +381,19 @@
if(!length(.))
return list(.)
-/datum/proc/AddComponent(new_type, ...)
+/**
+ * Creates an instance of `new_type` in the datum and attaches to it as parent
+ *
+ * Sends the [COMSIG_COMPONENT_ADDED] signal to the datum
+ *
+ * Returns the component that was created. Or the old component in a dupe situation where [COMPONENT_DUPE_UNIQUE] was set
+ *
+ * If this tries to add a component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
+ *
+ * Properly handles duplicate situations based on the `dupe_mode` var
+ */
+/datum/proc/_AddComponent(list/raw_args)
+ var/new_type = raw_args[1]
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
@@ -228,7 +408,7 @@
new_comp = nt
nt = new_comp.type
- args[1] = src
+ raw_args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
@@ -239,37 +419,62 @@
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
- new_comp = new nt(arglist(args))
+ new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
- new_comp = new nt(arglist(args))
+ new_comp = new nt(raw_args)
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
- var/list/arguments = args.Copy(2)
- old_comp.InheritComponent(null, TRUE, arguments)
+ var/list/arguments = raw_args.Copy(2)
+ arguments.Insert(1, null, TRUE)
+ old_comp.InheritComponent(arglist(arguments))
else
old_comp.InheritComponent(new_comp, TRUE)
+ if(COMPONENT_DUPE_SELECTIVE)
+ var/list/arguments = raw_args.Copy()
+ arguments[1] = new_comp
+ var/make_new_component = TRUE
+ for(var/i in GetComponents(new_type))
+ var/datum/component/C = i
+ if(C.CheckDupeComponent(arglist(arguments)))
+ make_new_component = FALSE
+ QDEL_NULL(new_comp)
+ break
+ if(!new_comp && make_new_component)
+ new_comp = new nt(raw_args)
else if(!new_comp)
- new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
+ new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
- new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
+ new_comp = new nt(raw_args) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
+/**
+ * Get existing component of type, or create it and return a reference to it
+ *
+ * Use this if the item needs to exist at the time of this call, but may not have been created before now
+ *
+ * Arguments:
+ * * component_type The typepath of the component to create or return
+ * * ... additional arguments to be passed when creating the component if it does not exist
+ */
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
- return AddComponent(arglist(args))
+ return _AddComponent(args)
+/**
+ * Removes the component from parent, ends up with a null parent
+ */
/datum/component/proc/RemoveComponent()
if(!parent)
return
@@ -279,6 +484,14 @@
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
+/**
+ * Transfer this component to another parent
+ *
+ * Component is taken from source datum
+ *
+ * Arguments:
+ * * datum/component/target Target datum to transfer to
+ */
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
@@ -295,6 +508,14 @@
if(target == AddComponent(target))
target._JoinParent()
+/**
+ * Transfer all components to target
+ *
+ * All components from source datum are taken
+ *
+ * Arguments:
+ * * /datum/target the target to move the components to
+ */
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
@@ -309,5 +530,8 @@
if(C.can_transfer)
target.TakeComponent(comps)
+/**
+ * Return the object that is the host of any UI's that this component has
+ */
/datum/component/nano_host()
return parent
diff --git a/code/datums/components/decal.dm b/code/datums/components/decal.dm
index 6a0f686b13a..876cf0c0507 100644
--- a/code/datums/components/decal.dm
+++ b/code/datums/components/decal.dm
@@ -7,7 +7,7 @@
var/first_dir // This only stores the dir arg from init
-/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description, _alpha=255)
+/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable = CLEAN_GOD, _color, _layer = TURF_LAYER, _description, _alpha = 255)
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color, _alpha))
return COMPONENT_INCOMPATIBLE
first_dir = _dir
diff --git a/code/datums/components/ducttape.dm b/code/datums/components/ducttape.dm
index 98512589a46..49931db8edc 100644
--- a/code/datums/components/ducttape.dm
+++ b/code/datums/components/ducttape.dm
@@ -37,10 +37,10 @@
I.anchored = initial(I.anchored)
for(var/datum/action/item_action/remove_tape/RT in I.actions)
RT.Remove(user)
- RT.Destroy()
+ qdel(RT)
I.overlays.Cut(tape_overlay)
user.transfer_fingerprints_to(I)
- Destroy()
+ qdel(src)
/datum/component/ducttape/proc/afterattack(obj/item/I, atom/target, mob/user, proximity, params)
if(!proximity)
diff --git a/code/datums/components/edit_complainer.dm b/code/datums/components/edit_complainer.dm
new file mode 100644
index 00000000000..7910515cb45
--- /dev/null
+++ b/code/datums/components/edit_complainer.dm
@@ -0,0 +1,23 @@
+// This is just a bit of fun while making an example for global signal
+/datum/component/edit_complainer
+ var/list/say_lines
+
+/datum/component/edit_complainer/Initialize(list/text)
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ var/static/list/default_lines = list(
+ "CentComm's profligacy frays another thread.",
+ "Another tug at the weave.",
+ "Who knows when the stresses will finally shatter the form?",
+ "Even now a light shines through the cracks.",
+ "CentComm once more twists knowledge beyond its authority.",
+ "There is an uncertain air in the mansus.",
+ )
+ say_lines = text || default_lines
+
+ RegisterSignal(SSdcs, COMSIG_GLOB_VAR_EDIT, .proc/var_edit_react)
+
+/datum/component/edit_complainer/proc/var_edit_react(datum/source, list/arguments)
+ var/atom/movable/master = parent
+ master.atom_say(pick(say_lines))
diff --git a/code/datums/components/jestosterone.dm b/code/datums/components/jestosterone.dm
deleted file mode 100644
index f37f1f03efb..00000000000
--- a/code/datums/components/jestosterone.dm
+++ /dev/null
@@ -1,5 +0,0 @@
-/datum/component/jestosterone
- var/mind_type //Is the affected mob a clown / mime?
-
-/datum/component/jestosterone/Initialize(mind_type_arg)
- mind_type = mind_type_arg
diff --git a/code/datums/components/label.dm b/code/datums/components/label.dm
index 26cb99c7e3c..c6d0c595ebb 100644
--- a/code/datums/components/label.dm
+++ b/code/datums/components/label.dm
@@ -32,12 +32,12 @@
This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
*/
-/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, list/arguments)
+/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
remove_label()
if(new_comp)
label_name = new_comp.label_name
else
- label_name = arguments[1]
+ label_name = _label_name
apply_label()
/**
diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm
index 3e505eb0a8a..88e51209afb 100644
--- a/code/datums/components/slippery.dm
+++ b/code/datums/components/slippery.dm
@@ -20,12 +20,12 @@
var/slip_tiles
/// TRUE If this slip can be avoided by walking.
var/walking_is_safe
- /// TRUE if having no slip shoes makes you immune to this slip.
- var/noslip_is_immune
+ /// FALSE if you want no slip shoes to make you immune to the slip
+ var/slip_always
/// The verb that players will see when someone slips on the parent. In the form of "You [slip_verb]ped on".
var/slip_verb
-/datum/component/slippery/Initialize(_description, _stun = 0, _weaken = 0, _slip_chance = 100, _slip_tiles = 0, _walking_is_safe = TRUE, _noslip_is_immune = TRUE, _slip_verb = "slip")
+/datum/component/slippery/Initialize(_description, _stun = 0, _weaken = 0, _slip_chance = 100, _slip_tiles = 0, _walking_is_safe = TRUE, _slip_always = FALSE, _slip_verb = "slip")
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -35,7 +35,7 @@
slip_chance = max(0, _slip_chance)
slip_tiles = max(0, _slip_tiles)
walking_is_safe = _walking_is_safe
- noslip_is_immune = _noslip_is_immune
+ slip_always = _slip_always
slip_verb = _slip_verb
/datum/component/slippery/RegisterWithParent()
@@ -51,6 +51,6 @@
Additionally calls the parent's `after_slip()` proc on the `victim`.
*/
/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim)
- if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, noslip_is_immune, slip_verb))
+ if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, slip_always, slip_verb))
var/atom/movable/owner = parent
owner.after_slip(victim)
diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm
index 818e78e8d2e..4c55ad2ad82 100644
--- a/code/datums/components/squeak.dm
+++ b/code/datums/components/squeak.dm
@@ -16,7 +16,7 @@
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak)
- if(ismovableatom(parent))
+ if(ismovable(parent))
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/play_squeak_crossed)
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
diff --git a/code/datums/components/swarming.dm b/code/datums/components/swarming.dm
new file mode 100644
index 00000000000..16ddc66280e
--- /dev/null
+++ b/code/datums/components/swarming.dm
@@ -0,0 +1,55 @@
+/datum/component/swarming
+ var/offset_x = 0
+ var/offset_y = 0
+ var/is_swarming = FALSE
+ var/list/swarm_members = list()
+
+/datum/component/swarming/Initialize(max_x = 24, max_y = 24)
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+ offset_x = rand(-max_x, max_x)
+ offset_y = rand(-max_y, max_y)
+
+ RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/join_swarm)
+ RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/leave_swarm)
+
+/datum/component/swarming/Destroy()
+ for(var/other in swarm_members)
+ var/datum/component/swarming/other_swarm = other
+ other_swarm.swarm_members -= src
+ if(!other_swarm.swarm_members.len)
+ other_swarm.unswarm()
+ swarm_members = null
+ return ..()
+
+/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/AM)
+ var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
+ if(!other_swarm)
+ return
+ swarm()
+ swarm_members |= other_swarm
+ other_swarm.swarm()
+ other_swarm.swarm_members |= src
+
+/datum/component/swarming/proc/leave_swarm(datum/source, atom/movable/AM)
+ var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
+ if(!other_swarm || !(other_swarm in swarm_members))
+ return
+ swarm_members -= other_swarm
+ if(!swarm_members.len)
+ unswarm()
+ other_swarm.swarm_members -= src
+ if(!other_swarm.swarm_members.len)
+ other_swarm.unswarm()
+
+/datum/component/swarming/proc/swarm()
+ var/atom/movable/owner = parent
+ if(!is_swarming)
+ is_swarming = TRUE
+ animate(owner, pixel_x = owner.pixel_x + offset_x, pixel_y = owner.pixel_y + offset_y, time = 2)
+
+/datum/component/swarming/proc/unswarm()
+ var/atom/movable/owner = parent
+ if(is_swarming)
+ animate(owner, pixel_x = owner.pixel_x - offset_x, pixel_y = owner.pixel_y - offset_y, time = 2)
+ is_swarming = FALSE
diff --git a/code/datums/components/waddling.dm b/code/datums/components/waddling.dm
deleted file mode 100644
index a1f538e4dd7..00000000000
--- a/code/datums/components/waddling.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/datum/component/waddling
- dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
-
-/datum/component/waddling/Initialize()
- if(!isliving(parent))
- return COMPONENT_INCOMPATIBLE
- RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/Waddle)
-
-/datum/component/waddling/proc/Waddle()
- var/mob/living/L = parent
- if(L.incapacitated() || L.lying)
- return
- animate(L, pixel_z = 4, time = 0)
- animate(pixel_z = 0, transform = turn(matrix(), pick(-12, 0, 12)), time=2)
- animate(pixel_z = 0, transform = matrix(), time = 0)
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index b2b09003934..e8d0b881ccb 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -819,6 +819,59 @@
message_admins("[key_name(usr)] has made [A] process normally")
return TRUE
+ else if(href_list["modifyarmor"])
+ if(!check_rights(R_DEBUG|R_ADMIN))
+ return
+ var/obj/A = locateUID(href_list["modifyarmor"])
+ if(!istype(A))
+ return
+ A.var_edited = TRUE
+ var/list/armorlist = A.armor.getList()
+ var/list/displaylist
+
+ var/result
+ do
+ displaylist = list()
+ for(var/key in armorlist)
+ displaylist += "[key] = [armorlist[key]]"
+ result = input(usr, "Select an armor type to modify..", "Modify armor") as null|anything in displaylist + "(ADD ALL)" + "(SET ALL)" + "(DONE)"
+
+ if(result == "(DONE)")
+ break
+ else if(result == "(ADD ALL)" || result == "(SET ALL)")
+ var/new_amount = input(usr, result == "(ADD ALL)" ? "Enter armor to add to all types:" : "Enter new armor value for all types:", "Modify all types") as num|null
+ if(isnull(new_amount))
+ continue
+ var/proper_amount = text2num(new_amount)
+ if(isnull(proper_amount))
+ continue
+ for(var/key in armorlist)
+ armorlist[key] = (result == "(ADD ALL)" ? armorlist[key] : 0) + proper_amount
+ else if(result)
+ var/list/fields = splittext(result, " = ")
+ if(length(fields) != 2)
+ continue
+ var/type = fields[1]
+ if(isnull(armorlist[type]))
+ continue
+ var/new_amount = input(usr, "Enter new armor value for [type]:", "Modify [type]") as num|null
+ if(isnull(new_amount))
+ continue
+ var/proper_amount = text2num(new_amount)
+ if(isnull(proper_amount))
+ continue
+ armorlist[type] = proper_amount
+ while(result)
+
+ if(!result || !A)
+ return TRUE
+
+ A.armor = A.armor.setRating(armorlist["melee"], armorlist["bullet"], armorlist["laser"], armorlist["energy"], armorlist["bomb"], armorlist["bio"], armorlist["rad"], armorlist["fire"], armorlist["acid"], armorlist["magic"])
+
+ log_admin("[key_name(usr)] modified the armor on [A] to: melee = [armorlist["melee"]], bullet = [armorlist["bullet"]], laser = [armorlist["laser"]], energy = [armorlist["energy"]], bomb = [armorlist["bomb"]], bio = [armorlist["bio"]], rad = [armorlist["rad"]], fire = [armorlist["fire"]], acid = [armorlist["acid"]], magic = [armorlist["magic"]]")
+ message_admins("[key_name(usr)] modified the armor on [A] to: melee = [armorlist["melee"]], bullet = [armorlist["bullet"]], laser = [armorlist["laser"]], energy = [armorlist["energy"]], bomb = [armorlist["bomb"]], bio = [armorlist["bio"]], rad = [armorlist["rad"]], fire = [armorlist["fire"]], acid = [armorlist["acid"]], magic = [armorlist["magic"]]")
+ return TRUE
+
else if(href_list["addreagent"]) /* Made on /TG/, credit to them. */
if(!check_rights(R_DEBUG|R_ADMIN)) return
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 9aeade59a1d..34c41c581f2 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -171,7 +171,6 @@ GLOBAL_LIST_INIT(advance_cures, list(
if(!symptoms || !symptoms.len)
CRASH("We did not have any symptoms before generating properties.")
- return
var/list/properties = list("resistance" = 1, "stealth" = 0, "stage_rate" = 1, "transmittable" = 1, "severity" = 0)
@@ -196,9 +195,9 @@ GLOBAL_LIST_INIT(advance_cures, list(
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
// The more symptoms we have, the less transmittable it is but some symptoms can make up for it.
- SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
- permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
- cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
+ SetSpread(clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
+ permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
+ cure_chance = 15 - clamp(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
@@ -245,7 +244,7 @@ GLOBAL_LIST_INIT(advance_cures, list(
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure(list/properties = list())
if(properties && properties.len)
- var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, GLOB.advance_cures.len)
+ var/res = clamp(properties["resistance"] - (symptoms.len / 2), 1, GLOB.advance_cures.len)
// to_chat(world, "Res = [res]")
cures = list(GLOB.advance_cures[res])
diff --git a/code/datums/diseases/critical.dm b/code/datums/diseases/critical.dm
index 3afb48ce534..e8486a8f408 100644
--- a/code/datums/diseases/critical.dm
+++ b/code/datums/diseases/critical.dm
@@ -159,7 +159,7 @@
var/mob/living/carbon/human/H = affected_mob
if(NO_HUNGER in H.dna.species.species_traits)
return TRUE
- if(ismachine(H))
+ if(ismachineperson(H))
return TRUE
return ..()
diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm
new file mode 100644
index 00000000000..46a295f90be
--- /dev/null
+++ b/code/datums/elements/_element.dm
@@ -0,0 +1,55 @@
+/**
+ * A holder for simple behaviour that can be attached to many different types
+ *
+ * Only one element of each type is instanced during game init.
+ * Otherwise acts basically like a lightweight component.
+ */
+/datum/element
+ /// Option flags for element behaviour
+ var/element_flags = NONE
+ /**
+ * The index of the first attach argument to consider for duplicate elements
+ *
+ * Is only used when flags contains [ELEMENT_BESPOKE]
+ *
+ * This is infinity so you must explicitly set this
+ */
+ var/id_arg_index = INFINITY
+
+/// Activates the functionality defined by the element on the given target datum
+/datum/element/proc/Attach(datum/target)
+ SHOULD_CALL_PARENT(1)
+ if(type == /datum/element)
+ return ELEMENT_INCOMPATIBLE
+ SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
+ if(element_flags & ELEMENT_DETACH)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
+
+/// Deactivates the functionality defines by the element on the given datum
+/datum/element/proc/Detach(datum/source, force)
+ SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
+ SHOULD_CALL_PARENT(1)
+ UnregisterSignal(source, COMSIG_PARENT_QDELETING)
+
+/datum/element/Destroy(force)
+ if(!force)
+ return QDEL_HINT_LETMELIVE
+ SSdcs.elements_by_type -= type
+ return ..()
+
+//DATUM PROCS
+
+/// Finds the singleton for the element type given and attaches it to src
+/datum/proc/_AddElement(list/arguments)
+ var/datum/element/ele = SSdcs.GetElement(arguments)
+ arguments[1] = src
+ if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
+ CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
+
+/**
+ * Finds the singleton for the element type given and detaches it from src
+ * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
+ */
+/datum/proc/_RemoveElement(list/arguments)
+ var/datum/element/ele = SSdcs.GetElement(arguments)
+ ele.Detach(src)
diff --git a/code/datums/elements/waddling.dm b/code/datums/elements/waddling.dm
new file mode 100644
index 00000000000..e8870653941
--- /dev/null
+++ b/code/datums/elements/waddling.dm
@@ -0,0 +1,25 @@
+/datum/element/waddling
+
+/datum/element/waddling/Attach(datum/target)
+ . = ..()
+ if(!ismovable(target))
+ return ELEMENT_INCOMPATIBLE
+ if(isliving(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/LivingWaddle)
+ else
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/Waddle)
+
+/datum/element/waddling/Detach(datum/source, force)
+ . = ..()
+ UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
+
+/datum/element/waddling/proc/LivingWaddle(mob/living/target)
+ if(target.incapacitated() || target.lying)
+ return
+ Waddle(target)
+
+/datum/element/waddling/proc/Waddle(atom/movable/target)
+ animate(target, pixel_z = 4, time = 0)
+ var/prev_trans = matrix(target.transform)
+ animate(pixel_z = 0, transform = turn(target.transform, pick(-12, 0, 12)), time = 2)
+ animate(pixel_z = 0, transform = prev_trans, time = 0)
diff --git a/code/datums/gas_mixture.dm b/code/datums/gas_mixture.dm
index 63b70b512ee..91bebcdad39 100644
--- a/code/datums/gas_mixture.dm
+++ b/code/datums/gas_mixture.dm
@@ -7,33 +7,22 @@ What are the archived variables for?
#define SPECIFIC_HEAT_TOXIN 200
#define SPECIFIC_HEAT_AIR 20
#define SPECIFIC_HEAT_CDO 30
-#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \
- (carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN)
+#define SPECIFIC_HEAT_N2O 40
+#define SPECIFIC_HEAT_AGENT_B 300
+
+#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b) \
+ (carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN + sleeping_agent * SPECIFIC_HEAT_N2O + agent_b * SPECIFIC_HEAT_AGENT_B)
#define MINIMUM_HEAT_CAPACITY 0.0003
-#define QUANTIZE(variable) (round(variable,0.0001))
-
-/datum/gas
- var/moles = 0
- var/specific_heat = 0
-
- var/moles_archived = 0
-
-/datum/gas/sleeping_agent
- specific_heat = 40
-
-/datum/gas/oxygen_agent_b
- specific_heat = 300
-
-/datum/gas/volatile_fuel
- specific_heat = 30
-
+#define QUANTIZE(variable) (round(variable, 0.0001))
/datum/gas_mixture
var/oxygen = 0
var/carbon_dioxide = 0
var/nitrogen = 0
var/toxins = 0
+ var/sleeping_agent = 0
+ var/agent_b = 0
var/volume = CELL_VOLUME
@@ -41,13 +30,12 @@ What are the archived variables for?
var/last_share
- var/list/datum/gas/trace_gases = list()
-
-
var/tmp/oxygen_archived
var/tmp/carbon_dioxide_archived
var/tmp/nitrogen_archived
var/tmp/toxins_archived
+ var/tmp/sleeping_agent_archived
+ var/tmp/agent_b_archived
var/tmp/temperature_archived
@@ -55,35 +43,24 @@ What are the archived variables for?
//PV=nRT - related procedures
/datum/gas_mixture/proc/heat_capacity()
- var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins)
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- heat_capacity += trace_gas.moles*trace_gas.specific_heat
- return heat_capacity
+ return HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b)
/datum/gas_mixture/proc/heat_capacity_archived()
- var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived)
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat
- return heat_capacity_archived
+ return HEAT_CAPACITY_CALCULATION(oxygen_archived, carbon_dioxide_archived, nitrogen_archived, toxins_archived, sleeping_agent_archived, agent_b_archived)
/datum/gas_mixture/proc/total_moles()
- var/moles = oxygen + carbon_dioxide + nitrogen + toxins
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- moles += trace_gas.moles
+ var/moles = oxygen + carbon_dioxide + nitrogen + toxins + sleeping_agent + agent_b
return moles
+/datum/gas_mixture/proc/total_trace_moles()
+ var/moles = sleeping_agent + agent_b
+ return moles
/datum/gas_mixture/proc/return_pressure()
- if(volume>0)
- return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume
+ if(volume > 0)
+ return total_moles() * R_IDEAL_GAS_EQUATION * temperature / volume
return 0
@@ -96,7 +73,7 @@ What are the archived variables for?
/datum/gas_mixture/proc/thermal_energy()
- return temperature*heat_capacity()
+ return temperature * heat_capacity()
//Procedures used for very specific events
@@ -105,28 +82,23 @@ What are the archived variables for?
/datum/gas_mixture/proc/react(atom/dump_location)
var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network)
- if(trace_gases.len > 0)
- if(temperature > 900)
- if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
- var/datum/gas/oxygen_agent_b/trace_gas = locate(/datum/gas/oxygen_agent_b/) in trace_gases
- if(trace_gas)
- var/reaction_rate = min(carbon_dioxide*0.75, toxins*0.25, trace_gas.moles*0.05)
+ if(agent_b && temperature > 900)
+ if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
+ var/reaction_rate = min(carbon_dioxide * 0.75, toxins * 0.25, agent_b * 0.05)
- carbon_dioxide -= reaction_rate
- oxygen += reaction_rate
+ carbon_dioxide -= reaction_rate
+ oxygen += reaction_rate
- trace_gas.moles -= reaction_rate*0.05
+ agent_b -= reaction_rate * 0.05
- temperature += (reaction_rate*20000)/heat_capacity()
+ temperature += (reaction_rate * 20000) / heat_capacity()
- reacting = 1
+ reacting = 1
fuel_burnt = 0
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
-// to_chat(world, "pre [temperature], [oxygen], [toxins]")
if(fire() > 0)
reacting = 1
-// to_chat(world, "post [temperature], [oxygen], [toxins]")
return reacting
@@ -134,24 +106,6 @@ What are the archived variables for?
var/energy_released = 0
var/old_heat_capacity = heat_capacity()
- var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel/) in trace_gases
- if(fuel_store) //General volatile gas burn
- var/burned_fuel = 0
-
- if(oxygen < fuel_store.moles)
- burned_fuel = oxygen
- fuel_store.moles -= burned_fuel
- oxygen = 0
- else
- burned_fuel = fuel_store.moles
- oxygen -= fuel_store.moles
- trace_gases -= fuel_store
- fuel_store = null
-
- energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel
- carbon_dioxide += burned_fuel
- fuel_burnt += burned_fuel
-
//Handle plasma burning
if(toxins > MINIMUM_HEAT_CAPACITY)
var/plasma_burn_rate = 0
@@ -161,13 +115,13 @@ What are the archived variables for?
if(temperature > PLASMA_UPPER_TEMPERATURE)
temperature_scale = 1
else
- temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
+ temperature_scale = (temperature - PLASMA_MINIMUM_BURN_TEMPERATURE) / (PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
if(temperature_scale > 0)
oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
- if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN)
- plasma_burn_rate = (toxins*temperature_scale)/PLASMA_BURN_RATE_DELTA
+ if(oxygen > toxins * PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = (toxins * temperature_scale) / PLASMA_BURN_RATE_DELTA
else
- plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
+ plasma_burn_rate = (temperature_scale * (oxygen / PLASMA_OXYGEN_FULLBURN)) / PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
toxins -= plasma_burn_rate
oxygen -= plasma_burn_rate*oxygen_burn_rate
@@ -175,12 +129,12 @@ What are the archived variables for?
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
- fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate)
+ fuel_burnt += (plasma_burn_rate) * (1 + oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
+ temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
return fuel_burnt
@@ -231,10 +185,8 @@ What are the archived variables for?
carbon_dioxide_archived = carbon_dioxide
nitrogen_archived = nitrogen
toxins_archived = toxins
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- trace_gas.moles_archived = trace_gas.moles
+ sleeping_agent_archived = sleeping_agent
+ agent_b_archived = agent_b
temperature_archived = temperature
@@ -244,55 +196,45 @@ What are the archived variables for?
if(!giver)
return 0
- if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ if(abs(temperature - giver.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
var/giver_heat_capacity = giver.heat_capacity()
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
- temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
+ temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
oxygen += giver.oxygen
carbon_dioxide += giver.carbon_dioxide
nitrogen += giver.nitrogen
toxins += giver.toxins
-
- for(var/gas in giver.trace_gases)
- var/datum/gas/trace_gas = gas
- var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
- if(!corresponding)
- corresponding = new trace_gas.type()
- trace_gases += corresponding
- corresponding.moles += trace_gas.moles
+ sleeping_agent += giver.sleeping_agent
+ agent_b += giver.agent_b
return 1
/datum/gas_mixture/remove(amount)
var/sum = total_moles()
- amount = min(amount,sum) //Can not take more air than tile has!
+ amount = min(amount, sum) //Can not take more air than tile has!
if(amount <= 0)
return null
var/datum/gas_mixture/removed = new
- removed.oxygen = QUANTIZE((oxygen/sum)*amount)
- removed.nitrogen = QUANTIZE((nitrogen/sum)*amount)
- removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount)
- removed.toxins = QUANTIZE((toxins/sum)*amount)
+ removed.oxygen = QUANTIZE((oxygen / sum) * amount)
+ removed.nitrogen = QUANTIZE((nitrogen/ sum) * amount)
+ removed.carbon_dioxide = QUANTIZE((carbon_dioxide / sum) * amount)
+ removed.toxins = QUANTIZE((toxins / sum) * amount)
+ removed.sleeping_agent = QUANTIZE((sleeping_agent / sum) * amount)
+ removed.agent_b = QUANTIZE((agent_b / sum) * amount)
oxygen -= removed.oxygen
nitrogen -= removed.nitrogen
carbon_dioxide -= removed.carbon_dioxide
toxins -= removed.toxins
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- var/datum/gas/corresponding = new trace_gas.type()
- removed.trace_gases += corresponding
-
- corresponding.moles = (trace_gas.moles/sum)*amount
- trace_gas.moles -= corresponding.moles
+ sleeping_agent -= removed.sleeping_agent
+ agent_b -= removed.agent_b
removed.temperature = temperature
@@ -307,23 +249,19 @@ What are the archived variables for?
var/datum/gas_mixture/removed = new
- removed.oxygen = QUANTIZE(oxygen*ratio)
- removed.nitrogen = QUANTIZE(nitrogen*ratio)
- removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio)
- removed.toxins = QUANTIZE(toxins*ratio)
+ removed.oxygen = QUANTIZE(oxygen * ratio)
+ removed.nitrogen = QUANTIZE(nitrogen * ratio)
+ removed.carbon_dioxide = QUANTIZE(carbon_dioxide * ratio)
+ removed.toxins = QUANTIZE(toxins * ratio)
+ removed.sleeping_agent = QUANTIZE(sleeping_agent * ratio)
+ removed.agent_b = QUANTIZE(agent_b * ratio)
oxygen -= removed.oxygen
nitrogen -= removed.nitrogen
carbon_dioxide -= removed.carbon_dioxide
toxins -= removed.toxins
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- var/datum/gas/corresponding = new trace_gas.type()
- removed.trace_gases += corresponding
-
- corresponding.moles = trace_gas.moles*ratio
- trace_gas.moles -= corresponding.moles
+ sleeping_agent -= removed.sleeping_agent
+ agent_b -= removed.agent_b
removed.temperature = temperature
@@ -334,14 +272,8 @@ What are the archived variables for?
carbon_dioxide = sample.carbon_dioxide
nitrogen = sample.nitrogen
toxins = sample.toxins
-
- trace_gases.len=null
- for(var/gas in sample.trace_gases)
- var/datum/gas/trace_gas = gas
- var/datum/gas/corresponding = new trace_gas.type()
- trace_gases += corresponding
-
- corresponding.moles = trace_gas.moles
+ sleeping_agent = sample.sleeping_agent
+ agent_b = sample.agent_b
temperature = sample.temperature
@@ -352,6 +284,8 @@ What are the archived variables for?
carbon_dioxide = model.carbon_dioxide
nitrogen = model.nitrogen
toxins = model.toxins
+ sleeping_agent = model.sleeping_agent
+ agent_b = model.agent_b
//acounts for changes in temperature
var/turf/model_parent = model.parent_type
@@ -361,26 +295,25 @@ What are the archived variables for?
return 1
/datum/gas_mixture/check_turf(turf/model, atmos_adjacent_turfs = 4)
- var/delta_oxygen = (oxygen_archived - model.oxygen)/(atmos_adjacent_turfs+1)
- var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/(atmos_adjacent_turfs+1)
- var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/(atmos_adjacent_turfs+1)
- var/delta_toxins = (toxins_archived - model.toxins)/(atmos_adjacent_turfs+1)
+ var/delta_oxygen = (oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = (nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = (toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = (sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = (agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - model.temperature)
- if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
- return 0
-
return 1
/datum/gas_mixture/proc/check_turf_total(turf/model) //I want this proc to die a painful death
@@ -388,30 +321,32 @@ What are the archived variables for?
var/delta_carbon_dioxide = (carbon_dioxide - model.carbon_dioxide)
var/delta_nitrogen = (nitrogen - model.nitrogen)
var/delta_toxins = (toxins - model.toxins)
+ var/delta_sleeping_agent = (sleeping_agent - model.sleeping_agent)
+ var/delta_agent_b = (agent_b - model.agent_b)
var/delta_temperature = (temperature - model.temperature)
- if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND*4)
- return 0
-
return 1
/datum/gas_mixture/share(datum/gas_mixture/sharer, atmos_adjacent_turfs = 4)
- if(!sharer) return 0
- var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/(atmos_adjacent_turfs+1)
- var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/(atmos_adjacent_turfs+1)
- var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/(atmos_adjacent_turfs+1)
- var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/(atmos_adjacent_turfs+1)
+ if(!sharer)
+ return 0
+ var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - sharer.sleeping_agent_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = QUANTIZE(agent_b_archived - sharer.agent_b_archived) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
@@ -423,28 +358,42 @@ What are the archived variables for?
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
- var/delta_air = delta_oxygen+delta_nitrogen
+ var/delta_air = delta_oxygen + delta_nitrogen
if(delta_air)
- var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
+ var/air_heat_capacity = SPECIFIC_HEAT_AIR * delta_air
if(delta_air > 0)
heat_capacity_self_to_sharer += air_heat_capacity
else
heat_capacity_sharer_to_self -= air_heat_capacity
if(delta_carbon_dioxide)
- var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
+ var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO * delta_carbon_dioxide
if(delta_carbon_dioxide > 0)
heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity
else
heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity
if(delta_toxins)
- var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
+ var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN * delta_toxins
if(delta_toxins > 0)
heat_capacity_self_to_sharer += toxins_heat_capacity
else
heat_capacity_sharer_to_self -= toxins_heat_capacity
+ if(delta_sleeping_agent)
+ var/sleeping_agent_heat_capacity = SPECIFIC_HEAT_N2O * delta_sleeping_agent
+ if(delta_sleeping_agent > 0)
+ heat_capacity_self_to_sharer += sleeping_agent_heat_capacity
+ else
+ heat_capacity_sharer_to_self -= sleeping_agent_heat_capacity
+
+ if(delta_agent_b)
+ var/agent_b_heat_capacity = SPECIFIC_HEAT_AGENT_B * delta_agent_b
+ if(delta_agent_b > 0)
+ heat_capacity_self_to_sharer += agent_b_heat_capacity
+ else
+ heat_capacity_sharer_to_self -= agent_b_heat_capacity
+
old_self_heat_capacity = heat_capacity()
old_sharer_heat_capacity = sharer.heat_capacity()
@@ -460,83 +409,40 @@ What are the archived variables for?
toxins -= delta_toxins
sharer.toxins += delta_toxins
- var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
- last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins)
+ sleeping_agent -= delta_sleeping_agent
+ sharer.sleeping_agent += delta_sleeping_agent
- var/list/trace_types_considered = list()
+ agent_b -= delta_agent_b
+ sharer.agent_b += delta_agent_b
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
- var/delta = 0
-
- if(corresponding)
- delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/(atmos_adjacent_turfs+1)
- else
- corresponding = new trace_gas.type()
- sharer.trace_gases += corresponding
-
- delta = trace_gas.moles_archived/(atmos_adjacent_turfs+1)
-
- trace_gas.moles -= delta
- corresponding.moles += delta
-
- if(delta)
- var/individual_heat_capacity = trace_gas.specific_heat*delta
- if(delta > 0)
- heat_capacity_self_to_sharer += individual_heat_capacity
- else
- heat_capacity_sharer_to_self -= individual_heat_capacity
-
- moved_moles += delta
- last_share += abs(delta)
-
- trace_types_considered += trace_gas.type
-
- for(var/gas in sharer.trace_gases)
- var/datum/gas/trace_gas = gas
- if(trace_gas.type in trace_types_considered)
- continue
- var/datum/gas/corresponding
- var/delta = 0
- corresponding = new trace_gas.type()
- trace_gases += corresponding
-
- delta = trace_gas.moles_archived/5
-
- trace_gas.moles -= delta
- corresponding.moles += delta
-
- //Guaranteed transfer from sharer to self
- var/individual_heat_capacity = trace_gas.specific_heat*delta
- heat_capacity_sharer_to_self += individual_heat_capacity
-
- moved_moles += -delta
- last_share += abs(delta)
+ var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
+ last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer
var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity
+ temperature = (old_self_heat_capacity * temperature - heat_capacity_self_to_sharer * temperature_archived + heat_capacity_sharer_to_self * sharer.temperature_archived) / new_self_heat_capacity
if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY)
- sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity
+ sharer.temperature = (old_sharer_heat_capacity * sharer.temperature - heat_capacity_sharer_to_self * sharer.temperature_archived + heat_capacity_self_to_sharer * temperature_archived) / new_sharer_heat_capacity
if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
- if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
+ if(abs(new_sharer_heat_capacity / old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
- var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles)
- return delta_pressure*R_IDEAL_GAS_EQUATION/volume
+ var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - sharer.temperature_archived * (sharer.total_moles() - moved_moles)
+ return delta_pressure * R_IDEAL_GAS_EQUATION / volume
/datum/gas_mixture/mimic(turf/model, atmos_adjacent_turfs = 4)
- var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/(atmos_adjacent_turfs+1)
- var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/(atmos_adjacent_turfs+1)
- var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/(atmos_adjacent_turfs+1)
- var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/(atmos_adjacent_turfs+1)
+ var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = QUANTIZE(toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = QUANTIZE(agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
var/delta_temperature = (temperature_archived - model.temperature)
@@ -546,57 +452,54 @@ What are the archived variables for?
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
- var/delta_air = delta_oxygen+delta_nitrogen
+ var/delta_air = delta_oxygen + delta_nitrogen
if(delta_air)
- var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
- heat_transferred -= air_heat_capacity*model.temperature
+ var/air_heat_capacity = SPECIFIC_HEAT_AIR * delta_air
+ heat_transferred -= air_heat_capacity * model.temperature
heat_capacity_transferred -= air_heat_capacity
if(delta_carbon_dioxide)
- var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
- heat_transferred -= carbon_dioxide_heat_capacity*model.temperature
+ var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO * delta_carbon_dioxide
+ heat_transferred -= carbon_dioxide_heat_capacity * model.temperature
heat_capacity_transferred -= carbon_dioxide_heat_capacity
if(delta_toxins)
- var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
- heat_transferred -= toxins_heat_capacity*model.temperature
+ var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN * delta_toxins
+ heat_transferred -= toxins_heat_capacity * model.temperature
heat_capacity_transferred -= toxins_heat_capacity
+ if(delta_sleeping_agent)
+ var/sleeping_agent_heat_capacity = SPECIFIC_HEAT_N2O * delta_sleeping_agent
+ heat_transferred -= sleeping_agent_heat_capacity * model.temperature
+ heat_capacity_transferred -= sleeping_agent_heat_capacity
+
+ if(delta_agent_b)
+ var/agent_b_heat_capacity = SPECIFIC_HEAT_AGENT_B * delta_agent_b
+ heat_transferred -= agent_b_heat_capacity * model.temperature
+ heat_capacity_transferred -= agent_b_heat_capacity
+
old_self_heat_capacity = heat_capacity()
oxygen -= delta_oxygen
carbon_dioxide -= delta_carbon_dioxide
nitrogen -= delta_nitrogen
toxins -= delta_toxins
+ sleeping_agent -= delta_sleeping_agent
+ agent_b -= delta_agent_b
- var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
- last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins)
-
- if(trace_gases.len)
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- var/delta = 0
-
- delta = trace_gas.moles_archived/(atmos_adjacent_turfs+1)
-
- trace_gas.moles -= delta
-
- var/heat_cap_transferred = delta*trace_gas.specific_heat
- heat_transferred += heat_cap_transferred*temperature_archived
- heat_capacity_transferred += heat_cap_transferred
- moved_moles += delta
- moved_moles += abs(delta)
+ var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
+ last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*temperature_archived)/new_self_heat_capacity
+ temperature = (old_self_heat_capacity * temperature - heat_capacity_transferred * temperature_archived) / new_self_heat_capacity
temperature_mimic(model, model.thermal_conductivity)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
- var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins)
- return delta_pressure*R_IDEAL_GAS_EQUATION/volume
+ var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b)
+ return delta_pressure * R_IDEAL_GAS_EQUATION / volume
else
return 0
@@ -608,11 +511,11 @@ What are the archived variables for?
var/sharer_heat_capacity = sharer.heat_capacity_archived()
if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
- var/heat = conduction_coefficient*delta_temperature* \
- (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
+ var/heat = conduction_coefficient*delta_temperature * \
+ (self_heat_capacity * sharer_heat_capacity / (self_heat_capacity + sharer_heat_capacity))
- temperature -= heat/self_heat_capacity
- sharer.temperature += heat/sharer_heat_capacity
+ temperature -= heat / self_heat_capacity
+ sharer.temperature += heat / sharer_heat_capacity
/datum/gas_mixture/temperature_mimic(turf/model, conduction_coefficient)
var/delta_temperature = (temperature - model.temperature)
@@ -620,10 +523,10 @@ What are the archived variables for?
var/self_heat_capacity = heat_capacity()
if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
- var/heat = conduction_coefficient*delta_temperature* \
- (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
+ var/heat = conduction_coefficient * delta_temperature * \
+ (self_heat_capacity * model.heat_capacity / (self_heat_capacity + model.heat_capacity))
- temperature -= heat/self_heat_capacity
+ temperature -= heat / self_heat_capacity
/datum/gas_mixture/temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature)
@@ -631,52 +534,36 @@ What are the archived variables for?
var/self_heat_capacity = heat_capacity()
if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
- var/heat = conduction_coefficient*delta_temperature* \
- (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
+ var/heat = conduction_coefficient * delta_temperature * \
+ (self_heat_capacity * sharer.heat_capacity / (self_heat_capacity + sharer.heat_capacity))
- temperature -= heat/self_heat_capacity
- sharer.temperature += heat/sharer.heat_capacity
+ temperature -= heat / self_heat_capacity
+ sharer.temperature += heat / sharer.heat_capacity
/datum/gas_mixture/compare(datum/gas_mixture/sample)
- if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
- ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen)))
+ if((abs(oxygen - sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((oxygen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen) || (oxygen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen)))
return 0
- if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
- ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen)))
+ if((abs(nitrogen - sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((nitrogen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen) || (nitrogen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen)))
return 0
- if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
- ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (carbon_dioxide > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide)))
+ if((abs(carbon_dioxide - sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((carbon_dioxide < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide) || (carbon_dioxide > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide)))
return 0
- if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
- ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins)))
+ if((abs(toxins - sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((toxins < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins) || (toxins > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins)))
+ return 0
+ if((abs(sleeping_agent - sample.sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((sleeping_agent < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent) || (sleeping_agent > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent)))
+ return 0
+ if((abs(agent_b - sample.agent_b) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((agent_b < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b) || (agent_b > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b)))
return 0
if(total_moles() > MINIMUM_AIR_TO_SUSPEND)
- if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
- ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
+ if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
+ ((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature) || (temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature)))
return 0
-
- for(var/gas in sample.trace_gases)
- var/datum/gas/trace_gas = gas
- if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND)
- var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
- if(corresponding)
- if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
- ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles)))
- return 0
- else
- return 0
-
- for(var/gas in trace_gases)
- var/datum/gas/trace_gas = gas
- if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND)
- var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases
- if(corresponding)
- if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
- ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles)))
- return 0
- else
- return 0
return 1
@@ -691,12 +578,12 @@ What are the archived variables for?
//Does handle trace gases!
/datum/gas_mixture/proc/get_breath_partial_pressure(gas_pressure)
- return (gas_pressure*R_IDEAL_GAS_EQUATION*temperature)/BREATH_VOLUME
+ return (gas_pressure * R_IDEAL_GAS_EQUATION * temperature) / BREATH_VOLUME
//Reverse of the above
/datum/gas_mixture/proc/get_true_breath_pressure(breath_pp)
- return (breath_pp*BREATH_VOLUME)/(R_IDEAL_GAS_EQUATION*temperature)
+ return (breath_pp * BREATH_VOLUME) / (R_IDEAL_GAS_EQUATION * temperature)
//Mathematical proofs:
/*
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 9bba49f2678..4e20d2a675e 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -211,7 +211,7 @@
var/datum/gas_mixture/A = F.air
// Can most things breathe?
- if(A.trace_gases.len)
+ if(A.sleeping_agent)
continue
if(A.oxygen < 16)
continue
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 7d3a73abf24..54635f01b0a 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -39,7 +39,6 @@
var/role_alt_title
var/datum/job/assigned_job
- var/list/kills = list()
var/list/datum/objective/objectives = list()
var/list/datum/objective/special_verbs = list()
var/list/targets = list()
@@ -90,6 +89,9 @@
if(antag_datum.delete_on_mind_deletion)
qdel(i)
antag_datums = null
+ current = null
+ original = null
+ soulOwner = null
return ..()
/datum/mind/proc/transfer_to(mob/living/new_character)
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index dae85c1726f..4a812b40e4e 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -39,7 +39,7 @@
if(user.client)
user.client.images += bar
- progress = Clamp(progress, 0, goal)
+ progress = clamp(progress, 0, goal)
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
if(!shown)
user.client.images += bar
diff --git a/code/datums/spell.dm b/code/datums/spell.dm
index 6b114971258..3855dbcfac3 100644
--- a/code/datums/spell.dm
+++ b/code/datums/spell.dm
@@ -237,10 +237,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
if(action)
action.UpdateButtonIcon()
-/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr) //if recharge is started is important for the trigger spells
+/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr, make_attack_logs = TRUE) //if recharge is started is important for the trigger spells
before_cast(targets)
invocation()
- if(user && user.ckey)
+ if(user && user.ckey && make_attack_logs)
add_attack_logs(user, targets, "cast the spell [name]", ATKLOG_ALL)
spawn(0)
if(charge_type == "recharge" && recharge)
diff --git a/code/datums/spells/knock.dm b/code/datums/spells/knock.dm
index dc2efcc1e91..88f5eec9474 100644
--- a/code/datums/spells/knock.dm
+++ b/code/datums/spells/knock.dm
@@ -13,6 +13,11 @@
action_icon_state = "knock"
sound = 'sound/magic/knock.ogg'
+// Knock doesn't need to generate an attack log for every turf, set `make_attack_logs` to FALSE and just create a custom one.
+/obj/effect/proc_holder/spell/aoe_turf/knock/perform(list/targets, recharge, mob/user)
+ add_attack_logs(user, user, "cast the spell [name]", ATKLOG_ALL)
+ return ..(targets, recharge, user, make_attack_logs = FALSE)
+
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
@@ -30,8 +35,6 @@
SC.locked = 0
C.open()
- return
-
/obj/effect/proc_holder/spell/aoe_turf/knock/greater
name = "Greater Knock"
desc = "On first cast, will remove access restrictions on all airlocks on the station, and announce this spell's use to the station. On any further cast, will open all doors in sight. Cannot be refunded once bought!"
diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm
index 2a8e1d94526..a0c41b57001 100644
--- a/code/datums/spells/summonitem.dm
+++ b/code/datums/spells/summonitem.dm
@@ -75,8 +75,6 @@
B.transfer_identity(C)
C.death()
add_attack_logs(target, C, "Magically debrained INTENT: [uppertext(target.a_intent)]")*/
- if(C.stomach_contents && (item_to_retrieve in C.stomach_contents))
- C.stomach_contents -= item_to_retrieve
for(var/X in C.bodyparts)
var/obj/item/organ/external/part = X
if(item_to_retrieve in part.embedded_objects)
diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm
index 6a951ac66a0..94383f1b1e2 100644
--- a/code/datums/spells/wizard.dm
+++ b/code/datums/spells/wizard.dm
@@ -423,7 +423,7 @@
M.Weaken(stun_amt)
to_chat(M, "You're thrown back by a mystical force!")
spawn(0)
- AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time.
+ AM.throw_at(throwtarget, ((clamp((maxthrow - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time.
/obj/effect/proc_holder/spell/targeted/sacred_flame
name = "Sacred Flame"
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index a0c9a19e4b0..8dbdfd95420 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -188,15 +188,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/storage/box/syndie_kit/fake_revolver
cost = 1
job = list("Clown")
-/*
-/datum/uplink_item/stealthy_weapons/romerol_kit
- name = "Romerol"
- reference = "ROM"
- desc = "A highly experimental bioterror agent which creates dormant nodules to be etched into the grey matter of the brain. On death, these nodules take control of the dead body, causing limited revivification, along with slurred speech, aggression, and the ability to infect others with this agent."
- item = /obj/item/storage/box/syndie_kit/romerol
- cost = 25
- cant_discount = TRUE
-*/
//mime
/datum/uplink_item/jobspecific/caneshotgun
name = "Cane Shotgun and Assassination Shells"
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index e3d90b8d075..dcde08d7ec1 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -166,9 +166,9 @@
//raises them if they are down (only if power's on)
if(!A.locked)
if(A.lock())
- A.audible_message("You hear a click from the bottom of the door.", null, 1)
+ A.audible_message("You hear a click from the bottom of the door.", hearing_distance = 1)
else if(A.unlock())
- A.audible_message("You hear a click from the bottom of the door.", null, 1)
+ A.audible_message("You hear a click from the bottom of the door.", hearing_distance = 1)
if(AIRLOCK_WIRE_BACKUP_POWER1)
//two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter).
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index 907e6a695e1..09c874ce8a8 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -31,7 +31,6 @@ GLOBAL_LIST_INIT(wireColours, list("red", "blue", "green", "black", "orange", "b
src.holder = holder
if(!istype(holder, holder_type))
CRASH("Our holder is null/the wrong type!")
- return
// Generate new wires
if(random)
diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm
index 094e4f9ca2b..8f3eeeaa6fa 100644
--- a/code/defines/procs/statistics.dm
+++ b/code/defines/procs/statistics.dm
@@ -29,8 +29,9 @@
var/laname
var/lakey
if(H.lastattacker)
- laname = sanitizeSQL(H.lastattacker:real_name)
- lakey = sanitizeSQL(H.lastattacker:key)
+ laname = sanitizeSQL(H.lastattacker)
+ if(H.lastattackerckey)
+ lakey = sanitizeSQL(H.lastattackerckey)
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
var/coord = "[H.x], [H.y], [H.z]"
// to_chat(world, "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.getBrainLoss()], [H.getOxyLoss()])")
@@ -64,8 +65,9 @@
var/laname
var/lakey
if(H.lastattacker)
- laname = sanitizeSQL(H.lastattacker:real_name)
- lakey = sanitizeSQL(H.lastattacker:key)
+ laname = sanitizeSQL(H.lastattacker)
+ if(H.lastattackerckey)
+ lakey = sanitizeSQL(H.lastattackerckey)
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
var/coord = "[H.x], [H.y], [H.z]"
// to_chat(world, "INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()])")
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index edfae8fd53e..9070d1409f6 100644
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
power_environ = FALSE
valid_territory = FALSE
outdoors = TRUE
- ambientsounds = list('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/traitor.ogg')
+ ambientsounds = SPACE_SOUNDS
/area/space/nearstation
icon_state = "space_near"
@@ -117,39 +117,33 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/escape
name = "\improper Emergency Shuttle"
- music = "music/escape.ogg"
icon_state = "shuttle2"
nad_allowed = TRUE
/area/shuttle/pod_1
name = "\improper Escape Pod One"
- music = "music/escape.ogg"
icon_state = "shuttle"
nad_allowed = TRUE
/area/shuttle/pod_2
name = "\improper Escape Pod Two"
- music = "music/escape.ogg"
icon_state = "shuttle"
nad_allowed = TRUE
/area/shuttle/pod_3
name = "\improper Escape Pod Three"
- music = "music/escape.ogg"
icon_state = "shuttle"
nad_allowed = TRUE
parallax_movedir = EAST
/area/shuttle/pod_4
name = "\improper Escape Pod Four"
- music = "music/escape.ogg"
icon_state = "shuttle"
nad_allowed = TRUE
parallax_movedir = EAST
/area/shuttle/escape_pod1
name = "\improper Escape Pod One"
- music = "music/escape.ogg"
nad_allowed = TRUE
/area/shuttle/escape_pod1/station
@@ -163,7 +157,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/escape_pod2
name = "\improper Escape Pod Two"
- music = "music/escape.ogg"
nad_allowed = TRUE
/area/shuttle/escape_pod2/station
@@ -177,7 +170,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/escape_pod3
name = "\improper Escape Pod Three"
- music = "music/escape.ogg"
nad_allowed = TRUE
/area/shuttle/escape_pod3/station
@@ -191,7 +183,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/escape_pod5 //Pod 4 was lost to meteors
name = "\improper Escape Pod Five"
- music = "music/escape.ogg"
nad_allowed = TRUE
/area/shuttle/escape_pod5/station
@@ -205,7 +196,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/mining
name = "\improper Mining Shuttle"
- music = "music/escape.ogg"
icon_state = "shuttle"
/area/shuttle/transport
@@ -246,7 +236,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/siberia
name = "\improper Labor Camp Shuttle"
- music = "music/escape.ogg"
icon_state = "shuttle"
/area/shuttle/specops
@@ -329,7 +318,6 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/shuttle/research
name = "\improper Research Shuttle"
- music = "music/escape.ogg"
icon_state = "shuttle"
/area/shuttle/research/station
@@ -498,6 +486,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
requires_power = FALSE
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
nad_allowed = TRUE
+ ambientsounds = HIGHSEC_SOUNDS
/area/syndicate_mothership/control
name = "\improper Syndicate Control Room"
@@ -519,6 +508,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
requires_power = FALSE
valid_territory = FALSE
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
+ ambientsounds = MINING_SOUNDS
/area/asteroid/cave // -- TLE
name = "\improper Asteroid - Underground"
@@ -633,7 +623,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
//Maintenance
/area/maintenance
- ambientsounds = list('sound/ambience/ambimaint1.ogg', 'sound/ambience/ambimaint2.ogg', 'sound/ambience/ambimaint3.ogg', 'sound/ambience/ambimaint4.ogg', 'sound/ambience/ambimaint5.ogg')
+ ambientsounds = MAINTENANCE_SOUNDS
valid_territory = FALSE
/area/maintenance/atmos_control
@@ -803,12 +793,11 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/bridge
name = "\improper Bridge"
icon_state = "bridge"
- music = "signal"
+ ambientsounds = list('sound/ambience/signal.ogg')
/area/bridge/meeting_room
name = "\improper Heads of Staff Meeting Room"
icon_state = "meeting"
- music = null
/area/crew_quarters/captain
name = "\improper Captain's Office"
@@ -969,10 +958,12 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
name = "\improper Abandoned Library"
icon_state = "library"
+/area/chapel
+ icon_state = "chapel"
+ ambientsounds = HOLY_SOUNDS
+
/area/chapel/main
name = "\improper Chapel"
- icon_state = "chapel"
- ambientsounds = list('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg','sound/music/traitor.ogg')
/area/chapel/office
name = "\improper Chapel Office"
@@ -1107,7 +1098,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
//Engineering
/area/engine
- ambientsounds = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
+ ambientsounds = ENGINEERING_SOUNDS
/area/engine/engine_smes
name = "\improper Engineering SMES"
@@ -1161,6 +1152,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
requires_power = FALSE
valid_territory = FALSE
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
+ ambientsounds = ENGINEERING_SOUNDS
/area/solar/auxport
name = "\improper Fore Port Solar Array"
@@ -1227,18 +1219,17 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/teleporter
name = "\improper Teleporter"
icon_state = "teleporter"
- music = "signal"
+ ambientsounds = ENGINEERING_SOUNDS
/area/gateway
name = "\improper Gateway"
icon_state = "teleporter"
- music = "signal"
+ ambientsounds = ENGINEERING_SOUNDS
/area/AIsattele
name = "\improper Abandoned Teleporter"
icon_state = "teleporter"
- music = "signal"
- ambientsounds = list('sound/ambience/ambimalf.ogg')
+ ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/signal.ogg')
/area/toxins/explab
name = "\improper E.X.P.E.R.I-MENTOR Lab"
@@ -1250,42 +1241,39 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
//MedBay
+/area/medical
+ ambientsounds = MEDICAL_SOUNDS
+
/area/medical/medbay
name = "\improper Medbay"
icon_state = "medbay"
- music = 'sound/ambience/signal.ogg'
//Medbay is a large area, these additional areas help level out APC load.
/area/medical/medbay2
name = "\improper Medbay"
icon_state = "medbay2"
- music = 'sound/ambience/signal.ogg'
/area/medical/medbay3
name = "\improper Medbay"
icon_state = "medbay3"
- music = 'sound/ambience/signal.ogg'
/area/medical/biostorage
name = "\improper Medical Storage"
icon_state = "medbaysecstorage"
- music = 'sound/ambience/signal.ogg'
/area/medical/reception
name = "\improper Medbay Reception"
icon_state = "medbay"
- music = 'sound/ambience/signal.ogg'
/area/medical/psych
name = "\improper Psych Room"
icon_state = "medbaypsych"
- music = 'sound/ambience/signal.ogg'
+ ambientsounds = list('sound/ambience/aurora_caelus_short.ogg')
/area/medical/medbreak
name = "\improper Break Room"
icon_state = "medbaybreak"
- music = 'sound/ambience/signal.ogg'
/area/medical/patients_rooms
name = "\improper Patient's Rooms"
@@ -1342,7 +1330,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/medical/morgue
name = "\improper Morgue"
icon_state = "morgue"
- ambientsounds = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg')
+ ambientsounds = SPOOKY_SOUNDS
/area/medical/chemistry
name = "\improper Chemistry"
@@ -1390,6 +1378,9 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
//Security
+/area/security
+ ambientsounds = HIGHSEC_SOUNDS
+
/area/security/main
name = "\improper Security Office"
icon_state = "securityoffice"
@@ -1522,6 +1513,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/security/detectives_office
name = "\improper Detective's Office"
icon_state = "detective"
+ ambientsounds = list('sound/ambience/ambidet1.ogg', 'sound/ambience/ambidet2.ogg')
/area/security/range
name = "\improper Firing Range"
@@ -1865,84 +1857,12 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
name = "Derelict Atmospherics"
icon_state = "red"
-//HALF-BUILT STATION (REPLACES DERELICT IN BAYCODE, ABOVE IS LEFT FOR DOWNSTREAM)
-
-/area/shuttle/constructionsite
- name = "\improper Construction Site Shuttle"
- icon_state = "yellow"
- parallax_movedir = EAST
-
-/area/shuttle/constructionsite/station
- name = "\improper Construction Site Shuttle"
-
-/area/shuttle/constructionsite/site
- name = "\improper Construction Site Shuttle"
-
-/area/constructionsite
- name = "\improper Construction Site"
- icon_state = "storage"
-
-/area/constructionsite/storage
- name = "\improper Construction Site Storage Area"
-
-/area/constructionsite/science
- name = "\improper Construction Site Research"
- icon_state = "medresearch"
-
-/area/constructionsite/bridge
- name = "\improper Construction Site Bridge"
- icon_state = "bridge"
-
-/area/constructionsite/hallway/center
- name = "\improper Construction Site Central Hallway"
- icon_state = "hallC"
-
-/area/constructionsite/hallway/engcore
- name = "\improper Construction Site Eng Core"
- icon_state = "green"
-
-/area/constructionsite/hallway/fore
- name = "\improper Construction Site Fore"
- icon_state = "green"
-
-/area/constructionsite/hallway/port
- name = "\improper Construction Site Port"
- icon_state = "hallP"
-
-/area/constructionsite/hallway/aft
- name = "\improper Construction Site Aft"
- icon_state = "hallA"
-
-/area/constructionsite/hallway/starboard
- name = "\improper Construction Site Starboard"
- icon_state = "hallS"
-
-/area/constructionsite/atmospherics
- name = "\improper Construction Site Atmospherics"
- icon_state = "atmos"
-
-/area/constructionsite/medical
- name = "\improper Construction Site Medbay"
- icon_state = "medbay"
-
-/area/constructionsite/ai
- name = "\improper Construction Computer Core"
- icon_state = "ai"
-
-/area/constructionsite/engineering
- name = "\improper Construction Site Engine Bay"
- icon_state = "engine"
-
-/area/solar/constructionsite
- name = "\improper Construction Site Solars"
- icon_state = "panelsA"
-
-
//Construction
/area/construction
name = "\improper Construction Area"
icon_state = "yellow"
+ ambientsounds = ENGINEERING_SOUNDS
/area/mining_construction
name = "Auxillary Base Construction"
@@ -2035,6 +1955,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/ai_monitored/storage/eva
name = "EVA Storage"
icon_state = "eva"
+ ambientsounds = HIGHSEC_SOUNDS
/area/ai_monitored/storage/secure
name = "Secure Storage"
@@ -2045,7 +1966,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
icon_state = "storage"
/area/turret_protected/
- ambientsounds = list('sound/ambience/ambimalf.ogg')
+ ambientsounds = list('sound/ambience/ambimalf.ogg', 'sound/ambience/ambitech.ogg', 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambiatmos.ogg', 'sound/ambience/ambiatmos2.ogg')
/area/turret_protected/ai_upload
name = "\improper AI Upload Chamber"
@@ -2107,7 +2028,8 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
// Telecommunications Satellite
/area/tcommsat
- ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
+ ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambitech.ogg',\
+ 'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg', 'sound/ambience/ambimystery.ogg')
/area/tcommsat/chamber
name = "\improper Telecoms Central Compartment"
@@ -2155,6 +2077,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
name = "\improper Strange Location"
icon_state = "away"
report_alerts = FALSE
+ ambientsounds = AWAY_MISSION_SOUNDS
/area/awaymission/example
name = "\improper Strange Station"
@@ -2169,7 +2092,7 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
icon_state = "beach"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
requires_power = FALSE
- ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg')
+ ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg', 'sound/ambience/seag2.ogg', 'sound/ambience/seag2.ogg', 'sound/ambience/ambiodd.ogg', 'sound/ambience/ambinice.ogg')
/area/awaymission/undersea
name = "Undersea"
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 6ad45532641..da80a6e775c 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -26,7 +26,6 @@
var/power_equip = TRUE
var/power_light = TRUE
var/power_environ = TRUE
- var/music = null
var/used_equip = FALSE
var/used_light = FALSE
var/used_environ = FALSE
@@ -56,12 +55,7 @@
var/global/global_uid = 0
var/uid
- var/list/ambientsounds = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg',\
- 'sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg',\
- 'sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg',\
- 'sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg',\
- 'sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg',\
- 'sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
+ var/list/ambientsounds = GENERIC_SOUNDS
var/fast_despawn = FALSE
var/can_get_auto_cryod = TRUE
@@ -379,20 +373,24 @@
// 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
if(L && L.client && !L.client.ambience_playing && (L.client.prefs.sound & SOUND_BUZZ)) //split off the white noise from the rest of the ambience because of annoyance complaints - Kluys
- L.client.ambience_playing = 1
- L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)
+ L.client.ambience_playing = TRUE
+ SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = TRUE, wait = FALSE, volume = 35, channel = CHANNEL_BUZZ))
else if(L && L.client && !(L.client.prefs.sound & SOUND_BUZZ))
- L.client.ambience_playing = 0
+ L.client.ambience_playing = FALSE
if(prob(35) && L && L.client && (L.client.prefs.sound & SOUND_AMBIENCE))
var/sound = pick(ambientsounds)
if(!L.client.played)
- L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE)
- L.client.played = 1
- spawn(600) //ewww - this is very very bad
- if(L && L.client)
- L.client.played = 0
+ SEND_SOUND(L, sound(sound, repeat = FALSE, wait = FALSE, volume = 25, channel = CHANNEL_AMBIENCE))
+ L.client.played = TRUE
+ addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
+
+/**
+ * Reset the played var to false on the client
+ */
+/client/proc/ResetAmbiencePlayed()
+ played = FALSE
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
A.has_gravity = gravitystate
diff --git a/code/game/area/areas/depot-areas.dm b/code/game/area/areas/depot-areas.dm
index 7a7c934df35..48760540c78 100644
--- a/code/game/area/areas/depot-areas.dm
+++ b/code/game/area/areas/depot-areas.dm
@@ -216,7 +216,8 @@
if(!silent)
announce_here("Depot Code BLUE", reason)
var/list/possible_bot_spawns = list()
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "syndi_depot_bot")
possible_bot_spawns |= L
if(possible_bot_spawns.len)
@@ -248,7 +249,8 @@
comms_online = TRUE
if(comms_online)
spawn(0)
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(prob(50))
if(L.name == "syndi_depot_backup")
var/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/space/S = new /mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/space(get_turf(L))
@@ -344,7 +346,8 @@
/area/syndicate_depot/core/proc/shields_up()
if(shield_list.len)
return
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "syndi_depot_shield")
var/obj/machinery/shieldwall/syndicate/S = new /obj/machinery/shieldwall/syndicate(L.loc)
shield_list += S.UID()
diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm
index 0b07fffda5e..b621bade493 100644
--- a/code/game/area/areas/mining.dm
+++ b/code/game/area/areas/mining.dm
@@ -7,7 +7,6 @@
/area/mine/explored
name = "Mine"
icon_state = "explored"
- music = null
always_unpowered = TRUE
requires_power = TRUE
poweralm = FALSE
@@ -15,7 +14,7 @@
power_equip = FALSE
power_light = FALSE
outdoors = TRUE
- ambientsounds = list('sound/ambience/ambimine.ogg')
+ ambientsounds = MINING_SOUNDS
flags = NONE
/area/mine/dangerous/explored/golem
@@ -24,7 +23,6 @@
/area/mine/unexplored
name = "Mine"
icon_state = "unexplored"
- music = null
always_unpowered = TRUE
requires_power = TRUE
poweralm = FALSE
@@ -32,7 +30,7 @@
power_equip = FALSE
power_light = FALSE
outdoors = TRUE
- ambientsounds = list('sound/ambience/ambimine.ogg')
+ ambientsounds = MINING_SOUNDS
flags = NONE
/area/mine/lobby
@@ -80,6 +78,7 @@
/area/mine/laborcamp/security
name = "Labor Camp Security"
icon_state = "security"
+ ambientsounds = HIGHSEC_SOUNDS
/area/mine/podbay
name = "Mining Podbay"
@@ -95,26 +94,24 @@
/area/lavaland/surface
name = "Lavaland"
icon_state = "explored"
- music = null
always_unpowered = TRUE
poweralm = FALSE
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
requires_power = TRUE
- ambientsounds = list('sound/ambience/ambilava.ogg')
+ ambientsounds = MINING_SOUNDS
/area/lavaland/underground
name = "Lavaland Caves"
icon_state = "unexplored"
- music = null
always_unpowered = TRUE
requires_power = TRUE
poweralm = FALSE
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
- ambientsounds = list('sound/ambience/ambilava.ogg')
+ ambientsounds = MINING_SOUNDS
/area/lavaland/surface/outdoors
name = "Lavaland Wastes"
diff --git a/code/game/area/areas/ruins/lavaland.dm b/code/game/area/areas/ruins/lavaland.dm
index 5baf1fe315e..53544d8643b 100644
--- a/code/game/area/areas/ruins/lavaland.dm
+++ b/code/game/area/areas/ruins/lavaland.dm
@@ -5,6 +5,7 @@
/area/ruin/powered/clownplanet
icon_state = "dk_yellow"
+ ambientsounds = list('sound/music/clown.ogg')
/area/ruin/powered/animal_hospital
icon_state = "dk_yellow"
@@ -38,7 +39,7 @@
/area/ruin/unpowered/syndicate_lava_base
name = "Secret Base"
icon_state = "dk_yellow"
- ambientsounds = list('sound/ambience/ambidanger.ogg', 'sound/ambience/ambidanger2.ogg')
+ ambientsounds = HIGHSEC_SOUNDS
report_alerts = FALSE
hide_attacklogs = TRUE
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index abd224e409b..776a2bccd12 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -14,21 +14,18 @@
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
var/simulated = TRUE //filter for actions - used by lighting overlays
var/atom_say_verb = "says"
- var/dont_save = 0 // For atoms that are temporary by necessity - like lighting overlays
-
+ var/bubble_icon = "default" ///what icon the mob uses for speechbubbles
+ var/dont_save = FALSE // For atoms that are temporary by necessity - like lighting overlays
///Chemistry.
var/container_type = NONE
var/datum/reagents/reagents = null
//This atom's HUD (med/sec, etc) images. Associative list.
- var/list/image/hud_list = list()
+ var/list/image/hud_list
//HUD images that this atom can provide.
var/list/hud_possible
- ///Chemistry.
-
-
//Value used to increment ex_act() if reactionary_explosions is on
var/explosion_block = 0
@@ -38,9 +35,9 @@
//Detective Work, used for allowing a given atom to leave its fibers on stuff. Allowed by default
var/can_leave_fibers = TRUE
- var/allow_spin = 1 //Set this to 1 for a _target_ that is being thrown at; if an atom has this set to 1 then atoms thrown AT it will not spin; currently used for the singularity. -Fox
+ var/allow_spin = TRUE //Set this to 1 for a _target_ that is being thrown at; if an atom has this set to 1 then atoms thrown AT it will not spin; currently used for the singularity. -Fox
- var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
+ var/admin_spawned = FALSE //was this spawned by an admin? used for stat tracking stuff.
var/initialized = FALSE
@@ -67,7 +64,6 @@
// we were deleted
return
-
//Called after New if the map is being loaded. mapload = TRUE
//Called from base of New if the map is not being loaded. mapload = FALSE
//This base must be called or derivatives must set initialized to TRUE
@@ -101,7 +97,6 @@
return INITIALIZE_HINT_NORMAL
-
//called if Initialize returns INITIALIZE_HINT_LATELOAD
/atom/proc/LateInitialize()
return
@@ -114,34 +109,34 @@
return
/atom/proc/onCentcom()
+ . = FALSE
var/turf/T = get_turf(src)
if(!T)
- return 0
+ return
if(!is_admin_level(T.z))//if not, don't bother
- return 0
+ return
//check for centcomm shuttles
for(var/centcom_shuttle in list("emergency", "pod1", "pod2", "pod3", "pod4", "ferry"))
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(centcom_shuttle)
if(T in M.areaInstance)
- return 1
+ return TRUE
//finally check for centcom itself
- return istype(T.loc,/area/centcom)
+ return istype(T.loc, /area/centcom)
/atom/proc/onSyndieBase()
+ . = FALSE
var/turf/T = get_turf(src)
if(!T)
- return 0
+ return
if(!is_admin_level(T.z))//if not, don't bother
- return 0
+ return
if(istype(T.loc, /area/shuttle/syndicate_elite) || istype(T.loc, /area/syndicate_mothership))
- return 1
-
- return 0
+ return TRUE
/atom/Destroy()
if(alternate_appearances)
@@ -164,6 +159,34 @@
SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir)
dir = newdir
+/*
+ Sets the atom's pixel locations based on the atom's `dir` variable, and what pixel offset arguments are passed into it
+ If no arguments are supplied, `pixel_x` or `pixel_y` will be set to 0
+ Used primarily for when players attach mountable frames to walls (APC frame, fire alarm frame, etc.)
+*/
+/atom/proc/set_pixel_offsets_from_dir(pixel_north = 0, pixel_south = 0, pixel_east = 0, pixel_west = 0)
+ switch(dir)
+ if(NORTH)
+ pixel_y = pixel_north
+ if(SOUTH)
+ pixel_y = pixel_south
+ if(EAST)
+ pixel_x = pixel_east
+ if(WEST)
+ pixel_x = pixel_west
+ if(NORTHEAST)
+ pixel_y = pixel_north
+ pixel_x = pixel_east
+ if(NORTHWEST)
+ pixel_y = pixel_north
+ pixel_x = pixel_west
+ if(SOUTHEAST)
+ pixel_y = pixel_south
+ pixel_x = pixel_east
+ if(SOUTHWEST)
+ pixel_y = pixel_south
+ pixel_x = pixel_west
+
///Handle melee attack by a mech
/atom/proc/mech_melee_attack(obj/mecha/M)
return
@@ -202,7 +225,7 @@
else
return null
-/atom/proc/check_eye(user)
+/atom/proc/check_eye(mob/user)
return
/atom/proc/on_reagent_change()
@@ -217,11 +240,11 @@
/// Is this atom injectable into other atoms
/atom/proc/is_injectable(mob/user, allowmobs = TRUE)
- return reagents && (container_type & (INJECTABLE | REFILLABLE))
+ return reagents && (container_type & (INJECTABLE|REFILLABLE))
/// Can we draw from this atom with an injectable atom
/atom/proc/is_drawable(mob/user, allowmobs = TRUE)
- return reagents && (container_type & (DRAWABLE | DRAINABLE))
+ return reagents && (container_type & (DRAWABLE|DRAINABLE))
/// Can this atoms reagents be refilled
/atom/proc/is_refillable()
@@ -232,12 +255,12 @@
return reagents && (container_type & DRAINABLE)
/atom/proc/CheckExit()
- return 1
+ return TRUE
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
-/atom/proc/emp_act(var/severity)
+/atom/proc/emp_act(severity)
return
/atom/proc/bullet_act(obj/item/projectile/P, def_zone)
@@ -247,13 +270,13 @@
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
if(istype(src.loc, container))
- return 1
+ return TRUE
else if(src in container)
- return 1
- return
+ return TRUE
+ return FALSE
/*
- * atom/proc/search_contents_for(path,list/filter_path=null)
+ * atom/proc/search_contents_for(path, list/filter_path = null)
* Recursevly searches all atom contens (including contents contents and so on).
*
* ARGS: path - search atom contents for atoms of this type
@@ -262,7 +285,7 @@
* RETURNS: list of found atoms
*/
-/atom/proc/search_contents_for(path,list/filter_path=null)
+/atom/proc/search_contents_for(path, list/filter_path = null)
var/list/found = list()
for(var/atom/A in src)
if(istype(A, path))
@@ -274,7 +297,7 @@
if(!pass)
continue
if(A.contents.len)
- found += A.search_contents_for(path,filter_path)
+ found += A.search_contents_for(path, filter_path)
return found
@@ -406,43 +429,47 @@
/atom/proc/after_slip(mob/living/carbon/human/H)
return
-/atom/proc/add_hiddenprint(mob/living/M as mob)
- if(isnull(M)) return
- if(isnull(M.key)) return
+/atom/proc/add_hiddenprint(mob/living/M)
+ if(isnull(M))
+ return
+ if(isnull(M.key))
+ return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(!istype(H.dna, /datum/dna))
- return 0
+ return FALSE
if(H.gloves)
if(fingerprintslast != H.ckey)
//Add the list if it does not exist.
if(!fingerprintshidden)
fingerprintshidden = list()
- fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []",H.real_name, H.key)
+ fingerprintshidden += text("\[[time_stamp()]\] (Wearing gloves). Real name: [], Key: []", H.real_name, H.key)
fingerprintslast = H.ckey
- return 0
+ return FALSE
if(!fingerprints)
if(fingerprintslast != H.ckey)
//Add the list if it does not exist.
if(!fingerprintshidden)
fingerprintshidden = list()
- fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",H.real_name, H.key)
+ fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []", H.real_name, H.key)
fingerprintslast = H.ckey
- return 1
+ return TRUE
else
if(fingerprintslast != M.ckey)
//Add the list if it does not exist.
if(!fingerprintshidden)
fingerprintshidden = list()
- fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []",M.real_name, M.key)
+ fingerprintshidden += text("\[[time_stamp()]\] Real name: [], Key: []", M.real_name, M.key)
fingerprintslast = M.ckey
return
//Set ignoregloves to add prints irrespective of the mob having gloves on.
-/atom/proc/add_fingerprint(mob/living/M as mob, ignoregloves = 0)
- if(isnull(M)) return
- if(isnull(M.key)) return
+/atom/proc/add_fingerprint(mob/living/M, ignoregloves = FALSE)
+ if(isnull(M))
+ return
+ if(isnull(M.key))
+ return
if(ishuman(M))
//Add the list if it does not exist.
if(!fingerprintshidden)
@@ -456,7 +483,7 @@
if(fingerprintslast != M.key)
fingerprintshidden += "(Has no fingerprints) Real name: [M.real_name], Key: [M.key]"
fingerprintslast = M.key
- return 0 //Now, lets get to the dirty work.
+ return FALSE //Now, lets get to the dirty work.
//First, make sure their DNA makes sense.
var/mob/living/carbon/human/H = M
if(!istype(H.dna, /datum/dna) || !H.dna.uni_identity || (length(H.dna.uni_identity) != 32))
@@ -469,20 +496,20 @@
if(H.gloves)
var/obj/item/clothing/gloves/G = H.gloves
if(G.transfer_prints)
- ignoregloves = 1
+ ignoregloves = TRUE
//Now, deal with gloves.
if(!ignoregloves)
if(H.gloves && H.gloves != src)
if(fingerprintslast != H.ckey)
- fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []",time_stamp(), H.real_name, H.key)
+ fingerprintshidden += text("\[[]\](Wearing gloves). Real name: [], Key: []", time_stamp(), H.real_name, H.key)
fingerprintslast = H.ckey
H.gloves.add_fingerprint(M)
- return 0
+ return FALSE
//More adminstuffz
if(fingerprintslast != H.ckey)
- fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), H.real_name, H.key)
+ fingerprintshidden += text("\[[]\]Real name: [], Key: []", time_stamp(), H.real_name, H.key)
fingerprintslast = H.ckey
//Make the list if it does not exist.
@@ -495,18 +522,16 @@
// Add the fingerprints
fingerprints[full_print] = full_print
- return 1
+ return TRUE
else
//Smudge up dem prints some
if(fingerprintslast != M.ckey)
- fingerprintshidden += text("\[[]\]Real name: [], Key: []",time_stamp(), M.real_name, M.key)
+ fingerprintshidden += text("\[[]\]Real name: [], Key: []", time_stamp(), M.real_name, M.key)
fingerprintslast = M.ckey
return
-
-/atom/proc/transfer_fingerprints_to(var/atom/A)
-
+/atom/proc/transfer_fingerprints_to(atom/A)
// Make sure everything are lists.
if(!islist(A.fingerprints))
A.fingerprints = list()
@@ -553,7 +578,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
/atom/proc/transfer_mob_blood_dna(mob/living/L)
var/new_blood_dna = L.get_blood_dna_list()
if(!new_blood_dna)
- return 0
+ return FALSE
return transfer_blood_dna(new_blood_dna)
/obj/effect/decal/cleanable/blood/splatter/transfer_mob_blood_dna(mob/living/L)
@@ -581,14 +606,13 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
var/old_length = blood_DNA.len
blood_DNA |= blood_dna
if(blood_DNA.len > old_length)
- return 1//some new blood DNA was added
-
+ return TRUE//some new blood DNA was added
//to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
var/list/blood_dna = M.get_blood_dna_list()
if(!blood_dna)
- return 0
+ return FALSE
var/bloodcolor = "#A10808"
var/list/b_data = M.get_blood_data(M.get_blood_id())
if(b_data)
@@ -598,7 +622,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
//to add blood onto something, with blood dna info to include.
/atom/proc/add_blood(list/blood_dna, color)
- return 0
+ return FALSE
/obj/add_blood(list/blood_dna, color)
return transfer_blood_dna(blood_dna)
@@ -606,10 +630,10 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
/obj/item/add_blood(list/blood_dna, color)
var/blood_count = !blood_DNA ? 0 : blood_DNA.len
if(!..())
- return 0
+ return FALSE
if(!blood_count)//apply the blood-splatter overlay if it isn't already in there
add_blood_overlay(color)
- return 1 //we applied blood to the item
+ return TRUE //we applied blood to the item
/obj/item/clothing/gloves/add_blood(list/blood_dna, color)
. = ..()
@@ -621,7 +645,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
B = new /obj/effect/decal/cleanable/blood/splatter(src)
B.transfer_blood_dna(blood_dna) //give blood info to the blood decal.
B.basecolor = color
- return 1 //we bloodied the floor
+ return TRUE //we bloodied the floor
/mob/living/carbon/human/add_blood(list/blood_dna, color)
if(wear_suit)
@@ -652,7 +676,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
verbs += /mob/living/carbon/human/proc/bloody_doodle
update_inv_gloves() //handles bloody hands overlays and updating
- return 1
+ return TRUE
/obj/item/proc/add_blood_overlay(color)
if(initial(icon) && initial(icon_state))
@@ -690,7 +714,6 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
if(.)
transfer_blood = 0
-
/obj/item/clothing/shoes/clean_blood()
..()
bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_NOT_BLOODY = 0)
@@ -699,23 +722,42 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
var/mob/M = loc
M.update_inv_shoes()
-
-/mob/living/carbon/human/clean_blood()
- if(gloves)
+/mob/living/carbon/human/clean_blood(clean_hands = TRUE, clean_mask = TRUE, clean_feet = TRUE)
+ if(w_uniform && !(wear_suit && wear_suit.flags_inv & HIDEJUMPSUIT))
+ if(w_uniform.clean_blood())
+ update_inv_w_uniform()
+ if(gloves && !(wear_suit && wear_suit.flags_inv & HIDEGLOVES))
if(gloves.clean_blood())
- clean_blood()
- update_inv_gloves()
- gloves.germ_level = 0
- else
- ..() // Clear the Blood_DNA list
- if(bloody_hands)
- bloody_hands = 0
update_inv_gloves()
+ gloves.germ_level = 0
+ clean_hands = FALSE
+ if(shoes && !(wear_suit && wear_suit.flags_inv & HIDESHOES))
+ if(shoes.clean_blood())
+ update_inv_shoes()
+ clean_feet = FALSE
+ if(s_store && !(wear_suit && wear_suit.flags_inv & HIDESUITSTORAGE))
+ if(s_store.clean_blood())
+ update_inv_s_store()
+ if(lip_style && !(head && head.flags_inv & HIDEMASK))
+ lip_style = null
+ update_body()
+ if(glasses && !(wear_mask && wear_mask.flags_inv & HIDEEYES))
+ if(glasses.clean_blood())
+ update_inv_glasses()
+ if(l_ear && !(wear_mask && wear_mask.flags_inv & HIDEEARS))
+ if(l_ear.clean_blood())
+ update_inv_ears()
+ if(r_ear && !(wear_mask && wear_mask.flags_inv & HIDEEARS))
+ if(r_ear.clean_blood())
+ update_inv_ears()
+ if(belt)
+ if(belt.clean_blood())
+ update_inv_belt()
+ ..(clean_hands, clean_mask, clean_feet)
update_icons() //apply the now updated overlays to the mob
-
-/atom/proc/add_vomit_floor(toxvomit = 0, green = FALSE)
- playsound(src, 'sound/effects/splat.ogg', 50, 1)
+/atom/proc/add_vomit_floor(toxvomit = FALSE, green = FALSE)
+ playsound(src, 'sound/effects/splat.ogg', 50, TRUE)
if(!isspaceturf(src))
var/type = green ? /obj/effect/decal/cleanable/vomit/green : /obj/effect/decal/cleanable/vomit
var/vomit_reagent = green ? "green_vomit" : "vomit"
@@ -728,23 +770,24 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
// Make toxins vomit look different
if(toxvomit)
- this.icon_state = "vomittox_[pick(1,4)]"
+ this.icon_state = "vomittox_[pick(1, 4)]"
/atom/proc/get_global_map_pos()
- if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map)) return
+ if(!islist(GLOB.global_map) || isemptylist(GLOB.global_map))
+ return
var/cur_x = null
var/cur_y = null
var/list/y_arr = null
- for(cur_x=1,cur_x<=GLOB.global_map.len,cur_x++)
+ for(cur_x in 1 to GLOB.global_map.len)
y_arr = GLOB.global_map[cur_x]
cur_y = y_arr.Find(src.z)
if(cur_y)
break
// to_chat(world, "X = [cur_x]; Y = [cur_y]")
if(cur_x && cur_y)
- return list("x"=cur_x,"y"=cur_y)
+ return list("x" = cur_x, "y" = cur_y)
else
- return 0
+ return null
// Used to provide overlays when using this atom as a viewing focus
// (cameras, locker tint, etc.)
@@ -757,7 +800,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
return
/atom/proc/checkpass(passflag)
- return pass_flags&passflag
+ return pass_flags & passflag
/atom/proc/isinspace()
if(isspaceturf(get_turf(src)))
@@ -798,9 +841,18 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
/atom/proc/atom_say(message)
if(!message)
return
- audible_message("[src] [atom_say_verb], \"[message]\"")
+ var/list/speech_bubble_hearers = list()
+ for(var/mob/M in get_mobs_in_view(7, src))
+ M.show_message("[src] [atom_say_verb], \"[message]\"", 2, null, 1)
+ if(M.client)
+ speech_bubble_hearers += M.client
-/atom/proc/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
+ if(length(speech_bubble_hearers))
+ var/image/I = image('icons/mob/talk.dmi', src, "[bubble_icon][say_test(message)]", FLY_LAYER)
+ I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+ INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_hearers, 30)
+
+/atom/proc/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
return
/atom/vv_edit_var(var_name, var_value)
@@ -857,7 +909,6 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
atom_colours[colour_priority] = coloration
update_atom_colour()
-
/*
Removes an instance of colour_type from the atom's atom_colours list
*/
@@ -872,7 +923,6 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
atom_colours[colour_priority] = null
update_atom_colour()
-
/*
Resets the atom's color to null, and then sets it to the highest priority
colour available
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 70926d7ba2b..ab5ff19462a 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -44,16 +44,18 @@
/atom/movable/Destroy()
unbuckle_all_mobs(force = TRUE)
+
+ . = ..()
if(loc)
loc.handle_atom_del(src)
for(var/atom/movable/AM in contents)
qdel(AM)
+ LAZYCLEARLIST(client_mobs_in_contents)
loc = null
if(pulledby)
- if(pulledby.pulling == src)
- pulledby.pulling = null
- pulledby = null
- return ..()
+ pulledby.stop_pulling()
+ if(orbiting)
+ stop_orbit()
//Returns an atom's power cell, if it has one. Overload for individual items.
/atom/movable/proc/get_cell()
@@ -233,6 +235,9 @@
SEND_SIGNAL(src, COMSIG_MOVABLE_CROSSED, AM)
SEND_SIGNAL(AM, COMSIG_CROSSED_MOVABLE, src)
+/atom/movable/Uncrossed(atom/movable/AM)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_UNCROSSED, AM)
+
/atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump().
if(A && yes)
SEND_SIGNAL(src, COMSIG_MOVABLE_BUMP, A)
@@ -265,15 +270,8 @@
var/dest_z = (destturf ? destturf.z : null)
if(old_z != dest_z)
onTransitZ(old_z, dest_z)
- if(isturf(destination) && opacity)
- var/turf/new_loc = destination
- new_loc.reconsider_lights()
- if(isturf(old_loc) && opacity)
- old_loc.reconsider_lights()
-
- for(var/datum/light_source/L in light_sources)
- L.source_atom.update_light()
+ Moved(old_loc, NONE)
return 1
@@ -500,7 +498,7 @@
target.fingerprintshidden += fingerprintshidden
target.fingerprintslast = fingerprintslast
-/atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && (visual_effect_icon || used_item))
do_item_attack_animation(A, visual_effect_icon, used_item)
@@ -508,10 +506,6 @@
return //don't do an animation if attacking self
var/pixel_x_diff = 0
var/pixel_y_diff = 0
- var/final_pixel_y = initial(pixel_y)
- if(end_pixel_y)
- final_pixel_y = end_pixel_y
-
var/direction = get_dir(src, A)
if(direction & NORTH)
pixel_y_diff = 8
@@ -524,7 +518,7 @@
pixel_x_diff = -8
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
- animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
+ animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, time = 2)
/atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item)
var/image/I
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 08a7b77daff..6bd00d286fe 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -135,8 +135,6 @@
return "health-90"
else
return "health-100" //past this point, you're just in trouble
- return "0"
-
///HOOKS
@@ -270,7 +268,6 @@
return "crit"
else
return "dead"
- return "dead"
//Sillycone hooks
/mob/living/silicon/proc/diag_hud_set_health()
@@ -400,7 +397,6 @@
return "max"
else
return "zero"
- return "zero"
/obj/machinery/hydroponics/proc/plant_hud_set_nutrient()
var/image/holder = hud_list[PLANT_NUTRIENT_HUD]
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index a6ec98e8866..eae6edd3bd4 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -144,7 +144,7 @@
set category = null
set name = "Enter DNA Scanner"
- if(usr.incapacitated()) //are you cuffed, dying, lying, stunned or other
+ if(usr.incapacitated() || usr.buckled) //are you cuffed, dying, lying, stunned or other
return
if(!ishuman(usr)) //Make sure they're a mob that has dna
to_chat(usr, "Try as you might, you can not climb up into the [src].")
diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm
index a11e5d922ba..641167c768c 100644
--- a/code/game/gamemodes/blob/blob.dm
+++ b/code/game/gamemodes/blob/blob.dm
@@ -46,7 +46,6 @@ GLOBAL_LIST_EMPTY(blob_nodes)
var/datum/mind/blob = pick(possible_blobs)
infected_crew += blob
blob.special_role = SPECIAL_ROLE_BLOB
- update_blob_icons_added(blob)
blob.restricted_roles = restricted_jobs
log_game("[key_name(blob)] has been selected as a Blob")
possible_blobs -= blob
@@ -152,6 +151,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
for(var/datum/mind/blob in infected_crew)
greet_blob(blob)
+ update_blob_icons_added(blob)
if(SSshuttle)
SSshuttle.emergencyNoEscape = 1
diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm
index 6128c22f66d..9c7fb99fe81 100644
--- a/code/game/gamemodes/blob/blob_report.dm
+++ b/code/game/gamemodes/blob/blob_report.dm
@@ -19,7 +19,7 @@
intercepttext += "Message ends."
if(2)
var/nukecode = rand(10000, 99999)
- for(var/obj/machinery/nuclearbomb/bomb in world)
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb && bomb.r_code)
if(is_station_level(bomb.z))
bomb.r_code = nukecode
diff --git a/code/game/gamemodes/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm
index b7bcd737dfd..46b1972e565 100644
--- a/code/game/gamemodes/blob/blobs/blob_mobs.dm
+++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm
@@ -8,6 +8,7 @@
icon = 'icons/mob/blob.dmi'
pass_flags = PASSBLOB
faction = list(ROLE_BLOB)
+ bubble_icon = "blob"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = 360
@@ -56,7 +57,7 @@
/mob/living/simple_animal/hostile/blob/blobspore/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
- adjustBruteLoss(Clamp(0.01 * exposed_temperature, 1, 5))
+ adjustBruteLoss(clamp(0.01 * exposed_temperature, 1, 5))
/mob/living/simple_animal/hostile/blob/blobspore/CanPass(atom/movable/mover, turf/target, height=0)
@@ -86,8 +87,8 @@
is_zombie = TRUE
if(H.wear_suit)
var/obj/item/clothing/suit/armor/A = H.wear_suit
- if(A.armor && A.armor["melee"])
- maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
+ if(A.armor && A.armor.getRating("melee"))
+ maxHealth += A.armor.getRating("melee") //That zombie's got armor, I want armor!
maxHealth += 40
health = maxHealth
name = "blob zombie"
diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm
index 672ab037cc5..be794b9092b 100644
--- a/code/game/gamemodes/blob/blobs/core.dm
+++ b/code/game/gamemodes/blob/blobs/core.dm
@@ -89,41 +89,40 @@
..()
-/obj/structure/blob/core/proc/create_overmind(var/client/new_overmind, var/override_delay)
+/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
if(overmind_get_delay > world.time && !override_delay)
return
- overmind_get_delay = world.time + 3000 // 5 minutes
+ overmind_get_delay = world.time + 5 MINUTES
if(overmind)
qdel(overmind)
+ INVOKE_ASYNC(src, .proc/get_new_overmind, new_overmind)
+
+/obj/structure/blob/core/proc/get_new_overmind(client/new_overmind)
var/mob/C = null
var/list/candidates = list()
-
- spawn()
- if(!new_overmind)
- if(is_offspring)
- candidates = pollCandidates("Do you want to play as a blob offspring?", ROLE_BLOB, 1)
- else
- candidates = pollCandidates("Do you want to play as a blob?", ROLE_BLOB, 1)
-
- if(candidates.len)
- C = pick(candidates)
+ if(!new_overmind)
+ if(is_offspring)
+ candidates = pollCandidates("Do you want to play as a blob offspring?", ROLE_BLOB, 1)
else
- C = new_overmind
+ candidates = pollCandidates("Do you want to play as a blob?", ROLE_BLOB, 1)
- if(C)
- var/mob/camera/blob/B = new(src.loc)
- B.key = C.key
- B.blob_core = src
- src.overmind = B
- color = overmind.blob_reagent_datum.color
- if(B.mind && !B.mind.special_role)
- B.mind.make_Overmind()
- spawn(0)
- if(is_offspring)
- B.is_offspring = TRUE
+ if(length(candidates))
+ C = pick(candidates)
+ else
+ C = new_overmind
+
+ if(C && !QDELETED(src))
+ var/mob/camera/blob/B = new(loc)
+ B.key = C.key
+ B.blob_core = src
+ overmind = B
+ color = overmind.blob_reagent_datum.color
+ if(B.mind && !B.mind.special_role)
+ B.mind.make_Overmind()
+ B.is_offspring = is_offspring
/obj/structure/blob/core/proc/lateblobtimer()
addtimer(CALLBACK(src, .proc/lateblobcheck), 50)
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index 0c2342328a2..316a136afc6 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -57,7 +57,7 @@
/mob/camera/blob/proc/add_points(var/points)
if(points != 0)
- blob_points = Clamp(blob_points + points, 0, max_blob_points)
+ blob_points = clamp(blob_points + points, 0, max_blob_points)
if(hud_used)
hud_used.blobpwrdisplay.maptext = "
[round(src.blob_points)]
"
diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm
index 886975a2c92..5e2c3befc9a 100644
--- a/code/game/gamemodes/blob/theblob.dm
+++ b/code/game/gamemodes/blob/theblob.dm
@@ -49,7 +49,7 @@
/obj/structure/blob/CanAStarPass(ID, dir, caller)
. = 0
- if(ismovableatom(caller))
+ if(ismovable(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSBLOB)
@@ -74,9 +74,6 @@
/obj/structure/blob/proc/Pulse(var/pulse = 0, var/origin_dir = 0, var/a_color)//Todo: Fix spaceblob expand
-
- set background = BACKGROUND_ENABLED
-
RegenHealth()
if(run_action())//If we can do something here then we dont need to pulse more
@@ -179,7 +176,7 @@
return 0
var/armor_protection = 0
if(damage_flag)
- armor_protection = armor[damage_flag]
+ armor_protection = armor.getRating(damage_flag)
damage_amount = round(damage_amount * (100 - armor_protection)*0.01, 0.1)
if(overmind && damage_flag)
damage_amount = overmind.blob_reagent_datum.damage_reaction(src, damage_amount, damage_type, damage_flag)
diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
index 34a2d67b58b..d6062a02c5d 100644
--- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
+++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
@@ -76,11 +76,11 @@
var/mob/living/carbon/human/H = owner
H.weakeyes = 1
if(!H.vision_type)
- H.vision_type = new /datum/vision_override/nightvision
+ H.set_sight(/datum/vision_override/nightvision)
/obj/item/organ/internal/cyberimp/eyes/thermals/ling/remove(mob/living/carbon/M, special = 0)
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.weakeyes = 0
- H.vision_type = null
+ H.set_sight(null)
..()
diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm
index ce62242ca0f..d12b970d884 100644
--- a/code/game/gamemodes/changeling/powers/mutations.dm
+++ b/code/game/gamemodes/changeling/powers/mutations.dm
@@ -321,7 +321,7 @@
if(INTENT_GRAB)
C.visible_message("[L] is grabbed by [H]'s tentacle!","A tentacle grabs you and pulls you towards [H]!")
- add_attack_logs(src, C, "[src] has grabbed [C] and pulled them towards [H] with a tentacle")
+ add_attack_logs(H, C, "[H] grabbed [C] with a changeling tentacle")
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(H, /mob/proc/tentacle_grab, C))
return 1
diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
index 94bde26674b..fbfb75b8b6a 100644
--- a/code/game/gamemodes/changeling/powers/tiny_prick.dm
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -36,11 +36,9 @@
to_chat(user, "We haven't prepared our sting yet!")
if(!iscarbon(target))
return
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- if(H.isSynthetic())
- to_chat(user, "This won't work on synthetics.")
- return
+ if(ismachineperson(target))
+ to_chat(user, "This won't work on synthetics.")
+ return
if(!isturf(user.loc))
return
if(!AStar(user, target.loc, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0))
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 1a9dd15c65e..bf5fbb70731 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -84,8 +84,8 @@ GLOBAL_LIST_EMPTY(all_cults)
var/survivors = 0
/datum/game_mode/cult/announce()
- to_chat(world, "The current game mode is - Cult!")
- to_chat(world, "Some crewmembers are attempting to start a cult! \nCultists - complete your objectives. Convert crewmembers to your cause by using the convert rune. Remember - there is no you, there is only the cult. \nPersonnel - Do not let the cult succeed in its mission. Brainwashing them with the chaplain's bible reverts them to whatever CentComm-allowed faith they had.")
+ to_chat(world, "The current game mode is - Cult!")
+ to_chat(world, "Some crew members are attempting to start a cult! \nCultists - complete your objectives. Convert crew members to your cause by using the convert rune. Remember - there is no you, there is only the cult. \nPersonnel - Do not let the cult succeed in its mission. Brainwashing them with the chaplain's bible reverts them to whatever CentComm-allowed faith they had.")
/datum/game_mode/cult/pre_setup()
@@ -147,8 +147,8 @@ GLOBAL_LIST_EMPTY(all_cults)
explanation = "Free objective."
if("eldergod")
explanation = "Summon [SSticker.cultdat.entity_name] by invoking the 'Tear Reality' rune.The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin."
- to_chat(cult_mind.current, "Objective #[obj_count]: [explanation]")
- cult_mind.memory += "Objective #[obj_count]: [explanation] "
+ to_chat(cult_mind.current, "Objective #[obj_count]: [explanation]")
+ cult_mind.memory += "Objective #[obj_count]: [explanation] "
/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob)
@@ -210,7 +210,7 @@ GLOBAL_LIST_EMPTY(all_cults)
update_cult_icons_removed(cult_mind)
if(show_message)
for(var/mob/M in viewers(cult_mind.current))
- to_chat(M, "[cult_mind.current] looks like [cult_mind.current.p_they()] just reverted to [cult_mind.current.p_their()] old faith!")
+ to_chat(M, "[cult_mind.current] looks like [cult_mind.current.p_they()] just reverted to [cult_mind.current.p_their()] old faith!")
/datum/game_mode/proc/update_cult_icons_added(datum/mind/cult_mind)
@@ -284,11 +284,11 @@ GLOBAL_LIST_EMPTY(all_cults)
if(!check_cult_victory())
feedback_set_details("round_end_result","cult win - cult win")
feedback_set("round_end_result",acolytes_survived)
- to_chat(world, " The cult wins! It has succeeded in serving its dark masters!")
+ to_chat(world, " The cult wins! It has succeeded in serving its dark masters!")
else
feedback_set_details("round_end_result","cult loss - staff stopped the cult")
feedback_set("round_end_result",acolytes_survived)
- to_chat(world, " The staff managed to stop the cult!")
+ to_chat(world, " The staff managed to stop the cult!")
var/text = "Cultists escaped: [acolytes_survived]"
@@ -299,7 +299,7 @@ GLOBAL_LIST_EMPTY(all_cults)
switch(objectives[obj_count])
if("survive")
if(!check_survive())
- explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Success!"
+ explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Success!"
feedback_add_details("cult_objective","cult_survive|SUCCESS|[acolytes_needed]")
else
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. Fail."
@@ -307,7 +307,7 @@ GLOBAL_LIST_EMPTY(all_cults)
if("sacrifice")
if(sacrifice_target)
if(sacrifice_target in sacrificed)
- explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Success!"
+ explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Success!"
feedback_add_details("cult_objective","cult_sacrifice|SUCCESS")
else if(sacrifice_target && sacrifice_target.current)
explanation = "Sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role]. Fail."
@@ -317,7 +317,7 @@ GLOBAL_LIST_EMPTY(all_cults)
feedback_add_details("cult_objective","cult_sacrifice|FAIL|GIBBED")
if("eldergod")
if(!eldergod)
- explanation = "Summon [SSticker.cultdat.entity_name]. Success!"
+ explanation = "Summon [SSticker.cultdat.entity_name]. Success!"
feedback_add_details("cult_objective","cult_narsie|SUCCESS")
else
explanation = "Summon [SSticker.cultdat.entity_name]. Fail."
@@ -332,45 +332,45 @@ GLOBAL_LIST_EMPTY(all_cults)
if("convert")//convert half the crew
if(cult.len >= convert_target)
- explanation = "Convert [convert_target] crewmembers ([cult.len] cultists at round end). Success!"
+ explanation = "Convert [convert_target] crew members ([cult.len] cultists at round end). Success!"
feedback_add_details("cult_objective","cult_convertion|SUCCESS")
else
- explanation = "Convert [convert_target] crewmembers ([cult.len] total cultists). Fail!"
+ explanation = "Convert [convert_target] crew members ([cult.len] total cultists). Fail."
feedback_add_details("cult_objective","cult_convertion|FAIL")
if("bloodspill")//cover a large portion of the station in blood
if(max_spilled_blood >= spilltarget)
- explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Success!"
+ explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Success!"
feedback_add_details("cult_objective","cult_bloodspill|SUCCESS")
else
- explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Fail!"
+ explanation = "Cover [spilltarget] tiles of the station in blood (The peak number of covered tiles was: [max_spilled_blood]). Fail."
feedback_add_details("cult_objective","cult_bloodspill|FAIL")
if("harvest")
if(harvested > harvest_target)
- explanation = "Offer [harvest_target] humans for [SSticker.cultdat.entity_name]'s first meal of the day. ([harvested] sacrificed) Success!"
+ explanation = "Offer [harvest_target] humanoids for [SSticker.cultdat.entity_name]'s first meal of the day. ([harvested] sacrificed) Success!"
feedback_add_details("cult_objective","cult_harvest|SUCCESS")
else
- explanation = "Offer [harvest_target] humans for [SSticker.cultdat.entity_name]'s first meal of the day. ([harvested] sacrificed) Fail!"
+ explanation = "Offer [harvest_target] humanoids for [SSticker.cultdat.entity_name]'s first meal of the day. ([harvested] sacrificed) Fail."
feedback_add_details("cult_objective","cult_harvest|FAIL")
if("hijack")
if(!escaped_shuttle)
- explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Success!"
+ explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Success!"
feedback_add_details("cult_objective","cult_hijack|SUCCESS")
else
- explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Fail!"
+ explanation = "Do not let a single non-cultist board the Escape Shuttle. ([escaped_shuttle] escaped on the shuttle) ([escaped_pod] escaped on pods) Fail."
feedback_add_details("cult_objective","cult_hijack|FAIL")
if("massacre")
if(survivors < massacre_target)
- explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humans left alive) Success!"
+ explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humanoids left alive) Success!"
feedback_add_details("cult_objective","cult_massacre|SUCCESS")
else
- explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humans left alive) Fail!"
+ explanation = "Massacre the crew until less than [massacre_target] people are left on the station. ([survivors] humanoids left alive) Fail."
feedback_add_details("cult_objective","cult_massacre|FAIL")
- text += " Objective #[obj_count]: [explanation]"
+ text += " Objective #[obj_count]: [explanation]"
to_chat(world, text)
..()
@@ -379,7 +379,7 @@ GLOBAL_LIST_EMPTY(all_cults)
/datum/game_mode/proc/auto_declare_completion_cult()
if(cult.len || (SSticker && GAMEMODE_IS_CULT))
- var/text = "The cultists were:"
+ var/text = "The cultists were:"
for(var/datum/mind/cultist in cult)
text += " [cultist.key] was [cultist.name] ("
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index fcc39124233..0f637153f6c 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -24,7 +24,7 @@
return
if((MUTE in user.mutations) || user.mind.miming) //Under vow of silence/mute?
- user.visible_message("[user] appears to whisper to themselves.","You begin to whisper to yourself.") //Make them do *something* abnormal.
+ user.visible_message("[user] appears to whisper to [user.p_them()]self.","You begin to whisper to yourself.") //Make them do *something* abnormal.
else
user.whisper("O bidai nabora se[pick("'","`")]sma!") // Otherwise book club sayings.
sleep(10)
@@ -35,8 +35,8 @@
if(!((MUTE in user.mutations) || user.mind.miming)) // If they aren't mute/miming, commence the whisperting
user.whisper(message)
var/my_message
- if(istype(user, /mob/living/simple_animal/slaughter/cult)) //Harbringers of the Slaughter
- my_message = "Harbringer of the Slaughter: [message]"
+ if(istype(user, /mob/living/simple_animal/slaughter/cult)) //Harbingers of the Slaughter
+ my_message = "Harbinger of the Slaughter: [message]"
else
my_message = "[(ishuman(user) ? "Acolyte" : "Construct")] [user.real_name]: [message]"
for(var/mob/M in GLOB.player_list)
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index c0daac2a01a..388b16d71af 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -105,7 +105,7 @@
/obj/item/clothing/suit/magusred
name = "magus robes"
- desc = "A set of armored robes worn by the followers of Nar-Sie"
+ desc = "A set of armored robes worn by the followers of Nar-Sie."
icon_state = "magusred"
item_state = "magusred"
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
@@ -132,7 +132,7 @@
/obj/item/clothing/suit/hooded/cultrobes/cult_shield
name = "empowered cultist robe"
- desc = "Empowered garb which creates a powerful shield around the user."
+ desc = "An empowered garb which creates a powerful shield around the user."
icon_state = "cult_armour"
item_state = "cult_armour"
w_class = WEIGHT_CLASS_BULKY
@@ -144,7 +144,7 @@
/obj/item/clothing/head/hooded/cult_hoodie
name = "empowered cultist robe"
- desc = "Empowered garb which creates a powerful shield around the user."
+ desc = "An empowered garb which creates a powerful shield around the user."
icon_state = "cult_hoodalt"
armor = list("melee" = 40, "bullet" = 30, "laser" = 40,"energy" = 20, "bomb" = 25, "bio" = 10, "rad" = 0, "fire" = 10, "acid" = 10)
body_parts_covered = HEAD
@@ -213,8 +213,8 @@
list_reagents = list("unholywater" = 40)
/obj/item/clothing/glasses/night/cultblind
- desc = "May the master guide you through the darkness and shield you from the light."
name = "zealot's blindfold"
+ desc = "May the master guide you through the darkness and shield you from the light."
icon_state = "blindfold"
item_state = "blindfold"
see_in_dark = 8
@@ -247,7 +247,7 @@
to_chat(user, "We have exhausted our ability to curse the shuttle.")
return
if(locate(/obj/singularity/narsie) in GLOB.poi_list || locate(/mob/living/simple_animal/slaughter/cult) in GLOB.mob_list)
- to_chat(user, "Nar-Sie or his avatars are already on this plane, there is no delaying the end of all things.")
+ to_chat(user, "Nar-Sie or her avatars are already on this plane, there is no delaying the end of all things.")
return
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
@@ -273,7 +273,7 @@
/obj/item/cult_shift
name = "veil shifter"
- desc = "This relic teleports you forward a medium distance."
+ desc = "This relic teleports you forward by a medium distance."
icon = 'icons/obj/cult.dmi'
icon_state ="shifter"
var/uses = 4
@@ -353,7 +353,7 @@
/obj/item/clothing/suit/cultrobesghost
name = "ghostly cult robes"
- desc = "A set of ethreal armored robes worn by the undead followers of a cult."
+ desc = "A set of ethereal armored robes worn by the undead followers of a cult."
icon_state = "cultrobesalt"
item_state = "cultrobesalt"
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
diff --git a/code/game/gamemodes/cult/cult_objectives.dm b/code/game/gamemodes/cult/cult_objectives.dm
index f1a188022a0..38bd1919c62 100644
--- a/code/game/gamemodes/cult/cult_objectives.dm
+++ b/code/game/gamemodes/cult/cult_objectives.dm
@@ -27,8 +27,8 @@
explanation = "We need to sacrifice [sacrifice_target.name], the [sacrifice_target.assigned_role], for [sacrifice_target.p_their()] blood is the key that will lead our master to this realm. You will need 3 cultists around a Sacrifice rune to perform the ritual."
for(var/datum/mind/cult_mind in cult)
- to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
- cult_mind.memory += "Objective #[current_objective]: [explanation] "
+ to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
+ cult_mind.memory += "Objective #[current_objective]: [explanation] "
/datum/game_mode/cult/proc/bypass_phase()
@@ -89,8 +89,8 @@
for(var/datum/mind/cult_mind in cult)
if(cult_mind)
to_chat(cult_mind.current, "You and your acolytes have completed your task, but this place requires yet more preparation!")
- to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
- cult_mind.memory += "Objective #[current_objective]: [explanation] "
+ to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
+ cult_mind.memory += "Objective #[current_objective]: [explanation] "
message_admins("New Cult Objective: [new_objective]")
log_admin("New Cult Objective: [new_objective]")
@@ -104,8 +104,8 @@
for(var/datum/mind/cult_mind in cult)
if(cult_mind)
to_chat(cult_mind.current, "You and your acolytes suddenly feel the urge to do your best, but survive!")
- to_chat(cult_mind.current, "Objective Survive: [explanation]")
- cult_mind.memory += "Objective Survive: [explanation] "
+ to_chat(cult_mind.current, "Objective Survive: [explanation]")
+ cult_mind.memory += "Objective Survive: [explanation] "
/datum/game_mode/cult/proc/second_phase()
@@ -117,13 +117,13 @@
explanation = "Summon [SSticker.cultdat.entity_name] on the Station via the use of the Tear Reality rune. The veil is weak enough in [english_list(GLOB.summon_spots)] for the ritual to begin."
else
objectives += "slaughter"
- explanation = "Bring the Slaughter via the rune 'Bring forth the slaughter'. The veil is weak enough in [english_list(GLOB.summon_spots)] for the ritual to begin."
+ explanation = "Bring the Slaughter via the rune 'Call Forth The Slaughter'. The veil is weak enough in [english_list(GLOB.summon_spots)] for the ritual to begin."
for(var/datum/mind/cult_mind in cult)
if(cult_mind)
to_chat(cult_mind.current, "You and your acolytes have succeeded in preparing the station for the ultimate ritual!")
- to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
- cult_mind.memory += "Objective #[current_objective]: [explanation] "
+ to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
+ cult_mind.memory += "Objective #[current_objective]: [explanation] "
/datum/game_mode/cult/proc/third_phase()
current_objective++
@@ -138,16 +138,16 @@
switch(last_objective)
if("harvest")
- explanation = "[SSticker.cultdat.entity_title1] hungers for their first meal of this never-ending day. Offer them [harvest_target] humans in sacrifice."
+ explanation = "[SSticker.cultdat.entity_title1] hungers for their first meal of this never-ending day. Offer them [harvest_target] humanoids in sacrifice."
if("hijack")
- explanation = "[SSticker.cultdat.entity_name] wishes for their troops to start the assault on Centcom immediately. Hijack the escape shuttle and don't let a single non-cultist board it."
+ explanation = "[SSticker.cultdat.entity_name] wishes for their troops to start the assault on CentCom immediately. Hijack the escape shuttle and don't let a single non-cultist board it."
if("massacre")
- explanation = "[SSticker.cultdat.entity_name] wants to watch you as you massacre the remaining humans on the station (until less than [massacre_target] humans are left alive)."
+ explanation = "[SSticker.cultdat.entity_name] wants to watch you as you massacre the remaining crew on the station (until less than [massacre_target] humans are left alive)."
for(var/datum/mind/cult_mind in cult)
if(cult_mind)
- to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
- cult_mind.memory += "Objective #[current_objective]: [explanation] "
+ to_chat(cult_mind.current, "Objective #[current_objective]: [explanation]")
+ cult_mind.memory += "Objective #[current_objective]: [explanation] "
message_admins("Last Cult Objective: [last_objective]")
log_admin("Last Cult Objective: [last_objective]")
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 618abec4470..0e96dd92062 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -134,7 +134,7 @@
to_chat(user, "You may only dunk carbon-based creatures!")
return 0
if(G.affecting == LAVA_PROOF)
- to_chat(user, "Is immune to the lava!")
+ to_chat(user, "[G.affecting] is immune to lava!")
return 0
if(G.affecting.stat == DEAD)
to_chat(user, "[G.affecting] is dead!")
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 9422ffcc716..823a9a8980e 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -50,7 +50,7 @@
if(iscultist(user) || user.stat == DEAD)
. += "The scriptures of [SSticker.cultdat.entity_title3]. Allows the scribing of runes and access to the knowledge archives of the cult of [SSticker.cultdat.entity_name]."
. += "Striking another cultist with it will purge holy water from them."
- . += "Striking a noncultist, however, will sear their flesh."
+ . += "Striking a non-cultist, however, will sear their flesh."
/obj/item/tome/attack(mob/living/M, mob/living/user)
if(!istype(M))
@@ -67,8 +67,8 @@
return
M.take_organ_damage(0, 15) //Used to be a random between 5 and 20
playsound(M, 'sound/weapons/sear.ogg', 50, 1)
- M.visible_message("[user] strikes [M] with the arcane tome!", \
- "[user] strikes you with the tome, searing your flesh!")
+ M.visible_message("[user] strikes [M] with [src]!", \
+ "[user] strikes you with [src], searing your flesh!")
flick("tome_attack", src)
user.do_attack_animation(M)
add_attack_logs(user, M, "Hit with [src]")
@@ -133,7 +133,7 @@
text += "Blood Boil When invoked, this rune will do a massive amount of damage to all non-cultist viewers, but it will also emit a small explosion upon invocation. \
It requires three invokers.
"
- text += "Leeching When invoked, this rune will transfer lifeforce from the victim to the invoker.
"
+ text += "Leeching When invoked, this rune will transfer life force from the victim to the invoker.
"
text += "Rite of Spectral Manifestation This rune allows you to summon spirits as humanoid fighters. When invoked, a spirit above the rune will be brought to life as a human, wearing nothing, that seeks only to serve you and [SSticker.cultdat.entity_title3]. \
However, the spirit's link to reality is fragile - you must remain on top of the rune, and you will slowly take damage. Upon stepping off the rune, all summoned spirits will dissipate, dropping their items to the ground. You may manifest \
@@ -175,7 +175,7 @@
text += "Cult Robes Cult robes are heavily armored robes. These robes are produced by the Talisman of Arming.
"
- text += "Soulstone A soulstone is a simple piece of magic, produced either via the starter talisman or by sacrificing humans. Using it on an unconscious or dead human, or on a Shade, will trap their soul in the stone, allowing its use in construct shells. \
+ text += "Soulstone A soulstone is a simple piece of magic, produced either via the starter talisman or by sacrificing humans. Using it on an unconscious or dead humanoid, or on a Shade, will trap their soul in the stone, allowing its use in construct shells. \
The soul within can also be released as a Shade by using it in-hand.
"
text += "Construct Shell A construct shell is useless on its own, but placing a filled soulstone within it allows you to produce your choice of a Wraith, a Juggernaut, or an Artificer. \
@@ -206,7 +206,7 @@
if(GAMEMODE_IS_CULT)
if(!canbypass)//not an admin-tome, check things
if(!cult_mode.narsie_condition_cleared)
- to_chat(user, "There is still more to do before unleashing [SSticker.cultdat.entity_name] power!")
+ to_chat(user, "There is still more to do before unleashing [SSticker.cultdat.entity_name]'s' power!")
return 0
if(!cult_mode.eldergod)
to_chat(user, "\"I am already here. There is no need to try to summon me now.\"")
@@ -220,14 +220,14 @@
if(!(A in GLOB.summon_spots))
to_chat(user, "[SSticker.cultdat.entity_name] can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!")
return 0
- var/confirm_final = alert(user, "This is the FINAL step to summon your deities power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for [SSticker.cultdat.entity_name]!", "No")
+ var/confirm_final = alert(user, "This is the FINAL step to summon your deity's power. It is a long, painful ritual and the crew will be alerted to your presence.", "Are you prepared for the final battle?", "My life for [SSticker.cultdat.entity_name]!", "No")
if(confirm_final == "No" || confirm_final == null)
to_chat(user, "You decide to prepare further before scribing the rune.")
return 0
else
return 1
else//the game mode is not cult..but we ARE a cultist...ALL ON THE ADMINBUS
- var/confirm_final = alert(user, "This is the FINAL step to summon your deities power, it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for [SSticker.cultdat.entity_name]!", "No")
+ var/confirm_final = alert(user, "This is the FINAL step to summon your deity's power. It is a long, painful ritual and the crew will be alerted to your presence.", "Are you prepared for the final battle?", "My life for [SSticker.cultdat.entity_name]!", "No")
if(confirm_final == "No" || confirm_final == null)
to_chat(user, "You decide to prepare further before scribing the rune.")
return 0
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index 8c83c88f3d0..02cd7b6db65 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -332,11 +332,11 @@ GLOBAL_LIST_EMPTY(teleport_runes)
user.forceMove(get_turf(actual_selected_rune))
var/mob/living/carbon/human/H = user
if(user.z != T.z)
- if(istype(H))
+ if(istype(H))
H.bleed(5)
user.apply_damage(5, BRUTE)
else
- if(istype(H))
+ if(istype(H))
H.bleed(rand(5,10))
else
fail_invoke()
@@ -498,7 +498,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
if((istype(I, /obj/item/tome) && iscultist(user)))
- user.visible_message("[user] begins erasing the [src]...", "You begin erasing the [src]...")
+ user.visible_message("[user] begins erasing [src]...", "You begin erasing [src]...")
if(do_after(user, 50, target = src)) //Prevents accidental erasures.
log_game("Summon Narsie rune erased by [key_name(user)] with a tome")
message_admins("[key_name_admin(user)] erased a Narsie rune with a tome")
@@ -534,7 +534,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
/obj/effect/rune/slaughter/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
if((istype(I, /obj/item/tome) && iscultist(user)))
- user.visible_message("[user.name] begins erasing the [src]...", "You begin erasing the [src]...")
+ user.visible_message("[user.name] begins erasing [src]...", "You begin erasing [src]...")
if(do_after(user, 50, target = src)) //Prevents accidental erasures.
log_game("Summon demon rune erased by [key_name(user)] with a tome")
message_admins("[key_name_admin(user)] erased a demon rune with a tome")
@@ -649,7 +649,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
mob_to_revive.Beam(mob_to_sacrifice,icon_state="sendbeam",time=20)
sleep(20)
if(!mob_to_sacrifice || !in_range(mob_to_sacrifice, src))
- mob_to_sacrifice.visible_message("[mob_to_sacrifice] disintegrates into a pile of bones")
+ mob_to_sacrifice.visible_message("[mob_to_sacrifice] disintegrates into a pile of bones.")
return
mob_to_sacrifice.dust()
if(!mob_to_revive || mob_to_revive.stat != DEAD)
@@ -691,7 +691,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
if(3 to 6)
playsound(E, 'sound/effects/EMPulse.ogg', 50, 1)
for(var/M in invokers)
- to_chat(M, "Your hair stands on end as a shockwave eminates from the rune!")
+ to_chat(M, "Your hair stands on end as a shockwave emanates from the rune!")
if(7 to INFINITY)
playsound(E, 'sound/effects/EMPulse.ogg', 100, 1)
for(var/M in invokers)
@@ -808,6 +808,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
allow_excess_invokers = 1
icon_state = "5"
invoke_damage = 5
+ var/summoning = FALSE
var/summontime = 0
/obj/effect/rune/summon/invoke(var/list/invokers)
@@ -819,6 +820,11 @@ GLOBAL_LIST_EMPTY(teleport_runes)
var/mob/living/cultist_to_summon = input(user, "Who do you wish to call to [src]?", "Followers of [SSticker.cultdat.entity_title3]") as null|anything in cultists
if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
return
+ if(summoning)
+ to_chat(user, "You are already summoning a target!")
+ fail_invoke()
+ return
+
if(!cultist_to_summon)
to_chat(user, "You require a summoning target!")
fail_invoke()
@@ -836,23 +842,25 @@ GLOBAL_LIST_EMPTY(teleport_runes)
return
var/hard_summon = (cultist_to_summon.reagents && cultist_to_summon.reagents.has_reagent("holywater")) || cultist_to_summon.restrained()
if(hard_summon && invokers.len < 3)
- to_chat(user, "The summoning of [cultist_to_summon] is being blocked somehow! You need 3 chanters to counter it!")
+ to_chat(user, "The summoning of [cultist_to_summon] is being blocked somehow! You need 3 invokers to counter it!")
fail_invoke()
new /obj/effect/temp_visual/cult/sparks(get_turf(cultist_to_summon)) //observer warning
log_game("Summon Cultist rune failed - holywater in target")
return
-
+ summoning = TRUE
..()
if(hard_summon)
summontime = 20
- if(do_after(user, summontime, target = loc))
+ if(do_after(user, summontime, target = src))
+ summoning = FALSE // Here incase the proc stops after the qdel
cultist_to_summon.visible_message("[cultist_to_summon] suddenly disappears in a flash of red light!", \
"Overwhelming vertigo consumes you as you are hurled through the air!")
visible_message("A foggy shape materializes atop [src] and solidifies into [cultist_to_summon]!")
cultist_to_summon.forceMove(get_turf(src))
qdel(src)
+ summoning = FALSE
//Rite of Boiling Blood: Deals extremely high amounts of damage to non-cultists nearby
/obj/effect/rune/blood_boil
@@ -982,7 +990,7 @@ GLOBAL_LIST_EMPTY(teleport_runes)
..()
playsound(src, 'sound/misc/exit_blood.ogg', 50, 1)
- visible_message("A cloud of red mist forms above [src], and from within steps... a man.")
+ visible_message("A cloud of red mist forms above [src], and from within steps... a humanoid shape.")
to_chat(user, "Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...")
var/obj/machinery/shield/N = new(get_turf(src))
N.name = "Invoker's Shield"
diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm
index e7fb06c1b94..60d2a7ff73b 100644
--- a/code/game/gamemodes/cult/talisman.dm
+++ b/code/game/gamemodes/cult/talisman.dm
@@ -61,17 +61,17 @@
/obj/item/paper/talisman/supply/invoke(mob/living/user, successfuluse = 1)
var/dat = list()
- dat += "There are [uses] bloody runes on the parchment. "
- dat += "Please choose the chant to be imbued into the fabric of reality. "
+ dat += "There are [uses] bloody runes on the parchment. "
+ dat += "Please choose the chant to be imbued into the fabric of reality. "
dat += ""
- dat += "N'ath reth sh'yro eth d'raggathnor! - Summons an arcane tome, used to scribe runes and communicate with other cultists. "
- dat += "Bar'tea eas! - Provides 5 runed metal. "
- dat += "Sas'so c'arta forbici! - Allows you to move to a selected teleportation rune. "
- dat += "Ta'gh fara'qha fel d'amar det! - Allows you to destroy technology in a short range. "
- dat += "Fuu ma'jin! - Allows you to stun a person by attacking them with the talisman. "
- dat += "Kla'atu barada nikt'o! - Two use talisman, first use makes all nearby runes invisible, second use reveals nearby hidden runes. "
- dat += "Kal'om neth! - Summons a soul stone, used to capture the spirits of dead or dying humans. "
- dat += "Daa'ig osk! - Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person. "
+ dat += "N'ath reth sh'yro eth d'raggathnor! - Summons an arcane tome, used to scribe runes and communicate with other cultists. "
+ dat += "Bar'tea eas! - Provides 5 runed metal. "
+ dat += "Sas'so c'arta forbici! - Allows you to move to a selected teleportation rune. "
+ dat += "Ta'gh fara'qha fel d'amar det! - Allows you to destroy technology in a short range. "
+ dat += "Fuu ma'jin! - Allows you to stun a person by attacking them with the talisman. "
+ dat += "Kla'atu barada nikt'o! - Two use talisman, first use makes all nearby runes invisible, second use reveals nearby hidden runes. "
+ dat += "Kal'om neth! - Summons a soul stone, used to capture the spirits of dead or dying humans. "
+ dat += "Daa'ig osk! - Summons a construct shell for use with soulstone-captured souls. It is too large to carry on your person. "
var/datum/browser/popup = new(user, "talisman", "", 400, 400)
popup.set_content(jointext(dat, ""))
popup.open()
@@ -290,7 +290,7 @@
/obj/item/paper/talisman/armor/invoke(mob/living/user, successfuluse = 1)
. = ..()
var/mob/living/carbon/human/H = user
- user.visible_message("Otherworldly armor suddenly appears on [user]!", \
+ user.visible_message("Otherworldly equipment suddenly appears on [user]!", \
"You speak the words of the talisman, arming yourself!")
H.equip_to_slot_or_del(new /obj/item/clothing/suit/hooded/cultrobes/alt(user), slot_wear_suit)
@@ -334,14 +334,14 @@
/obj/item/paper/talisman/construction/attack_self(mob/living/user)
if(iscultist(user))
- to_chat(user, "To use this talisman, place it upon a stack of metal sheets or plasteel sheets!.")
+ to_chat(user, "To use this talisman, place it upon a stack of metal sheets or plasteel sheets!")
else
to_chat(user, "You see strange symbols on the paper. Are they supposed to mean something?")
/obj/item/paper/talisman/construction/attack(obj/M,mob/living/user)
if(iscultist(user))
- to_chat(user, "This talisman will only work on a stack of metal sheets or plasteel sheets!!")
+ to_chat(user, "This talisman will only work on a stack of metal sheets or plasteel sheets!")
log_game("Construct talisman failed - not a valid target")
/obj/item/paper/talisman/construction/afterattack(obj/item/stack/sheet/target, mob/user, proximity_flag, click_parameters)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 2b604839c62..2d71df8c979 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -415,7 +415,7 @@ proc/display_roundstart_logout_report()
/proc/get_nuke_code()
var/nukecode = "ERROR"
- for(var/obj/machinery/nuclearbomb/bomb in world)
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb && bomb.r_code && is_station_level(bomb.z))
nukecode = bomb.r_code
return nukecode
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index c1a907f9191..a4b8c594b89 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -652,7 +652,8 @@
button.desc = desc
/datum/action/innate/ai/blackout/Activate()
- for(var/obj/machinery/power/apc/apc in GLOB.apcs)
+ for(var/thing in GLOB.apcs)
+ var/obj/machinery/power/apc/apc
if(prob(30 * apc.overload))
apc.overload_lighting()
else
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index c27b230b3b2..a0519fcbe56 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -25,6 +25,11 @@
var/combat_armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 50, "rad" = 50, "fire" = 90, "acid" = 90)
sprite_sheets = null
+/obj/item/clothing/suit/armor/abductor/vest/Initialize(mapload)
+ . = ..()
+ stealth_armor = getArmor(arglist(stealth_armor))
+ combat_armor = getArmor(arglist(combat_armor))
+
/obj/item/clothing/suit/armor/abductor/vest/proc/toggle_nodrop()
flags ^= NODROP
if(ismob(loc))
@@ -475,8 +480,8 @@ Congratulations! You are now trained for invasive xenobiology research!"}
H.update_inv_r_hand()
/obj/item/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
- user.lastattacked = L
- L.lastattacker = user
+ L.lastattacker = user.real_name
+ L.lastattackerckey = user.ckey
L.Stun(7)
L.Weaken(7)
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index 6e1b4a39d3a..d7354b87c5c 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -166,7 +166,6 @@
eject_abductee()
SendBack(H)
return "Specimen braindead - disposed."
- return "ERROR"
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
diff --git a/code/game/gamemodes/miniantags/borer/borer_event.dm b/code/game/gamemodes/miniantags/borer/borer_event.dm
index 245b8fa7b41..f5a3b7aa4af 100644
--- a/code/game/gamemodes/miniantags/borer/borer_event.dm
+++ b/code/game/gamemodes/miniantags/borer/borer_event.dm
@@ -16,7 +16,7 @@
/datum/event/borer_infestation/start()
var/list/vents = list()
- for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
+ for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSair.atmos_machinery)
if(is_station_level(temp_vent.loc.z) && !temp_vent.welded)
//Stops cortical borers getting stuck in small networks. See: Security, Virology
if(temp_vent.parent.other_atmosmch.len > 50)
diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
index 059eed3541c..8da5b4468d7 100644
--- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
+++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
@@ -61,6 +61,7 @@
icon = 'icons/mob/swarmer.dmi'
desc = "Robotic constructs of unknown design, swarmers seek only to consume materials and replicate themselves indefinitely."
speak_emote = list("tones")
+ bubble_icon = "swarmer"
health = 40
maxHealth = 40
status_flags = CANPUSH
@@ -362,6 +363,10 @@
to_chat(S, "This cryopod control computer should be preserved, it contains useful items and information about the inhabitants. Aborting.")
return FALSE
+/obj/structure/spacepoddoor/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
+ to_chat(S, "Disrupting this energy field would overload us. Aborting.")
+ return FALSE
+
/turf/simulated/wall/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
var/isonshuttle = istype(loc, /area/shuttle)
for(var/turf/T in range(1, src))
@@ -604,7 +609,7 @@
if(!istype(L, /mob/living/simple_animal/hostile/swarmer))
playsound(loc,'sound/effects/snap.ogg',50, 1, -1)
L.electrocute_act(0, src, 1, TRUE, TRUE)
- if(isrobot(L) || L.isSynthetic())
+ if(isrobot(L) || ismachineperson(L))
L.Weaken(5)
qdel(src)
..()
diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm
index c0e22515553..f647ae5a6d1 100644
--- a/code/game/gamemodes/miniantags/guardian/guardian.dm
+++ b/code/game/gamemodes/miniantags/guardian/guardian.dm
@@ -3,6 +3,7 @@
real_name = "Guardian Spirit"
desc = "A mysterious being that stands by it's charge, ever vigilant."
speak_emote = list("intones")
+ bubble_icon = "guardian"
response_help = "passes through"
response_disarm = "flails at"
response_harm = "punches"
@@ -180,15 +181,19 @@
input = stripped_input(src, "Please enter a message to tell your summoner.", "Guardian", "")
else
input = message
- if(!input) return
+ if(!input)
+ return
- for(var/mob/M in GLOB.mob_list)
- if(M == summoner)
- to_chat(M, "[src]: [input]")
- log_say("(GUARDIAN to [key_name(M)]) [input]", src)
- else if(M in GLOB.dead_mob_list && M.client && M.stat == DEAD && !isnewplayer(M))
- to_chat(M, "Guardian Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]")
+ // Show the message to the host and to the guardian.
+ to_chat(summoner, "[src]: [input]")
to_chat(src, "[src]: [input]")
+ log_say("(GUARDIAN to [key_name(summoner)]) [input]", src)
+ create_log(SAY_LOG, "GUARDIAN to HOST: [input]", summoner)
+
+ // Show the message to any ghosts/dead players.
+ for(var/mob/M in GLOB.dead_mob_list)
+ if(M && M.client && M.stat == DEAD && !isnewplayer(M))
+ to_chat(M, "Guardian Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]")
//override set to true if message should be passed through instead of going to host communication
/mob/living/simple_animal/hostile/guardian/say(message, override = FALSE)
@@ -206,18 +211,24 @@
set category = "Guardian"
set desc = "Communicate telepathically with your guardian."
var/input = stripped_input(src, "Please enter a message to tell your guardian.", "Message", "")
- if(!input) return
+ if(!input)
+ return
- for(var/mob/M in GLOB.mob_list)
- if(istype(M, /mob/living/simple_animal/hostile/guardian))
- var/mob/living/simple_animal/hostile/guardian/G = M
- if(G.summoner == src)
- to_chat(G, "[src]: [input]")
- log_say("(GUARDIAN to [key_name(G)]) [input]", src)
+ // Find the guardian in our host's contents.
+ var/mob/living/simple_animal/hostile/guardian/G = locate() in contents
+ if(!G)
+ return
- else if(M in GLOB.dead_mob_list && M.client && M.stat == DEAD && !isnewplayer(M))
- to_chat(M, "Guardian Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]")
+ // Show the message to our guardian and to host.
+ to_chat(G, "[src]: [input]")
to_chat(src, "[src]: [input]")
+ log_say("(GUARDIAN to [key_name(G)]) [input]", src)
+ create_log(SAY_LOG, "HOST to GUARDIAN: [input]", G)
+
+ // Show the message to any ghosts/dead players.
+ for(var/mob/M in GLOB.dead_mob_list)
+ if(M && M.client && M.stat == DEAD && !isnewplayer(M))
+ to_chat(M, "Guardian Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]")
/mob/living/proc/guardian_recall()
set name = "Recall Guardian"
diff --git a/code/game/gamemodes/miniantags/guardian/types/fire.dm b/code/game/gamemodes/miniantags/guardian/types/fire.dm
index 09a202afb91..bf8a908e979 100644
--- a/code/game/gamemodes/miniantags/guardian/types/fire.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/fire.dm
@@ -35,7 +35,7 @@
new /obj/effect/hallucination/delusion(target.loc, target, force_kind = "custom", duration = 200, skip_nearby = 0, custom_icon = icon_state, custom_icon_file = icon)
else
if(prob(45))
- if(ismovableatom(target))
+ if(ismovable(target))
var/atom/movable/M = target
if(!M.anchored && M != summoner)
new /obj/effect/temp_visual/guardian/phase/out(get_turf(M))
diff --git a/code/game/gamemodes/miniantags/guardian/types/healer.dm b/code/game/gamemodes/miniantags/guardian/types/healer.dm
index e3217e0249a..75f5fddba53 100644
--- a/code/game/gamemodes/miniantags/guardian/types/healer.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/healer.dm
@@ -130,7 +130,7 @@
if(beacon) //Check that the beacon still exists and is in a safe place. No instant kills.
if(beacon.air)
var/datum/gas_mixture/Z = beacon.air
- if(Z.oxygen >= 16 && !Z.toxins && Z.carbon_dioxide < 10 && !Z.trace_gases.len)
+ if(Z.oxygen >= 16 && !Z.toxins && Z.carbon_dioxide < 10 && !Z.sleeping_agent)
if((Z.temperature > 270) && (Z.temperature < 360))
var/pressure = Z.return_pressure()
if((pressure > 20) && (pressure < 550))
diff --git a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
index 34bf06f07f7..91ed583efc7 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
@@ -265,8 +265,8 @@
if(!istype(T, /turf/simulated/floor/plating) && !istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(15))
var/turf/simulated/floor/floor = T
- if(floor.intact)
- floor.builtin_tile.loc = floor
+ if(floor.intact && floor.floor_tile)
+ new floor.floor_tile(floor)
floor.broken = 0
floor.burnt = 0
floor.make_plating(1)
diff --git a/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm b/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
index 1f902a51806..5e5f0f87a79 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant_spawn_event.dm
@@ -26,13 +26,15 @@
var/datum/mind/player_mind = new /datum/mind(key_of_revenant)
player_mind.active = 1
var/list/spawn_locs = list()
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(isturf(L.loc))
switch(L.name)
if("revenantspawn")
spawn_locs += L.loc
if(!spawn_locs) //If we can't find any revenant spawns, try the carp spawns
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(isturf(L.loc))
switch(L.name)
if("carpspawn")
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
index e3ce78d582a..d7e53bdae28 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
@@ -45,8 +45,8 @@
var/gorecooldown = 0
var/vialspawned = FALSE
loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon)
- var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: To kill. \
- You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \
+ var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: to kill. \
+ You may Ctrl+Click on blood pools to travel through them, appearing and dissapearing from the station at will. \
Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. "
del_on_death = 1
@@ -111,8 +111,8 @@
// Cult slaughter demon
/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
- name = "harbringer of the slaughter"
- real_name = "harbringer of the Slaughter"
+ name = "harbinger of the slaughter"
+ real_name = "harbinger of the Slaughter"
desc = "An awful creature from beyond the realms of madness."
maxHealth = 500
health = 500
@@ -120,14 +120,14 @@
melee_damage_lower = 60
environment_smash = ENVIRONMENT_SMASH_RWALLS //Smashes through EVERYTHING - r-walls included
faction = list("cult")
- playstyle_string = "You are a Harbringer of the Slaughter. Brought forth by the servants of Nar-Sie, you have a single purpose: slaughter the heretics \
+ playstyle_string = "You are a Harbinger of the Slaughter. Brought forth by the servants of Nar-Sie, you have a single purpose: slaughter the heretics \
who do not worship your master. You may use the ability 'Blood Crawl' near a pool of blood to enter it and become incorporeal. Using the ability again near a blood pool will allow you \
to emerge from it. You are fast, powerful, and almost invincible. By dragging a dead or unconscious body into a blood pool with you, you will consume it after a time and fully regain \
- your health. You may use the Sense Victims in your Cultist tab to locate a random, living heretic."
+ your health. You may use the ability 'Sense Victims' in your Cultist tab to locate a random, living heretic."
/obj/effect/proc_holder/spell/targeted/sense_victims
name = "Sense Victims"
- desc = "Sense the location of heratics"
+ desc = "Sense the location of heretics"
charge_max = 0
clothes_req = 0
range = 20
@@ -171,8 +171,8 @@
var/client/C = M.client
S.key = C.key
- S.mind.assigned_role = "Harbringer of the Slaughter"
- S.mind.special_role = "Harbringer of the Slaughter"
+ S.mind.assigned_role = "Harbinger of the Slaughter"
+ S.mind.special_role = "Harbinger of the Slaughter"
to_chat(S, playstyle_string)
SSticker.mode.add_cultist(S.mind)
var/obj/effect/proc_holder/spell/targeted/sense_victims/SV = new
@@ -259,7 +259,7 @@
// Eating a 2nd heart. Gives the ability to drag people into blood and eat them.
if(HAS_TRAIT(user, TRAIT_BLOODCRAWL))
- to_chat(user, "You feel diffr- CONSUME THEM! ")
+ to_chat(user, "You feel differ- CONSUME THEM! ")
ADD_TRAIT(user, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
qdel(src) // Replacing their demon heart with another demon heart is pointless, just delete this one and return.
return TRUE
@@ -312,7 +312,7 @@
if(M.revive())
M.grab_ghost(force = TRUE)
playsound(get_turf(src), feast_sound, 50, 1, -1)
- to_chat(M, "You leave the [src]'s warm embrace, and feel ready to take on the world.")
+ to_chat(M, "You leave [src]'s warm embrace, and feel ready to take on the world.")
..(M)
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index ad1146c0bc8..5fed8ae00f4 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -95,7 +95,8 @@ proc/issyndicate(mob/living/M as mob)
var/list/turf/synd_spawn = list()
- for(var/obj/effect/landmark/A in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/A = thing
if(A.name == "Syndicate-Spawn")
synd_spawn += get_turf(A)
qdel(A)
@@ -140,7 +141,7 @@ proc/issyndicate(mob/living/M as mob)
/datum/game_mode/nuclear/proc/scale_telecrystals()
var/danger
danger = GLOB.player_list.len
- while(!IsMultiple(++danger, 10)) //Increments danger up to the nearest multiple of ten
+ while(!ISMULTIPLE(++danger, 10)) //Increments danger up to the nearest multiple of ten
total_tc += danger * NUKESCALINGMODIFIER
@@ -450,7 +451,7 @@ proc/issyndicate(mob/living/M as mob)
if(foecount == GLOB.score_arrested)
GLOB.score_allarrested = 1
- for(var/obj/machinery/nuclearbomb/nuke in world)
+ for(var/obj/machinery/nuclearbomb/nuke in GLOB.machines)
if(nuke.r_code == "Nope") continue
var/turf/T = get_turf(nuke)
var/area/A = T.loc
@@ -491,13 +492,16 @@ proc/issyndicate(mob/living/M as mob)
for(var/datum/mind/M in SSticker.mode.syndicates)
foecount++
- for(var/mob/living/C in world)
+ for(var/mob in GLOB.mob_living_list)
+ var/mob/living/C = mob
if(ishuman(C) || isAI(C) || isrobot(C))
- if(C.stat == 2) continue
- if(!C.client) continue
+ if(C.stat == DEAD)
+ continue
+ if(!C.client)
+ continue
crewcount++
- var/obj/item/disk/nuclear/N = locate() in world
+ var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list
if(istype(N))
var/atom/disk_loc = N.loc
while(!isturf(disk_loc))
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 0da5d8a3a0a..0b46264cb33 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -67,7 +67,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/assassinate/check_completion()
if(target && target.current)
- if(target.current.stat == DEAD || iszombie(target))
+ if(target.current.stat == DEAD)
return 1
if(issilicon(target.current) || isbrain(target.current)) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
return 1
@@ -111,7 +111,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
/datum/objective/maroon/check_completion()
if(target && target.current)
- if(target.current.stat == DEAD || iszombie(target))
+ if(target.current.stat == DEAD)
return 1
if(!target.current.ckey)
return 1
@@ -168,7 +168,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
if(!target) //If it's a free objective.
return 1
if(target.current)
- if(target.current.stat == DEAD || iszombie(target))
+ if(target.current.stat == DEAD)
return 0
if(issilicon(target.current))
return 0
@@ -262,7 +262,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
return 0
if(isbrain(owner.current))
return 0
- if(!owner.current || owner.current.stat == DEAD || iszombie(owner))
+ if(!owner.current || owner.current.stat == DEAD)
return 0
if(SSticker.force_ending) //This one isn't their fault, so lets just assume good faith
return 1
@@ -317,7 +317,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
explanation_text = "Die a glorious death."
/datum/objective/die/check_completion()
- if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current) || iszombie(owner))
+ if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
return 1
if(issilicon(owner.current) && owner.current != owner.original)
return 1
@@ -573,9 +573,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
// /vg/; Vox Inviolate for humans :V
/datum/objective/minimize_casualties
explanation_text = "Minimise casualties."
+
/datum/objective/minimize_casualties/check_completion()
- if(owner.kills.len>5) return 0
- return 1
+ return TRUE
+
//Vox heist objectives.
@@ -781,16 +782,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
explanation_text = "Follow the Inviolate. Minimise death and loss of resources."
/datum/objective/heist/inviolate_death/check_completion()
- var/vox_allowed_kills = 3 // The number of people the vox can accidently kill. Mostly a counter to people killing themselves if a raider touches them to force fail.
- var/vox_total_kills = 0
-
- var/datum/game_mode/heist/H = SSticker.mode
- for(var/datum/mind/raider in H.raiders)
- vox_total_kills += raider.kills.len // Kills are listed in the mind; uses this to calculate vox kills
-
- if(vox_total_kills > vox_allowed_kills) return 0
- return 1
-
+ return TRUE
// Traders
// These objectives have no check_completion, they exist only to tell Sol Traders what to aim for.
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index a38982905bc..b09bb7a851f 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -385,7 +385,7 @@
if(foecount == GLOB.score_arrested)
GLOB.score_allarrested = 1
- for(var/mob/living/carbon/human/player in world)
+ for(var/mob/living/carbon/human/player in GLOB.mob_living_list)
if(player.mind)
var/role = player.mind.assigned_role
if(role in list("Captain", "Head of Security", "Head of Personnel", "Chief Engineer", "Research Director"))
@@ -415,7 +415,7 @@
for(var/datum/mind/M in SSticker.mode:revolutionaries)
if(M.current && M.current.stat != DEAD)
revcount++
- for(var/mob/living/carbon/human/player in world)
+ for(var/mob/living/carbon/human/player in GLOB.mob_living_list)
if(player.mind)
var/role = player.mind.assigned_role
if(role in list("Captain", "Head of Security", "Head of Personnel", "Chief Engineer", "Research Director"))
@@ -425,7 +425,8 @@
if(player.mind in SSticker.mode.revolutionaries) continue
loycount++
- for(var/mob/living/silicon/X in world)
+ for(var/beepboop in GLOB.silicon_mob_list)
+ var/mob/living/silicon/X = beepboop
if(X.stat != DEAD)
loycount++
diff --git a/code/game/gamemodes/scoreboard.dm b/code/game/gamemodes/scoreboard.dm
index 069b0915c00..182bcc78bd2 100644
--- a/code/game/gamemodes/scoreboard.dm
+++ b/code/game/gamemodes/scoreboard.dm
@@ -71,7 +71,8 @@
// Check station's power levels
- for(var/obj/machinery/power/apc/A in GLOB.apcs)
+ for(var/thing in GLOB.apcs)
+ var/obj/machinery/power/apc/A = thing
if(!is_station_level(A.z)) continue
for(var/obj/item/stock_parts/cell/C in A.contents)
if(C.charge < 2300)
diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm
index 9cd91817af4..b46bc3c6c51 100644
--- a/code/game/gamemodes/shadowling/shadowling.dm
+++ b/code/game/gamemodes/shadowling/shadowling.dm
@@ -101,7 +101,7 @@ Made by Xhuis
shadowlings--
var/thrall_scaling = round(num_players() / 3)
- required_thralls = Clamp(thrall_scaling, 15, 25)
+ required_thralls = clamp(thrall_scaling, 15, 25)
thrall_ratio = required_thralls / 15
warning_threshold = round(0.66 * required_thralls)
@@ -194,8 +194,8 @@ Made by Xhuis
return 1
var/mob/living/M = thrall_mind.current
if(issilicon(M))
- M.audible_message("[M] lets out a short blip.", \
- "You have been turned into a robot! You are no longer a thrall! Though you try, you cannot remember anything about your servitude...")
+ M.audible_message("[M] lets out a short blip.")
+ to_chat(M, "You have been turned into a robot! You are no longer a thrall! Though you try, you cannot remember anything about your servitude...")
else
M.visible_message("[M] looks like [M.p_their()] mind is [M.p_their()] own again!", \
"A piercing white light floods your eyes. Your mind is your own again! Though you try, you cannot remember anything about the shadowlings or your time \
@@ -244,8 +244,8 @@ Made by Xhuis
ling_mind.RemoveSpell(S)
var/mob/living/M = ling_mind.current
if(issilicon(M))
- M.audible_message("[M] lets out a short blip.", \
- "You have been turned into a robot! You are no longer a shadowling! Though you try, you cannot remember anything about your time as one...")
+ M.audible_message("[M] lets out a short blip.")
+ to_chat(M, "You have been turned into a robot! You are no longer a shadowling! Though you try, you cannot remember anything about your time as one...")
else
M.visible_message("[M] screams and contorts!", \
"THE LIGHT-- YOUR MIND-- BURNS--")
diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm
index 2cafb1bc219..27267d2ec02 100644
--- a/code/game/gamemodes/shadowling/shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm
@@ -175,7 +175,6 @@
range = -1
include_user = 1
clothes_req = 0
- var/datum/vision_override/vision_path = /datum/vision_override/nightvision
action_icon_state = "darksight"
/obj/effect/proc_holder/spell/targeted/shadow_vision/cast(list/targets, mob/user = usr)
@@ -185,10 +184,10 @@
var/mob/living/carbon/human/H = target
if(!H.vision_type)
to_chat(H, "You shift the nerves in your eyes, allowing you to see in the dark.")
- H.vision_type = new vision_path
+ H.set_sight(/datum/vision_override/nightvision)
else
to_chat(H, "You return your vision to normal.")
- H.vision_type = null
+ H.set_sight(null)
/obj/effect/proc_holder/spell/targeted/shadow_vision/thrall
desc = "Thrall Darksight"
diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
index 7896a4aab61..5fc5e1e78cc 100644
--- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
@@ -161,7 +161,8 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
for(var/mob/living/M in orange(7, H))
M.Weaken(10)
to_chat(M, "An immense pressure slams you onto the ground!")
- for(var/obj/machinery/power/apc/A in GLOB.apcs)
+ for(var/thing in GLOB.apcs)
+ var/obj/machinery/power/apc/A = thing
A.overload_lighting()
var/mob/living/simple_animal/ascendant_shadowling/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc)
A.announce("VYSHA NERADA YEKHEZET U'RUU!!", 5, 'sound/hallucinations/veryfar_noise.ogg')
diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm
index 2c7cee9d61a..7e0f00f8721 100644
--- a/code/game/gamemodes/vampire/vampire_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers.dm
@@ -507,13 +507,13 @@
to_chat(user, "You cannot find darkness to step to.")
return
+ turfs = list(pick(turfs)) // Pick a single turf for the vampire to jump to.
perform(turfs, user = user)
+// `targets` should only ever contain the 1 valid turf we're jumping to, even though its a list, that's just how the cast() proc works.
/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr)
spawn(0)
- var/turf/picked = pick(targets)
-
- if(!picked || !isturf(picked))
+ if(!LAZYLEN(targets)) // If for some reason the turf got deleted.
return
var/mob/living/U = user
U.ExtinguishMob()
@@ -525,7 +525,7 @@
animation.alpha = 127
animation.layer = 5
//animation.master = src
- user.forceMove(picked)
+ user.forceMove(targets[1])
spawn(10)
qdel(animation)
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index 205fd63d9c6..09b228bdd0c 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -470,7 +470,7 @@ GLOBAL_LIST_EMPTY(multiverse)
M.equip_to_slot_or_del(sword, slot_r_hand)
if("cyborg")
- if(!ismachine(M))
+ if(!ismachineperson(M))
for(var/obj/item/organ/O in M.bodyparts)
O.robotize(make_tough = 1)
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses)
diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm
index 7f93fd9fef6..d5a59a36872 100644
--- a/code/game/jobs/access.dm
+++ b/code/game/jobs/access.dm
@@ -20,8 +20,6 @@
else
return check_access_list(acc)
- return 0
-
/obj/item/proc/GetAccess()
return list()
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index a30799f08b9..d5c5089c8af 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -51,6 +51,7 @@
var/disabilities_allowed = 1
var/transfer_allowed = TRUE // If false, ID computer will always discourage transfers to this job, even if player is eligible
+ var/hidden_from_job_prefs = FALSE // if true, job preferences screen never shows this job.
var/admin_only = 0
var/spawn_ert = 0
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index b6321765861..c510518716a 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -24,8 +24,8 @@
title = "Cyborg"
flag = JOB_CYBORG
department_flag = JOBCAT_ENGSEC
- total_positions = 1
- spawn_positions = 1
+ total_positions = 2
+ spawn_positions = 2
supervisors = "your laws and the AI" //Nodrak
department_head = list("AI")
selection_color = "#ddffdd"
diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm
index c56d27bb408..1d627f131b2 100644
--- a/code/game/jobs/job/supervisor.dm
+++ b/code/game/jobs/job/supervisor.dm
@@ -223,6 +223,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
id = /obj/item/card/id/nanotrasen
l_pocket = /obj/item/flash
+ r_pocket = /obj/item/clothing/accessory/lawyers_badge
pda = /obj/item/pda/heads/magistrate
backpack_contents = list(
/obj/item/melee/classic_baton/telescopic = 1
@@ -262,9 +263,12 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
glasses = /obj/item/clothing/glasses/hud/security/sunglasses/read_only
id = /obj/item/card/id/security
l_pocket = /obj/item/laser_pointer
- r_pocket = /obj/item/flash
+ r_pocket = /obj/item/clothing/accessory/lawyers_badge
l_hand = /obj/item/storage/briefcase
pda = /obj/item/pda/lawyer
+ backpack_contents = list(
+ /obj/item/flash = 1
+ )
implants = list(/obj/item/implant/mindshield)
satchel = /obj/item/storage/backpack/satchel_sec
dufflebag = /obj/item/storage/backpack/duffel/security
diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm
index d0064300b62..09328865b59 100644
--- a/code/game/jobs/job/support.dm
+++ b/code/game/jobs/job/support.dm
@@ -282,14 +282,14 @@
if(visualsOnly)
return
- if(ismachine(H))
+ if(ismachineperson(H))
var/obj/item/organ/internal/cyberimp/brain/clown_voice/implant = new
implant.insert(H)
H.dna.SetSEState(GLOB.clumsyblock, TRUE)
genemutcheck(H, GLOB.clumsyblock, null, MUTCHK_FORCED)
H.dna.default_blocks.Add(GLOB.clumsyblock)
- if(!ismachine(H))
+ if(!ismachineperson(H))
H.dna.SetSEState(GLOB.comicblock, TRUE)
genemutcheck(H, GLOB.comicblock, null, MUTCHK_FORCED)
H.dna.default_blocks.Add(GLOB.comicblock)
@@ -450,3 +450,24 @@
/obj/item/storage/box/lip_stick = 1,
/obj/item/storage/box/barber = 1
)
+
+/datum/job/explorer
+ title = "Explorer"
+ flag = JOB_EXPLORER
+ department_flag = JOBCAT_SUPPORT
+ total_positions = 0
+ spawn_positions = 0
+ supervisors = "the head of personnel"
+ selection_color = "#dddddd"
+ access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS)
+ minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS)
+ outfit = /datum/outfit/job/explorer
+ hidden_from_job_prefs = TRUE
+
+/datum/outfit/job/explorer
+ // This outfit is never used, because there are no slots for this job.
+ // To get it, you have to go to the HOP and ask for a transfer to it.
+ name = "Explorer"
+ jobtype = /datum/job/explorer
+ uniform = /obj/item/clothing/under/color/random
+ shoes = /obj/item/clothing/shoes/black
diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm
index 8ff6b58e5c4..81cc54aa3c3 100644
--- a/code/game/jobs/jobs.dm
+++ b/code/game/jobs/jobs.dm
@@ -58,7 +58,8 @@ GLOBAL_LIST_INIT(support_positions, list(
"Barber",
"Magistrate",
"Nanotrasen Representative",
- "Blueshield"
+ "Blueshield",
+ "Explorer"
))
GLOBAL_LIST_INIT(supply_positions, list(
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index 7317099b8dc..3bcb9675c50 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -136,7 +136,7 @@
/obj/machinery/optable/wrench_act(mob/user, obj/item/I)
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
if(I.use_tool(src, user, 20, volume = I.tool_volume))
to_chat(user, "You deconstruct the table.")
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 70d88e92b71..e4d0befa61e 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -526,7 +526,7 @@
if(panel_open)
to_chat(usr, "Close the maintenance panel first.")
return
- if(usr.incapacitated()) //are you cuffed, dying, lying, stunned or other
+ if(usr.incapacitated() || usr.buckled) //are you cuffed, dying, lying, stunned or other
return
if(usr.has_buckled_mobs()) //mob attached to us
to_chat(usr, "[usr] will not fit into [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 02d95278e30..9fda2cfe45c 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -199,8 +199,8 @@
mode = AALARM_MODE_REPLACEMENT
apply_mode()
-/obj/machinery/alarm/New(var/loc, var/dir, var/building = 0)
- ..()
+/obj/machinery/alarm/New(loc, direction, building = 0)
+ . = ..()
GLOB.air_alarms += src
GLOB.air_alarms = sortAtom(GLOB.air_alarms)
@@ -211,12 +211,11 @@
src.loc = loc
if(dir)
- src.dir = dir
+ setDir(direction)
buildstage = 0
wiresexposed = 1
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
- pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
+ set_pixel_offsets_from_dir(-24, 24, -24, 24)
update_icon()
return
@@ -251,7 +250,7 @@
/obj/machinery/alarm/proc/master_is_operating()
if(!alarm_area)
- alarm_area = areaMaster
+ alarm_area = get_area(src)
if(!alarm_area)
log_runtime(EXCEPTION("Air alarm /obj/machinery/alarm lacks alarm_area and areaMaster vars during proc/master_is_operating()"), src)
return FALSE
@@ -299,10 +298,7 @@
var/plasma_dangerlevel = cur_tlv.get_danger_level(environment.toxins*GET_PP)
cur_tlv = TLV["other"]
- var/other_moles = 0.0
- for(var/datum/gas/G in environment.trace_gases)
- other_moles+=G.moles
- var/other_dangerlevel = cur_tlv.get_danger_level(other_moles*GET_PP)
+ var/other_dangerlevel = cur_tlv.get_danger_level(environment.total_trace_moles() * GET_PP)
cur_tlv = TLV["temperature"]
var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
@@ -326,16 +322,18 @@
apply_mode()
-/obj/machinery/alarm/proc/handle_heating_cooling(var/datum/gas_mixture/environment, var/datum/tlv/cur_tlv, var/turf/simulated/location)
+/obj/machinery/alarm/proc/handle_heating_cooling(datum/gas_mixture/environment, datum/tlv/cur_tlv, turf/simulated/location)
cur_tlv = TLV["temperature"]
//Handle temperature adjustment here.
if(environment.temperature < target_temperature - 2 || environment.temperature > target_temperature + 2 || regulating_temperature)
//If it goes too far, we should adjust ourselves back before stopping.
if(!cur_tlv.get_danger_level(target_temperature))
+ var/datum/gas_mixture/gas = location.remove_air(0.25 * environment.total_moles())
+ if(!gas)
+ return
if(!regulating_temperature)
regulating_temperature = 1
- visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\
- "You hear a click and a faint electronic hum.")
+ visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click and a faint electronic hum.")
if(target_temperature > MAX_TEMPERATURE)
target_temperature = MAX_TEMPERATURE
@@ -343,9 +341,8 @@
if(target_temperature < MIN_TEMPERATURE)
target_temperature = MIN_TEMPERATURE
- var/datum/gas_mixture/gas = location.remove_air(0.25*environment.total_moles())
var/heat_capacity = gas.heat_capacity()
- var/energy_used = max( abs( heat_capacity*(gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
+ var/energy_used = max(abs(heat_capacity * (gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
//Use power. Assuming that each power unit represents 1000 watts....
use_power(energy_used/1000, ENVIRON)
@@ -353,16 +350,15 @@
//We need to cool ourselves.
if(heat_capacity)
if(environment.temperature > target_temperature)
- gas.temperature -= energy_used/heat_capacity
+ gas.temperature -= energy_used / heat_capacity
else
- gas.temperature += energy_used/heat_capacity
+ gas.temperature += energy_used / heat_capacity
environment.merge(gas)
if(abs(environment.temperature - target_temperature) <= 0.5)
regulating_temperature = 0
- visible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\
- "You hear a click as a faint electronic humming stops.")
+ visible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click as a faint electronic humming stops.")
/obj/machinery/alarm/update_icon()
if(wiresexposed)
@@ -625,10 +621,8 @@
var/plasma_percent = round(environment.toxins / total * 100, 2)
cur_tlv = TLV["other"]
- var/other_moles = 0.0
- for(var/datum/gas/G in environment.trace_gases)
- other_moles+=G.moles
- var/other_dangerlevel = cur_tlv.get_danger_level(other_moles*GET_PP)
+ var/other_moles = environment.total_trace_moles()
+ var/other_dangerlevel = cur_tlv.get_danger_level(other_moles * GET_PP)
cur_tlv = TLV["temperature"]
var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
@@ -996,7 +990,7 @@
if(buildstage != AIR_ALARM_BUILDING)
return
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
to_chat(user, "You start prying out the circuit.")
if(!I.use_tool(src, user, 20, volume = I.tool_volume))
diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm
index 3d53e130628..d7650d1cb68 100644
--- a/code/game/machinery/atmoalter/area_atmos_computer.dm
+++ b/code/game/machinery/atmoalter/area_atmos_computer.dm
@@ -164,7 +164,7 @@
var/turf/T = get_turf(src)
if(!T.loc) return
var/area/A = get_area(T)
- for(var/obj/machinery/portable_atmospherics/scrubber/huge/scrubber in world )
+ for(var/obj/machinery/portable_atmospherics/scrubber/huge/scrubber in SSair.atmos_machinery)
var/turf/T2 = get_turf(scrubber)
if(T2 && T2.loc)
var/area/A2 = T2.loc
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index d91fba5fa5c..e927415c759 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -417,8 +417,7 @@ update_flag
if(air_contents.toxins > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (JMP)")
log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
- var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air_contents.trace_gases
- if(sleeping_agent && (sleeping_agent.moles > 1))
+ if(air_contents.sleeping_agent > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains N2O in [get_area(src)]! (JMP)")
log_admin("[key_name(usr)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
investigate_log(logmsg, "atmos")
@@ -533,29 +532,11 @@ update_flag
..()
canister_color["prim"] = "redws"
- var/datum/gas/sleeping_agent/trace_gas = new
- air_contents.trace_gases += trace_gas
- trace_gas.moles = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.sleeping_agent = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
return 1
-
-//Dirty way to fill room with gas. However it is a bit easier to do than creating some floor/engine/n2o -rastaf0
-/obj/machinery/portable_atmospherics/canister/sleeping_agent/roomfiller/New()
- ..()
- var/datum/gas/sleeping_agent/trace_gas = air_contents.trace_gases[1]
- trace_gas.moles = 9*4000
- spawn(100)
- var/turf/simulated/location = src.loc
- if(istype(src.loc))
- while(!location.air)
- sleep(1000)
- location.assume_air(air_contents)
- air_contents = new
- return 1
-
-
/obj/machinery/portable_atmospherics/canister/nitrogen/New()
..()
diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm
index 0144a7f93c2..4d54b162466 100644
--- a/code/game/machinery/atmoalter/pump.dm
+++ b/code/game/machinery/atmoalter/pump.dm
@@ -167,7 +167,7 @@
if(href_list["pressure_adj"])
var/diff = text2num(href_list["pressure_adj"])
- target_pressure = Clamp(target_pressure+diff, pressuremin, pressuremax)
+ target_pressure = clamp(target_pressure+diff, pressuremin, pressuremax)
update_icon()
src.add_fingerprint(usr)
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 36e340d1a12..7af7751ff2c 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -81,17 +81,11 @@
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
- if(removed.trace_gases.len>0)
- for(var/datum/gas/trace_gas in removed.trace_gases)
- if(istype(trace_gas, /datum/gas/sleeping_agent))
- removed.trace_gases -= trace_gas
- filtered_out.trace_gases += trace_gas
+ filtered_out.sleeping_agent = removed.sleeping_agent
+ removed.sleeping_agent = 0
- if(removed.trace_gases.len>0)
- for(var/datum/gas/trace_gas in removed.trace_gases)
- if(istype(trace_gas, /datum/gas/oxygen_agent_b))
- removed.trace_gases -= trace_gas
- filtered_out.trace_gases += trace_gas
+ filtered_out.agent_b = removed.agent_b
+ removed.agent_b = 0
//Remix the resulting gases
air_contents.merge(filtered_out)
@@ -158,7 +152,7 @@
if(href_list["volume_adj"])
var/diff = text2num(href_list["volume_adj"])
- volume_rate = Clamp(volume_rate+diff, minrate, maxrate)
+ volume_rate = clamp(volume_rate+diff, minrate, maxrate)
src.add_fingerprint(usr)
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 78367327a0c..c22922e4d14 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -38,7 +38,7 @@
var/list/categories = list("Tools", "Electronics", "Construction", "Communication", "Security", "Machinery", "Medical", "Miscellaneous", "Dinnerware", "Imported")
/obj/machinery/autolathe/New()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS), 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS), _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
..()
component_parts = list()
component_parts += new /obj/item/circuitboard/autolathe(null)
@@ -66,7 +66,7 @@
/obj/machinery/autolathe/Destroy()
QDEL_NULL(wires)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -87,7 +87,7 @@
ui.open()
/obj/machinery/autolathe/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/data[0]
data["screen"] = screen
data["total_amount"] = materials.total_amount
@@ -138,7 +138,7 @@
/obj/machinery/autolathe/proc/design_cost_data(datum/design/D)
var/list/data = list()
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/has_metal = 1
if(D.materials[MAT_METAL] && (materials.amount(MAT_METAL) < (D.materials[MAT_METAL] / coeff)))
has_metal = 0
@@ -152,7 +152,7 @@
return data
/obj/machinery/autolathe/proc/queue_data(list/data)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/temp_metal = materials.amount(MAT_METAL)
var/temp_glass = materials.amount(MAT_GLASS)
data["processing"] = being_built.len ? get_processing_line() : null
@@ -288,7 +288,7 @@
//multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier
var/multiplier = text2num(href_list["multiplier"])
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY)
var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack)
@@ -309,13 +309,13 @@
if(href_list["remove_from_queue"])
var/index = text2num(href_list["remove_from_queue"])
- if(isnum(index) && IsInRange(index, 1, queue.len))
+ if(isnum(index) && ISINRANGE(index, 1, queue.len))
remove_from_queue(index)
if(href_list["queue_move"] && href_list["index"])
var/index = text2num(href_list["index"])
var/new_index = index + text2num(href_list["queue_move"])
if(isnum(index) && isnum(new_index))
- if(IsInRange(new_index, 1, queue.len))
+ if(ISINRANGE(new_index, 1, queue.len))
queue.Swap(index,new_index)
if(href_list["clear_queue"])
queue = list()
@@ -342,7 +342,7 @@
for(var/obj/item/stock_parts/matter_bin/MB in component_parts)
tot_rating += MB.rating
tot_rating *= 25000
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = tot_rating * 3
for(var/obj/item/stock_parts/manipulator/M in component_parts)
prod_coeff += M.rating - 1
@@ -355,7 +355,7 @@
desc = initial(desc)+"\nIt's building \a [initial(D.name)]."
var/is_stack = ispath(D.build_path, /obj/item/stack)
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/metal_cost = D.materials[MAT_METAL]
var/glass_cost = D.materials[MAT_GLASS]
var/power = max(2000, (metal_cost+glass_cost)*multiplier/5)
@@ -387,7 +387,7 @@
return 0
var/coeff = get_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/metal_amount = materials.amount(MAT_METAL)
if(custom_metal)
metal_amount = custom_metal
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index 796d5c552dd..5ec4206734c 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -189,12 +189,12 @@
active = 1
icon_state = "launcheract"
- for(var/obj/machinery/sparker/M in world)
+ for(var/obj/machinery/sparker/M in GLOB.machines)
if(M.id == id)
spawn( 0 )
M.spark()
- for(var/obj/machinery/igniter/M in world)
+ for(var/obj/machinery/igniter/M in GLOB.machines)
if(M.id == id)
use_power(50)
M.on = !( M.on )
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 24ffb494422..b66cad8d328 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -360,15 +360,12 @@
for(var/obj/machinery/camera/C in oview(4, M))
if(C.can_use()) // check if camera disabled
return C
- break
return null
/proc/near_range_camera(mob/M)
for(var/obj/machinery/camera/C in range(4, M))
if(C.can_use()) // check if camera disabled
return C
- break
-
return null
/obj/machinery/camera/proc/Togglelight(on = FALSE)
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index c0949fb3c9d..b7ae75cd13f 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -41,7 +41,7 @@
number = 1
var/area/A = get_area(src)
if(A)
- for(var/obj/machinery/camera/autoname/C in world)
+ for(var/obj/machinery/camera/autoname/C in GLOB.machines)
if(C == src) continue
var/area/CA = get_area(C)
if(CA.type == A.type)
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index adc4175a45d..b502d6e5441 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -45,7 +45,6 @@
var/list/req_components = null
var/powernet = null
var/list/records = null
- var/frame_desc = null
var/contain_parts = 1
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
@@ -64,7 +63,7 @@
var/atom/A = B
if(!ispath(A))
continue
- nice_list += list("[req_components[A]] [initial(A.name)]")
+ nice_list += list("[req_components[A]] [initial(A.name)]\s")
. += "Required components: [english_list(nice_list)]."
/obj/item/circuitboard/message_monitor
@@ -351,9 +350,6 @@
build_path = /obj/machinery/computer/telescience
origin_tech = "programming=3;bluespace=3;plasmatech=4"
-/obj/item/circuitboard/atmos_automation
- name = "Circuit board (Atmospherics Automation)"
- build_path = /obj/machinery/computer/general_air_control/atmos_automation
/obj/item/circuitboard/large_tank_control
name = "Circuit board (Atmospheric Tank Control)"
build_path = /obj/machinery/computer/general_air_control/large_tank_control
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index 40005f8fd12..978ba25b8d3 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -25,7 +25,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
/datum/job/ntnavyofficer,
/datum/job/ntspecops,
/datum/job/civilian,
- /datum/job/syndicateofficer
+ /datum/job/syndicateofficer,
+ /datum/job/explorer // blacklisted so that HOPs don't try prioritizing it, then wonder why that doesn't work
)
// Jobs that appear in the list, and you can prioritize, but not open/close slots for
var/list/blacklisted_partial = list(
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index aec41c80be3..2ec8611f420 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -135,7 +135,7 @@
/obj/machinery/computer/screwdriver_act(mob/user, obj/item/I)
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
if(circuit && !(flags & NODECONSTRUCT))
if(I.use_tool(src, user, 20, volume = I.tool_volume))
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index a832e2b5d16..131956ca3c1 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -8,7 +8,7 @@
active_power_usage = 500
light_color = LIGHT_COLOR_DARKBLUE
circuit = /obj/item/circuitboard/crew
- var/datum/nano_module/crew_monitor/crew_monitor
+ var/datum/tgui_module/crew_monitor/crew_monitor
/obj/machinery/computer/crew/New()
crew_monitor = new(src)
@@ -20,17 +20,15 @@
/obj/machinery/computer/crew/attack_ai(mob/user)
attack_hand(user)
- ui_interact(user)
-
/obj/machinery/computer/crew/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- crew_monitor.ui_interact(user, ui_key, ui, force_open)
+/obj/machinery/computer/crew/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ crew_monitor.tgui_interact(user, ui_key, ui, force_open)
/obj/machinery/computer/crew/interact(mob/user)
- crew_monitor.ui_interact(user)
+ crew_monitor.tgui_interact(user)
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index 9464c43b107..3674358f07f 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -121,7 +121,7 @@
data["virus"] += list(list("name" = DS.name, "D" = D))
if(MED_DATA_MEDBOT)
data["medbots"] = list()
- for(var/mob/living/simple_animal/bot/medbot/M in world)
+ for(var/mob/living/simple_animal/bot/medbot/M in GLOB.bots_list)
if(M.z != z)
continue
var/turf/T = get_turf(M)
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index 6ea095028a2..bafcd2d8ca2 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -23,7 +23,7 @@
timings = list()
times = list()
synced = list()
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
for(var/ident_tag in id_tags)
if((M.id_tag == ident_tag) && !(ident_tag in synced))
@@ -49,7 +49,7 @@
return
/obj/machinery/computer/pod/proc/solo_sync(var/ident_tag)
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
if((M.id_tag == ident_tag) && !(ident_tag in synced))
synced += ident_tag
@@ -78,7 +78,7 @@
if(stat & (NOPOWER|BROKEN))
return
var/anydriver = 0
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
if(M.id_tag == ident_tag)
anydriver = 1
@@ -94,7 +94,7 @@
sleep(20)
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
if(M.id_tag == ident_tag)
M.drive()
@@ -219,7 +219,7 @@
var/ident_tag = href_list["driver"]
var/t = text2num(href_list["power"])
t = min(max(0.25, t), 16)
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.id_tag == ident_tag)
M.power = t
powers[ident_tag] = t
@@ -294,7 +294,7 @@
if(stat & (NOPOWER|BROKEN))
return
var/anydriver = 0
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
if(M.id_tag == ident_tag)
anydriver = 1
@@ -303,10 +303,12 @@
return
var/spawn_marauder[] = new()
- for(var/obj/effect/landmark/L in world)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "Marauder Entry")
spawn_marauder.Add(L)
- for(var/obj/effect/landmark/L in world)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "Marauder Exit")
var/obj/effect/portal/P = new(L.loc, pick(spawn_marauder))
P.invisibility = 101//So it is not seen by anyone.
@@ -320,7 +322,7 @@
M.open()
sleep(20)
- for(var/obj/machinery/mass_driver/M in world)
+ for(var/obj/machinery/mass_driver/M in GLOB.machines)
if(M.z != src.z) continue
if(M.id_tag == ident_tag)
M.drive()
diff --git a/code/game/machinery/computer/specops_shuttle.dm b/code/game/machinery/computer/specops_shuttle.dm
index f509ee42d34..2ba3b25b6f6 100644
--- a/code/game/machinery/computer/specops_shuttle.dm
+++ b/code/game/machinery/computer/specops_shuttle.dm
@@ -93,7 +93,7 @@ GLOBAL_VAR_INIT(specops_shuttle_timeleft, 0)
GLOB.specops_shuttle_at_station = 0
- for(var/obj/machinery/computer/specops_shuttle/S in world)
+ for(var/obj/machinery/computer/specops_shuttle/S in GLOB.machines)
S.specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY
qdel(announcer)
@@ -160,10 +160,12 @@ GLOBAL_VAR_INIT(specops_shuttle_timeleft, 0)
sleep(10)
var/spawn_marauder[] = new()
- for(var/obj/effect/landmark/L in world)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "Marauder Entry")
spawn_marauder.Add(L.loc)
- for(var/obj/effect/landmark/L in world)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "Marauder Exit")
var/obj/effect/portal/P = new(L.loc, pick(spawn_marauder))
//P.invisibility = 101//So it is not seen by anyone.
@@ -233,7 +235,7 @@ GLOBAL_VAR_INIT(specops_shuttle_timeleft, 0)
var/mob/M = locate(/mob) in T
to_chat(M, "You have arrived to [station_name()]. Commence operation!")
- for(var/obj/machinery/computer/specops_shuttle/S in world)
+ for(var/obj/machinery/computer/specops_shuttle/S in GLOB.machines)
S.specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY
qdel(announcer)
@@ -241,7 +243,7 @@ GLOBAL_VAR_INIT(specops_shuttle_timeleft, 0)
/proc/specops_can_move()
if(GLOB.specops_shuttle_moving_to_station || GLOB.specops_shuttle_moving_to_centcom)
return 0
- for(var/obj/machinery/computer/specops_shuttle/S in world)
+ for(var/obj/machinery/computer/specops_shuttle/S in GLOB.machines)
if(world.timeofday <= S.specops_shuttle_timereset)
return 0
return 1
diff --git a/code/game/machinery/computer/syndicate_specops_shuttle.dm b/code/game/machinery/computer/syndicate_specops_shuttle.dm
index 0a65b6be408..7ec7bd7a026 100644
--- a/code/game/machinery/computer/syndicate_specops_shuttle.dm
+++ b/code/game/machinery/computer/syndicate_specops_shuttle.dm
@@ -23,7 +23,7 @@ GLOBAL_VAR_INIT(syndicate_elite_shuttle_timeleft, 0)
/proc/syndicate_elite_process()
var/area/syndicate_mothership/control/syndicate_ship = locate()//To find announcer. This area should exist for this proc to work.
- var/area/syndicate_mothership/elite_squad/elite_squad = locate()//Where is the specops area located?
+ //var/area/syndicate_mothership/elite_squad/elite_squad = locate()//Where is the specops area located?
var/mob/living/silicon/decoy/announcer = locate() in syndicate_ship//We need a fake AI to announce some stuff below. Otherwise it will be wonky.
var/message_tracker[] = list(0,1,2,3,5,10,30,45)//Create a a list with potential time values.
@@ -63,7 +63,6 @@ GLOBAL_VAR_INIT(syndicate_elite_shuttle_timeleft, 0)
to_chat(usr, "The Syndicate Elite shuttle is unable to leave.")
return
- sleep(600)
/*
//Begin Marauder launchpad.
spawn(0)//So it parallel processes it.
@@ -129,11 +128,12 @@ GLOBAL_VAR_INIT(syndicate_elite_shuttle_timeleft, 0)
if("ASSAULT3")
spawn(0)
M.close()
- */
elite_squad.readyreset()//Reset firealarm after the team launched.
+ */
//End Marauder launchpad.
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ for(var/thing in GLOB.landmarks_list)
+ var/obj/effect/landmark/L = thing
if(L.name == "Syndicate Breach Area")
explosion(L.loc,4,6,8,10,0)
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 92db2f4a419..ee29504fe99 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -218,7 +218,7 @@
//Machine Frame Circuit Boards
/*Common Parts: Parts List: Ignitor, Timer, Infra-red laser, Infra-red sensor, t_scanner, Capacitor, Valve, sensor unit,
-micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
+micro-manipulator, glass sheets, beaker, Microlaser, matter bin, power cells.
Note: Once everything is added to the public areas, will add MAT_METAL and MAT_GLASS to circuit boards since autolathe won't be able
to destroy them and players will be able to make replacements.
*/
@@ -226,7 +226,6 @@ to destroy them and players will be able to make replacements.
name = "circuit board (Booze-O-Mat Vendor)"
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 1 Resupply Canister."
build_path = /obj/machinery/vending/boozeomat
req_components = list(/obj/item/vending_refill/boozeomat = 1)
@@ -282,7 +281,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/power/smes
board_type = "machine"
origin_tech = "programming=3;powerstorage=3;engineering=3"
- frame_desc = "Requires 5 pieces of cable, 5 Power Cells and 1 Capacitor."
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/cell = 5,
@@ -321,7 +319,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/atmospherics/unary/cold_sink/freezer
board_type = "machine"
origin_tech = "programming=3;plasmatech=3"
- frame_desc = "Requires 2 Matter Bins, 2 Micro Lasers, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/micro_laser = 2,
@@ -346,7 +343,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/recharger
board_type = "machine"
origin_tech = "powerstorage=3;materials=2"
- frame_desc = "Requires 1 Capacitor"
req_components = list(/obj/item/stock_parts/capacitor = 1)
/obj/item/circuitboard/snow_machine
@@ -354,7 +350,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/snow_machine
board_type = "machine"
origin_tech = "programming=2;materials=2"
- frame_desc = "Requires 1 Matter Bin and 1 Micro Laser."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/micro_laser = 1)
@@ -364,7 +359,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/biogenerator
board_type = "machine"
origin_tech = "programming=2;biotech=3;materials=3"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -376,7 +370,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/plantgenes
board_type = "machine"
origin_tech = "programming=3;biotech=3"
- frame_desc = "Requires 1 Manipulator, 1 Micro Laser, 1 Console Screen, and 1 Scanning Module."
req_components = list(
/obj/item/stock_parts/manipulator = 1,
/obj/item/stock_parts/micro_laser = 1,
@@ -390,7 +383,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/seed_extractor
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 1 Matter Bin and 1 Manipulator."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1)
@@ -400,7 +392,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/hydroponics/constructable
board_type = "machine"
origin_tech = "programming=1;biotech=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulator, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -411,7 +402,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/microwave
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 1 Micro Laser, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/cable_coil = 2,
@@ -422,7 +412,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/oven
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 2 Micro Lasers, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5,
@@ -433,7 +422,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/grill
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 2 Micro Lasers, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5,
@@ -444,7 +432,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/kitchen_machine/candy_maker
board_type = "machine"
origin_tech = "programming=2;magnets=2"
- frame_desc = "Requires 1 Manipulator, 5 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/manipulator = 1,
/obj/item/stack/cable_coil = 5,
@@ -455,7 +442,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/cooker/deepfryer
board_type = "machine"
origin_tech = "programming=1"
- frame_desc = "Requires 2 Micro Lasers and 5 pieces of cable."
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stack/cable_coil = 5)
@@ -568,7 +554,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/chem_dispenser
board_type = "machine"
origin_tech = "materials=4;programming=4;plasmatech=4;biotech=3"
- frame_desc = "Requires 2 Matter Bins, 1 Capacitor, 1 Manipulator, 1 Console Screen, and 1 Power Cell."
req_components = list( /obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/capacitor = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -609,7 +594,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/chem_heater
board_type = "machine"
origin_tech = "programming=2;engineering=2;biotech=2"
- frame_desc = "Requires 1 Micro Laser and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/sheet/glass = 1)
@@ -619,7 +603,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/reagentgrinder/empty
board_type = "machine"
origin_tech = "materials=2;engineering=2;biotech=2"
- frame_desc = "Requires 2 Manipulators and 1 Matter Bin."
req_components = list(
/obj/item/stock_parts/manipulator = 2,
/obj/item/stock_parts/matter_bin = 1)
@@ -640,7 +623,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/destructive_analyzer
board_type = "machine"
origin_tech = "magnets=2;engineering=2;programming=2"
- frame_desc = "Requires 1 Scanning Module, 1 Manipulator, and 1 Micro-Laser."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -651,7 +633,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/autolathe
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 3 Matter Bins, 1 Manipulator, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 3,
/obj/item/stock_parts/manipulator = 1,
@@ -662,7 +643,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/protolathe
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 2 Matter Bins, 2 Manipulators, and 2 Beakers."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 2,
@@ -681,7 +661,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/circuit_imprinter
board_type = "machine"
origin_tech = "engineering=2;programming=2"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, and 2 Beakers."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -692,7 +671,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/power/port_gen/pacman
board_type = "machine"
origin_tech = "programming=2;powerstorage=3;plasmatech=3;engineering=3"
- frame_desc = "Requires 1 Matter Bin, 1 Micro-Laser, 2 Pieces of Cable, and 1 Capacitor."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/micro_laser = 1,
@@ -714,7 +692,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/r_n_d/server
board_type = "machine"
origin_tech = "programming=3"
- frame_desc = "Requires 2 pieces of cable, and 1 Scanning Module."
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/scanning_module = 1)
@@ -724,7 +701,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mecha_part_fabricator
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulator, 1 Micro-Laser and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -736,7 +712,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mecha_part_fabricator/spacepod
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Matter Bins, 1 Manipulators, 1 Micro-Lasers, and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/matter_bin = 2,
/obj/item/stock_parts/manipulator = 1,
@@ -749,7 +724,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/clonepod
board_type = "machine"
origin_tech = "programming=2;biotech=2"
- frame_desc = "Requires 2 Manipulator, 2 Scanning Module, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/stock_parts/scanning_module = 2,
@@ -761,7 +735,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/dna_scannernew
board_type = "machine"
origin_tech = "programming=2;biotech=2"
- frame_desc = "Requires 1 Scanning Module, 1 Manipulator, 1 Micro-Laser, 2 pieces of cable and 1 Console Screen."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -774,7 +747,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/mech_bay_recharge_port
board_type = "machine"
origin_tech = "programming=3;powerstorage=3;engineering=3"
- frame_desc = "Requires 1 piece of cable and 5 Capacitors."
req_components = list(
/obj/item/stack/cable_coil = 1,
/obj/item/stock_parts/capacitor = 5)
@@ -784,7 +756,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/hub
board_type = "machine"
origin_tech = "programming=3;engineering=4;bluespace=4;materials=4"
- frame_desc = "Requires 3 Bluespace Crystals and 1 Matter Bin."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 3,
/obj/item/stock_parts/matter_bin = 1)
@@ -794,7 +765,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/station
board_type = "machine"
origin_tech = "programming=4;engineering=4;bluespace=4;plasmatech=3"
- frame_desc = "Requires 2 Bluespace Crystals, 2 Capacitors and 1 Console Screen."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 2,
/obj/item/stock_parts/capacitor = 2,
@@ -805,7 +775,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/teleport/perma
board_type = "machine"
origin_tech = "programming=3;engineering=4;bluespace=4;materials=4"
- frame_desc = "Requires 3 Bluespace Crystals and 1 Matter Bin."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 3,
/obj/item/stock_parts/matter_bin = 1)
@@ -825,7 +794,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/telepad
board_type = "machine"
origin_tech = "programming=4;engineering=3;plasmatech=4;bluespace=4"
- frame_desc = "Requires 2 Bluespace Crystals, 1 Capacitor, 1 piece of cable and 1 Console Screen."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 2,
/obj/item/stock_parts/capacitor = 1,
@@ -837,7 +805,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/quantumpad
board_type = "machine"
origin_tech = "programming=3;engineering=3;plasmatech=3;bluespace=4"
- frame_desc = "Requires 1 Bluespace Crystal, 1 Capacitor, 1 piece of cable and 1 Manipulator."
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 1,
/obj/item/stock_parts/capacitor = 1,
@@ -849,7 +816,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/sleeper
board_type = "machine"
origin_tech = "programming=3;biotech=2;engineering=3"
- frame_desc = "Requires 1 Matter Bin, 1 Manipulator, 1 piece of cable and 2 Console Screens."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/manipulator = 1,
@@ -870,7 +836,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/bodyscanner
board_type = "machine"
origin_tech = "programming=3;biotech=2;engineering=3"
- frame_desc = "Requires 1 Scanning Module, 2 pieces of cable and 2 Console Screens."
req_components = list(
/obj/item/stock_parts/scanning_module = 1,
/obj/item/stack/cable_coil = 2,
@@ -881,7 +846,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/atmospherics/unary/cryo_cell
board_type = "machine"
origin_tech = "programming=4;biotech=3;engineering=4;plasmatech=3"
- frame_desc = "Requires 1 Matter Bin, 1 piece of cable and 4 Console Screens."
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stack/cable_coil = 1,
@@ -892,7 +856,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/recharge_station
board_type = "machine"
origin_tech = "powerstorage=3;engineering=3"
- frame_desc = "Requires 2 Capacitors, 1 Power Cell and 1 Manipulator."
req_components = list(
/obj/item/stock_parts/capacitor = 2,
/obj/item/stock_parts/cell = 1,
@@ -904,7 +867,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/tcomms/relay
board_type = "machine"
origin_tech = "programming=2;engineering=2;bluespace=2"
- frame_desc = "Requires 2 Manipulators and 2 Cable Coil."
req_components = list(/obj/item/stock_parts/manipulator = 2, /obj/item/stack/cable_coil = 2)
/obj/item/circuitboard/tcomms/core
@@ -912,7 +874,6 @@ to destroy them and players will be able to make replacements.
build_path = /obj/machinery/tcomms/core
board_type = "machine"
origin_tech = "programming=2;engineering=2"
- frame_desc = "Requires 2 Manipulators and 2 Cable Coil."
req_components = list(/obj/item/stock_parts/manipulator = 2, /obj/item/stack/cable_coil = 2)
// End telecomms circuit boards
/obj/item/circuitboard/ore_redemption
@@ -975,50 +936,3 @@ to destroy them and players will be able to make replacements.
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stack/cable_coil = 3,
/obj/item/stack/sheet/glass = 1)
-
-//Selectable mode board, like vending machine boards
-/obj/item/circuitboard/logic_gate
- name = "circuit board (Logic Connector)"
- build_path = /obj/machinery/logic_gate
- board_type = "machine"
- origin_tech = "programming=1" //This stuff is pretty much the absolute basis of programming, so it's mostly useless for research
- req_components = list(/obj/item/stack/cable_coil = 1)
-
- var/list/names_paths = list(
- "NOT Gate" = /obj/machinery/logic_gate/not,
- "OR Gate" = /obj/machinery/logic_gate/or,
- "AND Gate" = /obj/machinery/logic_gate/and,
- "NAND Gate" = /obj/machinery/logic_gate/nand,
- "NOR Gate" = /obj/machinery/logic_gate/nor,
- "XOR Gate" = /obj/machinery/logic_gate/xor,
- "XNOR Gate" = /obj/machinery/logic_gate/xnor,
- "STATUS Gate" = /obj/machinery/logic_gate/status,
- "CONVERT Gate" = /obj/machinery/logic_gate/convert
- )
-
-/obj/item/circuitboard/logic_gate/New()
- ..()
- if(build_path == /obj/machinery/logic_gate) //If we spawn the base type board (determined by the base type machine as the build path), become a random gate board
- var/new_path = names_paths[pick(names_paths)]
- set_type(new_path)
-
-/obj/item/circuitboard/logic_gate/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/screwdriver))
- set_type(null, user)
- return
- return ..()
-
-/obj/item/circuitboard/logic_gate/proc/set_type(typepath, mob/user)
- var/new_name = "Logic Base"
- if(!typepath)
- new_name = input("Circuit Setting", "What would you change the board setting to?") in names_paths
- typepath = names_paths[new_name]
- else
- for(var/name in names_paths)
- if(names_paths[name] == typepath)
- new_name = name
- break
- build_path = typepath
- name = "circuit board ([new_name])"
- if(user)
- to_chat(user, "You set the board to [new_name].")
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index c7dc139446a..ea0104e75bf 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -516,7 +516,7 @@
if(stat & (NOPOWER|BROKEN))
return
- if(usr.incapacitated()) //are you cuffed, dying, lying, stunned or other
+ if(usr.incapacitated() || usr.buckled) //are you cuffed, dying, lying, stunned or other
return
put_mob(usr)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 49b75588468..36196ea4eca 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -671,6 +671,9 @@
to_chat(usr, "[usr] will not fit into [src] because [usr.p_they()] [usr.p_have()] a slime latched onto [usr.p_their()] head.")
return
+ if(usr.incapacitated() || usr.buckled) //are you cuffed, dying, lying, stunned or other
+ return
+
visible_message("[usr] starts climbing into [src].")
if(do_after(usr, 20, target = usr))
diff --git a/code/game/machinery/defib_mount.dm b/code/game/machinery/defib_mount.dm
index 9ee32716e53..79d02155832 100644
--- a/code/game/machinery/defib_mount.dm
+++ b/code/game/machinery/defib_mount.dm
@@ -29,11 +29,10 @@
loc = location
if(direction)
- dir = direction
+ setDir(direction)
if(building)
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
- pixel_y = (dir & 3)? (dir == 1 ? -30 : 30) : 0
+ set_pixel_offsets_from_dir(30, -30, 30, -30)
/obj/machinery/defibrillator_mount/loaded/New() //loaded subtype for mapping use
..()
@@ -157,6 +156,6 @@
w_class = WEIGHT_CLASS_BULKY
/obj/item/mounted/frame/defib_mount/do_build(turf/on_wall, mob/user)
- new /obj/machinery/defibrillator_mount(get_turf(src), get_dir(on_wall, user), 1)
+ new /obj/machinery/defibrillator_mount(get_turf(src), get_dir(user, on_wall), 1)
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
qdel(src)
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 94a3219c159..ffb56109e9e 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -42,7 +42,7 @@
WELDER_ATTEMPT_REPAIR_MESSAGE
if(I.use_tool(src, user, 40, volume = I.tool_volume))
WELDER_REPAIR_SUCCESS_MESSAGE
- obj_integrity = Clamp(obj_integrity + 20, 0, max_integrity)
+ obj_integrity = clamp(obj_integrity + 20, 0, max_integrity)
update_icon()
return TRUE
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 73d0e9281e1..1450278e736 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -219,21 +219,21 @@ About the new airlock wires panel:
return isWireCut(AIRLOCK_WIRE_BACKUP_POWER1)
/obj/machinery/door/airlock/proc/loseMainPower()
- main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + SecondsToTicks(60)
+ main_power_lost_until = mainPowerCablesCut() ? -1 : world.time + 60 SECONDS
if(main_power_lost_until > 0)
- main_power_timer = addtimer(CALLBACK(src, .proc/regainMainPower), SecondsToTicks(60), TIMER_UNIQUE | TIMER_STOPPABLE)
+ main_power_timer = addtimer(CALLBACK(src, .proc/regainMainPower), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
// If backup power is permanently disabled then activate in 10 seconds if possible, otherwise it's already enabled or a timer is already running
if(backup_power_lost_until == -1 && !backupPowerCablesCut())
- backup_power_lost_until = world.time + SecondsToTicks(10)
- backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), SecondsToTicks(10), TIMER_UNIQUE | TIMER_STOPPABLE)
+ backup_power_lost_until = world.time + 10 SECONDS
+ backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), 10 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
// Disable electricity if required
if(electrified_until && isAllPowerLoss())
electrify(0)
/obj/machinery/door/airlock/proc/loseBackupPower()
- backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + SecondsToTicks(60)
+ backup_power_lost_until = backupPowerCablesCut() ? -1 : world.time + 60 SECONDS
if(backup_power_lost_until > 0)
- backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), SecondsToTicks(60), TIMER_UNIQUE | TIMER_STOPPABLE)
+ backup_power_timer = addtimer(CALLBACK(src, .proc/regainBackupPower), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
// Disable electricity if required
if(electrified_until && isAllPowerLoss())
@@ -280,9 +280,9 @@ About the new airlock wires panel:
else
shockedby += text("\[[time_stamp()]\] - EMP)")
message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]."
- electrified_until = duration == -1 ? -1 : world.time + SecondsToTicks(duration)
+ electrified_until = duration == -1 ? -1 : world.time + duration SECONDS
if(duration != -1)
- electrified_timer = addtimer(CALLBACK(src, .proc/electrify, 0), SecondsToTicks(duration), TIMER_UNIQUE | TIMER_STOPPABLE)
+ electrified_timer = addtimer(CALLBACK(src, .proc/electrify, 0), duration SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)
if(feedback && message)
to_chat(usr, message)
@@ -876,6 +876,8 @@ About the new airlock wires panel:
if(!user.unEquip(C))
to_chat(user, "For some reason, you can't attach [C]!")
return
+ C.add_fingerprint(user)
+ user.create_log(MISC_LOG, "put [C] on", src)
C.forceMove(src)
user.visible_message("[user] pins [C] to [src].", "You pin [C] to [src].")
note = C
@@ -933,7 +935,7 @@ About the new airlock wires panel:
if(!panel_open || user.a_intent == INTENT_HARM)
return
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
if(security_level == AIRLOCK_SECURITY_PLASTEEL)
if(arePowerSystemsOn() && shock(user, 60)) // Protective grille of wiring is electrified
@@ -965,63 +967,58 @@ About the new airlock wires panel:
. = TRUE
if(!I.tool_use_check(user, 0))
return
- switch(security_level)
- if(AIRLOCK_SECURITY_METAL)
- to_chat(user, "You begin cutting the panel's shielding...")
- if(!I.use_tool(src, user, 40, volume = I.tool_volume))
- return
- if(!panel_open)
- return
- visible_message("[user] cuts through \the [src]'s shielding.",
- "You cut through \the [src]'s shielding.",
- "You hear welding.")
- security_level = AIRLOCK_SECURITY_NONE
- spawn_atom_to_turf(/obj/item/stack/sheet/metal, user.loc, 2)
- if(AIRLOCK_SECURITY_PLASTEEL_O)
- to_chat(user, "You begin cutting the outer layer of shielding...")
- if(!I.use_tool(src, user, 40, volume = I.tool_volume))
- return
- if(!panel_open)
- return
- visible_message("[user] cuts through \the [src]'s shielding.",
- "You cut through \the [src]'s shielding.",
- "You hear welding.")
- security_level = AIRLOCK_SECURITY_PLASTEEL_O_S
- if(AIRLOCK_SECURITY_PLASTEEL_I)
- to_chat(user, "You begin cutting the inner layer of shielding...")
- if(!I.use_tool(src, user, 40, volume = I.tool_volume))
- return
- if(!panel_open)
- return
- user.visible_message("[user] cuts through \the [src]'s shielding.",
- "You cut through \the [src]'s shielding.",
- "You hear welding.")
- security_level = AIRLOCK_SECURITY_PLASTEEL_I_S
- else
- if(user.a_intent != INTENT_HELP)
- user.visible_message("[user] is [welded ? "unwelding":"welding"] the airlock.", \
- "You begin [welded ? "unwelding":"welding"] the airlock...", \
+ if(panel_open) // panel should be open before we try to slice out any shielding.
+ switch(security_level)
+ if(AIRLOCK_SECURITY_METAL)
+ to_chat(user, "You begin cutting the panel's shielding...")
+ if(!I.use_tool(src, user, 40, volume = I.tool_volume))
+ return
+ visible_message("[user] cuts through \the [src]'s shielding.",
+ "You cut through \the [src]'s shielding.",
"You hear welding.")
+ security_level = AIRLOCK_SECURITY_NONE
+ spawn_atom_to_turf(/obj/item/stack/sheet/metal, user.loc, 2)
+ if(AIRLOCK_SECURITY_PLASTEEL_O)
+ to_chat(user, "You begin cutting the outer layer of shielding...")
+ if(!I.use_tool(src, user, 40, volume = I.tool_volume))
+ return
+ visible_message("[user] cuts through \the [src]'s shielding.",
+ "You cut through \the [src]'s shielding.",
+ "You hear welding.")
+ security_level = AIRLOCK_SECURITY_PLASTEEL_O_S
+ if(AIRLOCK_SECURITY_PLASTEEL_I)
+ to_chat(user, "You begin cutting the inner layer of shielding...")
+ if(!I.use_tool(src, user, 40, volume = I.tool_volume))
+ return
+ user.visible_message("[user] cuts through \the [src]'s shielding.",
+ "You cut through \the [src]'s shielding.",
+ "You hear welding.")
+ security_level = AIRLOCK_SECURITY_PLASTEEL_I_S
+ else
+ if(user.a_intent != INTENT_HELP)
+ user.visible_message("[user] is [welded ? "unwelding":"welding"] the airlock.", \
+ "You begin [welded ? "unwelding":"welding"] the airlock...", \
+ "You hear welding.")
- if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
- if(!density && !welded)
- return
- welded = !welded
- user.visible_message("[user.name] has [welded? "welded shut":"unwelded"] [src].", \
- "You [welded ? "weld the airlock shut":"unweld the airlock"].")
- update_icon()
- else if(obj_integrity < max_integrity)
- user.visible_message("[user] is welding the airlock.", \
- "You begin repairing the airlock...", \
- "You hear welding.")
- if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
- obj_integrity = max_integrity
- stat &= ~BROKEN
- user.visible_message("[user.name] has repaired [src].", \
- "You finish repairing the airlock.")
+ if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
+ if(!density && !welded)
+ return
+ welded = !welded
+ user.visible_message("[user.name] has [welded? "welded shut":"unwelded"] [src].", \
+ "You [welded ? "weld the airlock shut":"unweld the airlock"].")
update_icon()
- else
- to_chat(user, "The airlock doesn't need repairing.")
+ else if(obj_integrity < max_integrity)
+ user.visible_message("[user] is welding the airlock.", \
+ "You begin repairing the airlock...", \
+ "You hear welding.")
+ if(I.use_tool(src, user, 40, volume = I.tool_volume, extra_checks = CALLBACK(src, .proc/weld_checks, I, user)))
+ obj_integrity = max_integrity
+ stat &= ~BROKEN
+ user.visible_message("[user.name] has repaired [src].", \
+ "You finish repairing the airlock.")
+ update_icon()
+ else
+ to_chat(user, "The airlock doesn't need repairing.")
update_icon()
/obj/machinery/door/airlock/proc/weld_checks(obj/item/I, mob/user)
@@ -1217,7 +1214,7 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/emp_act(severity)
..()
if(prob(40/severity))
- var/duration = world.time + SecondsToTicks(30 / severity)
+ var/duration = world.time + (30 / severity) SECONDS
if(duration > electrified_until)
electrify(duration)
@@ -1347,10 +1344,13 @@ About the new airlock wires panel:
if (ishuman(user) && user.a_intent == INTENT_GRAB)//grab that note
user.visible_message("[user] removes [note] from [src].", "You remove [note] from [src].")
playsound(src, 'sound/items/poster_ripped.ogg', 50, 1)
- else return FALSE
+ else
+ return FALSE
else
user.visible_message("[user] cuts down [note] from [src].", "You remove [note] from [src].")
playsound(src, 'sound/items/wirecutter.ogg', 50, 1)
+ note.add_fingerprint(user)
+ user.create_log(MISC_LOG, "removed [note] from", src)
user.put_in_hands(note)
note = null
update_icon()
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 8d842179db5..9970974e4ff 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -94,9 +94,10 @@
R.fields["criminal"] = SEC_RECORD_STATUS_INCARCERATED
var/mob/living/carbon/human/M = usr
var/rank = "UNKNOWN RANK"
- if(istype(M) && M.wear_id)
- var/obj/item/card/id/I = M.wear_id
- rank = I.assignment
+ if(istype(M))
+ var/obj/item/card/id/I = M.get_id_card()
+ if(I)
+ rank = I.assignment
if(!R.fields["comments"] || !islist(R.fields["comments"])) //copied from security computer code because apparently these need to be initialized
R.fields["comments"] = list()
R.fields["comments"] += "Autogenerated by [name] on [GLOB.current_date_string] [station_time_timestamp()] Sentenced to [timetoset/10] seconds for the charges of \"[crimes]\" by [rank] [usr.name]."
@@ -136,8 +137,7 @@
Radio.config(list("Security" = 0))
Radio.follow_target = src
- pixel_x = ((dir & 3)? (0) : (dir == 4 ? 32 : -32))
- pixel_y = ((dir & 3)? (dir ==1 ? 32 : -32) : (0))
+ set_pixel_offsets_from_dir(32, -32, 32, -32)
spawn(20)
for(var/obj/machinery/door/window/brigdoor/M in GLOB.airlocks)
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 448c410c1c8..37dbdb6c9c0 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -419,7 +419,7 @@
if(constructionStep != CONSTRUCTION_WIRES_EXPOSED)
return
. = TRUE
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
user.visible_message("[user] starts cutting the wires from [src]...", \
@@ -442,7 +442,7 @@
if(locate(/obj/machinery/door/firedoor) in get_turf(src))
to_chat(user, "There's already a firelock there.")
return
- if(!I.tool_start_check(user, 0))
+ if(!I.tool_start_check(src, user, 0))
return
user.visible_message("[user] starts bolting down [src]...", \
"You begin bolting [src]...")
diff --git a/code/game/machinery/doppler_array.dm b/code/game/machinery/doppler_array.dm
index 05198a7a55f..a4b9510945a 100644
--- a/code/game/machinery/doppler_array.dm
+++ b/code/game/machinery/doppler_array.dm
@@ -89,12 +89,12 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
/obj/machinery/doppler_array/proc/print_explosive_logs(mob/user)
if(!logged_explosions.len)
- atom_say("No logs currently stored in internal database.")
+ atom_say("No logs currently stored in internal database.")
return
if(active_timers)
to_chat(user, "[src] is already printing something, please wait.")
return
- atom_say("Printing explosive log. Standby...")
+ atom_say("Printing explosive log. Standby...")
addtimer(CALLBACK(src, .proc/print), 50)
/obj/machinery/doppler_array/proc/print()
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 9beba3f4789..f12361f1664 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -309,13 +309,13 @@ FIRE ALARM
update_icon()
/obj/machinery/firealarm/New(location, direction, building)
- ..()
+ . = ..()
if(building)
buildstage = 0
wiresexposed = TRUE
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
- pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
+ setDir(direction)
+ set_pixel_offsets_from_dir(26, -26, 26, -26)
if(is_station_contact(z) && show_alert_level)
if(GLOB.security_level)
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 57057ad510a..37766db58fb 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -144,7 +144,7 @@
active = 1
icon_state = "launcheract"
- for(var/obj/machinery/flasher/M in world)
+ for(var/obj/machinery/flasher/M in GLOB.machines)
if(M.id == id)
spawn()
M.flash()
diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm
index aca4254b517..aa541ec8619 100644
--- a/code/game/machinery/holosign.dm
+++ b/code/game/machinery/holosign.dm
@@ -67,7 +67,7 @@
else
icon_state = "light0"
- for(var/obj/machinery/holosign/M in world)
+ for(var/obj/machinery/holosign/M in GLOB.machines)
if(M.id == src.id)
spawn( 0 )
M.toggle()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 19dc80f9a40..f02e037e8c5 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -116,8 +116,8 @@ Class Procs:
var/panel_open = 0
var/area/myArea
var/interact_offline = 0 // Can the machine be interacted with while de-powered.
- var/use_log = list()
- var/list/settagwhitelist = list()//WHITELIST OF VARIABLES THAT THE set_tag HREF CAN MODIFY, DON'T PUT SHIT YOU DON'T NEED ON HERE, AND IF YOU'RE GONNA USE set_tag (format_tag() proc), ADD TO THIS LIST.
+ var/list/use_log // Init this list if you wish to add logging to your machine - currently only viewable in VV
+ var/list/settagwhitelist // (Init this list if needed) WHITELIST OF VARIABLES THAT THE set_tag HREF CAN MODIFY, DON'T PUT SHIT YOU DON'T NEED ON HERE, AND IF YOU'RE GONNA USE set_tag (format_tag() proc), ADD TO THIS LIST.
atom_say_verb = "beeps"
var/siemens_strength = 0.7 // how badly will it shock you?
@@ -224,7 +224,7 @@ Class Procs:
var/obj/item/multitool/P = get_multitool(usr)
if(P && istype(P))
var/update_mt_menu = FALSE
- if("set_tag" in href_list)
+ if("set_tag" in href_list && settagwhitelist)
if(!(href_list["set_tag"] in settagwhitelist))//I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING. (seriously though, this is a powerfull HREF, I originally found this loophole, I'm not leaving it in on my PR)
message_admins("set_tag HREF (var attempted to edit: [href_list["set_tag"]]) exploit attempted by [key_name_admin(user)] on [src] (JMP)")
return FALSE
@@ -369,7 +369,6 @@ Class Procs:
/obj/machinery/proc/RefreshParts() //Placeholder proc for machines that are built using frames.
return
- return 0
/obj/machinery/proc/assign_uid()
uid = gl_uid
diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm
index b73fa94259f..d713817ca06 100644
--- a/code/game/machinery/magnet.dm
+++ b/code/game/machinery/magnet.dm
@@ -202,7 +202,7 @@
..()
if(autolink)
- for(var/obj/machinery/magnetic_module/M in world)
+ for(var/obj/machinery/magnetic_module/M in GLOB.machines)
if(M.freq == frequency && M.code == code)
magnets.Add(M)
@@ -224,7 +224,7 @@
/obj/machinery/magnetic_controller/process()
if(magnets.len == 0 && autolink)
- for(var/obj/machinery/magnetic_module/M in world)
+ for(var/obj/machinery/magnetic_module/M in GLOB.machines)
if(M.freq == frequency && M.code == code)
magnets.Add(M)
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index b63f4ab7f8b..79f1eb83e23 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -520,8 +520,6 @@ GLOBAL_LIST_EMPTY(turret_icons)
/obj/machinery/porta_turret/process()
//the main machinery process
- set background = BACKGROUND_ENABLED
-
if(stat & (NOPOWER|BROKEN))
if(!always_up)
//if the turret has no power or is broken, make the turret pop down if it hasn't already
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index a17f9dfb9bd..b6da46a67c8 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -177,8 +177,8 @@
F.broken = 0
F.times_used = 0
F.icon_state = "flash"
- if(istype(O,/obj/item/gun/energy/disabler/cyborg))
- var/obj/item/gun/energy/disabler/cyborg/D = O
+ if(istype(O,/obj/item/gun/energy))
+ var/obj/item/gun/energy/D = O
if(D.cell.charge < D.cell.maxcharge)
var/obj/item/ammo_casing/energy/E = D.ammo_type[D.select]
D.cell.give(E.e_cost)
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index 081a48c3da1..e4e37ae1bcb 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -19,8 +19,7 @@
var/item_recycle_sound = 'sound/machines/recycler.ogg'
/obj/machinery/recycler/New()
- AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_PLASTIC, MAT_BLUESPACE), 0,
- TRUE, null, null, null, TRUE)
+ AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_PLASTIC, MAT_BLUESPACE), 0, TRUE, null, null, null, TRUE)
..()
component_parts = list()
component_parts += new /obj/item/circuitboard/recycler(null)
@@ -37,7 +36,7 @@
mat_mod *= 50000
for(var/obj/item/stock_parts/manipulator/M in component_parts)
amt_made = 25 * M.rating //% of materials salvaged
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = mat_mod
amount_produced = min(100, amt_made)
@@ -135,7 +134,7 @@
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
I.forceMove(loc)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/material_amount = materials.get_item_material_amount(I)
if(!material_amount)
qdel(I)
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index 095b2e7d56e..81379df97c4 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -200,7 +200,7 @@ GLOBAL_LIST_EMPTY(allRequestConsoles)
var/log_msg = message
var/pass = 0
screen = RCS_SENTFAIL
- for(var/obj/machinery/message_server/MS in world)
+ for(var/obj/machinery/message_server/MS in GLOB.machines)
if(!MS.active) continue
MS.send_rc_message(ckey(href_list["department"]),department,log_msg,msgStamped,msgVerified,priority)
pass = 1
@@ -225,7 +225,7 @@ GLOBAL_LIST_EMPTY(allRequestConsoles)
message_log += "Message sent to [recipient] at [station_time_timestamp()] [message]"
Radio.autosay("Alert; a new requests console message received for [recipient] from [department]", null, "[radiochannel]")
else
- audible_message(text("[bicon(src)] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4)
+ atom_say("No server detected!")
//Handle screen switching
if(href_list["setScreen"])
@@ -256,7 +256,7 @@ GLOBAL_LIST_EMPTY(allRequestConsoles)
else if(world.time < print_cooldown)
error_message = "Please allow the printer time to prepare the next shipping label."
if(error_message)
- audible_message(text("[bicon(src)] *The Requests Console beeps: 'NOTICE: [error_message]'"),,4)
+ atom_say("[error_message]")
return
print_label(ship_tag_name, ship_tag_index)
shipping_log += "Shipping Label printed for [ship_tag_name] [msgVerified]"
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 3a6f3011747..da4df4f8382 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -772,6 +772,8 @@
if(usr.stat != 0)
return
+ if(usr.incapacitated() || usr.buckled) //are you cuffed, dying, lying, stunned or other
+ return
if(!state_open)
to_chat(usr, "The unit's doors are shut.")
return
diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm
index 6299be7be3d..a5cff57ad52 100644
--- a/code/game/machinery/syndicatebeacon.dm
+++ b/code/game/machinery/syndicatebeacon.dm
@@ -121,7 +121,8 @@
if(user)
to_chat(user, "The connected wire doesn't have enough current.")
return
- for(var/obj/singularity/singulo in GLOB.singularities)
+ for(var/thing in GLOB.singularities)
+ var/obj/singularity/singulo = thing
if(singulo.z == z)
singulo.target = src
icon_state = "[icontype]1"
@@ -132,7 +133,8 @@
/obj/machinery/power/singularity_beacon/proc/Deactivate(mob/user = null)
- for(var/obj/singularity/singulo in world)
+ for(var/thing in GLOB.singularities)
+ var/obj/singularity/singulo = thing
if(singulo.target == src)
singulo.target = null
icon_state = "[icontype]0"
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index b3745f947cd..2d15472f521 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -244,7 +244,7 @@
/obj/machinery/syndicatebomb/proc/settings(mob/user)
var/new_timer = input(user, "Please set the timer.", "Timer", "[timer_set]") as num
if(can_interact(user)) //No running off and setting bombs from across the station
- timer_set = Clamp(new_timer, minimum_timer, maximum_timer)
+ timer_set = clamp(new_timer, minimum_timer, maximum_timer)
loc.visible_message("[bicon(src)] timer set for [timer_set] seconds.")
if(alert(user,"Would you like to start the countdown now?",,"Yes","No") == "Yes" && can_interact(user))
if(defused || active)
diff --git a/code/game/machinery/tcomms/_base.dm b/code/game/machinery/tcomms/_base.dm
index a857afcef89..dc933099faa 100644
--- a/code/game/machinery/tcomms/_base.dm
+++ b/code/game/machinery/tcomms/_base.dm
@@ -40,6 +40,8 @@ GLOBAL_LIST_EMPTY(tcomms_machines)
var/network_id = "None"
/// Is the machine active
var/active = TRUE
+ /// Has the machine been hit by an ionspheric anomalie
+ var/ion = FALSE
/**
* Base Initializer
@@ -67,7 +69,8 @@ GLOBAL_LIST_EMPTY(tcomms_machines)
*/
/obj/machinery/tcomms/update_icon()
. = ..()
- if(!active || (stat & NOPOWER))
+ // Show the off sprite if were inactive, ion'd or unpowered
+ if(!active || (stat & NOPOWER) || ion)
icon_state = "[initial(icon_state)]_off"
else
icon_state = initial(icon_state)
@@ -88,21 +91,21 @@ GLOBAL_LIST_EMPTY(tcomms_machines)
/**
- * Machine Enabler
+ * Start of Ion Anomalie Event
*
- * Quick and dirty proc to allow for the machine to be programatically enabled easily. Used for the anomaly event
+ * Proc to easily start an Ion Anomalie's effects, and update the icon
*/
-/obj/machinery/tcomms/proc/enable_machine()
- active = TRUE
+/obj/machinery/tcomms/proc/start_ion()
+ ion = TRUE
update_icon()
/**
- * Machine Disabler
+ * End of Ion Anomalie Event
*
- * Quick and dirty proc to allow for the machine to be programatically disabled easily. Used for the anomaly event
+ * Proc to easily stop an Ion Anomalie's effects, and update the icon
*/
-/obj/machinery/tcomms/proc/disable_machine()
- active = FALSE
+/obj/machinery/tcomms/proc/end_ion()
+ ion = FALSE
update_icon()
/**
@@ -171,6 +174,8 @@ GLOBAL_LIST_EMPTY(tcomms_machines)
var/vname
/// List of all channels this can be sent or recieved on
var/list/zlevels = list()
+ /// Should this signal be re-broadcasted (Can be modified by NTTC, defaults to TRUE)
+ var/pass = TRUE
/**
* Destructor for the TCM datum.
@@ -301,7 +306,7 @@ GLOBAL_LIST_EMPTY(tcomms_machines)
if(is_admin(R) && !R.get_preference(CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios.
continue
- if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes.
+ if(isnewplayer(R)) // we don't want new players to hear messages. rare but generates runtimes.
continue
// --- Can understand the speech ---
diff --git a/code/game/machinery/tcomms/core.dm b/code/game/machinery/tcomms/core.dm
index 9e638913f9d..f1599edd8b8 100644
--- a/code/game/machinery/tcomms/core.dm
+++ b/code/game/machinery/tcomms/core.dm
@@ -1,5 +1,6 @@
#define UI_TAB_CONFIG "CONFIG"
#define UI_TAB_LINKS "LINKS"
+#define UI_TAB_FILTER "FILTER"
/**
* # Telecommunications Core
@@ -71,8 +72,8 @@
* * tcm - The tcomms message datum
*/
/obj/machinery/tcomms/core/proc/handle_message(datum/tcomms_message/tcm)
- // Don't do anything with rejected signals, or if were offline, or if we have no power
- if(tcm.reject || !active || (stat & NOPOWER))
+ // Don't do anything with rejected signals, if were offline, if we are ion'd, or if we have no power
+ if(tcm.reject || !active || (stat & NOPOWER) || ion)
return FALSE
// Kill the signal if its on a z-level that isnt reachable
if(!zlevel_reachable(tcm.source_level))
@@ -81,6 +82,11 @@
// Now we can run NTTC
tcm = nttc.modify_message(tcm)
+ // If the signal shouldnt be broadcast, dont broadcast it
+ if(!tcm.pass)
+ // We still return TRUE here because the signal was handled, even though we didnt broadcast
+ return TRUE
+
// Now we generate the list of where that signal should go to
tcm.zlevels = reachable_zlevels
tcm.zlevels |= tcm.source_level
@@ -131,6 +137,7 @@
var/data[0]
// What tab are we on
data["tab"] = ui_tab
+ data["ion"] = ion
// Only send NTTC settings if were on the right tab. This saves on sending overhead.
if(ui_tab == UI_TAB_CONFIG)
@@ -168,6 +175,9 @@
data["entries"] += list(list("addr" = "\ref[R]", "net_id" = R.network_id, "sector" = R.loc.z, "status" = status, "status_color" = status_color))
// End the shit
+ if(ui_tab == UI_TAB_FILTER)
+ data["filtered_users"] = nttc.filtering
+
return data
/obj/machinery/tcomms/core/Topic(href, href_list)
@@ -177,7 +187,7 @@
if(href_list["tab"])
// Make sure its a valid tab
- if(href_list["tab"] in list(UI_TAB_CONFIG, UI_TAB_LINKS))
+ if(href_list["tab"] in list(UI_TAB_CONFIG, UI_TAB_LINKS, UI_TAB_FILTER))
ui_tab = href_list["tab"]
// Check if they did a href, but only for that current tab
@@ -257,9 +267,35 @@
to_chat(usr, "Successfully changed password from [link_password] to [new_password].")
link_password = new_password
+ if(ui_tab == UI_TAB_FILTER)
+ if(href_list["add_filter"])
+ // This is a stripped input because I did NOT come this far for this system to be abused by HTML injection
+ var/name_to_add = stripped_input(usr, "Enter a name to add to the filtering list", "Name Entry")
+ if(name_to_add == "")
+ return
+ if(name_to_add in nttc.filtering)
+ to_chat(usr, "ERROR: User already in filtering list.")
+ else
+ nttc.filtering |= name_to_add
+ log_action(usr, "has added [name_to_add] to the NTTC filter list on core with ID [network_id]", TRUE)
+ to_chat(usr, "Successfully added [name_to_add] to the NTTC filtering list.")
+
+
+ if(href_list["remove_filter"])
+ var/name_to_remove = href_list["remove_filter"]
+ if(!(name_to_remove in nttc.filtering))
+ to_chat(usr, "ERROR: Name does not exist in filter list. Please file an issue report.")
+ else
+ var/confirm = alert(usr, "Are you sure you want to remove [name_to_remove] from the filtering list?", "Confirm Removal", "Yes", "No")
+ if(confirm == "Yes")
+ nttc.filtering -= name_to_remove
+ log_action(usr, "has removed [name_to_remove] from the NTTC filter list on core with ID [network_id]", TRUE)
+ to_chat(usr, "Successfully removed [name_to_remove] from the NTTC filtering list.")
+
// Hack to speed update the nanoUI
SSnanoui.update_uis(src)
#undef UI_TAB_CONFIG
#undef UI_TAB_LINKS
+#undef UI_TAB_FILTER
diff --git a/code/game/machinery/tcomms/nttc.dm b/code/game/machinery/tcomms/nttc.dm
index 6ee158c6cc0..cd880970b23 100644
--- a/code/game/machinery/tcomms/nttc.dm
+++ b/code/game/machinery/tcomms/nttc.dm
@@ -2,7 +2,7 @@
NTTC system
This is basically the replacement for NTSL and allows tickbox features such as job titles and colours, without needing a script
This also means that there is no user input here, which means the system isnt prone to exploits since its only selecting options, no user input
- Basically, just imagine pfSense for tcomsm
+ Basically, just imagine pfSense for tcomms
All this code was written by Tigercat2000. I take no credit -aa07
*/
@@ -153,6 +153,10 @@
var/list/job_card_styles = list(
JOB_STYLE_1, JOB_STYLE_2, JOB_STYLE_3, JOB_STYLE_4
)
+
+ // List of people who will get blocked out of comms
+ var/list/filtering = list()
+
// Used to determine what languages are allowable for conversion. Generated during runtime.
var/list/valid_languages = list("--DISABLE--")
@@ -220,6 +224,9 @@
// Primary signal modification. This is where all of the variables behavior are actually implemented.
/datum/nttc_configuration/proc/modify_message(datum/tcomms_message/tcm)
+ // Check if they should be blacklisted right off the bat. We can save CPU if the message wont even be processed
+ if(tcm.sender_name in filtering)
+ tcm.pass = FALSE
// All job and coloring shit
if(toggle_job_color || toggle_name_color)
var/job = tcm.sender_job
diff --git a/code/game/machinery/tcomms/relay.dm b/code/game/machinery/tcomms/relay.dm
index 8c2bbf28bf2..9309a6109da 100644
--- a/code/game/machinery/tcomms/relay.dm
+++ b/code/game/machinery/tcomms/relay.dm
@@ -76,27 +76,6 @@
linked_core = null
linked = FALSE
-/**
- * Relay Enabler
- *
- * Modification to the standard one so that the links get updated
- */
-/obj/machinery/tcomms/relay/enable_machine()
- ..()
- if(linked_core)
- linked_core.refresh_zlevels()
-
-/**
- * Relay Disabler
- *
- * Modification to the standard one so that the links get updated
- */
-/obj/machinery/tcomms/relay/disable_machine()
- ..()
- if(linked_core)
- linked_core.refresh_zlevels()
-
-
//////////////
// UI STUFF //
//////////////
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 1487256c712..7aa5661febe 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -190,7 +190,6 @@
var/obj/item/vending_refill/R = locate() in component_parts
if(!R)
CRASH("Constructible vending machine did not have a refill canister")
- return
R.products = unbuild_inventory(product_records)
R.contraband = unbuild_inventory(hidden_records)
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 7dac9de2b9a..9acdcba48de 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -166,10 +166,6 @@
var/mob/M = A
if(istype(firer, /mob))
add_attack_logs(firer, M, "Mecha-shot with [src]")
- if(!iscarbon(firer))
- M.LAssailant = null
- else
- M.LAssailant = firer
else
add_attack_logs(null, M, "Mecha-shot with [src]")
if(life <= 0)
diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm
index 04322c63093..896ce886887 100644
--- a/code/game/mecha/mech_bay.dm
+++ b/code/game/mecha/mech_bay.dm
@@ -5,8 +5,8 @@
/turf/simulated/floor/mech_bay_recharge_floor/airless
icon_state = "recharge_floor_asteroid"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/obj/machinery/mech_bay_recharge_port
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 90256fe5d2a..50fdfef3cb3 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -38,9 +38,7 @@
)
/obj/machinery/mecha_part_fabricator/New()
- var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
- list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE), 0,
- FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
+ var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE), 0, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
..()
component_parts = list()
@@ -65,7 +63,7 @@
RefreshParts()
/obj/machinery/mecha_part_fabricator/Destroy()
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -75,7 +73,7 @@
//maximum stocking amount (default 300000, 600000 at T4)
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
T += M.rating
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = (200000 + (T*50000))
//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
@@ -118,7 +116,7 @@
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
var/output
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/mat_id in materials.materials)
var/datum/material/M = materials.materials[mat_id]
output += "[M.name]: [M.amount] cm³"
@@ -139,7 +137,7 @@
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
if(D.reagents_list.len) // No reagents storage - no reagent designs.
return FALSE
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
@@ -149,7 +147,7 @@
desc = "It's building \a [initial(D.name)]."
var/list/res_coef = get_resources_w_coeff(D)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.use_amount(res_coef)
overlays += "fab-active"
use_power = ACTIVE_POWER_USE
@@ -392,7 +390,7 @@
var/index = afilter.getNum("index")
var/new_index = index + afilter.getNum("queue_move")
if(isnum(index) && isnum(new_index))
- if(IsInRange(new_index,1,queue.len))
+ if(ISINRANGE(new_index,1,queue.len))
queue.Swap(index,new_index)
return update_queue_on_page()
if(href_list["clear_queue"])
@@ -414,7 +412,7 @@
break
if(href_list["remove_mat"] && href_list["material"])
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_sheets(text2num(href_list["remove_mat"]), href_list["material"])
updateUsrDialog()
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 610436406d8..90d466baf3e 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -11,6 +11,7 @@
force = 5
max_integrity = 300 //max_integrity is base health
armor = list(melee = 20, bullet = 10, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 100)
+ bubble_icon = "machine"
var/list/facing_modifiers = list(MECHA_FRONT_ARMOUR = 1.5, MECHA_SIDE_ARMOUR = 1, MECHA_BACK_ARMOUR = 0.5)
var/ruin_mecha = FALSE //if the mecha starts on a ruin, don't automatically give it a tracking beacon to prevent metagaming.
var/initial_icon = null //Mech type for resetting icon. Only used for reskinning kits (see custom items)
@@ -609,6 +610,8 @@
occupant = null
icon_state = initial(icon_state)+"-open"
setDir(dir_in)
+ if(A in trackers)
+ trackers -= A
/obj/mecha/Destroy()
if(occupant)
@@ -639,7 +642,7 @@
cabin_air = null
QDEL_NULL(spark_system)
QDEL_NULL(smoke_system)
-
+ QDEL_LIST(trackers)
GLOB.mechas_list -= src //global mech list
return ..()
@@ -1444,8 +1447,10 @@
diag_hud_set_mechtracking()
-/obj/mecha/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list())
- flick_overlay(image('icons/mob/talk.dmi', bubble_loc, bubble_state,MOB_LAYER+1), bubble_recipients, 30)
+/obj/mecha/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
+ var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, FLY_LAYER)
+ I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
+ INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, bubble_recipients, 30)
/obj/mecha/update_remote_sight(mob/living/user)
if(occupant_sight_flags)
@@ -1454,7 +1459,7 @@
..()
-/obj/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/obj/mecha/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect)
if(selected)
used_item = selected
diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm
index 9a3dffb0c3b..f72770a8ea3 100644
--- a/code/game/mecha/mecha_control_console.dm
+++ b/code/game/mecha/mecha_control_console.dm
@@ -28,7 +28,12 @@
data["screen"] = screen
if(screen == 0)
var/list/mechas[0]
- for(var/obj/item/mecha_parts/mecha_tracking/TR in world)
+ var/list/trackerlist = list()
+ for(var/stompy in GLOB.mechas_list)
+ var/obj/mecha/MC = stompy
+ trackerlist += MC.trackers
+ for(var/thing in trackerlist)
+ var/obj/item/mecha_parts/mecha_tracking/TR = thing
var/answer = TR.get_mecha_info()
if(answer)
mechas[++mechas.len] = answer
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 494fc70d36b..7569d8b5263 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -124,8 +124,7 @@
//Attach hydraulic clamp
var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new
HC.attach(src)
- for(var/obj/item/mecha_parts/mecha_tracking/B in trackers)//Deletes the beacon so it can't be found easily
- qdel(B)
+ QDEL_LIST(trackers) //Deletes the beacon so it can't be found easily
var/obj/item/mecha_parts/mecha_equipment/mining_scanner/scanner = new
scanner.attach(src)
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index bb1070f2cf1..e3c14ff459c 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -11,7 +11,7 @@
/atom/movable/attack_hand(mob/living/user)
. = ..()
if(can_buckle && has_buckled_mobs())
- if(buckled_mobs.len > 1)
+ if(length(buckled_mobs) > 1)
var/unbuckled = input(user, "Who do you wish to unbuckle?", "Unbuckle Who?") as null|mob in buckled_mobs
if(user_unbuckle_mob(unbuckled,user))
return TRUE
@@ -26,15 +26,12 @@
return TRUE
/atom/movable/proc/has_buckled_mobs()
- if(!buckled_mobs)
- return FALSE
- if(buckled_mobs.len)
- return TRUE
+ return length(buckled_mobs)
/atom/movable/attack_robot(mob/living/user)
. = ..()
if(can_buckle && has_buckled_mobs() && Adjacent(user)) // attack_robot is called on all ranges, so the Adjacent check is needed
- if(buckled_mobs.len > 1)
+ if(length(buckled_mobs) > 1)
var/unbuckled = input(user, "Who do you wish to unbuckle?", "Unbuckle Who?") as null|mob in buckled_mobs
if(user_unbuckle_mob(unbuckled,user))
return TRUE
@@ -54,7 +51,7 @@
if(check_loc && M.loc != loc)
return FALSE
- if((!can_buckle && !force) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src)
+ if((!can_buckle && !force) || M.buckled || (length(buckled_mobs) >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src)
return FALSE
M.buckling = src
if(!M.can_buckle() && !force)
@@ -69,6 +66,9 @@
if(buckle_prevents_pull)
M.pulledby.stop_pulling()
+ for(var/obj/item/grab/G in M.grabbed_by)
+ qdel(G)
+
if(!check_loc && M.loc != loc)
M.forceMove(loc)
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index f8abaa7a17e..4978a4ee314 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -7,6 +7,7 @@
var/list/loot //a list of possible items to spawn e.g. list(/obj/item, /obj/structure, /obj/effect)
/obj/effect/spawner/lootdrop/New()
+ ..()
if(loot && loot.len)
for(var/i = lootcount, i > 0, i--)
if(!loot.len) break
@@ -15,7 +16,7 @@
loot.Remove(lootspawn)
if(lootspawn)
- new lootspawn(get_turf(src))
+ new lootspawn(loc)
qdel(src)
/obj/effect/spawner/lootdrop/armory_contraband
diff --git a/code/game/objects/effects/spawners/vaultspawner.dm b/code/game/objects/effects/spawners/vaultspawner.dm
index 0d882cc9bd2..a78c6111eb7 100644
--- a/code/game/objects/effects/spawners/vaultspawner.dm
+++ b/code/game/objects/effects/spawners/vaultspawner.dm
@@ -21,6 +21,7 @@
if(i == lowBoundX || i == hiBoundX || j == lowBoundY || j == hiBoundY)
new /turf/simulated/wall/vault(locate(i,j,z),type)
else
- new /turf/simulated/floor/vault(locate(i,j,z),type)
+ var/turf/T = new /turf/simulated/floor/vault(locate(i, j, z))
+ T.icon_state = "[type]vault"
qdel(src)
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index d97663759af..7af5d7a998f 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -98,6 +98,7 @@
pixel_x = rand(6,-6)
pixel_y = rand(6,-6)
START_PROCESSING(SSobj, src)
+ AddComponent(/datum/component/swarming)
/obj/structure/spider/spiderling/Destroy()
STOP_PROCESSING(SSobj, src)
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index 0a47e57112e..bde6cb538df 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -51,7 +51,7 @@
var/list/affecting = list()
/obj/effect/step_trigger/thrower/Trigger(atom/A)
- if(!A || !ismovableatom(A))
+ if(!A || !ismovable(A))
return
var/atom/movable/AM = A
var/curtiles = 0
diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm
index 54ddb01b653..1b31891e537 100644
--- a/code/game/objects/explosion.dm
+++ b/code/game/objects/explosion.dm
@@ -88,7 +88,7 @@
var/turf/T = A
if(!T)
continue
- var/dist = hypotenuse(T.x, T.y, x0, y0)
+ var/dist = HYPOTENUSE(T.x, T.y, x0, y0)
if(config.reactionary_explosions)
var/turf/Trajectory = T
@@ -209,7 +209,7 @@
var/list/wipe_colours = list()
for(var/turf/T in spiral_range_turfs(max_range, epicenter))
wipe_colours += T
- var/dist = hypotenuse(T.x, T.y, x0, y0)
+ var/dist = HYPOTENUSE(T.x, T.y, x0, y0)
if(newmode == "Yes")
var/turf/TT = T
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index ab6ebe6a0fe..76361776b0a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -19,6 +19,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
can_be_hit = FALSE
suicidal_hands = TRUE
+ var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
var/hitsound = null
var/usesound = null
var/throwhitsound
@@ -124,10 +125,10 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
return ..()
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
- if(((src in target) && !target_self) || ((!istype(target.loc, /turf)) && (!istype(target, /turf)) && (not_inside)))
- return 0
+ if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
+ return FALSE
else
- return 1
+ return TRUE
/obj/item/blob_act(obj/structure/blob/B)
if(B && B.loc == loc)
diff --git a/code/game/objects/items/contraband.dm b/code/game/objects/items/contraband.dm
index 77aef9bb71d..5246652aa0e 100644
--- a/code/game/objects/items/contraband.dm
+++ b/code/game/objects/items/contraband.dm
@@ -56,7 +56,7 @@
desc = "Huh."
allow_wrap = FALSE
-/obj/item/storage/pill_bottle/random_drug_bottle/New()
- ..()
+/obj/item/storage/pill_bottle/random_drug_bottle/Initialize(mapload)
+ . = ..()
for(var/i in 1 to 5)
new /obj/item/reagent_containers/food/pill/random_drugs(src)
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index 97c5817f05b..95b36194f56 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -241,6 +241,7 @@
user.base_icon = disguise
user.icon_state = disguise
user.cham_proj = src
+ user.bubble_icon = "robot"
active = TRUE
user.update_icons()
@@ -249,6 +250,7 @@
S = user
user.base_icon = initial(user.base_icon)
user.icon_state = initial(user.icon_state)
+ user.bubble_icon = "syndibot"
active = FALSE
user.update_icons()
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 58848f3f7e4..8bfbf22f05d 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -113,7 +113,6 @@
/obj/item/flash/attack(mob/living/M, mob/user)
if(!try_use_flash(user))
return 0
-
if(iscarbon(M))
flash_carbon(M, user, 5, 1)
if(overcharged)
@@ -121,22 +120,12 @@
M.IgniteMob()
burn_out()
return 1
-
else if(issilicon(M))
- if(isrobot(M))
- var/mob/living/silicon/robot/R = M
- if(R.module) // Perhaps they didn't choose a module yet
- for(var/obj/item/borg/combat/shield/S in R.module.modules)
- if(R.activated(S))
- add_attack_logs(user, M, "Flashed with [src]")
- user.visible_message("[user] tries to overloads [M]'s sensors with the [src.name], but is blocked by [M]'s shield!", "You try to overload [M]'s sensors with the [src.name], but are blocked by [M.p_their()] shield!")
- return 1
add_attack_logs(user, M, "Flashed with [src]")
if(M.flash_eyes(affect_silicon = 1))
M.Weaken(rand(5,10))
user.visible_message("[user] overloads [M]'s sensors with the [src.name]!", "You overload [M]'s sensors with the [src.name]!")
return 1
-
user.visible_message("[user] fails to blind [M] with the [src.name]!", "You fail to blind [M] with the [src.name]!")
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index d9c6d60cf54..7a6b41966a8 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -167,7 +167,7 @@
// Negative numbers will subtract
/obj/item/lightreplacer/proc/AddUses(amount = 1)
- uses = Clamp(uses + amount, 0, max_uses)
+ uses = clamp(uses + amount, 0, max_uses)
/obj/item/lightreplacer/proc/AddShards(amount = 1, user)
bulb_shards += amount
diff --git a/code/game/objects/items/devices/pizza_bomb.dm b/code/game/objects/items/devices/pizza_bomb.dm
index c12331b2be2..e5c237938d6 100644
--- a/code/game/objects/items/devices/pizza_bomb.dm
+++ b/code/game/objects/items/devices/pizza_bomb.dm
@@ -27,7 +27,7 @@
desc = "A box suited for pizzas."
icon_state = "pizzabox1"
return
- timer = Clamp(timer, 10, 100)
+ timer = clamp(timer, 10, 100)
icon_state = "pizzabox1"
to_chat(user, "You set the timer to [timer / 10] before activating the payload and closing \the [src].")
message_admins("[key_name_admin(usr)] has set a timer on a pizza bomb to [timer/10] seconds at (JMP).")
@@ -52,7 +52,7 @@
if(disarmed)
visible_message("[bicon(src)] Sparks briefly jump out of the [correct_wire] wire on \the [src], but it's disarmed!")
return
- src.audible_message("[bicon(src)] [src] beeps, \"Enjoy the pizza!\"")
+ atom_say("Enjoy the pizza!")
src.visible_message("\The [src] violently explodes!")
explosion(src.loc,1,2,4,flame_range = 2) //Identical to a minibomb
qdel(src)
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index 083720f0e22..284ce8d5598 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -65,7 +65,7 @@
else if(href_list["code"])
code += text2num(href_list["code"])
code = round(code)
- code = Clamp(code, 1, 100)
+ code = clamp(code, 1, 100)
else if(href_list["power"])
on = !on
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 13c97f26730..59d2c2a99bd 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -46,16 +46,15 @@
name = "station intercom (Security)"
frequency = SEC_I_FREQ
-/obj/item/radio/intercom/New(turf/loc, ndir, building = 3)
- ..()
+/obj/item/radio/intercom/New(turf/loc, direction, building = 3)
+ . = ..()
buildstage = building
if(buildstage)
START_PROCESSING(SSobj, src)
else
- if(ndir)
- pixel_x = (ndir & EAST|WEST) ? (ndir == EAST ? 28 : -28) : 0
- pixel_y = (ndir & NORTH|SOUTH) ? (ndir == NORTH ? 28 : -28) : 0
- dir=ndir
+ if(direction)
+ setDir(direction)
+ set_pixel_offsets_from_dir(28, -28, 28, -28)
b_stat=1
on = 0
GLOB.global_intercoms.Add(src)
@@ -204,7 +203,7 @@
STOP_PROCESSING(SSobj, src)
/obj/item/radio/intercom/welder_act(mob/user, obj/item/I)
- if(!buildstage)
+ if(buildstage != 0)
return
. = TRUE
if(!I.tool_use_check(user, 3))
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 4c2aaa82c1e..009ec01ef43 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -295,7 +295,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
universal_speak = 1
/mob/living/automatedannouncer/New()
- lifetime_timer = addtimer(CALLBACK(src, .proc/autocleanup), SecondsToTicks(10), TIMER_STOPPABLE)
+ lifetime_timer = addtimer(CALLBACK(src, .proc/autocleanup), 10 SECONDS, TIMER_STOPPABLE)
..()
/mob/living/automatedannouncer/Destroy()
@@ -623,6 +623,9 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
..()
set_frequency(ERT_FREQ)
+/obj/item/radio/borg/ert/specops
+ keyslot = new /obj/item/encryptionkey/centcom
+
/obj/item/radio/borg/attackby(obj/item/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/encryptionkey/))
user.set_machine(src)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 0d8873a6377..f20a2cc5875 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -141,7 +141,7 @@ REAGENT SCANNER
// Used by the PDA medical scanner too
/proc/healthscan(mob/user, mob/living/M, mode = 1, advanced = FALSE)
- if(!ishuman(M) || M.isSynthetic())
+ if(!ishuman(M) || ismachineperson(M))
//these sensors are designed for organic life
to_chat(user, "Analyzing Results for ERROR:\n\t Overall Status: ERROR")
to_chat(user, "\t Key: Suffocation/Toxin/Burns/Brute")
diff --git a/code/game/objects/items/devices/sensor_device.dm b/code/game/objects/items/devices/sensor_device.dm
index 8c69402ed70..b83128cf4a5 100644
--- a/code/game/objects/items/devices/sensor_device.dm
+++ b/code/game/objects/items/devices/sensor_device.dm
@@ -6,7 +6,7 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
origin_tech = "programming=3;materials=3;magnets=3"
- var/datum/nano_module/crew_monitor/crew_monitor
+ var/datum/tgui_module/crew_monitor/crew_monitor
/obj/item/sensor_device/New()
..()
@@ -17,7 +17,7 @@
return ..()
/obj/item/sensor_device/attack_self(mob/user as mob)
- ui_interact(user)
+ tgui_interact(user)
-/obj/item/sensor_device/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- crew_monitor.ui_interact(user, ui_key, ui, force_open)
+/obj/item/sensor_device/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
+ crew_monitor.tgui_interact(user, ui_key, ui, force_open)
diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm
index c5c8f67e34d..77e9eacc6a1 100644
--- a/code/game/objects/items/devices/uplinks.dm
+++ b/code/game/objects/items/devices/uplinks.dm
@@ -131,7 +131,6 @@ GLOBAL_LIST_EMPTY(world_uplinks)
else
var/datum/uplink_item/UI = ItemsReference[href_list["buy_item"]]
return buy(UI, UI ? UI.reference : "")
- return 0
/obj/item/uplink/proc/buy(var/datum/uplink_item/UI, var/reference)
if(!UI)
diff --git a/code/game/objects/items/mixing_bowl.dm b/code/game/objects/items/mixing_bowl.dm
index da851437fd5..1e1a39d49d0 100644
--- a/code/game/objects/items/mixing_bowl.dm
+++ b/code/game/objects/items/mixing_bowl.dm
@@ -118,7 +118,7 @@
/obj/item/mixing_bowl/Topic(href, href_list)
if(..())
return
- if("dispose")
+ if(href_list["dispose"])
dispose()
return
diff --git a/code/game/objects/items/mountable_frames/fire_alarm.dm b/code/game/objects/items/mountable_frames/fire_alarm.dm
index 83f435a277c..22c526664aa 100644
--- a/code/game/objects/items/mountable_frames/fire_alarm.dm
+++ b/code/game/objects/items/mountable_frames/fire_alarm.dm
@@ -6,5 +6,5 @@
mount_reqs = list("simfloor", "nospace")
/obj/item/mounted/frame/firealarm/do_build(turf/on_wall, mob/user)
- new /obj/machinery/firealarm(get_turf(src), get_dir(on_wall, user), 1)
+ new /obj/machinery/firealarm(get_turf(src), get_dir(user, on_wall), 1)
qdel(src)
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 43178a85ef8..8b82341a06c 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -9,23 +9,23 @@
origin_tech = "programming=2"
var/locked = 0
var/installed = 0
- var/require_module = 0
+ var/require_module = FALSE
var/module_type = null
/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R)
if(R.stat == DEAD)
to_chat(usr, "[src] will not function on a deceased cyborg.")
- return 1
+ return TRUE
if(module_type && !istype(R.module, module_type))
to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
to_chat(usr, "There's no mounting point for the module!")
- return 1
+ return TRUE
/obj/item/borg/upgrade/reset
name = "cyborg module reset board"
desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the cyborg."
icon_state = "cyborg_upgrade1"
- require_module = 1
+ require_module = TRUE
/obj/item/borg/upgrade/reset/action(mob/living/silicon/robot/R)
if(..())
@@ -55,7 +55,7 @@
R.custom_name = heldname
R.real_name = heldname
- return 1
+ return TRUE
/obj/item/borg/upgrade/restart
name = "cyborg emergency reboot module"
@@ -77,14 +77,14 @@
GLOB.alive_mob_list += R
R.notify_ai(1)
- return 1
+ return TRUE
/obj/item/borg/upgrade/vtec
name = "robotic VTEC Module"
desc = "Used to kick in a robot's VTEC systems, increasing their speed."
icon_state = "cyborg_upgrade2"
- require_module = 1
+ require_module = TRUE
origin_tech = "engineering=4;materials=5;programming=4"
/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R)
@@ -97,14 +97,14 @@
R.speed = -1 // Gotta go fast.
- return 1
+ return TRUE
/obj/item/borg/upgrade/disablercooler
name = "cyborg rapid disabler cooling module"
desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
icon_state = "cyborg_upgrade3"
origin_tech = "engineering=4;powerstorage=4;combat=4"
- require_module = 1
+ require_module = TRUE
module_type = /obj/item/robot_module/security
/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R)
@@ -122,7 +122,7 @@
T.charge_delay = max(2 , T.charge_delay - 4)
- return 1
+ return TRUE
/obj/item/borg/upgrade/thrusters
name = "ion thruster upgrade"
@@ -139,14 +139,14 @@
return
R.ionpulse = 1
- return 1
+ return TRUE
/obj/item/borg/upgrade/ddrill
name = "mining cyborg diamond drill"
desc = "A diamond drill replacement for the mining module's standard drill."
icon_state = "cyborg_upgrade3"
origin_tech = "engineering=4;materials=5"
- require_module = 1
+ require_module = TRUE
module_type = /obj/item/robot_module/miner
/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R)
@@ -161,14 +161,14 @@
R.module.modules += new /obj/item/pickaxe/drill/cyborg/diamond(R.module)
R.module.rebuild()
- return 1
+ return TRUE
/obj/item/borg/upgrade/soh
name = "mining cyborg satchel of holding"
desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
icon_state = "cyborg_upgrade3"
origin_tech = "engineering=4;materials=4;bluespace=4"
- require_module = 1
+ require_module = TRUE
module_type = /obj/item/robot_module/miner
/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
@@ -181,35 +181,46 @@
R.module.modules += new /obj/item/storage/bag/ore/holding(R.module)
R.module.rebuild()
- return 1
+ return TRUE
/obj/item/borg/upgrade/syndicate
- name = "illegal equipment module"
+ name = "safety override module"
desc = "Unlocks the hidden, deadlier functions of a cyborg. Also prevents emag subversion."
icon_state = "cyborg_upgrade3"
origin_tech = "combat=4;syndicate=1"
- require_module = 1
+ require_module = TRUE
/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R)
if(..())
return
-
if(R.emagged)
return
-
if(R.weapons_unlock)
to_chat(R, "Internal diagnostic error: incompatible upgrade module detected.");
return
-
R.emagged = 1
+ return TRUE
- return 1
+/obj/item/borg/upgrade/lavaproof
+ name = "mining cyborg lavaproof chassis"
+ desc = "An upgrade kit to apply specialized coolant systems and insulation layers to a mining cyborg's chassis, enabling them to withstand exposure to molten rock."
+ icon_state = "ash_plating"
+ resistance_flags = LAVA_PROOF | FIRE_PROOF
+ require_module = TRUE
+ module_type = /obj/item/robot_module/miner
+
+/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+ if(istype(R))
+ R.weather_immunities += "lava"
+ return TRUE
/obj/item/borg/upgrade/selfrepair
name = "self-repair module"
desc = "This module will repair the cyborg over time."
icon_state = "cyborg_upgrade5"
- require_module = 1
+ require_module = TRUE
var/repair_amount = -1
var/repair_tick = 1
var/msg_cooldown = 0
@@ -230,7 +241,7 @@
icon_state = "selfrepair_off"
var/datum/action/A = new /datum/action/item_action/toggle(src)
A.Grant(R)
- return 1
+ return TRUE
/obj/item/borg/upgrade/selfrepair/Destroy()
cyborg = null
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 8b85d8821d9..9b24b1efce6 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -4,24 +4,23 @@
desc = "A shooting target."
icon = 'icons/obj/objects.dmi'
icon_state = "target_h"
- density = 0
+ density = FALSE
var/hp = 1800
- var/icon/virtualIcon
- var/list/bulletholes = list()
/obj/item/target/Destroy()
+ cut_overlays()
// if a target is deleted and associated with a stake, force stake to forget
- for(var/obj/structure/target_stake/T in view(3,src))
+ for(var/obj/structure/target_stake/T in view(3, src))
if(T.pinned_target == src)
T.pinned_target = null
- T.density = 1
+ T.density = TRUE
break
return ..() // delete target
/obj/item/target/Move()
..()
// After target moves, check for nearby stakes. If associated, move to target
- for(var/obj/structure/target_stake/M in view(3,src))
+ for(var/obj/structure/target_stake/M in view(3, src))
if(M.density == 0 && M.pinned_target == src)
M.loc = loc
@@ -33,12 +32,12 @@
/obj/item/target/welder_act(mob/user, obj/item/I)
. = TRUE
- if(!use_tool(src, user, 0,, volume = I.tool_volume))
+ if(!use_tool(src, user, 0, volume = I.tool_volume))
return
overlays.Cut()
- to_chat(usr, "You slice off [src]'s uneven chunks of aluminum and scorch marks.")
+ to_chat(user, "You slice off [src]'s uneven chunks of aluminium and scorch marks.")
-/obj/item/target/attack_hand(mob/user as mob)
+/obj/item/target/attack_hand(mob/user)
// taking pinned targets off!
var/obj/structure/target_stake/stake
for(var/obj/structure/target_stake/T in view(3,src))
@@ -48,8 +47,8 @@
if(stake)
if(stake.pinned_target)
- stake.density = 1
- density = 0
+ stake.density = TRUE
+ density = FALSE
layer = OBJ_LAYER
loc = user.loc
@@ -77,101 +76,37 @@
desc = "A shooting target that looks like a xenomorphic alien."
hp = 2350 // alium onest too kinda
-/obj/item/target/bullet_act(var/obj/item/projectile/Proj)
- var/p_x = Proj.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset Proj.p_x!"
- var/p_y = Proj.p_y + pick(0,0,0,0,0,-1,1)
- var/decaltype = 1 // 1 - scorch, 2 - bullet
+#define DECALTYPE_SCORCH 1
+#define DECALTYPE_BULLET 2
- if(istype(/obj/item/projectile/bullet, Proj))
- decaltype = 2
+/obj/item/target/bullet_act(obj/item/projectile/P)
+ var/p_x = P.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset P.p_x!"
+ var/p_y = P.p_y + pick(0,0,0,0,0,-1,1)
+ var/decaltype = DECALTYPE_SCORCH
+ if(istype(P, /obj/item/projectile/bullet))
+ decaltype = DECALTYPE_BULLET
-
- virtualIcon = new(icon, icon_state)
-
- if( virtualIcon.GetPixel(p_x, p_y) ) // if the located pixel isn't blank (null)
-
- hp -= Proj.damage
+ var/icon/C = icon(icon, icon_state)
+ if(LAZYLEN(overlays) <= 35 && C.GetPixel(p_x, p_y)) // if the located pixel isn't blank (null)
+ hp -= P.damage
if(hp <= 0)
- visible_message("[src] breaks into tiny pieces and collapses!")
+ visible_message("[src] breaks into tiny pieces and collapses!")
qdel(src)
-
- // Create a temporary object to represent the damage
- var/obj/bmark = new
- bmark.pixel_x = p_x
- bmark.pixel_y = p_y
- bmark.icon = 'icons/effects/effects.dmi'
- bmark.layer = 3.5
- bmark.icon_state = "scorch"
-
- if(decaltype == 1)
- // Energy weapons are hot. they scorch!
-
- // offset correction
- bmark.pixel_x--
- bmark.pixel_y--
-
- if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/beam/practice))
- bmark.icon_state = "scorch"
- bmark.dir = pick(NORTH,SOUTH,EAST,WEST) // random scorch design
-
-
+ return
+ var/image/bullet_hole = image('icons/effects/effects.dmi', "scorch", OBJ_LAYER + 0.5)
+ bullet_hole.pixel_x = p_x - 1 //offset correction
+ bullet_hole.pixel_y = p_y - 1
+ if(decaltype == DECALTYPE_SCORCH)
+ if(P.damage >= 20 || istype(P, /obj/item/projectile/beam/practice))
+ bullet_hole.setDir(pick(NORTH,SOUTH,EAST,WEST))// random scorch design. light_scorch does not have different directions
else
- bmark.icon_state = "light_scorch"
+ bullet_hole.icon_state = "light_scorch"
else
-
- // Bullets are hard. They make dents!
- bmark.icon_state = "dent"
-
- if(Proj.damage >= 10 && bulletholes.len <= 35) // maximum of 35 bullet holes
- if(decaltype == 2) // bullet
- if(prob(Proj.damage+30)) // bullets make holes more commonly!
- new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole
- else // Lasers!
- if(prob(Proj.damage-10)) // lasers make holes less commonly
- new/datum/bullethole(src, bmark.pixel_x, bmark.pixel_y) // create new bullet hole
-
- // draw bullet holes
- for(var/datum/bullethole/B in bulletholes)
-
- virtualIcon.DrawBox(null, B.b1x1, B.b1y, B.b1x2, B.b1y) // horizontal line, left to right
- virtualIcon.DrawBox(null, B.b2x, B.b2y1, B.b2x, B.b2y2) // vertical line, top to bottom
-
- overlays += bmark // add the decal
-
- icon = virtualIcon // apply bulletholes over decals
-
+ bullet_hole.icon_state = "dent"
+ add_overlay(bullet_hole)
return
return -1 // the bullet/projectile goes through the target! Ie, you missed
-
-// Small memory holder entity for transparent bullet holes
-/datum/bullethole
- // First box
- var/b1x1 = 0
- var/b1x2 = 0
- var/b1y = 0
-
- // Second box
- var/b2x = 0
- var/b2y1 = 0
- var/b2y2 = 0
-
-/datum/bullethole/New(obj/item/target/Target, pixel_x = 0, pixel_y = 0)
- if(!Target) return
-
- // Randomize the first box
- b1x1 = pixel_x - pick(1,1,1,1,2,2,3,3,4)
- b1x2 = pixel_x + pick(1,1,1,1,2,2,3,3,4)
- b1y = pixel_y
- if(prob(35))
- b1y += rand(-4,4)
-
- // Randomize the second box
- b2x = pixel_x
- if(prob(35))
- b2x += rand(-4,4)
- b2y1 = pixel_y + pick(1,1,1,1,2,2,3,3,4)
- b2y2 = pixel_y - pick(1,1,1,1,2,2,3,3,4)
-
- Target.bulletholes.Add(src)
+#undef DECALTYPE_SCORCH
+#undef DECALTYPE_BULLET
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index 708070e1478..ff469ba3c59 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -57,7 +57,7 @@
E.heal_damage(0, remheal, 0, 1) //Healing Burn
remheal = nremheal
user.visible_message("\The [user] applies some nanite paste at \the [M]'s [E.name] with \the [src].")
- if(H.bleed_rate && H.isSynthetic())
+ if(H.bleed_rate && ismachineperson(H))
H.bleed_rate = 0
else
to_chat(user, "Nothing to fix here.")
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 5fc457dae62..6bdfdd49234 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -169,9 +169,9 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
return
if(is_type_in_typecache(target, goliath_platable_armor_typecache))
var/obj/item/clothing/C = target
- var/list/current_armor = C.armor
- if(current_armor["melee"] < 60)
- current_armor["melee"] = min(current_armor["melee"] + 10, 60)
+ var/datum/armor/current_armor = C.armor
+ if(current_armor.getRating("melee") < 60)
+ C.armor = current_armor.setRating(melee_value = min(current_armor.getRating("melee") + 10, 60))
to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
use(1)
else
@@ -180,9 +180,9 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
var/obj/mecha/working/ripley/D = target
if(D.hides < 3)
D.hides++
- D.armor["melee"] = min(D.armor["melee"] + 10, 70)
- D.armor["bullet"] = min(D.armor["bullet"] + 5, 50)
- D.armor["laser"] = min(D.armor["laser"] + 5, 50)
+ D.armor = D.armor.setRating(melee_value = min(D.armor.getRating("melee") + 10, 70))
+ D.armor = D.armor.setRating(bullet_value = min(D.armor.getRating("bullet") + 5, 50))
+ D.armor = D.armor.setRating(laser_value = min(D.armor.getRating("laser") + 5, 50))
to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
D.update_icon()
if(D.hides == 3)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 14ccc103ab1..ab592cc0402 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -204,7 +204,7 @@
if(amount < 1) // Just in case a stack's amount ends up fractional somehow
var/oldsrc = src
- src = null //dont kill proc after del()
+ src = null //dont kill proc after qdel()
usr.unEquip(oldsrc, 1)
qdel(oldsrc)
if(istype(O, /obj/item))
diff --git a/code/game/objects/items/tools/tool_behaviour.dm b/code/game/objects/items/tools/tool_behaviour.dm
index 986e3a981b2..136bea77e6a 100644
--- a/code/game/objects/items/tools/tool_behaviour.dm
+++ b/code/game/objects/items/tools/tool_behaviour.dm
@@ -4,7 +4,7 @@
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
// Run the start check here so we wouldn't have to call it manually.
target.add_fingerprint(user)
- if(!tool_start_check(user, amount) && !delay)
+ if(!tool_start_check(target, user, amount) && !delay)
return
delay *= toolspeed
@@ -39,7 +39,7 @@
// Called before use_tool if there is a delay, or by use_tool if there isn't.
// Only ever used by welding tools and stacks, so it's not added on any other use_tool checks.
-/obj/item/proc/tool_start_check(mob/living/user, amount=0)
+/obj/item/proc/tool_start_check(atom/target, mob/living/user, amount=0)
return tool_use_check(user, amount)
// A check called by tool_start_check once, and by use_tool on every tick of delay.
diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm
index 49f5bb4073b..4ac934462a0 100644
--- a/code/game/objects/items/tools/welder.dm
+++ b/code/game/objects/items/tools/welder.dm
@@ -108,9 +108,9 @@
return FALSE
// When welding is about to start, run a normal tool_use_check, then flash a mob if it succeeds.
-/obj/item/weldingtool/tool_start_check(mob/living/user, amount=0)
+/obj/item/weldingtool/tool_start_check(atom/target, mob/living/user, amount=0)
. = tool_use_check(user, amount)
- if(. && user)
+ if(. && user && !ismob(target)) // Don't flash the user if they're repairing robo limbs or repairing a borg etc. Only flash them if the target is an object
user.flash_eyes(light_intensity)
/obj/item/weldingtool/use(amount)
@@ -167,7 +167,7 @@
/obj/item/weldingtool/update_icon()
if(low_fuel_changes_icon)
var/ratio = GET_FUEL / maximum_fuel
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
if(ratio == 100)
icon_state = initial(icon_state)
else
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 85d664d4e08..66f35a169f9 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1023,6 +1023,18 @@ obj/item/toy/cards/deck/syndicate/black
name = "orange fox plushie"
icon_state = "orangefox"
+/obj/item/toy/plushie/orange_fox/grump
+ name = "grumpy fox"
+ desc = "An ancient plushie that seems particularly grumpy."
+
+/obj/item/toy/plushie/orange_fox/grump/ComponentInitialize()
+ . = ..()
+ var/static/list/grumps = list("Ahh, yes, you're so clever, var editing that.", "Really?", "If you make a runtime with var edits, it's your own damn fault.",
+ "Don't you dare post issues on the git when you don't even know how this works.", "Was that necessary?", "Ohhh, setting admin edited var must be your favorite pastime!",
+ "Oh, so you have time to var edit, but you don't have time to ban that greytider?", "Oh boy, is this another one of those 'events'?", "Seriously, just stop.", "You do realize this is incurring proc call overhead.",
+ "Congrats, you just left a reference with your dirty client and now that thing you edited will never garbage collect properly.", "Is it that time of day, again, for unecessary adminbus?")
+ AddComponent(/datum/component/edit_complainer, grumps)
+
/obj/item/toy/plushie/coffee_fox
name = "coffee fox plushie"
icon_state = "coffeefox"
@@ -1086,7 +1098,7 @@ obj/item/toy/cards/deck/syndicate/black
spawn(30) cooldown = 0
return
..()
-
+
/obj/item/toy/plushie/ipcplushie
name = "IPC plushie"
desc = "An adorable IPC plushie, straight from New Canaan. Arguably more durable than the real deal. Toaster functionality included."
@@ -1099,7 +1111,7 @@ obj/item/toy/cards/deck/syndicate/black
to_chat(user, " You insert bread into the toaster. ")
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
qdel(B)
- else
+ else
return ..()
//New generation TG plushies
@@ -1132,15 +1144,15 @@ obj/item/toy/cards/deck/syndicate/black
* Foam Armblade
*/
- /obj/item/toy/foamblade
- name = "foam armblade"
- desc = "it says \"Sternside Changs #1 fan\" on it. "
- icon = 'icons/obj/toy.dmi'
- icon_state = "foamblade"
- item_state = "arm_blade"
- attack_verb = list("pricked", "absorbed", "gored")
- w_class = WEIGHT_CLASS_SMALL
- resistance_flags = FLAMMABLE
+/obj/item/toy/foamblade
+ name = "foam armblade"
+ desc = "it says \"Sternside Changs #1 fan\" on it. "
+ icon = 'icons/obj/toy.dmi'
+ icon_state = "foamblade"
+ item_state = "arm_blade"
+ attack_verb = list("pricked", "absorbed", "gored")
+ w_class = WEIGHT_CLASS_SMALL
+ resistance_flags = FLAMMABLE
/*
* Toy/fake flash
@@ -1235,7 +1247,6 @@ obj/item/toy/cards/deck/syndicate/black
spawn(20)
cooldown = FALSE
return
- ..()
/obj/item/toy/owl
name = "owl action figure"
@@ -1397,6 +1408,7 @@ obj/item/toy/cards/deck/syndicate/black
name = "xenomorph action figure"
desc = "MEGA presents the new Xenos Isolated action figure! Comes complete with realistic sounds! Pull back string to use."
w_class = WEIGHT_CLASS_SMALL
+ bubble_icon = "alien"
var/cooldown = 0
/obj/item/toy/toy_xeno/attack_self(mob/user)
@@ -1405,7 +1417,7 @@ obj/item/toy/cards/deck/syndicate/black
user.visible_message("[user] pulls back the string on [src].")
icon_state = "[initial(icon_state)]_used"
sleep(5)
- audible_message("[bicon(src)] Hiss!")
+ atom_say("Hiss!")
var/list/possible_sounds = list('sound/voice/hiss1.ogg', 'sound/voice/hiss2.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss4.ogg')
playsound(get_turf(src), pick(possible_sounds), 50, 1)
spawn(45)
diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm
index d6397025424..f8f9a48102a 100644
--- a/code/game/objects/items/weapons/RCD.dm
+++ b/code/game/objects/items/weapons/RCD.dm
@@ -477,9 +477,7 @@ GLOBAL_LIST_INIT(rcd_door_types, list(
return R.cell.charge >= (amount * use_multiplier)
/obj/item/rcd/proc/detonate_pulse()
- audible_message("[src] begins to vibrate and \
- buzz loudly!","[src] begins \
- vibrating violently!")
+ audible_message("[src] begins to vibrate and buzz loudly!", "[src] begins vibrating violently!")
// 5 seconds to get rid of it
addtimer(CALLBACK(src, .proc/detonate_pulse_explode), 50)
diff --git a/code/game/objects/items/weapons/chrono_eraser.dm b/code/game/objects/items/weapons/chrono_eraser.dm
index bf46343b963..1dc0b22abdf 100644
--- a/code/game/objects/items/weapons/chrono_eraser.dm
+++ b/code/game/objects/items/weapons/chrono_eraser.dm
@@ -188,7 +188,7 @@
/obj/structure/chrono_field/update_icon()
var/ttk_frame = 1 - (tickstokill / initial(tickstokill))
- ttk_frame = Clamp(Ceiling(ttk_frame * CHRONO_FRAME_COUNT), 1, CHRONO_FRAME_COUNT)
+ ttk_frame = clamp(CEILING(ttk_frame * CHRONO_FRAME_COUNT, 1), 1, CHRONO_FRAME_COUNT)
if(ttk_frame != RPpos)
RPpos = ttk_frame
mob_underlay.icon_state = "frame[RPpos]"
diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm
index 581c4395650..ee98d309876 100644
--- a/code/game/objects/items/weapons/defib.dm
+++ b/code/game/objects/items/weapons/defib.dm
@@ -72,7 +72,7 @@
if(powered) //so it doesn't show charge if it's unpowered
if(cell)
var/ratio = cell.charge / cell.maxcharge
- ratio = Ceiling(ratio*4) * 25
+ ratio = CEILING(ratio*4, 1) * 25
overlays += "[icon_state]-charge[ratio]"
/obj/item/defibrillator/CheckParts(list/parts_list)
diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm
index bc6a98a9b1f..629942860be 100644
--- a/code/game/objects/items/weapons/dice.dm
+++ b/code/game/objects/items/weapons/dice.dm
@@ -138,7 +138,7 @@
/obj/item/dice/proc/diceroll(mob/user)
result = roll(sides)
if(rigged != DICE_NOT_RIGGED && result != rigged_value)
- if(rigged == DICE_BASICALLY_RIGGED && prob(Clamp(1/(sides - 1) * 100, 25, 80)))
+ if(rigged == DICE_BASICALLY_RIGGED && prob(clamp(1/(sides - 1) * 100, 25, 80)))
result = rigged_value
else if(rigged == DICE_TOTALLY_RIGGED)
result = rigged_value
diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm
index 8f11f65fe71..45047e97156 100644
--- a/code/game/objects/items/weapons/dna_injector.dm
+++ b/code/game/objects/items/weapons/dna_injector.dm
@@ -147,10 +147,6 @@
to_chat(user, "You inject yourself with [src].")
add_attack_logs(user, M, attack_log, ATKLOG_ALL)
- if(!iscarbon(user))
- M.LAssailant = null
- else
- M.LAssailant = user
inject(M, user)
used = TRUE
diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm
index 5c69a59aba9..9584130c0c6 100644
--- a/code/game/objects/items/weapons/explosives.dm
+++ b/code/game/objects/items/weapons/explosives.dm
@@ -62,7 +62,7 @@
return
var/newtime = input(usr, "Please set the timer.", "Timer", det_time) as num
if(user.is_in_active_hand(src))
- newtime = Clamp(newtime, 10, 60000)
+ newtime = clamp(newtime, 10, 60000)
det_time = newtime
to_chat(user, "Timer set for [det_time] seconds.")
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 006de63af17..f6fb213b353 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -6,7 +6,7 @@
var/list/nemesis_factions //Any mob with a faction that exists in this list will take bonus damage/effects
w_class = WEIGHT_CLASS_SMALL
var/w_class_on = WEIGHT_CLASS_BULKY
- var/icon_state_on = "axe1"
+ var/icon_state_on
var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/blade1.ogg' // Probably more appropriate than the previous hitsound. -- Dave
usesound = 'sound/weapons/blade1.ogg'
@@ -48,9 +48,9 @@
throw_speed = 4
if(attack_verb_on.len)
attack_verb = attack_verb_on
- if(!item_color)
+ if(icon_state_on)
icon_state = icon_state_on
- set_light(brightness_on)
+ set_light(brightness_on, l_color = item_color ? colormap[item_color] : null)
else
icon_state = "sword[item_color]"
set_light(brightness_on, l_color=colormap[item_color])
@@ -80,6 +80,7 @@
name = "energy axe"
desc = "An energised battle axe."
icon_state = "axe0"
+ icon_state_on = "axe1"
force = 40
force_on = 150
throwforce = 25
@@ -301,9 +302,9 @@
throw_speed = 4
if(attack_verb_on.len)
attack_verb = attack_verb_on
- if(!item_color)
+ if(icon_state_on)
icon_state = icon_state_on
- set_light(brightness_on)
+ set_light(brightness_on, l_color = item_color ? colormap[item_color] : null)
else
icon_state = "sword[item_color]"
set_light(brightness_on, l_color=colormap[item_color])
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index 66288713775..4a449069d4c 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -33,9 +33,11 @@
icon_state = "trashbag"
item_state = "trashbag"
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_BULKY
max_w_class = WEIGHT_CLASS_SMALL
+ slot_flags = null
storage_slots = 30
+ max_combined_w_class = 30
can_hold = list() // any
cant_hold = list(/obj/item/disk/nuclear)
@@ -45,18 +47,15 @@
return TOXLOSS
/obj/item/storage/bag/trash/update_icon()
- if(contents.len == 0)
- w_class = WEIGHT_CLASS_TINY
- icon_state = "[initial(icon_state)]"
- else if(contents.len < 12)
- w_class = WEIGHT_CLASS_BULKY
- icon_state = "[initial(icon_state)]1"
- else if(contents.len < 21)
- w_class = WEIGHT_CLASS_BULKY
- icon_state = "[initial(icon_state)]2"
- else
- w_class = WEIGHT_CLASS_BULKY
- icon_state = "[initial(icon_state)]3"
+ switch(contents.len)
+ if(20 to INFINITY)
+ icon_state = "[initial(icon_state)]3"
+ if(11 to 20)
+ icon_state = "[initial(icon_state)]2"
+ if(1 to 11)
+ icon_state = "[initial(icon_state)]1"
+ else
+ icon_state = "[initial(icon_state)]"
/obj/item/storage/bag/trash/cyborg
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index f965907c5ba..6cf011bc2c3 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -121,19 +121,6 @@
desc = "A sleek, sturdy box"
icon_state = "box_of_doom"
-/obj/item/storage/box/syndie_kit/romerol
- name = "Romerol Kit"
- desc = "A box containing a deadly virus capable of reanimating dead as zombies."
- max_w_class = WEIGHT_CLASS_NORMAL
- can_hold = list(/obj/item/reagent_containers/glass/bottle/romerol,/obj/item/reagent_containers/syringe,/obj/item/reagent_containers/dropper)
-
-/obj/item/storage/box/syndie_kit/romerol/New()
- ..()
- new /obj/item/reagent_containers/glass/bottle/romerol(src)
- new /obj/item/reagent_containers/syringe(src)
- new /obj/item/reagent_containers/dropper(src)
- return
-
/obj/item/storage/box/syndie_kit/space
name = "Boxed Space Suit and Helmet"
can_hold = list(/obj/item/clothing/suit/space/syndicate/black/red, /obj/item/clothing/head/helmet/space/syndicate/black/red, /obj/item/tank/emergency_oxygen/syndi, /obj/item/clothing/mask/gas/syndicate)
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 6782057d928..a39050cba47 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -189,8 +189,8 @@
L.apply_effect(STUTTER, stunforce)
if(user)
- user.lastattacked = L
- L.lastattacker = user
+ L.lastattacker = user.real_name
+ L.lastattackerckey = user.ckey
L.visible_message("[user] has stunned [L] with [src]!", \
"[user] has stunned you with [src]!")
add_attack_logs(user, L, "stunned")
diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm
index 11355b34170..a82d6c0c223 100644
--- a/code/game/objects/items/weapons/tanks/tank_types.dm
+++ b/code/game/objects/items/weapons/tanks/tank_types.dm
@@ -53,13 +53,8 @@ obj/item/tank/oxygen/empty/New()
/obj/item/tank/anesthetic/New()
..()
-
- air_contents.oxygen = (3*ONE_ATMOSPHERE)*70/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD
-
- var/datum/gas/sleeping_agent/trace_gas = new()
- trace_gas.moles = (3*ONE_ATMOSPHERE)*70/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD
-
- air_contents.trace_gases += trace_gas
+ air_contents.oxygen = (3 * ONE_ATMOSPHERE) * 70 / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD
+ air_contents.sleeping_agent = (3 * ONE_ATMOSPHERE) * 70 / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD
/*
* Air
diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm
index 4ac9651ea65..33aeddeaab0 100644
--- a/code/game/objects/items/weapons/teleportation.dm
+++ b/code/game/objects/items/weapons/teleportation.dm
@@ -115,7 +115,7 @@ Frequency:
to_chat(user, "\The [src] is malfunctioning.")
return
var/list/L = list( )
- for(var/obj/machinery/computer/teleporter/com in world)
+ for(var/obj/machinery/computer/teleporter/com in GLOB.machines)
if(com.target)
if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged)
L["[com.id] (Active)"] = com.target
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
deleted file mode 100644
index 012fcf79b10..00000000000
--- a/code/game/objects/items/weapons/tools.dm
+++ /dev/null
@@ -1,785 +0,0 @@
-#define HEALPERWELD 15
-
-/* Tools!
- * Note: Multitools are in devices
- *
- * Contains:
- * Wrench
- * Screwdriver
- * Wirecutters
- * Welding Tool
- * Crowbar
- * Revolver Conversion Kit
- */
-
-//Wrench
-/obj/item/wrench
- name = "wrench"
- desc = "A wrench with common uses. Can be found in your hand."
- icon = 'icons/obj/tools.dmi'
- icon_state = "wrench"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- force = 5
- throwforce = 7
- usesound = 'sound/items/ratchet.ogg'
- w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=150)
- origin_tech = "materials=1;engineering=1"
- attack_verb = list("bashed", "battered", "bludgeoned", "whacked")
- toolspeed = 1
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
-
-/obj/item/wrench/suicide_act(mob/user)
- user.visible_message("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
- return BRUTELOSS
-
-/obj/item/wrench/cyborg
- name = "automatic wrench"
- desc = "An advanced robotic wrench. Can be found in construction cyborgs."
- toolspeed = 0.5
-
-/obj/item/wrench/brass
- name = "brass wrench"
- desc = "A brass wrench. It's faintly warm to the touch."
- icon_state = "wrench_brass"
- toolspeed = 0.5
- resistance_flags = FIRE_PROOF | ACID_PROOF
-
-/obj/item/wrench/abductor
- name = "alien wrench"
- desc = "A polarized wrench. It causes anything placed between the jaws to turn."
- icon = 'icons/obj/abductor.dmi'
- icon_state = "wrench"
- usesound = 'sound/effects/empulse.ogg'
- toolspeed = 0.1
- origin_tech = "materials=5;engineering=5;abductor=3"
-
-/obj/item/wrench/power
- name = "hand drill"
- desc = "A simple powered drill with a bolt bit."
- icon_state = "drill_bolt"
- item_state = "drill"
- usesound = 'sound/items/drill_use.ogg'
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
- origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get
- force = 8 //might or might not be too high, subject to change
- throwforce = 8
- attack_verb = list("drilled", "screwed", "jabbed")
- toolspeed = 0.25
-
-/obj/item/wrench/power/attack_self(mob/user)
- playsound(get_turf(user),'sound/items/change_drill.ogg', 50, 1)
- var/obj/item/wirecutters/power/s_drill = new /obj/item/screwdriver/power
- to_chat(user, "You attach the screwdriver bit to [src].")
- qdel(src)
- user.put_in_active_hand(s_drill)
-
-/obj/item/wrench/power/suicide_act(mob/user)
- user.visible_message("[user] is pressing [src] against [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/wrench/medical
- name = "medical wrench"
- desc = "A medical wrench with common (medical?) uses. Can be found in your hand."
- icon_state = "wrench_medical"
- force = 2 //MEDICAL
- throwforce = 4
- origin_tech = "materials=1;engineering=1;biotech=3"
- attack_verb = list("wrenched", "medicaled", "tapped", "jabbed", "whacked")
-
-/obj/item/wrench/medical/suicide_act(mob/user)
- user.visible_message("[user] is praying to the medical wrench to take [user.p_their()] soul. It looks like [user.p_theyre()] trying to commit suicide!")
- // TODO Make them glow with the power of the M E D I C A L W R E N C H
- // during their ascension
-
- // Stun stops them from wandering off
- user.Stun(5)
- playsound(loc, 'sound/effects/pray.ogg', 50, 1, -1)
-
- // Let the sound effect finish playing
- sleep(20)
-
- if(!user)
- return
-
- for(var/obj/item/W in user)
- user.unEquip(W)
-
- var/obj/item/wrench/medical/W = new /obj/item/wrench/medical(loc)
- W.add_fingerprint(user)
- W.desc += " For some reason, it reminds you of [user.name]."
-
- if(!user)
- return
-
- user.dust()
- return OBLITERATION
-
-//Screwdriver
-/obj/item/screwdriver
- name = "screwdriver"
- desc = "You can be totally screwy with this."
- icon = 'icons/obj/tools.dmi'
- icon_state = "screwdriver_map"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- force = 5
- w_class = WEIGHT_CLASS_TINY
- throwforce = 5
- throw_speed = 3
- throw_range = 5
- materials = list(MAT_METAL=75)
- attack_verb = list("stabbed")
- hitsound = 'sound/weapons/bladeslice.ogg'
- usesound = 'sound/items/screwdriver.ogg'
- toolspeed = 1
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
- var/random_color = TRUE //if the screwdriver uses random coloring
-
-/obj/item/screwdriver/nuke
- name = "screwdriver"
- desc = "A screwdriver with an ultra thin tip."
- icon_state = "screwdriver_nuke"
- toolspeed = 0.5
-
-/obj/item/screwdriver/suicide_act(mob/user)
- user.visible_message("[user] is stabbing [src] into [user.p_their()] [pick("temple", "heart")]! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/screwdriver/New(loc, var/param_color = null)
- ..()
- if(random_color)
- if(!param_color)
- param_color = pick("red","blue","pink","brown","green","cyan","yellow")
- icon_state = "screwdriver_[param_color]"
-
- if (prob(75))
- src.pixel_y = rand(0, 16)
-
-/obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(!istype(M) || user.a_intent == INTENT_HELP)
- return ..()
- if(user.zone_selected != "eyes" && user.zone_selected != "head")
- return ..()
- if(HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to harm [M]!")
- return
- if((CLUMSY in user.mutations) && prob(50))
- M = user
- return eyestab(M,user)
-
-/obj/item/screwdriver/brass
- name = "brass screwdriver"
- desc = "A screwdriver made of brass. The handle feels freezing cold."
- icon_state = "screwdriver_brass"
- toolspeed = 0.5
- random_color = FALSE
- resistance_flags = FIRE_PROOF | ACID_PROOF
-
-/obj/item/screwdriver/abductor
- name = "alien screwdriver"
- desc = "An ultrasonic screwdriver."
- icon = 'icons/obj/abductor.dmi'
- icon_state = "screwdriver"
- usesound = 'sound/items/pshoom.ogg'
- toolspeed = 0.1
- random_color = FALSE
-
-/obj/item/screwdriver/power
- name = "hand drill"
- desc = "A simple hand drill with a screwdriver bit attached."
- icon_state = "drill_screw"
- item_state = "drill"
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
- origin_tech = "materials=2;engineering=2" //done for balance reasons, making them high value for research, but harder to get
- force = 8 //might or might not be too high, subject to change
- throwforce = 8
- throw_speed = 2
- throw_range = 3//it's heavier than a screw driver/wrench, so it does more damage, but can't be thrown as far
- attack_verb = list("drilled", "screwed", "jabbed","whacked")
- hitsound = 'sound/items/drill_hit.ogg'
- usesound = 'sound/items/drill_use.ogg'
- toolspeed = 0.25
- random_color = FALSE
-
-/obj/item/screwdriver/power/suicide_act(mob/user)
- user.visible_message("[user] is putting [src] to [user.p_their()] temple. It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/screwdriver/power/attack_self(mob/user)
- playsound(get_turf(user), 'sound/items/change_drill.ogg', 50, 1)
- var/obj/item/wrench/power/b_drill = new /obj/item/wrench/power
- to_chat(user, "You attach the bolt driver bit to [src].")
- qdel(src)
- user.put_in_active_hand(b_drill)
-
-/obj/item/screwdriver/cyborg
- name = "powered screwdriver"
- desc = "An electrical screwdriver, designed to be both precise and quick."
- usesound = 'sound/items/drill_use.ogg'
- toolspeed = 0.5
-
-//Wirecutters
-/obj/item/wirecutters
- name = "wirecutters"
- desc = "This cuts wires."
- icon = 'icons/obj/tools.dmi'
- icon_state = "cutters"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- force = 6
- throw_speed = 3
- throw_range = 7
- w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=80)
- origin_tech = "materials=1;engineering=1"
- attack_verb = list("pinched", "nipped")
- hitsound = 'sound/items/wirecutter.ogg'
- usesound = 'sound/items/wirecutter.ogg'
- sharp = 1
- toolspeed = 1
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
- var/random_color = TRUE
-
-/obj/item/wirecutters/New(loc, param_color = null)
- ..()
- if(random_color)
- if(!param_color)
- param_color = pick("yellow", "red")
- icon_state = "cutters_[param_color]"
-
-/obj/item/wirecutters/attack(mob/living/carbon/C, mob/user)
- if(istype(C) && C.handcuffed && istype(C.handcuffed, /obj/item/restraints/handcuffs/cable))
- user.visible_message("[user] cuts [C]'s restraints with [src]!")
- QDEL_NULL(C.handcuffed)
- if(C.buckled && C.buckled.buckle_requires_restraints)
- C.buckled.unbuckle_mob(C)
- C.update_handcuffed()
- return
- else
- ..()
-
-/obj/item/wirecutters/suicide_act(mob/user)
- user.visible_message("[user] is cutting at [user.p_their()] arteries with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(loc, usesound, 50, 1, -1)
- return BRUTELOSS
-
-/obj/item/wirecutters/brass
- name = "brass wirecutters"
- desc = "A pair of wirecutters made of brass. The handle feels freezing cold to the touch."
- icon_state = "cutters_brass"
- toolspeed = 0.5
- random_color = FALSE
- resistance_flags = FIRE_PROOF | ACID_PROOF
-
-/obj/item/wirecutters/abductor
- name = "alien wirecutters"
- desc = "Extremely sharp wirecutters, made out of a silvery-green metal."
- icon = 'icons/obj/abductor.dmi'
- icon_state = "cutters"
- toolspeed = 0.1
- origin_tech = "materials=5;engineering=4;abductor=3"
- random_color = FALSE
-
-/obj/item/wirecutters/cyborg
- name = "wirecutters"
- desc = "This cuts wires."
- toolspeed = 0.5
-
-/obj/item/wirecutters/power
- name = "jaws of life"
- desc = "A set of jaws of life, the magic of science has managed to fit it down into a device small enough to fit in a tool belt. It's fitted with a cutting head."
- icon_state = "jaws_cutter"
- item_state = "jawsoflife"
- origin_tech = "materials=2;engineering=2"
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
- usesound = 'sound/items/jaws_cut.ogg'
- toolspeed = 0.25
- random_color = FALSE
-
-/obj/item/wirecutters/power/suicide_act(mob/user)
- user.visible_message("[user] is wrapping \the [src] around [user.p_their()] neck. It looks like [user.p_theyre()] trying to rip [user.p_their()] head off!")
- playsound(loc, 'sound/items/jaws_cut.ogg', 50, 1, -1)
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- var/obj/item/organ/external/head/head = H.bodyparts_by_name["head"]
- if(head)
- head.droplimb(0, DROPLIMB_BLUNT, FALSE, TRUE)
- playsound(loc,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
- return BRUTELOSS
-
-/obj/item/wirecutters/power/attack_self(mob/user)
- playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1)
- var/obj/item/crowbar/power/pryjaws = new /obj/item/crowbar/power
- to_chat(user, "You attach the pry jaws to [src].")
- qdel(src)
- user.put_in_active_hand(pryjaws)
-
-//Welding Tool
-/obj/item/weldingtool
- name = "welding tool"
- desc = "A standard edition welder provided by Nanotrasen."
- icon = 'icons/obj/tools.dmi'
- icon_state = "welder"
- item_state = "welder"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- force = 3
- throwforce = 5
- throw_speed = 3
- throw_range = 5
- hitsound = "swing_hit"
- usesound = 'sound/items/welder.ogg'
- var/acti_sound = 'sound/items/welderactivate.ogg'
- var/deac_sound = 'sound/items/welderdeactivate.ogg'
- w_class = WEIGHT_CLASS_SMALL
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
- resistance_flags = FIRE_PROOF
- materials = list(MAT_METAL=70, MAT_GLASS=30)
- origin_tech = "engineering=1;plasmatech=1"
- toolspeed = 1
- var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
- var/status = 1 //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower)
- var/max_fuel = 20 //The max amount of fuel the welder can hold
- var/change_icons = 1
- var/can_off_process = 0
- var/light_intensity = 2 //how powerful the emitted light is when used.
- var/nextrefueltick = 0
-
-/obj/item/weldingtool/New()
- ..()
- create_reagents(max_fuel)
- reagents.add_reagent("fuel", max_fuel)
- update_icon()
-
-/obj/item/weldingtool/examine(mob/user)
- . = ..()
- if(get_dist(user, src) <= 0)
- . += "It contains [get_fuel()] unit\s of fuel out of [max_fuel]."
-
-/obj/item/weldingtool/suicide_act(mob/user)
- user.visible_message("[user] welds [user.p_their()] every orifice closed! It looks like [user.p_theyre()] trying to commit suicide!")
- return FIRELOSS
-
-/obj/item/weldingtool/proc/update_torch()
- overlays.Cut()
- if(welding)
- overlays += "[initial(icon_state)]-on"
- item_state = "[initial(item_state)]1"
- else
- item_state = "[initial(item_state)]"
-
-/obj/item/weldingtool/update_icon()
- if(change_icons)
- var/ratio = get_fuel() / max_fuel
- ratio = Ceiling(ratio*4) * 25
- if(ratio == 100)
- icon_state = initial(icon_state)
- else
- icon_state = "[initial(icon_state)][ratio]"
- update_torch()
- ..()
-
-/obj/item/weldingtool/process()
- switch(welding)
- if(0)
- force = 3
- damtype = "brute"
- update_icon()
- if(!can_off_process)
- STOP_PROCESSING(SSobj, src)
- return
- //Welders left on now use up fuel, but lets not have them run out quite that fast
- if(1)
- force = 15
- damtype = "fire"
- if(prob(5))
- remove_fuel(1)
- update_icon()
-
- //This is to start fires. process() is only called if the welder is on.
- var/turf/location = loc
- if(ismob(location))
- var/mob/M = location
- if(M.l_hand == src || M.r_hand == src)
- location = get_turf(M)
- if(isturf(location))
- location.hotspot_expose(700, 5)
-
-/obj/item/weldingtool/attackby(obj/item/I, mob/user, params)
- if(isscrewdriver(I))
- flamethrower_screwdriver(I, user)
- else if(istype(I, /obj/item/stack/rods))
- flamethrower_rods(I, user)
- else
- ..()
-
-/obj/item/weldingtool/attack(mob/M, mob/user)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/obj/item/organ/external/S = H.bodyparts_by_name[user.zone_selected]
-
- if(!S)
- return
-
- if(!S.is_robotic() || user.a_intent != INTENT_HELP || S.open == 2)
- return ..()
-
- if(!isOn()) //why wasn't this being checked already?
- to_chat(user, "Turn on [src] before attempting repairs!")
- return 1
-
- if(S.brute_dam > ROBOLIMB_SELF_REPAIR_CAP)
- to_chat(user, "The damage is far too severe to patch over externally.")
- return
-
- if(!S.brute_dam)
- to_chat(user, "Nothing to fix!")
- return
-
- if(get_fuel() >= 1)
- if(H == user)
- if(!do_mob(user, H, 10))
- return 1
- if(!remove_fuel(1,null))
- to_chat(user, "Need more welding fuel!")
- var/rembrute = HEALPERWELD
- var/nrembrute = 0
- var/childlist
- if(!isnull(S.children))
- childlist = S.children.Copy()
- var/parenthealed = FALSE
- while(rembrute > 0)
- var/obj/item/organ/external/E
- if(S.brute_dam)
- E = S
- else if(LAZYLEN(childlist))
- E = pick_n_take(childlist)
- if(!E.brute_dam || !E.is_robotic())
- continue
- else if(S.parent && !parenthealed)
- E = S.parent
- parenthealed = TRUE
- if(!E.brute_dam || !E.is_robotic())
- break
- else
- break
- playsound(src.loc, usesound, 50, 1)
- nrembrute = max(rembrute - E.brute_dam, 0)
- E.heal_damage(rembrute,0,0,1)
- rembrute = nrembrute
- user.visible_message("\The [user] patches some dents on \the [M]'s [E.name] with \the [src].")
- if(H.bleed_rate && H.isSynthetic())
- H.bleed_rate = 0
- user.visible_message("\The [user] patches some leaks on [M] with \the [src].")
- return 1
- else
- return ..()
-
-/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity)
- if(!proximity)
- return
- if(welding)
- remove_fuel(1)
- var/turf/location = get_turf(user)
- location.hotspot_expose(700, 50, 1)
- if(get_fuel() <= 0)
- set_light(0)
-
- if(isliving(O))
- var/mob/living/L = O
- if(L.IgniteMob())
- message_admins("[key_name_admin(user)] set [key_name_admin(L)] on fire")
- log_game("[key_name(user)] set [key_name(L)] on fire")
-
-/obj/item/weldingtool/attack_self(mob/user)
- switched_on(user)
- if(welding)
- set_light(light_intensity)
-
- update_icon()
-
-//Returns the amount of fuel in the welder
-/obj/item/weldingtool/proc/get_fuel()
- return reagents.get_reagent_amount("fuel")
-
-//Removes fuel from the welding tool. If a mob is passed, it will try to flash the mob's eyes. This should probably be renamed to use()
-/obj/item/weldingtool/proc/remove_fuel(amount = 1, mob/living/M = null)
- if(!welding || !check_fuel())
- return FALSE
- if(get_fuel() >= amount)
- reagents.remove_reagent("fuel", amount)
- check_fuel()
- if(M)
- M.flash_eyes(light_intensity)
- return TRUE
- else
- if(M)
- to_chat(M, "You need more welding fuel to complete this task.")
- return FALSE
-
-//Returns whether or not the welding tool is currently on.
-/obj/item/weldingtool/proc/isOn()
- return welding
-
-//Turns off the welder if there is no more fuel (does this really need to be its own proc?)
-/obj/item/weldingtool/proc/check_fuel(mob/user)
- if(get_fuel() <= 0 && welding)
- switched_on(user)
- update_icon()
- //mob icon update
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_r_hand(0)
- M.update_inv_l_hand(0)
- return 0
- return 1
-
-//Switches the welder on
-/obj/item/weldingtool/proc/switched_on(mob/user)
- if(!status)
- to_chat(user, "[src] can't be turned on while unsecured!")
- return
- welding = !welding
- if(welding)
- if(get_fuel() >= 1)
- to_chat(user, "You switch [src] on.")
- playsound(loc, acti_sound, 50, 1)
- force = 15
- damtype = "fire"
- hitsound = 'sound/items/welder.ogg'
- update_icon()
- START_PROCESSING(SSobj, src)
- else
- to_chat(user, "You need more fuel!")
- switched_off(user)
- else
- if(user)
- to_chat(user, "You switch [src] off.")
- playsound(loc, deac_sound, 50, 1)
- switched_off(user)
-
-//Switches the welder off
-/obj/item/weldingtool/proc/switched_off(mob/user)
- welding = 0
- set_light(0)
-
- force = 3
- damtype = "brute"
- hitsound = "swing_hit"
- update_icon()
-
-/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/I, mob/user)
- if(welding)
- to_chat(user, "Turn it off first!")
- return
- status = !status
- if(status)
- to_chat(user, "You resecure [src].")
- else
- to_chat(user, "[src] can now be attached and modified.")
- add_fingerprint(user)
-
-/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user)
- if(!status)
- var/obj/item/stack/rods/R = I
- if(R.use(1))
- var/obj/item/flamethrower/F = new /obj/item/flamethrower(user.loc)
- if(!remove_item_from_storage(F))
- user.unEquip(src)
- loc = F
- F.weldtool = src
- add_fingerprint(user)
- to_chat(user, "You add a rod to a welder, starting to build a flamethrower.")
- user.put_in_hands(F)
- else
- to_chat(user, "You need one rod to start building a flamethrower!")
-
-/obj/item/weldingtool/largetank
- name = "Industrial Welding Tool"
- desc = "A slightly larger welder with a larger tank."
- icon_state = "indwelder"
- max_fuel = 40
- materials = list(MAT_METAL=70, MAT_GLASS=60)
- origin_tech = "engineering=2;plasmatech=2"
-
-/obj/item/weldingtool/largetank/cyborg
- name = "integrated welding tool"
- desc = "An advanced welder designed to be used in robotic systems."
- toolspeed = 0.5
-
-/obj/item/weldingtool/largetank/flamethrower_screwdriver()
- return
-
-/obj/item/weldingtool/mini
- name = "emergency welding tool"
- desc = "A miniature welder used during emergencies."
- icon_state = "miniwelder"
- max_fuel = 10
- w_class = WEIGHT_CLASS_TINY
- materials = list(MAT_METAL=30, MAT_GLASS=10)
- change_icons = 0
-
-/obj/item/weldingtool/mini/flamethrower_screwdriver()
- return
-
-/obj/item/weldingtool/abductor
- name = "alien welding tool"
- desc = "An alien welding tool. Whatever fuel it uses, it never runs out."
- icon = 'icons/obj/abductor.dmi'
- icon_state = "welder"
- toolspeed = 0.1
- light_intensity = 0
- change_icons = 0
- origin_tech = "plasmatech=5;engineering=5;abductor=3"
- can_off_process = 1
-
-/obj/item/weldingtool/abductor/process()
- if(get_fuel() <= max_fuel)
- reagents.add_reagent("fuel", 1)
- ..()
-
-/obj/item/weldingtool/hugetank
- name = "Upgraded Welding Tool"
- desc = "An upgraded welder based off the industrial welder."
- icon_state = "upindwelder"
- item_state = "upindwelder"
- max_fuel = 80
- materials = list(MAT_METAL=70, MAT_GLASS=120)
- origin_tech = "engineering=3;plasmatech=2"
-
-/obj/item/weldingtool/experimental
- name = "Experimental Welding Tool"
- desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes."
- icon_state = "exwelder"
- item_state = "exwelder"
- max_fuel = 40
- materials = list(MAT_METAL=70, MAT_GLASS=120)
- origin_tech = "materials=4;engineering=4;bluespace=3;plasmatech=4"
- change_icons = 0
- can_off_process = 1
- light_intensity = 1
- toolspeed = 0.5
- var/last_gen = 0
-
-/obj/item/weldingtool/experimental/brass
- name = "brass welding tool"
- desc = "A brass welder that seems to constantly refuel itself. It is faintly warm to the touch."
- icon_state = "brasswelder"
- item_state = "brasswelder"
- resistance_flags = FIRE_PROOF | ACID_PROOF
-
-obj/item/weldingtool/experimental/process()
- ..()
- if(get_fuel() < max_fuel && nextrefueltick < world.time)
- nextrefueltick = world.time + 10
- reagents.add_reagent("fuel", 1)
-
-//Crowbar
-/obj/item/crowbar
- name = "pocket crowbar"
- desc = "A small crowbar. This handy tool is useful for lots of things, such as prying floor tiles or opening unpowered doors."
- icon = 'icons/obj/tools.dmi'
- icon_state = "crowbar"
- item_state = "crowbar"
- usesound = 'sound/items/crowbar.ogg'
- flags = CONDUCT
- slot_flags = SLOT_BELT
- force = 5
- throwforce = 7
- item_state = "crowbar"
- w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=50)
- origin_tech = "engineering=1;combat=1"
- attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked")
- toolspeed = 1
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
-
-/obj/item/crowbar/red
- icon_state = "crowbar_red"
- item_state = "crowbar_red"
- force = 8
-
-/obj/item/crowbar/brass
- name = "brass crowbar"
- desc = "A brass crowbar. It feels faintly warm to the touch."
- icon_state = "crowbar_brass"
- item_state = "crowbar_brass"
- toolspeed = 0.5
- resistance_flags = FIRE_PROOF | ACID_PROOF
-
-/obj/item/crowbar/abductor
- name = "alien crowbar"
- desc = "A hard-light crowbar. It appears to pry by itself, without any effort required."
- icon = 'icons/obj/abductor.dmi'
- usesound = 'sound/weapons/sonic_jackhammer.ogg'
- icon_state = "crowbar"
- toolspeed = 0.1
- origin_tech = "combat=4;engineering=4;abductor=3"
-
-/obj/item/crowbar/large
- name = "crowbar"
- desc = "It's a big crowbar. It doesn't fit in your pockets, because its too big."
- force = 12
- w_class = WEIGHT_CLASS_NORMAL
- throw_speed = 3
- throw_range = 3
- materials = list(MAT_METAL=70)
- icon_state = "crowbar_large"
- item_state = "crowbar_large"
- toolspeed = 0.5
-
-/obj/item/crowbar/cyborg
- name = "hydraulic crowbar"
- desc = "A hydraulic prying tool, compact but powerful. Designed to replace crowbar in construction cyborgs."
- usesound = 'sound/items/jaws_pry.ogg'
- force = 10
- toolspeed = 0.5
-
-/obj/item/crowbar/power
- name = "jaws of life"
- desc = "A set of jaws of life, the magic of science has managed to fit it down into a device small enough to fit in a tool belt. It's fitted with a prying head."
- icon_state = "jaws_pry"
- item_state = "jawsoflife"
- materials = list(MAT_METAL=150,MAT_SILVER=50,MAT_TITANIUM=25)
- origin_tech = "materials=2;engineering=2"
- usesound = 'sound/items/jaws_pry.ogg'
- force = 15
- toolspeed = 0.25
- var/airlock_open_time = 100 // Time required to open powered airlocks
-
-/obj/item/crowbar/power/suicide_act(mob/user)
- user.visible_message("[user] is putting [user.p_their()] head in [src]. It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(loc, 'sound/items/jaws_pry.ogg', 50, 1, -1)
- return BRUTELOSS
-
-/obj/item/crowbar/power/attack_self(mob/user)
- playsound(get_turf(user), 'sound/items/change_jaws.ogg', 50, 1)
- var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power
- to_chat(user, "You attach the cutting jaws to [src].")
- qdel(src)
- user.put_in_active_hand(cutjaws)
-
-// Conversion kit
-/obj/item/conversion_kit
- name = "\improper Revolver Conversion Kit"
- desc = "A professional conversion kit used to convert any knock off revolver into the real deal capable of shooting lethal .357 rounds without the possibility of catastrophic failure."
- icon_state = "kit"
- flags = CONDUCT
- w_class = WEIGHT_CLASS_SMALL
- origin_tech = "combat=2"
- var/open = 0
-
-/obj/item/conversion_kit/New()
- ..()
- update_icon()
-
-/obj/item/conversion_kit/update_icon()
- icon_state = "[initial(icon_state)]_[open]"
-
-/obj/item/conversion_kit/attack_self(mob/user)
- open = !open
- to_chat(user, "You [open ? "open" : "close"] the conversion kit.")
- update_icon()
diff --git a/code/game/objects/items/weapons/whetstone.dm b/code/game/objects/items/weapons/whetstone.dm
index f74f8d28f57..d2ab4b2733f 100644
--- a/code/game/objects/items/weapons/whetstone.dm
+++ b/code/game/objects/items/weapons/whetstone.dm
@@ -34,15 +34,15 @@
if(TH.force_wielded > initial(TH.force_wielded))
to_chat(user, "[TH] has already been refined before. It cannot be sharpened further!")
return
- TH.force_wielded = Clamp(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
+ TH.force_wielded = clamp(TH.force_wielded + increment, 0, max)//wieldforce is increased since normal force wont stay
if(I.force > initial(I.force))
to_chat(user, "[I] has already been refined before. It cannot be sharpened further!")
return
user.visible_message("[user] sharpens [I] with [src]!", "You sharpen [I], making it much more deadly than before.")
if(!requires_sharpness)
I.sharp = 1
- I.force = Clamp(I.force + increment, 0, max)
- I.throwforce = Clamp(I.throwforce + increment, 0, max)
+ I.force = clamp(I.force + increment, 0, max)
+ I.throwforce = clamp(I.throwforce + increment, 0, max)
I.name = "[prefix] [I.name]"
playsound(get_turf(src), usesound, 50, 1)
name = "worn out [name]"
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index e1464e47e48..bbd43db7c1e 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -30,9 +30,9 @@
return 0
var/armor_protection = 0
if(damage_flag)
- armor_protection = armor[damage_flag]
+ armor_protection = armor.getRating(damage_flag)
if(armor_protection) //Only apply weak-against-armor/hollowpoint effects if there actually IS armor.
- armor_protection = Clamp(armor_protection - armour_penetration, min(armor_protection, 0), 100)
+ armor_protection = clamp(armor_protection - armour_penetration, min(armor_protection, 0), 100)
return round(damage_amount * (100 - armor_protection)*0.01, DAMAGE_PRECISION)
///the sound played when the obj is damaged.
@@ -201,7 +201,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
return
..()
if(exposed_temperature && !(resistance_flags & FIRE_PROOF))
- take_damage(Clamp(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
+ take_damage(clamp(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE) && !(resistance_flags & FIRE_PROOF))
resistance_flags |= ON_FIRE
SSfires.processing[src] = src
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 951eb79f853..d40c628ed90 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -1,15 +1,14 @@
/obj
//var/datum/module/mod //not used
var/origin_tech = null //Used by R&D to determine what research bonuses it grants.
- var/crit_fail = 0
+ var/crit_fail = FALSE
animate_movement = 2
- var/list/attack_verb = list() //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
var/list/species_exception = null // list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item
- var/sharp = 0 // whether this object cuts
- var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
+ var/sharp = FALSE // whether this object cuts
+ var/in_use = FALSE // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
var/damtype = "brute"
var/force = 0
- var/list/armor
+ var/datum/armor/armor
var/obj_integrity //defaults to max_integrity
var/max_integrity = 500
var/integrity_failure = 0 //0 if we have no special broken behavior
@@ -22,9 +21,9 @@
var/can_be_hit = TRUE //can this be bludgeoned by items?
- var/Mtoollink = 0 // variable to decide if an object should show the multitool menu linking menu, not all objects use it
+ var/Mtoollink = FALSE // variable to decide if an object should show the multitool menu linking menu, not all objects use it
- var/being_shocked = 0
+ var/being_shocked = FALSE
var/speed_process = FALSE
var/on_blueprints = FALSE //Are we visible on the station blueprints at roundstart?
@@ -33,8 +32,6 @@
/obj/New()
..()
- if(!armor)
- armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
if(obj_integrity == null)
obj_integrity = max_integrity
if(on_blueprints && isturf(loc))
@@ -44,25 +41,34 @@
else
T.add_blueprints_preround(src)
-/obj/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state = GLOB.default_state)
+/obj/Initialize(mapload)
+ . = ..()
+ if(islist(armor))
+ armor = getArmor(arglist(armor))
+ else if(!armor)
+ armor = getArmor()
+ else if(!istype(armor, /datum/armor))
+ stack_trace("Invalid type [armor.type] found in .armor during /obj Initialize()")
+
+/obj/Topic(href, href_list, nowindow = FALSE, datum/topic_state/state = GLOB.default_state)
// Calling Topic without a corresponding window open causes runtime errors
if(!nowindow && ..())
- return 1
+ return TRUE
// In the far future no checks are made in an overriding Topic() beyond if(..()) return
// Instead any such checks are made in CanUseTopic()
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
- return 0
+ return FALSE
CouldNotUseTopic(usr)
- return 1
+ return TRUE
-/obj/proc/CouldUseTopic(var/mob/user)
+/obj/proc/CouldUseTopic(mob/user)
var/atom/host = nano_host()
host.add_fingerprint(user)
-/obj/proc/CouldNotUseTopic(var/mob/user)
+/obj/proc/CouldNotUseTopic(mob/user)
// Nada
/obj/Destroy()
@@ -110,23 +116,23 @@
// null if object handles breathing logic for lifeform
// datum/air_group to tell lifeform to process using that breath return
//DEFAULT: Take air from turf to give to have mob process
- if(breath_request>0)
+ if(breath_request > 0)
return remove_air(breath_request)
else
return null
/obj/proc/updateUsrDialog()
if(in_use)
- var/is_in_use = 0
+ var/is_in_use = FALSE
var/list/nearby = viewers(1, src)
for(var/mob/M in nearby)
if((M.client && M.machine == src))
- is_in_use = 1
+ is_in_use = TRUE
src.attack_hand(M)
if(istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot))
if(!(usr in nearby))
if(usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
- is_in_use = 1
+ is_in_use = TRUE
src.attack_ai(usr)
// check for TK users
@@ -134,8 +140,8 @@
if(istype(usr, /mob/living/carbon/human))
if(istype(usr.l_hand, /obj/item/tk_grab) || istype(usr.r_hand, /obj/item/tk_grab/))
if(!(usr in nearby))
- if(usr.client && usr.machine==src)
- is_in_use = 1
+ if(usr.client && usr.machine == src)
+ is_in_use = TRUE
src.attack_hand(usr)
in_use = is_in_use
@@ -143,15 +149,15 @@
// Check that people are actually using the machine. If not, don't update anymore.
if(in_use)
var/list/nearby = viewers(1, src)
- var/is_in_use = 0
+ var/is_in_use = FALSE
for(var/mob/M in nearby)
if((M.client && M.machine == src))
- is_in_use = 1
+ is_in_use = TRUE
src.interact(M)
var/ai_in_use = AutoUpdateAI(src)
if(!ai_in_use && !is_in_use)
- in_use = 0
+ in_use = FALSE
/obj/proc/interact(mob/user)
return
@@ -168,12 +174,12 @@
/atom/movable/proc/on_unset_machine(mob/user)
return
-/mob/proc/set_machine(var/obj/O)
+/mob/proc/set_machine(obj/O)
if(src.machine)
unset_machine()
src.machine = O
if(istype(O))
- O.in_use = 1
+ O.in_use = TRUE
/obj/item/proc/updateSelfDialog()
var/mob/M = src.loc
@@ -183,48 +189,48 @@
/obj/proc/hide(h)
return
-
/obj/proc/hear_talk(mob/M, list/message_pieces)
return
-/obj/proc/hear_message(mob/M as mob, text)
+/obj/proc/hear_message(mob/M, text)
-/obj/proc/multitool_menu(var/mob/user,var/obj/item/multitool/P)
+/obj/proc/multitool_menu(mob/user, obj/item/multitool/P)
return "NO MULTITOOL_MENU!"
-/obj/proc/linkWith(var/mob/user, var/obj/buffer, var/context)
- return 0
+/obj/proc/linkWith(mob/user, obj/buffer, context)
+ return FALSE
-/obj/proc/unlinkFrom(var/mob/user, var/obj/buffer)
- return 0
+/obj/proc/unlinkFrom(mob/user, obj/buffer)
+ return FALSE
-/obj/proc/canLink(var/obj/O, var/context)
- return 0
+/obj/proc/canLink(obj/O, list/context)
+ return FALSE
-/obj/proc/isLinkedWith(var/obj/O)
- return 0
+/obj/proc/isLinkedWith(obj/O)
+ return FALSE
-/obj/proc/getLink(var/idx)
+/obj/proc/getLink(idx)
return null
-/obj/proc/linkMenu(var/obj/O)
- var/dat=""
+/obj/proc/linkMenu(obj/O)
+ var/dat = ""
if(canLink(O, list()))
dat += " \[Link\] "
return dat
-/obj/proc/format_tag(var/label,var/varname, var/act="set_tag")
+/obj/proc/format_tag(label, varname, act = "set_tag")
var/value = vars[varname]
- if(!value || value=="")
- value="-----"
+ if(!value || value == "")
+ value = "-----"
return "[label]:[value]"
-/obj/proc/update_multitool_menu(mob/user as mob)
+/obj/proc/update_multitool_menu(mob/user)
var/obj/item/multitool/P = get_multitool(user)
if(!istype(P))
- return 0
+ return FALSE
+
var/dat = {"
[name] Configuration
@@ -246,13 +252,13 @@ a {
[name]
"}
if(allowed(user))//no, assistants, you're not ruining all vents on the station with just a multitool
- dat += multitool_menu(user,P)
+ dat += multitool_menu(user, P)
if(Mtoollink)
if(P)
if(P.buffer)
var/id = null
if("id_tag" in P.buffer.vars)
- id=P.buffer:id_tag
+ id = P.buffer:id_tag
dat += "
"
/obj/item/paper/safe_code/Initialize(mapload)
+ ..()
return INITIALIZE_HINT_LATELOAD
/obj/item/paper/safe_code/LateInitialize(mapload)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 5acd4f7d8a3..bdab5ca2466 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -128,7 +128,7 @@
/obj/structure/table/CanAStarPass(ID, dir, caller)
. = !density
- if(ismovableatom(caller))
+ if(ismovable(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSTABLE)
@@ -224,8 +224,8 @@
if(!click_params || !click_params["icon-x"] || !click_params["icon-y"])
return
//Clamp it so that the icon never moves more than 16 pixels in either direction (thus leaving the table turf)
- I.pixel_x = Clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
- I.pixel_y = Clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_x = clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
+ I.pixel_y = clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
item_placed(I)
else
return ..()
@@ -666,7 +666,7 @@
/obj/structure/rack/CanAStarPass(ID, dir, caller)
. = !density
- if(ismovableatom(caller))
+ if(ismovable(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSTABLE)
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 87107f97abe..1a5b275bc01 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -403,75 +403,7 @@
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
to_chat(L, "You've been drenched in water!")
- if(iscarbon(O))
- var/mob/living/carbon/M = O
- if(M.r_hand)
- M.r_hand.clean_blood()
- if(M.l_hand)
- M.l_hand.clean_blood()
- if(M.back)
- if(M.back.clean_blood())
- M.update_inv_back()
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/washgloves = 1
- var/washshoes = 1
- var/washmask = 1
- var/washears = 1
- var/washglasses = 1
-
- if(H.wear_suit)
- washgloves = !(H.wear_suit.flags_inv & HIDEGLOVES)
- washshoes = !(H.wear_suit.flags_inv & HIDESHOES)
-
- if(H.head)
- washmask = !(H.head.flags_inv & HIDEMASK)
- washglasses = !(H.head.flags_inv & HIDEEYES)
- washears = !(H.head.flags_inv & HIDEEARS)
-
- if(H.wear_mask)
- if(washears)
- washears = !(H.wear_mask.flags_inv & HIDEEARS)
- if(washglasses)
- washglasses = !(H.wear_mask.flags_inv & HIDEEYES)
-
- if(H.head)
- if(H.head.clean_blood())
- H.update_inv_head()
- if(H.wear_suit)
- if(H.wear_suit.clean_blood())
- H.update_inv_wear_suit()
- else if(H.w_uniform)
- if(H.w_uniform.clean_blood())
- H.update_inv_w_uniform()
- if(H.gloves && washgloves)
- if(H.gloves.clean_blood())
- H.update_inv_gloves()
- if(H.shoes && washshoes)
- if(H.shoes.clean_blood())
- H.update_inv_shoes()
- if(H.wear_mask && washmask)
- if(H.wear_mask.clean_blood())
- H.update_inv_wear_mask()
- if(H.glasses && washglasses)
- if(H.glasses.clean_blood())
- H.update_inv_glasses()
- if(H.l_ear && washears)
- if(H.l_ear.clean_blood())
- H.update_inv_ears()
- if(H.r_ear && washears)
- if(H.r_ear.clean_blood())
- H.update_inv_ears()
- if(H.belt)
- if(H.belt.clean_blood())
- H.update_inv_belt()
- else
- if(M.wear_mask) //if the mob is not human, it cleans the mask without asking for bitflags
- if(M.wear_mask.clean_blood())
- M.update_inv_wear_mask()
-
- else
- O.clean_blood()
+ L.clean_blood()
if(isturf(loc))
var/turf/tile = loc
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 19717991593..6bc1c4ba142 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -8,12 +8,6 @@
nitrogen = MOLES_N2STANDARD
var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed
var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to
- var/dirtoverlay = null
-
-/turf/simulated/New()
- ..()
- levelupdate()
- visibilityChanged()
/turf/simulated/proc/break_tile()
return
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 2d886f44bfd..614b8232b0b 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -27,24 +27,16 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama
var/burnt = 0
var/current_overlay = null
var/floor_tile = null //tile that this floor drops
- var/obj/item/stack/tile/builtin_tile = null //needed for performance reasons when the singularity rips off floor tiles
var/list/broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
var/list/burnt_states = list("floorscorched1", "floorscorched2")
var/list/prying_tool_list = list(TOOL_CROWBAR) //What tool/s can we use to pry up the tile?
-/turf/simulated/floor/New()
- ..()
+/turf/simulated/floor/Initialize(mapload)
+ . = ..()
if(icon_state in GLOB.icons_to_ignore_at_floor_init) //so damaged/burned tiles or plating icons aren't saved as the default
icon_regular_floor = "floor"
else
icon_regular_floor = icon_state
- if(floor_tile)
- builtin_tile = new floor_tile
-
-/turf/simulated/floor/Destroy()
- QDEL_NULL(builtin_tile)
- return ..()
-
//turf/simulated/floor/CanPass(atom/movable/mover, turf/target, height=0)
// if((istype(mover, /obj/machinery/vehicle) && !(src.burnt)))
@@ -209,30 +201,26 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama
else
if(user && !silent)
to_chat(user, "You remove the floor tile.")
- if(builtin_tile && make_tile)
- builtin_tile.forceMove(src)
- builtin_tile = null
+ if(floor_tile && make_tile)
+ new floor_tile(src)
return make_plating()
/turf/simulated/floor/singularity_pull(S, current_size)
..()
if(current_size == STAGE_THREE)
if(prob(30))
- if(builtin_tile)
- builtin_tile.loc = src
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
make_plating()
else if(current_size == STAGE_FOUR)
if(prob(50))
- if(builtin_tile)
- builtin_tile.loc = src
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
make_plating()
else if(current_size >= STAGE_FIVE)
- if(builtin_tile)
+ if(floor_tile)
if(prob(70))
- builtin_tile.loc = src
- builtin_tile = null
+ new floor_tile(src)
make_plating()
else if(prob(50))
ReplaceWithLattice()
diff --git a/code/game/turfs/simulated/floor/asteroid.dm b/code/game/turfs/simulated/floor/asteroid.dm
index 6d5d95dff0e..6118885a921 100644
--- a/code/game/turfs/simulated/floor/asteroid.dm
+++ b/code/game/turfs/simulated/floor/asteroid.dm
@@ -227,7 +227,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me
break
var/list/L = list(45)
- if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
+ if(ISODD(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels.
L += -45
// Expand the edges of our tunnel
diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm
index 3ab424e69cc..bfbfa70331e 100644
--- a/code/game/turfs/simulated/floor/fancy_floor.dm
+++ b/code/game/turfs/simulated/floor/fancy_floor.dm
@@ -31,9 +31,8 @@
if(make_tile)
if(user && !silent)
to_chat(user, "You unscrew the planks.")
- if(builtin_tile)
- builtin_tile.forceMove(src)
- builtin_tile = null
+ if(floor_tile)
+ new floor_tile(src)
else
if(user && !silent)
to_chat(user, "You forcefully pry off the planks, destroying them in the process.")
@@ -50,9 +49,9 @@
floor_tile = /obj/item/stack/tile/grass
broken_states = list("sand")
-/turf/simulated/floor/grass/Initialize()
+/turf/simulated/floor/grass/Initialize(mapload)
+ . = ..()
update_icon()
- ..()
/turf/simulated/floor/grass/update_icon()
icon_state = "grass[pick("1","2","3","4")]"
@@ -81,10 +80,9 @@
)
-/turf/simulated/floor/carpet/New()
- ..()
- if(broken || burnt)
- make_plating()
+/turf/simulated/floor/carpet/Initialize(mapload)
+ . = ..()
+ update_icon()
/turf/simulated/floor/carpet/update_icon()
if(!..())
@@ -120,18 +118,18 @@
broken_states = list("damaged")
plane = PLANE_SPACE
-/turf/simulated/floor/fakespace/New()
- ..()
- icon_state = "[rand(0,25)]"
-
-/turf/simulated/floor/carpet/arcade
- icon = 'icons/goonstation/turf/floor.dmi'
- icon_state = "arcade"
- floor_tile = /obj/item/stack/tile/arcade_carpet
- smooth = SMOOTH_FALSE
+/turf/simulated/floor/fakespace/Initialize(mapload)
+ . = ..()
+ icon_state = SPACE_ICON_STATE
/turf/simulated/floor/fakespace/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
underlay_appearance.icon = 'icons/turf/space.dmi'
underlay_appearance.icon_state = SPACE_ICON_STATE
underlay_appearance.plane = PLANE_SPACE
return TRUE
+
+/turf/simulated/floor/carpet/arcade
+ icon = 'icons/goonstation/turf/floor.dmi'
+ icon_state = "arcade"
+ floor_tile = /obj/item/stack/tile/arcade_carpet
+ smooth = SMOOTH_FALSE
diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm
index aa1be2200fa..14a08639132 100644
--- a/code/game/turfs/simulated/floor/lava.dm
+++ b/code/game/turfs/simulated/floor/lava.dm
@@ -8,9 +8,6 @@
light_power = 0.75
light_color = LIGHT_COLOR_LAVA
-/turf/simulated/floor/plating/lava/New()
- ..()
-
/turf/simulated/floor/plating/lava/ex_act()
return
@@ -80,8 +77,8 @@
O.resistance_flags |= FLAMMABLE //Even fireproof things burn up in lava
if(O.resistance_flags & FIRE_PROOF)
O.resistance_flags &= ~FIRE_PROOF
- if(O.armor["fire"] > 50) //obj with 100% fire armor still get slowly burned away.
- O.armor["fire"] = 50
+ if(O.armor.getRating("fire") > 50) //obj with 100% fire armor still get slowly burned away.
+ O.armor = O.armor.setRating(fire_value = 50)
O.fire_act(10000, 1000)
else if(isliving(thing))
diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm
index 332cf745a4c..8276c0de33f 100644
--- a/code/game/turfs/simulated/floor/light_floor.dm
+++ b/code/game/turfs/simulated/floor/light_floor.dm
@@ -20,8 +20,8 @@
var/state = LIGHTFLOOR_ON
var/can_modify_colour = TRUE
-/turf/simulated/floor/light/New()
- ..()
+/turf/simulated/floor/light/Initialize(mapload)
+ . = ..()
update_icon()
/turf/simulated/floor/light/update_icon()
@@ -77,14 +77,13 @@
/turf/simulated/floor/light/attackby(obj/item/C, mob/user, params)
if(istype(C,/obj/item/light/bulb)) //only for light tiles
- if(istype(builtin_tile, /obj/item/stack/tile/light))
- if(!state)
- qdel(C)
- state = LIGHTFLOOR_ON
- update_icon()
- to_chat(user, "You replace the light bulb.")
- else
- to_chat(user, "The light bulb seems fine, no need to replace it.")
+ if(!state)
+ qdel(C)
+ state = LIGHTFLOOR_ON
+ update_icon()
+ to_chat(user, "You replace the light bulb.")
+ else
+ to_chat(user, "The light bulb seems fine, no need to replace it.")
else
return ..()
diff --git a/code/game/turfs/simulated/floor/mineral.dm b/code/game/turfs/simulated/floor/mineral.dm
index ffb1cce0b5c..dd975dc80d9 100644
--- a/code/game/turfs/simulated/floor/mineral.dm
+++ b/code/game/turfs/simulated/floor/mineral.dm
@@ -14,8 +14,8 @@
icon_state = ""
var/list/icons = list()
-/turf/simulated/floor/mineral/New()
- ..()
+/turf/simulated/floor/mineral/Initialize(mapload)
+ . = ..()
broken_states = list("[initial(icon_state)]_dam")
/turf/simulated/floor/mineral/update_icon()
@@ -97,24 +97,24 @@
broken_states = list("titanium_dam1","titanium_dam2","titanium_dam3","titanium_dam4","titanium_dam5")
/turf/simulated/floor/mineral/titanium/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/blue
icon_state = "titanium_blue"
/turf/simulated/floor/mineral/titanium/blue/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/yellow
icon_state = "titanium_yellow"
/turf/simulated/floor/mineral/titanium/yellow/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/titanium/purple
@@ -122,8 +122,8 @@
floor_tile = /obj/item/stack/tile/mineral/titanium/purple
/turf/simulated/floor/mineral/titanium/purple/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
//PLASTITANIUM (syndieshuttle)
@@ -137,8 +137,8 @@
icon_state = "plastitanium_red"
/turf/simulated/floor/mineral/plastitanium/red/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
/turf/simulated/floor/mineral/plastitanium/red/brig
@@ -179,8 +179,8 @@
spam_flag = world.time + 10
/turf/simulated/floor/mineral/bananium/airless
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
@@ -254,8 +254,8 @@
floor_tile = /obj/item/stack/tile/mineral/abductor
icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9")
-/turf/simulated/floor/mineral/abductor/New()
- ..()
+/turf/simulated/floor/mineral/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/simulated/floor/mineral/abductor/break_tile()
diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm
index 0ca6494497c..83835cd947f 100644
--- a/code/game/turfs/simulated/floor/misc_floor.dm
+++ b/code/game/turfs/simulated/floor/misc_floor.dm
@@ -3,23 +3,23 @@
icon_state = "rockvault"
smooth = SMOOTH_FALSE
-/turf/simulated/floor/vault/New(location, vtype)
- ..()
- icon_state = "[vtype]vault"
-
/turf/simulated/wall/vault
icon = 'icons/turf/walls.dmi'
icon_state = "rockvault"
smooth = SMOOTH_FALSE
-/turf/simulated/wall/vault/New(location, vtype)
- ..()
- icon_state = "[vtype]vault"
-
/turf/simulated/floor/bluegrid
icon = 'icons/turf/floors.dmi'
icon_state = "bcircuit"
+/turf/simulated/floor/bluegrid/telecomms
+ nitrogen = 100
+ oxygen = 0
+ temperature = 80
+
+/turf/simulated/floor/bluegrid/telecomms/server
+ name = "server base"
+
/turf/simulated/floor/greengrid
icon = 'icons/turf/floors.dmi'
icon_state = "gcircuit"
@@ -27,12 +27,12 @@
/turf/simulated/floor/greengrid/airless
icon_state = "gcircuit"
name = "airless floor"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/greengrid/airless/New()
- ..()
+/turf/simulated/floor/greengrid/airless/Initialize(mapload)
+ . = ..()
name = "floor"
/turf/simulated/floor/redgrid
@@ -70,8 +70,8 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
var/obj/machinery/poolcontroller/linkedcontroller = null
-/turf/simulated/floor/beach/water/New()
- ..()
+/turf/simulated/floor/beach/water/Initialize(mapload)
+ . = ..()
var/image/overlay_image = image('icons/misc/beach.dmi', icon_state = "water5", layer = ABOVE_MOB_LAYER)
overlay_image.plane = GAME_PLANE
overlays += overlay_image
diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm
index d36396aaa5f..116d57dc1ef 100644
--- a/code/game/turfs/simulated/floor/plasteel_floor.dm
+++ b/code/game/turfs/simulated/floor/plasteel_floor.dm
@@ -12,12 +12,12 @@
/turf/simulated/floor/plasteel/airless
name = "airless floor"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/plasteel/airless/New()
- ..()
+/turf/simulated/floor/plasteel/airless/Initialize(mapload)
+ . = ..()
name = "floor"
/turf/simulated/floor/plasteel/airless/indestructible // For bomb testing range
@@ -41,6 +41,11 @@
/turf/simulated/floor/plasteel/dark
icon_state = "darkfull"
+/turf/simulated/floor/plasteel/dark/telecomms
+ nitrogen = 100
+ oxygen = 0
+ temperature = 80
+
/turf/simulated/floor/plasteel/freezer
icon_state = "freezerfloor"
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 588a8387474..a6dbe0de281 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -14,17 +14,17 @@
"xeno" = list('sound/effects/footstep/plating_xeno.ogg')
)
-/turf/simulated/floor/plating/New()
- ..()
+/turf/simulated/floor/plating/Initialize(mapload)
+ . = ..()
icon_plating = icon_state
update_icon()
-/turf/simulated/floor/plating/damaged/New()
- ..()
+/turf/simulated/floor/plating/damaged/Initialize(mapload)
+ . = ..()
break_tile()
-/turf/simulated/floor/plating/burnt/New()
- ..()
+/turf/simulated/floor/plating/burnt/Initialize(mapload)
+ . = ..()
burn_tile()
/turf/simulated/floor/plating/update_icon()
@@ -113,12 +113,12 @@
/turf/simulated/floor/plating/airless
icon_state = "plating"
name = "airless plating"
- oxygen = 0.01
- nitrogen = 0.01
+ oxygen = 0
+ nitrogen = 0
temperature = TCMB
-/turf/simulated/floor/plating/airless/New()
- ..()
+/turf/simulated/floor/plating/airless/Initialize(mapload)
+ . = ..()
name = "plating"
/turf/simulated/floor/engine
@@ -190,8 +190,8 @@
name = "engraved floor"
icon_state = "cult"
-/turf/simulated/floor/engine/cult/New()
- ..()
+/turf/simulated/floor/engine/cult/Initialize(mapload)
+ . = ..()
if(SSticker.mode)//only do this if the round is going..otherwise..fucking asteroid..
icon_state = SSticker.cultdat.cult_floor_icon_state
@@ -205,16 +205,41 @@
color = "#FAE48C"
animate(src, color = previouscolor, time = 8)
-/turf/simulated/floor/engine/n20/New()
- ..()
- var/datum/gas_mixture/adding = new
- var/datum/gas/sleeping_agent/trace_gas = new
+//air filled floors; used in atmos pressure chambers
- trace_gas.moles = 6000
- adding.trace_gases += trace_gas
- adding.temperature = T20C
+/turf/simulated/floor/engine/n20
+ name = "\improper N2O floor"
+ sleeping_agent = 6000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/co2
+ name = "\improper CO2 floor"
+ carbon_dioxide = 50000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/plasma
+ name = "plasma floor"
+ toxins = 70000
+ oxygen = 0
+ nitrogen = 0
+
+/turf/simulated/floor/engine/o2
+ name = "\improper O2 floor"
+ oxygen = 100000
+ nitrogen = 0
+
+/turf/simulated/floor/engine/n2
+ name = "\improper N2 floor"
+ nitrogen = 100000
+ oxygen = 0
+
+/turf/simulated/floor/engine/air
+ name = "air floor"
+ oxygen = 2644
+ nitrogen = 10580
- assume_air(adding)
/turf/simulated/floor/engine/singularity_pull(S, current_size)
..()
@@ -250,8 +275,8 @@
icon = 'icons/turf/floors/ironsand.dmi'
icon_state = "ironsand1"
-/turf/simulated/floor/plating/ironsand/New()
- ..()
+/turf/simulated/floor/plating/ironsand/Initialize(mapload)
+ . = ..()
icon_state = "ironsand[rand(1,15)]"
/turf/simulated/floor/plating/ironsand/remove_plating()
@@ -334,8 +359,8 @@
name = "alien floor"
icon_state = "alienpod1"
-/turf/simulated/floor/plating/abductor/New()
- ..()
+/turf/simulated/floor/plating/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/simulated/floor/plating/ice
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index c18acf19d0a..23d0c9789bd 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -34,7 +34,6 @@
var/sheet_type = /obj/item/stack/sheet/metal
var/sheet_amount = 2
var/girder_type = /obj/structure/girder
- var/obj/item/stack/sheet/builtin_sheet = null
canSmoothWith = list(
/turf/simulated/wall,
@@ -46,10 +45,6 @@
/turf/simulated/wall/r_wall/coated)
smooth = SMOOTH_TRUE
-/turf/simulated/wall/New()
- ..()
- builtin_sheet = new sheet_type
-
/turf/simulated/wall/BeforeChange()
for(var/obj/effect/overlay/wall_rot/WR in src)
qdel(WR)
diff --git a/code/game/turfs/simulated/walls_misc.dm b/code/game/turfs/simulated/walls_misc.dm
index d2d7f8386ee..56908a7ecae 100644
--- a/code/game/turfs/simulated/walls_misc.dm
+++ b/code/game/turfs/simulated/walls_misc.dm
@@ -3,15 +3,14 @@
desc = "A cold metal wall engraved with indecipherable symbols. Studying them causes your head to pound."
icon = 'icons/turf/walls/cult_wall.dmi'
icon_state = "cult"
- builtin_sheet = null
canSmoothWith = null
smooth = SMOOTH_FALSE
sheet_type = /obj/item/stack/sheet/runed_metal
sheet_amount = 1
girder_type = /obj/structure/girder/cult
-/turf/simulated/wall/cult/New()
- ..()
+/turf/simulated/wall/cult/Initialize(mapload)
+ . = ..()
if(SSticker.mode)//game hasn't started offically don't do shit..
new /obj/effect/temp_visual/cult/turf(src)
icon_state = SSticker.cultdat.cult_wall_icon_state
@@ -73,10 +72,7 @@
realappearance.linked = src
/turf/simulated/wall/clockwork/Destroy()
- if(realappearance)
- qdel(realappearance)
- realappearance = null
-
+ QDEL_NULL(realappearance)
return ..()
/turf/simulated/wall/clockwork/ReplaceWithLattice()
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index f78f520cfd3..1a8ccdae550 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -21,6 +21,11 @@
/turf/space/Initialize(mapload)
if(!istype(src, /turf/space/transit))
icon_state = SPACE_ICON_STATE
+ vis_contents.Cut() //removes inherited overlays
+
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
@@ -34,12 +39,6 @@
return INITIALIZE_HINT_NORMAL
-/turf/space/Destroy(force)
- if(force)
- . = ..()
- else
- return QDEL_HINT_LETMELIVE
-
/turf/space/BeforeChange()
..()
var/datum/space_level/S = GLOB.space_manager.get_zlev(z)
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 2a14230d467..a96cbae1269 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -125,9 +125,9 @@
/turf/space/transit/attackby()
return
-/turf/space/transit/New()
+/turf/space/transit/Initialize(mapload)
+ . = ..()
update_icon()
- ..()
/turf/space/transit/proc/update_icon()
var/p = 9
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index aa3f7b898a1..e174634123d 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -3,15 +3,18 @@
level = 1
luminosity = 1
- var/intact = 1
+ var/intact = TRUE
var/turf/baseturf = /turf/space
var/slowdown = 0 //negative for faster, positive for slower
- //Properties for open tiles (/floor)
+ ///Properties for open tiles (/floor)
+ /// All the gas vars, on the turf, are meant to be utilized for initializing a gas datum and setting its first gas values; the turf vars are never further modified at runtime; it is never directly used for calculations by the atmospherics system.
var/oxygen = 0
var/carbon_dioxide = 0
var/nitrogen = 0
var/toxins = 0
+ var/sleeping_agent = 0
+ var/agent_b = 0
//Properties for airtight tiles (/wall)
var/thermal_conductivity = 0.05
@@ -28,21 +31,29 @@
var/image/obscured //camerachunks
+ var/changing_turf = FALSE
+
var/list/blueprint_data //for the station blueprints, images of objects eg: pipes
- var/list/footstep_sounds = list()
+ var/list/footstep_sounds
var/shoe_running_volume = 50
var/shoe_walking_volume = 20
-/turf/New()
- ..()
+/turf/Initialize(mapload)
+ if(initialized)
+ stack_trace("Warning: [src]([type]) initialized multiple times!")
+ initialized = TRUE
+
+ // by default, vis_contents is inherited from the turf that was here before
+ vis_contents.Cut()
+
+ levelupdate()
+ if(smooth)
+ queue_smooth(src)
+ visibilityChanged()
+
for(var/atom/movable/AM in src)
Entered(AM)
- if(smooth && SSticker && SSticker.current_state == GAME_STATE_PLAYING)
- queue_smooth(src)
-
-/turf/Initialize(mapload)
- . = ..()
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
@@ -51,9 +62,11 @@
if(light_power && light_range)
update_light()
- if (opacity)
+ if(opacity)
has_opaque_atom = TRUE
+ return INITIALIZE_HINT_NORMAL
+
/hook/startup/proc/smooth_world()
var/watch = start_watch()
log_startup_progress("Smoothing atoms...")
@@ -65,24 +78,37 @@
if(AA.smooth)
queue_smooth(AA)
log_startup_progress(" Smoothed atoms in [stop_watch(watch)]s.")
- return 1
+ return TRUE
-/turf/Destroy()
-// Adds the adjacent turfs to the current atmos processing
- if(SSair)
- for(var/direction in GLOB.cardinal)
- if(atmos_adjacent_turfs & direction)
- var/turf/simulated/T = get_step(src, direction)
- if(istype(T))
- SSair.add_to_active(T)
+/turf/Destroy(force)
+ . = QDEL_HINT_IWILLGC
+ if(!changing_turf)
+ stack_trace("Incorrect turf deletion")
+ changing_turf = FALSE
+ if(force)
+ ..()
+ //this will completely wipe turf state
+ var/turf/B = new world.turf(src)
+ for(var/A in B.contents)
+ qdel(A)
+ return
+ // Adds the adjacent turfs to the current atmos processing
+ for(var/direction in GLOB.cardinal)
+ if(atmos_adjacent_turfs & direction)
+ var/turf/simulated/T = get_step(src, direction)
+ if(istype(T))
+ SSair.add_to_active(T)
+ SSair.remove_from_active(src)
+ visibilityChanged()
+ QDEL_LIST(blueprint_data)
+ initialized = FALSE
..()
- return QDEL_HINT_HARDDEL_NOW
/turf/attack_hand(mob/user as mob)
user.Move_Pulled(src)
/turf/ex_act(severity)
- return 0
+ return FALSE
/turf/rpd_act(mob/user, obj/item/rpd/our_rpd) //This is the default turf behaviour for the RPD; override it as required
if(our_rpd.mode == RPD_ATMOS_MODE)
@@ -100,55 +126,53 @@
else if(our_rpd.mode == RPD_DELETE_MODE)
our_rpd.delete_all_pipes(user, src)
-/turf/bullet_act(var/obj/item/projectile/Proj)
- if(istype(Proj ,/obj/item/projectile/beam/pulse))
+/turf/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj, /obj/item/projectile/beam/pulse))
src.ex_act(2)
..()
- return 0
+ return FALSE
-/turf/bullet_act(var/obj/item/projectile/Proj)
- if(istype(Proj ,/obj/item/projectile/bullet/gyro))
+/turf/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj, /obj/item/projectile/bullet/gyro))
explosion(src, -1, 0, 2)
..()
- return 0
+ return FALSE
-/turf/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area)
+/turf/Enter(atom/movable/mover as mob|obj, atom/forget)
if(!mover)
- return 1
-
+ return TRUE
// First, make sure it can leave its square
if(isturf(mover.loc))
// Nothing but border objects stop you from leaving a tile, only one loop is needed
for(var/obj/obstacle in mover.loc)
if(!obstacle.CheckExit(mover, src) && obstacle != mover && obstacle != forget)
- mover.Bump(obstacle, 1)
- return 0
+ mover.Bump(obstacle, TRUE)
+ return FALSE
var/list/large_dense = list()
//Next, check objects to block entry that are on the border
for(var/atom/movable/border_obstacle in src)
- if(border_obstacle.flags&ON_BORDER)
- if(!border_obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != border_obstacle))
- mover.Bump(border_obstacle, 1)
- return 0
+ if(border_obstacle.flags & ON_BORDER)
+ if(!border_obstacle.CanPass(mover, mover.loc, 1) && (forget != border_obstacle))
+ mover.Bump(border_obstacle, TRUE)
+ return FALSE
else
large_dense += border_obstacle
//Then, check the turf itself
if(!src.CanPass(mover, src))
- mover.Bump(src, 1)
- return 0
+ mover.Bump(src, TRUE)
+ return FALSE
//Finally, check objects/mobs to block entry that are not on the border
for(var/atom/movable/obstacle in large_dense)
- if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle))
- mover.Bump(obstacle, 1)
- return 0
- return 1 //Nothing found to block so return success!
+ if(!obstacle.CanPass(mover, mover.loc, 1) && (forget != obstacle))
+ mover.Bump(obstacle, TRUE)
+ return FALSE
+ return TRUE //Nothing found to block so return success!
-
-/turf/Entered(atom/movable/M, atom/OL, ignoreRest = 0)
+/turf/Entered(atom/movable/M, atom/OL, ignoreRest = FALSE)
..()
if(ismob(M))
var/mob/O = M
@@ -161,7 +185,12 @@
if(loopsanity == 0)
break
loopsanity--
- A.HasProximity(M, 1)
+ A.HasProximity(M)
+
+ // If an opaque movable atom moves around we need to potentially update visibility.
+ if(M.opacity)
+ has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
+ reconsider_lights()
/turf/proc/levelupdate()
for(var/obj/O in src)
@@ -172,7 +201,7 @@
/turf/space/levelupdate()
for(var/obj/O in src)
if(O.level == 1)
- O.hide(0)
+ O.hide(FALSE)
// Removes all signs of lattice on the pos of the turf -Donkieyo
/turf/proc/RemoveLattice()
@@ -203,10 +232,10 @@
var/old_corners = corners
BeforeChange()
- if(SSair)
- SSair.remove_from_active(src)
var/old_baseturf = baseturf
+ changing_turf = TRUE
+ qdel(src) //Just get the side effects and call Destroy
var/turf/W = new path(src)
W.baseturf = old_baseturf
@@ -219,7 +248,6 @@
if(SSlighting.initialized)
recalc_atom_opacity()
lighting_object = old_lighting_object
-
affecting_lights = old_affecting_lights
corners = old_corners
if(old_opacity != opacity || dynamic_lighting != old_dynamic_lighting)
@@ -242,7 +270,7 @@
return
// I'm including `ignore_air` because BYOND lacks positional-only arguments
-/turf/proc/AfterChange(ignore_air, keep_cabling = FALSE) //called after a turf has been replaced in ChangeTurf()
+/turf/proc/AfterChange(ignore_air = FALSE, keep_cabling = FALSE) //called after a turf has been replaced in ChangeTurf()
levelupdate()
CalculateAdjacentTurfs()
@@ -253,7 +281,7 @@
for(var/obj/structure/cable/C in contents)
qdel(C)
-/turf/simulated/AfterChange(ignore_air, keep_cabling = FALSE)
+/turf/simulated/AfterChange(ignore_air = FALSE, keep_cabling = FALSE)
..()
RemoveLattice()
if(!ignore_air)
@@ -262,32 +290,38 @@
//////Assimilate Air//////
/turf/simulated/proc/Assimilate_Air()
if(air)
- var/aoxy = 0//Holders to assimilate air from nearby turfs
+ var/aoxy = 0 //Holders to assimilate air from nearby turfs
var/anitro = 0
var/aco = 0
var/atox = 0
+ var/asleep = 0
+ var/ab = 0
var/atemp = 0
var/turf_count = 0
for(var/direction in GLOB.cardinal)//Only use cardinals to cut down on lag
- var/turf/T = get_step(src,direction)
- if(istype(T,/turf/space))//Counted as no air
+ var/turf/T = get_step(src, direction)
+ if(istype(T, /turf/space))//Counted as no air
turf_count++//Considered a valid turf for air calcs
continue
- else if(istype(T,/turf/simulated/floor))
+ else if(istype(T, /turf/simulated/floor))
var/turf/simulated/S = T
if(S.air)//Add the air's contents to the holders
aoxy += S.air.oxygen
anitro += S.air.nitrogen
aco += S.air.carbon_dioxide
atox += S.air.toxins
+ asleep += S.air.sleeping_agent
+ ab += S.air.agent_b
atemp += S.air.temperature
turf_count++
- air.oxygen = (aoxy/max(turf_count,1))//Averages contents of the turfs, ignoring walls and the like
- air.nitrogen = (anitro/max(turf_count,1))
- air.carbon_dioxide = (aco/max(turf_count,1))
- air.toxins = (atox/max(turf_count,1))
- air.temperature = (atemp/max(turf_count,1))//Trace gases can get bant
+ air.oxygen = (aoxy / max(turf_count, 1)) //Averages contents of the turfs, ignoring walls and the like
+ air.nitrogen = (anitro / max(turf_count, 1))
+ air.carbon_dioxide = (aco / max(turf_count, 1))
+ air.toxins = (atox / max(turf_count, 1))
+ air.sleeping_agent = (asleep / max(turf_count, 1))
+ air.agent_b = (ab / max(turf_count, 1))
+ air.temperature = (atemp / max(turf_count, 1))
if(SSair)
SSair.add_to_active(src)
@@ -301,12 +335,11 @@
/turf/proc/kill_creatures(mob/U = null)//Will kill people/creatures and damage mechs./N
//Useful to batch-add creatures to the list.
for(var/mob/living/M in src)
- if(M==U) continue//Will not harm U. Since null != M, can be excluded to kill everyone.
- spawn(0)
- M.gib()
+ if(M == U)
+ continue//Will not harm U. Since null != M, can be excluded to kill everyone.
+ INVOKE_ASYNC(M, /mob/.proc/gib)
for(var/obj/mecha/M in src)//Mecha are not gibbed but are damaged.
- spawn(0)
- M.take_damage(100, "brute")
+ INVOKE_ASYNC(M, /obj/mecha/.proc/take_damage, 100, "brute")
/turf/proc/Bless()
flags |= NOJAUNT
@@ -363,11 +396,11 @@
// Returns the surrounding simulated turfs with open links
// Including through doors openable with the ID
-/turf/proc/AdjacentTurfsWithAccess(var/obj/item/card/id/ID = null,var/list/closed)//check access if one is passed
+/turf/proc/AdjacentTurfsWithAccess(obj/item/card/id/ID = null, list/closed)//check access if one is passed
var/list/L = new()
var/turf/simulated/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded in A*
continue
if(istype(T) && !T.density)
@@ -376,11 +409,11 @@
return L
//Idem, but don't check for ID and goes through open doors
-/turf/proc/AdjacentTurfs(var/list/closed)
+/turf/proc/AdjacentTurfs(list/closed)
var/list/L = new()
var/turf/simulated/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded by A*
continue
if(istype(T) && !T.density)
@@ -389,11 +422,11 @@
return L
// check for all turfs, including unsimulated ones
-/turf/proc/AdjacentTurfsSpace(var/obj/item/card/id/ID = null, var/list/closed)//check access if one is passed
+/turf/proc/AdjacentTurfsSpace(obj/item/card/id/ID = null, list/closed)//check access if one is passed
var/list/L = new()
var/turf/T
- for(var/dir in list(NORTHWEST,NORTHEAST,SOUTHEAST,SOUTHWEST,NORTH,EAST,SOUTH,WEST)) //arbitrarily ordered list to favor non-diagonal moves in case of ties
- T = get_step(src,dir)
+ for(var/dir in GLOB.alldirs2) //arbitrarily ordered list to favor non-diagonal moves in case of ties
+ T = get_step(src, dir)
if(T in closed) //turf already proceeded by A*
continue
if(istype(T) && !T.density)
@@ -410,20 +443,21 @@
//////////////////////////////
//Distance associates with all directions movement
-/turf/proc/Distance(var/turf/T)
- return get_dist(src,T)
+/turf/proc/Distance(turf/T)
+ return get_dist(src, T)
// This Distance proc assumes that only cardinal movement is
// possible. It results in more efficient (CPU-wise) pathing
// for bots and anything else that only moves in cardinal dirs.
/turf/proc/Distance_cardinal(turf/T)
- if(!src || !T) return 0
+ if(!src || !T)
+ return 0
return abs(src.x - T.x) + abs(src.y - T.y)
////////////////////////////////////////////////////
/turf/acid_act(acidpwr, acid_volume)
- . = 1
+ . = TRUE
var/acid_type = /obj/effect/acid
if(acidpwr >= 200) //alien acid power
acid_type = /obj/effect/acid/alien
@@ -448,7 +482,7 @@
if(!forced)
return
if(has_gravity(src))
- playsound(src, "bodyfall", 50, 1)
+ playsound(src, "bodyfall", 50, TRUE)
/turf/singularity_act()
if(intact)
@@ -458,7 +492,7 @@
if(O.invisibility == INVISIBILITY_MAXIMUM)
O.singularity_act()
ChangeTurf(baseturf)
- return(2)
+ return 2
/turf/proc/visibilityChanged()
if(SSticker)
@@ -469,25 +503,25 @@
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = I
for(var/obj/structure/cable/LC in src)
- if(LC.d1 == 0 || LC.d2==0)
- LC.attackby(C,user)
+ if(LC.d1 == 0 || LC.d2 == 0)
+ LC.attackby(C, user)
return
C.place_turf(src, user)
- return 1
+ return TRUE
else if(istype(I, /obj/item/twohanded/rcl))
var/obj/item/twohanded/rcl/R = I
if(R.loaded)
for(var/obj/structure/cable/LC in src)
- if(LC.d1 == 0 || LC.d2==0)
+ if(LC.d1 == 0 || LC.d2 == 0)
LC.attackby(R, user)
return
R.loaded.place_turf(src, user)
R.is_empty(user)
- return 0
+ return FALSE
/turf/proc/can_have_cabling()
- return 1
+ return TRUE
/turf/proc/can_lay_cable()
return can_have_cabling() & !intact
@@ -512,18 +546,15 @@
I.appearance = AM.appearance
I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM
I.loc = src
- I.dir = AM.dir
+ I.setDir(AM.dir)
I.alpha = 128
-
- if(!blueprint_data)
- blueprint_data = list()
- blueprint_data += I
+ LAZYADD(blueprint_data, I)
/turf/proc/add_blueprints_preround(atom/movable/AM)
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
add_blueprints(AM)
-/turf/proc/empty(turf_type=/turf/space)
+/turf/proc/empty(turf_type = /turf/space)
// Remove all atoms except observers, landmarks, docking ports, and (un)`simulated` atoms (lighting overlays)
var/turf/T0 = src
for(var/X in T0.GetAllContents())
@@ -536,13 +567,13 @@
continue
if(istype(A, /obj/docking_port))
continue
- qdel(A, force=TRUE)
+ qdel(A, force = TRUE)
T0.ChangeTurf(turf_type)
SSair.remove_from_active(T0)
T0.CalculateAdjacentTurfs()
- SSair.add_to_active(T0,1)
+ SSair.add_to_active(T0, TRUE)
/turf/AllowDrop()
return TRUE
diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm
index 688dc778ce3..02af9173e2b 100644
--- a/code/game/turfs/unsimulated.dm
+++ b/code/game/turfs/unsimulated.dm
@@ -40,6 +40,6 @@
nitrogen = 0
temperature = TCMB
-/turf/unsimulated/floor/plating/airless/New()
- ..()
+/turf/unsimulated/floor/plating/airless/Initialize(mapload)
+ . = ..()
name = "plating"
diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm
index f6a3a62c324..a7c73971e99 100644
--- a/code/game/turfs/unsimulated/beach.dm
+++ b/code/game/turfs/unsimulated/beach.dm
@@ -3,9 +3,9 @@
icon = 'icons/misc/beach.dmi'
var/water_overlay_image = null
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-
-/turf/unsimulated/beach/New()
- ..()
+
+/turf/unsimulated/beach/Initialize(mapload)
+ . = ..()
if(water_overlay_image)
var/image/overlay_image = image('icons/misc/beach.dmi', icon_state = water_overlay_image, layer = ABOVE_MOB_LAYER)
overlay_image.plane = GAME_PLANE
@@ -15,10 +15,10 @@
name = "Sand"
icon_state = "desert"
mouse_opacity = MOUSE_OPACITY_ICON
-
-/turf/unsimulated/beach/sand/New() //adds some aesthetic randomness to the beach sand
+
+/turf/unsimulated/beach/sand/Initialize(mapload)
+ . = ..() //adds some aesthetic randomness to the beach sand
icon_state = pick("desert", "desert0", "desert1", "desert2", "desert3", "desert4")
- ..()
/turf/unsimulated/beach/sand/dense //for boundary "walls"
density = 1
@@ -42,7 +42,7 @@
/turf/unsimulated/beach/water/Entered(atom/movable/AM, atom/OldLoc)
. = ..()
if(!linkedcontroller)
- return
+ return
if(ismob(AM))
linkedcontroller.mobinpool += AM
@@ -79,8 +79,8 @@
/turf/unsimulated/beach/water/edge_drop)
var/obj/effect/beach_drop_overlay/water_overlay
-/turf/unsimulated/beach/water/drop/New()
- ..()
+/turf/unsimulated/beach/water/drop/Initialize(mapload)
+ . = ..()
water_overlay = new(src)
/turf/unsimulated/beach/water/drop/Destroy()
diff --git a/code/game/turfs/unsimulated/floor.dm b/code/game/turfs/unsimulated/floor.dm
index 28f4e359223..750ebe015ae 100644
--- a/code/game/turfs/unsimulated/floor.dm
+++ b/code/game/turfs/unsimulated/floor.dm
@@ -7,8 +7,8 @@
name = "grass patch"
icon_state = "grass1"
-/turf/unsimulated/floor/grass/New()
- ..()
+/turf/unsimulated/floor/grass/Initialize(mapload)
+ . = ..()
icon_state = "grass[rand(1,4)]"
/turf/unsimulated/floor/snow
@@ -20,8 +20,8 @@
name = "alien floor"
icon_state = "alienpod1"
-/turf/unsimulated/floor/abductor/New()
- ..()
+/turf/unsimulated/floor/abductor/Initialize(mapload)
+ . = ..()
icon_state = "alienpod[rand(1,9)]"
/turf/unsimulated/floor/vox
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index 2683e236269..95b11353b86 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -27,7 +27,7 @@
entry += " - Observing"
else
entry += " - DEAD"
- else if(istype(C.mob, /mob/new_player))
+ else if(isnewplayer(C.mob))
entry += " - New Player"
else
entry += " - DEAD"
@@ -90,7 +90,7 @@
if(isobserver(C.mob))
msg += " - Observing"
- else if(istype(C.mob,/mob/new_player))
+ else if(isnewplayer(C.mob))
msg += " - Lobby"
else
msg += " - Playing"
@@ -106,7 +106,7 @@
if(isobserver(C.mob))
modmsg += " - Observing"
- else if(istype(C.mob,/mob/new_player))
+ else if(isnewplayer(C.mob))
modmsg += " - Lobby"
else
modmsg += " - Playing"
diff --git a/code/game/world.dm b/code/game/world.dm
index c1f6a076677..355c6280aaf 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -1,5 +1,3 @@
-#define RECOMMENDED_VERSION 510
-
GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
/world/New()
@@ -11,8 +9,11 @@ GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
enable_debugger() // Enable the extools debugger
log_world("World loaded at [time_stamp()]")
log_world("[GLOB.vars.len - GLOB.gvars_datum_in_built_vars.len] global variables")
+ #ifdef UNIT_TESTS
+ log_world("Unit Tests Are Enabled!")
+ #endif
- if(byond_version < RECOMMENDED_VERSION)
+ if(byond_version < MIN_COMPILER_VERSION || byond_build < MIN_COMPILER_BUILD)
log_world("Your server's byond version does not meet the recommended requirements for this code. Please update BYOND")
if(config && config.server_name != null && config.server_suffix && world.port > 0)
@@ -35,8 +36,9 @@ GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
Master.Initialize(10, FALSE)
-
-#undef RECOMMENDED_VERSION
+ #ifdef UNIT_TESTS
+ HandleTestRun()
+ #endif
return
@@ -230,7 +232,7 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
if(!C)
return "No client with that name on server"
- del(C)
+ qdel(C)
return "Kick Successful"
@@ -246,7 +248,7 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
if(!key_valid)
return keySpamProtect(addr)
if(input["req"] == "public")
- hub_password = hub_password_base
+ hub_password = initial(hub_password)
update_status()
return "Set listed status to public."
else
@@ -315,6 +317,11 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
GLOB.dbcon.Disconnect() // DCs cleanly from the database
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
+ #ifdef UNIT_TESTS
+ FinishTestRun()
+ return
+ #endif
+
for(var/client/C in GLOB.clients)
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
C << link("byond://[config.server]")
@@ -418,10 +425,12 @@ GLOBAL_VAR_INIT(failed_old_db_connections, 0)
GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log"
GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log"
GLOB.world_asset_log = "[GLOB.log_directory]/asset.log"
+ GLOB.tgui_log = "[GLOB.log_directory]/tgui.log"
start_log(GLOB.world_game_log)
start_log(GLOB.world_href_log)
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_qdel_log)
+ start_log(GLOB.tgui_log)
// This log follows a special format and this path should NOT be used for anything else
GLOB.runtime_summary_log = "data/logs/runtime_summary.log"
diff --git a/code/hub.dm b/code/hub.dm
index 665193a9d5b..32fe613399e 100644
--- a/code/hub.dm
+++ b/code/hub.dm
@@ -3,7 +3,6 @@
hub = "Exadv1.spacestation13"
hub_password = "kMZy3U5jJHSiBQjr"
name = "Space Station 13"
- /var/hub_password_base = "kMZy3U5jJHSiBQjr"
/* This is for any host that would like their server to appear on the main SS13 hub.
To use it, simply replace the password above, with the password found below, and it should work.
If not, let us know on the main tgstation IRC channel of irc.rizon.net #tgstation13 we can help you there.
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 21b59586bfd..25693b58f47 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -146,7 +146,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
if(kickbannedckey)
if(banned_mob && banned_mob.client && banned_mob.client.ckey == banckey)
- del(banned_mob.client)
+ qdel(banned_mob.client)
if(isjobban)
jobban_client_fullban(ckey, job)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index df156c5b0df..1eed8083a97 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -72,7 +72,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\] "
body += "\[" + M.client.get_exp_type(EXP_TYPE_CREW) + " as [EXP_TYPE_CREW]\]"
- if(istype(M, /mob/new_player))
+ if(isnewplayer(M))
body += " Hasn't Entered Game "
else
body += " \[Heal\] "
@@ -147,7 +147,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
body += {" | Cryo "}
if(M.client)
- if(!istype(M, /mob/new_player))
+ if(!isnewplayer(M))
body += "
"
body += "Transformation:"
body += " "
@@ -1004,13 +1004,13 @@ GLOBAL_VAR_INIT(gamma_ship_location, 1) // 0 = station , 1 = space
/proc/kick_clients_in_lobby(message, kick_only_afk = 0)
var/list/kicked_client_names = list()
for(var/client/C in GLOB.clients)
- if(istype(C.mob, /mob/new_player))
+ if(isnewplayer(C.mob))
if(kick_only_afk && !C.is_afk()) //Ignore clients who are not afk
continue
if(message)
to_chat(C, message)
kicked_client_names.Add("[C.ckey]")
- del(C)
+ qdel(C)
return kicked_client_names
//returns 1 to let the dragdrop code know we are trapping this event
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 4e3d2d65f30..80a60957c75 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -337,7 +337,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
ghost.reenter_corpse()
log_admin("[key_name(usr)] re-entered their body")
feedback_add_details("admin_verb","P") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- else if(istype(mob,/mob/new_player))
+ else if(isnewplayer(mob))
to_chat(src, "Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.")
else
//ghostize
@@ -542,7 +542,7 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
message_admins("[key_name_admin(src)] has warned [key_name_admin(C)] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [key_name(C)] resulting in a [AUTOBANTIME] minute ban")
to_chat(C, "You have been autobanned due to a warning by [ckey]. This is a temporary ban, it will be removed in [AUTOBANTIME] minutes.")
- del(C)
+ qdel(C)
else
message_admins("[key_name_admin(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
log_admin("[key_name(src)] has warned [warned_ckey] resulting in a [AUTOBANTIME] minute ban")
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 0d55840b5b8..e89b829f421 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -268,7 +268,7 @@
else
M_job = "Living"
- else if(istype(M,/mob/new_player))
+ else if(isnewplayer(M))
M_job = "New player"
else if(isobserver(M))
@@ -356,7 +356,7 @@
dat += "
[M.real_name]
"
else if(istype(M, /mob/living/silicon/pai))
dat += "
"
@@ -490,6 +490,9 @@
if(SSticker.mode.wizards.len)
dat += check_role_table("Wizards", SSticker.mode.wizards)
+ if(SSticker.mode.apprentices.len)
+ dat += check_role_table("Apprentices", SSticker.mode.apprentices)
+
if(SSticker.mode.raiders.len)
dat += check_role_table("Raiders", SSticker.mode.raiders)
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
index 238c380f417..a438a43eaec 100644
--- a/code/modules/admin/sql_notes.dm
+++ b/code/modules/admin/sql_notes.dm
@@ -186,9 +186,13 @@
var/err = query_list_notes.ErrorMsg()
log_game("SQL ERROR obtaining ckey from notes table. Error : \[[err]\]\n")
return
+ to_chat(usr, "Started regex note search for [search]. Please wait for results...")
+ message_admins("[usr.ckey] has started a note search with the following regex: [search] | CPU usage may be higher.")
while(query_list_notes.NextRow())
index_ckey = query_list_notes.item[1]
output += "[index_ckey] "
+ CHECK_TICK
+ message_admins("The note search started by [usr.ckey] has complete. CPU should return to normal.")
else
output += "
"}
@@ -207,7 +207,7 @@
var/obj/item/barcodescanner/scanner = W
scanner.computer = src
to_chat(user, "[scanner]'s associated machine has been set to [src].")
- audible_message("[src] lets out a low, short blip.", 2)
+ audible_message("[src] lets out a low, short blip.", hearing_distance = 2)
return 1
else
return ..()
@@ -224,13 +224,13 @@
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
- page_num = Clamp(pn, 1, num_pages)
+ page_num = clamp(pn, 1, num_pages)
if(href_list["page"])
if(num_pages == 0)
page_num = 1
else
- page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
+ page_num = clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
if(newtitle)
@@ -252,7 +252,7 @@
if(href_list["search"])
num_results = src.get_num_results()
- num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
+ num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
page_num = 1
screenstate = 4
@@ -413,7 +413,7 @@
return
if(bibledelay)
- audible_message("[src]'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
+ visible_message("[src]'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"")
else
bibledelay = 1
spawn(60)
diff --git a/code/modules/library/computers/public.dm b/code/modules/library/computers/public.dm
index f94369b11b7..3c5116bc074 100644
--- a/code/modules/library/computers/public.dm
+++ b/code/modules/library/computers/public.dm
@@ -75,7 +75,7 @@
else
var/pn = text2num(href_list["pagenum"])
if(!isnull(pn))
- page_num = Clamp(pn, 1, num_pages)
+ page_num = clamp(pn, 1, num_pages)
if(href_list["settitle"])
var/newtitle = input("Enter a title to search for:") as text|null
@@ -100,11 +100,11 @@
if(num_pages == 0)
page_num = 1
else
- page_num = Clamp(text2num(href_list["page"]), 1, num_pages)
+ page_num = clamp(text2num(href_list["page"]), 1, num_pages)
if(href_list["search"])
num_results = src.get_num_results()
- num_pages = Ceiling(num_results/LIBRARY_BOOKS_PER_PAGE)
+ num_pages = CEILING(num_results/LIBRARY_BOOKS_PER_PAGE, 1)
page_num = 1
screenstate = 1
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index ff4bc517979..fa848700557 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -38,7 +38,7 @@
if(!light_power || !light_range) // We won't emit light anyways, destroy the light source.
QDEL_NULL(light)
else
- if(!ismovableatom(loc)) // We choose what atom should be the top atom of the light here.
+ if(!ismovable(loc)) // We choose what atom should be the top atom of the light here.
. = src
else
. = loc
diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm
index bc521114d56..57302b5b168 100644
--- a/code/modules/lighting/lighting_corner.dm
+++ b/code/modules/lighting/lighting_corner.dm
@@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_mx = 0
-/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
+/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
masters = list()
masters[new_turf] = turn(diagonal, 180)
@@ -79,15 +79,16 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
active = FALSE
var/turf/T
var/thing
- for (thing in masters)
+ for(thing in masters)
T = thing
if(T.lighting_object)
active = TRUE
+ return
// God that was a mess, now to do the rest of the corner code! Hooray!
-/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b)
+/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b)
- if((abs(delta_r)+abs(delta_g)+abs(delta_b)) == 0)
+ if(!(delta_r || delta_g || delta_b)) // 0 is falsey ok
return
lum_r += delta_r
@@ -96,10 +97,10 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
if(!needs_update)
needs_update = TRUE
- GLOB.lighting_update_corners += src
+ SSlighting.corners_queue += src
/datum/lighting_corner/proc/update_objects()
- // Cache these values a head of time so 4 individual lighting objects don't all calculate them individually.
+ // Cache these values ahead of time so 4 individual lighting objects don't all calculate them individually.
var/lum_r = src.lum_r
var/lum_g = src.lum_g
var/lum_b = src.lum_b
@@ -122,19 +123,18 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
#endif
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
- for (var/TT in masters)
+ for(var/TT in masters)
var/turf/T = TT
- if(T.lighting_object)
- if(!T.lighting_object.needs_update)
- T.lighting_object.needs_update = TRUE
- GLOB.lighting_update_objects += T.lighting_object
+ if(T.lighting_object && !T.lighting_object.needs_update)
+ T.lighting_object.needs_update = TRUE
+ SSlighting.objects_queue += T.lighting_object
/datum/lighting_corner/dummy/New()
return
-/datum/lighting_corner/Destroy(var/force)
+/datum/lighting_corner/Destroy(force)
if(!force)
return QDEL_HINT_LETMELIVE
diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm
index ea3e954fa6e..168a95c07f2 100644
--- a/code/modules/lighting/lighting_object.dm
+++ b/code/modules/lighting/lighting_object.dm
@@ -5,7 +5,7 @@
icon = LIGHTING_ICON
icon_state = "transparent"
- color = LIGHTING_BASE_MATRIX
+ color = null //we manually set color in init instead
plane = LIGHTING_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
layer = LIGHTING_LAYER
@@ -18,6 +18,9 @@
/atom/movable/lighting_object/Initialize(mapload)
. = ..()
verbs.Cut()
+ //We avoid setting this in the base as if we do then the parent atom handling will add_atom_color it and that
+ //is totally unsuitable for this object, as we are always changing it's colour manually
+ color = LIGHTING_BASE_MATRIX
myturf = loc
if(myturf.lighting_object)
@@ -29,11 +32,11 @@
S.update_starlight()
needs_update = TRUE
- GLOB.lighting_update_objects += src
+ SSlighting.objects_queue += src
-/atom/movable/lighting_object/Destroy(var/force)
+/atom/movable/lighting_object/Destroy(force)
if(force)
- GLOB.lighting_update_objects -= src
+ SSlighting.objects_queue -= src
if(loc != myturf)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
@@ -143,6 +146,6 @@
return
// Override here to prevent things accidentally moving around overlays.
-/atom/movable/lighting_object/forceMove(atom/destination, var/no_tp=FALSE, var/harderforce = FALSE)
+/atom/movable/lighting_object/forceMove(atom/destination, no_tp = FALSE, harderforce = FALSE)
if(harderforce)
. = ..()
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index fc87a855dc4..9398bd9683c 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -29,7 +29,7 @@
var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update.
-/datum/light_source/New(var/atom/owner, var/atom/top)
+/datum/light_source/New(atom/owner, atom/top)
source_atom = owner // Set our new owner.
LAZYADD(source_atom.light_sources, src)
top_atom = top
@@ -56,7 +56,7 @@
LAZYREMOVE(top_atom.light_sources, src)
if(needs_update)
- GLOB.lighting_update_lights -= src
+ SSlighting.sources_queue -= src
. = ..()
@@ -65,13 +65,13 @@
// Actually that'd be great if you could!
#define EFFECT_UPDATE(level) \
if(needs_update == LIGHTING_NO_UPDATE) \
- GLOB.lighting_update_lights += src; \
+ SSlighting.sources_queue += src; \
if(needs_update < level) \
needs_update = level; \
// This proc will cause the light source to update the top atom, and add itself to the update queue.
-/datum/light_source/proc/update(var/atom/new_top_atom)
+/datum/light_source/proc/update(atom/new_top_atom)
// This top atom is different.
if(new_top_atom && new_top_atom != top_atom)
if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom.
@@ -141,7 +141,7 @@
effect_str = null
-/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
+/datum/light_source/proc/recalc_corner(datum/lighting_corner/C)
LAZYINITLIST(effect_str)
if(effect_str[C]) // Already have one.
REMOVE_CORNER(C)
@@ -220,13 +220,14 @@
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(T in view(CEILING(light_range, 1), source_turf))
- if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom)
+ if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources))
continue
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- for(thing in T.corners)
- C = thing
- corners[C] = 0
+ if(!T.has_opaque_atom)
+ if(!T.lighting_corners_initialised)
+ T.generate_missing_corners()
+ for(thing in T.corners)
+ C = thing
+ corners[C] = 0
turfs += T
source_turf.luminosity = oldlum
diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm
index f368ff5ac4b..5483eebf4e1 100644
--- a/code/modules/lighting/lighting_turf.dm
+++ b/code/modules/lighting/lighting_turf.dm
@@ -57,7 +57,7 @@
C.active = TRUE
// Used to get a scaled lumcount.
-/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
+/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
if(!lighting_object)
return 1
@@ -102,7 +102,7 @@
recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
reconsider_lights()
-/turf/proc/change_area(var/area/old_area, var/area/new_area)
+/turf/proc/change_area(area/old_area, area/new_area)
if(SSlighting.initialized)
if(new_area.dynamic_lighting != old_area.dynamic_lighting)
if(new_area.dynamic_lighting)
diff --git a/code/modules/logic/converter.dm b/code/modules/logic/converter.dm
deleted file mode 100644
index c54e3fe4882..00000000000
--- a/code/modules/logic/converter.dm
+++ /dev/null
@@ -1,143 +0,0 @@
-
-//////////////////////////////////
-// Converter Gate //
-//////////////////////////////////
-
-/*
- This gate is special enough to warrant its own file, as it overrides a lot of the logic_gate procs as well as adds a new one.
- - CONVERT Gates convert signaler and logic signals, to allow logic gates to actually be used in tandem with assemblies and station equipment like doors.
- - While technically a mono-input device, the input and output are actually completely different types of signals, and thus incompatible without this gate.
- - A signaler must be attached manually before the gate is fully functional, and will retain any frequency and code settings it had when attached.
- - You can adjust these settings through a link in the multitool menu, but the receiving mode is automatically controlled by the converter.
- - While attached, the ability to manually send the signal on the signaler through its menu is also disabled, to avoid messing up the logic system.
-*/
-
-//CONVERT Gate
-/obj/machinery/logic_gate/convert
- name = "CONVERT Gate"
- desc = "Converts signals between radio and logic types, allowing for signaller input/output from logic systems."
- icon_state = "logic_convert"
- mono_input = 1
-
- var/logic_output = 0 //When set to 1, the logic signal is the output. When set to 0, the logic signal is the input.
- var/obj/item/assembly/signaler/attached_signaler = null
-
-/obj/machinery/logic_gate/convert/handle_logic()
- output_state = input1_state
- return
-
-/obj/machinery/logic_gate/convert/attackby(obj/item/O, mob/user, params)
- if(tamperproof) //Extra precaution to avoid people attaching/removing signalers from tamperproofed converters
- return
- if(istype(O, /obj/item/assembly/signaler))
- var/obj/item/assembly/signaler/S = O
- if(S.secured)
- to_chat(user, "The [S] is already secured.")
- return
- if(attached_signaler)
- to_chat(user, "There is already a device attached, remove it first.")
- return
- user.unEquip(S)
- S.forceMove(src)
- S.holder = src
- S.toggle_secure()
- if(logic_output) //Make sure we are set to receive if the converter is set to output logic, and send if the converter is set to accept logic input
- S.receiving = 1
- else
- S.receiving = 0
- attached_signaler = S
- to_chat(user, "You attach \the [S] to the I/O connection port and secure it.")
- return
- if(attached_signaler && istype(O, /obj/item/screwdriver)) //Makes sure we remove the attached signaler before we can open up and deconstruct the machine
- var/obj/item/assembly/signaler/S = attached_signaler
- attached_signaler = null
- S.forceMove(get_turf(src))
- S.holder = null
- S.toggle_secure()
- to_chat(user, "You unsecure and detach \the [S] from the I/O connection port.")
- return
- return ..()
-
-/obj/machinery/logic_gate/convert/multitool_menu(var/mob/user, var/obj/item/multitool/P)
- var/logic_state_string
- var/menu_contents = {"
-
- "}
- return menu_contents
-
-/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O)
- ..()
- if("toggle_logic" in href_list)
- logic_output = !logic_output
- if(attached_signaler) //If we have a signaler attached, make sure we update it to send/receive when we change the logic signal desgination
- if(logic_output)
- attached_signaler.receiving = 1
- else
- attached_signaler.receiving = 0
- if(("adjust_signaler" in href_list) && attached_signaler) //Make sure that we have a signaler attached to handle this one, otherwise ignore this command
- attached_signaler.interact(user, 1)
- update_multitool_menu(user)
-
-/obj/machinery/logic_gate/convert/receive_signal(datum/signal/signal, receive_method, receive_param)
- if(logic_output)
- if(attached_signaler)
- attached_signaler.receive_signal(signal)
- return
- else
- ..()
-
-/obj/machinery/logic_gate/convert/handle_output()
- if(logic_output)
- ..()
- else
- if(attached_signaler && (output_state == LOGIC_ON || output_state == LOGIC_FLICKER))
- attached_signaler.signal()
- return
-
-/obj/machinery/logic_gate/convert/proc/process_activation(var/obj/item/D)
- if(!logic_output) //Don't bother if our input is a logic signal
- return
- if(D == attached_signaler) //Ignore if we somehow got called by a device that isn't what we have attached
- input1_state = LOGIC_FLICKER
- spawn(LOGIC_FLICKER_TIME)
- if(input1_state == LOGIC_FLICKER)
- input1_state = LOGIC_OFF
- return
diff --git a/code/modules/logic/dual_input.dm b/code/modules/logic/dual_input.dm
deleted file mode 100644
index b8f915ff46d..00000000000
--- a/code/modules/logic/dual_input.dm
+++ /dev/null
@@ -1,100 +0,0 @@
-
-//////////////////////////////////
-// Dual-Input Gates //
-//////////////////////////////////
-
-
-// OR Gate
-/obj/machinery/logic_gate/or
- name = "OR Gate"
- desc = "Outputs ON when at least one input is ON."
- icon_state = "logic_or"
-
-/obj/machinery/logic_gate/or/handle_logic()
- if(input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER || input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)
- if(input1_state == LOGIC_ON || input2_state == LOGIC_ON) //continuous signal takes priority in determining what to output
- output_state = LOGIC_ON
- else
- output_state = LOGIC_FLICKER
- else //Both inputs were off, so input is off
- output_state = LOGIC_OFF
- return
-
-// AND Gate
-/obj/machinery/logic_gate/and
- name = "AND Gate"
- desc = "Outputs ON only when both inputs are ON."
- icon_state = "logic_and"
-
-/obj/machinery/logic_gate/and/handle_logic()
- if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER))
- if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //only output a continuous signal when both inputs are continuous signals
- output_state = LOGIC_ON
- else
- output_state = LOGIC_FLICKER
- else //At least one input was off, so output is off
- output_state = LOGIC_OFF
- return
-
-// NAND Gate
-/obj/machinery/logic_gate/nand
- name = "NAND Gate"
- desc = "Outputs OFF only when both inputs are ON."
- output_state = LOGIC_ON
- icon_state = "logic_nand"
-
-/obj/machinery/logic_gate/nand/handle_logic()
- if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER))
- output_state = LOGIC_OFF //Both inputs are ON/FLICKER, so output is off
- else
- output_state = LOGIC_ON //This can only output continuous signals
- return
-
-// NOR Gate
-/obj/machinery/logic_gate/nor
- name = "NOR Gate"
- desc = "Outputs OFF when at least one input is ON."
- icon_state = "logic_nor"
- output_state = LOGIC_ON
-
-/obj/machinery/logic_gate/nor/handle_logic()
- if(input1_state == LOGIC_OFF && input2_state == LOGIC_OFF) //Both inputs are OFF, so output is ON
- output_state = LOGIC_ON //This can only output continuous signals
- else
- output_state = LOGIC_OFF
- return
-
-// XOR Gate
-/obj/machinery/logic_gate/xor
- name = "XOR Gate"
- desc = "Outputs ON when only one input is ON."
- icon_state = "logic_xor"
-
-/obj/machinery/logic_gate/xor/handle_logic()
- if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_OFF)) //Only input1 is ON/FLICKER, so output matches input1
- output_state = input1_state
- else if((input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER) && (input1_state == LOGIC_OFF)) //Only input2 is ON/FLICKER, so output matches input2
- output_state = input2_state
- else //Both inputs are ON or OFF, so output is OFF
- output_state = LOGIC_OFF
- return
-
-
-// XNOR Gate
-/obj/machinery/logic_gate/xnor
- name = "XNOR Gate"
- desc = "Outputs ON when both inputs are ON or OFF."
- icon_state = "logic_xnor"
- output_state = LOGIC_ON
-
-/obj/machinery/logic_gate/xnor/handle_logic()
- if((input1_state == LOGIC_ON || input1_state == LOGIC_FLICKER) && (input2_state == LOGIC_ON || input2_state == LOGIC_FLICKER)) //Both inputs are ON/FLICKER
- if(input1_state == LOGIC_ON && input2_state == LOGIC_ON) //Only continuous signal when both inputs are ON
- output_state = LOGIC_ON
- else //If at least one input is FLICKER, output FLICKER
- output_state = LOGIC_FLICKER
- else if(input1_state == LOGIC_OFF && input2_state == LOGIC_OFF) //Both inputs are OFF
- output_state = LOGIC_ON //Always continuous in this case
- else //Only one input is ON/FLICKER
- output_state = LOGIC_OFF
- return
diff --git a/code/modules/logic/logic_base.dm b/code/modules/logic/logic_base.dm
deleted file mode 100644
index 542cb09bc7f..00000000000
--- a/code/modules/logic/logic_base.dm
+++ /dev/null
@@ -1,284 +0,0 @@
-
-/obj/machinery/logic_gate
- name = "Logic Base"
- desc = "This does nothing except connect to things. Highly illogical, report to a coder at once if you see this in-game."
- icon = 'icons/obj/computer3.dmi'
- icon_state = "serverframe"
- density = 1
- anchored = 1
-
- settagwhitelist = list("input1_id_tag", "input2_id_tag", "output_id_tag")
-
- var/tamperproof = 0 //if set, will make the machine unable to be destroyed, adjusted, etc. via in-game interaction (USE ONLY FOR MAPPING STUFF)
- var/mono_input = 0 //if set, will ignore input2
-
- var/datum/radio_frequency/radio_connection
- var/frequency = 0
-
- /*
- Some notes on Input/Output:
- - Multiple things can be linked to the same input or output tag, just like how wires can connect multiple sources and receivers.
- - For inputs, only the last signal received BEFORE a process() call will be used in the logic handling.
- - Input states are updated immediately whenever an input signal is received, so it is possible to update multiple times within a single process cycle.
- - This means if you have multiple connected inputs, but the last signal received before the process() call is OFF, it won't matter if the others are both ON.
- - For this reason, please set up your logic properly. You can theoretically chain these infinitely, so there's no need to link multiple things to a single input.
- - For outputs, the signal will attempt to be sent out every process() call, to ensure newly connected things are updated within one process cycle
- - Connecting an output to multiple inputs should not cause issues, as long as you don't have multiple connections to a given input (see previous notes on inputs).
- - The output state is determined immediately preceeding the signal broadcast, using the input states at the time of the process() call, not when a signal is received.
- - Because of how the process cycle works, it is possible that it may take multiple cycles for a signal to fully propogate through a logic chain.
- - This is because machines attempt to process in the order they were added to the scheduler.
- - Building the logic gates at the end of the chain first may cause delays in signal propogation.
- If you take all this into consideration when linking and using logic machinery, you should have no unexpected issues with input/output. Your design flaws are on you though.
- */
-
- var/input1_id_tag = null
- var/input1_state = LOGIC_OFF
- var/input2_id_tag = null
- var/input2_state = LOGIC_OFF
- var/output_id_tag = null
- var/output_state = LOGIC_OFF
-
-/obj/machinery/logic_gate/New()
- if(tamperproof) //doing this during New so we don't have to worry about forgetting to set these vars during editting / defining
- resistance_flags |= ACID_PROOF
- ..()
- if(SSradio)
- set_frequency(frequency)
- component_parts = list()
- var/obj/item/circuitboard/logic_gate/LG = new(null)
- LG.set_type(type)
- component_parts += LG
- component_parts += new /obj/item/stack/cable_coil(null, 1)
-
-/obj/machinery/logic_gate/Initialize()
- ..()
- set_frequency(frequency)
-
-/obj/machinery/logic_gate/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_LOGIC)
- return
-
-/obj/machinery/logic_gate/Destroy()
- if(SSradio)
- SSradio.remove_object(src, frequency)
- radio_connection = null
- return ..()
-
-/obj/machinery/logic_gate/process()
- handle_logic()
- handle_output() //All output will send for at least one cycle, and will attempt to send every cycle. Hopefully this won't be too taxing.
- return
-
-/obj/machinery/logic_gate/proc/handle_logic()
- return
-
-/obj/machinery/logic_gate/proc/handle_output()
- if(!radio_connection) //can't output without this
- return
-
- if(output_id_tag == null) //Don't output to an undefined id_tag
- return
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "tag" = output_id_tag,
- "sigtype" = "logic",
- "state" = output_state,
- )
-
- radio_connection.post_signal(src, signal, filter = RADIO_LOGIC)
-
-/obj/machinery/logic_gate/receive_signal(datum/signal/signal, receive_method, receive_param)
- if(!signal.data["tag"] || ((signal.data["tag"] != input1_id_tag) && (signal.data["tag"] != input2_id_tag)) || (signal.data["sigtype"] != "logic"))
- //If the signal lacks tag data, the signal's tag data doesn't match either input id tag, or is not a "logic" signal, ignore it since it's not for us
- return
-
- if(signal.data["tag"] == input1_id_tag) //If the signal is for input1
- if(signal.data["state"] == input1_state) //If we already match, ignore the new signal since nothing changes
- return
- if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off
- input1_state = LOGIC_OFF
- return
- if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on
- input1_state = LOGIC_ON
- return
- if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off
- if(input1_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals
- return
- input1_state = LOGIC_FLICKER
- spawn(LOGIC_FLICKER_TIME)
- if(input1_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority)
- input1_state = LOGIC_OFF
- return
-
- //Now, you may be wondering why I included those returns.
- //The answer is "If you link both inputs to the same source, you're an idiot and deserve to have it break", so yeah. Deal with it.
-
- if(mono_input)
- //We only care about input1, so if we didn't receive a signal for that, we're done.
- return
-
- if(signal.data["tag"] == input2_id_tag) //If the signal is for input2 (reaching this point assumes mono_input is not set)
- if(signal.data["state"] == input2_state) //If we already match, ignore the new signal since nothing changes
- return
- if(signal.data["state"] == LOGIC_OFF) //Shut it down and keep it off
- input2_state = LOGIC_OFF
- return
- if(signal.data["state"] == LOGIC_ON) //Turn it on and keep it on
- input2_state = LOGIC_ON
- return
- if(signal.data["state"] == LOGIC_FLICKER) //Turn it on then turn it off
- if(input2_state == LOGIC_ON) //An existing continuous ON state overrides new flicker signals
- return
- input2_state = LOGIC_FLICKER
- spawn(LOGIC_FLICKER_TIME)
- if(input2_state == LOGIC_FLICKER) //Make sure we didn't get a new continuous signal set while we waited (those take priority)
- input2_state = LOGIC_OFF
- return
-
-/obj/machinery/logic_gate/multitool_menu(var/mob/user, var/obj/item/multitool/P)
- var/input1_state_string
- var/input2_state_string
- var/output_state_string
-
- switch(input1_state)
- if(LOGIC_OFF)
- input1_state_string = "OFF"
- if(LOGIC_ON)
- input1_state_string = "ON"
- if(LOGIC_FLICKER)
- input1_state_string = "FLICKER"
- else
- input1_state_string = "ERROR: UNKNOWN STATE"
-
- switch(input2_state)
- if(LOGIC_OFF)
- input2_state_string = "OFF"
- if(LOGIC_ON)
- input2_state_string = "ON"
- if(LOGIC_FLICKER)
- input2_state_string = "FLICKER"
- else
- input2_state_string = "ERROR: UNKNOWN STATE"
-
- switch(output_state)
- if(LOGIC_OFF)
- output_state_string = "OFF"
- if(LOGIC_ON)
- output_state_string = "ON"
- if(LOGIC_FLICKER)
- output_state_string = "FLICKER"
- else
- output_state_string = "ERROR: UNKNOWN STATE"
- var/menu_contents = {"
-
-
Input: [format_tag("ID Tag","input1_id_tag")]
-
Input State: [input1_state_string]
- "}
- if(!mono_input)
- menu_contents = {"
-
Input 1: [format_tag("ID Tag","input1_id_tag")]
-
Input 1 State: [input1_state_string]
-
Input 2: [format_tag("ID Tag","input2_id_tag")]
-
Input 2 State: [input2_state_string]
- "}
- menu_contents += {"
-
Output: [format_tag("ID Tag","output_id_tag")]
-
Output State: [output_state_string]
-
- "}
- return menu_contents
-
-/obj/machinery/logic_gate/convert/multitool_topic(var/mob/user,var/list/href_list,var/obj/O)
- ..()
- update_multitool_menu(user)
-
-/obj/machinery/logic_gate/attackby(obj/item/O, mob/user, params)
- if(tamperproof)
- to_chat(user, "The [src] appears to be tamperproofed! You can't interact with it!")
- return 0
- if(istype(O, /obj/item/multitool))
- update_multitool_menu(user)
- return 1
- if(istype(O, /obj/item/screwdriver))
- panel_open = !panel_open
- to_chat(user, "You [panel_open ? "open" : "close"] the access panel.")
- return 1
- if(panel_open && istype(O, /obj/item/crowbar))
- default_deconstruction_crowbar(user, O)
- return 1
- return ..()
-
-//////////////////////////////////////
-// Attack procs //
-//////////////////////////////////////
-
-/obj/machinery/logic_gate/attack_ai(mob/user)
- if(tamperproof)
- to_chat(user, "The [src] appears to be tamperproofed! You can't interface with it!")
- return 0
- add_hiddenprint(user)
- return ui_interact(user)
-
-/obj/machinery/logic_gate/attack_ghost(mob/user)
- if(tamperproof)
- to_chat(user, "The [src] appears to be tamperproofed! You can't haunt it!")
- return 0
- return ui_interact(user)
-
-/obj/machinery/logic_gate/attack_hand(mob/user)
- if(tamperproof)
- to_chat(user, "The [src] appears to be tamperproofed! You can't interact with it!")
- return 0
- . = ..()
- if(.)
- return 0
- return interact(user)
-
-/obj/machinery/logic_gate/attack_alien(mob/user) //No xeno logic, that's too silly.
- to_chat(user, "The [src] appears to be too complex! You can't comprehend it and back off in fear!")
- return 0
-
-/obj/machinery/logic_gate/attack_animal(mob/user) //No animal logic either.
- to_chat(user, "The [src] appears to be beyond your comprehension! You can't fathom it!")
- return 0
-
-/obj/machinery/logic_gate/attack_slime(mob/user) //No slime logic. Seriously.
- to_chat(user, "The [src] appears to be beyond your gelatinous understanding! You ignore it!")
- return 0
-
-/obj/machinery/logic_gate/emp_act(severity)
- if(tamperproof)
- return 0
- ..()
-
-/obj/machinery/logic_gate/ex_act(severity)
- if(tamperproof)
- return 0
- ..()
-
-/obj/machinery/logic_gate/blob_act(obj/structure/blob/B)
- if(!tamperproof)
- return ..()
-
-/obj/machinery/logic_gate/singularity_act()
- if(tamperproof)
- //This is some top-level tamperproofing right here, that's for sure. It can even defy a singularity!
- return 0
- ..()
-
-/obj/machinery/logic_gate/bullet_act()
- if(tamperproof)
- return 0
- ..()
-
-/obj/machinery/logic_gate/tesla_act(var/power)
- if(tamperproof)
- tesla_zap(src, 3, power) //If we're tamperproof, we'll just bounce the full shock of the tesla zap we got hit by, so it continues on normally without diminishing
- return 0
- ..()
diff --git a/code/modules/logic/mono_input.dm b/code/modules/logic/mono_input.dm
deleted file mode 100644
index 58b76232fa0..00000000000
--- a/code/modules/logic/mono_input.dm
+++ /dev/null
@@ -1,62 +0,0 @@
-
-//////////////////////////////////
-// Mono-Input Gates //
-//////////////////////////////////
-
-//NOT Gate
-/obj/machinery/logic_gate/not
- name = "NOT Gate"
- desc = "Accepts one input and outputs the reverse state."
- icon_state = "logic_not"
- mono_input = 1 //NOT Gates are the simplest logic gate because they only utilize one input.
- output_state = LOGIC_ON //Starts with an active output, since the input will be OFF at start
-/*
- A quick note regarding NOT Gates:
- - Connecting multiple things to the input of a NOT Gate can cause weird behaviour due to updating both when it receives a signal and when it calls process().
- - This means it will attempt to output once for every logic machine connected to its input's own process() call.
- - It will then attempt to output an additional time based on the current state when it comes to its own process() call.
- - For this reason, it is HIGHLY RECOMMENDED that you only connect a single signal source to the input of a NOT Gate to avoid signal spasms.
- - Connecting multiple things to the output of a NOT Gate should not cause this unusual behavior.
-*/
-/obj/machinery/logic_gate/not/handle_logic() //Our output will always be a continuous signal, even with a FLICKER, it just will update the output when the FLICKER ends
- if(input1_state == LOGIC_ON) //Output is OFF while input is ON
- output_state = LOGIC_OFF
- else if(input1_state == LOGIC_FLICKER) //Output is OFF while input is FLICKER, then output returns to ON when input returns to OFF
- output_state = LOGIC_OFF
- spawn(LOGIC_FLICKER_TIME + 1) //Call handle_logic again after this delay (the input should update from the spawn(LOGIC_FLICKER_TIME) in receive_signal() by then)
- handle_logic()
- else //Output is ON while input is OFF
- output_state = LOGIC_ON
- handle_output()
- return
-
-//STATUS Gate
-/obj/machinery/logic_gate/status
- name = "Status Gate"
- desc = "Accepts one input and outputs the same state, showing a colored light based on current state."
- icon_state = "logic_status"
- mono_input = 1 //STATUS Gate doesn't actually perform logic operations, but instead acts as a testing conduit.
-
-/*
- STATUS Gates are largely a diagnostics tool, but I'm sure someone will still make a logic gate rave with them anyways.
- - There is no need to actually connect an output for these to work, they just need an input to sample from.
- - STATUS Gates attempt to update their lights whenever they receive a signal.
-*/
-
-/obj/machinery/logic_gate/status/receive_signal(datum/signal/signal, receive_method, receive_params)
- ..()
- handle_logic() //STATUS Gate calls handle_logic() when it receives a signal to update its light and output_state
-
-/obj/machinery/logic_gate/status/handle_logic()
- output_state = input1_state //Output is equal to input, since it is simply a connection with an attached light
- if(output_state == LOGIC_OFF) //Red light when OFF
- set_light(2,2,"#ff0000")
- return
- if(output_state == LOGIC_ON) //Green light when ON
- set_light(2,2,"#009933")
- return
- if(output_state == LOGIC_FLICKER) //Orange light when FLICKER, then update after LOGIC_FLICKER_TIME + 1 to reflect the changed state
- set_light(2,2,"#ff9900")
- spawn(LOGIC_FLICKER_TIME + 1)
- handle_logic()
- return
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index 478438c47cb..882da0a9387 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -275,7 +275,6 @@
return
else
return ..()
- return ..()
/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index 44462dedfda..43cce5904e3 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -26,7 +26,7 @@
/obj/item/wormhole_jaunter/proc/get_destinations(mob/user)
var/list/destinations = list()
- for(var/obj/item/radio/beacon/B in world)
+ for(var/obj/item/radio/beacon/B in GLOB.global_radios)
var/turf/T = get_turf(B)
if(is_station_level(T.z))
destinations += B
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index e9728bc7901..a0ea3eb7639 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -81,7 +81,7 @@
var/mob/dead/observer/current_spirits = list()
for(var/mob/dead/observer/O in GLOB.player_list)
- if((O.following in contents))
+ if((O.orbiting in contents))
ghost_counter++
O.invisibility = 0
current_spirits |= O
@@ -97,13 +97,13 @@
force = 0
var/ghost_counter = ghost_check()
- force = Clamp((ghost_counter * 4), 0, 75)
+ force = clamp((ghost_counter * 4), 0, 75)
user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!")
..()
/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
var/ghost_counter = ghost_check()
- final_block_chance += Clamp((ghost_counter * 5), 0, 75)
+ final_block_chance += clamp((ghost_counter * 5), 0, 75)
owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!")
return ..()
diff --git a/code/modules/mining/lavaland/loot/hierophant_loot.dm b/code/modules/mining/lavaland/loot/hierophant_loot.dm
index a3f6e738380..fc81e6399ae 100644
--- a/code/modules/mining/lavaland/loot/hierophant_loot.dm
+++ b/code/modules/mining/lavaland/loot/hierophant_loot.dm
@@ -93,7 +93,7 @@
blast_range = initial(blast_range)
if(isliving(user))
var/mob/living/L = user
- var/health_percent = L.health / L.maxHealth
+ var/health_percent = max(L.health / L.maxHealth, 0) // Don't go negative
chaser_cooldown += round(health_percent * 20) //two tenths of a second for each missing 10% of health
cooldown_time += round(health_percent * 10) //one tenth of a second for each missing 10% of health
chaser_speed = max(chaser_speed + health_percent, 0.5) //one tenth of a second faster for each missing 10% of health
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 50cb7d09801..579df861c19 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -98,7 +98,7 @@
/obj/machinery/mineral/processing_unit/Destroy()
CONSOLE = null
QDEL_NULL(files)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
return ..()
@@ -120,7 +120,7 @@
CONSOLE.updateUsrDialog()
/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O)
- GET_COMPONENT(materials, /datum/component/material_container)
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/material_amount = materials.get_item_material_amount(O)
if(!materials.has_space(material_amount))
unload_mineral(O)
@@ -132,7 +132,7 @@
/obj/machinery/mineral/processing_unit/proc/get_machine_data()
var/dat = "Smelter control console
-{{/if}}
\ No newline at end of file
diff --git a/paradise.dme b/paradise.dme
index 1e60c68b509..21029f96bfc 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -28,7 +28,6 @@
#include "code\__DEFINES\clothing.dm"
#include "code\__DEFINES\colors.dm"
#include "code\__DEFINES\combat.dm"
-#include "code\__DEFINES\components.dm"
#include "code\__DEFINES\construction.dm"
#include "code\__DEFINES\contracts.dm"
#include "code\__DEFINES\crafting.dm"
@@ -76,6 +75,9 @@
#include "code\__DEFINES\typeids.dm"
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\zlevel.dm"
+#include "code\__DEFINES\dcs\flags.dm"
+#include "code\__DEFINES\dcs\helpers.dm"
+#include "code\__DEFINES\dcs\signals.dm"
#include "code\__HELPERS\_logging.dm"
#include "code\__HELPERS\_string_lists.dm"
#include "code\__HELPERS\AnimationLibrary.dm"
@@ -88,7 +90,6 @@
#include "code\__HELPERS\icon_smoothing.dm"
#include "code\__HELPERS\icons.dm"
#include "code\__HELPERS\lists.dm"
-#include "code\__HELPERS\maths.dm"
#include "code\__HELPERS\matrices.dm"
#include "code\__HELPERS\mobs.dm"
#include "code\__HELPERS\names.dm"
@@ -219,6 +220,7 @@
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\changelog.dm"
#include "code\controllers\subsystem\chat.dm"
+#include "code\controllers\subsystem\dcs.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\fires.dm"
#include "code\controllers\subsystem\garbage.dm"
@@ -244,6 +246,7 @@
#include "code\controllers\subsystem\spacedrift.dm"
#include "code\controllers\subsystem\statistics.dm"
#include "code\controllers\subsystem\sun.dm"
+#include "code\controllers\subsystem\tgui.dm"
#include "code\controllers\subsystem\throwing.dm"
#include "code\controllers\subsystem\ticker.dm"
#include "code\controllers\subsystem\timer.dm"
@@ -257,6 +260,7 @@
#include "code\datums\action.dm"
#include "code\datums\ai_law_sets.dm"
#include "code\datums\ai_laws.dm"
+#include "code\datums\armor.dm"
#include "code\datums\beam.dm"
#include "code\datums\browser.dm"
#include "code\datums\callback.dm"
@@ -296,14 +300,14 @@
#include "code\datums\components\caltrop.dm"
#include "code\datums\components\decal.dm"
#include "code\datums\components\ducttape.dm"
-#include "code\datums\components\jestosterone.dm"
+#include "code\datums\components\edit_complainer.dm"
#include "code\datums\components\label.dm"
#include "code\datums\components\material_container.dm"
#include "code\datums\components\paintable.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
#include "code\datums\components\squeak.dm"
-#include "code\datums\components\waddling.dm"
+#include "code\datums\components\swarming.dm"
#include "code\datums\diseases\_disease.dm"
#include "code\datums\diseases\_MobProcs.dm"
#include "code\datums\diseases\anxiety.dm"
@@ -360,6 +364,8 @@
#include "code\datums\diseases\advance\symptoms\weakness.dm"
#include "code\datums\diseases\advance\symptoms\weight.dm"
#include "code\datums\diseases\advance\symptoms\youth.dm"
+#include "code\datums\elements\_element.dm"
+#include "code\datums\elements\waddling.dm"
#include "code\datums\helper_datums\construction_datum.dm"
#include "code\datums\helper_datums\events.dm"
#include "code\datums\helper_datums\icon_snapshot.dm"
@@ -1281,14 +1287,6 @@
#include "code\modules\assembly\signaler.dm"
#include "code\modules\assembly\timer.dm"
#include "code\modules\assembly\voice.dm"
-#include "code\modules\atmos_automation\console.dm"
-#include "code\modules\atmos_automation\statements.dm"
-#include "code\modules\atmos_automation\implementation\digital_valves.dm"
-#include "code\modules\atmos_automation\implementation\emitters.dm"
-#include "code\modules\atmos_automation\implementation\injectors.dm"
-#include "code\modules\atmos_automation\implementation\scrubbers.dm"
-#include "code\modules\atmos_automation\implementation\sensors.dm"
-#include "code\modules\atmos_automation\implementation\vent_pump.dm"
#include "code\modules\awaymissions\corpse.dm"
#include "code\modules\awaymissions\exile.dm"
#include "code\modules\awaymissions\gateway.dm"
@@ -1670,10 +1668,6 @@
#include "code\modules\lighting\lighting_setup.dm"
#include "code\modules\lighting\lighting_source.dm"
#include "code\modules\lighting\lighting_turf.dm"
-#include "code\modules\logic\converter.dm"
-#include "code\modules\logic\dual_input.dm"
-#include "code\modules\logic\logic_base.dm"
-#include "code\modules\logic\mono_input.dm"
#include "code\modules\map_fluff\cyberiad.dm"
#include "code\modules\map_fluff\delta.dm"
#include "code\modules\map_fluff\maps.dm"
@@ -1856,7 +1850,6 @@
#include "code\modules\mob\living\carbon\human\species\vox.dm"
#include "code\modules\mob\living\carbon\human\species\vulpkanin.dm"
#include "code\modules\mob\living\carbon\human\species\wryn.dm"
-#include "code\modules\mob\living\carbon\human\species\zombies.dm"
#include "code\modules\mob\living\silicon\death.dm"
#include "code\modules\mob\living\silicon\emote.dm"
#include "code\modules\mob\living\silicon\laws.dm"
@@ -2144,7 +2137,6 @@
#include "code\modules\nano\interaction\zlevel.dm"
#include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\atmos_control.dm"
-#include "code\modules\nano\modules\crew_monitor.dm"
#include "code\modules\nano\modules\ert_manager.dm"
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\law_manager.dm"
@@ -2476,14 +2468,31 @@
#include "code\modules\surgery\organs\subtypes\xenos.dm"
#include "code\modules\telesci\bscrystal.dm"
#include "code\modules\telesci\gps.dm"
+#include "code\modules\telesci\rcs.dm"
#include "code\modules\telesci\telepad.dm"
#include "code\modules\telesci\telesci_computer.dm"
+#include "code\modules\tgui\external.dm"
+#include "code\modules\tgui\states.dm"
+#include "code\modules\tgui\tgui.dm"
+#include "code\modules\tgui\modules\_base.dm"
+#include "code\modules\tgui\modules\crew_monitor.dm"
+#include "code\modules\tgui\states\admin.dm"
+#include "code\modules\tgui\states\always.dm"
+#include "code\modules\tgui\states\conscious.dm"
+#include "code\modules\tgui\states\contained.dm"
+#include "code\modules\tgui\states\deep_inventory.dm"
+#include "code\modules\tgui\states\default.dm"
+#include "code\modules\tgui\states\hands.dm"
+#include "code\modules\tgui\states\human_adjacent.dm"
+#include "code\modules\tgui\states\inventory.dm"
+#include "code\modules\tgui\states\not_incapacitated.dm"
+#include "code\modules\tgui\states\notcontained.dm"
+#include "code\modules\tgui\states\observer.dm"
+#include "code\modules\tgui\states\physical.dm"
+#include "code\modules\tgui\states\self.dm"
+#include "code\modules\tgui\states\zlevel.dm"
#include "code\modules\tooltip\tooltip.dm"
-#include "code\modules\tram\tram.dm"
-#include "code\modules\tram\tram_control_pad.dm"
-#include "code\modules\tram\tram_floor.dm"
-#include "code\modules\tram\tram_rail.dm"
-#include "code\modules\tram\tram_wall.dm"
+#include "code\modules\unit_tests\_unit_tests.dm"
#include "code\modules\vehicle\ambulance.dm"
#include "code\modules\vehicle\atv.dm"
#include "code\modules\vehicle\janicart.dm"
@@ -2493,8 +2502,6 @@
#include "code\modules\vehicle\speedbike.dm"
#include "code\modules\vehicle\sportscar.dm"
#include "code\modules\vehicle\vehicle.dm"
-#include "code\modules\zombie\items.dm"
-#include "code\modules\zombie\organs.dm"
#include "goon\code\datums\browserOutput.dm"
#include "interface\interface.dm"
#include "interface\skin.dmf"
diff --git a/sound/ambience/ambiatmos.ogg b/sound/ambience/ambiatmos.ogg
new file mode 100644
index 00000000000..c832c677d5e
Binary files /dev/null and b/sound/ambience/ambiatmos.ogg differ
diff --git a/sound/ambience/ambiatmos2.ogg b/sound/ambience/ambiatmos2.ogg
new file mode 100644
index 00000000000..9651049c25b
Binary files /dev/null and b/sound/ambience/ambiatmos2.ogg differ
diff --git a/sound/ambience/ambicave.ogg b/sound/ambience/ambicave.ogg
new file mode 100644
index 00000000000..d78dc46a4ce
Binary files /dev/null and b/sound/ambience/ambicave.ogg differ
diff --git a/sound/ambience/ambidet1.ogg b/sound/ambience/ambidet1.ogg
new file mode 100644
index 00000000000..2ffc3ba494c
Binary files /dev/null and b/sound/ambience/ambidet1.ogg differ
diff --git a/sound/ambience/ambidet2.ogg b/sound/ambience/ambidet2.ogg
new file mode 100644
index 00000000000..7d5aae34d0b
Binary files /dev/null and b/sound/ambience/ambidet2.ogg differ
diff --git a/sound/ambience/ambifailure.ogg b/sound/ambience/ambifailure.ogg
new file mode 100644
index 00000000000..4dcf451bca6
Binary files /dev/null and b/sound/ambience/ambifailure.ogg differ
diff --git a/sound/ambience/ambigen15.ogg b/sound/ambience/ambigen15.ogg
new file mode 100644
index 00000000000..63afd437a65
Binary files /dev/null and b/sound/ambience/ambigen15.ogg differ
diff --git a/sound/ambience/ambiholy.ogg b/sound/ambience/ambiholy.ogg
new file mode 100644
index 00000000000..cd53dc2789c
Binary files /dev/null and b/sound/ambience/ambiholy.ogg differ
diff --git a/sound/ambience/ambiholy2.ogg b/sound/ambience/ambiholy2.ogg
new file mode 100644
index 00000000000..4532dd0a815
Binary files /dev/null and b/sound/ambience/ambiholy2.ogg differ
diff --git a/sound/ambience/ambiholy3.ogg b/sound/ambience/ambiholy3.ogg
new file mode 100644
index 00000000000..93f7a897e1c
Binary files /dev/null and b/sound/ambience/ambiholy3.ogg differ
diff --git a/sound/ambience/ambilava.ogg b/sound/ambience/ambilava1.ogg
similarity index 100%
rename from sound/ambience/ambilava.ogg
rename to sound/ambience/ambilava1.ogg
diff --git a/sound/ambience/ambilava2.ogg b/sound/ambience/ambilava2.ogg
new file mode 100644
index 00000000000..12e496670d0
Binary files /dev/null and b/sound/ambience/ambilava2.ogg differ
diff --git a/sound/ambience/ambilava3.ogg b/sound/ambience/ambilava3.ogg
new file mode 100644
index 00000000000..8913ad4a0ea
Binary files /dev/null and b/sound/ambience/ambilava3.ogg differ
diff --git a/sound/ambience/ambimaint.ogg b/sound/ambience/ambimaint.ogg
new file mode 100644
index 00000000000..592850a75c7
Binary files /dev/null and b/sound/ambience/ambimaint.ogg differ
diff --git a/sound/ambience/ambimystery.ogg b/sound/ambience/ambimystery.ogg
new file mode 100644
index 00000000000..b6e65c0bf62
Binary files /dev/null and b/sound/ambience/ambimystery.ogg differ
diff --git a/sound/ambience/ambinice.ogg b/sound/ambience/ambinice.ogg
new file mode 100644
index 00000000000..6ce351521bc
Binary files /dev/null and b/sound/ambience/ambinice.ogg differ
diff --git a/sound/ambience/ambiodd.ogg b/sound/ambience/ambiodd.ogg
new file mode 100644
index 00000000000..dde64a9858f
Binary files /dev/null and b/sound/ambience/ambiodd.ogg differ
diff --git a/sound/ambience/ambiruin.ogg b/sound/ambience/ambiruin.ogg
new file mode 100644
index 00000000000..ff4cef4a415
Binary files /dev/null and b/sound/ambience/ambiruin.ogg differ
diff --git a/sound/ambience/ambiruin2.ogg b/sound/ambience/ambiruin2.ogg
new file mode 100644
index 00000000000..2dc408e2b69
Binary files /dev/null and b/sound/ambience/ambiruin2.ogg differ
diff --git a/sound/ambience/ambiruin3.ogg b/sound/ambience/ambiruin3.ogg
new file mode 100644
index 00000000000..7a97ff9c60c
Binary files /dev/null and b/sound/ambience/ambiruin3.ogg differ
diff --git a/sound/ambience/ambiruin4.ogg b/sound/ambience/ambiruin4.ogg
new file mode 100644
index 00000000000..ad56a915f92
Binary files /dev/null and b/sound/ambience/ambiruin4.ogg differ
diff --git a/sound/ambience/ambiruin5.ogg b/sound/ambience/ambiruin5.ogg
new file mode 100644
index 00000000000..2073b5a2770
Binary files /dev/null and b/sound/ambience/ambiruin5.ogg differ
diff --git a/sound/ambience/ambiruin6.ogg b/sound/ambience/ambiruin6.ogg
new file mode 100644
index 00000000000..4b6c79a72d5
Binary files /dev/null and b/sound/ambience/ambiruin6.ogg differ
diff --git a/sound/ambience/ambiruin7.ogg b/sound/ambience/ambiruin7.ogg
new file mode 100644
index 00000000000..ed88fcd52d4
Binary files /dev/null and b/sound/ambience/ambiruin7.ogg differ
diff --git a/sound/ambience/ambispace2.ogg b/sound/ambience/ambispace2.ogg
new file mode 100644
index 00000000000..44b4c62c36e
Binary files /dev/null and b/sound/ambience/ambispace2.ogg differ
diff --git a/sound/ambience/ambitech.ogg b/sound/ambience/ambitech.ogg
new file mode 100644
index 00000000000..5f21514e5c4
Binary files /dev/null and b/sound/ambience/ambitech.ogg differ
diff --git a/sound/ambience/ambitech2.ogg b/sound/ambience/ambitech2.ogg
new file mode 100644
index 00000000000..bd6428bff3e
Binary files /dev/null and b/sound/ambience/ambitech2.ogg differ
diff --git a/sound/ambience/ambitech3.ogg b/sound/ambience/ambitech3.ogg
new file mode 100644
index 00000000000..effd23b1326
Binary files /dev/null and b/sound/ambience/ambitech3.ogg differ
diff --git a/sound/ambience/ambivapor1.ogg b/sound/ambience/ambivapor1.ogg
new file mode 100644
index 00000000000..4374f46710d
Binary files /dev/null and b/sound/ambience/ambivapor1.ogg differ
diff --git a/sound/ambience/aurora_caelus_short.ogg b/sound/ambience/aurora_caelus_short.ogg
new file mode 100644
index 00000000000..f6d1acaa2fe
Binary files /dev/null and b/sound/ambience/aurora_caelus_short.ogg differ
diff --git a/sound/ambience/servicebell.ogg b/sound/ambience/servicebell.ogg
new file mode 100644
index 00000000000..f55c7d5a759
Binary files /dev/null and b/sound/ambience/servicebell.ogg differ
diff --git a/sound/ambience/shipambience.ogg b/sound/ambience/shipambience.ogg
index 3c315961f71..51e090b02c8 100644
Binary files a/sound/ambience/shipambience.ogg and b/sound/ambience/shipambience.ogg differ
diff --git a/sound/music/clown.ogg b/sound/music/clown.ogg
new file mode 100644
index 00000000000..3214da56fa2
Binary files /dev/null and b/sound/music/clown.ogg differ
diff --git a/sound/voice/lowHiss1.ogg b/sound/voice/lowHiss1.ogg
new file mode 100644
index 00000000000..1373f010f84
Binary files /dev/null and b/sound/voice/lowHiss1.ogg differ
diff --git a/sound/voice/lowHiss2.ogg b/sound/voice/lowHiss2.ogg
new file mode 100644
index 00000000000..90a91db5dda
Binary files /dev/null and b/sound/voice/lowHiss2.ogg differ
diff --git a/sound/voice/lowHiss3.ogg b/sound/voice/lowHiss3.ogg
new file mode 100644
index 00000000000..ab1f2d5bdb7
Binary files /dev/null and b/sound/voice/lowHiss3.ogg differ
diff --git a/sound/voice/lowHiss4.ogg b/sound/voice/lowHiss4.ogg
new file mode 100644
index 00000000000..a5c95b02977
Binary files /dev/null and b/sound/voice/lowHiss4.ogg differ
diff --git a/tgui/.editorconfig b/tgui/.editorconfig
new file mode 100644
index 00000000000..33092d4928a
--- /dev/null
+++ b/tgui/.editorconfig
@@ -0,0 +1,13 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+max_line_length = 80
diff --git a/tgui/.eslintignore b/tgui/.eslintignore
new file mode 100644
index 00000000000..010416b9e88
--- /dev/null
+++ b/tgui/.eslintignore
@@ -0,0 +1,6 @@
+/**/node_modules
+/**/*.bundle.*
+/**/*.chunk.*
+/**/*.hot-update.*
+/packages/inferno/**
+/packages/tgui/public/shim-*.js
diff --git a/tgui/.eslintrc-harder.yml b/tgui/.eslintrc-harder.yml
new file mode 100644
index 00000000000..eb06f5b33db
--- /dev/null
+++ b/tgui/.eslintrc-harder.yml
@@ -0,0 +1,14 @@
+rules:
+ ## Enforce a maximum cyclomatic complexity allowed in a program
+ complexity: [error, { max: 25 }]
+ ## Enforce consistent brace style for blocks
+ brace-style: [error, stroustrup, { allowSingleLine: false }]
+ ## Enforce the consistent use of either backticks, double, or single quotes
+ quotes: [error, single, {
+ avoidEscape: true,
+ allowTemplateLiterals: true,
+ }]
+ react/jsx-closing-bracket-location: [error, {
+ selfClosing: after-props,
+ nonEmpty: after-props,
+ }]
diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml
new file mode 100644
index 00000000000..67e74085c7e
--- /dev/null
+++ b/tgui/.eslintrc.yml
@@ -0,0 +1,755 @@
+parser: babel-eslint
+parserOptions:
+ ecmaVersion: 2019
+ sourceType: module
+ ecmaFeatures:
+ jsx: true
+env:
+ es6: true
+ browser: true
+ node: true
+plugins:
+ - react
+settings:
+ react:
+ version: '16.10'
+rules:
+
+ ## Possible Errors
+ ## ----------------------------------------
+
+ ## Enforce “for” loop update clause moving the counter in the right
+ ## direction.
+ # for-direction: error
+ ## Enforce return statements in getters
+ # getter-return: error
+ ## Disallow using an async function as a Promise executor
+ no-async-promise-executor: error
+ ## Disallow await inside of loops
+ # no-await-in-loop: error
+ ## Disallow comparing against -0
+ # no-compare-neg-zero: error
+ ## Disallow assignment operators in conditional expressions
+ no-cond-assign: error
+ ## Disallow the use of console
+ # no-console: error
+ ## Disallow constant expressions in conditions
+ # no-constant-condition: error
+ ## Disallow control characters in regular expressions
+ # no-control-regex: error
+ ## Disallow the use of debugger
+ no-debugger: error
+ ## Disallow duplicate arguments in function definitions
+ no-dupe-args: error
+ ## Disallow duplicate keys in object literals
+ no-dupe-keys: error
+ ## Disallow duplicate case labels
+ no-duplicate-case: error
+ ## Disallow empty block statements
+ # no-empty: error
+ ## Disallow empty character classes in regular expressions
+ no-empty-character-class: error
+ ## Disallow reassigning exceptions in catch clauses
+ no-ex-assign: error
+ ## Disallow unnecessary boolean casts
+ no-extra-boolean-cast: error
+ ## Disallow unnecessary parentheses
+ # no-extra-parens: warn
+ ## Disallow unnecessary semicolons
+ no-extra-semi: error
+ ## Disallow reassigning function declarations
+ no-func-assign: error
+ ## Disallow assigning to imported bindings
+ no-import-assign: error
+ ## Disallow variable or function declarations in nested blocks
+ no-inner-declarations: error
+ ## Disallow invalid regular expression strings in RegExp constructors
+ no-invalid-regexp: error
+ ## Disallow irregular whitespace
+ no-irregular-whitespace: error
+ ## Disallow characters which are made with multiple code points in character
+ ## class syntax
+ no-misleading-character-class: error
+ ## Disallow calling global object properties as functions
+ no-obj-calls: error
+ ## Disallow calling some Object.prototype methods directly on objects
+ no-prototype-builtins: error
+ ## Disallow multiple spaces in regular expressions
+ no-regex-spaces: error
+ ## Disallow sparse arrays
+ no-sparse-arrays: error
+ ## Disallow template literal placeholder syntax in regular strings
+ no-template-curly-in-string: error
+ ## Disallow confusing multiline expressions
+ no-unexpected-multiline: error
+ ## Disallow unreachable code after return, throw, continue, and break
+ ## statements
+ # no-unreachable: warn
+ ## Disallow control flow statements in finally blocks
+ no-unsafe-finally: error
+ ## Disallow negating the left operand of relational operators
+ no-unsafe-negation: error
+ ## Disallow assignments that can lead to race conditions due to usage of
+ ## await or yield
+ # require-atomic-updates: error
+ ## Require calls to isNaN() when checking for NaN
+ use-isnan: error
+ ## Enforce comparing typeof expressions against valid strings
+ valid-typeof: error
+
+ ## Best practices
+ ## ----------------------------------------
+ ## Enforce getter and setter pairs in objects and classes
+ # accessor-pairs: error
+ ## Enforce return statements in callbacks of array methods
+ # array-callback-return: error
+ ## Enforce the use of variables within the scope they are defined
+ # block-scoped-var: error
+ ## Enforce that class methods utilize this
+ # class-methods-use-this: error
+ ## Enforce a maximum cyclomatic complexity allowed in a program
+ complexity: [error, { max: 50 }]
+ ## Require return statements to either always or never specify values
+ # consistent-return: error
+ ## Enforce consistent brace style for all control statements
+ curly: [error, all]
+ ## Require default cases in switch statements
+ # default-case: error
+ ## Enforce default parameters to be last
+ # default-param-last: error
+ ## Enforce consistent newlines before and after dots
+ dot-location: [error, property]
+ ## Enforce dot notation whenever possible
+ # dot-notation: error
+ ## Require the use of === and !==
+ eqeqeq: [error, always]
+ ## Require for-in loops to include an if statement
+ # guard-for-in: error
+ ## Enforce a maximum number of classes per file
+ # max-classes-per-file: error
+ ## Disallow the use of alert, confirm, and prompt
+ # no-alert: error
+ ## Disallow the use of arguments.caller or arguments.callee
+ # no-caller: error
+ ## Disallow lexical declarations in case clauses
+ no-case-declarations: error
+ ## Disallow division operators explicitly at the beginning of regular
+ ## expressions
+ # no-div-regex: error
+ ## Disallow else blocks after return statements in if statements
+ # no-else-return: error
+ ## Disallow empty functions
+ # no-empty-function: error
+ ## Disallow empty destructuring patterns
+ no-empty-pattern: error
+ ## Disallow null comparisons without type-checking operators
+ # no-eq-null: error
+ ## Disallow the use of eval()
+ # no-eval: error
+ ## Disallow extending native types
+ # no-extend-native: error
+ ## Disallow unnecessary calls to .bind()
+ # no-extra-bind: error
+ ## Disallow unnecessary labels
+ # no-extra-label: error
+ ## Disallow fallthrough of case statements
+ no-fallthrough: error
+ ## Disallow leading or trailing decimal points in numeric literals
+ # no-floating-decimal: error
+ ## Disallow assignments to native objects or read-only global variables
+ no-global-assign: error
+ ## Disallow shorthand type conversions
+ # no-implicit-coercion: error
+ ## Disallow variable and function declarations in the global scope
+ # no-implicit-globals: error
+ ## Disallow the use of eval()-like methods
+ # no-implied-eval: error
+ ## Disallow this keywords outside of classes or class-like objects
+ # no-invalid-this: error
+ ## Disallow the use of the __iterator__ property
+ # no-iterator: error
+ ## Disallow labeled statements
+ # no-labels: error
+ ## Disallow unnecessary nested blocks
+ # no-lone-blocks: error
+ ## Disallow function declarations that contain unsafe references inside
+ ## loop statements
+ # no-loop-func: error
+ ## Disallow magic numbers
+ # no-magic-numbers: error
+ ## Disallow multiple spaces
+ no-multi-spaces: warn
+ ## Disallow multiline strings
+ # no-multi-str: error
+ ## Disallow new operators outside of assignments or comparisons
+ # no-new: error
+ ## Disallow new operators with the Function object
+ # no-new-func: error
+ ## Disallow new operators with the String, Number, and Boolean objects
+ # no-new-wrappers: error
+ ## Disallow octal literals
+ no-octal: error
+ ## Disallow octal escape sequences in string literals
+ no-octal-escape: error
+ ## Disallow reassigning function parameters
+ # no-param-reassign: error
+ ## Disallow the use of the __proto__ property
+ # no-proto: error
+ ## Disallow variable redeclaration
+ no-redeclare: error
+ ## Disallow certain properties on certain objects
+ # no-restricted-properties: error
+ ## Disallow assignment operators in return statements
+ no-return-assign: error
+ ## Disallow unnecessary return await
+ # no-return-await: error
+ ## Disallow javascript: urls
+ # no-script-url: error
+ ## Disallow assignments where both sides are exactly the same
+ no-self-assign: error
+ ## Disallow comparisons where both sides are exactly the same
+ # no-self-compare: error
+ ## Disallow comma operators
+ no-sequences: error
+ ## Disallow throwing literals as exceptions
+ # no-throw-literal: error
+ ## Disallow unmodified loop conditions
+ # no-unmodified-loop-condition: error
+ ## Disallow unused expressions
+ # no-unused-expressions: error
+ ## Disallow unused labels
+ no-unused-labels: warn
+ ## Disallow unnecessary calls to .call() and .apply()
+ # no-useless-call: error
+ ## Disallow unnecessary catch clauses
+ # no-useless-catch: error
+ ## Disallow unnecessary concatenation of literals or template literals
+ # no-useless-concat: error
+ ## Disallow unnecessary escape characters
+ no-useless-escape: warn
+ ## Disallow redundant return statements
+ # no-useless-return: error
+ ## Disallow void operators
+ # no-void: error
+ ## Disallow specified warning terms in comments
+ # no-warning-comments: error
+ ## Disallow with statements
+ no-with: error
+ ## Enforce using named capture group in regular expression
+ # prefer-named-capture-group: error
+ ## Require using Error objects as Promise rejection reasons
+ # prefer-promise-reject-errors: error
+ ## Disallow use of the RegExp constructor in favor of regular expression
+ ## literals
+ # prefer-regex-literals: error
+ ## Enforce the consistent use of the radix argument when using parseInt()
+ radix: error
+ ## Disallow async functions which have no await expression
+ # require-await: error
+ ## Enforce the use of u flag on RegExp
+ # require-unicode-regexp: error
+ ## Require var declarations be placed at the top of their containing scope
+ # vars-on-top: error
+ ## Require parentheses around immediate function invocations
+ # wrap-iife: error
+ ## Require or disallow “Yoda” conditions
+ # yoda: error
+
+ ## Strict mode
+ ## ----------------------------------------
+ ## Require or disallow strict mode directives
+ strict: error
+
+ ## Variables
+ ## ----------------------------------------
+ ## Require or disallow initialization in variable declarations
+ # init-declarations: error
+ ## Disallow deleting variables
+ no-delete-var: error
+ ## Disallow labels that share a name with a variable
+ # no-label-var: error
+ ## Disallow specified global variables
+ # no-restricted-globals: error
+ ## Disallow variable declarations from shadowing variables declared in
+ ## the outer scope
+ # no-shadow: error
+ ## Disallow identifiers from shadowing restricted names
+ no-shadow-restricted-names: error
+ ## Disallow the use of undeclared variables unless mentioned
+ ## in /*global*/ comments
+ no-undef: error
+ ## Disallow initializing variables to undefined
+ no-undef-init: error
+ ## Disallow the use of undefined as an identifier
+ # no-undefined: error
+ ## Disallow unused variables
+ # no-unused-vars: error
+ ## Disallow the use of variables before they are defined
+ # no-use-before-define: error
+
+ ## Code style
+ ## ----------------------------------------
+ ## Enforce linebreaks after opening and before closing array brackets
+ array-bracket-newline: [error, consistent]
+ ## Enforce consistent spacing inside array brackets
+ array-bracket-spacing: [error, never]
+ ## Enforce line breaks after each array element
+ # array-element-newline: error
+ ## Disallow or enforce spaces inside of blocks after opening block and
+ ## before closing block
+ block-spacing: [error, always]
+ ## Enforce consistent brace style for blocks
+ # brace-style: [error, stroustrup, { allowSingleLine: false }]
+ ## Enforce camelcase naming convention
+ # camelcase: error
+ ## Enforce or disallow capitalization of the first letter of a comment
+ # capitalized-comments: error
+ ## Require or disallow trailing commas
+ comma-dangle: [error, {
+ arrays: always-multiline,
+ objects: always-multiline,
+ imports: always-multiline,
+ exports: always-multiline,
+ functions: only-multiline, ## Optional on functions
+ }]
+ ## Enforce consistent spacing before and after commas
+ comma-spacing: [error, { before: false, after: true }]
+ ## Enforce consistent comma style
+ comma-style: [error, last]
+ ## Enforce consistent spacing inside computed property brackets
+ computed-property-spacing: [error, never]
+ ## Enforce consistent naming when capturing the current execution context
+ # consistent-this: error
+ ## Require or disallow newline at the end of files
+ # eol-last: error
+ ## Require or disallow spacing between function identifiers and their
+ ## invocations
+ func-call-spacing: [error, never]
+ ## Require function names to match the name of the variable or property
+ ## to which they are assigned
+ # func-name-matching: error
+ ## Require or disallow named function expressions
+ # func-names: error
+ ## Enforce the consistent use of either function declarations or expressions
+ func-style: [error, expression]
+ ## Enforce line breaks between arguments of a function call
+ # function-call-argument-newline: error
+ ## Enforce consistent line breaks inside function parentheses
+ ## NOTE: This rule does not honor a newline on opening paren.
+ # function-paren-newline: [error, never]
+ ## Disallow specified identifiers
+ # id-blacklist: error
+ ## Enforce minimum and maximum identifier lengths
+ # id-length: error
+ ## Require identifiers to match a specified regular expression
+ # id-match: error
+ ## Enforce the location of arrow function bodies
+ # implicit-arrow-linebreak: error
+ ## Enforce consistent indentation
+ indent: [error, 2, { SwitchCase: 1 }]
+ ## Enforce the consistent use of either double or single quotes in JSX
+ ## attributes
+ jsx-quotes: [error, prefer-double]
+ ## Enforce consistent spacing between keys and values in object literal
+ ## properties
+ key-spacing: [error, { beforeColon: false, afterColon: true }]
+ ## Enforce consistent spacing before and after keywords
+ keyword-spacing: [error, { before: true, after: true }]
+ ## Enforce position of line comments
+ # line-comment-position: error
+ ## Enforce consistent linebreak style
+ # linebreak-style: error
+ ## Require empty lines around comments
+ # lines-around-comment: error
+ ## Require or disallow an empty line between class members
+ # lines-between-class-members: error
+ ## Enforce a maximum depth that blocks can be nested
+ # max-depth: error
+ ## Enforce a maximum line length
+ max-len: [error, {
+ code: 80,
+ ## Ignore imports
+ ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
+ ignoreUrls: true,
+ ignoreRegExpLiterals: true,
+ }]
+ ## Enforce a maximum number of lines per file
+ # max-lines: error
+ ## Enforce a maximum number of line of code in a function
+ # max-lines-per-function: error
+ ## Enforce a maximum depth that callbacks can be nested
+ # max-nested-callbacks: error
+ ## Enforce a maximum number of parameters in function definitions
+ # max-params: error
+ ## Enforce a maximum number of statements allowed in function blocks
+ # max-statements: error
+ ## Enforce a maximum number of statements allowed per line
+ # max-statements-per-line: error
+ ## Enforce a particular style for multiline comments
+ # multiline-comment-style: error
+ ## Enforce newlines between operands of ternary expressions
+ multiline-ternary: [error, always-multiline]
+ ## Require constructor names to begin with a capital letter
+ # new-cap: error
+ ## Enforce or disallow parentheses when invoking a constructor with no
+ ## arguments
+ # new-parens: error
+ ## Require a newline after each call in a method chain
+ # newline-per-chained-call: error
+ ## Disallow Array constructors
+ # no-array-constructor: error
+ ## Disallow bitwise operators
+ # no-bitwise: error
+ ## Disallow continue statements
+ # no-continue: error
+ ## Disallow inline comments after code
+ # no-inline-comments: error
+ ## Disallow if statements as the only statement in else blocks
+ # no-lonely-if: error
+ ## Disallow mixed binary operators
+ # no-mixed-operators: error
+ ## Disallow mixed spaces and tabs for indentation
+ no-mixed-spaces-and-tabs: error
+ ## Disallow use of chained assignment expressions
+ # no-multi-assign: error
+ ## Disallow multiple empty lines
+ # no-multiple-empty-lines: error
+ ## Disallow negated conditions
+ # no-negated-condition: error
+ ## Disallow nested ternary expressions
+ # no-nested-ternary: error
+ ## Disallow Object constructors
+ # no-new-object: error
+ ## Disallow the unary operators ++ and --
+ # no-plusplus: error
+ ## Disallow specified syntax
+ # no-restricted-syntax: error
+ ## Disallow all tabs
+ # no-tabs: error
+ ## Disallow ternary operators
+ # no-ternary: error
+ ## Disallow trailing whitespace at the end of lines
+ # no-trailing-spaces: error
+ ## Disallow dangling underscores in identifiers
+ # no-underscore-dangle: error
+ ## Disallow ternary operators when simpler alternatives exist
+ # no-unneeded-ternary: error
+ ## Disallow whitespace before properties
+ no-whitespace-before-property: error
+ ## Enforce the location of single-line statements
+ # nonblock-statement-body-position: error
+ ## Enforce consistent line breaks inside braces
+ # object-curly-newline: [error, { multiline: true }]
+ ## Enforce consistent spacing inside braces
+ object-curly-spacing: [error, always]
+ ## Enforce placing object properties on separate lines
+ # object-property-newline: error
+ ## Enforce variables to be declared either together or separately in
+ ## functions
+ # one-var: error
+ ## Require or disallow newlines around variable declarations
+ # one-var-declaration-per-line: error
+ ## Require or disallow assignment operator shorthand where possible
+ # operator-assignment: error
+ ## Enforce consistent linebreak style for operators
+ operator-linebreak: [error, before]
+ ## Require or disallow padding within blocks
+ # padded-blocks: error
+ ## Require or disallow padding lines between statements
+ # padding-line-between-statements: error
+ ## Disallow using Object.assign with an object literal as the first
+ ## argument and prefer the use of object spread instead.
+ # prefer-object-spread: error
+ ## Require quotes around object literal property names
+ # quote-props: error
+ ## Enforce the consistent use of either backticks, double, or single quotes
+ # quotes: [error, single]
+ ## Require or disallow semicolons instead of ASI
+ semi: error
+ ## Enforce consistent spacing before and after semicolons
+ semi-spacing: [error, { before: false, after: true }]
+ ## Enforce location of semicolons
+ semi-style: [error, last]
+ ## Require object keys to be sorted
+ # sort-keys: error
+ ## Require variables within the same declaration block to be sorted
+ # sort-vars: error
+ ## Enforce consistent spacing before blocks
+ space-before-blocks: [error, always]
+ ## Enforce consistent spacing before function definition opening parenthesis
+ space-before-function-paren: [error, {
+ anonymous: always,
+ named: never,
+ asyncArrow: always,
+ }]
+ ## Enforce consistent spacing inside parentheses
+ space-in-parens: [error, never]
+ ## Require spacing around infix operators
+ # space-infix-ops: error
+ ## Enforce consistent spacing before or after unary operators
+ # space-unary-ops: error
+ ## Enforce consistent spacing after the // or /* in a comment
+ spaced-comment: [error, always]
+ ## Enforce spacing around colons of switch statements
+ switch-colon-spacing: [error, { before: false, after: true }]
+ ## Require or disallow spacing between template tags and their literals
+ template-tag-spacing: [error, never]
+ ## Require or disallow Unicode byte order mark (BOM)
+ # unicode-bom: [error, never]
+ ## Require parenthesis around regex literals
+ # wrap-regex: error
+
+ ## ES6
+ ## ----------------------------------------
+ ## Require braces around arrow function bodies
+ # arrow-body-style: error
+ ## Require parentheses around arrow function arguments
+ arrow-parens: [error, as-needed]
+ ## Enforce consistent spacing before and after the arrow in arrow functions
+ arrow-spacing: [error, { before: true, after: true }]
+ ## Require super() calls in constructors
+ # constructor-super: error
+ ## Enforce consistent spacing around * operators in generator functions
+ generator-star-spacing: [error, { before: false, after: true }]
+ ## Disallow reassigning class members
+ no-class-assign: error
+ ## Disallow arrow functions where they could be confused with comparisons
+ # no-confusing-arrow: error
+ ## Disallow reassigning const variables
+ no-const-assign: error
+ ## Disallow duplicate class members
+ no-dupe-class-members: error
+ ## Disallow duplicate module imports
+ # no-duplicate-imports: error
+ ## Disallow new operators with the Symbol object
+ no-new-symbol: error
+ ## Disallow specified modules when loaded by import
+ # no-restricted-imports: error
+ ## Disallow this/super before calling super() in constructors
+ no-this-before-super: error
+ ## Disallow unnecessary computed property keys in object literals
+ # no-useless-computed-key: error
+ ## Disallow unnecessary constructors
+ # no-useless-constructor: error
+ ## Disallow renaming import, export, and destructured assignments to the
+ ## same name
+ # no-useless-rename: error
+ ## Require let or const instead of var
+ no-var: error
+ ## Require or disallow method and property shorthand syntax for object
+ ## literals
+ # object-shorthand: error
+ ## Require using arrow functions for callbacks
+ prefer-arrow-callback: error
+ ## Require const declarations for variables that are never reassigned after
+ ## declared
+ # prefer-const: error
+ ## Require destructuring from arrays and/or objects
+ # prefer-destructuring: error
+ ## Disallow parseInt() and Number.parseInt() in favor of binary, octal, and
+ ## hexadecimal literals
+ # prefer-numeric-literals: error
+ ## Require rest parameters instead of arguments
+ # prefer-rest-params: error
+ ## Require spread operators instead of .apply()
+ # prefer-spread: error
+ ## Require template literals instead of string concatenation
+ # prefer-template: error
+ ## Require generator functions to contain yield
+ # require-yield: error
+ ## Enforce spacing between rest and spread operators and their expressions
+ # rest-spread-spacing: error
+ ## Enforce sorted import declarations within modules
+ # sort-imports: error
+ ## Require symbol descriptions
+ # symbol-description: error
+ ## Require or disallow spacing around embedded expressions of template
+ ## strings
+ # template-curly-spacing: error
+ ## Require or disallow spacing around the * in yield* expressions
+ yield-star-spacing: [error, { before: false, after: true }]
+
+ ## React
+ ## ----------------------------------------
+ ## Enforces consistent naming for boolean props
+ react/boolean-prop-naming: error
+ ## Forbid "button" element without an explicit "type" attribute
+ react/button-has-type: error
+ ## Prevent extraneous defaultProps on components
+ react/default-props-match-prop-types: error
+ ## Rule enforces consistent usage of destructuring assignment in component
+ # react/destructuring-assignment: [error, always, { ignoreClassFields: true }]
+ ## Prevent missing displayName in a React component definition
+ react/display-name: error
+ ## Forbid certain props on Components
+ # react/forbid-component-props: error
+ ## Forbid certain props on DOM Nodes
+ # react/forbid-dom-props: error
+ ## Forbid certain elements
+ # react/forbid-elements: error
+ ## Forbid certain propTypes
+ # react/forbid-prop-types: error
+ ## Forbid foreign propTypes
+ # react/forbid-foreign-prop-types: error
+ ## Prevent using this.state inside this.setState
+ react/no-access-state-in-setstate: error
+ ## Prevent using Array index in key props
+ # react/no-array-index-key: error
+ ## Prevent passing children as props
+ react/no-children-prop: error
+ ## Prevent usage of dangerous JSX properties
+ react/no-danger: error
+ ## Prevent problem with children and props.dangerouslySetInnerHTML
+ react/no-danger-with-children: error
+ ## Prevent usage of deprecated methods, including component lifecycle
+ ## methods
+ react/no-deprecated: error
+ ## Prevent usage of setState in componentDidMount
+ react/no-did-mount-set-state: error
+ ## Prevent usage of setState in componentDidUpdate
+ react/no-did-update-set-state: error
+ ## Prevent direct mutation of this.state
+ react/no-direct-mutation-state: error
+ ## Prevent usage of findDOMNode
+ react/no-find-dom-node: error
+ ## Prevent usage of isMounted
+ react/no-is-mounted: error
+ ## Prevent multiple component definition per file
+ # react/no-multi-comp: error
+ ## Prevent usage of shouldComponentUpdate when extending React.PureComponent
+ react/no-redundant-should-component-update: error
+ ## Prevent usage of the return value of React.render
+ react/no-render-return-value: error
+ ## Prevent usage of setState
+ # react/no-set-state: error
+ ## Prevent common casing typos
+ react/no-typos: error
+ ## Prevent using string references in ref attribute.
+ react/no-string-refs: error
+ ## Prevent using this in stateless functional components
+ react/no-this-in-sfc: error
+ ## Prevent invalid characters from appearing in markup
+ react/no-unescaped-entities: error
+ ## Prevent usage of unknown DOM property (fixable)
+ # react/no-unknown-property: error
+ ## Prevent usage of unsafe lifecycle methods
+ react/no-unsafe: error
+ ## Prevent definitions of unused prop types
+ react/no-unused-prop-types: error
+ ## Prevent definitions of unused state properties
+ react/no-unused-state: error
+ ## Prevent usage of setState in componentWillUpdate
+ react/no-will-update-set-state: error
+ ## Enforce ES5 or ES6 class for React Components
+ react/prefer-es6-class: error
+ ## Enforce that props are read-only
+ react/prefer-read-only-props: error
+ ## Enforce stateless React Components to be written as a pure function
+ react/prefer-stateless-function: error
+ ## Prevent missing props validation in a React component definition
+ # react/prop-types: error
+ ## Prevent missing React when using JSX
+ # react/react-in-jsx-scope: error
+ ## Enforce a defaultProps definition for every prop that is not a required
+ ## prop
+ # react/require-default-props: error
+ ## Enforce React components to have a shouldComponentUpdate method
+ # react/require-optimization: error
+ ## Enforce ES5 or ES6 class for returning value in render function
+ react/require-render-return: error
+ ## Prevent extra closing tags for components without children (fixable)
+ react/self-closing-comp: error
+ ## Enforce component methods order (fixable)
+ # react/sort-comp: error
+ ## Enforce propTypes declarations alphabetical sorting
+ # react/sort-prop-types: error
+ ## Enforce the state initialization style to be either in a constructor or
+ ## with a class property
+ react/state-in-constructor: error
+ ## Enforces where React component static properties should be positioned.
+ # react/static-property-placement: error
+ ## Enforce style prop value being an object
+ react/style-prop-object: error
+ ## Prevent void DOM elements (e.g. , ) from receiving children
+ react/void-dom-elements-no-children: error
+
+ ## JSX-specific rules
+ ## ----------------------------------------
+ ## Enforce boolean attributes notation in JSX (fixable)
+ react/jsx-boolean-value: error
+ ## Enforce or disallow spaces inside of curly braces in JSX attributes and
+ ## expressions.
+ # react/jsx-child-element-spacing: error
+ ## Validate closing bracket location in JSX (fixable)
+ react/jsx-closing-bracket-location: [error, {
+ ## NOTE: Not really sure about enforcing this one
+ selfClosing: false,
+ nonEmpty: after-props,
+ }]
+ ## Validate closing tag location in JSX (fixable)
+ react/jsx-closing-tag-location: error
+ ## Enforce or disallow newlines inside of curly braces in JSX attributes and
+ ## expressions (fixable)
+ react/jsx-curly-newline: error
+ ## Enforce or disallow spaces inside of curly braces in JSX attributes and
+ ## expressions (fixable)
+ react/jsx-curly-spacing: error
+ ## Enforce or disallow spaces around equal signs in JSX attributes (fixable)
+ react/jsx-equals-spacing: error
+ ## Restrict file extensions that may contain JSX
+ # react/jsx-filename-extension: error
+ ## Enforce position of the first prop in JSX (fixable)
+ # react/jsx-first-prop-new-line: error
+ ## Enforce event handler naming conventions in JSX
+ react/jsx-handler-names: error
+ ## Validate JSX indentation (fixable)
+ react/jsx-indent: [error, 2, {
+ checkAttributes: true,
+ }]
+ ## Validate props indentation in JSX (fixable)
+ react/jsx-indent-props: [error, 2]
+ ## Validate JSX has key prop when in array or iterator
+ react/jsx-key: error
+ ## Validate JSX maximum depth
+ react/jsx-max-depth: [error, { max: 10 }] ## Generous
+ ## Limit maximum of props on a single line in JSX (fixable)
+ # react/jsx-max-props-per-line: error
+ ## Prevent usage of .bind() and arrow functions in JSX props
+ # react/jsx-no-bind: error
+ ## Prevent comments from being inserted as text nodes
+ react/jsx-no-comment-textnodes: error
+ ## Prevent duplicate props in JSX
+ react/jsx-no-duplicate-props: error
+ ## Prevent usage of unwrapped JSX strings
+ # react/jsx-no-literals: error
+ ## Prevent usage of unsafe target='_blank'
+ react/jsx-no-target-blank: error
+ ## Disallow undeclared variables in JSX
+ react/jsx-no-undef: error
+ ## Disallow unnecessary fragments (fixable)
+ react/jsx-no-useless-fragment: error
+ ## Limit to one expression per line in JSX
+ # react/jsx-one-expression-per-line: error
+ ## Enforce curly braces or disallow unnecessary curly braces in JSX
+ # react/jsx-curly-brace-presence: error
+ ## Enforce shorthand or standard form for React fragments
+ react/jsx-fragments: error
+ ## Enforce PascalCase for user-defined JSX components
+ react/jsx-pascal-case: error
+ ## Disallow multiple spaces between inline JSX props (fixable)
+ react/jsx-props-no-multi-spaces: error
+ ## Disallow JSX props spreading
+ # react/jsx-props-no-spreading: error
+ ## Enforce default props alphabetical sorting
+ # react/jsx-sort-default-props: error
+ ## Enforce props alphabetical sorting (fixable)
+ # react/jsx-sort-props: error
+ ## Validate whitespace in and around the JSX opening and closing brackets
+ ## (fixable)
+ react/jsx-tag-spacing: error
+ ## Prevent React to be incorrectly marked as unused
+ react/jsx-uses-react: error
+ ## Prevent variables used in JSX to be incorrectly marked as unused
+ react/jsx-uses-vars: error
+ ## Prevent missing parentheses around multilines JSX (fixable)
+ react/jsx-wrap-multilines: error
diff --git a/tgui/.gitattributes b/tgui/.gitattributes
new file mode 100644
index 00000000000..0016cc3bf67
--- /dev/null
+++ b/tgui/.gitattributes
@@ -0,0 +1,10 @@
+* text=auto
+
+## Enforce text mode and LF line breaks
+*.js text eol=lf
+*.css text eol=lf
+*.html text eol=lf
+*.json text eol=lf
+
+## Treat bundles as binary and ignore them during conflicts
+*.bundle.* binary merge=tgui-merge-bundle
diff --git a/tgui/.gitignore b/tgui/.gitignore
new file mode 100644
index 00000000000..416ca3768da
--- /dev/null
+++ b/tgui/.gitignore
@@ -0,0 +1,7 @@
+node_modules
+*.log
+package-lock.json
+
+/packages/tgui/public/.tmp/**/*
+/packages/tgui/public/**/*.hot-update.*
+/packages/tgui/public/**/*.map
diff --git a/tgui/README.md b/tgui/README.md
new file mode 100644
index 00000000000..5ddeb18fdda
--- /dev/null
+++ b/tgui/README.md
@@ -0,0 +1,187 @@
+# tgui
+
+## Introduction
+
+tgui is a robust user interface framework of /tg/station.
+
+tgui is very different from most UIs you will encounter in BYOND programming.
+It is heavily reliant on Javascript and web technologies as opposed to DM.
+If you are familiar with NanoUI (a library which can be found on almost
+every other SS13 codebase), tgui should be fairly easy to pick up.
+
+## Learn tgui
+
+People come to tgui from different backgrounds and with different
+learning styles. Whether you prefer a more theoretical or a practical
+approach, we hope you’ll find this section helpful.
+
+### Practical Tutorial
+
+If you are completely new to frontend and prefer to **learn by doing**,
+start with our [practical tutorial](docs/tutorial-and-examples.md).
+
+### Guides
+
+This project uses **Inferno** - a very fast UI rendering engine with a similar
+API to React. Take your time to read these guides:
+
+- [React guide](https://reactjs.org/docs/hello-world.html)
+- [Inferno documentation](https://infernojs.org/docs/guides/components) -
+highlights differences with React.
+
+If you were already familiar with an older, Ractive-based tgui, and want
+to translate concepts between old and new tgui, read this
+[interface conversion guide](docs/converting-old-tgui-interfaces.md).
+
+## Pre-requisites
+
+You will need these programs to start developing in tgui:
+
+- [Node v12.13+](https://nodejs.org/en/download/)
+- [Yarn v1.19+](https://yarnpkg.com/en/docs/install)
+- [MSys2](https://www.msys2.org/) (optional)
+
+> MSys2 closely replicates a unix-like environment which is necessary for
+> the `bin/tgui` script to run. It comes with a robust "mintty" terminal
+> emulator which is better than any standard Windows shell, it supports
+> "git" out of the box (almost like Git for Windows, but better), has
+> a "pacman" package manager, and you can install a text editor like "vim"
+> for a full boomer experience.
+
+## Usage
+
+**For MSys2, Git Bash, WSL, Linux or macOS users:**
+
+First and foremost, change your directory to `tgui`.
+
+Run `bin/tgui --install-git-hooks` (optional) to install merge drivers
+which will assist you in conflict resolution when rebasing your branches.
+
+Run one of the following:
+
+- `bin/tgui` - build the project in production mode.
+- `bin/tgui --dev` - launch a development server.
+ - tgui development server provides you with incremental compilation,
+ hot module replacement and logging facilities in all running instances
+ of tgui. In short, this means that you will instantly see changes in the
+ game as you code it. Very useful, highly recommended.
+ - In order to use it, you should start the game server first, connect to it
+ and wait until the world has been properly loaded and you are no longer
+ in the lobby. Start tgui dev server. You'll know that it's hooked correctly
+ if data gets dumped to the log when tgui windows are opened.
+- `bin/tgui --dev --reload` - reload byond cache once.
+- `bin/tgui --dev --debug` - run server with debug logging enabled.
+- `bin/tgui --dev --no-hot` - disable hot module replacement (helps when
+doing development on IE8).
+- `bin/tgui --lint` - show problems with the code.
+- `bin/tgui --lint --fix` - auto-fix problems with the code.
+- `bin/tgui --analyze` - run a bundle analyzer.
+- `bin/tgui --clean` - clean up project repo.
+- `bin/tgui [webpack options]` - build the project with custom webpack
+options.
+
+**For everyone else:**
+
+If you haven't opened the console already, you can do that by holding
+Shift and right clicking on the `tgui` folder, then pressing
+either `Open command window here` or `Open PowerShell window here`.
+
+Run `yarn install` to install npm dependencies, then one of the following:
+
+- `yarn run build` - build the project in production mode.
+- `yarn run watch` - launch a development server.
+- `yarn run lint` - show problems with the code.
+- `yarn run lint --fix` - auto-fix problems with the code.
+- `yarn run analyze` - run a bundle analyzer.
+
+We also got some batch files in store, for those who don't like fiddling
+with the console:
+
+- `bin/tgui-build.bat` - build the project in production mode.
+- `bin/tgui-dev-server.bat` - launch a development server.
+
+> Remember to always run a full build before submitting a PR. It creates
+> a compressed javascript bundle which is then referenced from DM code.
+> We prefer to keep it version controlled, so that people could build the
+> game just by using Dream Maker.
+
+## Troubleshooting
+
+**Development server doesn't find my BYOND cache!**
+
+This happens if your Documents folder in Windows has a custom location, for
+example in `E:\Libraries\Documents`. Development server has no knowledge
+of these non-standard locations, therefore you have to run the dev server
+with an additional environmental variable, with a full path to BYOND cache.
+
+```
+export BYOND_CACHE="E:/Libraries/Documents/BYOND/cache"
+bin/tgui --dev
+```
+
+Note that in Windows, you have to go through Advanced System Settings,
+System Properties and then open Environment Variables window to do the
+same thing. You may need to reboot after this.
+
+## Developer Tools
+
+When developing with `tgui-dev-server`, you will have access to certain
+development only features.
+
+**Debug Logs.**
+When running server via `bin/tgui --dev --debug`, server will print debug
+logs and time spent on rendering. Use this information to optimize your
+code, and try to keep re-renders below 16ms.
+
+**Kitchen Sink.**
+Press `Ctrl+Alt+=` to open the KitchenSink interface. This interface is a
+playground to test various tgui components.
+
+**Layout Debugger.**
+Press `Ctrl+Alt+-` to toggle the *layout debugger*. It will show outlines of
+all tgui elements, which makes it easy to understand how everything comes
+together, and can reveal certain layout bugs which are not normally visible.
+
+## Project Structure
+
+- `/packages` - Each folder here represents a self-contained Node module.
+- `/packages/common` - Helper functions
+- `/packages/tgui/index.js` - Application entry point.
+- `/packages/tgui/components` - Basic UI building blocks.
+- `/packages/tgui/interfaces` - Actual in-game interfaces.
+Interface takes data via the `state` prop and outputs an html-like stucture,
+which you can build using existing UI components.
+- `/packages/tgui/layouts` - Root level UI components, that affect the final
+look and feel of the browser window. They usually hold various window
+elements, like the titlebar and resize handlers, and control the UI theme.
+- `/packages/tgui/routes.js` - This is where tgui decides which interface to
+pull and render.
+- `/packages/tgui/layout.js` - A root-level component, holding the
+window elements, like the titlebar, buttons, resize handlers. Calls
+`routes.js` to decide which component to render.
+- `/packages/tgui/styles/main.scss` - CSS entry point.
+- `/packages/tgui/styles/functions.scss` - Useful SASS functions.
+Stuff like `lighten`, `darken`, `luminance` are defined here.
+- `/packages/tgui/styles/atomic` - Atomic CSS classes.
+These are very simple, tiny, reusable CSS classes which you can use and
+combine to change appearance of your elements. Keep them small.
+- `/packages/tgui/styles/components` - CSS classes which are used
+in UI components. These stylesheets closely follow the
+[BEM](https://en.bem.info/methodology/) methodology.
+- `/packages/tgui/styles/interfaces` - Custom stylesheets for your interfaces.
+Add stylesheets here if you really need a fine control over your UI styles.
+- `/packages/tgui/styles/layouts` - Layout-related styles.
+- `/packages/tgui/styles/themes` - Contains all the various themes you can
+use in tgui. Each theme must be registered in `webpack.config.js` file.
+
+## Component Reference
+
+See: [Component Reference](docs/component-reference.md).
+
+## License
+
+All code is licensed with the parent license of *tgstation*, **AGPL-3.0**.
+
+See the main [README](../README.md) for more details.
+
+The Authors retain all copyright to their respective work here submitted.
diff --git a/tgui/bin/tgui b/tgui/bin/tgui
new file mode 100755
index 00000000000..eb1f200b31e
--- /dev/null
+++ b/tgui/bin/tgui
@@ -0,0 +1,173 @@
+#!/bin/bash
+set -e
+shopt -s globstar
+shopt -s expand_aliases
+
+## Initial set-up
+## --------------------------------------------------------
+
+## Returns an absolute path to file
+alias tgui-realpath="readlink -f"
+
+## Fallbacks for GNU readlink
+## Detecting GNU coreutils http://stackoverflow.com/a/8748344/319952
+if ! readlink --version >/dev/null 2>&1; then
+ if hash greadlink 2>/dev/null; then
+ alias tgui-realpath="greadlink -f"
+ else
+ alias tgui-realpath="perl -MCwd -le 'print Cwd::abs_path(shift)'"
+ fi
+fi
+
+## Find a canonical path to project root
+base_dir="$(dirname "$(tgui-realpath "${0}")")/.."
+base_dir="$(tgui-realpath "${base_dir}")"
+
+## Add locally installed node programs to path
+PATH="${PATH}:node_modules/.bin"
+
+
+## Functions
+## --------------------------------------------------------
+
+## Installs node modules
+task-install() {
+ cd "${base_dir}"
+ yarn install
+}
+
+## Runs webpack
+task-webpack() {
+ cd "${base_dir}/packages/tgui"
+ webpack "${@}"
+}
+
+## Runs a development server
+task-dev-server() {
+ cd "${base_dir}/packages/tgui-dev-server"
+ exec node --experimental-modules index.js "${@}"
+}
+
+## Run a linter through all packages
+task-eslint() {
+ cd "${base_dir}"
+ eslint ./packages "${@}"
+}
+
+## Mr. Proper
+task-clean() {
+ cd "${base_dir}"
+ rm -rf packages/tgui/public/.tmp
+ rm -rf **/node_modules
+ rm -f **/package-lock.json
+}
+
+## Validates current build against the build stored in git
+task-validate-build() {
+ cd "${base_dir}"
+ local diff
+ diff="$(git diff packages/tgui/public/tgui.bundle.*)"
+ if [[ -n ${diff} ]]; then
+ echo "Error: our build differs from the build committed into git."
+ echo "Please rebuild tgui."
+ exit 1
+ fi
+ echo "tgui: build is ok"
+}
+
+## Installs merge drivers and git hooks
+task-install-git-hooks() {
+ cd "${base_dir}"
+ local git_root
+ local git_base_dir
+ git_root="$(git rev-parse --show-toplevel)"
+ git_base_dir="${base_dir/${git_root}/.}"
+ git config --replace-all merge.tgui-merge-bundle.driver \
+ "${git_base_dir}/bin/tgui --merge=bundle %O %A %B %L"
+ echo "tgui: Merge drivers have been successfully installed!"
+}
+
+## Bundle merge driver
+task-merge-bundle() {
+ local file_ancestor="${1}"
+ local file_current="${2}"
+ local file_other="${3}"
+ local conflict_marker_size="${4}"
+ echo "tgui: Discarding a local tgui build"
+ ## Do nothing (file_current will be merged and is what we want to keep).
+ exit 0
+}
+
+
+## Main
+## --------------------------------------------------------
+
+if [[ ${1} == "--merge"* ]]; then
+ if [[ ${1} == "--merge=bundle" ]]; then
+ shift 1
+ task-merge-bundle "${@}"
+ fi
+ echo "Unknown merge strategy: ${1}"
+ exit 1
+fi
+
+if [[ ${1} == "--install-git-hooks" ]]; then
+ shift 1
+ task-install-git-hooks
+ exit 0
+fi
+
+## Continuous integration scenario
+if [[ ${1} == "--ci" ]]; then
+ task-clean
+ task-install
+ task-eslint
+ task-webpack --mode=production
+ task-validate-build
+ exit 0
+fi
+
+if [[ ${1} == "--clean" ]]; then
+ task-clean
+ exit 0
+fi
+
+if [[ ${1} == "--dev" ]]; then
+ shift
+ task-install
+ task-dev-server "${@}"
+ exit 0
+fi
+
+if [[ ${1} == '--lint' ]]; then
+ shift 1
+ task-install
+ task-eslint "${@}"
+ exit 0
+fi
+
+if [[ ${1} == '--lint-harder' ]]; then
+ shift 1
+ task-install
+ task-eslint -c .eslintrc-harder.yml "${@}"
+ exit 0
+fi
+
+## Analyze the bundle
+if [[ ${1} == '--analyze' ]]; then
+ task-install
+ task-webpack --mode=production --analyze
+ exit 0
+fi
+
+## Make a production webpack build
+if [[ -z ${1} ]]; then
+ task-install
+ task-eslint
+ task-webpack --mode=production
+ exit 0
+fi
+
+## Run webpack with custom flags
+task-install
+task-webpack "${@}"
diff --git a/tgui/bin/tgui-build.bat b/tgui/bin/tgui-build.bat
new file mode 100644
index 00000000000..89e1aca9152
--- /dev/null
+++ b/tgui/bin/tgui-build.bat
@@ -0,0 +1,5 @@
+@echo off
+cd "%~dp0\.."
+call yarn install
+call yarn run build
+timeout /t 9
diff --git a/tgui/bin/tgui-dev-server.bat b/tgui/bin/tgui-dev-server.bat
new file mode 100644
index 00000000000..1b5bdcfb1db
--- /dev/null
+++ b/tgui/bin/tgui-dev-server.bat
@@ -0,0 +1,4 @@
+@echo off
+cd "%~dp0\.."
+call yarn install
+call yarn run watch
diff --git a/tgui/docs/component-reference.md b/tgui/docs/component-reference.md
new file mode 100644
index 00000000000..b853fee4de3
--- /dev/null
+++ b/tgui/docs/component-reference.md
@@ -0,0 +1,1000 @@
+# Component Reference
+
+> Notice: This documentation might be out of date, so always check the source
+> code to see the most up-to-date information.
+
+
+
+- [General Concepts](#general-concepts)
+- [`tgui/components`](#tguicomponents)
+ - [`AnimatedNumber`](#animatednumber)
+ - [`BlockQuote`](#blockquote)
+ - [`Box`](#box)
+ - [`Button`](#button)
+ - [`Button.Checkbox`](#buttoncheckbox)
+ - [`Button.Confirm`](#buttonconfirm)
+ - [`Button.Input`](#buttoninput)
+ - [`ByondUi`](#byondui)
+ - [`Collapsible`](#collapsible)
+ - [`ColorBox`](#colorbox)
+ - [`Dimmer`](#dimmer)
+ - [`Divider`](#divider)
+ - [`Dropdown`](#dropdown)
+ - [`Flex`](#flex)
+ - [`Flex.Item`](#flexitem)
+ - [`Grid`](#grid)
+ - [`Grid.Column`](#gridcolumn)
+ - [`Icon`](#icon)
+ - [`Input`](#input)
+ - [`Knob`](#knob)
+ - [`LabeledControls`](#labeledcontrols)
+ - [`LabeledControls.Item`](#labeledcontrolsitem)
+ - [`LabeledList`](#labeledlist)
+ - [`LabeledList.Item`](#labeledlistitem)
+ - [`LabeledList.Divider`](#labeledlistdivider)
+ - [`Modal`](#modal)
+ - [`NoticeBox`](#noticebox)
+ - [`NumberInput`](#numberinput)
+ - [`ProgressBar`](#progressbar)
+ - [`Section`](#section)
+ - [`Slider`](#slider)
+ - [`Table`](#table)
+ - [`Table.Row`](#tablerow)
+ - [`Table.Cell`](#tablecell)
+ - [`Tabs`](#tabs)
+ - [`Tabs.Tab`](#tabstab)
+ - [`Tooltip`](#tooltip)
+- [`tgui/layouts`](#tguilayouts)
+ - [`Window`](#window)
+ - [`Window.Content`](#windowcontent)
+
+## General Concepts
+
+These are the components which you can use for interface construction.
+If you have trouble finding the exact prop you need on a component,
+please note, that most of these components inherit from other basic
+components, such as [Box](#box). This component in particular provides a lot
+of styling options for all components, e.g. `color` and `opacity`, thus
+it is used a lot in this framework.
+
+**Event handlers.**
+Event handlers are callbacks that you can attack to various element to
+listen for browser events. Inferno supports camelcase (`onClick`) and
+lowercase (`onclick`) event names.
+
+- Camel case names are what's called *synthetic* events, and are the
+**preferred way** of handling events in React, for efficiency and
+performance reasons. Please read
+[Inferno Event Handling](https://infernojs.org/docs/guides/event-handling)
+to understand what this is about.
+- Lower case names are native browser events and should be used sparingly,
+for example when you need an explicit IE8 support. **DO NOT** use
+lowercase event handlers unless you really know what you are doing.
+- [Button](#button) component does not support the lowercase `onclick` event.
+Use the camel case `onClick` instead.
+
+## `tgui/components`
+
+### `AnimatedNumber`
+
+This component provides animations for numeric values.
+
+**Props:**
+
+- `value: number` - Value to animate.
+- `initial: number` - Initial value to use in animation when element
+first appears. If you set initial to `0` for example, number will always
+animate starting from `0`, and if omitted, it will not play an initial
+animation.
+- `format: value => value` - Output formatter.
+ - Example: `value => Math.round(value)`.
+- `children: (formattedValue, rawValue) => any` - Pull the animated number to
+animate more complex things deeper in the DOM tree.
+ - Example: `(_, value) => `
+
+### `BlockQuote`
+
+Just a block quote, just like this example in markdown:
+
+> Here's an example of a block quote.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+
+### `Box`
+
+The Box component serves as a wrapper component for most of the CSS utility
+needs. It creates a new DOM element, a `
` by default that can be changed
+with the `as` property. Let's say you want to use a `` instead:
+
+```jsx
+
+
+
+```
+
+This works great when the changes can be isolated to a new DOM element.
+For instance, you can change the margin this way.
+
+However, sometimes you have to target the underlying DOM element.
+For instance, you want to change the text color of the button. The Button
+component defines its own color. CSS inheritance doesn't help.
+
+To workaround this problem, the Box children accept a render props function.
+This way, `Button` can pull out the `className` generated by the `Box`.
+
+```jsx
+
+ {props => }
+
+```
+
+**Box Units**
+
+`Box` units, like width, height and margins can be defined in two ways:
+
+- By plain numbers
+ - 1 unit equals `1rem` for width, height and positioning properties.
+ - 1 unit equals `0.5rem` for margins and paddings.
+- By strings with proper CSS units
+ - For example: `100px`, `2em`, `1rem`, `100%`, etc.
+
+If you need more precision, you can always use fractional numbers.
+
+Default font size (`1rem`) is equal to `12px`.
+
+**Props:**
+
+- `as: string` - The component used for the root node.
+- `color: string` - Applies an atomic `color-` class to the element.
+ - See `styles/atomic/color.scss`.
+- `width: number` - Box width.
+- `minWidth: number` - Box minimum width.
+- `maxWidth: number` - Box maximum width.
+- `height: number` - Box height.
+- `minHeight: number` - Box minimum height.
+- `maxHeight: number` - Box maximum height.
+- `fontSize: number` - Font size.
+- `fontFamily: string` - Font family.
+- `lineHeight: number` - Directly affects the height of text lines.
+Useful for adjusting button height.
+- `inline: boolean` - Forces the `Box` to appear as an `inline-block`,
+or in other words, makes the `Box` flow with the text instead of taking
+all available horizontal space.
+- `m: number` - Margin on all sides.
+- `mx: number` - Horizontal margin.
+- `my: number` - Vertical margin.
+- `mt: number` - Top margin.
+- `mb: number` - Bottom margin.
+- `ml: number` - Left margin.
+- `mr: number` - Right margin.
+- `p: number` - Padding on all sides.
+- `px: number` - Horizontal padding.
+- `py: number` - Vertical padding.
+- `pt: number` - Top padding.
+- `pb: number` - Bottom padding.
+- `pl: number` - Left padding.
+- `pr: number` - Right padding.
+- `opacity: number` - Opacity, from 0 to 1.
+- `bold: boolean` - Make text bold.
+- `italic: boolean` - Make text italic.
+- `nowrap: boolean` - Stops text from wrapping.
+- `textAlign: string` - Align text inside the box.
+ - `left` (default)
+ - `center`
+ - `right`
+- `position: string` - A direct mapping to `position` CSS property.
+ - `relative` - Relative positioning.
+ - `absolute` - Absolute positioning.
+ - `fixed` - Fixed positioning.
+- `color: string` - An alias to `textColor`.
+- `textColor: string` - Sets text color.
+ - `#ffffff` - Hex format
+ - `rgba(255, 255, 255, 1)` - RGB format
+ - `purple` - Applies an atomic `color-` class to the element.
+ See `styles/color-map.scss`.
+- `backgroundColor: string` - Sets background color.
+ - `#ffffff` - Hex format
+ - `rgba(255, 255, 255, 1)` - RGB format
+
+### `Button`
+
+Buttons allow users to take actions, and make choices, with a single click.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `fluid: boolean` - Fill all available horizontal space.
+- `icon: string` - Adds an icon to the button.
+- `color: string` - Button color, as defined in `variables.scss`.
+ - There is also a special color `transparent` - makes the button
+ transparent and slightly dim when inactive.
+- `disabled: boolean` - Disables and greys out the button.
+- `selected: boolean` - Activates the button (gives it a green color).
+- `tooltip: string` - A fancy, boxy tooltip, which appears when hovering
+over the button.
+- `tooltipPosition: string` - Position of the tooltip.
+ - `top` - Show tooltip above the button.
+ - `bottom` (default) - Show tooltip below the button.
+ - `left` - Show tooltip on the left of the button.
+ - `right` - Show tooltip on the right of the button.
+- `ellipsis: boolean` - If button width is constrained, button text will
+be truncated with an ellipsis. Be careful however, because this prop breaks
+the baseline alignment.
+- `title: string` - A native browser tooltip, which appears when hovering
+over the button.
+- `content/children: any` - Content to render inside the button.
+- `onClick: function` - Called when element is clicked.
+
+### `Button.Checkbox`
+
+A ghetto checkbox, made entirely using existing Button API.
+
+**Props:**
+
+- See inherited props: [Button](#button)
+- `checked: boolean` - Boolean value, which marks the checkbox as checked.
+
+### `Button.Confirm`
+
+A button with a an extra confirmation step, using native button component.
+
+**Props:**
+
+- See inherited props: [Button](#button)
+- `confirmMessage: string` - Text to display after first click; defaults to "Confirm?"
+- `confirmColor: string` - Color to display after first click; defaults to "bad"
+
+### `Button.Input`
+
+A button that turns into an input box after the first click. Turns back into a
+button after the user hits enter, defocuses, or hits escape. Enter and defocus
+commit, while escape cancels.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `fluid`: fill availible horizontal space
+- `onCommit: (e, value) => void`: function that is called after the user
+defocuses the input or presses enter
+- `currentValue: string`: default string to display when the input is shown
+- `defaultValue: string`: default value emitted if the user leaves the box
+blank when hitting enter or defocusing. If left undefined, will cancel the
+change on a blank defocus/enter
+
+### `ByondUi`
+
+Displays a BYOND UI element on top of the browser, and leverages browser's
+layout engine to position it just like any other HTML element. It is
+especially useful if you want to display a secondary game map in your
+interface.
+
+Example (button):
+
+```
+
+```
+
+Example (map):
+
+```
+
+```
+
+It supports a full set of `Box` properties for layout purposes.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `params: any` - An object with parameters, which are directly passed to
+the `winset` proc call. You can find a full reference of these parameters
+in [BYOND controls and parameters guide](https://secure.byond.com/docs/ref/skinparams.html).
+
+### `Collapsible`
+
+Displays contents when open, acts as a fluid button when closed. Click to
+toggle, closed by default.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `children: any` - What is collapsed when closed
+- `title: string` - Text to display on the button for collapsing
+- `color: string` - Color of the button; see [Button](#button)
+- `buttons: any` - Buttons or other content to render inline with the button
+
+### `ColorBox`
+
+Displays a 1-character wide colored square. Can be used as a status indicator,
+or for visually representing a color.
+
+If you want to set a background color on an element, use a plain
+[Box](#box) instead.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `color: string` - Color of the box.
+
+### `Dimmer`
+
+Dims surrounding area to emphasize content placed inside.
+
+Content is automatically centered inside the dimmer.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+
+### `Divider`
+
+Draws a horizontal or vertical line, dividing a section into groups.
+Works like the good old `` element, but it's fancier.
+
+**Props:**
+
+- `vertical: boolean` - Divide content vertically.
+- `hidden: boolean` - Divider can divide content without creating a dividing
+line.
+
+### `Dropdown`
+
+A simple dropdown box component. Lets the user select from a list of options
+and displays selected entry.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `options: string[]` - An array of strings which will be displayed in the
+dropdown when open
+- `selected: string` - Currently selected entry
+- `width: number` - Width of dropdown button and resulting menu
+- `over: boolean` - dropdown renders over instead of below
+- `color: string` - color of dropdown button
+- `onClick: (e) => void` - Called when dropdown button is clicked
+- `onSelected: (value) => void` - Called when a value is picked from the list, `value` is the value that was picked
+
+### `Flex`
+
+Quickly manage the layout, alignment, and sizing of grid columns, navigation,
+components, and more with a full suite of responsive flexbox utilities.
+
+If you are new to or unfamiliar with flexbox, we encourage you to read this
+[CSS-Tricks flexbox guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).
+
+Consists of two elements: `` and ``. Both of them provide
+the most straight-forward mapping to flex CSS properties as possible.
+
+One of the most basic usage of flex, is to align certain elements
+to the left, and certain elements to the right:
+
+```jsx
+
+
+ Button description
+
+
+
+
+
+
+```
+
+Flex item with `grow` property serves as a "filler", to separate the other
+two flex items as far as possible from each other.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `spacing: number` - Spacing between flex items, in integer units
+(1 unit - 0.5em). Does not directly relate to a flex css property
+(adds a modifier class under the hood), and only integer numbers are
+supported.
+- `inline: boolean` - Makes flexbox container inline, with similar behavior
+to an `inline` property on a `Box`.
+- `direction: string` - This establishes the main-axis, thus defining the
+direction flex items are placed in the flex container.
+ - `row` (default) - left to right.
+ - `row-reverse` - right to left.
+ - `column` - top to bottom.
+ - `column-reverse` - bottom to top.
+- `wrap: string` - By default, flex items will all try to fit onto one line.
+You can change that and allow the items to wrap as needed with this property.
+ - `nowrap` (default) - all flex items will be on one line
+ - `wrap` - flex items will wrap onto multiple lines, from top to bottom.
+ - `wrap-reverse` - flex items will wrap onto multiple lines from bottom to top.
+- `align: string` - Default alignment of all children.
+ - `stretch` (default) - stretch to fill the container.
+ - `start` - items are placed at the start of the cross axis.
+ - `end` - items are placed at the end of the cross axis.
+ - `center` - items are centered on the cross axis.
+ - `baseline` - items are aligned such as their baselines align.
+- `justify: string` - This defines the alignment along the main axis.
+It helps distribute extra free space leftover when either all the flex
+items on a line are inflexible, or are flexible but have reached their
+maximum size. It also exerts some control over the alignment of items
+when they overflow the line.
+ - `flex-start` (default) - items are packed toward the start of the
+ flex-direction.
+ - `flex-end` - items are packed toward the end of the flex-direction.
+ - `space-between` - items are evenly distributed in the line; first item is
+ on the start line, last item on the end line
+ - `space-around` - items are evenly distributed in the line with equal space
+ around them. Note that visually the spaces aren't equal, since all the items
+ have equal space on both sides. The first item will have one unit of space
+ against the container edge, but two units of space between the next item
+ because that next item has its own spacing that applies.
+ - `space-evenly` - items are distributed so that the spacing between any two
+ items (and the space to the edges) is equal.
+ - TBD (not all properties are supported in IE11).
+
+### `Flex.Item`
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `order: number` - By default, flex items are laid out in the source order.
+However, the order property controls the order in which they appear in the
+flex container.
+- `grow: number` - This defines the ability for a flex item to grow if
+necessary. It accepts a unitless value that serves as a proportion. It
+dictates what amount of the available space inside the flex container the
+item should take up. This number is unit-less and is relative to other
+siblings.
+- `shrink: number` - This defines the ability for a flex item to shrink
+if necessary. Inverse of `grow`.
+- `basis: string` - This defines the default size of an element before any
+flex-related calculations are done. Has to be a length (e.g. `20%`, `5rem`),
+an `auto` or `content` keyword.
+ - **Important:** IE11 flex is buggy, and auto width/height calculations
+ can sometimes end up in a circular dependency. This usually happens, when
+ working with tables inside flex (they have wacky internal widths and such).
+ Setting basis to `0` breaks the loop and fixes all of the problems.
+- `align: string` - This allows the default alignment (or the one specified by
+align-items) to be overridden for individual flex items. See: [Flex](#flex).
+
+### `Grid`
+
+> **Deprecated:** This component is no longer recommended due to the variety
+> of bugs that come with table-based layouts.
+> We recommend using [Flex](#flex) instead.
+
+Helps you to divide horizontal space into two or more equal sections.
+It is essentially a single-row `Table`, but with some extra features.
+
+Example:
+
+```jsx
+
+
+
+ Hello world!
+
+
+
+
+ Hello world!
+
+
+
+```
+
+**Props:**
+
+- See inherited props: [Table](#table)
+
+### `Grid.Column`
+
+**Props:**
+
+- See inherited props: [Table.Cell](#tablecell)
+- `size: number` (default: 1) - Size of the column relative to other columns.
+
+### `Icon`
+
+Renders one of the FontAwesome icons of your choice.
+
+```jsx
+
+```
+
+To smoothen the transition from v4 to v5, we have added a v4 semantic to
+transform names with `-o` suffixes to FA Regular icons. For example:
+- `square` will get transformed to `fas square`
+- `square-o` will get transformed to `far square`
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `name: string` - Icon name.
+- `size: number` - Icon size. `1` is normal size, `2` is two times bigger.
+Fractional numbers are supported.
+- `rotation: number` - Icon rotation, in degrees.
+- `spin: boolean` - Whether an icon should be spinning. Good for load
+indicators.
+
+### `Input`
+
+A basic text input, which allow users to enter text into a UI.
+
+> Input does not support custom font size and height due to the way
+> it's implemented in CSS. Eventually, this needs to be fixed.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `value: string` - Value of an input.
+- `placeholder: string` - Text placed into Input box when it's empty,
+otherwise nothing. Clears automatically when focused.
+- `fluid: boolean` - Fill all available horizontal space.
+- `selfClear: boolean` - Clear after hitting enter, as well as remain focused
+when this happens. Useful for things like chat inputs.
+- `onChange: (e, value) => void` - An event, which fires when you commit
+the text by either unfocusing the input box, or by pressing the Enter key.
+- `onInput: (e, value) => void` - An event, which fires on every keypress.
+
+### `Knob`
+
+A radial control, which allows dialing in precise values by dragging it
+up and down.
+
+Single click opens an input box to manually type in a number.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `animated: boolean` - Animates the value if it was changed externally.
+- `bipolar: boolean` - Knob can be bipolar or unipolar.
+- `size: number` - Relative size of the knob. `1` is normal size, `2` is two
+times bigger. Fractional numbers are supported.
+- `color: string` - Color of the outer ring around the knob.
+- `value: number` - Value itself, controls the position of the cursor.
+- `unit: string` - Unit to display to the right of value.
+- `minValue: number` - Lowest possible value.
+- `maxValue: number` - Highest possible value.
+- `fillValue: number` - If set, this value will be used to set the fill
+percentage of the outer ring independently of the main value.
+- `ranges: { color: [from, to] }` - Applies a `color` to the outer ring around
+the knob based on whether the value lands in the range between `from` and `to`.
+See an example of this prop in [ProgressBar](#progressbar).
+- `step: number` (default: 1) - Adjust value by this amount when
+dragging the input.
+- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
+to travel to adjust value by one `step`.
+- `format: value => value` - Format value using this function before
+displaying it.
+- `suppressFlicker: number` - A number in milliseconds, for which the input
+will hold off from updating while events propagate through the backend.
+Default is about 250ms, increase it if you still see flickering.
+- `onChange: (e, value) => void` - An event, which fires when you release
+the input, or successfully enter a number.
+- `onDrag: (e, value) => void` - An event, which fires about every 500ms
+when you drag the input up and down, on release and on manual editing.
+
+### `LabeledControls`
+
+LabeledControls is a horizontal grid, that is designed to hold various
+controls, like [Knobs](#knob) or small [Buttons](#button). Every item in
+this grid is labeled at the bottom.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `children: LabeledControls.Item` - Items to render.
+
+### `LabeledControls.Item`
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `label: string` - Item label.
+
+### `LabeledList`
+
+LabeledList is a continuous, vertical list of text and other content, where
+every item is labeled. It works just like a two column table, where first
+column is labels, and second column is content.
+
+```jsx
+
+
+ Content
+
+
+```
+
+If you want to have a button on the right side of an item (for example,
+to perform some sort of action), there is a way to do that:
+
+```jsx
+
+
+ )}>
+ Content
+
+
+```
+
+**Props:**
+
+- `children: LabeledList.Item` - Items to render.
+
+### `LabeledList.Item`
+
+**Props:**
+
+- `label: string` - Item label.
+- `color: string` - Sets the color of the text.
+- `buttons: any` - Buttons to render aside the content.
+- `content/children: any` - Content of this labeled item.
+
+### `LabeledList.Divider`
+
+Adds some empty space between LabeledList items.
+
+Example:
+
+```jsx
+
+
+ Content
+
+
+
+```
+
+**Props:**
+
+- `size: number` - Size of the divider.
+
+### `Modal`
+
+A modal window. Uses a [Dimmer](#dimmer) under the hood, and dynamically
+adjusts its own size to fit the content you're trying to display.
+
+Must be a direct child of a layout component (e.g. [Window](#window)).
+
+**Props:**
+
+- See inherited props: [Box](#box)
+
+### `NoticeBox`
+
+A notice box, which warns you about something very important.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `info: boolean` - Info box
+- `success: boolean` - Success box
+- `warning: bolean` - Warning box
+- `danger: boolean` - Danger box
+
+### `NumberInput`
+
+A fancy, interactive number input, which you can either drag up and down
+to fine tune the value, or single click it to manually type a number.
+
+**Props:**
+
+- `animated: boolean` - Animates the value if it was changed externally.
+- `fluid: boolean` - Fill all available horizontal space.
+- `value: number` - Value itself.
+- `unit: string` - Unit to display to the right of value.
+- `minValue: number` - Lowest possible value.
+- `maxValue: number` - Highest possible value.
+- `step: number` (default: 1) - Adjust value by this amount when
+dragging the input.
+- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
+to travel to adjust value by one `step`.
+- `width: string|number` - Width of the element, in `Box` units or pixels.
+- `height: string|numer` - Height of the element, in `Box` units or pixels.
+- `lineHeight: string|number` - lineHeight of the element, in `Box` units or pixels.
+- `fontSize: string|number` - fontSize of the element, in `Box` units or pixels.
+- `format: value => value` - Format value using this function before
+displaying it.
+- `suppressFlicker: number` - A number in milliseconds, for which the input
+will hold off from updating while events propagate through the backend.
+Default is about 250ms, increase it if you still see flickering.
+- `onChange: (e, value) => void` - An event, which fires when you release
+the input, or successfully enter a number.
+- `onDrag: (e, value) => void` - An event, which fires about every 500ms
+when you drag the input up and down, on release and on manual editing.
+
+### `ProgressBar`
+
+Progress indicators inform users about the status of ongoing processes.
+
+```jsx
+
+```
+
+Usage of `ranges` prop:
+
+```jsx
+
+```
+
+**Props:**
+
+- `value: number` - Current progress as a floating point number between
+`minValue` (default: 0) and `maxValue` (default: 1). Determines the
+percentage and how filled the bar is.
+- `minValue: number` - Lowest possible value.
+- `maxValue: number` - Highest possible value.
+- `ranges: { color: [from, to] }` - Applies a `color` to the progress bar
+based on whether the value lands in the range between `from` and `to`.
+- `color: string` - Color of the progress bar.
+- `content/children: any` - Content to render inside the progress bar.
+
+### `Section`
+
+Section is a surface that displays content and actions on a single topic.
+
+They should be easy to scan for relevant and actionable information.
+Elements, like text and images, should be placed in them in a way that
+clearly indicates hierarchy.
+
+Section can also be titled to clearly define its purpose.
+
+```jsx
+
+ Here you can order supply crates.
+
+```
+
+If you want to have a button on the right side of an section title
+(for example, to perform some sort of action), there is a way to do that:
+
+```jsx
+
+ )}>
+ Here you can order supply crates.
+
+```
+
+- See inherited props: [Box](#box)
+- `title: string` - Title of the section.
+- `level: number` - Section level in hierarchy. Default is 1, higher number
+means deeper level of nesting. Must be an integer number.
+- `buttons: any` - Buttons to render aside the section title.
+- `content/children: any` - Content of this section.
+
+### `Slider`
+
+A horizontal, [ProgressBar](#progressbar)-like control, which allows dialing
+in precise values by dragging it left and right.
+
+Single click opens an input box to manually type in a number.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `animated: boolean` - Animates the value if it was changed externally.
+- `color: string` - Color of the slider.
+- `value: number` - Value itself, controls the position of the cursor.
+- `unit: string` - Unit to display to the right of value.
+- `minValue: number` - Lowest possible value.
+- `maxValue: number` - Highest possible value.
+- `fillValue: number` - If set, this value will be used to set the fill
+percentage of the progress bar filler independently of the main value.
+- `ranges: { color: [from, to] }` - Applies a `color` to the slider
+based on whether the value lands in the range between `from` and `to`.
+See an example of this prop in [ProgressBar](#progressbar).
+- `step: number` (default: 1) - Adjust value by this amount when
+dragging the input.
+- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
+to travel to adjust value by one `step`.
+- `format: value => value` - Format value using this function before
+displaying it.
+- `suppressFlicker: number` - A number in milliseconds, for which the input
+will hold off from updating while events propagate through the backend.
+Default is about 250ms, increase it if you still see flickering.
+- `onChange: (e, value) => void` - An event, which fires when you release
+the input, or successfully enter a number.
+- `onDrag: (e, value) => void` - An event, which fires about every 500ms
+when you drag the input up and down, on release and on manual editing.
+
+### `Table`
+
+A straight forward mapping to a standard html table, which is slightly
+simplified (does not need a `` tag) and with sane default styles
+(e.g. table width is 100% by default).
+
+Example:
+
+```jsx
+
+
+
+ Hello world!
+
+
+ Label
+
+
+
+```
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `collapsing: boolean` - Collapses table to the smallest possible size.
+
+### `Table.Row`
+
+A straight forward mapping to `
` element.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+
+### `Table.Cell`
+
+A straight forward mapping to `
` element.
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `collapsing: boolean` - Collapses table cell to the smallest possible size,
+and stops any text inside from wrapping.
+
+### `Tabs`
+
+Tabs make it easy to explore and switch between different views.
+
+Here is an example of how you would construct a simple tabbed view:
+
+```jsx
+
+ setTabIndex(1)}>
+ Tab one
+
+ setTabIndex(2)}>
+ Tab two
+
+
+
+ Tab selected: {tabIndex}
+
+```
+
+Notice that tabs do not contain state. It is your job to track the selected
+tab, handle clicks and place tab content where you need it. In return, you get
+a lot of flexibility in regards to how you can layout your tabs.
+
+Tabs also support a vertical configuration. This is usually paired with a
+[Flex](#flex) component to render tab content to the right.
+
+```jsx
+
+
+
+ ...
+
+
+
+ Tab content.
+
+
+```
+
+**Props:**
+
+- See inherited props: [Box](#box)
+- `vertical: boolean` - Use a vertical configuration, where tabs will be
+stacked vertically.
+- `children: Tab[]` - This component only accepts tabs as its children.
+
+### `Tabs.Tab`
+
+An individual tab element. Tabs function like buttons, so they inherit
+a lot of `Button` props.
+
+**Props:**
+
+- See inherited props: [Button](#button)
+- `altSelection` - Whether the tab buttons select via standard select (color
+change) or by adding a white indicator to the selected tab.
+Intended for usage on interfaces where tab color has relevance.
+- `icon: string` - Tab icon.
+- `children: any` - Tab text.
+- `onClick: function` - Called when element is clicked.
+
+### `Tooltip`
+
+A boxy tooltip from tgui 1. It is very hacky in its current state, and
+requires setting `position: relative` on the container.
+
+Please note, that [Button](#button) component has a `tooltip` prop, and
+it is recommended to use that prop instead.
+
+Usage:
+
+```jsx
+
+ Sample text.
+
+
+```
+
+**Props:**
+
+- `position: string` - Tooltip position.
+- `content/children: string` - Content of the tooltip. Must be a plain string.
+Fragments or other elements are **not** supported.
+
+## `tgui/layouts`
+
+### `Window`
+
+A root-level component, which draws the window chrome, titlebar, resize
+handlers, and controls the UI theme. All tgui interfaces must implement
+it in one way or another.
+
+Example:
+
+```jsx
+
+
+ Hello, world!
+
+
+```
+
+**Props:**
+
+- `className: string` - Applies a CSS class to the element.
+- `theme: string` - A name of the theme.
+ - For a list of themes, see `packages/tgui/styles/themes`.
+- `resizable: boolean` - Controls resizability of the window.
+- `children: any` - Child elements, which are rendered directly inside the
+window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI,
+they should be put as direct childs of a Window, otherwise you should be
+putting your content into [Window.Content](#windowcontent).
+
+### `Window.Content`
+
+Canonical window content, which is usually the main target of window focus.
+Can be scrollable.
+
+**Props:**
+
+- `className: string` - Applies a CSS class to the element.
+- `scrollable: boolean` - Shows or hides the scrollbar.
+- `children: any` - Main content of your window.
diff --git a/tgui/docs/converting-old-nano-interfaces.md b/tgui/docs/converting-old-nano-interfaces.md
new file mode 100644
index 00000000000..83d44220b1a
--- /dev/null
+++ b/tgui/docs/converting-old-nano-interfaces.md
@@ -0,0 +1,321 @@
+# Converting old NanoUI interfaces to TGUI
+
+This guide is going to assume you already know roughly how tgui-next works, how to make new uis, etc. It's mostly aimed at helping translate concepts between nano and tgui-next, and clarify some confusing parts of the transition.
+
+## Backend
+
+Backend in almost every case does not require any changes. In particularly heavy ui cases, something to be aware of is the new `tgui_static_data()` proc. This proc allows you to split some data sent to the interface off into data that will only be sent on ui initialize and when manually updated by elsewhere in the code. Useful for things like cargo where you have a very large set of mostly identical code.
+
+Keep in mind that for uis where *all* data doesn't need to be live updating, you can just toggle off autoupdate for the ui instead of messing with static data.
+
+## Frontend
+
+The very first thing to note is the name of the `tmpl` file containing the old interface. Whatever the name is (minus the extension) is going to be what the route key is going to be.
+
+One thing I like to do before starting work on a conversion is screenshot what the old interface looks like so I have something to reference to make sure that the styling can line up as well.
+
+## General syntax changes
+
+Ractive has a fairly different templating syntax from React.
+
+### `data`
+
+You likely already know that React data inserts look like this
+
+```jsx
+{data.example_data}
+```
+
+Ractive looks very similar, the only real difference is that React uses one paranthesis instead of two.
+
+```tmpl
+{{data.example_data}}
+```
+
+However, you may occasionally come across data inserts that instead of referencing the `data` var or things contained within it instead reference `adata`. `adata` was short for animated data, and was used for smooth number animations in interfaces. instead of having a seperate data structure for this. tgui-next instead uses a component, which is `AnimatedNumber`.
+
+`AnimatedNumber` is used like this
+
+```jsx
+
+```
+
+Make sure you don't forget to import it.
+
+### Conditionals
+
+Template conditionals look very different from React conditionals.
+
+A template `if` (only render if result of expression is true) looks like this
+
+```tmpl
+{{#if data.condition}}
+ Example Render
+{{/if}}
+```
+
+The equivalent React would be
+
+```jsx
+{!!data.condition && (
+ Example Render
+)}
+```
+
+This might look a bit intimidating compared to the reactive part but it's not as complicated as it seems:
+
+1. A new jsx context is opened with `{}`
+2. jsx contexts like this always render whatever the return value is, so we can use `&&` to return a value we want. `&&` returns the last true value (or not "falsey" because this is js).
+3. jsx tags are never "falsey", so a conditioned paired with a jsx tag will mean the condition being true will continue on and return the tag. `()` is just used to contain the tag
+4. The `!!` is not a special operator, it is a literal double negation. This is because most `false` values coming from byond are going to actually be `0`, which would be rendered if the condition is false. Negating `0` returns `true`, negating `true` returns `false`, which isn't rendered.
+5. `Fragment` is actually a true "dead tag". It's similar to `span` in that it just contains things without providing functionality, but it's unwrapped before the final render and children of it are injected into its parent. In a case where you only need to render text without any styling, it's probably better to just return a string literal (`"Example Render"`), but this was just to illustrate that you can put any tag in this expression.
+
+You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong.
+
+Template conditionals can have an `else` as well
+```tmpl
+{{#if data.condition}}
+ value
+{{else}}
+ other value
+{{/if}}
+```
+
+Similarly to the previous example, just add a `||` operator to handle the
+"falsy" condition:
+
+```jsx
+{!!data.condition && (
+
+ value
+
+) || (
+
+ other value
+
+)}
+```
+
+There's also our good old friend - the ternary:
+
+```jsx
+{data.condition ? 'value' : 'other value'}
+```
+
+Keep in mind you can also use tags here like the conditional example,
+and you can mix string literals, values, and tags as well.
+
+```jsx
+{data.is_robot ? (
+
+) : 'Not a robot'}
+```
+
+### Loops
+
+Templates have loops for iterating over data and inserting something for each
+member of an array or object
+
+```tmpl
+{{for data.entries}}
+ {{:value.name}}
+{{/for}}
+```
+
+This didn't care whether the data was an array or an object, and members of each entry of the loop were "unwrapped" so to say. `{{number}}` in that example is referring to the `{{number}}` value on the entry of the list for that iterate.
+
+The React equivalent to this is going to be `map`.
+
+_AN IMPORTANT DISTINCTION HERE IS THAT NOW WE CARE WHETHER THIS IS AN OBJECT OR AN ARRAY BEING ACTED ON._
+
+Objects are represented by `{}`, arrays by `[]`
+
+"How can I tell?" you may ask. It's fairly simple, associated lists on the byond side are going to be turned into objects when they get json converted, normal lists are going to be turned into arrays.
+
+`list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}`
+
+First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this
+```jsx
+const things = data.things || [];
+```
+
+This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate.
+
+If it's an array, you'll want to do this in the template
+```jsx
+{things.map(thing => (
+
+ Thing {thing.number} is here!
+
+))}
+```
+
+`map` is a function that calls a passed function (a lambda) on each entry, and returns the value. You should already know that returned tags and values (except `false`) get rendered, so that's how it's rendering each time.
+
+A lambda is what's known as an anonymous function, it's a function that doesn't have a name that's only used for a specific usage. `map` wants a function that has one parameter, so we define one parameter then use `=>` to say the parameter has to do with the following block.
+
+`parameter => ()` is just a shorthand for `parameter => {return();}`
+
+This is quite a bit higher concept than ractive's each statements, so feel free to look around and ~~copy paste~~ learn from how other interfaces use this.
+
+Now for objects, there's a genuinely pretty gross syntax here. We apoligize, it's related to ie8 compatibility nonsense.
+
+```jsx
+{map((value, key) => (
+
+ Key is {key}, value is {value}
+
+))(fooObject)}
+```
+
+Again, sorry for this syntax. `fooObject` would be the object being iterated on, value would be the value of the iterated entry on the list, and key would be the key. the naming of value and key isn't important here, but knowing that it goes `value`, `key` in that order is important.
+
+It is sometimes better to preemptively convert an object to array before
+the big return statement, like this:
+
+```jsx
+const fooArray = map((value, key) => {
+ return { key, value };
+})(fooObject);
+```
+
+Or if you just want to discard all keys, this will also work nicely:
+
+```jsx
+const fooArray = toArray(fooObject);
+```
+
+
+If you want to see if an array has no contents and output a message, just check if array is empty like this:
+
+```jsx
+{fooArray.length === 0 && 'fooArray is empty.'}
+{fooArray.map(foo => (
+
+ Foo is {foo}
+
+))}
+```
+
+### Extra Stuff
+
+I'll put some extra stuff here when I think of it.
+
+## Components
+
+This will be a reference of tgui components and the tgui-next equivalent.
+
+### `ui-display`
+
+Equivalent of `` is ``
+
+```
+
+ Contents
+
+```
+
+becomes
+
+```jsx
+
+ Contents
+
+```
+
+A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`:
+
+```
+
+ {{#partial button}}
+ // lots more button bullshit here
+ {{/partial}}
+ Contents
+
+```
+
+becomes
+
+```jsx
+
+ )}>
+ Contents
+
+```
+
+### `ui-section`
+
+Very important to note `ui-section` is NOT the equivalent of `Section`
+
+`` does not have a direct equivalent, but the closest equivalent is ``
+
+```
+
+ No Power
+
+
+ No Connection
+
+```
+
+becomes
+
+```jsx
+
+
+ No Power
+
+
+ No Connection
+
+
+```
+
+Important to note that `LabeledList.Item` has `buttons` as well.
+
+Also good to know that if you need the contents of a `LabeledList.Item` to be colored, you can just set the `color` prop on it instead of putting a `span` inside it.
+
+### `ui-notice`
+
+`` has a direct equivalent in ``
+
+```
+
+ Notice stuff!
+
+```
+
+becomes
+
+```jsx
+
+ Notice stuff!
+
+```
+
+### `ui-button`
+
+The equivalent of `ui-button` is `Button` but it works quite a bit differently.
+
+```
+
+ Click
+
+```
+
+becomes
+
+```jsx
+