Merge branch 'master' into upstream-merge-5908

This commit is contained in:
Novacat
2019-03-28 15:19:53 -04:00
committed by GitHub
1516 changed files with 52002 additions and 51494 deletions

View File

@@ -200,7 +200,7 @@
"moles" = round(air2.gas[output_gas], 0.01))
// update the ui if it exists, returns null if no ui is passed/found
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "algae_farm_vr.tmpl", "Algae Farm Control Panel", 500, 600)
ui.set_initial_data(data)

View File

@@ -125,8 +125,20 @@
..()
/obj/machinery/atmospherics/binary/circulator/verb/rotate_clockwise()
set name = "Rotate Circulator Clockwise"
set category = "Object"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, 270))
desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
/obj/machinery/atmospherics/binary/circulator/verb/rotate_counterclockwise()
set name = "Rotate Circulator Counterclockwise"
set category = "Object"
set name = "Rotate Circulator (Clockwise)"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
@@ -134,15 +146,3 @@
src.set_dir(turn(src.dir, 90))
desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
/obj/machinery/atmospherics/binary/circulator/verb/rotate_anticlockwise()
set category = "Object"
set name = "Rotate Circulator (Counterclockwise)"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, -90))
desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."

View File

@@ -194,7 +194,7 @@
return 1
/obj/machinery/atmospherics/binary/dp_vent_pump/initialize()
/obj/machinery/atmospherics/binary/dp_vent_pump/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -129,7 +129,7 @@
return 1
/obj/machinery/atmospherics/binary/passive_gate/initialize()
/obj/machinery/atmospherics/binary/passive_gate/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)
@@ -197,7 +197,7 @@
)
// update the ui if it exists, returns null if no ui is passed/found
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm

View File

@@ -20,7 +20,7 @@
var/datum/pipe_network/network1
var/datum/pipe_network/network2
New()
/obj/machinery/atmospherics/pipeturbine/New()
..()
air_in.volume = 200
air_out.volume = 800
@@ -35,7 +35,7 @@
if(WEST)
initialize_directions = NORTH|SOUTH
Destroy()
/obj/machinery/atmospherics/pipeturbine/Destroy()
. = ..()
if(node1)
@@ -48,7 +48,7 @@
node1 = null
node2 = null
process()
/obj/machinery/atmospherics/pipeturbine/process()
..()
if(anchored && !(stat&BROKEN))
kin_energy *= 1 - kin_loss
@@ -72,7 +72,7 @@
if (network2)
network2.update = 1
update_icon()
/obj/machinery/atmospherics/pipeturbine/update_icon()
overlays.Cut()
if (dP > 10)
overlays += image('icons/obj/pipeturbine.dmi', "moto-turb")
@@ -83,7 +83,7 @@
if (kin_energy > 1000000)
overlays += image('icons/obj/pipeturbine.dmi', "hi-turb")
attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/machinery/atmospherics/pipeturbine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_wrench())
anchored = !anchored
playsound(src, W.usesound, 50, 1)
@@ -114,23 +114,23 @@
node1 = null
node2 = null
else
return
..()
verb/rotate_clockwise()
/obj/machinery/atmospherics/pipeturbine/verb/rotate_clockwise()
set name = "Rotate Turbine Clockwise"
set category = "Object"
set name = "Rotate Circulator (Clockwise)"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, -90))
src.set_dir(turn(src.dir, 270))
verb/rotate_anticlockwise()
/obj/machinery/atmospherics/pipeturbine/verb/rotate_counterclockwise()
set name = "Rotate Turbine Counterclockwise"
set category = "Object"
set name = "Rotate Circulator (Counterclockwise)"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
@@ -139,10 +139,10 @@
src.set_dir(turn(src.dir, 90))
//Goddamn copypaste from binary base class because atmospherics machinery API is not damn flexible
get_neighbor_nodes_for_init()
/obj/machinery/atmospherics/pipeturbine/get_neighbor_nodes_for_init()
return list(node1, node2)
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/pipeturbine/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
@@ -156,8 +156,9 @@
return null
atmos_init()
if(node1 && node2) return
/obj/machinery/atmospherics/pipeturbine/atmos_init()
if(node1 && node2)
return
var/node2_connect = turn(dir, -90)
var/node1_connect = turn(dir, 90)
@@ -172,7 +173,7 @@
node2 = target
break
build_network()
/obj/machinery/atmospherics/pipeturbine/build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
@@ -184,7 +185,7 @@
network2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/pipeturbine/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
@@ -195,7 +196,7 @@
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
/obj/machinery/atmospherics/pipeturbine/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
@@ -203,7 +204,7 @@
return 1
return_network_air(datum/pipe_network/reference)
/obj/machinery/atmospherics/pipeturbine/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
@@ -213,7 +214,7 @@
return results
disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/pipeturbine/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null
@@ -236,19 +237,19 @@
var/kin_to_el_ratio = 0.1 //How much kinetic energy will be taken from turbine and converted into electricity
var/obj/machinery/atmospherics/pipeturbine/turbine
New()
/obj/machinery/power/turbinemotor/New()
..()
spawn(1)
updateConnection()
proc/updateConnection()
/obj/machinery/power/turbinemotor/proc/updateConnection()
turbine = null
if(src.loc && anchored)
turbine = locate(/obj/machinery/atmospherics/pipeturbine) in get_step(src,dir)
if (turbine.stat & (BROKEN) || !turbine.anchored || turn(turbine.dir,180) != dir)
turbine = null
process()
/obj/machinery/power/turbinemotor/process()
updateConnection()
if(!turbine || !anchored || stat & (BROKEN))
return
@@ -257,8 +258,7 @@
turbine.kin_energy -= power_generated
add_avail(power_generated)
attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/machinery/power/turbinemotor/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_wrench())
anchored = !anchored
playsound(src, W.usesound, 50, 1)
@@ -268,19 +268,19 @@
else
..()
verb/rotate_clock()
set category = "Object"
/obj/machinery/power/turbinemotor/verb/rotate_clockwise()
set name = "Rotate Motor Clockwise"
set category = "Object"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, -90))
src.set_dir(turn(src.dir, 270))
verb/rotate_anticlock()
set category = "Object"
/obj/machinery/power/turbinemotor/verb/rotate_counterclockwise()
set name = "Rotate Motor Counterclockwise"
set category = "Object"
set src in view(1)
if (usr.stat || usr.restrained() || anchored)

View File

@@ -140,7 +140,7 @@ Thus, the two variables affect pump operation are set in New():
)
// update the ui if it exists, returns null if no ui is passed/found
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
@@ -149,7 +149,7 @@ Thus, the two variables affect pump operation are set in New():
ui.open() // open the new ui window
ui.set_auto_update(1) // auto update every Master Controller tick
/obj/machinery/atmospherics/binary/pump/initialize()
/obj/machinery/atmospherics/binary/pump/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -93,7 +93,7 @@
data = build_uidata()
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
@@ -181,7 +181,7 @@
switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter))
update_icon()
GLOB.nanomanager.update_uis(src)
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/atmos_filter/proc/mode_return_switch(var/mode)

View File

@@ -131,7 +131,7 @@
data = build_uidata()
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
@@ -200,7 +200,7 @@
con_lock(dir_flag(href_list["dir"]))
update_icon()
GLOB.nanomanager.update_uis(src)
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE)

View File

@@ -105,7 +105,7 @@
return 1
/obj/machinery/atmospherics/trinary/atmos_filter/initialize()
/obj/machinery/atmospherics/trinary/atmos_filter/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -302,7 +302,7 @@
/obj/machinery/atmospherics/tvalve/digital/initialize()
/obj/machinery/atmospherics/tvalve/digital/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -83,7 +83,7 @@
data["gasTemperatureClass"] = temp_class
// update the ui if it exists, returns null if no ui is passed/found
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm

View File

@@ -103,7 +103,7 @@
data["gasTemperatureClass"] = temp_class
// update the ui if it exists, returns null if no ui is passed/found
ui = GLOB.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm

View File

@@ -122,7 +122,7 @@
return 1
/obj/machinery/atmospherics/unary/outlet_injector/initialize()
/obj/machinery/atmospherics/unary/outlet_injector/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -263,7 +263,7 @@
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/valve/digital/initialize()
/obj/machinery/atmospherics/valve/digital/Initialize()
. = ..()
if(frequency)
set_frequency(frequency)

View File

@@ -20,7 +20,7 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS
gases.Cut() // Do not qdel the gases, we don't own them
return ..()
proc/process()
process()
//Equalize gases amongst pipe if called for
if(update)
update = 0

View File

@@ -20,7 +20,7 @@ datum/pipeline
edges = null
. = ..()
proc/process()//This use to be called called from the pipe networks
process()//This use to be called called from the pipe networks
//Check to see if pressure is within acceptable limits
var/pressure = air.return_pressure()

View File

@@ -571,7 +571,7 @@ obj/machinery/atmospherics/mains_pipe/valve
else
icon_state = "[hide?"h":""]mvalve[open]"
initialize()
Initialize()
normalize_dir()
var/node1_dir
var/node2_dir
@@ -609,7 +609,7 @@ obj/machinery/atmospherics/mains_pipe/valve
open = 1
update_icon()
initialize()
Initialize()
return 1
@@ -668,7 +668,7 @@ obj/machinery/atmospherics/mains_pipe/valve
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
Initialize()
..()
if(frequency)
set_frequency(frequency)

View File

@@ -22,9 +22,6 @@ mob/proc/airflow_stun()
mob/living/silicon/airflow_stun()
return
mob/living/simple_animal/slime/airflow_stun()
return
mob/living/carbon/human/airflow_stun()
if(shoes && (shoes.item_flags & NOSLIP))
to_chat(src, "<span class='notice'>Air suddenly rushes past you!</span>")

View File

@@ -36,3 +36,4 @@
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)

View File

@@ -1,16 +1,82 @@
#define MC_TICK_CHECK ( ( TICK_USAGE > GLOB.CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 )
// Used for splitting up your remaining time into phases, if you want to evenly divide it.
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = GLOB.CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count
#define MC_TICK_CHECK ( ( TICK_USAGE > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
#define MC_SPLIT_TICK \
if(split_tick_phases > 1){\
GLOB.CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
Master.current_ticklimit = ((original_tick_limit - TICK_USAGE) / split_tick_phases) + TICK_USAGE;\
--split_tick_phases;\
} else {\
GLOB.CURRENT_TICKLIMIT = original_tick_limit;\
Master.current_ticklimit = original_tick_limit;\
}
// Used to smooth out costs to try and avoid oscillation.
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
#define START_PROCESSING(Processor, Datum) if (!(Datum.datum_flags & DF_ISPROCESSING)) {Datum.datum_flags |= DF_ISPROCESSING;Processor.processing += Datum}
#define STOP_PROCESSING(Processor, Datum) Datum.datum_flags &= ~DF_ISPROCESSING;Processor.processing -= Datum
//! SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
/// subsystem does not initialize.
#define SS_NO_INIT 1
/** subsystem does not fire. */
/// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
/// (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
#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)
/// (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
/** keep the subsystem's timing on point by firing early if it fired late last fire because of lag */
/// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING 32
/** Calculate its next fire after its fired. */
/// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
/// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING 64
//! SUBSYSTEM STATES
#define SS_IDLE 0 /// aint doing shit.
#define SS_QUEUED 1 /// queued to run
#define SS_RUNNING 2 /// actively running
#define SS_PAUSED 3 /// paused by mc_tick_check
#define SS_SLEEPING 4 /// fire() slept.
#define SS_PAUSING 5 /// in the middle of pausing
#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
/datum/controller/subsystem/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
/datum/controller/subsystem/##X
#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\
/datum/controller/subsystem/processing/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
/datum/controller/subsystem/processing/##X
// Boilerplate code for multi-step processors. See machines.dm for example use.
#define INTERNAL_PROCESS_STEP(this_step, initial_step, proc_to_call, cost_var, next_step)\
if(current_step == this_step || (initial_step && !resumed)) /* So we start at step 1 if not resumed.*/ {\
@@ -23,71 +89,3 @@ if(current_step == this_step || (initial_step && !resumed)) /* So we start at st
resumed = 0;\
current_step = next_step;\
}
// Used to smooth out costs to try and avoid oscillation.
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current))
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
#define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum}
#define STOP_PROCESSING(Processor, Datum) Datum.isprocessing = 0;Processor.processing -= Datum
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
//subsystem does not initialize.
#define SS_NO_INIT 1
//subsystem does not fire.
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
// (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
#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)
// (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
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
#define SS_KEEP_TIMING 32
//Calculate its next fire after its fired.
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
// This flag overrides SS_KEEP_TIMING
#define SS_POST_FIRE_TIMING 64
//SUBSYSTEM STATES
#define SS_IDLE 0 //aint doing shit.
#define SS_QUEUED 1 //queued to run
#define SS_RUNNING 2 //actively running
#define SS_PAUSED 3 //paused by mc_tick_check
#define SS_SLEEPING 4 //fire() slept.
#define SS_PAUSING 5 //in the middle of pausing
// Standard way to define a global subsystem, keep boilerplate organized here!
#define SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/##X);\
/datum/controller/subsystem/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
/datum/controller/subsystem/##X
#define PROCESSING_SUBSYSTEM_DEF(X) GLOBAL_REAL(SS##X, /datum/controller/subsystem/processing/##X);\
/datum/controller/subsystem/processing/##X/New(){\
NEW_SS_GLOBAL(SS##X);\
PreInit();\
}\
/datum/controller/subsystem/processing/##X

56
code/__defines/_lists.dm Normal file
View File

@@ -0,0 +1,56 @@
// Helper macros to aid in optimizing lazy instantiation of lists.
// All of these are null-safe, you can use them without knowing if the list var is initialized yet
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
// Ensures L is initailized after this point
#define LAZYINITLIST(L) if (!L) L = list()
// Sets a L back to null iff it is empty
#define UNSETEMPTY(L) if (L && !length(L)) L = null
// Removes I from list L, and sets I to null if it is now empty
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
// Adds I to L, initalizing I if necessary
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYOR(L, I) if(!L) { L = list(); } L |= I;
#define LAZYFIND(L, V) L ? L.Find(V) : 0
// Reads I from L safely - Works with both associative and traditional lists.
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null)
// Turns LAZYINITLIST(L) L[K] = V into ... for associated lists
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;
// Reads the length of L, returning 0 if null
#define LAZYLEN(L) length(L)
// Null-safe L.Cut()
#define LAZYCLEARLIST(L) if(L) L.Cut()
// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression.
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
#define reverseList(L) reverseRange(L.Copy())
// binary search sorted insert
// IN: Object to be inserted
// LIST: List to insert object into
// TYPECONT: The typepath of the contents of the list
// COMPARE: The variable on the objects to compare
#define BINARY_INSERT(IN, LIST, TYPECONT, COMPARE) \
var/__BIN_CTTL = length(LIST);\
if(!__BIN_CTTL) {\
LIST += IN;\
} else {\
var/__BIN_LEFT = 1;\
var/__BIN_RIGHT = __BIN_CTTL;\
var/__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
var/##TYPECONT/__BIN_ITEM;\
while(__BIN_LEFT < __BIN_RIGHT) {\
__BIN_ITEM = LIST[__BIN_MID];\
if(__BIN_ITEM.##COMPARE <= IN.##COMPARE) {\
__BIN_LEFT = __BIN_MID + 1;\
} else {\
__BIN_RIGHT = __BIN_MID;\
};\
__BIN_MID = (__BIN_LEFT + __BIN_RIGHT) >> 1;\
};\
__BIN_ITEM = LIST[__BIN_MID];\
__BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\
LIST.Insert(__BIN_MID, IN);\
}
#define islist(L) istype(L, /list)

View File

@@ -58,7 +58,10 @@ What is the naming convention for planes or layers?
#define ATMOS_LAYER 2.4 // Pipe-like atmos machinery that goes on the floor, like filters.
#define ABOVE_UTILITY 2.5 // Above stuff like pipes and wires
#define TURF_PLANE -45 // Turfs themselves, most flooring
#define ABOVE_TURF_LAYER 2.1 // Snow and wallmounted/floormounted equipment
#define WATER_FLOOR_LAYER 2.0 // The 'bottom' of water tiles.
#define UNDERWATER_LAYER 2.5 // Anything on this layer will render under the water layer.
#define WATER_LAYER 3.0 // Layer for water overlays.
#define ABOVE_TURF_LAYER 3.1 // Snow and wallmounted/floormounted equipment
#define DECAL_PLANE -44 // Permanent decals
#define DIRTY_PLANE -43 // Nonpermanent decals
#define BLOOD_PLANE -42 // Blood is really dirty, but we can do special stuff if we separate it
@@ -73,8 +76,8 @@ What is the naming convention for planes or layers?
#define ABOVE_JUNK_LAYER 3.1 // Things that want to be slightly above common objects
#define DOOR_CLOSED_LAYER 3.1 // Doors when closed
#define WINDOW_LAYER 3.2 // Windows
#define ABOVE_WINDOW_LAYER 3.25 //Above full tile windows so wall items are clickable
#define ON_WINDOW_LAYER 3.3 // Ontop of a window
#define ABOVE_WINDOW_LAYER 3.4 //Above full tile windows so wall items are clickable
// Mob planes
#define MOB_PLANE -25

View File

@@ -1,9 +1,15 @@
#define TICK_LIMIT_RUNNING 80
#define TICK_LIMIT_TO_RUN 70
#define TICK_LIMIT_MC 70
#define TICK_LIMIT_MC_INIT_DEFAULT 98
#define TICK_CHECK ( TICK_USAGE > GLOB.CURRENT_TICKLIMIT )
#define CHECK_TICK if TICK_CHECK stoplag()
#define TICK_USAGE world.tick_usage
#define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit )
#define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 )
#define TICK_CHECK_HIGH_PRIORITY ( TICK_USAGE > 95 )
#define CHECK_TICK_HIGH_PRIORITY ( TICK_CHECK_HIGH_PRIORITY? stoplag() : 0 )
#define UNTIL(X) while(!(X)) stoplag()

View File

@@ -7,6 +7,7 @@
#define CLONE "clone"
#define HALLOSS "halloss"
#define ELECTROCUTE "electrocute"
#define BIOACID "bioacid"
#define CUT "cut"
#define BRUISE "bruise"

45
code/__defines/flags.dm Normal file
View File

@@ -0,0 +1,45 @@
//MARK ALL FLAG CHANGES IN _globals/bitfields.dm!
//All flags should go in here if possible.
#define ALL (~0) //For convenience.
#define NONE 0
//for convenience
#define ENABLE_BITFIELD(variable, flag) (variable |= (flag))
#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag))
#define CHECK_BITFIELD(variable, flag) (variable & (flag))
//check if all bitflags specified are present
#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
// datum_flags
#define DF_VAR_EDITED (1<<0)
#define DF_ISPROCESSING (1<<1)
// /atom/movable movement_type
#define UNSTOPPABLE (1<<0) //Can not be stopped from moving from Cross(), CanPass(), or Uncross() failing. Still bumps everything it passes through, though.
// Flags bitmasks. - Used in /atom/var/flags
#define NOBLUDGEON (1<<0) // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
#define CONDUCT (1<<1) // Conducts electricity. (metal etc.)
#define ON_BORDER (1<<2) // Item has priority to check when entering or leaving.
#define NOBLOODY (1<<3) // Used for items if they don't want to get a blood overlay.
#define OPENCONTAINER (1<<4) // Is an open container for chemistry purposes.
#define PHORONGUARD (1<<5) // Does not get contaminated by phoron.
#define NOREACT (1<<6) // Reagents don't react inside this container.
#define PROXMOVE (1<<7)// Does this object require proximity checking in Enter()?
#define OVERLAY_QUEUED (1<<8)// Atom queued to SSoverlay for COMPILE_OVERLAYS
//Flags for items (equipment) - Used in /obj/item/var/item_flags
#define THICKMATERIAL (1<<0) // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
#define AIRTIGHT (1<<1) // Functions with internals.
#define NOSLIP (1<<2) // Prevents from slipping on wet floors, in space, etc.
#define BLOCK_GAS_SMOKE_EFFECT (1<<3) // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
#define FLEXIBLEMATERIAL (1<<4) // At the moment, masks with this flag will not prevent eating even if they are covering your face.
// Flags for pass_flags. - Used in /atom/var/pass_flags
#define PASSTABLE (1<<0)
#define PASSGLASS (1<<1)
#define PASSGRILLE (1<<2)
#define PASSBLOB (1<<3)

View File

@@ -45,8 +45,6 @@ var/list/be_special_flags = list(
"pAI" = BE_PAI
)
#define IS_MODE_COMPILED(MODE) (ispath(text2path("/datum/game_mode/"+(MODE))))
// Antagonist datum flags.
#define ANTAG_OVERRIDE_JOB 0x1 // Assigned job is set to MODE when spawning.

View File

@@ -0,0 +1,53 @@
#define isdatum(D) istype(D, /datum)
#define isweakref(A) istype(A, /weakref)
#define islist(D) istype(D, /list)
//---------------
#define isatom(D) istype(D, /atom)
//---------------
//#define isobj(D) istype(D, /obj) //Built in
#define isitem(D) istype(D, /obj/item)
#define isairlock(A) istype(A, /obj/machinery/door/airlock)
#define isorgan(A) istype(A, /obj/item/organ/external)
//---------------
//#define isarea(D) istype(D, /area) //Built in
//---------------
//#define ismob(D) istype(D, /mob) //Built in
#define isliving(A) istype(A, /mob/living)
#define isobserver(A) istype(A, /mob/observer/dead)
#define isEye(A) istype(A, /mob/observer/eye)
#define isnewplayer(A) istype(A, /mob/new_player)
#define isanimal(A) istype(A, /mob/living/simple_mob)
#define ismouse(A) istype(A, /mob/living/simple_mob/animal/passive/mouse)
#define iscorgi(A) istype(A, /mob/living/simple_mob/animal/passive/dog/corgi)
#define isslime(A) istype(A, /mob/living/simple_mob/slime)
#define isxeno(A) istype(A, /mob/living/simple_mob/animal/space/alien)
#define iscarbon(A) istype(A, /mob/living/carbon)
#define isalien(A) istype(A, /mob/living/carbon/alien)
#define isbrain(A) istype(A, /mob/living/carbon/brain)
#define ishuman(A) istype(A, /mob/living/carbon/human)
#define issilicon(A) istype(A, /mob/living/silicon)
#define isAI(A) istype(A, /mob/living/silicon/ai)
#define isrobot(A) istype(A, /mob/living/silicon/robot)
#define ispAI(A) istype(A, /mob/living/silicon/pai)
#define isbot(A) istype(A, /mob/living/bot)
#define isvoice(A) istype(A, /mob/living/voice)
//---------------
//#define isturf(D) istype(D, /turf) //Built in
#define isopenspace(A) istype(A, /turf/simulated/open)

View File

@@ -40,31 +40,6 @@
#define ACCESSORY_SLOT_TORSO (ACCESSORY_SLOT_UTILITY|ACCESSORY_SLOT_WEAPON)
// Flags bitmasks. - Used in /atom/var/flags
#define NOBLUDGEON 0x1 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
#define CONDUCT 0x2 // Conducts electricity. (metal etc.)
#define ON_BORDER 0x4 // Item has priority to check when entering or leaving.
#define NOBLOODY 0x8 // Used for items if they don't want to get a blood overlay.
#define OPENCONTAINER 0x10 // Is an open container for chemistry purposes.
#define PHORONGUARD 0x20 // Does not get contaminated by phoron.
#define NOREACT 0x40 // Reagents don't react inside this container.
#define PROXMOVE 0x80 // Does this object require proximity checking in Enter()?
#define OVERLAY_QUEUED 0x100 // Atom queued to SSoverlay for COMPILE_OVERLAYS
//Flags for items (equipment) - Used in /obj/item/var/item_flags
#define THICKMATERIAL 0x1 // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
#define STOPPRESSUREDAMAGE 0x2 // Counts towards pressure protection. Note that like temperature protection, body_parts_covered is considered here as well.
#define AIRTIGHT 0x4 // Functions with internals.
#define NOSLIP 0x8 // Prevents from slipping on wet floors, in space, etc.
#define BLOCK_GAS_SMOKE_EFFECT 0x10 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
#define FLEXIBLEMATERIAL 0x20 // At the moment, masks with this flag will not prevent eating even if they are covering your face.
// Flags for pass_flags. - Used in /atom/var/pass_flags
#define PASSTABLE 0x1
#define PASSGLASS 0x2
#define PASSGRILLE 0x4
#define PASSBLOB 0x8
// Bitmasks for the /obj/item/var/flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
// WARNING: The following flags apply only to the external suit!
#define HIDEGLOVES 0x1

View File

@@ -106,26 +106,15 @@ var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret
#define ATMOS_DEFAULT_VOLUME_MIXER 200 // L.
#define ATMOS_DEFAULT_VOLUME_PIPE 70 // L.
//wIP - PORT ALL OF THESE TO SUBSYSTEMS AND GET RID OF THE WHOLE LIST PROCESS THING
// Fancy-pants START/STOP_PROCESSING() macros that lets us custom define what the list is.
#define START_PROCESSING_IN_LIST(DATUM, LIST) \
if (DATUM.is_processing) {\
if(DATUM.is_processing != #LIST)\
{\
crash_with("Failed to start processing. [log_info_line(DATUM)] is already being processed by [DATUM.is_processing] but queue attempt occured on [#LIST]."); \
}\
} else {\
DATUM.is_processing = #LIST;\
if (!(DATUM.datum_flags & DF_ISPROCESSING)) {\
LIST += DATUM;\
DATUM.datum_flags |= DF_ISPROCESSING\
}
#define STOP_PROCESSING_IN_LIST(DATUM, LIST) \
if(DATUM.is_processing) {\
if(LIST.Remove(DATUM)) {\
DATUM.is_processing = null;\
} else {\
crash_with("Failed to stop processing. [log_info_line(DATUM)] is being processed by [is_processing] and not found in SSmachines.[#LIST]"); \
}\
}
#define STOP_PROCESSING_IN_LIST(DATUM, LIST) LIST.Remove(DATUM);DATUM.datum_flags &= ~DF_ISPROCESSING
// Note - I would prefer these be defined machines.dm, but some are used prior in file order. ~Leshana
#define START_MACHINE_PROCESSING(Datum) START_PROCESSING_IN_LIST(Datum, global.processing_machines)

View File

@@ -1,18 +1,228 @@
// Credits to Nickr5 for the useful procs I've taken from his library resource.
// This file is quadruple wrapped for your pleasure
// (
#define NUM_E 2.71828183
#define M_PI (3.14159265)
#define INFINITY (1.#INF) //closer then enough
#define SHORT_REAL_LIMIT 16777216
//"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-starting_tickusage))
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(world.tick_usage - 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 ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
#define SHORT_REAL_LIMIT 16777216 // 2^24 - Maximum integer that can be exactly represented in a float (BYOND num var)
#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) )
// Check if a BYOND dir var is a cardinal direction (power of two)
#define CLAMP(CLVALUE,CLMIN,CLMAX) ( max( (CLMIN), min((CLVALUE), (CLMAX)) ) )
// 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))) )
// Real modulus that handles decimals
#define MODULUS(x, y) ( (x) - (y) * round((x) / (y)) )
// Tangent
#define TAN(x) (sin(x) / cos(x))
// 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))) )
// 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 IS_CARDINAL(x) ((x & (x - 1)) == 0)
#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)))
/proc/Mean(...)
var/sum = 0
for(var/val in args)
sum += val
return sum / args.len
// 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
// Return if the roots are imaginary.
if(d < 0)
return
var/root = sqrt(d)
. += (-b + root) / bottom
// If discriminant == 0, there would be two roots at the same position.
if(!d)
return
. += (-b - root) / bottom
// 180 / Pi ~ 57.2957795
#define TODEGREES(radians) ((radians) * 57.2957795)
// Pi / 180 ~ 0.0174532925
#define TORADIANS(degrees) ((degrees) * 0.0174532925)
// Will filter out extra rotations and negative rotations
// E.g: 540 becomes 180. -180 becomes 180.
#define SIMPLIFY_DEGREES(degrees) (MODULUS((degrees), 360))
#define GET_ANGLE_OF_INCIDENCE(face, input) (MODULUS((face) - (input), 360))
//Finds the shortest angle that angle A has to change to get to angle B. Aka, whether to move clock or counterclockwise.
/proc/closer_angle_difference(a, b)
if(!isnum(a) || !isnum(b))
return
a = SIMPLIFY_DEGREES(a)
b = SIMPLIFY_DEGREES(b)
var/inc = b - a
if(inc < 0)
inc += 360
var/dec = a - b
if(dec < 0)
dec += 360
. = inc > 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 RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW)
#define SQUARE(x) (x*x)
//Vector Algebra
#define SQUAREDNORM(x, y) (x*x+y*y)
#define NORM(x, y) (sqrt(SQUAREDNORM(x,y)))
#define ISPOWEROFTWO(x) ((x & (x - 1)) == 0)
#define ROUNDUPTOPOWEROFTWO(x) (2 ** -round(-log(2,x)))
#define DEFAULT(a, b) (a? a : b)

View File

@@ -1,10 +1,13 @@
// Math constants.
#define M_PI 3.14159265
#define R_IDEAL_GAS_EQUATION 8.31 // kPa*L/(K*mol).
#define ONE_ATMOSPHERE 101.325 // kPa.
#define IDEAL_GAS_ENTROPY_CONSTANT 1164 // (mol^3 * s^3) / (kg^3 * L).
#define T0C 273.15 // 0.0 degrees celcius
#define T20C 293.15 // 20.0 degrees celcius
#define TCMB 2.7 // -270.3 degrees celcius
#define TN60C 213.15 // -60 degrees celcius
// Radiation constants.
#define STEFAN_BOLTZMANN_CONSTANT 5.6704e-8 // W/(m^2*K^4).
#define COSMIC_RADIATION_TEMPERATURE 3.15 // K.
@@ -15,18 +18,7 @@
#define RADIATOR_EXPOSED_SURFACE_AREA_RATIO 0.04 // (3 cm + 100 cm * sin(3deg))/(2*(3+100 cm)). Unitless ratio.
#define HUMAN_EXPOSED_SURFACE_AREA 5.2 //m^2, surface area of 1.7m (H) x 0.46m (D) cylinder
#define T0C 273.15 // 0.0 degrees celcius
#define T20C 293.15 // 20.0 degrees celcius
#define TCMB 2.7 // -270.3 degrees celcius
#define TN60C 213.15 // -60 degrees celcius
#define CLAMP01(x) max(0, min(1, x))
#define QUANTIZE(variable) (round(variable,0.0001))
#define INFINITY 1.#INF
#define TICKS_IN_DAY 24*60*60*10
#define TICKS_IN_SECOND 10
#define SIMPLE_SIGN(X) ((X) < 0 ? -1 : 1)
#define SIGN(X) ((X) ? SIMPLE_SIGN(X) : 0)
#define TICKS_IN_DAY (TICKS_IN_SECOND * 60 * 60 * 24)
#define TICKS_IN_SECOND (world.fps)

View File

@@ -258,7 +258,7 @@
// If the GLOB system is ever ported, you can change this macro in one place and have less work to do than you otherwise would.
#define GLOBAL_LIST_BOILERPLATE(LIST_NAME, PATH)\
var/global/list/##LIST_NAME = list();\
##PATH/initialize(mapload, ...)\
##PATH/Initialize(mapload, ...)\
{\
##LIST_NAME += src;\
return ..();\
@@ -290,6 +290,11 @@ var/global/list/##LIST_NAME = list();\
#define IS_WIRECUTTER "wirecutter"
#define IS_WRENCH "wrench"
// Diagonal movement
#define FIRST_DIAG_STEP 1
#define SECOND_DIAG_STEP 2
// RCD modes. Used on the RCD, and gets passed to an object's rcd_act() when an RCD is used on it, to determine what happens.
#define RCD_FLOORWALL "Floor / Wall" // Builds plating on space/ground/open tiles. Builds a wall when on floors. Finishes walls when used on girders.
#define RCD_AIRLOCK "Airlock" // Builds an airlock on the tile if one isn't already there.
@@ -300,6 +305,11 @@ var/global/list/##LIST_NAME = list();\
#define RCD_VALUE_DELAY "delay"
#define RCD_VALUE_COST "cost"
#define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units.
#define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT
// Radiation 'levels'. Used for the geiger counter, for visuals and sound. They are in different files so this goes here.
#define RAD_LEVEL_LOW 0.01 // Around the level at which radiation starts to become harmful
#define RAD_LEVEL_MODERATE 10
#define RAD_LEVEL_HIGH 25
#define RAD_LEVEL_VERY_HIGH 50

View File

@@ -27,6 +27,9 @@
#define BORGXRAY 0x4
#define BORGMATERIAL 8
#define STANCE_ATTACK 11 // Backwards compatability
#define STANCE_ATTACKING 12 // Ditto
/*
#define STANCE_IDLE 1 // Looking for targets if hostile. Does idle wandering.
#define STANCE_ALERT 2 // Bears
#define STANCE_ATTACK 3 // Attempting to get into attack position
@@ -34,6 +37,20 @@
#define STANCE_TIRED 5 // Bears
#define STANCE_FOLLOW 6 // Following somone
#define STANCE_BUSY 7 // Do nothing on life ticks (Other code is running)
*/
#define STANCE_SLEEP 0 // Doing (almost) nothing, to save on CPU because nobody is around to notice or the mob died.
#define STANCE_IDLE 1 // The more or less default state. Wanders around, looks for baddies, and spouts one-liners.
#define STANCE_ALERT 2 // A baddie is visible but not too close, and essentially we tell them to go away or die.
#define STANCE_APPROACH 3 // Attempting to get into range to attack them.
#define STANCE_FIGHT 4 // Actually fighting, with melee or ranged.
#define STANCE_BLINDFIGHT 5 // Fighting something that cannot be seen by the mob, from invisibility or out of sight.
#define STANCE_REPOSITION 6 // Relocating to a better position while in combat. Also used when moving away from a danger like grenades.
#define STANCE_MOVE 7 // Similar to above but for out of combat. If a baddie is seen, they'll cancel and fight them.
#define STANCE_FOLLOW 8 // Following somone, without trying to murder them.
#define STANCE_FLEE 9 // Run away from the target because they're too spooky/we're dying/some other reason.
#define STANCE_DISABLED 10 // Used when the holder is afflicted with certain status effects, such as stuns or confusion.
#define STANCES_COMBAT list(STANCE_ALERT, STANCE_APPROACH, STANCE_FIGHT, STANCE_BLINDFIGHT, STANCE_REPOSITION)
#define LEFT 0x1
#define RIGHT 0x2
@@ -279,11 +296,34 @@
#define SA_ROBOTIC 3
#define SA_HUMANOID 4
// More refined version of SA_* ""intelligence"" seperators.
// Now includes bitflags, so to target two classes you just do 'MOB_CLASS_ANIMAL|MOB_CLASS_HUMANOID'
#define MOB_CLASS_NONE 0 // Default value, and used to invert for _ALL.
#define MOB_CLASS_PLANT 1 // Unused at the moment.
#define MOB_CLASS_ANIMAL 2 // Animals and beasts like spiders, saviks, and bears.
#define MOB_CLASS_HUMANOID 4 // Non-robotic humanoids, including /simple_mob and /carbon/humans and their alien variants.
#define MOB_CLASS_SYNTHETIC 8 // Silicons, mechanical simple mobs, FBPs, and anything else that would pass is_synthetic()
#define MOB_CLASS_SLIME 16 // Everyone's favorite xenobiology specimen (and maybe prometheans?).
#define MOB_CLASS_ABERRATION 32 // Weird shit.
#define MOB_CLASS_DEMONIC 64 // Cult stuff.
#define MOB_CLASS_BOSS 128 // Future megafauna hopefully someday.
#define MOB_CLASS_ILLUSION 256 // Fake mobs, e.g. Technomancer illusions.
#define MOB_CLASS_PHOTONIC 512 // Holographic mobs like holocarp, similar to _ILLUSION, but that make no attempt to hide their true nature.
#define MOB_CLASS_ALL (~MOB_CLASS_NONE)
// For slime commanding. Higher numbers allow for more actions.
#define SLIME_COMMAND_OBEY 1 // When disciplined.
#define SLIME_COMMAND_FACTION 2 // When in the same 'faction'.
#define SLIME_COMMAND_FRIEND 3 // When befriended with a slime friendship agent.
// Threshold for mobs being able to damage things like airlocks or reinforced glass windows.
// If the damage is below this, nothing will happen besides a message saying that the attack was ineffective.
// Generally, this was not a define but was commonly set to 10, however 10 may be too low now since simple_mobs now attack twice as fast,
// at half damage compared to the old mob system, meaning mobs who could hurt structures may not be able to now, so now it is 5.
#define STRUCTURE_MIN_DAMAGE_THRESHOLD 5
//Vision flags, for dealing with plane visibility
#define VIS_FULLBRIGHT 1
#define VIS_LIGHTING 2

View File

@@ -1,6 +1,5 @@
/*
* Defines used for miscellaneous objects.
* Currently only the home of the Multiool.
*/
// Multitool Mode Defines.
@@ -8,3 +7,25 @@
#define MULTITOOL_MODE_STANDARD "Standard"
#define MULTITOOL_MODE_INTCIRCUITS "Modular Wiring"
#define MULTITOOL_MODE_DOORHACK "Advanced Jacking"
// Identity system defines.
#define IDENTITY_UNKNOWN 0 // Nothing is known so far.
#define IDENTITY_PROPERTIES 1 // Basic function of the item, and amount of charges available if it uses them.
#define IDENTITY_QUALITY 2 // Blessed/Uncursed/Cursed status. Some things don't use this.
#define IDENTITY_FULL IDENTITY_PROPERTIES|IDENTITY_QUALITY // Know everything.
#define IDENTITY_TYPE_NONE "generic"
#define IDENTITY_TYPE_TECH "technological"
#define IDENTITY_TYPE_CHEMICAL "chemical"
// Roguelike object quality defines. Not used at the moment.
#define ROGUELIKE_ITEM_ARTIFACT 2 // Cannot degrade, very rare.
#define ROGUELIKE_ITEM_BLESSED 1 // Better than average and resists cursing.
#define ROGUELIKE_ITEM_UNCURSED 0 // Normal.
#define ROGUELIKE_ITEM_CURSED -1 // Does bad things, clothing cannot be taken off.
// Consistant messages for certain events.
// Consistancy is import in order to avoid giving too much information away when using an
// unidentified object due to a typo or some other unique difference in message output.
#define ROGUELIKE_MESSAGE_NOTHING "Nothing happens."
#define ROGUELIKE_MESSAGE_UNKNOWN "Something happened, but you're not sure what."

View File

@@ -9,6 +9,9 @@
#define WEATHER_WINDY "windy"
#define WEATHER_HOT "hot"
#define WEATHER_BLOOD_MOON "blood moon" // For admin fun or cult later on.
#define WEATHER_EMBERFALL "emberfall" // More adminbuse, from TG. Harmless.
#define WEATHER_ASH_STORM "ash storm" // Ripped from TG, like the above. Less harmless.
#define WEATHER_FALLOUT "fallout" // Modified emberfall, actually harmful. Admin only.
#define MOON_PHASE_NEW_MOON "new moon"
#define MOON_PHASE_WAXING_CRESCENT "waxing crescent"

View File

@@ -22,7 +22,13 @@
#define QDELETED(X) (!X || X.gc_destroyed)
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
//Qdel helper macros.
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)
#define QDEL_NULL(item) qdel(item); item = null
#define QDEL_LIST_NULL(x) if(x) { for(var/y in x) { qdel(y) } ; x = null }
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }

View File

@@ -51,6 +51,7 @@
#define LANGUAGE_EVENT1 "Occursus"
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.

View File

@@ -1,18 +1,23 @@
//Timing subsystem
//Don't run if there is an identical unique timer active
#define TIMER_UNIQUE 0x1
//if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer
#define TIMER_UNIQUE (1<<0)
//For unique timers: Replace the old timer rather then not start this one
#define TIMER_OVERRIDE 0x2
#define TIMER_OVERRIDE (1<<1)
//Timing should be based on how timing progresses on clients, not the sever.
// tracking this is more expensive,
// should only be used in conjuction with things that have to progress client side, such as animate() or sound()
#define TIMER_CLIENT_TIME 0x4
#define TIMER_CLIENT_TIME (1<<2)
//Timer can be stopped using deltimer()
#define TIMER_STOPPABLE 0x8
#define TIMER_STOPPABLE (1<<3)
//To be used with TIMER_UNIQUE
//prevents distinguishing identical timers with the wait variable
#define TIMER_NO_HASH_WAIT 0x10
#define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something
#define TIMER_NO_HASH_WAIT (1<<4)
//Loops the timer repeatedly until qdeleted
//In most cases you want a subsystem instead
#define TIMER_LOOP (1<<5)
#define TIMER_ID_NULL -1
#define INITIALIZATION_INSSATOMS 0 //New should not call Initialize
#define INITIALIZATION_INNEW_MAPLOAD 1 //New should call Initialize(TRUE)
@@ -47,11 +52,13 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
// Subsystem init_order, from highest priority to lowest priority
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
#define INIT_ORDER_MAPPING 20 // VOREStation Edit
#define INIT_ORDER_CHEMISTRY 18
#define INIT_ORDER_MAPPING 17
#define INIT_ORDER_DECALS 16
#define INIT_ORDER_ATOMS 15
#define INIT_ORDER_MACHINES 10
#define INIT_ORDER_SHUTTLES 3
#define INIT_ORDER_TIMER 1
#define INIT_ORDER_DEFAULT 0
#define INIT_ORDER_LIGHTING 0
#define INIT_ORDER_AIR -1
@@ -60,6 +67,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_XENOARCH -20
#define INIT_ORDER_CIRCUIT -21
#define INIT_ORDER_AI -22
// Subsystem fire priority, from lowest to highest priority
@@ -67,12 +75,16 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_SHUTTLES 5
#define FIRE_PRIORITY_ORBIT 8
#define FIRE_PRIORITY_VOTE 9
#define FIRE_PRIORITY_AI 10
#define FIRE_PRIORITY_GARBAGE 15
#define FIRE_PRIORITY_AIRFLOW 30
#define FIRE_PRIORITY_AIR 35
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_PROCESS 45
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_PROJECTILES 150
#define FIRE_PRIORITY_OVERLAYS 500
// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)

View File

46
code/__defines/vv.dm Normal file
View File

@@ -0,0 +1,46 @@
#define VV_NUM "Number"
#define VV_TEXT "Text"
#define VV_MESSAGE "Mutiline Text"
#define VV_ICON "Icon"
#define VV_ATOM_REFERENCE "Atom Reference"
#define VV_DATUM_REFERENCE "Datum Reference"
#define VV_MOB_REFERENCE "Mob Reference"
#define VV_CLIENT "Client"
#define VV_ATOM_TYPE "Atom Typepath"
#define VV_DATUM_TYPE "Datum Typepath"
#define VV_TYPE "Custom Typepath"
#define VV_FILE "File"
#define VV_LIST "List"
#define VV_NEW_ATOM "New Atom"
#define VV_NEW_DATUM "New Datum"
#define VV_NEW_TYPE "New Custom Typepath"
#define VV_NEW_LIST "New List"
#define VV_NULL "NULL"
#define VV_RESTORE_DEFAULT "Restore to Default"
#define VV_MARKED_DATUM "Marked Datum"
#define VV_BITFIELD "Bitfield"
#define VV_MSG_MARKED "<br><font size='1' color='red'><b>Marked Object</b></font>"
#define VV_MSG_EDITED "<br><font size='1' color='red'><b>Var Edited</b></font>"
#define VV_MSG_DELETED "<br><font size='1' color='red'><b>Deleted</b></font>"
#define VV_NORMAL_LIST_NO_EXPAND_THRESHOLD 50
#define VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD 150
#define IS_VALID_ASSOC_KEY(V) (istext(V) || isdatum(V) || islist(V))
//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[href_key]=TRUE;target=\ref[src]'>[name]</option>"
//Helpers for vv_do_topic(list/href_list)
#define IF_VV_OPTION(href_key) if(href_list[href_key])
// /datum
#define VV_HK_DELETE "delete"
#define VV_HK_EXPOSE "expose"
#define VV_HK_CALLPROC "proc_call"
#define VV_HK_MARK "mark"
// /atom
#define VV_HK_ATOM_EXPLODE "turf_explode"
#define VV_HK_ATOM_EMP "turf_emp"

View File

@@ -0,0 +1,7 @@
GLOBAL_LIST_INIT(bitfields, list(
"datum_flags" = list(
"DF_VAR_EDITED" = DF_VAR_EDITED,
"DF_ISPROCESSING" = DF_ISPROCESSING
)
))

View File

@@ -1,4 +1,8 @@
GLOBAL_LIST_EMPTY(all_observable_events)
GLOBAL_LIST_EMPTY(error_last_seen)
GLOBAL_LIST_EMPTY(error_cooldown)
GLOBAL_DATUM_INIT(all_observable_events, /datum/all_observable_events, new) // This is a datum. It is not a list.
GLOBAL_DATUM_INIT(destroyed_event, /decl/observ/destroyed, new())
GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks.

View File

@@ -3,3 +3,5 @@ GLOBAL_PROTECT(admins)
GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb.
GLOBAL_LIST_EMPTY(stealthminID)
GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client
GLOBAL_LIST_EMPTY(clients)
GLOBAL_LIST_EMPTY(players_by_zlevel)

View File

@@ -27,9 +27,6 @@ proc/listgetindex(var/list/list,index)
return list[index]
return
proc/islist(list/list)
return(istype(list))
//Return either pick(list) or null if list is not of type /list or is empty
proc/safepick(list/list)
if(!islist(list) || !list.len)
@@ -753,3 +750,9 @@ proc/dd_sortedTextList(list/incoming)
for(var/i = 1 to l.len)
if(islist(.[i]))
.[i] = .(.[i])
//Return a list with no duplicate entries
/proc/uniqueList(list/L)
. = list()
for(var/i in L)
. |= i

View File

@@ -432,7 +432,7 @@ proc/isInSight(var/atom/A, var/atom/B)
/proc/Show2Group4Delay(obj/O, list/group, delay=0)
if(!isobj(O)) return
if(!group) group = clients
if(!group) group = GLOB.clients
for(var/client/C in group)
C.screen += O
if(delay)

View File

@@ -1,6 +1,4 @@
var/list/clients = list() //list of all clients
var/list/admins = list() //list of all clients whom are admins
var/list/directory = list() //list of all ckeys with associated client
//Since it didn't really belong in any other category, I'm putting this here
//This is for procs to replace all the goddamn 'in world's that are chilling around the code
@@ -15,8 +13,6 @@ var/global/list/dead_mob_list = list() //List of all dead mobs, including cli
var/global/list/listening_objects = list() //List of all objects which care about receiving messages (communicators, radios, etc)
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
var/global/list/landmarks_list = list() //list of all landmarks created
var/global/list/surgery_steps = list() //list of all surgery steps |BS12
var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12

View File

@@ -94,7 +94,7 @@ var/global/list/struggle_sounds = list(
"Squish4" = 'sound/vore/squish4.ogg')
var/global/list/global_egg_types = list(
var/global/list/global_vore_egg_types = list(
"Unathi" = UNATHI_EGG,
"Tajaran" = TAJARAN_EGG,
"Akula" = AKULA_EGG,
@@ -107,7 +107,7 @@ var/global/list/global_egg_types = list(
"Xenochimera" = XENOCHIMERA_EGG,
"Xenomorph" = XENOMORPH_EGG)
var/global/list/tf_egg_types = list(
var/global/list/tf_vore_egg_types = list(
"Unathi" = /obj/structure/closet/secure_closet/egg/unathi,
"Tajara" = /obj/structure/closet/secure_closet/egg/tajaran,
"Akula" = /obj/structure/closet/secure_closet/egg/shark,

View File

@@ -627,22 +627,44 @@ proc/ColorTone(rgb, tone)
if(gray <= tone_gray) return BlendRGB("#000000", tone, gray/(tone_gray || 1))
else return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1))
/*
Get flat icon by DarkCampainger. As it says on the tin, will return an icon with all the overlays
as a single icon. Useful for when you want to manipulate an icon via the above as overlays are not normally included.
The _flatIcons list is a cache for generated icon files.
*/
// Ported from /tg/station
// Creates a single icon from a given /atom or /image. Only the first argument is required.
/proc/getFlatIcon(image/A, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE)
// We start with a blank canvas, otherwise some icon procs crash silently
var/icon/flat = icon('icons/effects/effects.dmi', "nothing") // Final flattened icon
if(!A)
return flat
if(A.alpha <= 0)
return flat
var/noIcon = FALSE
//Define... defines.
var/static/icon/flat_template = icon('icons/effects/effects.dmi', "nothing")
#define BLANK icon(flat_template)
#define SET_SELF(SETVAR) do { \
var/icon/SELF_ICON=icon(icon(curicon, curstate, base_icon_dir),"",SOUTH,no_anim?1:null); \
if(A.alpha<255) { \
SELF_ICON.Blend(rgb(255,255,255,A.alpha),ICON_MULTIPLY);\
} \
if(A.color) { \
if(islist(A.color)){ \
SELF_ICON.MapColors(arglist(A.color))} \
else{ \
SELF_ICON.Blend(A.color,ICON_MULTIPLY)} \
} \
##SETVAR=SELF_ICON;\
} while (0)
#define INDEX_X_LOW 1
#define INDEX_X_HIGH 2
#define INDEX_Y_LOW 3
#define INDEX_Y_HIGH 4
#define flatX1 flat_size[INDEX_X_LOW]
#define flatX2 flat_size[INDEX_X_HIGH]
#define flatY1 flat_size[INDEX_Y_LOW]
#define flatY2 flat_size[INDEX_Y_HIGH]
#define addX1 add_size[INDEX_X_LOW]
#define addX2 add_size[INDEX_X_HIGH]
#define addY1 add_size[INDEX_Y_LOW]
#define addY2 add_size[INDEX_Y_HIGH]
if(!A || A.alpha <= 0)
return BLANK
var/noIcon = FALSE
if(start)
if(!defdir)
defdir = A.dir
@@ -653,23 +675,13 @@ The _flatIcons list is a cache for generated icon files.
if(!defblend)
defblend = A.blend_mode
var/curicon
if(A.icon)
curicon = A.icon
else
curicon = deficon
var/curicon = A.icon || deficon
var/curstate = A.icon_state || defstate
if(!curicon)
noIcon = TRUE // Do not render this object.
var/curstate
if(A.icon_state)
curstate = A.icon_state
else
curstate = defstate
if(!noIcon && !(curstate in icon_states(curicon)))
if("" in icon_states(curicon))
if(!((noIcon = (!curicon))))
var/curstates = icon_states(curicon)
if(!(curstate in curstates))
if("" in curstates)
curstate = ""
else
noIcon = TRUE // Do not render this object.
@@ -683,36 +695,28 @@ The _flatIcons list is a cache for generated icon files.
else
curdir = A.dir
//Let's check if the icon actually contains any diagonals, just skip if it's south to save (lot of) time
if(curdir != SOUTH)
var/icon/test_icon
var/directionals_exist = FALSE
var/list/dirs_to_check = cardinal - SOUTH
outer:
for(var/possible_dir in dirs_to_check)
test_icon = icon(curicon,curstate,possible_dir,frame=1)
for(var/x in 1 to world.icon_size)
for(var/y in 1 to world.icon_size)
if(!isnull(test_icon.GetPixel(x,y)))
directionals_exist = TRUE
break outer
if(!directionals_exist)
//Try to remove/optimize this section ASAP, CPU hog.
//Determines if there's directionals.
if(!noIcon && curdir != SOUTH)
var/exist = FALSE
var/static/list/checkdirs = list(NORTH, EAST, WEST)
for(var/i in checkdirs) //Not using GLOB for a reason.
if(length(icon_states(icon(curicon, curstate, i))))
exist = TRUE
break
if(!exist)
base_icon_dir = SOUTH
//
if(!base_icon_dir)
base_icon_dir = curdir
var/curblend
if(A.blend_mode == BLEND_DEFAULT)
curblend = defblend
else
curblend = A.blend_mode
ASSERT(!BLEND_DEFAULT) //I might just be stupid but lets make sure this define is 0.
// Before processing overlays, make sure any pending overlays are applied
if (isloc(A))
var/atom/aAtom = A
if(aAtom.flags & OVERLAY_QUEUED)
COMPILE_OVERLAYS(aAtom)
var/curblend = A.blend_mode || defblend
if(A.overlays.len || A.underlays.len)
var/icon/flat = BLANK
// Layers will be a sorted list of icons/overlays, based on the order in which they are displayed
var/list/layers = list()
var/image/copy
@@ -725,64 +729,35 @@ The _flatIcons list is a cache for generated icon files.
layers[copy] = A.layer
// Loop through the underlays, then overlays, sorting them into the layers list
var/list/process = A.underlays // Current list being processed
var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays
var/curIndex=1 // index of 'current' in list being processed
var/current // Current overlay being sorted
var/currentLayer // Calculated layer that overlay appears on (special case for FLOAT_LAYER)
var/compare // The overlay 'add' is being compared against
var/cmpIndex // The index in the layers list of 'compare'
while(TRUE)
if(curIndex<=process.len)
current = process[curIndex]
for(var/process_set in 0 to 1)
var/list/process = process_set? A.overlays : A.underlays
for(var/i in 1 to process.len)
var/image/current = process[i]
if(!current)
curIndex++ //Try the next layer
continue
var/image/I = current
if(I.plane != FLOAT_PLANE && I.plane != A.plane)
curIndex++
if(current.plane != FLOAT_PLANE && current.plane != A.plane)
continue
currentLayer = I.layer
if(currentLayer<0) // Special case for FLOAT_LAYER
if(currentLayer <= -1000)
var/current_layer = current.layer
if(current_layer < 0)
if(current_layer <= -1000)
return flat
if(pSet == 0) // Underlay
currentLayer = A.layer+currentLayer/1000
else // Overlay
currentLayer = A.layer+(1000+currentLayer)/1000
current_layer = process_set + A.layer + current_layer / 1000
// Sort add into layers list
for(cmpIndex=1,cmpIndex<=layers.len,cmpIndex++)
compare = layers[cmpIndex]
if(currentLayer < layers[compare]) // Associated value is the calculated layer
layers.Insert(cmpIndex,current)
layers[current] = currentLayer
for(var/p in 1 to layers.len)
var/image/cmp = layers[p]
if(current_layer < layers[cmp])
layers.Insert(p, current)
break
if(cmpIndex>layers.len) // Reached end of list without inserting
layers[current]=currentLayer // Place at end
layers[current] = current_layer
curIndex++
if(curIndex>process.len)
if(pSet == 0) // Switch to overlays
curIndex = 1
pSet = 1
process = A.overlays
else // All done
break
//sortTim(layers, /proc/cmp_image_layer_asc)
var/icon/add // Icon of overlay being added
// Current dimensions of flattened icon
var/flatX1=1
var/flatX2=flat.Width()
var/flatY1=1
var/flatY2=flat.Height()
var/list/flat_size = list(1, flat.Width(), 1, flat.Height())
// Dimensions of overlay being added
var/addX1
var/addX2
var/addY1
var/addY2
var/list/add_size[4]
for(var/V in layers)
var/image/I = V
@@ -793,25 +768,36 @@ The _flatIcons list is a cache for generated icon files.
curblend = BLEND_OVERLAY
add = icon(I.icon, I.icon_state, base_icon_dir)
else // 'I' is an appearance object.
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend, FALSE, no_anim)
add = getFlatIcon(image(I), curdir, curicon, curstate, curblend, FALSE, no_anim)
if(!add)
continue
// Find the new dimensions of the flat icon to fit the added overlay
addX1 = min(flatX1, I.pixel_x+1)
addX2 = max(flatX2, I.pixel_x+add.Width())
addY1 = min(flatY1, I.pixel_y+1)
addY2 = max(flatY2, I.pixel_y+add.Height())
add_size = list(
min(flatX1, I.pixel_x+1),
max(flatX2, I.pixel_x+add.Width()),
min(flatY1, I.pixel_y+1),
max(flatY2, I.pixel_y+add.Height())
)
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
if(flat_size ~! add_size)
// Resize the flattened icon so the new icon fits
flat.Crop(addX1-flatX1+1, addY1-flatY1+1, addX2-flatX1+1, addY2-flatY1+1)
flatX1=addX1;flatX2=addX2
flatY1=addY1;flatY2=addY2
flat.Crop(
addX1 - flatX1 + 1,
addY1 - flatY1 + 1,
addX2 - flatX1 + 1,
addY2 - flatY1 + 1
)
flat_size = add_size.Copy()
// Blend the overlay into the flattened icon
flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1)
if(A.color)
if(islist(A.color))
flat.MapColors(arglist(A.color))
else
flat.Blend(A.color, ICON_MULTIPLY)
if(A.alpha < 255)
flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY)
@@ -819,12 +805,30 @@ The _flatIcons list is a cache for generated icon files.
//Clean up repeated frames
var/icon/cleaned = new /icon()
cleaned.Insert(flat, "", SOUTH, 1, 0)
return cleaned
. = cleaned
else
return icon(flat, "", SOUTH)
. = icon(flat, "", SOUTH)
else //There's no overlays.
if(!noIcon)
SET_SELF(.)
//Clear defines
#undef flatX1
#undef flatX2
#undef flatY1
#undef flatY2
#undef addX1
#undef addX2
#undef addY1
#undef addY2
#undef INDEX_X_LOW
#undef INDEX_X_HIGH
#undef INDEX_Y_LOW
#undef INDEX_Y_HIGH
#undef BLANK
#undef SET_SELF
/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
@@ -900,9 +904,9 @@ proc/adjust_brightness(var/color, var/value)
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)

View File

@@ -1,131 +0,0 @@
// Macro functions.
#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW)
#define ceil(x) (-round(-(x)))
// 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)
/proc/Default(a, b)
return a ? a : b
// Trigonometric functions.
/proc/Tan(x)
return sin(x) / cos(x)
/proc/Csc(x)
return 1 / sin(x)
/proc/Sec(x)
return 1 / cos(x)
/proc/Cot(x)
return 1 / Tan(x)
/proc/Atan2(x, y)
if(!x && !y) return 0
var/a = arccos(x / sqrt(x*x + y*y))
return y >= 0 ? a : -a
/proc/Floor(x)
return round(x)
/proc/Ceiling(x)
return -round(-x)
// Greatest Common Divisor: Euclid's algorithm.
/proc/Gcd(a, b)
while (1)
if (!b) return a
a %= b
if (!a) return b
b %= a
// Least Common Multiple. The formula is a consequence of: a*b = LCM*GCD.
/proc/Lcm(a, b)
return abs(a) * abs(b) / Gcd(a, b)
// Useful in the cases when x is a large expression, e.g. x = 3a/2 + b^2 + Function(c)
/proc/Square(x)
return x*x
/proc/Inverse(x)
return 1 / x
// Condition checks.
/proc/IsAboutEqual(a, b, delta = 0.1)
return abs(a - b) <= delta
// Returns true if val is from min to max, inclusive.
/proc/IsInRange(val, min, max)
return (val >= min) && (val <= max)
/proc/IsInteger(x)
return Floor(x) == x
/proc/IsMultiple(x, y)
return x % y == 0
/proc/IsEven(x)
return !(x & 0x1)
/proc/IsOdd(x)
return (x & 0x1)
// Performs a linear interpolation between a and b.
// Note: weight=0 returns a, weight=1 returns b, and weight=0.5 returns the mean of a and b.
/proc/Interpolate(a, b, weight = 0.5)
return a + (b - a) * weight // Equivalent to: a*(1 - weight) + b*weight
/proc/Mean(...)
var/sum = 0
for(var/val in args)
sum += val
return sum / args.len
// Returns the nth root of x.
/proc/Root(n, x)
return 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/discriminant = b*b - 4*a*c
var/bottom = 2*a
// Return if the roots are imaginary.
if(discriminant < 0)
return
var/root = sqrt(discriminant)
. += (-b + root) / bottom
// If discriminant == 0, there would be two roots at the same position.
if(discriminant != 0)
. += (-b - root) / bottom
/proc/ToDegrees(radians)
// 180 / Pi ~ 57.2957795
return radians * 57.2957795
/proc/ToRadians(degrees)
// Pi / 180 ~ 0.0174532925
return degrees * 0.0174532925
// Vector algebra.
/proc/squaredNorm(x, y)
return x*x + y*y
/proc/norm(x, y)
return sqrt(squaredNorm(x, y))
/proc/IsPowerOfTwo(var/val)
return (val & (val-1)) == 0
/proc/RoundUpToPowerOfTwo(var/val)
return 2 ** -round(-log(2,val))

View File

@@ -50,7 +50,7 @@
/proc/color_rotation(angle)
if(angle == 0)
return color_identity()
angle = Clamp(angle, -180, 180)
angle = CLAMP(angle, -180, 180)
var/cos = cos(angle)
var/sin = sin(angle)
@@ -65,7 +65,7 @@
//Makes everything brighter or darker without regard to existing color or brightness
/proc/color_brightness(power)
power = Clamp(power, -255, 255)
power = CLAMP(power, -255, 255)
power = power/255
return list(1,0,0, 0,1,0, 0,0,1, power,power,power)
@@ -85,7 +85,7 @@
//Exxagerates or removes brightness
/proc/color_contrast(value)
value = Clamp(value, -100, 100)
value = CLAMP(value, -100, 100)
if(value == 0)
return color_identity()
@@ -108,7 +108,7 @@
/proc/color_saturation(value as num)
if(value == 0)
return color_identity()
value = Clamp(value, -100, 100)
value = CLAMP(value, -100, 100)
if(value > 0)
value *= 3
var/x = 1 + value / 100

View File

@@ -285,16 +285,3 @@ Proc for attack log creation, because really why not
else
. = getCompoundIcon(desired)
cached_character_icons[cachekey] = .
/proc/getviewsize(view)
var/viewX
var/viewY
if(isnum(view))
var/totalviewrange = 1 + 2 * view
viewX = totalviewrange
viewY = totalviewrange
else
var/list/viewrangelist = splittext(view,"x")
viewX = text2num(viewrangelist[1])
viewY = text2num(viewrangelist[2])
return list(viewX, viewY)

View File

@@ -19,6 +19,9 @@
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
return a.priority - b.priority
/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
return a.timeToRun - b.timeToRun
// Sorts qdel statistics recorsd by time and count
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
. = B.hard_delete_time - A.hard_delete_time

View File

@@ -16,8 +16,8 @@
#define TICK *world.tick_lag
#define TICKS *world.tick_lag
#define DS2TICKS(DS) (DS/world.tick_lag) // Convert deciseconds to ticks
#define TICKS2DS(T) (T TICKS) // Convert ticks to deciseconds
#define DS2TICKS(DS) ((DS)/world.tick_lag) // Convert deciseconds to ticks
#define TICKS2DS(T) ((T) TICKS) // Convert ticks to deciseconds
/proc/get_game_time()
var/global/time_offset = 0
@@ -140,103 +140,36 @@ var/round_start_time = 0
. += CEILING(i*DELTA_CALC, 1)
sleep(i*world.tick_lag*DELTA_CALC)
i *= 2
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, GLOB.CURRENT_TICKLIMIT))
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
#undef DELTA_CALC
//Takes a value of time in deciseconds.
//Returns a text value of that number in hours, minutes, or seconds.
/proc/DisplayTimeText(time_value, truncate = FALSE)
var/second = (time_value)*0.1
var/second_adjusted = null
var/second_rounded = FALSE
var/minute = null
var/hour = null
var/day = null
/proc/DisplayTimeText(time_value, round_seconds_to = 0.1)
var/second = round(time_value * 0.1, round_seconds_to)
if(!second)
return "0 seconds"
if(second >= 60)
minute = FLOOR(second/60, 1)
second = round(second - (minute*60), 0.1)
second_rounded = TRUE
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
second_adjusted = round(second) //used to prevent '1 seconds' being shown
if(day || hour || minute)
if(second_adjusted == 1 && second >= 1)
second = " and 1 second"
else if(second > 1)
second = " and [second_adjusted] seconds"
else //shows a fraction if seconds is < 1
if(second_rounded) //no sense rounding again if it's already done
second = " and [second] seconds"
else
second = " and [round(second, 0.1)] seconds"
else
if(second_adjusted == 1 && second >= 1)
second = "[truncate ? "second" : "1 second"]"
else if(second > 1)
second = "[second_adjusted] seconds"
else
if(second_rounded)
second = "[second] seconds"
else
second = "[round(second, 0.1)] seconds"
else
second = null
if(!minute)
return "[second]"
if(minute >= 60)
hour = FLOOR(minute/60, 1)
minute = (minute - (hour*60))
if(minute) //alot simpler from here since you don't have to worry about fractions
if(minute != 1)
if((day || hour) && second)
minute = ", [minute] minutes"
else if((day || hour) && !second)
minute = " and [minute] minutes"
else
minute = "[minute] minutes"
else
if((day || hour) && second)
minute = ", 1 minute"
else if((day || hour) && !second)
minute = " and 1 minute"
else
minute = "[truncate ? "minute" : "1 minute"]"
else
minute = null
if(!hour)
return "[minute][second]"
if(hour >= 24)
day = FLOOR(hour/24, 1)
hour = (hour - (day*24))
return "right now"
if(second < 60)
return "[second] second[(second != 1)? "s":""]"
var/minute = FLOOR(second / 60, 1)
second = MODULUS(second, 60)
var/secondT
if(second)
secondT = " and [second] second[(second != 1)? "s":""]"
if(minute < 60)
return "[minute] minute[(minute != 1)? "s":""][secondT]"
var/hour = FLOOR(minute / 60, 1)
minute = MODULUS(minute, 60)
var/minuteT
if(minute)
minuteT = " and [minute] minute[(minute != 1)? "s":""]"
if(hour < 24)
return "[hour] hour[(hour != 1)? "s":""][minuteT][secondT]"
var/day = FLOOR(hour / 24, 1)
hour = MODULUS(hour, 24)
var/hourT
if(hour)
if(hour != 1)
if(day && (minute || second))
hour = ", [hour] hours"
else if(day && (!minute || !second))
hour = " and [hour] hours"
else
hour = "[hour] hours"
else
if(day && (minute || second))
hour = ", 1 hour"
else if(day && (!minute || !second))
hour = " and 1 hour"
else
hour = "[truncate ? "hour" : "1 hour"]"
else
hour = null
if(!day)
return "[hour][minute][second]"
if(day > 1)
day = "[day] days"
else
day = "[truncate ? "day" : "1 day"]"
return "[day][hour][minute][second]"
hourT = " and [hour] hour[(hour != 1)? "s":""]"
return "[day] day[(day != 1)? "s":""][hourT][minuteT][secondT]"

View File

@@ -242,3 +242,42 @@
/proc/isLeap(y)
return ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
//Takes a string and a datum
//The string is well, obviously the string being checked
//The datum is used as a source for var names, to check validity
//Otherwise every single word could technically be a variable!
/proc/string2listofvars(var/t_string, var/datum/var_source)
if(!t_string || !var_source)
return list()
. = list()
var/var_found = findtext(t_string,"\[") //Not the actual variables, just a generic "should we even bother" check
if(var_found)
//Find var names
// "A dog said hi [name]!"
// splittext() --> list("A dog said hi ","name]!"
// jointext() --> "A dog said hi name]!"
// splittext() --> list("A","dog","said","hi","name]!")
t_string = replacetext(t_string,"\[","\[ ")//Necessary to resolve "word[var_name]" scenarios
var/list/list_value = splittext(t_string,"\[")
var/intermediate_stage = jointext(list_value, null)
list_value = splittext(intermediate_stage," ")
for(var/value in list_value)
if(findtext(value,"]"))
value = splittext(value,"]") //"name]!" --> list("name","!")
for(var/A in value)
if(var_source.vars.Find(A))
. += A
/proc/get_end_section_of_type(type)
var/strtype = "[type]"
var/delim_pos = findlasttext(strtype, "/")
if(delim_pos == 0)
return strtype
return copytext(strtype, delim_pos)

View File

@@ -501,7 +501,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M)
for(var/mob/new_player/M in sortmob)
moblist.Add(M)
for(var/mob/living/simple_animal/M in sortmob)
for(var/mob/living/simple_mob/M in sortmob)
moblist.Add(M)
// for(var/mob/living/silicon/hivebot/M in sortmob)
// mob_list.Add(M)
@@ -831,6 +831,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
//Move the objects. Not forceMove because the object isn't "moving" really, it's supposed to be on the "same" turf.
for(var/obj/O in T)
O.loc = X
O.update_light()
//Move the mobs unless it's an AI eye or other eye type.
for(var/mob/M in T)
@@ -1266,9 +1267,11 @@ var/mob/dview/dview_mob = new
if(!center)
return
if(!dview_mob) //VOREStation Add - Emergency Backup
//VOREStation Add - Emergency Backup
if(!dview_mob)
dview_mob = new()
WARNING("dview mob was lost, and had to be recreated!")
//VOREStation Add End
dview_mob.loc = center
@@ -1402,6 +1405,20 @@ var/mob/dview/dview_mob = new
#undef NOT_FLAG
#undef HAS_FLAG
//datum may be null, but it does need to be a typed var
#define NAMEOF(datum, X) (#X || ##datum.##X)
#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
//dupe code because dm can't handle 3 level deep macros
#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
/proc/___callbackvarset(list_or_datum, var_name, var_value)
if(length(list_or_datum))
list_or_datum[var_name] = var_value
return
var/datum/D = list_or_datum
D.vars[var_name] = var_value
// Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second
// N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW
/proc/get_adir(var/turf/A, var/turf/B)
@@ -1440,24 +1457,96 @@ var/mob/dview/dview_mob = new
if(337.5)
return "North-Northwest"
//This is used to force compiletime errors if you incorrectly supply variable names. Crafty!
#define NAMEOF(datum, X) (#X || ##datum.##X)
//Creates a callback with the specific purpose of setting a variable
#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, weakref(##datum), NAMEOF(##datum, ##var), ##var_value)
//Helper for the above
/proc/___callbackvarset(list_or_datum, var_name, var_value)
if(isweakref(list_or_datum))
var/weakref/wr = list_or_datum
list_or_datum = wr.resolve()
if(!list_or_datum)
return
if(length(list_or_datum))
list_or_datum[var_name] = var_value
return
var/datum/D = list_or_datum
D.vars[var_name] = var_value
/proc/pass()
return
#define NAMEOF(datum, X) (#X || ##datum.##X)
/proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
if (value == FALSE) //nothing should be calling us with a number, so this is safe
value = input("Enter type to find (blank for all, cancel to cancel)", "Search for type") as null|text
if (isnull(value))
return
value = trim(value)
if(!isnull(value) && value != "")
matches = filter_fancy_list(matches, value)
if(matches.len==0)
return
var/chosen
if(matches.len==1)
chosen = matches[1]
else
chosen = input("Select a type", "Pick Type", matches[1]) as null|anything in matches
if(!chosen)
return
chosen = matches[chosen]
return chosen
/proc/get_fancy_list_of_atom_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(typesof(/atom))
return pre_generated_list
/proc/get_fancy_list_of_datum_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom)))
return pre_generated_list
/proc/filter_fancy_list(list/L, filter as text)
var/list/matches = new
for(var/key in L)
var/value = L[key]
if(findtext("[key]", filter) || findtext("[value]", filter))
matches[key] = value
return matches
/proc/make_types_fancy(var/list/types)
if (ispath(types))
types = list(types)
. = list()
for(var/type in types)
var/typename = "[type]"
var/static/list/TYPES_SHORTCUTS = list(
/obj/effect/decal/cleanable = "CLEANABLE",
/obj/item/device/radio/headset = "HEADSET",
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
/obj/item/weapon/book/manual = "MANUAL",
/obj/item/weapon/reagent_containers/food/drinks = "DRINK",
/obj/item/weapon/reagent_containers/food = "FOOD",
/obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS",
/obj/machinery/atmospherics = "ATMOS_MECH",
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
/obj/item/organ = "ORGAN",
/obj/item = "ITEM",
/obj/machinery = "MACHINERY",
/obj/effect = "EFFECT",
/obj = "O",
/datum = "D",
/turf/simulated/wall = "S-WALL",
/turf/simulated/floor = "S-FLOOR",
/turf/simulated = "SIMULATED",
/turf/unsimulated/wall = "US-WALL",
/turf/unsimulated/floor = "US-FLOOR",
/turf/unsimulated = "UNSIMULATED",
/turf = "T",
/mob/living/carbon = "CARBON",
/mob/living/simple_mob = "SIMPLE",
/mob/living = "LIVING",
/mob = "M"
)
for (var/tn in TYPES_SHORTCUTS)
if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/"))
break
.[typename] = type
/proc/IsValidSrc(datum/D)
if(istype(D))
return !QDELETED(D)
return FALSE

View File

@@ -1,141 +0,0 @@
/*
plot_vector is a helper datum for plotting a path in a straight line towards a target turf.
This datum converts from world space (turf.x and turf.y) to pixel space, which the datum keeps track of itself. This
should work with any size turfs (i.e. 32x32, 64x64) as it references world.icon_size (note: not actually tested with
anything other than 32x32 turfs).
setup()
This should be called after creating a new instance of a plot_vector datum.
This does the initial setup and calculations. Since we are travelling in a straight line we only need to calculate
the vector and x/y steps once. x/y steps are capped to 1 full turf, whichever is further. If we are travelling along
the y axis each step will be +/- 1 y, and the x movement reduced based on the angle (tangent calculation). After
this every subsequent step will be incremented based on these calculations.
Inputs:
source - the turf the object is starting from
target - the target turf the object is travelling towards
xo - starting pixel_x offset, typically won't be needed, but included in case someone has a need for it later
yo - same as xo, but for the y_pixel offset
increment()
Adds the offset to the current location - incrementing it by one step along the vector.
return_angle()
Returns the direction (angle in degrees) the object is travelling in.
(N)
90<39>
^
|
(W) 180<38> <--+--> 0<> (E)
|
v
-90<39>
(S)
return_hypotenuse()
Returns the distance of travel for each step of the vector, relative to each full step of movement. 1 is a full turf
length. Currently used as a multiplier for scaling effects that should be contiguous, like laser beams.
return_location()
Returns a vector_loc datum containing the current location data of the object (see /datum/vector_loc). This includes
the turf it currently should be at, as well as the pixel offset from the centre of that turf. Typically increment()
would be called before this if you are going to move an object based on it's vector data.
*/
/datum/plot_vector
var/turf/source
var/turf/target
var/angle = 0 // direction of travel in degrees
var/loc_x = 0 // in pixels from the left edge of the map
var/loc_y = 0 // in pixels from the bottom edge of the map
var/loc_z = 0 // loc z is in world space coordinates (i.e. z level) - we don't care about measuring pixels for this
var/offset_x = 0 // distance to increment each step
var/offset_y = 0
/datum/plot_vector/proc/setup(var/turf/S, var/turf/T, var/xo = 0, var/yo = 0, var/angle_offset=0)
source = S
target = T
if(!istype(source))
source = get_turf(source)
if(!istype(target))
target = get_turf(target)
if(!istype(source) || !istype(target))
return
// convert coordinates to pixel space (default is 32px/turf, 8160px across for a size 255 map)
loc_x = source.x * world.icon_size + xo
loc_y = source.y * world.icon_size + yo
loc_z = source.z
// calculate initial x and y difference
var/dx = target.x - source.x
var/dy = target.y - source.y
// if we aren't moving anywhere; quit now
if(dx == 0 && dy == 0)
return
// calculate the angle
angle = Atan2(dx, dy) + angle_offset
// and some rounding to stop the increments jumping whole turfs - because byond favours certain angles
if(angle > -135 && angle < 45)
angle = Ceiling(angle)
else
angle = Floor(angle)
// calculate the offset per increment step
if(abs(angle) in list(0, 45, 90, 135, 180)) // check if the angle is a cardinal
if(abs(angle) in list(0, 45, 135, 180)) // if so we can skip the trigonometry and set these to absolutes as
offset_x = sign(dx) // they will always be a full step in one or more directions
if(abs(angle) in list(45, 90, 135))
offset_y = sign(dy)
else if(abs(dy) > abs(dx))
offset_x = Cot(abs(angle)) // otherwise set the offsets
offset_y = sign(dy)
else
offset_x = sign(dx)
offset_y = Tan(angle)
if(dx < 0)
offset_y = -offset_y
// multiply the offset by the turf pixel size
offset_x *= world.icon_size
offset_y *= world.icon_size
/datum/plot_vector/proc/increment()
loc_x += offset_x
loc_y += offset_y
/datum/plot_vector/proc/return_angle()
return angle
/datum/plot_vector/proc/return_hypotenuse()
return sqrt(((offset_x / 32) ** 2) + ((offset_y / 32) ** 2))
/datum/plot_vector/proc/return_location(var/datum/vector_loc/data)
if(!data)
data = new()
data.loc = locate(round(loc_x / world.icon_size, 1), round(loc_y / world.icon_size, 1), loc_z)
if(!data.loc)
return
data.pixel_x = loc_x - (data.loc.x * world.icon_size)
data.pixel_y = loc_y - (data.loc.y * world.icon_size)
return data
/*
vector_loc is a helper datum for returning precise location data from plot_vector. It includes the turf the object is in
as well as the pixel offsets.
return_turf()
Returns the turf the object should be currently located in.
*/
/datum/vector_loc
var/turf/loc
var/pixel_x
var/pixel_y
/datum/vector_loc/proc/return_turf()
return loc

12
code/_helpers/view.dm Normal file
View File

@@ -0,0 +1,12 @@
/proc/getviewsize(view)
var/viewX
var/viewY
if(isnum(view))
var/totalviewrange = 1 + 2 * view
viewX = totalviewrange
viewY = totalviewrange
else
var/list/viewrangelist = splittext(view,"x")
viewX = text2num(viewrangelist[1])
viewY = text2num(viewrangelist[2])
return list(viewX, viewY)

View File

@@ -1,57 +1,7 @@
#define Clamp(x, y, z) (x <= y ? y : (x >= z ? z : x))
#define CLAMP01(x) (Clamp(x, 0, 1))
#define span(class, text) ("<span class='[class]'>[text]</span>")
#define get_turf(A) get_step(A,0)
#define isAI(A) istype(A, /mob/living/silicon/ai)
#define isalien(A) istype(A, /mob/living/carbon/alien)
#define isanimal(A) istype(A, /mob/living/simple_animal)
#define isairlock(A) istype(A, /obj/machinery/door/airlock)
#define isbrain(A) istype(A, /mob/living/carbon/brain)
#define iscarbon(A) istype(A, /mob/living/carbon)
#define iscorgi(A) istype(A, /mob/living/simple_animal/corgi)
#define isEye(A) istype(A, /mob/observer/eye)
#define ishuman(A) istype(A, /mob/living/carbon/human)
#define isliving(A) istype(A, /mob/living)
#define ismouse(A) istype(A, /mob/living/simple_animal/mouse)
#define isnewplayer(A) istype(A, /mob/new_player)
#define isobserver(A) istype(A, /mob/observer/dead)
#define isorgan(A) istype(A, /obj/item/organ/external)
#define ispAI(A) istype(A, /mob/living/silicon/pai)
#define isrobot(A) istype(A, /mob/living/silicon/robot)
#define issilicon(A) istype(A, /mob/living/silicon)
#define isvoice(A) istype(A, /mob/living/voice)
#define isslime(A) istype(A, /mob/living/simple_animal/slime)
#define isbot(A) istype(A, /mob/living/bot)
#define isxeno(A) istype(A, /mob/living/simple_animal/xeno)
#define isopenspace(A) istype(A, /turf/simulated/open)
#define isweakref(A) istype(A, /weakref)
#define RANDOM_BLOOD_TYPE pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
#define to_chat(target, message) target << message
@@ -62,35 +12,12 @@
#define to_file(file_entry, source_var) file_entry << source_var
#define from_file(file_entry, target_var) file_entry >> target_var
// From TG, might be useful to have.
// Didn't port SEND_TEXT() since to_chat() appears to serve the same purpose.
#define DIRECT_OUTPUT(A, B) A << B
#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE)
#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) } ; x = null }
#define QDEL_NULL(x) if(x) { qdel(x) ; x = null }
#define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") }
// Helper macros to aid in optimizing lazy instantiation of lists.
// All of these are null-safe, you can use them without knowing if the list var is initialized yet
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
// Ensures L is initailized after this point
#define LAZYINITLIST(L) if (!L) L = list()
// Sets a L back to null iff it is empty
#define UNSETEMPTY(L) if (L && !L.len) L = null
// Removes I from list L, and sets I to null if it is now empty
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
// Adds I to L, initalizing I if necessary
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
// Reads I from L safely - Works with both associative and traditional lists.
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
// Reads the length of L, returning 0 if null
#define LAZYLEN(L) length(L)
// Null-safe L.Cut()
#define LAZYCLEARLIST(L) if(L) L.Cut()
// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression.
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
// Turns LAZYINITLIST(L) L[K] = V into ... for associated lists
#define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V;

View File

@@ -76,7 +76,7 @@
if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled
return
var/obj/mecha/M = loc
return M.click_action(A, src)
return M.click_action(A, src, params)
if(restrained())
setClickCooldown(10)
@@ -282,10 +282,10 @@
Laser Eyes: as the name implies, handles this since nothing else does currently
face_atom: turns the mob towards what you clicked on
*/
/mob/proc/LaserEyes(atom/A)
/mob/proc/LaserEyes(atom/A, params)
return
/mob/living/LaserEyes(atom/A)
/mob/living/LaserEyes(atom/A, params)
setClickCooldown(4)
var/turf/T = get_turf(src)
@@ -293,8 +293,11 @@
LE.icon = 'icons/effects/genetics.dmi'
LE.icon_state = "eyelasers"
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
LE.launch(A)
/mob/living/carbon/human/LaserEyes()
LE.firer = src
LE.preparePixelProjectile(A, src, params)
LE.fire()
/mob/living/carbon/human/LaserEyes(atom/A, params)
if(nutrition>0)
..()
nutrition = max(nutrition - rand(1,5),0)

View File

@@ -82,7 +82,7 @@
/datum/action/proc/Deactivate()
return
/datum/action/proc/Process()
/datum/action/process()
return
/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed

View File

@@ -98,7 +98,7 @@
/obj/screen/fullscreen/flash
icon = 'icons/mob/screen1.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "flash"
icon_state = "flash_static"
/obj/screen/fullscreen/flash/noise
icon_state = "noise"

View File

@@ -316,8 +316,6 @@ datum/hud/New(mob/owner)
mymob.instantiate_hud(src)
else if(isalien(mymob))
larva_hud()
else if(isslime(mymob))
slime_hud()
else if(isAI(mymob))
ai_hud()
else if(isobserver(mymob))

View File

@@ -23,7 +23,7 @@
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
mymob.client.screen += mymob.client.void
/*
/datum/hud/proc/slime_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
src.adding = list()
@@ -92,23 +92,20 @@
mymob.client.screen += mymob.client.void
return
/mob/living/simple_animal/construct/instantiate_hud(var/datum/hud/HUD)
..(HUD)
*/
// HUD.construct_hud() //Archaic.
/*
/datum/hud/proc/construct_hud()
var/constructtype
if(istype(mymob,/mob/living/simple_animal/construct/armoured) || istype(mymob,/mob/living/simple_animal/construct/behemoth))
if(istype(mymob,/mob/living/simple_mob/construct/armoured) || istype(mymob,/mob/living/simple_mob/construct/behemoth))
constructtype = "juggernaut"
else if(istype(mymob,/mob/living/simple_animal/construct/builder))
else if(istype(mymob,/mob/living/simple_mob/construct/builder))
constructtype = "artificer"
else if(istype(mymob,/mob/living/simple_animal/construct/wraith))
else if(istype(mymob,/mob/living/simple_mob/construct/wraith))
constructtype = "wraith"
else if(istype(mymob,/mob/living/simple_animal/construct/harvester))
else if(istype(mymob,/mob/living/simple_mob/construct/harvester))
constructtype = "harvester"
if(constructtype)

View File

@@ -1,15 +1,15 @@
/obj/screen/proc/Click_vr(location, control, params)
/obj/screen/proc/Click_vr(location, control, params) //VORESTATION AI TEMPORARY REMOVAL
if(!usr) return 1
switch(name)
//Shadekin
if("darkness")
var/mob/living/simple_animal/shadekin/sk = usr
var/mob/living/simple_mob/shadekin/sk = usr
var/turf/T = get_turf(sk)
var/darkness = round(1 - T.get_lumcount(),0.1)
to_chat(usr,"<span class='notice'><b>Darkness:</b> [darkness]</span>")
if("energy")
var/mob/living/simple_animal/shadekin/sk = usr
var/mob/living/simple_mob/shadekin/sk = usr
to_chat(usr,"<span class='notice'><b>Energy:</b> [sk.energy] ([sk.dark_gains])</span>")

View File

@@ -60,7 +60,7 @@ avoid code duplication. This includes items that may sometimes act as a standard
// Same as above but actually does useful things.
// W is the item being used in the attack, if any. modifier is if the attack should be longer or shorter than usual, for whatever reason.
/mob/living/get_attack_speed(var/obj/item/W)
var/speed = DEFAULT_ATTACK_COOLDOWN
var/speed = base_attack_cooldown
if(W && istype(W))
speed = W.attackspeed
for(var/datum/modifier/M in modifiers)

View File

@@ -68,58 +68,3 @@
*/
/mob/new_player/ClickOn()
return
/*
Animals
*/
/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity)
if(!(. = ..()))
return
setClickCooldown(get_attack_speed())
if(has_hands && istype(A,/obj) && a_intent != I_HURT)
var/obj/O = A
return O.attack_hand(src)
switch(a_intent)
if(I_HELP)
if(isliving(A))
custom_emote(1,"[pick(friendly)] [A]!")
if(I_HURT)
if(prob(spattack_prob))
if(spattack_min_range <= 1)
SpecialAtkTarget()
else if(melee_damage_upper == 0 && istype(A,/mob/living))
custom_emote(1,"[pick(friendly)] [A]!")
else
DoPunch(A)
if(I_GRAB)
if(has_hands)
A.attack_hand(src)
if(I_DISARM)
if(has_hands)
A.attack_hand(src)
/mob/living/simple_animal/RangedAttack(var/atom/A)
setClickCooldown(get_attack_speed())
var/distance = get_dist(src, A)
if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range))
target_mob = A
SpecialAtkTarget()
target_mob = null
return
if(ranged && distance <= shoot_range)
target_mob = A
ShootTarget(A)
target_mob = null

View File

@@ -155,7 +155,7 @@
/datum/controller/process/proc/setup()
/datum/controller/process/proc/process()
/datum/controller/process/process()
started()
doWork()
finished()

View File

@@ -70,7 +70,7 @@ var/global/datum/controller/processScheduler/processScheduler
spawn(0)
process()
/datum/controller/processScheduler/proc/process()
/datum/controller/processScheduler/process()
while(isRunning)
checkRunningProcesses()
queueProcesses()

View File

@@ -1,23 +0,0 @@
/datum/controller/process/air/setup()
name = "air"
schedule_interval = 20 // every 2 seconds
start_delay = 4
if(!air_master)
air_master = new
air_master.Setup()
/datum/controller/process/air/doWork()
if(!air_processing_killed)
if(!air_master.Tick()) //Runtimed.
air_master.failed_ticks++
if(air_master.failed_ticks > 5)
world << "<SPAN CLASS='danger'>RUNTIMES IN ATMOS TICKER. Killing air simulation!</SPAN>"
world.log << "### ZAS SHUTDOWN"
message_admins("ZASALERT: Shutting down! status: [air_master.tick_progress]")
log_admin("ZASALERT: Shutting down! status: [air_master.tick_progress]")
air_processing_killed = TRUE
air_master.failed_ticks = 0

View File

@@ -11,7 +11,7 @@
var/datum/controller/process/alarm/alarm_manager
/datum/controller/process/alarm
var/list/datum/alarm/all_handlers
var/list/datum/alarm/all_handlers = list()
/datum/controller/process/alarm/setup()
name = "alarm"

View File

@@ -1,33 +0,0 @@
var/datum/controller/process/chemistry/chemistryProcess
/datum/controller/process/chemistry
var/list/active_holders
var/list/chemical_reactions
var/list/chemical_reagents
/datum/controller/process/chemistry/setup()
name = "chemistry"
schedule_interval = 20 // every 2 seconds
chemistryProcess = src
active_holders = list()
chemical_reactions = chemical_reactions_list
chemical_reagents = chemical_reagents_list
/datum/controller/process/chemistry/statProcess()
..()
stat(null, "[active_holders.len] reagent holder\s")
/datum/controller/process/chemistry/doWork()
for(last_object in active_holders)
var/datum/reagents/holder = last_object
if(!holder.process_reactions())
active_holders -= holder
SCHECK
/datum/controller/process/chemistry/proc/mark_for_update(var/datum/reagents/holder)
if(holder in active_holders)
return
//Process once, right away. If we still need to continue then add to the active_holders list and continue later
if(holder.process_reactions())
active_holders += holder

View File

@@ -1,6 +0,0 @@
/datum/controller/process/event/setup()
name = "event controller"
schedule_interval = 20 // every 2 seconds
/datum/controller/process/event/doWork()
event_manager.process()

View File

@@ -1,19 +0,0 @@
/datum/controller/process/nanoui/setup()
name = "nanoui"
schedule_interval = 20 // every 2 seconds
/datum/controller/process/nanoui/statProcess()
..()
stat(null, "[GLOB.nanomanager.processing_uis.len] UIs")
/datum/controller/process/nanoui/doWork()
for(last_object in GLOB.nanomanager.processing_uis)
var/datum/nanoui/NUI = last_object
if(istype(NUI) && !QDELETED(NUI))
try
NUI.process()
catch(var/exception/e)
catchException(e, NUI)
else
catchBadType(NUI)
GLOB.nanomanager.processing_uis -= NUI

View File

@@ -1,26 +0,0 @@
/datum/controller/process/obj/setup()
name = "obj"
schedule_interval = 20 // every 2 seconds
start_delay = 8
/datum/controller/process/obj/started()
..()
if(!processing_objects)
processing_objects = list()
/datum/controller/process/obj/doWork()
for(last_object in processing_objects)
var/datum/O = last_object
if(!QDELETED(O))
try
O:process()
catch(var/exception/e)
catchException(e, O)
SCHECK
else
catchBadType(O)
processing_objects -= O
/datum/controller/process/obj/statProcess()
..()
stat(null, "[processing_objects.len] objects")

View File

@@ -40,7 +40,7 @@
// We are being killed. Least we can do is deregister all those events we registered
/datum/controller/process/scheduler/onKill()
for(var/st in scheduled_tasks)
destroyed_event.unregister(st, src)
GLOB.destroyed_event.unregister(st, src)
/datum/controller/process/scheduler/statProcess()
..()
@@ -148,7 +148,7 @@
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
src.source = source
destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
GLOB.destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
/datum/scheduled_task/source/Destroy()

View File

@@ -1,7 +0,0 @@
/datum/controller/process/sun/setup()
name = "sun"
schedule_interval = 20 // every second
sun = new
/datum/controller/process/sun/doWork()
sun.calc_position()

View File

@@ -65,7 +65,7 @@ var/datum/controller/supply/supply_controller = new()
// Supply shuttle ticker - handles supply point regeneration
// This is called by the process scheduler every thirty seconds
/datum/controller/supply/proc/process()
/datum/controller/supply/process()
points += points_per_process
//To stop things being sent to CentCom which should not be sent to centcomm. Recursively checks for these types.

View File

@@ -1,16 +0,0 @@
var/global/list/turf/processing_turfs = list()
/datum/controller/process/turf/setup()
name = "turf"
schedule_interval = 20 // every 2 seconds
/datum/controller/process/turf/doWork()
for(last_object in processing_turfs)
var/turf/T = last_object
if(T.process() == PROCESS_KILL)
processing_turfs.Remove(T)
SCHECK
/datum/controller/process/turf/statProcess()
..()
stat(null, "[processing_turfs.len] turf\s")

View File

@@ -9,12 +9,12 @@ datum/controller/transfer_controller/New()
timerbuffer = config.vote_autotransfer_initial
shift_hard_end = config.vote_autotransfer_initial + (config.vote_autotransfer_interval * 1) //VOREStation Edit //Change this "1" to how many extend votes you want there to be.
shift_last_vote = shift_hard_end - config.vote_autotransfer_interval //VOREStation Edit
processing_objects += src
START_PROCESSING(SSobj, src)
datum/controller/transfer_controller/Destroy()
processing_objects -= src
STOP_PROCESSING(SSobj, src)
datum/controller/transfer_controller/proc/process()
datum/controller/transfer_controller/process()
currenttick = currenttick + 1
//VOREStation Edit START
if (round_duration_in_ticks >= shift_last_vote - 2 MINUTES)

View File

@@ -220,7 +220,7 @@ var/list/gamemode_cache = list()
var/aggressive_changelog = 0
var/list/language_prefixes = list(",","#","-")//Default language prefixes
var/list/language_prefixes = list(",","#")//Default language prefixes
var/show_human_death_message = 1
@@ -228,6 +228,8 @@ var/list/gamemode_cache = list()
var/radiation_resistance_multiplier = 8.5 //VOREstation edit
var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
var/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated.
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -748,6 +750,9 @@ var/list/gamemode_cache = list()
if ("paranoia_logging")
config.paranoia_logging = 1
if("random_submap_orientation")
config.random_submap_orientation = 1
else
log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -26,7 +26,7 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
escape_pods = list()
..()
/datum/emergency_shuttle_controller/proc/process()
/datum/emergency_shuttle_controller/process()
if (wait_for_launch)
if (evac && auto_recall && world.time >= auto_recall_time)
recall()

View File

@@ -38,8 +38,10 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
stat("Globals:", statclick.update("Edit"))
/datum/controller/global_vars/VV_hidden()
return ..() + gvars_datum_protected_varlist
/datum/controller/global_vars/vv_edit_var(var_name, var_value)
if(gvars_datum_protected_varlist[var_name])
return FALSE
return ..()
/datum/controller/global_vars/Initialize(var/exclude_these)
gvars_datum_init_order = list()

View File

@@ -13,14 +13,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
//THIS IS THE INIT ORDER
//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe
//GOT IT MEMORIZED?
GLOBAL_VAR_INIT(MC_restart_clear, 0)
GLOBAL_VAR_INIT(MC_restart_timeout, 0)
GLOBAL_VAR_INIT(MC_restart_count, 0)
//current tick limit, assigned by the queue controller before running a subsystem.
//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
/datum/controller/master
name = "Master"
@@ -62,6 +54,10 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
var/static/restart_timeout = 0
var/static/restart_count = 0
//current tick limit, assigned by the queue controller before running a subsystem.
//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
var/static/current_ticklimit
/datum/controller/master/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
var/list/_subsystems = list()
@@ -98,14 +94,14 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// -1 if we encountered a runtime trying to recreate it
/proc/Recreate_MC()
. = -1 //so if we runtime, things know we failed
if (world.time < GLOB.MC_restart_timeout)
if (world.time < Master.restart_timeout)
return 0
if (world.time < GLOB.MC_restart_clear)
GLOB.MC_restart_count *= 0.5
if (world.time < Master.restart_clear)
Master.restart_count *= 0.5
var/delay = 50 * ++GLOB.MC_restart_count
GLOB.MC_restart_timeout = world.time + delay
GLOB.MC_restart_clear = world.time + (delay * 2)
var/delay = 50 * ++Master.restart_count
Master.restart_timeout = world.time + delay
Master.restart_clear = world.time + (delay * 2)
Master.processing = FALSE //stop ticking this one
try
new/datum/controller/master()
@@ -176,13 +172,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
var/start_timeofday = REALTIMEOFDAY
// Initialize subsystems.
GLOB.CURRENT_TICKLIMIT = config.tick_limit_mc_init
current_ticklimit = config.tick_limit_mc_init
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_NO_INIT)
continue
SS.Initialize(REALTIMEOFDAY)
CHECK_TICK
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
@@ -291,7 +287,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
var/starting_tick_usage = TICK_USAGE
if (processing <= 0)
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
@@ -300,7 +296,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// (because sleeps are processed in the order received, longer sleeps are more likely to run first)
if (starting_tick_usage > TICK_LIMIT_MC) //if there isn't enough time to bother doing anything this tick, sleep a bit.
sleep_delta *= 2
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
sleep(world.tick_lag * (processing * sleep_delta))
continue
@@ -346,7 +342,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if (!error_level)
iteration++
error_level++
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
@@ -358,7 +354,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
if (!error_level)
iteration++
error_level++
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
error_level--
@@ -369,9 +365,9 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
iteration++
last_run = world.time
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
current_ticklimit = TICK_LIMIT_RUNNING
if (processing * sleep_delta <= world.tick_lag)
GLOB.CURRENT_TICKLIMIT -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick
current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick
sleep(world.tick_lag * (processing * sleep_delta))
@@ -463,7 +459,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// Reduce tick allocation for subsystems that overran on their last tick.
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
GLOB.CURRENT_TICKLIMIT = round(TICK_USAGE + tick_precentage)
current_ticklimit = round(TICK_USAGE + tick_precentage)
if (!(queue_node_flags & SS_TICKER))
ran_non_ticker = TRUE

View File

@@ -6,6 +6,7 @@
var/priority = FIRE_PRIORITY_DEFAULT //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep
var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again)
var/subsystem_initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize
var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
//set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
@@ -154,6 +155,7 @@
//used to initialize the subsystem AFTER the map has loaded
/datum/controller/subsystem/Initialize(start_timeofday)
subsystem_initialized = TRUE
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, "<span class='boldannounce'>[msg]</span>")

View File

@@ -0,0 +1,36 @@
SUBSYSTEM_DEF(ai)
name = "AI"
init_order = INIT_ORDER_AI
priority = FIRE_PRIORITY_AI
wait = 5 // This gets run twice a second, however this is technically two loops in one, with the second loop being run every four iterations.
flags = SS_NO_INIT|SS_TICKER
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/processing = list()
var/list/currentrun = list()
/datum/controller/subsystem/ai/stat_entry(msg_prefix)
var/list/msg = list(msg_prefix)
msg += "P:[processing.len]"
..(msg.Join())
/datum/controller/subsystem/ai/fire(resumed = 0)
if (!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
// var/mob/living/L = currentrun[currentrun.len]
var/datum/ai_holder/A = currentrun[currentrun.len]
--currentrun.len
if(!A || QDELETED(A)) // Doesn't exist or won't exist soon.
continue
if(times_fired % 4 == 0 && A.holder.stat != DEAD)
A.handle_strategicals()
if(A.holder.stat != DEAD) // The /TG/ version checks stat twice, presumably in-case processing somehow got the mob killed in that instant.
A.handle_tactics()
if(MC_TICK_CHECK)
return

View File

@@ -77,7 +77,7 @@ SUBSYSTEM_DEF(atoms)
var/start_tick = world.time
var/result = A.initialize(arglist(arguments))
var/result = A.Initialize(arglist(arguments))
if(start_tick != world.time)
BadInitializeCalls[the_type] |= BAD_INIT_SLEPT

View File

@@ -1,29 +0,0 @@
//
// Creation subsystem, which is responsible for initializing newly created objects.
//
SUBSYSTEM_DEF(creation)
name = "Creation"
priority = 14
wait = 5
// flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
flags = SS_NO_FIRE|SS_NO_INIT
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/list/atoms_needing_initialize = list()
var/map_loading = FALSE
/datum/controller/subsystem/creation/StartLoadingMap(var/quiet)
map_loading = TRUE
/datum/controller/subsystem/creation/StopLoadingMap(var/quiet)
map_loading = FALSE
/datum/controller/subsystem/creation/proc/initialize_late_atoms()
admin_notice("<span class='danger'>Initializing atoms in submap.</span>", R_DEBUG)
var/total_atoms = atoms_needing_initialize.len
for(var/atom/movable/A in atoms_needing_initialize)
if(!QDELETED(A))
A.initialize()
atoms_needing_initialize -= A
admin_notice("<span class='danger'>Initalized [total_atoms] atoms in submap.</span>", R_DEBUG)

View File

@@ -0,0 +1,72 @@
SUBSYSTEM_DEF(events)
name = "Events"
wait = 20
var/list/datum/event/active_events = list()
var/list/datum/event/finished_events = list()
var/list/datum/event/allEvents
var/list/datum/event_container/event_containers
var/datum/event_meta/new_event = new
/datum/controller/subsystem/events/Initialize()
event_containers = list(
EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane,
EVENT_LEVEL_MODERATE = new/datum/event_container/moderate,
EVENT_LEVEL_MAJOR = new/datum/event_container/major
)
allEvents = typesof(/datum/event) - /datum/event
return ..()
/datum/controller/subsystem/events/fire(resumed)
for(var/datum/event/E in active_events)
E.process()
for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR)
var/list/datum/event_container/EC = event_containers[i]
EC.process()
/datum/controller/subsystem/events/Recover()
if(SSevents.active_events)
active_events |= SSevents.active_events
if(SSevents.finished_events)
finished_events |= SSevents.finished_events
/datum/controller/subsystem/events/proc/event_complete(var/datum/event/E)
if(!E.event_meta || !E.severity) // datum/event is used here and there for random reasons, maintaining "backwards compatibility"
log_debug("Event of '[E.type]' with missing meta-data has completed.")
return
finished_events += E
// Add the event back to the list of available events
var/datum/event_container/EC = event_containers[E.severity]
var/datum/event_meta/EM = E.event_meta
if(EM.add_to_queue)
EC.available_events += EM
log_debug("Event '[EM.name]' has completed at [worldtime2stationtime(world.time)].")
/datum/controller/subsystem/events/proc/delay_events(var/severity, var/delay)
var/list/datum/event_container/EC = event_containers[severity]
EC.next_event_time += delay
/datum/controller/subsystem/events/proc/RoundEnd()
if(!report_at_round_end)
return
to_chat(world, "<br><br><br><font size=3><b>Random Events This Round:</b></font>")
for(var/datum/event/E in active_events|finished_events)
var/datum/event_meta/EM = E.event_meta
if(EM.name == "Nothing")
continue
var/message = "'[EM.name]' began at [worldtime2stationtime(E.startedAt)] "
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
message += "and ended at [worldtime2stationtime(E.endedAt)]."
else
message += "and ran to completion."
to_chat(world, message)

View File

@@ -1,11 +1,12 @@
/datum/controller/process/inactivity/setup()
name = "inactivity"
schedule_interval = 600 // Once every minute (approx.)
SUBSYSTEM_DEF(inactivity)
name = "AFK Kick"
wait = 600
flags = SS_BACKGROUND | SS_NO_TICK_CHECK
/datum/controller/process/inactivity/doWork()
/datum/controller/subsystem/inactivity/fire()
if(config.kick_inactive)
for(last_object in clients)
var/client/C = last_object
for(var/i in GLOB.clients)
var/client/C = i
if(C.is_afk(config.kick_inactive MINUTES) && !C.holder) // VOREStation Edit - Allow admins to idle
to_chat(C,"<span class='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</span>")
var/information
@@ -33,4 +34,3 @@
log_and_message_admins("being kicked for AFK[information][adminlinks]", C.mob)
qdel(C)
SCHECK

View File

@@ -109,7 +109,7 @@ SUBSYSTEM_DEF(machines)
else
global.pipe_networks.Remove(PN)
if(!QDELETED(PN))
PN.is_processing = null
DISABLE_BITFIELD(PN.datum_flags, DF_ISPROCESSING)
if(MC_TICK_CHECK)
return
@@ -127,7 +127,7 @@ SUBSYSTEM_DEF(machines)
else
global.processing_machines.Remove(M)
if(!QDELETED(M))
M.is_processing = null
DISABLE_BITFIELD(M.datum_flags, DF_ISPROCESSING)
if(MC_TICK_CHECK)
return
@@ -144,7 +144,7 @@ SUBSYSTEM_DEF(machines)
else
global.powernets.Remove(PN)
if(!QDELETED(PN))
PN.is_processing = null
DISABLE_BITFIELD(PN.datum_flags, DF_ISPROCESSING)
if(MC_TICK_CHECK)
return
@@ -160,7 +160,7 @@ SUBSYSTEM_DEF(machines)
current_run.len--
if(!I.pwr_drain(wait)) // 0 = Process Kill, remove from processing list.
global.processing_power_items.Remove(I)
I.is_processing = null
DISABLE_BITFIELD(I.datum_flags, DF_ISPROCESSING)
if(MC_TICK_CHECK)
return

View File

@@ -0,0 +1,30 @@
// Handles map-related tasks, mostly here to ensure it does so after the MC initializes.
SUBSYSTEM_DEF(mapping)
name = "Mapping"
init_order = INIT_ORDER_MAPPING
flags = SS_NO_FIRE
var/list/map_templates = list()
var/dmm_suite/maploader = null
/datum/controller/subsystem/mapping/Initialize(timeofday)
if(subsystem_initialized)
return
world.max_z_changed() // This is to set up the player z-level list, maxz hasn't actually changed (probably)
maploader = new()
load_map_templates()
if(config.generate_map)
// Map-gen is still very specific to the map, however putting it here should ensure it loads in the correct order.
if(using_map.perform_map_generation())
using_map.refresh_mining_turfs()
/datum/controller/subsystem/mapping/proc/load_map_templates()
for(var/T in subtypesof(/datum/map_template))
var/datum/map_template/template = T
if(!(initial(template.mappath))) // If it's missing the actual path its probably a base type or being used for inheritence.
continue
template = new T()
map_templates[template.name] = template
return TRUE

View File

@@ -7,8 +7,9 @@ SUBSYSTEM_DEF(mapping)
init_order = INIT_ORDER_MAPPING
flags = SS_NO_FIRE
var/list/map_templates = list()
var/dmm_suite/maploader = null
var/obj/effect/landmark/engine_loader/engine_loader
var/list/shelter_templates = list()
/datum/controller/subsystem/mapping/Recover()
@@ -16,6 +17,17 @@ SUBSYSTEM_DEF(mapping)
shelter_templates = SSmapping.shelter_templates
/datum/controller/subsystem/mapping/Initialize(timeofday)
if(subsystem_initialized)
return
world.max_z_changed() // This is to set up the player z-level list, maxz hasn't actually changed (probably)
maploader = new()
load_map_templates()
if(config.generate_map)
// Map-gen is still very specific to the map, however putting it here should ensure it loads in the correct order.
if(using_map.perform_map_generation())
using_map.refresh_mining_turfs()
loadEngine()
preloadShelterTemplates()
// Mining generation probably should be here too
@@ -24,6 +36,15 @@ SUBSYSTEM_DEF(mapping)
loadLateMaps()
..()
/datum/controller/subsystem/mapping/proc/load_map_templates()
for(var/T in subtypesof(/datum/map_template))
var/datum/map_template/template = T
if(!(initial(template.mappath))) // If it's missing the actual path its probably a base type or being used for inheritence.
continue
template = new T()
map_templates[template.name] = template
return TRUE
/datum/controller/subsystem/mapping/proc/loadEngine()
if(!engine_loader)
return // Seems this map doesn't need an engine loaded.

View File

@@ -0,0 +1,42 @@
SUBSYSTEM_DEF(nanoui)
name = "NanoUI"
wait = 20
// a list of current open /nanoui UIs, grouped by src_object and ui_key
var/list/open_uis = list()
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/datum/controller/subsystem/nanoui/Initialize()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return ..()
/datum/controller/subsystem/nanoui/Recover()
if(SSnanoui.open_uis)
open_uis |= SSnanoui.open_uis
if(SSnanoui.processing_uis)
processing_uis |= SSnanoui.processing_uis
if(SSnanoui.asset_files)
asset_files |= SSnanoui.asset_files
/datum/controller/subsystem/nanoui/stat_entry()
return ..("[processing_uis.len] UIs")
/datum/controller/subsystem/nanoui/fire(resumed)
for(var/thing in processing_uis)
var/datum/nanoui/UI = thing
UI.process()

View File

@@ -0,0 +1,43 @@
PROCESSING_SUBSYSTEM_DEF(chemistry)
name = "Chemistry"
wait = 20
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING
init_order = INIT_ORDER_CHEMISTRY
var/list/chemical_reactions = list()
var/list/chemical_reagents = list()
/datum/controller/subsystem/processing/chemistry/Recover()
chemical_reactions = SSchemistry.chemical_reactions
chemical_reagents = SSchemistry.chemical_reagents
/datum/controller/subsystem/processing/chemistry/Initialize()
initialize_chemical_reactions()
initialize_chemical_reagents()
//Chemical Reactions - Initialises all /datum/chemical_reaction into a list
// It is filtered into multiple lists within a list.
// For example:
// chemical_reaction_list["phoron"] is a list of all reactions relating to phoron
// Note that entries in the list are NOT duplicated. So if a reaction pertains to
// more than one chemical it will still only appear in only one of the sublists.
/datum/controller/subsystem/processing/chemistry/proc/initialize_chemical_reactions()
var/paths = typesof(/datum/chemical_reaction) - /datum/chemical_reaction
SSchemistry.chemical_reactions = list()
for(var/path in paths)
var/datum/chemical_reaction/D = new path()
if(D.required_reagents && D.required_reagents.len)
var/reagent_id = D.required_reagents[1]
if(!chemical_reactions[reagent_id])
chemical_reactions[reagent_id] = list()
chemical_reactions[reagent_id] += D
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
/datum/controller/subsystem/processing/chemistry/proc/initialize_chemical_reagents()
var/paths = typesof(/datum/reagent) - /datum/reagent
chemical_reagents = list()
for(var/path in paths)
var/datum/reagent/D = new path()
if(!D.name)
continue
chemical_reagents[D.id] = D

View File

@@ -0,0 +1,6 @@
//Fires five times every second.
PROCESSING_SUBSYSTEM_DEF(fastprocess)
name = "Fast Processing"
wait = 2
stat_tag = "FP"

View File

@@ -0,0 +1,5 @@
PROCESSING_SUBSYSTEM_DEF(obj)
name = "Objects"
priority = FIRE_PRIORITY_OBJ
flags = SS_NO_INIT
wait = 20

View File

@@ -0,0 +1,35 @@
//Used to process objects. Fires once every second.
SUBSYSTEM_DEF(processing)
name = "Processing"
priority = FIRE_PRIORITY_PROCESS
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
wait = 10
var/stat_tag = "P" //Used for logging
var/list/processing = list()
var/list/currentrun = list()
/datum/controller/subsystem/processing/stat_entry()
..("[stat_tag]:[processing.len]")
/datum/controller/subsystem/processing/fire(resumed = 0)
if (!resumed)
currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/current_run = currentrun
while(current_run.len)
var/datum/thing = current_run[current_run.len]
current_run.len--
if(QDELETED(thing))
processing -= thing
else if(thing.process(wait) == PROCESS_KILL)
// fully stop so that a future START_PROCESSING will work
STOP_PROCESSING(src, thing)
if (MC_TICK_CHECK)
return
/datum/proc/process()
set waitfor = 0
return PROCESS_KILL

View File

@@ -0,0 +1,16 @@
PROCESSING_SUBSYSTEM_DEF(projectiles)
name = "Projectiles"
wait = 1
stat_tag = "PP"
priority = FIRE_PRIORITY_PROJECTILES
flags = SS_NO_INIT|SS_TICKER
var/global_max_tick_moves = 10
var/global_pixel_speed = 2
var/global_iterations_per_move = 16
/datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed)
global_pixel_speed = new_speed
for(var/i in processing)
var/obj/item/projectile/P = i
if(istype(P)) //there's non projectiles on this too.
P.set_pixel_speed(new_speed)

View File

@@ -0,0 +1,3 @@
PROCESSING_SUBSYSTEM_DEF(turfs)
name = "Turf Processing"
wait = 20

View File

@@ -0,0 +1,7 @@
SUBSYSTEM_DEF(sun)
name = "Sun"
wait = 600
var/static/datum/sun/sun = new
/datum/controller/subsystem/sun/fire()
sun.calc_position()

Some files were not shown because too many files have changed in this diff Show More