Merge branch 'master' of https://github.com/Yawn-Wider/YWPolarisVore into May2020UpstreamPull

This commit is contained in:
Razgriz
2020-05-06 22:36:01 -07:00
756 changed files with 362568 additions and 116045 deletions

View File

@@ -468,6 +468,10 @@
return "REGULAR"
if(PIPING_LAYER_SCRUBBER)
return "SCRUBBER"
if(PIPING_LAYER_FUEL)
return "FUEL"
if(PIPING_LAYER_AUX)
return "AUX"
/proc/atmos_pipe_flags_str(pipe_flags)
var/list/dat = list()
@@ -489,6 +493,10 @@
dat += "SUPPLY"
if(connect_types & CONNECT_TYPE_SCRUBBER)
dat += "SCRUBBER"
if(connect_types & CONNECT_TYPE_FUEL)
dat += "FUEL"
if(connect_types & CONNECT_TYPE_AUX)
dat += "AUX"
if(connect_types & CONNECT_TYPE_HE)
dat += "HE"
return dat.Join("|")

View File

@@ -209,8 +209,18 @@ Pipelines + Other Objects -> Pipe network
connect_types = CONNECT_TYPE_SUPPLY
layer = PIPES_SUPPLY_LAYER
icon_connect_type = "-supply"
if(PIPING_LAYER_FUEL)
icon_state = "[icon_state]-fuel"
connect_types = CONNECT_TYPE_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
if(PIPING_LAYER_AUX)
icon_state = "[icon_state]-aux"
connect_types = CONNECT_TYPE_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
if(pipe_flags & PIPING_ALL_LAYER)
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
// Or if we were to do it the TG way...
// pixel_x = PIPE_PIXEL_OFFSET_X(piping_layer)
// pixel_y = PIPE_PIXEL_OFFSET_Y(piping_layer)

View File

@@ -6,8 +6,8 @@
/obj/machinery/atmospherics/binary/circulator
name = "circulator"
desc = "A gas circulator turbine and heat exchanger."
icon = 'icons/obj/pipes.dmi'
icon_state = "circ-off"
icon = 'icons/obj/power.dmi'
icon_state = "circ-unassembled"
anchored = 0
pipe_flags = PIPING_DEFAULT_LAYER_ONLY|PIPING_ONE_PER_TURF
@@ -22,6 +22,7 @@
var/last_stored_energy_transferred = 0
var/volume_capacity_used = 0
var/stored_energy = 0
var/temperature_overlay
density = 1
@@ -76,15 +77,19 @@
update_icon()
/obj/machinery/atmospherics/binary/circulator/update_icon()
if(stat & (BROKEN|NOPOWER) || !anchored)
icon_state = "circ-p"
else if(last_pressure_delta > 0 && recent_moles_transferred > 0)
if(last_pressure_delta > 5*ONE_ATMOSPHERE)
icon_state = "circ-run"
icon_state = anchored ? "circ-assembled" : "circ-unassembled"
cut_overlays()
if (stat & (BROKEN|NOPOWER) || !anchored)
return 1
if (last_pressure_delta > 0 && recent_moles_transferred > 0)
if (temperature_overlay)
add_overlay(temperature_overlay)
if (last_pressure_delta > 5*ONE_ATMOSPHERE)
add_overlay("circ-run")
else
icon_state = "circ-slow"
add_overlay("circ-slow")
else
icon_state = "circ-off"
add_overlay("circ-off")
return 1
@@ -97,6 +102,7 @@
"You hear a ratchet.")
if(anchored)
temperature_overlay = null
if(dir & (NORTH|SOUTH))
initialize_directions = NORTH|SOUTH
else if(dir & (EAST|WEST))

View File

@@ -176,7 +176,7 @@
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(

View File

@@ -151,7 +151,7 @@
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(

View File

@@ -18,6 +18,7 @@ Thus, the two variables affect pump operation are set in New():
construction_type = /obj/item/pipe/directional
pipe_state = "pump"
level = 1
var/base_icon = "pump"
name = "gas pump"
desc = "A pump that moves gas from one place to another."
@@ -49,12 +50,31 @@ Thus, the two variables affect pump operation are set in New():
icon_state = "map_on"
use_power = USE_POWER_IDLE
/obj/machinery/atmospherics/binary/pump/fuel
icon_state = "map_off-fuel"
base_icon = "pump-fuel"
icon_connect_type = "-fuel"
connect_types = CONNECT_TYPE_FUEL
/obj/machinery/atmospherics/binary/pump/fuel/on
icon_state = "map_on-fuel"
use_power = USE_POWER_IDLE
/obj/machinery/atmospherics/binary/pump/aux
icon_state = "map_off-aux"
base_icon = "pump-aux"
icon_connect_type = "-aux"
connect_types = CONNECT_TYPE_AUX
/obj/machinery/atmospherics/binary/pump/aux/on
icon_state = "map_on-aux"
use_power = USE_POWER_IDLE
/obj/machinery/atmospherics/binary/pump/update_icon()
if(!powered())
icon_state = "off"
icon_state = "[base_icon]-off"
else
icon_state = "[use_power ? "on" : "off"]"
icon_state = "[use_power ? "[base_icon]-on" : "[base_icon]-off"]"
/obj/machinery/atmospherics/binary/pump/update_underlays()
if(..())
@@ -62,8 +82,8 @@ Thus, the two variables affect pump operation are set in New():
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
add_underlay(T, node2, dir)
add_underlay(T, node1, turn(dir, -180), node1?.icon_connect_type)
add_underlay(T, node2, dir, node2?.icon_connect_type)
/obj/machinery/atmospherics/binary/pump/hide(var/i)
update_underlays()
@@ -108,7 +128,7 @@ Thus, the two variables affect pump operation are set in New():
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(

View File

@@ -21,6 +21,20 @@
use_power = USE_POWER_OFF
level = 1
/obj/machinery/atmospherics/portables_connector/fuel
icon_state = "map_connector-fuel"
pipe_state = "connector-fuel"
icon_connect_type = "-fuel"
pipe_flags = PIPING_ONE_PER_TURF
connect_types = CONNECT_TYPE_FUEL
/obj/machinery/atmospherics/portables_connector/aux
icon_state = "map_connector-aux"
pipe_state = "connector-aux"
icon_connect_type = "-aux"
pipe_flags = PIPING_ONE_PER_TURF
connect_types = CONNECT_TYPE_AUX
/obj/machinery/atmospherics/portables_connector/init_dir()
initialize_directions = dir
@@ -33,7 +47,7 @@
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node, dir)
add_underlay(T, node, dir, node?.icon_connect_type)
/obj/machinery/atmospherics/portables_connector/hide(var/i)
update_underlays()

View File

@@ -107,7 +107,7 @@
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(

View File

@@ -53,6 +53,11 @@
use_power = USE_POWER_IDLE
icon_state = "map_vent_out"
/obj/machinery/atmospherics/unary/vent_pump/aux
icon_state = "map_vent_aux"
icon_connect_type = "-aux"
connect_types = CONNECT_TYPE_AUX //connects to aux pipes
/obj/machinery/atmospherics/unary/vent_pump/siphon
pump_direction = 0
@@ -80,7 +85,7 @@
icon = null
initial_loc = get_area(loc)
area_uid = initial_loc.uid
area_uid = "\ref[initial_loc]"
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
@@ -98,6 +103,11 @@
power_channel = EQUIP
power_rating = 45000 //15 kW ~ 20 HP //VOREStation Edit - 45000
/obj/machinery/atmospherics/unary/vent_pump/high_volume/aux
icon_state = "map_vent_aux"
icon_connect_type = "-aux"
connect_types = CONNECT_TYPE_AUX //connects to aux pipes
/obj/machinery/atmospherics/unary/vent_pump/high_volume/New()
..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
@@ -253,7 +263,7 @@
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(

View File

@@ -38,7 +38,7 @@
icon = null
initial_loc = get_area(loc)
area_uid = initial_loc.uid
area_uid = "\ref[initial_loc]"
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
@@ -93,7 +93,7 @@
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(
"area" = area_uid,

View File

@@ -93,6 +93,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/cap/visible/fuel
name = "fuel pipe endcap"
desc = "An endcap for fuel pipes"
icon_state = "cap-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/cap/visible/aux
name = "aux pipe endcap"
desc = "An endcap for aux pipes"
icon_state = "cap-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/cap/hidden
level = 1
icon_state = "cap"
@@ -117,3 +137,23 @@
layer = PIPES_SUPPLY_LAYER
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/cap/visible/fuel
name = "fuel pipe endcap"
desc = "An endcap for fuel pipes"
icon_state = "cap-f-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/cap/hidden/aux
name = "aux pipe endcap"
desc = "An endcap for aux pipes"
icon_state = "cap-f-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN

View File

@@ -108,16 +108,23 @@
underlays.Cut()
var/turf/T = get_turf(src)
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
var/node3_direction = get_dir(src, node3)
// Unfortunately our nodes are not in consistent directions (see atmos_init()) so do the dance...
var/list/directions = list(NORTH, SOUTH, EAST, WEST) // UN-connected directions
directions -= dir
if(node1)
var/node1_direction = get_dir(src, node1)
add_underlay(T, node1, node1_direction, icon_connect_type)
directions -= node1_direction
if(node2)
var/node2_direction = get_dir(src, node2)
add_underlay(T, node2, node2_direction, icon_connect_type)
directions -= node2_direction
if(node3)
var/node3_direction = get_dir(src, node3)
add_underlay(T, node3, node3_direction, icon_connect_type)
directions -= node3_direction
directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
for(var/D in directions)
add_underlay(T,,D,icon_connect_type)
@@ -195,6 +202,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold/visible/fuel
name="Fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold/visible/aux
name="Aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -241,6 +268,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold/hidden/fuel
name="Fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold/hidden/aux
name="Aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
color = PIPE_COLOR_YELLOW

View File

@@ -107,36 +107,12 @@
overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
underlays.Cut()
/*
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
directions -= add_underlay(node1)
directions -= add_underlay(node2)
directions -= add_underlay(node3)
directions -= add_underlay(node4)
for(var/D in directions)
add_underlay(,D)
*/
var/turf/T = get_turf(src)
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
var/node3_direction = get_dir(src, node3)
var/node4_direction = get_dir(src, node4)
directions -= dir
directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
for(var/D in directions)
add_underlay(T,,D,icon_connect_type)
// Take advantage of the fact that our nodes are *always* in the same directions (see atmos_init())
add_underlay(T, node1, NORTH, icon_connect_type)
add_underlay(T, node2, SOUTH, icon_connect_type)
add_underlay(T, node3, EAST, icon_connect_type)
add_underlay(T, node4, WEST, icon_connect_type)
/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
..()
@@ -197,6 +173,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold4w/visible/fuel
name="4-way fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map_4way-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold4w/visible/aux
name="4-way aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map_4way-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -243,6 +239,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel
name="4-way fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map_4way-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold4w/hidden/aux
name="4-way aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map_4way-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
color = PIPE_COLOR_YELLOW

View File

@@ -203,6 +203,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/simple/visible/fuel
name = "Fuel pipe"
desc = "A one meter section of fuel pipe"
icon_state = "intact-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/simple/visible/aux
name = "Aux pipe"
desc = "A one meter section of aux pipe"
icon_state = "intact-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/simple/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -249,6 +269,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/simple/hidden/fuel
name = "Fuel pipe"
desc = "A one meter section of fuel pipe"
icon_state = "intact-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/simple/hidden/aux
name = "Aux pipe"
desc = "A one meter section of aux pipe"
icon_state = "intact-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/simple/hidden/yellow
color = PIPE_COLOR_YELLOW

View File

@@ -136,6 +136,7 @@
/obj/machinery/atmospherics/pipe/tank/phoron
name = "Pressure Tank (Phoron)"
icon_state = "phoron_map"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL
/obj/machinery/atmospherics/pipe/tank/phoron/New()
air_temporary = new

View File

@@ -4,7 +4,7 @@
/obj/machinery/atmospherics/pipe/simple/visible/universal
name="Universal pipe adapter"
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
icon_state = "map_universal"
pipe_flags = PIPING_ALL_LAYER|PIPING_CARDINAL_AUTONORMALIZE
construction_type = /obj/item/pipe/binary
@@ -42,7 +42,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/universal
name="Universal pipe adapter"
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
icon_state = "map_universal"
pipe_flags = PIPING_ALL_LAYER|PIPING_CARDINAL_AUTONORMALIZE
construction_type = /obj/item/pipe/binary
@@ -81,21 +81,42 @@
var/turf/T = loc
if(node)
var/node_dir = get_dir(src,node)
if(node.icon_connect_type == "-supply")
switch(node.icon_connect_type)
if("-supply")
add_underlay_adapter(T, , node_dir, "")
add_underlay_adapter(T, node, node_dir, "-supply")
add_underlay_adapter(T, , node_dir, "-scrubbers")
else if (node.icon_connect_type == "-scrubbers")
add_underlay_adapter(T, , node_dir, "-fuel")
add_underlay_adapter(T, , node_dir, "-aux")
if ("-scrubbers")
add_underlay_adapter(T, , node_dir, "")
add_underlay_adapter(T, , node_dir, "-supply")
add_underlay_adapter(T, node, node_dir, "-scrubbers")
add_underlay_adapter(T, , node_dir, "-fuel")
add_underlay_adapter(T, , node_dir, "-aux")
if ("-fuel")
add_underlay_adapter(T, , node_dir, "")
add_underlay_adapter(T, , node_dir, "-supply")
add_underlay_adapter(T, , node_dir, "-scrubbers")
add_underlay_adapter(T, node, node_dir, "-fuel")
add_underlay_adapter(T, , node_dir, "-aux")
if ("-aux")
add_underlay_adapter(T, , node_dir, "")
add_underlay_adapter(T, , node_dir, "-supply")
add_underlay_adapter(T, , node_dir, "-scrubbers")
add_underlay_adapter(T, , node_dir, "-fuel")
add_underlay_adapter(T, node, node_dir, "-aux")
else
add_underlay_adapter(T, node, node_dir, "")
add_underlay_adapter(T, , node_dir, "-supply")
add_underlay_adapter(T, , node_dir, "-scrubbers")
add_underlay_adapter(T, , node_dir, "-fuel")
add_underlay_adapter(T, , node_dir, "-aux")
else
add_underlay_adapter(T, , direction, "-supply")
add_underlay_adapter(T, , direction, "-scrubbers")
add_underlay_adapter(T, , direction, "-fuel")
add_underlay_adapter(T, , direction, "-aux")
add_underlay_adapter(T, , direction, "")
/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays

View File

@@ -16,7 +16,7 @@
initialize_directions = SOUTH
pipe_flags = PIPING_DEFAULT_LAYER_ONLY
construction_type = /obj/item/pipe/directional
pipe_state = "passive vent"
pipe_state = "passive_vent"
var/build_killswitch = 1

View File

@@ -1,4 +1,5 @@
#define MC_TICK_CHECK ( ( TICK_USAGE > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
#define CURRENT_RUNLEVEL (2 ** (Master.current_runlevel - 1))
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
#define MC_SPLIT_TICK \

View File

@@ -1,5 +1,5 @@
#define TICK_LIMIT_RUNNING 85 //VOREStation Emergency Edit
#define TICK_LIMIT_RUNNING 80
#define TICK_LIMIT_TO_RUN 70
#define TICK_LIMIT_MC 70
#define TICK_LIMIT_MC_INIT_DEFAULT 98

View File

@@ -1,3 +1,5 @@
#define SMITE_SHADEKIN_ATTACK "Shadekin (Attack)"
#define SMITE_SHADEKIN_NOMF "Shadekin (Devour)"
#define SMITE_REDSPACE_ABDUCT "Redspace Abduction"
#define SMITE_AUTOSAVE "10 Second Autosave"
#define SMITE_AUTOSAVE_WIDE "10 Second Autosave (AoE)"

View File

@@ -34,19 +34,25 @@
#define PIPE_TRIN_T 7 //8 directions: N->S+E, S->N+E, N->S+W, S->N+W, E->W+S, W->E+S, E->W+N, W->E+N
// Pipe connectivity bit flags
#define CONNECT_TYPE_REGULAR 1
#define CONNECT_TYPE_SUPPLY 2
#define CONNECT_TYPE_SCRUBBER 4
#define CONNECT_TYPE_HE 8
#define CONNECT_TYPE_FUEL 16 // TODO - Implement this! Its piping so better ask Leshana
#define CONNECT_TYPE_REGULAR 1 //Center of tile, 'normal'
#define CONNECT_TYPE_SUPPLY 2 //Atmos air supply pipes
#define CONNECT_TYPE_SCRUBBER 4 //Atmos air scrubber pipes
#define CONNECT_TYPE_HE 8 //Heat exchanger pipes
#define CONNECT_TYPE_FUEL 16 //Fuel pipes for overmap ships
#define CONNECT_TYPE_AUX 32 //Aux pipes for 'other' things (airlocks, etc)
// We are based on the three named layers of supply, regular, and scrubber.
#define PIPING_LAYER_SUPPLY 1
#define PIPING_LAYER_REGULAR 2
#define PIPING_LAYER_SCRUBBER 3
#define PIPING_LAYER_FUEL 4
#define PIPING_LAYER_AUX 5
#define PIPING_LAYER_DEFAULT PIPING_LAYER_REGULAR
// We offset the layer values of the different pipe types to ensure they look nice
#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.05)
#define PIPES_AUX_LAYER (PIPES_LAYER - 0.04)
#define PIPES_FUEL_LAYER (PIPES_LAYER - 0.03)
#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.02)
#define PIPES_SUPPLY_LAYER (PIPES_LAYER - 0.01)
#define PIPES_HE_LAYER (PIPES_LAYER + 0.01)

View File

@@ -1,7 +1,16 @@
#define GAME_STATE_PREGAME 1
#define GAME_STATE_SETTING_UP 2
#define GAME_STATE_PLAYING 3
#define GAME_STATE_FINISHED 4
// Ticker game states, turns out these are equivilent to runlevels1
#define GAME_STATE_INIT 0 // RUNLEVEL_INIT
#define GAME_STATE_PREGAME 1 // RUNLEVEL_LOBBY
#define GAME_STATE_SETTING_UP 2 // RUNLEVEL_SETUP
#define GAME_STATE_PLAYING 3 // RUNLEVEL_GAME
#define GAME_STATE_FINISHED 4 // RUNLEVEL_POSTGAME
//End game state, to manage round end.
#define END_GAME_NOT_OVER 1 // Still playing normally
#define END_GAME_MODE_FINISHED 2 // Mode has finished but game has not, wait for game to end too.
#define END_GAME_READY_TO_END 3 // Game and Mode have finished, do rounded stuff.
#define END_GAME_ENDING 4 // Just waiting for ending timer.
#define END_GAME_DELAYED 5 // Admin has delayed the round.
// Security levels.
#define SEC_LEVEL_GREEN 0

View File

@@ -52,3 +52,4 @@
//---------------
//#define isturf(D) istype(D, /turf) //Built in
#define isopenspace(A) istype(A, /turf/simulated/open)
#define isspace(A) istype(A, /turf/space)

View File

@@ -70,11 +70,28 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define NETWORK_ALARM_ATMOS "Atmosphere Alarms"
#define NETWORK_ALARM_POWER "Power Alarms"
#define NETWORK_ALARM_FIRE "Fire Alarms"
#define NETWORK_TALON_HELMETS "TalonHelmets" //VOREStation Add
#define NETWORK_TALON_SHIP "TalonShip" //VOREStation Add
#define NETWORK_EXPLORATION "Exploration"
// Those networks can only be accessed by pre-existing terminals. AIs and new terminals can't use them.
var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret", NETWORK_COMMUNICATORS, NETWORK_EXPLORATION)
#define TRANSMISSION_WIRE 0 //Is this ever used? I don't think it is.
#define TRANSMISSION_RADIO 1 //Radio transmissions (like airlock controller to pump)
#define TRANSMISSION_SUBSPACE 2 //Like headsets
#define TRANSMISSION_BLUESPACE 3 //Point-to-point links
#define SIGNAL_NORMAL 0 //Normal subspace signals
#define SIGNAL_SIMPLE 1 //Normal inter-machinery(?) signals
#define SIGNAL_FAKE 2 //Untrackable signals
#define SIGNAL_TEST 4 //Unlogged signals
#define DATA_NORMAL 0 //Normal data
#define DATA_INTERCOM 1 //Intercoms only
#define DATA_LOCAL 2 //Intercoms and SBRs
#define DATA_ANTAG 3 //Antag interception
#define DATA_FAKE 4 //Not from a real mob
//singularity defines
#define STAGE_ONE 1

View File

@@ -56,3 +56,5 @@
#define PTO_EXPLORATION "Exploration"
#define PTO_CARGO "Cargo"
#define PTO_CIVILIAN "Civilian"
#define DEPARTMENT_TALON "ITV Talon"

View File

@@ -0,0 +1,6 @@
#define EXAMINE_MODE_DEFAULT 0
#define EXAMINE_MODE_INCLUDE_USAGE 1
#define EXAMINE_MODE_SWITCH_TO_PANEL 2
// Should be one higher than the above
#define EXAMINE_MODE_MAX 3

View File

@@ -18,3 +18,4 @@
#define MECHFAB 0x0004 //Mechfab
#define CHASSIS 0x0008 //For protolathe, but differently
#define PROSFAB 0x0010 //For prosthetics fab
#define AUTOLATHE 32 //YW add, for autolathe

49
code/__defines/shields.dm Normal file
View File

@@ -0,0 +1,49 @@
#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. "brute" damtype.
#define SHIELD_DAMTYPE_EM 2 // Electromagnetic damage - Ion weaponry, stun beams, ...
#define SHIELD_DAMTYPE_HEAT 3 // Heat damage - Lasers, fire
// TODO - Thats power not energy you silly goose! I think we mean 45 kilojoules
#define ENERGY_PER_HP (45 KILOWATTS)// Base amount energy that will be deducted from the generator's internal reserve per 1 HP of damage taken
#define ENERGY_UPKEEP_PER_TILE (4 KILOWATTS) // Base upkeep per tile protected. Multiplied by various enabled shield modes. Without them the field does literally nothing.
#define ENERGY_UPKEEP_IDLE 45 // Base upkeep when idle; modified by other factors.
// This shield model is slightly inspired by Sins of a Solar Empire series. In short, shields are designed to analyze what hits them, and adapt themselves against that type of damage.
// This means shields will become increasingly effective against things like emitters - as they will adapt to heat damage, however they will be vulnerable to brute and EM damage.
// In a theoretical assault scenario, it is best to combine all damage types, so mitigation can't build up. The value is capped to prevent full scale invulnerability.
#define MAX_MITIGATION_BASE 40 // % Base maximal reachable mitigation.
#define MAX_MITIGATION_RESEARCH 10 // % Added to MAX_MITIGATION_BASE when generator is built using more advanced components. This value is added for each "tier" of used component, ie. basic one has 1, the best one has 5. Actual maximum should be 90% in this case (with best components). Make sure you won't get above 100%!
#define MITIGATION_HIT_GAIN 5 // Mitigation gain per hit of respective damage type.
#define MITIGATION_HIT_LOSS 4 // Mitigation loss per hit. If we get hit once by EM damage type, EM mitigation will grow, while Physical and Heat mitigation values drop.
#define MITIGATION_LOSS_PASSIVE 0.5 // Mitigation of all damage types will drop by this every tick, up to 0.
// Shield modes allow you to calibrate the field to fit specific needs. It is, for example, possible to create a field that will block airflow, but let people pass.
// Relevant mode bitflags (maximal of 16 flags due to current BYOND limitations)
#define MODEFLAG_HYPERKINETIC 1
#define MODEFLAG_PHOTONIC 2
#define MODEFLAG_NONHUMANS 4
#define MODEFLAG_HUMANOIDS 8
#define MODEFLAG_ANORGANIC 16
#define MODEFLAG_ATMOSPHERIC 32
#define MODEFLAG_HULL 64
#define MODEFLAG_BYPASS 128
#define MODEFLAG_OVERCHARGE 256
#define MODEFLAG_MODULATE 512
#define MODEFLAG_MULTIZ 1024
#define MODEFLAG_EM 2048
// Return codes for shield hits.
#define SHIELD_ABSORBED 1 // The shield has completely absorbed the hit
#define SHIELD_BREACHED_MINOR 2 // The hit was absorbed, but a small gap will be created in the field (1-3 tiles)
#define SHIELD_BREACHED_MAJOR 3 // Same as above, with 2-5 tile gap
#define SHIELD_BREACHED_CRITICAL 4 // Same as above, with 4-8 tile gap
#define SHIELD_BREACHED_FAILURE 5 // Same as above, with 8-16 tile gap. Occurs when the hit exhausts all remaining shield energy.
#define SHIELD_OFF 0 // The shield is offline
#define SHIELD_DISCHARGING 1 // The shield is shutting down and discharging.
#define SHIELD_RUNNING 2 // The shield is running
#define SHIELD_IDLE 3 // The shield is being kept at an idle state
#define SHIELD_SPINNING_UP 4 // Going from idle to running
#define SHIELD_SHUTDOWN_DISPERSION_RATE (10000 KILOWATTS) // The rate at which shield energy disperses when shutdown is initiated.

View File

@@ -54,6 +54,7 @@
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
#define LANGUAGE_BLOB "Blob"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.

View File

@@ -57,6 +57,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_SKYBOX 30
#define INIT_ORDER_MAPPING 25
#define INIT_ORDER_DECALS 20
#define INIT_ORDER_JOB 17
#define INIT_ORDER_ATOMS 15
#define INIT_ORDER_MACHINES 10
#define INIT_ORDER_SHUTTLES 3
@@ -69,10 +70,12 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_HOLOMAPS -5
#define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_ALARM -7
#define INIT_ORDER_OPENSPACE -10
#define INIT_ORDER_XENOARCH -20
#define INIT_ORDER_CIRCUIT -21
#define INIT_ORDER_AI -22
#define INIT_ORDER_JOB -23
#define INIT_ORDER_GAME_MASTER -24
#define INIT_ORDER_TICKER -50
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
@@ -91,6 +94,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_PROCESS 45
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_TICKER 60
#define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_PROJECTILES 150

View File

@@ -2,5 +2,5 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)

View File

@@ -27,7 +27,7 @@
#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))
#define IS_VALID_ASSOC_KEY(V) (!isnum(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>"
@@ -35,6 +35,16 @@
//Helpers for vv_do_topic(list/href_list)
#define IF_VV_OPTION(href_key) if(href_list[href_key])
// vv_do_list() keys
#define VV_HK_LIST_ADD "listadd"
#define VV_HK_LIST_EDIT "listedit"
#define VV_HK_LIST_CHANGE "listchange"
#define VV_HK_LIST_REMOVE "listremove"
#define VV_HK_LIST_ERASE_NULLS "listnulls"
#define VV_HK_LIST_ERASE_DUPES "listdupes"
#define VV_HK_LIST_SHUFFLE "listshuffle"
#define VV_HK_LIST_SET_LENGTH "listlen"
// /datum
#define VV_HK_DELETE "delete"
#define VV_HK_EXPOSE "expose"

View File

@@ -6,10 +6,10 @@
*/
// Determiner constants
#define DET_NONE 0x00;
#define DET_DEFINITE 0x01; // the
#define DET_INDEFINITE 0x02; // a, an, some
#define DET_AUTO 0x04;
#define DET_NONE 0x00
#define DET_DEFINITE 0x01 // the
#define DET_INDEFINITE 0x02 // a, an, some
#define DET_AUTO 0x04
/*
* Misc

View File

@@ -25,3 +25,15 @@
return 1
return 0
// Returns a list of area instances, or a subtypes of them, that are mapped in somewhere.
// Avoid feeding it `/area`, as it will likely cause a lot of lag as it evaluates every single area coded in.
/proc/get_all_existing_areas_of_types(list/area_types)
. = list()
for(var/area_type in area_types)
var/list/types = typesof(area_type)
for(var/T in types)
// Test for existance.
var/area/A = locate(T)
if(!istype(A) || !A.contents.len) // Empty contents list means it's not on the map.
continue
. += A

View File

@@ -246,7 +246,7 @@
var/turf/speaker = get_turf(R)
if(speaker)
for(var/turf/T in hear(R.canhear_range,speaker))
speaker_coverage[T] = T
speaker_coverage[T] = R
// Try to find all the players who can hear the message

View File

@@ -107,11 +107,6 @@ var/round_start_time = 0
next_duration_update = world.time + 1 MINUTES
return last_round_duration
//Can be useful for things dependent on process timing
/proc/process_schedule_interval(var/process_name)
var/datum/controller/process/process = processScheduler.getProcess(process_name)
return process.schedule_interval
/hook/startup/proc/set_roundstart_hour()
roundstart_hour = pick(2,7,12,17)
return 1

View File

@@ -679,7 +679,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
//Returns: all the areas in the world
/proc/return_areas()
var/list/area/areas = list()
for(var/area/A in all_areas)
for(var/area/A in world)
areas += A
return areas
@@ -697,7 +697,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
areatype = areatemp.type
var/list/areas = new/list()
for(var/area/N in all_areas)
for(var/area/N in world)
if(istype(N, areatype)) areas += N
return areas
@@ -711,7 +711,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
areatype = areatemp.type
var/list/turfs = new/list()
for(var/area/N in all_areas)
for(var/area/N in world)
if(istype(N, areatype))
for(var/turf/T in N) turfs += T
return turfs
@@ -726,7 +726,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
areatype = areatemp.type
var/list/atoms = new/list()
for(var/area/N in all_areas)
for(var/area/N in world)
if(istype(N, areatype))
for(var/atom/A in N)
atoms += A

View File

@@ -43,7 +43,7 @@
next_click = world.time + 1
if(client.buildmode)
if(client && client.buildmode)
build_click(src, client.buildmode, params, A)
return

View File

@@ -358,11 +358,13 @@
mymob.radio_use_icon.color = ui_color
mymob.radio_use_icon.alpha = ui_alpha
if(mymob.client)
mymob.client.screen = list()
mymob.client.screen += hud_elements
mymob.client.screen += src.adding + src.hotkeybuttons
mymob.client.screen += mymob.client.void
inventory_shown = 0
return

View File

@@ -44,17 +44,14 @@
. = ..()
client.update_skybox(TRUE)
/mob/Move()
var/old_z = get_z(src)
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
/mob/onTransitZ(old_z, new_z)
..()
if(old_z != new_z)
client?.update_skybox(TRUE)
/mob/forceMove()
var/old_z = get_z(src)
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
/mob/doMove()
if((. = ..()))
client?.update_skybox()
/mob/set_viewsize()
. = ..()

View File

@@ -1,6 +0,0 @@
/bower_components
/node_modules
/ProcessScheduler.dmb
/ProcessScheduler.int
/ProcessScheduler.rsc
/*.lk

View File

@@ -1,212 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright <20> 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.

View File

@@ -1 +0,0 @@
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

View File

@@ -1,86 +0,0 @@
ProcessScheduler
================
A Goonstation release, maintained by Volundr
##SUMMARY
This is a mostly self-contained, fairly well-documented implementation of the main loop process architecture in use in Goonstation.
##LICENSE
This work is released under the following licenses.
[![Creative Commons License](https://licensebuttons.net/l/by-nc/4.0/80x15.png)](http://creativecommons.org/licenses/by-nc/4.0/)
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. The complete text of this license is included in the file LICENSE-CC-BY-NC.
[![Affero GPL Version 3](http://www.gnu.org/graphics/agplv3-88x31.png)](http://www.gnu.org/licenses/agpl-3.0.html)
This work is licensed under the Affero General Public License 3.0. The complete text of the license is included in the file LICENSE-AGPL.
##INSTALLATION
To integrate the process scheduler to your codebase, you will not need anything except the contents of the core/ folder. The rest of the project is simply for testing and to provide an example for the process scheduler code.
### Test project setup
To compile and run the test project, you will require:
- node.js
- BYOND
Clone the repository to a path of your choosing, then change directory to it and execute:
```
npm install -g
bower install -g
```
Then you can either compile with DM or open the DM environment in DreamMaker and compile/run from there.
##USAGE
###BASICS
To use the process scheduler in your SS13 codebase, you'll need:
- core/_defines.dm
- core/_stubs.dm
- core/process.dm
- core/processScheduler.dm
- core/processScheduler.js
- core/updateQueue.dm
- core/updateQueueWorker.dm
To integrate, you can copy the contents of _defines.dm into your global defines file. Most ss13 codebases already have the code from _stubs.dm.
The processScheduler is intended as a replacement for the old master_controller from r4407 and other fork codebases. To implement it, you need only to add the source files to your DM environment, and add the following code into world.New, above where the old master_controller is initialized.
```
processScheduler = new
processScheduler.setup()
processScheduler.start()
```
The processScheduler will automatically find all subtypes of process, and begin processing them.
The interface code in test/processSchedulerView.dm is simply an example frontend, and can easily be rebuilt to use other styles, and/or render simple html without using javascript for refreshing the panel and killing processes.
###DETAILS
To implement a process, you have two options:
1. Implement a raw loop-style processor
2. Implement an updateQueue processor
There are clear examples of both of these paradigms in the code provided. Both styles are valid, but for processes that are just a loop calling an update proc on a bunch of objects, you should use the updateQueue.
The updateQueue works by spawn(0)'ing your specified update proc, but it only puts one instance in the scheduler at a time. Examine the code for more details. The overall effect of this is that it doesn't block, and it lets update loops work concurrently. It enables a much smoother user experience.
##Contributing
I welcome pull requests and issue reports, and will try to merge/fix them as I have time.
### Licensing for code submitted via PR:
By submitting a pull request, you agree to release all original code submitted in the pull request under the [MIT License](http://opensource.org/licenses/MIT). You also agree that any code submitted is either your own work, or is public domain or under a equally or less restrictive license than the MIT license, or that you have the express written permission of the authors of the submitted code to submit the pull request.

View File

@@ -1,30 +0,0 @@
{
"name": "ProcessScheduler",
"main": "ProcessScheduler.js",
"version": "1.0.0",
"homepage": "https://github.com/goonstation/ProcessScheduler",
"authors": [
"Volundr <spoogemonster@gmail.com>"
],
"description": "BYOND SS13 Process Scheduler",
"keywords": [
"byond",
"ss13",
"process",
"scheduler"
],
"license": "CC-BY-NC",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"private": true,
"dependencies": {
"bootstrap2.3.2": "~2.3.2",
"jquery": "1.11.1",
"json2": "*"
}
}

View File

@@ -1,392 +0,0 @@
// Process
/datum/controller/process
/**
* State vars
*/
// Main controller ref
var/tmp/datum/controller/processScheduler/main
// 1 if process is not running or queued
var/tmp/idle = 1
// 1 if process is queued
var/tmp/queued = 0
// 1 if process is running
var/tmp/running = 0
// 1 if process is blocked up
var/tmp/hung = 0
// 1 if process was killed
var/tmp/killed = 0
// Status text var
var/tmp/status
// Previous status text var
var/tmp/previousStatus
// 1 if process is disabled
var/tmp/disabled = 0
/**
* Config vars
*/
// Process name
// Process schedule interval
// This controls how often the process would run under ideal conditions.
// If the process scheduler sees that the process has finished, it will wait until
// this amount of time has elapsed from the start of the previous run to start the
// process running again.
var/tmp/schedule_interval = PROCESS_DEFAULT_SCHEDULE_INTERVAL // run every 50 ticks
// Process sleep interval
// This controls how often the process will yield (call sleep(0)) while it is running.
// Every concurrent process should sleep periodically while running in order to allow other
// processes to execute concurrently.
var/tmp/sleep_interval = PROCESS_DEFAULT_SLEEP_INTERVAL
// Defer usage; the tick usage at which this process will defer until the next tick
var/tmp/defer_usage = PROCESS_DEFAULT_DEFER_USAGE
// hang_warning_time - this is the time (in 1/10 seconds) after which the server will begin to show "maybe hung" in the context window
var/tmp/hang_warning_time = PROCESS_DEFAULT_HANG_WARNING_TIME
// hang_alert_time - After this much time(in 1/10 seconds), the server will send an admin debug message saying the process may be hung
var/tmp/hang_alert_time = PROCESS_DEFAULT_HANG_ALERT_TIME
// hang_restart_time - After this much time(in 1/10 seconds), the server will automatically kill and restart the process.
var/tmp/hang_restart_time = PROCESS_DEFAULT_HANG_RESTART_TIME
// Number of deciseconds to delay before starting the process
var/start_delay = 0
/**
* recordkeeping vars
*/
// Records the time (1/10s timeofgame) at which the process last began running
var/tmp/run_start = 0
// Records the number of times this process has been killed and restarted
var/tmp/times_killed
// Tick count
var/tmp/ticks = 0
var/tmp/last_task = ""
var/tmp/last_object
// How many times in the current run has the process deferred work till the next tick?
var/tmp/cpu_defer_count = 0
// Counts the number of times an exception has occurred; gets reset after 10
var/tmp/list/exceptions = list()
// The next tick_usage the process will sleep at
var/tmp/next_sleep_usage
// Last run duration, in seconds
var/tmp/last_run_time = 0
// Last 20 run durations
var/tmp/list/last_twenty_run_times = list()
// Highest run duration, in seconds
var/tmp/highest_run_time = 0
// Tick usage at start of current run (updates upon deferring)
var/tmp/tick_usage_start
// Accumulated tick usage from before each deferral
var/tmp/tick_usage_accumulated = 0
/datum/controller/process/New(var/datum/controller/processScheduler/scheduler)
..()
main = scheduler
previousStatus = "idle"
idle()
name = "process"
run_start = 0
ticks = 0
last_task = 0
last_object = null
/datum/controller/process/proc/started()
// Initialize run_start so we can detect hung processes.
run_start = TimeOfGame
// Initialize defer count
cpu_defer_count = 0
// Prepare usage tracking (defer() updates these)
tick_usage_start = TICK_USAGE
tick_usage_accumulated = 0
running()
main.processStarted(src)
onStart()
/datum/controller/process/proc/finished()
ticks++
recordRunTime()
idle()
main.processFinished(src)
onFinish()
/datum/controller/process/proc/recordRunTime()
// Convert from tick usage (100/tick) to seconds of CPU time used
var/total_usage = (tick_usage_accumulated + (TICK_USAGE - tick_usage_start)) / 1000 * world.tick_lag
last_run_time = total_usage
if(total_usage > highest_run_time)
highest_run_time = total_usage
if(last_twenty_run_times.len == 20)
last_twenty_run_times.Cut(1, 2)
last_twenty_run_times += total_usage
/datum/controller/process/proc/doWork()
/datum/controller/process/proc/setup()
/datum/controller/process/process()
started()
doWork()
finished()
/datum/controller/process/proc/running()
idle = 0
queued = 0
running = 1
hung = 0
setStatus(PROCESS_STATUS_RUNNING)
/datum/controller/process/proc/idle()
queued = 0
running = 0
idle = 1
hung = 0
setStatus(PROCESS_STATUS_IDLE)
/datum/controller/process/proc/queued()
idle = 0
running = 0
queued = 1
hung = 0
setStatus(PROCESS_STATUS_QUEUED)
/datum/controller/process/proc/hung()
hung = 1
setStatus(PROCESS_STATUS_HUNG)
/datum/controller/process/proc/handleHung()
var/datum/lastObj = last_object
var/lastObjType = "null"
if(istype(lastObj))
lastObjType = lastObj.type
var/msg = "[name] process hung at tick #[ticks]. Process was unresponsive for [(TimeOfGame - run_start) / 10] seconds and was restarted. Last task: [last_task]. Last Object Type: [lastObjType]"
log_debug(msg)
message_admins(msg)
main.restartProcess(src.name)
/datum/controller/process/proc/kill()
if (!killed)
var/msg = "[name] process was killed at tick #[ticks]."
log_debug(msg)
message_admins(msg)
//finished()
// Allow inheritors to clean up if needed
onKill()
// This should del
del(src)
// Do not call this directly - use SHECK
/datum/controller/process/proc/defer()
if(killed)
// The kill proc is the only place where killed is set.
// The kill proc should have deleted this datum, and all sleeping procs that are
// owned by it.
CRASH("A killed process is still running somehow...")
if (hung)
// This will only really help if the doWork proc ends up in an infinite loop.
handleHung()
CRASH("Process [name] hung and was restarted.")
tick_usage_accumulated += (TICK_USAGE - tick_usage_start)
if(TICK_USAGE < defer_usage)
sleep(0)
else
sleep(world.tick_lag)
cpu_defer_count++
tick_usage_start = TICK_USAGE
next_sleep_usage = min(TICK_USAGE + sleep_interval, defer_usage)
/datum/controller/process/proc/update()
// Clear delta
if(previousStatus != status)
setStatus(status)
var/elapsedTime = getElapsedTime()
if (hung)
handleHung()
return
else if (elapsedTime > hang_restart_time)
hung()
else if (elapsedTime > hang_alert_time)
setStatus(PROCESS_STATUS_PROBABLY_HUNG)
else if (elapsedTime > hang_warning_time)
setStatus(PROCESS_STATUS_MAYBE_HUNG)
/datum/controller/process/proc/getElapsedTime()
return TimeOfGame - run_start
/datum/controller/process/proc/tickDetail()
return
/datum/controller/process/proc/getContext()
return "<tr><td>[name]</td><td>[getAverageRunTime()]</td><td>[last_run_time]</td><td>[highest_run_time]</td><td>[ticks]</td></tr>\n"
/datum/controller/process/proc/getContextData()
return list(
"name" = name,
"averageRunTime" = getAverageRunTime(),
"lastRunTime" = last_run_time,
"highestRunTime" = highest_run_time,
"ticks" = ticks,
"schedule" = schedule_interval,
"status" = getStatusText(),
"disabled" = disabled
)
/datum/controller/process/proc/getStatus()
return status
/datum/controller/process/proc/getStatusText(var/s = 0)
if(!s)
s = status
switch(s)
if(PROCESS_STATUS_IDLE)
return "idle"
if(PROCESS_STATUS_QUEUED)
return "queued"
if(PROCESS_STATUS_RUNNING)
return "running"
if(PROCESS_STATUS_MAYBE_HUNG)
return "maybe hung"
if(PROCESS_STATUS_PROBABLY_HUNG)
return "probably hung"
if(PROCESS_STATUS_HUNG)
return "HUNG"
else
return "UNKNOWN"
/datum/controller/process/proc/getPreviousStatus()
return previousStatus
/datum/controller/process/proc/getPreviousStatusText()
return getStatusText(previousStatus)
/datum/controller/process/proc/setStatus(var/newStatus)
previousStatus = status
status = newStatus
/datum/controller/process/proc/setLastTask(var/task, var/object)
last_task = task
last_object = object
/datum/controller/process/proc/_copyStateFrom(var/datum/controller/process/target)
main = target.main
name = target.name
schedule_interval = target.schedule_interval
sleep_interval = target.sleep_interval
run_start = 0
times_killed = target.times_killed
ticks = target.ticks
last_task = target.last_task
last_object = target.last_object
copyStateFrom(target)
/datum/controller/process/proc/copyStateFrom(var/datum/controller/process/target)
/datum/controller/process/proc/onKill()
/datum/controller/process/proc/onStart()
/datum/controller/process/proc/onFinish()
/datum/controller/process/proc/disable()
disabled = 1
/datum/controller/process/proc/enable()
disabled = 0
/datum/controller/process/proc/getAverageRunTime()
var/t = 0
var/c = 0
for(var/time in last_twenty_run_times)
t += time
c++
if(c > 0)
return t / c
return c
/datum/controller/process/proc/getLastRunTime()
return last_run_time
/datum/controller/process/proc/getHighestRunTime()
return highest_run_time
/datum/controller/process/proc/getTicks()
return ticks
/datum/controller/process/proc/statProcess()
var/averageRunTime = round(getAverageRunTime(), 0.001)
var/lastRunTime = round(last_run_time, 0.001)
var/highestRunTime = round(highest_run_time, 0.001)
var/deferTime = round(cpu_defer_count / 10 * world.tick_lag, 0.01)
stat("[name]", "T#[getTicks()] | AR [averageRunTime] | LR [lastRunTime] | HR [highestRunTime] | D [deferTime]")
/datum/controller/process/proc/catchException(var/exception/e, var/thrower)
if(istype(e)) // Real runtimes go to the real error handler
log_runtime(e, thrower, "Caught by process: [name]")
return
var/etext = "[e]"
var/eid = "[e]" // Exception ID, for tracking repeated exceptions
var/ptext = "" // "processing..." text, for what was being processed (if known)
if(istype(e))
etext += " in [e.file], line [e.line]"
eid = "[e.file]:[e.line]"
if(eid in exceptions)
if(exceptions[eid]++ >= 10)
return
else
exceptions[eid] = 1
if(istype(thrower, /datum))
var/datum/D = thrower
ptext = " processing [D.type]"
if(istype(thrower, /atom))
var/atom/A = thrower
ptext += " ([A]) ([A.x],[A.y],[A.z])"
log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]")
if(exceptions[eid] >= 10)
log_to_dd("This exception will now be ignored for ten minutes.")
spawn(6000)
exceptions[eid] = 0
/datum/controller/process/proc/catchBadType(var/datum/caught)
if(isnull(caught) || !istype(caught) || QDELETED(caught))
return // Only bother with types we can identify and that don't belong
catchException("Type [caught.type] does not belong in process' queue")

View File

@@ -1,234 +0,0 @@
// Singleton instance of game_controller_new, setup in world.New()
var/global/datum/controller/processScheduler/processScheduler
/datum/controller/processScheduler
// Processes known by the scheduler
var/tmp/datum/controller/process/list/processes = new
// Processes that are currently running
var/tmp/datum/controller/process/list/running = new
// Processes that are idle
var/tmp/datum/controller/process/list/idle = new
// Processes that are queued to run
var/tmp/datum/controller/process/list/queued = new
// Process name -> process object map
var/tmp/datum/controller/process/list/nameToProcessMap = new
// Process last queued times (world time)
var/tmp/datum/controller/process/list/last_queued = new
// How long to sleep between runs (set to tick_lag in New)
var/tmp/scheduler_sleep_interval
// Controls whether the scheduler is running or not
var/tmp/isRunning = 0
// Setup for these processes will be deferred until all the other processes are set up.
var/tmp/list/deferredSetupList = new
/datum/controller/processScheduler/New()
..()
// When the process scheduler is first new'd, tick_lag may be wrong, so these
// get re-initialized when the process scheduler is started.
// (These are kept here for any processes that decide to process before round start)
scheduler_sleep_interval = world.tick_lag
/**
* deferSetupFor
* @param path processPath
* If a process needs to be initialized after everything else, add it to
* the deferred setup list. On goonstation, only the ticker needs to have
* this treatment.
*/
/datum/controller/processScheduler/proc/deferSetupFor(var/processPath)
if (!(processPath in deferredSetupList))
deferredSetupList += processPath
/datum/controller/processScheduler/proc/setup()
// There can be only one
if(processScheduler && (processScheduler != src))
del(src)
return 0
var/process
// Add all the processes we can find, except for the ticker
for (process in subtypesof(/datum/controller/process))
if (!(process in deferredSetupList))
addProcess(new process(src))
for (process in deferredSetupList)
addProcess(new process(src))
/datum/controller/processScheduler/proc/start()
isRunning = 1
// tick_lag will have been set by now, so re-initialize these
scheduler_sleep_interval = world.tick_lag
updateStartDelays()
spawn(0)
process()
/datum/controller/processScheduler/process()
while(isRunning)
checkRunningProcesses()
queueProcesses()
runQueuedProcesses()
sleep(scheduler_sleep_interval)
/datum/controller/processScheduler/proc/stop()
isRunning = 0
/datum/controller/processScheduler/proc/checkRunningProcesses()
for(var/datum/controller/process/p in running)
p.update()
if (isnull(p)) // Process was killed
continue
var/status = p.getStatus()
var/previousStatus = p.getPreviousStatus()
// Check status changes
if(status != previousStatus)
//Status changed.
switch(status)
if(PROCESS_STATUS_PROBABLY_HUNG)
message_admins("Process '[p.name]' may be hung.")
if(PROCESS_STATUS_HUNG)
message_admins("Process '[p.name]' is hung and will be restarted.")
/datum/controller/processScheduler/proc/queueProcesses()
for(var/datum/controller/process/p in processes)
// Don't double-queue, don't queue running processes
if (p.disabled || p.running || p.queued || !p.idle)
continue
// If the process should be running by now, go ahead and queue it
if (world.time >= last_queued[p] + p.schedule_interval)
setQueuedProcessState(p)
/datum/controller/processScheduler/proc/runQueuedProcesses()
for(var/datum/controller/process/p in queued)
runProcess(p)
/datum/controller/processScheduler/proc/addProcess(var/datum/controller/process/process)
processes.Add(process)
process.idle()
idle.Add(process)
// Set up process
process.setup()
// Save process in the name -> process map
nameToProcessMap[process.name] = process
/datum/controller/processScheduler/proc/replaceProcess(var/datum/controller/process/oldProcess, var/datum/controller/process/newProcess)
processes.Remove(oldProcess)
processes.Add(newProcess)
newProcess.idle()
idle.Remove(oldProcess)
running.Remove(oldProcess)
queued.Remove(oldProcess)
idle.Add(newProcess)
newProcess.last_run_time = oldProcess.last_run_time
newProcess.last_twenty_run_times = oldProcess.last_twenty_run_times
newProcess.highest_run_time = oldProcess.highest_run_time
nameToProcessMap[newProcess.name] = newProcess
/datum/controller/processScheduler/proc/updateStartDelays()
for(var/datum/controller/process/p in processes)
if(p.start_delay)
last_queued[p] = world.time - p.start_delay
/datum/controller/processScheduler/proc/runProcess(var/datum/controller/process/process)
spawn(0)
process.process()
/datum/controller/processScheduler/proc/processStarted(var/datum/controller/process/process)
setRunningProcessState(process)
last_queued[process] = world.time
/datum/controller/processScheduler/proc/processFinished(var/datum/controller/process/process)
setIdleProcessState(process)
/datum/controller/processScheduler/proc/setIdleProcessState(var/datum/controller/process/process)
if (process in running)
running -= process
if (process in queued)
queued -= process
if (!(process in idle))
idle += process
/datum/controller/processScheduler/proc/setQueuedProcessState(var/datum/controller/process/process)
if (process in running)
running -= process
if (process in idle)
idle -= process
if (!(process in queued))
queued += process
// The other state transitions are handled internally by the process.
process.queued()
/datum/controller/processScheduler/proc/setRunningProcessState(var/datum/controller/process/process)
if (process in queued)
queued -= process
if (process in idle)
idle -= process
if (!(process in running))
running += process
/datum/controller/processScheduler/proc/getStatusData()
var/list/data = new
for (var/datum/controller/process/p in processes)
data.len++
data[data.len] = p.getContextData()
return data
/datum/controller/processScheduler/proc/getProcessCount()
return processes.len
/datum/controller/processScheduler/proc/hasProcess(var/processName as text)
if (nameToProcessMap[processName])
return 1
/datum/controller/processScheduler/proc/killProcess(var/processName as text)
restartProcess(processName)
/datum/controller/processScheduler/proc/restartProcess(var/processName as text)
if (hasProcess(processName))
var/datum/controller/process/oldInstance = nameToProcessMap[processName]
var/datum/controller/process/newInstance = new oldInstance.type(src)
newInstance._copyStateFrom(oldInstance)
replaceProcess(oldInstance, newInstance)
oldInstance.kill()
/datum/controller/processScheduler/proc/enableProcess(var/processName as text)
if (hasProcess(processName))
var/datum/controller/process/process = nameToProcessMap[processName]
process.enable()
/datum/controller/processScheduler/proc/disableProcess(var/processName as text)
if (hasProcess(processName))
var/datum/controller/process/process = nameToProcessMap[processName]
process.disable()
/datum/controller/processScheduler/proc/statProcesses()
if(!isRunning)
stat("Processes", "Scheduler not running")
return
stat("Processes", "[processes.len] (R [running.len] / Q [queued.len] / I [idle.len])")
for(var/datum/controller/process/p in processes)
p.statProcess()
/datum/controller/processScheduler/proc/getProcess(var/process_name)
return nameToProcessMap[process_name]

View File

@@ -1,28 +0,0 @@
{
"name": "ProcessScheduler",
"version": "1.0.0",
"description": "BYOND SS13 Process Scheduler",
"main": "processScheduler.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/goonstation/ProcessScheduler.git"
},
"keywords": [
"byond",
"ss13",
"process",
"scheduler"
],
"author": "Volundr",
"license": "CC-BY-NC",
"bugs": {
"url": "https://github.com/goonstation/ProcessScheduler/issues"
},
"homepage": "https://github.com/goonstation/ProcessScheduler",
"dependencies": {
"bower": "*"
}
}

View File

@@ -1,9 +0,0 @@
/datum/controller/process/emergencyShuttle/setup()
name = "emergency shuttle"
schedule_interval = 20 // every 2 seconds
if(!emergency_shuttle)
emergency_shuttle = new
/datum/controller/process/emergencyShuttle/doWork()
emergency_shuttle.process()

View File

@@ -1,6 +0,0 @@
/datum/controller/process/game_master/setup()
name = "\improper GM controller"
schedule_interval = 600 // every 60 seconds
/datum/controller/process/game_master/doWork()
game_master.process()

View File

@@ -1,42 +0,0 @@
var/global/datum/controller/process/ticker/tickerProcess
/datum/controller/process/ticker
var/lastTickerTimeDuration
var/lastTickerTime
/datum/controller/process/ticker/setup()
name = "ticker"
schedule_interval = 20 // every 2 seconds
lastTickerTime = world.timeofday
if(!ticker)
ticker = new
tickerProcess = src
spawn(0)
if(ticker)
ticker.pregame()
/datum/controller/process/ticker/doWork()
var/currentTime = world.timeofday
if(currentTime < lastTickerTime) // check for midnight rollover
lastTickerTimeDuration = (currentTime - (lastTickerTime - TICKS_IN_DAY)) / TICKS_IN_SECOND
else
lastTickerTimeDuration = (currentTime - lastTickerTime) / TICKS_IN_SECOND
lastTickerTime = currentTime
ticker.process()
/datum/controller/process/ticker/proc/getLastTickerTimeDuration()
return lastTickerTimeDuration
// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem!
/datum/controller/process/ticker/proc/HasRoundStarted()
return (ticker && ticker.current_state >= GAME_STATE_PLAYING)
/datum/controller/process/ticker/proc/IsRoundInProgress()
return (ticker && ticker.current_state == GAME_STATE_PLAYING)

View File

@@ -125,6 +125,8 @@ var/const/EXP_FREQ = 1361
var/const/MED_I_FREQ = 1485
var/const/SEC_I_FREQ = 1475
var/const/TALON_FREQ = 1481 //VOREStation Add
var/list/radiochannels = list(
"Common" = PUB_FREQ,
"Science" = SCI_FREQ,
@@ -142,7 +144,8 @@ var/list/radiochannels = list(
"AI Private" = AI_FREQ,
"Entertainment" = ENT_FREQ,
"Medical(I)" = MED_I_FREQ,
"Security(I)" = SEC_I_FREQ
"Security(I)" = SEC_I_FREQ,
"Talon" = TALON_FREQ //VOREStation Add
)
// central command channels, i.e deathsquid & response teams
@@ -154,6 +157,8 @@ var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ)
//Department channels, arranged lexically
var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ)
var/list/OFFMAP_FREQS = list(TALON_FREQ) //VOREStation Add
#define TRANSMISSION_WIRE 0
#define TRANSMISSION_RADIO 1
@@ -189,7 +194,10 @@ var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC
return "entradio"
if(frequency in DEPT_FREQS)
return "deptradio"
//VOREStation Add
if(frequency in OFFMAP_FREQS)
return "expradio"
//VOREStation Add End
return "radio"
/* filters */

View File

@@ -1,273 +1,275 @@
var/list/gamemode_cache = list()
/datum/configuration
var/server_name = null // server name (for world name / status)
var/server_suffix = 0 // generate numeric suffix based on server port
var/static/server_name = null // server name (for world name / status)
var/static/server_suffix = 0 // generate numeric suffix based on server port
var/nudge_script_path = "nudge.py" // where the nudge.py script is located
var/static/nudge_script_path = "nudge.py" // where the nudge.py script is located
var/log_ooc = 0 // log OOC channel
var/log_access = 0 // log login/logout
var/log_say = 0 // log client say
var/log_admin = 0 // log admin actions
var/log_debug = 1 // log debug output
var/log_game = 0 // log game events
var/log_vote = 0 // log voting
var/log_whisper = 0 // log client whisper
var/log_emote = 0 // log emotes
var/log_attack = 0 // log attack messages
var/log_adminchat = 0 // log admin chat messages
var/log_adminwarn = 0 // log warnings admins get about bomb construction and such
var/log_pda = 0 // log pda messages
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
var/log_runtime = 0 // logs world.log to a file
var/log_world_output = 0 // log to_world_log(messages)
var/log_graffiti = 0 // logs graffiti
var/sql_enabled = 0 // for sql switching
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/allow_vote_restart = 0 // allow votes to restart
var/ert_admin_call_only = 0
var/allow_vote_mode = 0 // allow votes to change mode
var/allow_admin_jump = 1 // allows admin jumping
var/allow_admin_spawning = 1 // allows admin item spawning
var/allow_admin_rev = 1 // allows admin revives
var/pregame_time = 180 // pregame time in seconds
var/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default)
var/vote_period = 600 // length of voting period (deciseconds, default 1 minute)
var/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called
var/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote
var/vote_autotransfer_amount = 1 // number of extension votes before the final one
var/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100).
var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi)
var/vote_no_dead = 0 // dead people can't vote (tbi)
// var/enable_authentication = 0 // goon authentication
var/del_new_on_log = 1 // del's new players if they log before they spawn in
var/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard
var/traitor_scaling = 0 //if amount of traitors scales based on amount of players
var/objectives_disabled = 0 //if objectives are disabled or not
var/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other
var/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke.
var/allow_Metadata = 0 // Metadata is supported.
var/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1.
var/fps = 20
var/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling
var/Tickcomp = 0
var/socket_talk = 0 // use socket_talk to communicate with other processes
var/list/resource_urls = null
var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round.
var/list/mode_names = list()
var/list/modes = list() // allowed modes
var/list/votable_modes = list() // votable modes
var/list/probabilities = list() // relative probability of each mode
var/list/player_requirements = list() // Overrides for how many players readied up a gamemode needs to start.
var/list/player_requirements_secret = list() // Same as above, but for the secret gamemode.
var/humans_need_surnames = 0
var/allow_random_events = 0 // enables random events mid-round when set to 1
var/enable_game_master = 0 // enables the 'smart' event system.
var/allow_ai = 1 // allow ai job
var/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable.
var/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell
var/hostedby = null
var/respawn = 1
var/guest_jobban = 1
var/usewhitelist = 0
var/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0
var/show_mods = 0
var/show_devs = 0
var/show_event_managers = 0
var/mods_can_tempban = 0
var/mods_can_job_tempban = 0
var/mod_tempban_max = 1440
var/mod_job_tempban_max = 1440
var/load_jobs_from_txt = 0
var/ToRban = 0
var/automute_on = 0 //enables automuting/spam prevention
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
var/static/log_ooc = 0 // log OOC channel
var/static/log_access = 0 // log login/logout
var/static/log_say = 0 // log client say
var/static/log_admin = 0 // log admin actions
var/static/log_debug = 1 // log debug output
var/static/log_game = 0 // log game events
var/static/log_vote = 0 // log voting
var/static/log_whisper = 0 // log client whisper
var/static/log_emote = 0 // log emotes
var/static/log_attack = 0 // log attack messages
var/static/log_adminchat = 0 // log admin chat messages
var/static/log_adminwarn = 0 // log warnings admins get about bomb construction and such
var/static/log_pda = 0 // log pda messages
var/static/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
var/static/log_runtime = 0 // logs world.log to a file
var/static/log_world_output = 0 // log to_world_log(messages)
var/static/log_graffiti = 0 // logs graffiti
var/static/sql_enabled = 0 // for sql switching
var/static/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/static/allow_vote_restart = 0 // allow votes to restart
var/static/ert_admin_call_only = 0
var/static/allow_vote_mode = 0 // allow votes to change mode
var/static/allow_admin_jump = 1 // allows admin jumping
var/static/allow_admin_spawning = 1 // allows admin item spawning
var/static/allow_admin_rev = 1 // allows admin revives
var/static/pregame_time = 180 // pregame time in seconds
var/static/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default)
var/static/vote_period = 600 // length of voting period (deciseconds, default 1 minute)
var/static/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called
var/static/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote
var/static/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100).
var/static/vote_autotransfer_amount = 3 //How many autotransfers to have
var/static/vote_no_default = 0 // vote does not default to nochange/norestart (tbi)
var/static/vote_no_dead = 0 // dead people can't vote (tbi)
// var/static/enable_authentication = 0 // goon authentication
var/static/del_new_on_log = 1 // del's new players if they log before they spawn in
var/static/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard
var/static/traitor_scaling = 0 //if amount of traitors scales based on amount of players
var/static/objectives_disabled = 0 //if objectives are disabled or not
var/static/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other
var/static/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke.
var/static/allow_Metadata = 0 // Metadata is supported.
var/static/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1.
var/static/fps = 20
var/static/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling
var/static/Tickcomp = 0
var/static/socket_talk = 0 // use socket_talk to communicate with other processes
var/static/list/resource_urls = null
var/static/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
var/static/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round.
var/static/list/mode_names = list()
var/static/list/modes = list() // allowed modes
var/static/list/votable_modes = list() // votable modes
var/static/list/probabilities = list() // relative probability of each mode
var/static/list/player_requirements = list() // Overrides for how many players readied up a gamemode needs to start.
var/static/list/player_requirements_secret = list() // Same as above, but for the secret gamemode.
var/static/humans_need_surnames = 0
var/static/allow_random_events = 0 // enables random events mid-round when set to 1
var/static/enable_game_master = 0 // enables the 'smart' event system.
var/static/allow_ai = 1 // allow ai job
var/static/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable.
var/static/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell
var/static/hostedby = null
var/static/respawn = 1
var/static/guest_jobban = 1
var/static/usewhitelist = 0
var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0
var/static/show_mods = 0
var/static/show_devs = 0
var/static/show_event_managers = 0
var/static/mods_can_tempban = 0
var/static/mods_can_job_tempban = 0
var/static/mod_tempban_max = 1440
var/static/mod_job_tempban_max = 1440
var/static/load_jobs_from_txt = 0
var/static/ToRban = 0
var/static/automute_on = 0 //enables automuting/spam prevention
var/static/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
var/static/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
var/static/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
var/character_slots = 10 // The number of available character slots
var/loadout_slots = 3 // The number of loadout slots per character
var/static/character_slots = 10 // The number of available character slots
var/static/loadout_slots = 3 // The number of loadout slots per character
var/max_maint_drones = 5 //This many drones can spawn,
var/allow_drone_spawn = 1 //assuming the admin allow them to.
var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes.
var/static/max_maint_drones = 5 //This many drones can spawn,
var/static/allow_drone_spawn = 1 //assuming the admin allow them to.
var/static/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes.
var/disable_player_mice = 0
var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
var/static/disable_player_mice = 0
var/static/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
var/usealienwhitelist = 0
var/limitalienplayers = 0
var/alien_to_human_ratio = 0.5
var/allow_extra_antags = 0
var/guests_allowed = 1
var/debugparanoid = 0
var/panic_bunker = 0
var/paranoia_logging = 0
var/static/usealienwhitelist = 0
var/static/limitalienplayers = 0
var/static/alien_to_human_ratio = 0.5
var/static/allow_extra_antags = 0
var/static/guests_allowed = 1
var/static/debugparanoid = 0
var/static/panic_bunker = 0
var/static/paranoia_logging = 0
var/ip_reputation = FALSE //Should we query IPs to get scores? Generates HTTP traffic to an API service.
var/ipr_email //Left null because you MUST specify one otherwise you're making the internet worse.
var/ipr_block_bad_ips = FALSE //Should we block anyone who meets the minimum score below? Otherwise we just log it (If paranoia logging is on, visibly in chat).
var/ipr_bad_score = 1 //The API returns a value between 0 and 1 (inclusive), with 1 being 'definitely VPN/Tor/Proxy'. Values equal/above this var are considered bad.
var/ipr_allow_existing = FALSE //Should we allow known players to use VPNs/Proxies? If the player is already banned then obviously they still can't connect.
var/ipr_minimum_age = 5 //How many days before a player is considered 'fine' for the purposes of allowing them to use VPNs.
var/static/ip_reputation = FALSE //Should we query IPs to get scores? Generates HTTP traffic to an API service.
var/static/ipr_email //Left null because you MUST specify one otherwise you're making the internet worse.
var/static/ipr_block_bad_ips = FALSE //Should we block anyone who meets the minimum score below? Otherwise we just log it (If paranoia logging is on, visibly in chat).
var/static/ipr_bad_score = 1 //The API returns a value between 0 and 1 (inclusive), with 1 being 'definitely VPN/Tor/Proxy'. Values equal/above this var are considered bad.
var/static/ipr_allow_existing = FALSE //Should we allow known players to use VPNs/Proxies? If the player is already banned then obviously they still can't connect.
var/static/ipr_minimum_age = 5 //How many days before a player is considered 'fine' for the purposes of allowing them to use VPNs.
var/serverurl
var/server
var/banappeals
var/wikiurl
var/wikisearchurl
var/forumurl
var/githuburl
var/rulesurl
var/mapurl
var/static/serverurl
var/static/server
var/static/banappeals
var/static/wikiurl
var/static/wikisearchurl
var/static/forumurl
var/static/githuburl
var/static/rulesurl
var/static/mapurl
//Alert level description
var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
var/alert_desc_yellow_upto = "A minor security emergency has developed. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
var/alert_desc_yellow_downto = "Code yellow procedures are now in effect. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
var/alert_desc_violet_upto = "A major medical emergency has developed. Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey all relevant instructions from medical staff."
var/alert_desc_violet_downto = "Code violet procedures are now in effect; Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey relevant instructions from medical staff."
var/alert_desc_orange_upto = "A major engineering emergency has developed. Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
var/alert_desc_orange_downto = "Code orange procedures are now in effect; Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
var/alert_desc_blue_upto = "A major security emergency has developed. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
var/alert_desc_blue_downto = "Code blue procedures are now in effect. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
var/alert_desc_red_upto = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
var/alert_desc_red_downto = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
var/alert_desc_delta = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
var/static/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced."
var/static/alert_desc_yellow_upto = "A minor security emergency has developed. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
var/static/alert_desc_yellow_downto = "Code yellow procedures are now in effect. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced."
var/static/alert_desc_violet_upto = "A major medical emergency has developed. Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey all relevant instructions from medical staff."
var/static/alert_desc_violet_downto = "Code violet procedures are now in effect; Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey relevant instructions from medical staff."
var/static/alert_desc_orange_upto = "A major engineering emergency has developed. Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
var/static/alert_desc_orange_downto = "Code orange procedures are now in effect; Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff."
var/static/alert_desc_blue_upto = "A major security emergency has developed. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
var/static/alert_desc_blue_downto = "Code blue procedures are now in effect. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person."
var/static/alert_desc_red_upto = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
var/static/alert_desc_red_downto = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised."
var/static/alert_desc_delta = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
var/forbid_singulo_possession = 0
var/static/forbid_singulo_possession = 0
//game_options.txt configs
var/health_threshold_softcrit = 0
var/health_threshold_crit = 0
var/health_threshold_dead = -100
var/static/health_threshold_softcrit = 0
var/static/health_threshold_crit = 0
var/static/health_threshold_dead = -100
var/organ_health_multiplier = 1
var/organ_regeneration_multiplier = 1
var/organs_decay
var/default_brain_health = 400
var/allow_headgibs = FALSE
var/static/organ_health_multiplier = 1
var/static/organ_regeneration_multiplier = 1
var/static/organs_decay
var/static/default_brain_health = 400
var/static/allow_headgibs = FALSE
//Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt,
//so that it's similar to HALLOSS. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun.
var/organ_damage_spillover_multiplier = 0.5
var/static/organ_damage_spillover_multiplier = 0.5
var/bones_can_break = 0
var/limbs_can_break = 0
var/static/bones_can_break = 0
var/static/limbs_can_break = 0
var/revival_pod_plants = 1
var/revival_cloning = 1
var/revival_brain_life = -1
var/static/revival_pod_plants = 1
var/static/revival_cloning = 1
var/static/revival_brain_life = -1
var/use_loyalty_implants = 0
var/static/use_loyalty_implants = 0
var/welder_vision = 1
var/generate_map = 0
var/no_click_cooldown = 0
var/static/welder_vision = 1
var/static/generate_map = 0
var/static/no_click_cooldown = 0
//Used for modifying movement speed for mobs.
//Unversal modifiers
var/run_speed = 0
var/walk_speed = 0
var/static/run_speed = 0
var/static/walk_speed = 0
//Mob specific modifiers. NOTE: These will affect different mob types in different ways
var/human_delay = 0
var/robot_delay = 0
var/monkey_delay = 0
var/alien_delay = 0
var/slime_delay = 0
var/animal_delay = 0
var/static/human_delay = 0
var/static/robot_delay = 0
var/static/monkey_delay = 0
var/static/alien_delay = 0
var/static/slime_delay = 0
var/static/animal_delay = 0
var/footstep_volume = 0
var/static/footstep_volume = 0
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database
var/static/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt
var/static/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt
var/static/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
var/static/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database
var/simultaneous_pm_warning_timeout = 100
var/static/simultaneous_pm_warning_timeout = 100
var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions.
var/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels.
var/static/use_recursive_explosions //Defines whether the server uses recursive or circular explosions.
var/static/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels.
var/assistant_maint = 0 //Do assistants get maint access?
var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour.
var/ghost_interaction = 0
var/static/assistant_maint = 0 //Do assistants get maint access?
var/static/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour.
var/static/ghost_interaction = 0
var/comms_password = ""
var/static/comms_password = ""
var/enter_allowed = 1
var/static/enter_allowed = 1
var/use_irc_bot = 0
var/use_node_bot = 0
var/irc_bot_port = 0
var/irc_bot_host = ""
var/irc_bot_export = 0 // whether the IRC bot in use is a Bot32 (or similar) instance; Bot32 uses world.Export() instead of nudge.py/libnudge
var/main_irc = ""
var/admin_irc = ""
var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix
var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge.
var/use_overmap = 0
var/static/use_irc_bot = 0
var/static/use_node_bot = 0
var/static/irc_bot_port = 0
var/static/irc_bot_host = ""
var/static/irc_bot_export = 0 // whether the IRC bot in use is a Bot32 (or similar) instance; Bot32 uses world.Export() instead of nudge.py/libnudge
var/static/main_irc = ""
var/static/admin_irc = ""
var/static/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix
var/static/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge.
var/static/use_overmap = 0
// Event settings
var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours
var/static/expected_round_length = 3 * 60 * 60 * 10 // 3 hours
// If the first delay has a custom start time
// No custom time, no custom time, between 80 to 100 minutes respectively.
var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000))
var/static/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000))
// The lowest delay until next event
// 10, 30, 50 minutes respectively
var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000)
var/static/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000)
// The upper delay until next event
// 15, 45, 70 minutes respectively
var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000)
var/static/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000)
var/aliens_allowed = 0
var/ninjas_allowed = 0
var/abandon_allowed = 1
var/ooc_allowed = 1
var/looc_allowed = 1
var/dooc_allowed = 1
var/dsay_allowed = 1
var/static/aliens_allowed = 0
var/static/ninjas_allowed = 0
var/static/abandon_allowed = 1
var/static/ooc_allowed = 1
var/static/looc_allowed = 1
var/static/dooc_allowed = 1
var/static/dsay_allowed = 1
var/starlight = 0 // Whether space turfs have ambient light or not
var/static/starlight = 0 // Whether space turfs have ambient light or not
var/list/ert_species = list(SPECIES_HUMAN)
var/static/list/ert_species = list(SPECIES_HUMAN)
var/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010"
var/static/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010"
var/aggressive_changelog = 0
var/static/aggressive_changelog = 0
var/list/language_prefixes = list(",","#")//Default language prefixes
var/static/list/language_prefixes = list(",","#")//Default language prefixes
var/show_human_death_message = 1
var/static/show_human_death_message = 1
var/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf
var/radiation_decay_rate = 1 //How much radiation is reduced by each tick
var/radiation_resistance_multiplier = 8.5 //VOREstation edit
var/radiation_material_resistance_divisor = 1
var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
var/static/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf
var/static/radiation_decay_rate = 1 //How much radiation is reduced by each tick
var/static/radiation_resistance_multiplier = 8.5 //VOREstation edit
var/static/radiation_material_resistance_divisor = 1
var/static/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it.
var/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated.
var/autostart_solars = FALSE // If true, specifically mapped in solar control computers will set themselves up when the round starts.
var/static/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated.
var/static/autostart_solars = FALSE // If true, specifically mapped in solar control computers will set themselves up when the round starts.
// New shiny SQLite stuff.
// The basics.
var/sqlite_enabled = FALSE // If it should even be active. SQLite can be ran alongside other databases but you should not have them do the same functions.
var/static/sqlite_enabled = FALSE // If it should even be active. SQLite can be ran alongside other databases but you should not have them do the same functions.
// In-Game Feedback.
var/sqlite_feedback = FALSE // Feedback cannot be submitted if this is false.
var/list/sqlite_feedback_topics = list("General") // A list of 'topics' that feedback can be catagorized under by the submitter.
var/sqlite_feedback_privacy = FALSE // If true, feedback submitted can have its author name be obfuscated. This is not 100% foolproof (it's md5 ffs) but can stop casual snooping.
var/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit.
var/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers.
var/static/sqlite_feedback = FALSE // Feedback cannot be submitted if this is false.
var/static/list/sqlite_feedback_topics = list("General") // A list of 'topics' that feedback can be catagorized under by the submitter.
var/static/sqlite_feedback_privacy = FALSE // If true, feedback submitted can have its author name be obfuscated. This is not 100% foolproof (it's md5 ffs) but can stop casual snooping.
var/static/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit.
var/static/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers.
var/static/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes.
var/static/defib_braindamage_timer = 2 // How long until someone will get brain damage when defibbed, in minutes. The closer to the end of the above timer, the more brain damage they get.
// disables the annoying "You have already logged in this round, disconnect or be banned" popup for multikeying, because it annoys the shit out of me when testing.
var/disable_cid_warn_popup = FALSE
var/static/disable_cid_warn_popup = FALSE
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
@@ -881,6 +883,12 @@ var/list/gamemode_cache = list()
if("sqlite_feedback_cooldown")
config.sqlite_feedback_cooldown = text2num(value)
if("defib_timer")
config.defib_timer = text2num(value)
if("defib_braindamage_timer")
config.defib_braindamage_timer = text2num(value)
if("disable_cid_warn_popup")
config.disable_cid_warn_popup = TRUE

View File

@@ -3,14 +3,14 @@
//
/datum/configuration
var/list/engine_map // Comma separated list of engines to choose from. Blank means fully random.
var/time_off = FALSE
var/pto_job_change = FALSE
var/limit_interns = -1 //Unlimited by default
var/limit_visitors = -1 //Unlimited by default
var/pto_cap = 100 //Hours
var/require_flavor = FALSE
var/ipqualityscore_apikey //API key for ipqualityscore.com
var/static/list/engine_map // Comma separated list of engines to choose from. Blank means fully random.
var/static/time_off = FALSE
var/static/pto_job_change = FALSE
var/static/limit_interns = -1 //Unlimited by default
var/static/limit_visitors = -1 //Unlimited by default
var/static/pto_cap = 100 //Hours
var/static/require_flavor = FALSE
var/static/ipqualityscore_apikey //API key for ipqualityscore.com
/hook/startup/proc/read_vs_config()
var/list/Lines = file2list("config/config.txt")

View File

@@ -2,7 +2,7 @@
// Controls the emergency shuttle
var/global/datum/emergency_shuttle_controller/emergency_shuttle
var/global/datum/emergency_shuttle_controller/emergency_shuttle = new
/datum/emergency_shuttle_controller
var/datum/shuttle/autodock/ferry/emergency/shuttle // Set in shuttle_emergency.dm TODO - is it really?
@@ -75,8 +75,10 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
/datum/emergency_shuttle_controller/proc/set_launch_countdown(var/seconds)
wait_for_launch = 1
launch_time = world.time + seconds*10
START_PROCESSING(SSprocessing, src)
/datum/emergency_shuttle_controller/proc/stop_launch_countdown()
STOP_PROCESSING(SSprocessing, src)
wait_for_launch = 0
//calls the shuttle for an emergency evacuation
@@ -94,7 +96,7 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
evac = 1
emergency_shuttle_called.Announce(replacetext(using_map.emergency_shuttle_called_message, "%ETA%", "[estimated_time] minute\s"))
for(var/area/A in all_areas)
for(var/area/A in world)
if(istype(A, /area/hallway))
A.readyalert()
@@ -120,13 +122,13 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
/datum/emergency_shuttle_controller/proc/recall()
if (!can_recall()) return
wait_for_launch = 0
stop_launch_countdown()
shuttle.cancel_launch(src)
if (evac)
emergency_shuttle_recalled.Announce(using_map.emergency_shuttle_recall_message)
for(var/area/A in all_areas)
for(var/area/A in world)
if(istype(A, /area/hallway))
A.readyreset()
evac = 0

View File

@@ -50,8 +50,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/current_runlevel //for scheduling different subsystems for different stages of the round
var/dbg_is_running_subsystem = FALSE // TEMPORARY DEBUGGING - true only while we are actually waiting on a subsystem
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
@@ -478,11 +476,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
queue_node.state = SS_RUNNING
dbg_is_running_subsystem = TRUE // TEMPORARY DEBUGGING
tick_usage = TICK_USAGE
var/state = queue_node.ignite(queue_node_paused)
tick_usage = TICK_USAGE - tick_usage
dbg_is_running_subsystem = FALSE // TEMPORARY DEBUGGING
if (state == SS_RUNNING)
state = SS_IDLE

View File

@@ -168,11 +168,12 @@
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
if(can_fire && !(SS_NO_FIRE & flags))
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
else
if(SS_NO_FIRE & flags)
msg = "NO FIRE\t[msg]"
else if(can_fire <= 0)
msg = "OFFLINE\t[msg]"
else
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
var/title = name
if (can_fire)
@@ -202,3 +203,15 @@
//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
//should attempt to salvage what it can from the old instance of subsystem
/datum/controller/subsystem/Recover()
// Suspends this subsystem from being queued for running. If already in the queue, sleeps until idle. Returns FALSE if the subsystem was already suspended.
/datum/controller/subsystem/proc/suspend()
. = (can_fire > 0) // Return true if we were previously runnable, false if previously suspended.
can_fire = FALSE
// Safely sleep in a loop until the subsystem is idle, (or its been un-suspended somehow)
while(can_fire <= 0 && state != SS_IDLE)
stoplag() // Safely sleep in a loop until
// Wakes a suspended subsystem.
/datum/controller/subsystem/proc/wake()
can_fire = TRUE

View File

@@ -1,5 +1,5 @@
SUBSYSTEM_DEF(events)
name = "Events"
name = "Events" // VOREStation Edit - This is still the main events subsystem for us.
wait = 2 SECONDS
var/tmp/list/currentrun = null

View File

@@ -0,0 +1,37 @@
// This is a simple ticker for the new event system.
// The logic that determines what events get chosen is held inside a seperate subsystem.
SUBSYSTEM_DEF(event_ticker)
name = "Events (Ticker)"
wait = 2 SECONDS
runlevels = RUNLEVEL_GAME
// List of `/datum/event2/event`s that are currently active, and receiving process() ticks.
var/list/active_events = list()
// List of `/datum/event2/event`s that finished, and are here for showing at roundend, if that's desired.
var/list/finished_events = list()
// Process active events.
/datum/controller/subsystem/event_ticker/fire(resumed)
for(var/E in active_events)
var/datum/event2/event/event = E
event.process()
if(event.finished)
event_finished(event)
// Starts an event, independent of the GM system.
// This means it will always run, and won't affect the GM system in any way, e.g. not putting the event off limits after one use.
/datum/controller/subsystem/event_ticker/proc/start_event(event_type)
var/datum/event2/event/E = new event_type()
E.execute()
event_started(E)
/datum/controller/subsystem/event_ticker/proc/event_started(datum/event2/event/E)
log_debug("Event [E.type] is now being ran.")
active_events += E
/datum/controller/subsystem/event_ticker/proc/event_finished(datum/event2/event/E)
log_debug("Event [E.type] has finished.")
active_events -= E
finished_events += E

View File

@@ -0,0 +1,369 @@
// This is a sort of successor to the various event systems created over the years. It is designed to be just a tad smarter than the
// previous ones, checking various things like player count, department size and composition, individual player activity,
// individual player (IC) skill, and such, in order to try to choose the best events to take in order to add spice or variety to
// the round.
// This subsystem holds the logic that chooses events. Actual event processing is handled in a seperate subsystem.
SUBSYSTEM_DEF(game_master)
name = "Events (Game Master)"
wait = 1 MINUTE
runlevels = RUNLEVEL_GAME
// The GM object is what actually chooses events.
// It's held in a seperate object for better encapsulation, and allows for different 'flavors' of GMs to be made, that choose events differently.
var/datum/game_master/GM = null
var/game_master_type = /datum/game_master/default
var/list/available_events = list() // A list of meta event objects.
var/danger = 0 // The GM's best guess at how chaotic the round is. High danger makes it hold back.
var/staleness = -20 // Determines liklihood of the GM doing something, increases over time.
var/next_event = 0 // Minimum amount of time of nothingness until the GM can pick something again.
var/debug_messages = FALSE // If true, debug information is written to `log_debug()`.
/datum/controller/subsystem/game_master/Initialize()
var/list/subtypes = subtypesof(/datum/event2/meta)
for(var/T in subtypes)
var/datum/event2/meta/M = new T()
if(!M.name)
continue
available_events += M
GM = new game_master_type()
if(config && !config.enable_game_master)
can_fire = FALSE
return ..()
/datum/controller/subsystem/game_master/fire(resumed)
adjust_staleness(1)
adjust_danger(-1)
var/global_afk = metric.assess_all_living_mobs()
global_afk = abs(global_afk - 100)
global_afk = round(global_afk / 100, 0.1)
adjust_staleness(global_afk) // Staleness increases faster if more people are less active.
if(GM.ignore_time_restrictions || next_event < world.time)
if(prob(staleness) && pre_event_checks())
do_event_decision()
/datum/controller/subsystem/game_master/proc/do_event_decision()
log_game_master("Going to choose an event.")
var/datum/event2/meta/event_picked = GM.choose_event()
if(event_picked)
run_event(event_picked)
next_event = world.time + rand(GM.decision_cooldown_lower_bound, GM.decision_cooldown_upper_bound)
/datum/controller/subsystem/game_master/proc/debug_gm()
can_fire = TRUE
staleness = 100
debug_messages = TRUE
/datum/controller/subsystem/game_master/proc/run_event(datum/event2/meta/chosen_event)
var/datum/event2/event/E = chosen_event.make_event()
chosen_event.times_ran++
if(!chosen_event.reusable)
// Disable this event, so it only gets picked once.
chosen_event.enabled = FALSE
if(chosen_event.event_class)
// Disable similar events, too.
for(var/M in available_events)
var/datum/event2/meta/meta = M
if(meta.event_class == chosen_event.event_class)
meta.enabled = FALSE
SSevent_ticker.event_started(E)
adjust_danger(chosen_event.chaos)
adjust_staleness(-(10 + chosen_event.chaos)) // More chaotic events reduce staleness more, e.g. a 25 chaos event will reduce it by 35.
// Tell the game master that something dangerous happened, e.g. someone dying, station explosions.
/datum/controller/subsystem/game_master/proc/adjust_danger(amount)
amount *= GM.danger_modifier
danger = round(between(0, danger + amount, 1000), 0.1)
// Tell the game master that things are getting boring if positive, or something interesting if negative..
/datum/controller/subsystem/game_master/proc/adjust_staleness(amount)
amount *= GM.staleness_modifier
staleness = round( between(-20, staleness + amount, 100), 0.1)
// These are ran before committing to an event.
// Returns TRUE if the system is allowed to procede, otherwise returns FALSE.
/datum/controller/subsystem/game_master/proc/pre_event_checks(quiet = FALSE)
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
if(!quiet)
log_game_master("Unable to start event: Ticker is nonexistant, or the game is not ongoing.")
return FALSE
if(GM.ignore_time_restrictions)
return TRUE
if(next_event > world.time) // Sanity.
if(!quiet)
log_game_master("Unable to start event: Time until next event is approximately [round((next_event - world.time) / (1 MINUTE))] minute(s)")
return FALSE
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
var/mills = round_duration_in_ticks
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
// if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
// if(!quiet)
// log_debug("Game Master unable to start event: It is too early.")
// return FALSE
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
if(!quiet)
log_game_master("Unable to start event: It is too late.")
return FALSE
return TRUE
/datum/controller/subsystem/game_master/proc/choose_game_master(mob/user)
var/list/subtypes = subtypesof(/datum/game_master)
var/new_gm_path = input(user, "What kind of Game Master do you want?", "New Game Master", /datum/game_master/default) as null|anything in subtypes
if(new_gm_path)
log_and_message_admins("has swapped the current GM ([GM.type]) for a new GM ([new_gm_path]).")
GM = new new_gm_path(src)
/datum/controller/subsystem/game_master/proc/log_game_master(message)
if(debug_messages)
log_debug("GAME MASTER: [message]")
// This object makes the actual decisions.
/datum/game_master
// Multiplier for how much 'danger' is accumulated. Higer generally makes it possible for more dangerous events to be picked.
var/danger_modifier = 1.0
// Ditto. Higher numbers generally result in more events occuring in a round.
var/staleness_modifier = 1.0
var/decision_cooldown_lower_bound = 5 MINUTES // Lower bound for how long to wait until -the potential- for another event being decided.
var/decision_cooldown_upper_bound = 20 MINUTES // Same, but upper bound.
var/ignore_time_restrictions = FALSE // Useful for debugging without needing to wait 20 minutes each time.
var/ignore_round_chaos = FALSE // If true, the system will happily choose back to back intense events like meteors and blobs, Dwarf Fortress style.
/client/proc/show_gm_status()
set category = "Debug"
set name = "Show GM Status"
set desc = "Shows you what the GM is thinking. If only that existed in real life..."
if(check_rights(R_ADMIN|R_EVENT|R_DEBUG))
SSgame_master.interact(usr)
else
to_chat(usr, span("warning", "You do not have sufficent rights to view the GM panel, sorry."))
/datum/controller/subsystem/game_master/proc/interact(var/client/user)
if(!user)
return
// Using lists for string tree conservation.
var/list/dat = list("<html><head><title>Automated Game Master Event System</title></head><body>")
// Makes the system turn on or off.
dat += href(src, list("toggle" = 1), "\[Toggle GM\]")
dat += " | "
// Makes the system not care about staleness or being near round-end.
dat += href(src, list("toggle_time_restrictions" = 1), "\[Toggle Time Restrictions\]")
dat += " | "
// Makes the system not care about how chaotic the round might be.
dat += href(src, list("toggle_chaos_throttle" = 1), "\[Toggle Chaos Throttling\]")
dat += " | "
// Makes the system immediately choose an event, while still bound to factors like danger, weights, and department staffing.
dat += href(src, list("force_choose_event" = 1), "\[Force Event Decision\]")
dat += "<br>"
// Swaps out the current GM for a new one with different ideas on what a good event might be.
dat += href(src, list("change_gm" = 1), "\[Change GM\]")
dat += "<br>"
dat += "Current GM Type: [GM.type]<br>"
dat += "State: [can_fire ? "Active": "Inactive"]<br>"
dat += "Status: [pre_event_checks(TRUE) ? "Ready" : "Suppressed"]<br><br>"
dat += "Staleness: [staleness] "
dat += href(src, list("set_staleness" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Staleness is an estimate of how boring the round might be, and if an event should be done. It is increased passively over time, \
and increases faster if people are AFK. It deceases when events and certain 'interesting' things happen in the round.</i><br>"
dat += "Danger: [danger] "
dat += href(src, list("set_danger" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Danger is an estimate of how chaotic the round has been so far. It is decreased passively over time, and is increased by having \
certain chaotic events be selected, or chaotic things happen in the round. A sufficently high amount of danger will make the system \
avoid using destructive events, to avoid pushing the station over the edge.</i><br>"
dat += "<h2>Player Activity:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Category</th>"
dat += "<th>Activity Percentage</th>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Living Mobs</td>"
dat += "<td>[metric.assess_all_living_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Ghosts</td>"
dat += "<td>[metric.assess_all_dead_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Departments</td>"
dat += "</tr>"
for(var/D in metric.departments)
dat += "<tr>"
dat += "<td>[D]</td>"
dat += "<td>[metric.assess_department(D)]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Players</td>"
dat += "</tr>"
for(var/P in player_list)
var/mob/M = P
dat += "<tr>"
dat += "<td>[M] ([M.ckey])</td>"
dat += "<td>[metric.assess_player_activity(M)]%</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events available:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Name</th>"
dat += "<th>Involved Departments</th>"
dat += "<th>Chaos</th>"
dat += "<th>Chaotic Threshold</th>"
dat += "<th>Weight</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in available_events)
var/datum/event2/meta/event = E
dat += "<tr>"
if(!event.enabled)
dat += "<td><strike>[event.name]</strike></td>"
else
dat += "<td>[event.name]</td>"
dat += "<td>[english_list(event.departments)]</td>"
dat += "<td>[event.chaos]</td>"
dat += "<td>[event.chaotic_threshold]</td>"
dat += "<td>[event.get_weight()]</td>"
dat += "<td>[href(event, list("force" = 1), "\[Force\]")] [href(event, list("toggle" = 1), "\[Toggle\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events active:</h2>"
dat += "Current time: [world.time]"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Time Started</th>"
dat += "<th>Time to Announce</th>"
dat += "<th>Time to End</th>"
dat += "<th>Announced</th>"
dat += "<th>Started</th>"
dat += "<th>Ended</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.active_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_to_announce ? event.time_to_announce : "NULL"]</td>"
dat += "<td>[event.time_to_end ? event.time_to_end : "NULL"]</td>"
dat += "<td>[event.announced ? "Yes" : "No"]</td>"
dat += "<td>[event.started ? "Yes" : "No"]</td>"
dat += "<td>[event.ended ? "Yes" : "No"]</td>"
dat += "<td>[href(event, list("abort" = 1), "\[Abort\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "</body></html>"
dat += "<h2>Events completed:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Start Time</th>"
dat += "<th>Finish Time</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.finished_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_finished]</td>"
dat += "</tr>"
dat += "</body></html>"
var/datum/browser/popup = new(user, "game_master_debug", "Automated Game Master Event System", 800, 500, src)
popup.set_content(dat.Join())
popup.open()
/datum/controller/subsystem/game_master/Topic(href, href_list)
if(..())
return
if(href_list["close"]) // Needed or the window re-opens after closing, making it last forever.
return
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
message_admins("[usr] has attempted to modify the Game Master values without sufficent privilages.")
return
if(href_list["toggle"])
can_fire = !can_fire
message_admins("GM was [!can_fire ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_time_restrictions"])
GM.ignore_time_restrictions = !GM.ignore_time_restrictions
message_admins("GM event time restrictions was [GM.ignore_time_restrictions ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_chaos_throttle"])
GM.ignore_round_chaos = !GM.ignore_round_chaos
message_admins("GM event chaos restrictions was [GM.ignore_round_chaos ? "dis" : "en"]abled by [usr.key].")
if(href_list["force_choose_event"])
do_event_decision()
message_admins("[usr.key] forced the Game Master to choose an event immediately.")
if(href_list["change_gm"])
choose_game_master(usr)
if(href_list["set_staleness"])
var/amount = input(usr, "How much staleness should there be?", "Game Master") as null|num
if(!isnull(amount))
staleness = amount
message_admins("GM staleness was set to [amount] by [usr.key].")
if(href_list["set_danger"])
var/amount = input(usr, "How much danger should there be?", "Game Master") as null|num
if(!isnull(amount))
danger = amount
message_admins("GM danger was set to [amount] by [usr.key].")
interact(usr) // To refresh the UI.

View File

@@ -0,0 +1,123 @@
//
// Controller handling icon updates of open space turfs
//
GLOBAL_VAR_INIT(open_space_initialised, FALSE)
SUBSYSTEM_DEF(open_space)
name = "Open Space"
wait = 2 // 5 times per second.
init_order = INIT_ORDER_OPENSPACE
var/list/turfs_to_process = list() // List of turfs queued for update.
var/list/turfs_to_process_old = null // List of turfs currently being updated.
var/counter = 1 // Can't use .len because we need to iterate in order
var/static/image/over_OS_darkness // Image overlayed over the bottom turf with stuff in it.
/datum/controller/subsystem/open_space/Initialize(timeofday)
over_OS_darkness = image('icons/turf/open_space.dmi', "black_open")
over_OS_darkness.plane = OVER_OPENSPACE_PLANE
over_OS_darkness.layer = MOB_LAYER
initialize_open_space()
// Pre-process open space turfs once before the round starts.
fire(FALSE, TRUE)
return ..()
/datum/controller/subsystem/open_space/Recover()
flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
. = ..()
/datum/controller/subsystem/open_space/fire(resumed = 0, init_tick_checks = FALSE)
// We use a different list so any additions to the update lists during a delay from MC_TICK_CHECK
// don't cause things to be cut from the list without being updated.
//If we're not resuming, this must mean it's a new iteration so we have to grab the turfs
if (!resumed)
src.counter = 1
src.turfs_to_process_old = turfs_to_process
turfs_to_process = list()
//cache for sanic speed (lists are references anyways)
var/list/turfs_to_process_old = src.turfs_to_process_old
var/counter = src.counter
while(counter <= turfs_to_process_old.len)
var/turf/T = turfs_to_process_old[counter]
counter += 1
if(!QDELETED(T))
update_turf(T)
if (init_tick_checks)
CHECK_TICK // Used during initialization processing
else if (MC_TICK_CHECK)
src.counter = counter // Save for when we're resumed
return // Used during normal MC processing.
/datum/controller/subsystem/open_space/proc/update_turf(var/turf/T)
for(var/atom/movable/A in T)
A.fall()
T.update_icon()
/datum/controller/subsystem/open_space/proc/add_turf(var/turf/T, var/recursive = 0)
ASSERT(isturf(T))
// Check for multiple additions
// Pointless to process the same turf twice. But we need to push it to the end of the list
// because any turfs below it need to process first.
turfs_to_process -= T
turfs_to_process += T
if(recursive > 0)
var/turf/above = GetAbove(T)
if(above && isopenspace(above))
add_turf(above, recursive)
// Queue the initial updates of open space turfs when the game starts. This will lag!
/datum/controller/subsystem/open_space/proc/initialize_open_space()
// Do initial setup from bottom to top.
for(var/zlevel = 1 to world.maxz)
for(var/turf/simulated/open/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
add_turf(T)
CHECK_TICK
GLOB.open_space_initialised = TRUE
/datum/controller/subsystem/open_space/stat_entry(msg_prefix)
return ..("T [turfs_to_process.len]")
/turf/Entered(atom/movable/AM)
. = ..()
if(GLOB.open_space_initialised && !AM.invisibility && isobj(AM))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Entered([AM])")
SSopen_space.add_turf(T, 1)
/turf/Exited(atom/movable/AM)
. = ..()
if(GLOB.open_space_initialised && !AM.invisibility && isobj(AM))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Exited([AM])")
SSopen_space.add_turf(T, 1)
/obj/update_icon()
. = ..()
if(GLOB.open_space_initialised && !invisibility && isturf(loc))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()")
SSopen_space.add_turf(T, 1)
// Ouch... this is painful. But is there any other way?
/* - No for now
/obj/New()
. = ..()
if(open_space_initialised && !invisibility)
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src]New()")
OS_controller.add_turf(T, 1)
*/
// We probably should hook Destroy() If we can think of something more efficient, lets hear it.
/obj/Destroy()
if(GLOB.open_space_initialised && !invisibility && isturf(loc))
var/turf/T = GetAbove(src)
if(isopenspace(T))
SSopen_space.add_turf(T, 1)
. = ..() // Important that this be at the bottom, or we will have been moved to nullspace.

View File

@@ -84,6 +84,7 @@ SUBSYSTEM_DEF(shuttles)
if(shuttle)
shuttles_made += shuttle
hook_up_motherships(shuttles_made)
hook_up_shuttle_objects(shuttles_made)
shuttles_to_initialize = null
/datum/controller/subsystem/shuttles/proc/initialize_sectors()
@@ -103,7 +104,7 @@ SUBSYSTEM_DEF(shuttles)
try_add_landmark_tag(shuttle_landmark_tag, O)
landmarks_still_needed -= shuttle_landmark_tag
else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically
O = map_sectors["[shuttle_landmark.z]"]
O = get_overmap_sector(get_z(shuttle_landmark))
O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
/datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag)
@@ -165,6 +166,11 @@ SUBSYSTEM_DEF(shuttles)
else
error("Shuttle [S] was unable to find mothership [mothership]!")
// Let shuttles scan their owned areas for objects they want to configure (Called after mothership hookup)
/datum/controller/subsystem/shuttles/proc/hook_up_shuttle_objects(shuttles_list)
for(var/datum/shuttle/S in shuttles_list)
S.populate_shuttle_objects()
// Admin command to halt/resume overmap
/datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting)
if(overmap_halted == new_setting)

View File

@@ -6,6 +6,7 @@ SUBSYSTEM_DEF(skybox)
flags = SS_NO_FIRE
var/static/list/skybox_cache = list()
var/static/mutable_appearance/normal_space
var/static/list/dust_cache = list()
var/static/list/speedspace_cache = list()
var/static/list/mapedge_cache = list()
@@ -13,52 +14,75 @@ SUBSYSTEM_DEF(skybox)
var/static/list/phase_shift_by_y = list()
/datum/controller/subsystem/skybox/PreInit()
//Shuffle some lists
phase_shift_by_x = get_cross_shift_list(15)
phase_shift_by_y = get_cross_shift_list(15)
//Create our 'normal' space appearance
normal_space = new()
normal_space.name = "\proper space"
normal_space.desc = "Space!"
normal_space.mouse_opacity = 2 //Always fully opaque. It's SPACE there can't be things BEHIND IT.
normal_space.appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER
normal_space.plane = SPACE_PLANE
normal_space.layer = TURF_LAYER
normal_space.icon = 'icons/turf/space.dmi'
normal_space.icon_state = "white"
//Static
for (var/i in 0 to 25)
var/mutable_appearance/MA = new(normal_space)
var/image/im = image('icons/turf/space_dust.dmi', "[i]")
im.plane = DUST_PLANE
im.alpha = 128 //80
im.blend_mode = BLEND_ADD
dust_cache["[i]"] = im
MA.overlays = list(im)
dust_cache["[i]"] = MA
//Moving
for (var/i in 0 to 14)
// NORTH/SOUTH
var/mutable_appearance/MA = new(normal_space)
var/image/im = image('icons/turf/space_dust_transit.dmi', "speedspace_ns_[i]")
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
speedspace_cache["NS_[i]"] = im
MA.overlays = list(im)
speedspace_cache["NS_[i]"] = MA
// EAST/WEST
MA = new(normal_space)
im = image('icons/turf/space_dust_transit.dmi', "speedspace_ew_[i]")
im.plane = DUST_PLANE
im.blend_mode = BLEND_ADD
speedspace_cache["EW_[i]"] = im
MA.overlays = list(im)
speedspace_cache["EW_[i]"] = MA
//Over-the-edge images
for (var/dir in alldirs)
var/image/I = image('icons/turf/space.dmi', "white")
var/mutable_appearance/MA = new(normal_space)
var/matrix/M = matrix()
var/horizontal = (dir & (WEST|EAST))
var/vertical = (dir & (NORTH|SOUTH))
M.Scale(horizontal ? 8 : 1, vertical ? 8 : 1)
I.transform = M
I.appearance_flags = KEEP_APART | TILE_BOUND
I.plane = SPACE_PLANE
I.layer = 0
MA.transform = M
MA.appearance_flags = KEEP_APART | TILE_BOUND
MA.plane = SPACE_PLANE
MA.layer = 0
if(dir & NORTH)
I.pixel_y = 112
MA.pixel_y = 112
else if(dir & SOUTH)
I.pixel_y = -112
MA.pixel_y = -112
if(dir & EAST)
I.pixel_x = 112
MA.pixel_x = 112
else if(dir & WEST)
I.pixel_x = -112
MA.pixel_x = -112
mapedge_cache["[dir]"] = I
//Shuffle some lists
phase_shift_by_x = get_cross_shift_list(15)
phase_shift_by_y = get_cross_shift_list(15)
mapedge_cache["[dir]"] = MA
. = ..()
@@ -68,11 +92,6 @@ SUBSYSTEM_DEF(skybox)
/datum/controller/subsystem/skybox/proc/get_skybox(z)
if(!skybox_cache["[z]"])
skybox_cache["[z]"] = generate_skybox(z)
if(global.using_map.use_overmap)
var/obj/effect/overmap/visitable/O = map_sectors["[z]"]
if(istype(O))
for(var/zlevel in O.map_z)
skybox_cache["[zlevel]"] = skybox_cache["[z]"]
return skybox_cache["[z]"]
/datum/controller/subsystem/skybox/proc/generate_skybox(z)
@@ -92,7 +111,7 @@ SUBSYSTEM_DEF(skybox)
res.overlays += base
if(global.using_map.use_overmap && settings.use_overmap_details)
var/obj/effect/overmap/visitable/O = map_sectors["[z]"]
var/obj/effect/overmap/visitable/O = get_overmap_sector(z)
if(istype(O))
var/image/overmap = image(settings.icon)
overmap.overlays += O.generate_skybox()
@@ -114,6 +133,10 @@ SUBSYSTEM_DEF(skybox)
skybox_cache["[z]"] = generate_skybox(z)
for(var/client/C)
var/their_z = get_z(C.mob)
if(!their_z) //Nullspace
continue
if(their_z in zlevels)
C.update_skybox(1)
// Settings datum that maps can override to play with their skyboxes

View File

@@ -0,0 +1,559 @@
//
// Ticker controls the state of the game, being responsible for round start, game mode, and round end.
//
SUBSYSTEM_DEF(ticker)
name = "Gameticker"
wait = 2 SECONDS
init_order = INIT_ORDER_TICKER
priority = FIRE_PRIORITY_TICKER
flags = SS_NO_TICK_CHECK | SS_KEEP_TIMING
runlevels = RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME // Every runlevel!
var/const/restart_timeout = 3 MINUTES // Default time to wait before rebooting in desiseconds.
var/current_state = GAME_STATE_INIT // We aren't even at pregame yet // TODO replace with CURRENT_GAME_STATE
/* Relies upon the following globals (TODO move those in here) */
// var/master_mode = "extended" //The underlying game mode (so "secret" or the voted mode).
// Set by SSvote when VOTE_GAMEMODE finishes.
// var/round_progressing = 1 //Whether the lobby clock is ticking down.
var/pregame_timeleft = 0 // Time remaining until game starts in seconds. Set by config
var/start_immediately = FALSE // If true there is no lobby phase, the game starts immediately.
var/hide_mode = FALSE // If the true game mode should be hidden (because we chose "secret")
var/datum/game_mode/mode = null // The actual gamemode, if selected.
var/end_game_state = END_GAME_NOT_OVER // Track where we are ending game/round
var/restart_timeleft // Time remaining until restart in desiseconds
var/last_restart_notify // world.time of last restart warning.
var/delay_end = FALSE // If set, the round will not restart on its own.
// var/login_music // music played in pregame lobby // VOREStation Edit - We do music differently
var/list/datum/mind/minds = list() // The people in the game. Used for objective tracking.
// TODO - I am sure there is a better place these can go.
var/Bible_icon_state // icon_state the chaplain has chosen for his bible
var/Bible_item_state // item_state the chaplain has chosen for his bible
var/Bible_name // name of the bible
var/Bible_deity_name
var/random_players = FALSE // If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
// TODO - Should this go here or in the job subsystem?
var/triai = FALSE // Global flag for Triumvirate AI being enabled
//station_explosion used to be a variable for every mob's hud. Which was a waste!
//Now we have a general cinematic centrally held within the gameticker....far more efficient!
var/obj/screen/cinematic = null
// This global variable exists for legacy support so we don't have to rename every 'ticker' to 'SSticker' yet.
var/global/datum/controller/subsystem/ticker/ticker
/datum/controller/subsystem/ticker/PreInit()
global.ticker = src // TODO - Remove this! Change everything to point at SSticker intead
/datum/controller/subsystem/ticker/Initialize()
pregame_timeleft = config.pregame_time
send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]")
return ..()
/datum/controller/subsystem/ticker/fire(resumed = FALSE)
switch(current_state)
if(GAME_STATE_INIT)
pregame_welcome()
current_state = GAME_STATE_PREGAME
if(GAME_STATE_PREGAME)
pregame_tick()
if(GAME_STATE_SETTING_UP)
setup_tick()
if(GAME_STATE_PLAYING)
playing_tick()
if(GAME_STATE_FINISHED)
post_game_tick()
/datum/controller/subsystem/ticker/proc/pregame_welcome()
to_chat(world, "<B><FONT color='blue'>Welcome to the pregame lobby!</FONT></B>")
to_chat(world, "Please set up your character and select ready. The round will start in [pregame_timeleft] seconds.")
// Called during GAME_STATE_PREGAME (RUNLEVEL_LOBBY)
/datum/controller/subsystem/ticker/proc/pregame_tick()
if(round_progressing && last_fire)
pregame_timeleft -= (world.time - last_fire) / (1 SECOND)
if(start_immediately)
pregame_timeleft = 0
else if(SSvote.time_remaining)
return // vote still going, wait for it.
// Time to start the game!
if(pregame_timeleft <= 0)
current_state = GAME_STATE_SETTING_UP
Master.SetRunLevel(RUNLEVEL_SETUP)
if(start_immediately)
fire() // Don't wait for next tick, do it now!
return
if(pregame_timeleft <= config.vote_autogamemode_timeleft && !SSvote.gamemode_vote_called)
SSvote.autogamemode() // Start the game mode vote (if we haven't had one already)
// Called during GAME_STATE_SETTING_UP (RUNLEVEL_SETUP)
/datum/controller/subsystem/ticker/proc/setup_tick(resumed = FALSE)
if(!setup_choose_gamemode())
// It failed, go back to lobby state and re-send the welcome message
pregame_timeleft = config.pregame_time
SSvote.gamemode_vote_called = FALSE // Allow another autogamemode vote
current_state = GAME_STATE_PREGAME
Master.SetRunLevel(RUNLEVEL_LOBBY)
pregame_welcome()
return
// If we got this far we succeeded in picking a game mode. Punch it!
setup_startgame()
return
// Formerly the first half of setup() - The part that chooses the game mode.
// Returns 0 if failed to pick a mode, otherwise 1
/datum/controller/subsystem/ticker/proc/setup_choose_gamemode()
//Create and announce mode
if(master_mode == "secret")
src.hide_mode = TRUE
var/list/runnable_modes = config.get_runnable_modes()
if((master_mode == "random") || (master_mode == "secret"))
if(!runnable_modes.len)
to_chat(world, "<B>Unable to choose playable game mode.</B> Reverting to pregame lobby.")
return 0
if(secret_force_mode != "secret")
src.mode = config.pick_mode(secret_force_mode)
if(!src.mode)
var/list/weighted_modes = list()
for(var/datum/game_mode/GM in runnable_modes)
weighted_modes[GM.config_tag] = config.probabilities[GM.config_tag]
src.mode = gamemode_cache[pickweight(weighted_modes)]
else
src.mode = config.pick_mode(master_mode)
if(!src.mode)
to_chat(world, "<span class='danger'>Serious error in mode setup!</span> Reverting to pregame lobby.") //Uses setup instead of set up due to computational context.
return 0
job_master.ResetOccupations()
src.mode.create_antagonists()
src.mode.pre_setup()
job_master.DivideOccupations() // Apparently important for new antagonist system to register specific job antags properly.
if(!src.mode.can_start())
to_world("<B>Unable to start [mode.name].</B> Not enough players readied, [config.player_requirements[mode.config_tag]] players needed. Reverting to pregame lobby.")
mode.fail_setup()
mode = null
job_master.ResetOccupations()
return 0
if(hide_mode)
to_world("<B>The current game mode is - Secret!</B>")
if(runnable_modes.len)
var/list/tmpmodes = new
for (var/datum/game_mode/M in runnable_modes)
tmpmodes+=M.name
tmpmodes = sortList(tmpmodes)
if(tmpmodes.len)
to_chat(world, "<B>Possibilities:</B> [english_list(tmpmodes, and_text= "; ", comma_text = "; ")]")
else
src.mode.announce()
return 1
// Formerly the second half of setup() - The part that actually initializes everything and starts the game.
/datum/controller/subsystem/ticker/proc/setup_startgame()
setup_economy()
create_characters() //Create player characters and transfer them.
collect_minds()
equip_characters()
//data_core.manifest() //VOREStation Removal
callHook("roundstart")
spawn(0)//Forking here so we dont have to wait for this to finish
mode.post_setup()
//Cleanup some stuff
for(var/obj/effect/landmark/start/S in landmarks_list)
//Deleting Startpoints but we need the ai point to AI-ize people later
if (S.name != "AI")
qdel(S)
to_chat(world, "<FONT color='blue'><B>Enjoy the game!</B></FONT>")
world << sound('sound/AI/welcome.ogg') // Skie
//Holiday Round-start stuff ~Carn
Holiday_Game_Start()
var/list/adm = get_admin_counts()
if(adm["total"] == 0)
send2adminirc("A round has started with no admins online.")
/* supply_controller.process() //Start the supply shuttle regenerating points -- TLE // handled in scheduler
master_controller.process() //Start master_controller.process()
lighting_controller.process() //Start processing DynamicAreaLighting updates
*/
current_state = GAME_STATE_PLAYING
Master.SetRunLevel(RUNLEVEL_GAME)
if(config.sql_enabled)
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
return 1
// Called during GAME_STATE_PLAYING (RUNLEVEL_GAME)
/datum/controller/subsystem/ticker/proc/playing_tick(resumed = FALSE)
mode.process() // So THIS is where we run mode.process() huh? Okay
if(mode.explosion_in_progress)
return // wait until explosion is done.
// Calculate if game and/or mode are finished (Complicated by the continuous_rounds config option)
var/game_finished = FALSE
var/mode_finished = FALSE
if (config.continous_rounds) // Game keeps going after mode ends.
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
mode_finished = ((end_game_state >= END_GAME_MODE_FINISHED) || mode.check_finished()) // Short circuit if already finished.
else // Game ends when mode does
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || universe_has_ended
mode_finished = game_finished
if(game_finished && mode_finished)
end_game_state = END_GAME_READY_TO_END
current_state = GAME_STATE_FINISHED
Master.SetRunLevel(RUNLEVEL_POSTGAME)
INVOKE_ASYNC(src, .proc/declare_completion)
else if (mode_finished && (end_game_state < END_GAME_MODE_FINISHED))
end_game_state = END_GAME_MODE_FINISHED // Only do this cleanup once!
mode.cleanup()
//call a transfer shuttle vote
to_chat(world, "<span class='danger'>The round has ended!</span>")
SSvote.autotransfer()
// Called during GAME_STATE_FINISHED (RUNLEVEL_POSTGAME)
/datum/controller/subsystem/ticker/proc/post_game_tick()
switch(end_game_state)
if(END_GAME_READY_TO_END)
callHook("roundend")
if (mode.station_was_nuked)
feedback_set_details("end_proper", "nuke")
restart_timeleft = 1 MINUTE // No point waiting five minutes if everyone's dead.
if(!delay_end)
to_chat(world, "<span class='notice'><b>Rebooting due to destruction of [station_name()] in [round(restart_timeleft/600)] minute\s.</b></span>")
last_restart_notify = world.time
else
feedback_set_details("end_proper", "proper completion")
restart_timeleft = restart_timeout
if(blackbox)
blackbox.save_all_data_to_sql() // TODO - Blackbox or statistics subsystem
end_game_state = END_GAME_ENDING
return
if(END_GAME_ENDING)
restart_timeleft -= (world.time - last_fire)
if(delay_end)
to_chat(world, "<span class='notice'><b>An admin has delayed the round end.</b></span>")
end_game_state = END_GAME_DELAYED
else if(restart_timeleft <= 0)
world.Reboot()
else if (world.time - last_restart_notify >= 1 MINUTE)
to_chat(world, "<span class='notice'><b>Restarting in [round(restart_timeleft/600, 1)] minute\s.</b></span>")
last_restart_notify = world.time
return
if(END_GAME_DELAYED)
restart_timeleft -= (world.time - last_fire)
if(!delay_end)
end_game_state = END_GAME_ENDING
else
log_error("Ticker arrived at round end in an unexpected endgame state '[end_game_state]'.")
end_game_state = END_GAME_READY_TO_END
// ----------------------------------------------------------------------
// These two below are not used! But they could be
// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem!
/datum/controller/subsystem/ticker/proc/PreRoundStart()
return (current_state < GAME_STATE_PLAYING)
/datum/controller/subsystem/ticker/proc/IsSettingUp()
return (current_state == GAME_STATE_SETTING_UP)
/datum/controller/subsystem/ticker/proc/IsRoundInProgress()
return (current_state == GAME_STATE_PLAYING)
/datum/controller/subsystem/ticker/proc/HasRoundStarted()
return (current_state >= GAME_STATE_PLAYING)
// ------------------------------------------------------------------------
// HELPER PROCS!
// ------------------------------------------------------------------------
//Plus it provides an easy way to make cinematics for other events. Just use this as a template :)
/datum/controller/subsystem/ticker/proc/station_explosion_cinematic(var/station_missed=0, var/override = null)
if( cinematic ) return //already a cinematic in progress!
//initialise our cinematic screen object
cinematic = new(src)
cinematic.icon = 'icons/effects/station_explosion.dmi'
cinematic.icon_state = "station_intact"
cinematic.layer = 100
cinematic.plane = PLANE_PLAYER_HUD
cinematic.mouse_opacity = 0
cinematic.screen_loc = "1,0"
var/obj/structure/bed/temp_buckle = new(src)
//Incredibly hackish. It creates a bed within the gameticker (lol) to stop mobs running around
if(station_missed)
for(var/mob/living/M in living_mob_list)
M.buckled = temp_buckle //buckles the mob so it can't do anything
if(M.client)
M.client.screen += cinematic //show every client the cinematic
else //nuke kills everyone on z-level 1 to prevent "hurr-durr I survived"
for(var/mob/living/M in living_mob_list)
M.buckled = temp_buckle
if(M.client)
M.client.screen += cinematic
switch(M.z)
if(0) //inside a crate or something
var/turf/T = get_turf(M)
if(T && T.z in using_map.station_levels) //we don't use M.death(0) because it calls a for(/mob) loop and
M.health = 0
M.set_stat(DEAD)
if(1) //on a z-level 1 turf.
M.health = 0
M.set_stat(DEAD)
//Now animate the cinematic
switch(station_missed)
if(1) //nuke was nearby but (mostly) missed
if( mode && !override )
override = mode.name
switch( override )
if("mercenary") //Nuke wasn't on station when it blew up
flick("intro_nuke",cinematic)
sleep(35)
world << sound('sound/effects/explosionfar.ogg')
flick("station_intact_fade_red",cinematic)
cinematic.icon_state = "summary_nukefail"
else
flick("intro_nuke",cinematic)
sleep(35)
world << sound('sound/effects/explosionfar.ogg')
//flick("end",cinematic)
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
sleep(50)
world << sound('sound/effects/explosionfar.ogg')
else //station was destroyed
if( mode && !override )
override = mode.name
switch( override )
if("mercenary") //Nuke Ops successfully bombed the station
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_nukewin"
if("AI malfunction") //Malf (screen,explosion,summary)
flick("intro_malf",cinematic)
sleep(76)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_malf"
if("blob") //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red",cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_selfdes"
else //Station nuked (nuke,explosion,summary)
flick("intro_nuke",cinematic)
sleep(35)
flick("station_explode_fade_red", cinematic)
world << sound('sound/effects/explosionfar.ogg')
cinematic.icon_state = "summary_selfdes"
for(var/mob/living/M in living_mob_list)
if(M.loc.z in using_map.station_levels)
M.death()//No mercy
//If its actually the end of the round, wait for it to end.
//Otherwise if its a verb it will continue on afterwards.
sleep(300)
if(cinematic) qdel(cinematic) //end the cinematic
if(temp_buckle) qdel(temp_buckle) //release everybody
return
/datum/controller/subsystem/ticker/proc/create_characters()
for(var/mob/new_player/player in player_list)
if(player && player.ready && player.mind)
if(player.mind.assigned_role=="AI")
player.close_spawn_windows()
player.AIize()
else if(!player.mind.assigned_role)
continue
else
//VOREStation Edit Start
var/mob/living/carbon/human/new_char = player.create_character()
if(new_char)
qdel(player)
if(istype(new_char) && !(new_char.mind.assigned_role=="Cyborg"))
data_core.manifest_inject(new_char)
//VOREStation Edit End
/datum/controller/subsystem/ticker/proc/collect_minds()
for(var/mob/living/player in player_list)
if(player.mind)
minds += player.mind
/datum/controller/subsystem/ticker/proc/equip_characters()
var/captainless=1
for(var/mob/living/carbon/human/player in player_list)
if(player && player.mind && player.mind.assigned_role)
if(player.mind.assigned_role == "Colony Director")
captainless=0
if(!player_is_antag(player.mind, only_offstation_roles = 1))
job_master.EquipRank(player, player.mind.assigned_role, 0)
UpdateFactionList(player)
//equip_custom_items(player) //VOREStation Removal
//player.apply_traits() //VOREStation Removal
if(captainless)
for(var/mob/M in player_list)
if(!istype(M,/mob/new_player))
to_chat(M, "Colony Directorship not forced on anyone.")
/datum/controller/subsystem/ticker/proc/declare_completion()
to_world("<br><br><br><H1>A round of [mode.name] has ended!</H1>")
for(var/mob/Player in player_list)
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD)
var/turf/playerTurf = get_turf(Player)
if(emergency_shuttle.departed && emergency_shuttle.evac)
if(isNotAdminLevel(playerTurf.z))
to_chat(Player, "<font color='blue'><b>You survived the round, but remained on [station_name()] as [Player.real_name].</b></font>")
else
to_chat(Player, "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></font>")
else if(isAdminLevel(playerTurf.z))
to_chat(Player, "<font color='green'><b>You successfully underwent crew transfer after events on [station_name()] as [Player.real_name].</b></font>")
else if(issilicon(Player))
to_chat(Player, "<font color='green'><b>You remain operational after the events on [station_name()] as [Player.real_name].</b></font>")
else
to_chat(Player, "<font color='blue'><b>You missed the crew transfer after the events on [station_name()] as [Player.real_name].</b></font>")
else
if(istype(Player,/mob/observer/dead))
var/mob/observer/dead/O = Player
if(!O.started_as_observer)
to_chat(Player, "<font color='red'><b>You did not survive the events on [station_name()]...</b></font>")
else
to_chat(Player, "<font color='red'><b>You did not survive the events on [station_name()]...</b></font>")
to_world("<br>")
for (var/mob/living/silicon/ai/aiPlayer in mob_list)
if (aiPlayer.stat != 2)
to_world("<b>[aiPlayer.name] (Played by: [aiPlayer.key])'s laws at the end of the round were:</b>")
else
to_world("<b>[aiPlayer.name] (Played by: [aiPlayer.key])'s laws when it was deactivated were:</b>")
aiPlayer.show_laws(1)
if (aiPlayer.connected_robots.len)
var/robolist = "<b>The AI's loyal minions were:</b> "
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.key]), ":" (Played by: [robo.key]), "]"
to_world("[robolist]")
var/dronecount = 0
for (var/mob/living/silicon/robot/robo in mob_list)
if(istype(robo,/mob/living/silicon/robot/drone) && !istype(robo,/mob/living/silicon/robot/drone/swarm))
dronecount++
continue
if (!robo.connected_ai)
if (robo.stat != 2)
to_world("<b>[robo.name] (Played by: [robo.key]) survived as an AI-less stationbound synthetic! Its laws were:</b>")
else
to_world("<b>[robo.name] (Played by: [robo.key]) was unable to survive the rigors of being a stationbound synthetic without an AI. Its laws were:</b>")
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
robo.laws.show_laws(world)
if(dronecount)
to_world("<b>There [dronecount>1 ? "were" : "was"] [dronecount] industrious maintenance [dronecount>1 ? "drones" : "drone"] at the end of this round.</b>")
mode.declare_completion()//To declare normal completion.
//Ask the event manager to print round end information
SSevents.RoundEnd()
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
for(var/datum/mind/Mind in minds)
var/temprole = Mind.special_role
if(temprole) //if they are an antagonist of some sort.
if(temprole in total_antagonists) //If the role exists already, add the name to it
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
else
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
//Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
return 1
/datum/controller/subsystem/ticker/stat_entry()
switch(current_state)
if(GAME_STATE_INIT)
..()
if(GAME_STATE_PREGAME) // RUNLEVEL_LOBBY
..("START [round_progressing ? "[round(pregame_timeleft)]s" : "(PAUSED)"]")
if(GAME_STATE_SETTING_UP) // RUNLEVEL_SETUP
..("SETUP")
if(GAME_STATE_PLAYING) // RUNLEVEL_GAME
..("GAME")
if(GAME_STATE_FINISHED) // RUNLEVEL_POSTGAME
switch(end_game_state)
if(END_GAME_MODE_FINISHED)
..("MODE OVER, WAITING")
if(END_GAME_READY_TO_END)
..("ENDGAME PROCESSING")
if(END_GAME_ENDING)
..("END IN [round(restart_timeleft/10)]s")
if(END_GAME_DELAYED)
..("END PAUSED")
else
..("ENDGAME ERROR:[end_game_state]")
/datum/controller/subsystem/ticker/Recover()
flags |= SS_NO_INIT // Don't initialize again
current_state = SSticker.current_state
mode = SSticker.mode
pregame_timeleft = SSticker.pregame_timeleft
end_game_state = SSticker.end_game_state
delay_end = SSticker.delay_end
restart_timeleft = SSticker.restart_timeleft
minds = SSticker.minds
Bible_icon_state = SSticker.Bible_icon_state
Bible_item_state = SSticker.Bible_item_state
Bible_name = SSticker.Bible_name
Bible_deity_name = SSticker.Bible_deity_name
random_players = SSticker.random_players

View File

@@ -13,6 +13,7 @@ SUBSYSTEM_DEF(vote)
var/duration
var/mode
var/question
var/gamemode_vote_called = FALSE // Have we had a gamemode vote this round? Only auto-call if we haven't
var/list/choices = list()
var/list/gamemode_names = list()
var/list/voted = list()
@@ -254,9 +255,11 @@ SUBSYSTEM_DEF(vote)
to_world("<font color='purple'><b>[text]</b>\nType <b>vote</b> or click <a href='?src=\ref[src]'>here</a> to place your votes.\nYou have [config.vote_period / 10] seconds to vote.</font>")
if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM)
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
world << sound('sound/misc/notice1.ogg', repeat = 0, wait = 0, volume = 50, channel = 3) //YW Edit
if(mode == VOTE_GAMEMODE && round_progressing)
gamemode_vote_called = TRUE
round_progressing = 0
to_world("<font color='red'><b>Round start has been delayed.</b></font>")
@@ -350,6 +353,7 @@ SUBSYSTEM_DEF(vote)
if("cancel")
if(usr.client.holder)
if("Yes" == alert(usr, "You are about to cancel this vote. Are you sure?", "Cancel Vote", "No", "Yes"))
reset()
if("toggle_restart")
if(usr.client.holder)

View File

@@ -89,8 +89,6 @@
//Goon PS stuff, and other yet-to-be-subsystem things.
options["LEGACY: master_controller"] = master_controller
options["LEGACY: ticker"] = ticker
options["LEGACY: tickerProcess"] = tickerProcess
options["LEGACY: air_master"] = air_master
options["LEGACY: job_master"] = job_master
options["LEGACY: radio_controller"] = radio_controller
@@ -110,28 +108,3 @@
feedback_add_details("admin_verb", "DebugController")
message_admins("Admin [key_name_admin(mob)] is debugging the [pick] controller.")
debug_variables(D)
//VOREStation Edit Begin
/client/proc/debug_process_scheduler()
set category = "Debug"
set name = "Debug Process Scheduler"
set desc = "Debug the process scheduler itself. For vulpine use only."
if(!check_rights(R_DEBUG)) return
if(config.debugparanoid && !check_rights(R_ADMIN)) return
debug_variables(processScheduler)
feedback_add_details("admin_verb", "DProcSchd")
message_admins("Admin [key_name_admin(usr)] is debugging the process scheduler.")
/client/proc/debug_process(controller in processScheduler.nameToProcessMap)
set category = "Debug"
set name = "Debug Process Controller"
set desc = "Debug one of the periodic loop background task controllers for the game (be careful!)"
if(!check_rights(R_DEBUG)) return
if(config.debugparanoid && !check_rights(R_ADMIN)) return
var/datum/controller/process/P = processScheduler.nameToProcessMap[controller]
debug_variables(P)
feedback_add_details("admin_verb", "DProcCtrl")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
//VOREStation Edit End

View File

@@ -0,0 +1,344 @@
/datum/design/item/autolathe
var/hidden = 0
build_type = AUTOLATHE //Flag as to what kind machine the design is built in. See defines.
/datum/design/item/autolathe/arms //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "Arms and Ammunition" //category item goes to
////////////////
/*Ammo casings*/
////////////////
//Shotgun
/datum/design/item/autolathe/arms/shotgun_blanks
name = "ammunition (12g, blank)"
id = "shotgun_blanks"
build_path = /obj/item/ammo_casing/a12g/blank
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 112)
/datum/design/item/autolathe/arms/shotgun_beanbag
name = "ammunition (12g, beanbag)"
id = "shotgun_beanbag"
build_path = /obj/item/ammo_casing/a12g/beanbag
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 225)
/datum/design/item/autolathe/arms/shotgun_flash
name = "ammunition (12g, flash)"
id = "shotgun_flash"
build_path = /obj/item/ammo_casing/a12g/flash
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 112, "glass" = 112)
/datum/design/item/autolathe/arms/shotgun_slug
name = "ammunition (12g, slug)"
id = "shotgun_slug"
build_path = /obj/item/ammo_casing/a12g
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 450)
hidden = 1
/datum/design/item/autolathe/arms/shotgun_pellet
name = "ammunition (12g, pellet)"
id = "shotgun_pellet"
build_path = /obj/item/ammo_casing/a12g/pellet
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 450)
hidden = 1
/datum/design/item/autolathe/arms/stunshell
name = "ammunition (stun cartridge, shotgun)"
id = "shotgun_stunshell"
build_path = /obj/item/ammo_casing/a12g/stunshell
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 450, "glass" = 900)
hidden = 1
//////////////////
/*Ammo magazines*/
//////////////////
/////// .45
/datum/design/item/autolathe/arms/pistol_45
name = "pistol magazine (.45)"
id = "pistol_45"
build_path = /obj/item/ammo_magazine/m45
time = 10
materials = list(DEFAULT_WALL_MATERIAL = 656)
hidden = 1
/datum/design/item/autolathe/arms/pistol_45p
name = "pistol magazine (.45 practice)"
id = "pistol_45p"
build_path = /obj/item/ammo_magazine/m45/practice
materials = list(DEFAULT_WALL_MATERIAL = 656)
/datum/design/item/autolathe/arms/pistol_45r
name = "pistol magazine (.45 rubber)"
id = "pistol_45r"
build_path = /obj/item/ammo_magazine/m45/rubber
materials = list(DEFAULT_WALL_MATERIAL = 656)
/datum/design/item/autolathe/arms/pistol_45f
name = "pistol magazine (.45 flash)"
id = "pistol_45f"
build_path = /obj/item/ammo_magazine/m45/flash
materials = list(DEFAULT_WALL_MATERIAL = 656)
/datum/design/item/autolathe/arms/pistol_45uzi
name = "uzi magazine (.45)"
id = "pistol_45uzi"
build_path = /obj/item/ammo_magazine/m45uzi
materials = list(DEFAULT_WALL_MATERIAL = 656)
hidden = 1
/datum/design/item/autolathe/arms/tommymag
name = "Tommy Gun magazine (.45)"
id = "tommymag"
build_path = /obj/item/ammo_magazine/m45tommy
materials = list(DEFAULT_WALL_MATERIAL = 1875)
hidden = 1
/datum/design/item/autolathe/arms/tommydrum
name = "Tommy Gun drum magazine (.45)"
id = "tommydrum"
build_path = /obj/item/ammo_magazine/m45tommydrum
materials = list(DEFAULT_WALL_MATERIAL = 4687)
hidden = 1
/////// 9mm
// Full size pistol mags.
/datum/design/item/autolathe/arms/pistol_9mm
name = "pistol magazine (9mm)"
id = "pistol_9mm"
build_path = /obj/item/ammo_magazine/m9mm
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/datum/design/item/autolathe/arms/pistol_9mmr
name = "pistol magazine (9mm rubber)"
id = "pistol_9mm_rubber"
build_path = /obj/item/ammo_magazine/m9mm/rubber
materials = list(DEFAULT_WALL_MATERIAL = 750)
/datum/design/item/autolathe/arms/pistol_9mmp
name = "pistol magazine (9mm practice)"
id = "pistol_9mm_practice"
build_path = /obj/item/ammo_magazine/m9mm/practice
materials = list(DEFAULT_WALL_MATERIAL = 750)
/datum/design/item/autolathe/arms/pistol_9mmf
name = "pistol magazine (9mm flash)"
id = "pistol_9mm_flash"
build_path = /obj/item/ammo_magazine/m9mm/flash
materials = list(DEFAULT_WALL_MATERIAL = 750)
/datum/design/item/autolathe/arms/pistol_9mm_compact
name = "compact pistol magazine (9mm)"
id = "pistol_9mm_compact"
build_path = /obj/item/ammo_magazine/m9mm/compact
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/datum/design/item/autolathe/arms/pistol_9mmr_compact
name = "compact pistol magazine (9mm rubber)"
id = "pistol_9mm_compact_rubber"
build_path = /obj/item/ammo_magazine/m9mm/compact/rubber
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/datum/design/item/autolathe/arms/pistol_9mmp_compact
name = "compact pistol magazine (9mm)"
id = "pistol_9mm_compact_practice"
build_path = /obj/item/ammo_magazine/m9mm/compact/practice
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/datum/design/item/autolathe/arms/pistol_9mmf_compact
name = "compact pistol magazine (9mm)"
id = "pistol_9mm_compact_flash"
build_path = /obj/item/ammo_magazine/m9mm/compact/flash
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/////// SMG Mags
/datum/design/item/autolathe/arms/smg_9mm
name = "top-mounted SMG magazine (9mm)"
id = "smg_9mm"
build_path = /obj/item/ammo_magazine/m9mmt
materials = list(DEFAULT_WALL_MATERIAL = 750)
hidden = 1
/datum/design/item/autolathe/arms/smg_9mmr
name = "top-mounted SMG magazine (9mm rubber)"
id = "smg_9mmr"
build_path = /obj/item/ammo_magazine/m9mmt/rubber
materials = list(DEFAULT_WALL_MATERIAL = 380)
/datum/design/item/autolathe/arms/smg_9mmp
name = "top-mounted SMG magazine (9mm practice)"
id = "smg_9mmp"
build_path = /obj/item/ammo_magazine/m9mmt/practice
materials = list(DEFAULT_WALL_MATERIAL = 380)
/datum/design/item/autolathe/arms/smg_9mmf
name = "top-mounted SMG magazine (9mm flash)"
id = "smg_9mmf"
build_path = /obj/item/ammo_magazine/m9mmt/flash
materials = list(DEFAULT_WALL_MATERIAL = 380)
/////// 10mm
/datum/design/item/autolathe/arms/smg_10mm
name = "SMG magazine (10mm)"
id = "smg_10mm"
build_path = /obj/item/ammo_magazine/m10mm
materials = list(DEFAULT_WALL_MATERIAL = 1875)
/////// 5.45mm
/datum/design/item/autolathe/arms/rifle_545
name = "rifle magazine (5.45mm)"
id = "rifle_545"
build_path = /obj/item/ammo_magazine/m545
materials = list(DEFAULT_WALL_MATERIAL = 2250)
hidden = 1
/datum/design/item/autolathe/arms/rifle_545p
name = "rifle magazine (5.45mm practice)"
id = "rifle_545_practice"
build_path = /obj/item/ammo_magazine/m545/practice
materials = list(DEFAULT_WALL_MATERIAL = 2250)
/datum/design/item/autolathe/arms/machinegun_545
name = "machinegun box magazine (5.45)"
id = "machinegun_545"
build_path = /obj/item/ammo_magazine/m545saw
materials = list(DEFAULT_WALL_MATERIAL = 12500)
hidden = 1
/////// 7.62
/datum/design/item/autolathe/arms/rifle_762
name = "rifle magazine (7.62mm)"
id = "rifle_762"
build_path = /obj/item/ammo_magazine/m762
materials = list(DEFAULT_WALL_MATERIAL = 2500)
hidden = 1
/////// Shotgun
/datum/design/item/autolathe/arms/shotgun_clip_beanbag
name = "2-round 12g speedloader (beanbag)"
id = "shotgun_speedloader_beanbag"
build_path = /obj/item/ammo_magazine/clip/c12g/beanbag
materials = list(DEFAULT_WALL_MATERIAL = 887)
/datum/design/item/autolathe/arms/shotgun_clip_pellet
name = "2-round 12g speedloader (pellet)"
id = "shotgun_speedloader_pellet"
build_path = /obj/item/ammo_magazine/clip/c12g/pellet
materials = list(DEFAULT_WALL_MATERIAL = 1337)
hidden = 1
/datum/design/item/autolathe/arms/shotgun_clip_slug
name = "2-round 12g speedloader (slug)"
id = "shotgun_speedloader_slug"
build_path = /obj/item/ammo_magazine/clip/c12g
materials = list(DEFAULT_WALL_MATERIAL = 1337)
hidden = 1
///////////////////////////////
/*Ammo clips and Speedloaders*/
///////////////////////////////
/datum/design/item/autolathe/arms/speedloader_357
name = "speedloader (.357)"
id = "speedloader_357"
build_path = /obj/item/ammo_magazine/s357
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_38
name = "speedloader (.38)"
id = "speedloader_38"
build_path = /obj/item/ammo_magazine/s38
materials = list(DEFAULT_WALL_MATERIAL = 450)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_38r
name = "speedloader (.38 rubber)"
id = "speedloader_38_rubber"
build_path = /obj/item/ammo_magazine/s38/rubber
materials = list(DEFAULT_WALL_MATERIAL = 450)
/datum/design/item/autolathe/arms/speedloader_45
name = "speedloader (.45)"
id = "speedloader_45"
build_path = /obj/item/ammo_magazine/s45
materials = list(DEFAULT_WALL_MATERIAL = 656)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_45r
name = "speedloader (.45 rubber)"
id = "speedloader_45_rubber"
build_path = /obj/item/ammo_magazine/s45/rubber
materials = list(DEFAULT_WALL_MATERIAL = 656)
/datum/design/item/autolathe/arms/rifle_clip_545
name = "ammo clip (5.45mm)"
id = "rifle_clip_545"
build_path = /obj/item/ammo_magazine/clip/c545
materials = list(DEFAULT_WALL_MATERIAL = 565)
hidden = 1
/datum/design/item/autolathe/arms/rifle_clip_545_practice
name = "ammo clip (5.45mm practice)"
id = "rifle_clip_545p"
build_path = /obj/item/ammo_magazine/clip/c545/practice
materials = list(DEFAULT_WALL_MATERIAL = 565)
/datum/design/item/autolathe/arms/rifle_clip_762
name = "ammo clip (7.62mm)"
id = "rifle_clip_762"
build_path = /obj/item/ammo_magazine/clip/c762
materials = list(DEFAULT_WALL_MATERIAL = 1250)
hidden = 1
/datum/design/item/autolathe/arms/rifle_clip_762_practice
name = "ammo clip (7.62mm practice)"
id = "rifle_clip_762p"
build_path = /obj/item/ammo_magazine/clip/c762/practice
materials = list(DEFAULT_WALL_MATERIAL = 1250)
/datum/design/item/autolathe/arms/knuckledusters
name = "knuckle dusters"
id = "knuckledusters"
build_path = /obj/item/clothing/gloves/knuckledusters
materials = list(DEFAULT_WALL_MATERIAL = 625)
hidden = 1
/datum/design/item/autolathe/arms/tacknife
name = "tactical knife"
id = "tacknife"
build_path = /obj/item/weapon/material/knife/tacknife
materials = list(DEFAULT_WALL_MATERIAL = 625)
hidden = 1
/datum/design/item/autolathe/arms/flamethrower
name = "flamethrower"
id = "flamethrower"
build_path = /obj/item/weapon/flamethrower/full
materials = list(DEFAULT_WALL_MATERIAL = 625)
hidden = 1

View File

@@ -0,0 +1,56 @@
/datum/design/item/autolathe/arms/speedloader_357_flash
name = "speedloader (.357 flash)"
id = "speedloader_357f"
build_path = /obj/item/ammo_magazine/s357/flash
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_357_stun
name = "speedloader (.357 stun)"
id = "speedloader_357s"
build_path = /obj/item/ammo_magazine/s357/stun
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_357_rubber
name = "speedloader (.357 rubber)"
id = "speedloader_357r"
build_path = /obj/item/ammo_magazine/s357/rubber
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_44
name = "speedloader (.44)"
id = "speedloader_44"
build_path = /obj/item/ammo_magazine/s44
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/speedloader_44_rubber
name = "speedloader (.44)"
id = "speedloader_44r"
build_path = /obj/item/ammo_magazine/s44/rubber
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/mag_44
name = "magazine (.44)"
id = "mag_44"
build_path = /obj/item/ammo_magazine/m44
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/mag_44_rubber
name = "magazine (.44 rubber)"
id = "mag_44r"
build_path = /obj/item/ammo_magazine/m44/rubber
materials = list(DEFAULT_WALL_MATERIAL = 1575)
hidden = 1
/datum/design/item/autolathe/arms/classic_smg_9mm
name = "SMG magazine (9mm)"
id = "classic_smg_9mm"
build_path = /obj/item/ammo_magazine/m9mml
materials = list(DEFAULT_WALL_MATERIAL = 2250)
hidden = 1

View File

@@ -0,0 +1,74 @@
/datum/design/item/autolathe/arms/shotgun_scatter
name = "ammunition (12g, scatter)"
id = "shotgun_scatter"
build_path = /obj/item/ammo_casing/a12g/scatter
materials = list(DEFAULT_WALL_MATERIAL = 450)
hidden = 1
/datum/design/item/autolathe/arms/shotgun_clip_scatter
name = "2-round 12g speedloader (scatter)"
id = "shotgun_speedloader_scatter"
build_path = /obj/item/ammo_magazine/clip/c12g/scatter
materials = list(DEFAULT_WALL_MATERIAL = 1337)
hidden = 1
//printable boxes of shotgun ammo, by KK
//the prices are rounded up to the cost of nine shells, but compared to printing a bunch of speedloaders you get a small discount. honestly the speedloaders are overpriced (the metal frame is somehow more expensive than a third shell!) but take it up with polaris.
/datum/design/item/autolathe/arms/ammobox/shotgun_box_beanbag
name = "8-round 12g ammo box (beanbag)"
id = "shotgun_ammobox_beanbag"
build_path = /obj/item/weapon/storage/box/beanbags
materials = list(DEFAULT_WALL_MATERIAL = 2025)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_slugs
name = "8-round 12g ammo box (slug)"
id = "shotgun_ammobox_slug"
build_path = /obj/item/weapon/storage/box/shotgunammo
materials = list(DEFAULT_WALL_MATERIAL = 4050)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_pellet
name = "8-round 12g ammo box (pellet)"
id = "shotgun_ammobox_pellet"
build_path = /obj/item/weapon/storage/box/shotgunshells
materials = list(DEFAULT_WALL_MATERIAL = 4050)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_scatter
name = "8-round 12g ammo box (scatter)"
id = "shotgun_ammobox_scatter"
build_path = /obj/item/weapon/storage/box/scattershot
materials = list(DEFAULT_WALL_MATERIAL = 4050)
hidden = 1
//commented out, pending review, maybe 16rnd boxes should be cargo only?
/*
/datum/design/item/autolathe/arms/ammobox/shotgun_box_beanbag_large
name = "16-round 12g ammo box (beanbag)"
id = "shotgun_ammobox_beanbag_large"
build_path = /obj/item/weapon/storage/box/beanbags/large
materials = list(DEFAULT_WALL_MATERIAL = 4050)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_slugs_large
name = "16-round 12g ammo box (slug)"
id = "shotgun_ammobox_slug_large"
build_path = /obj/item/weapon/storage/box/shotgunammo/large
materials = list(DEFAULT_WALL_MATERIAL = 8100)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_pellet_large
name = "16-round 12g ammo box (pellet)"
id = "shotgun_ammobox_pellet_large"
build_path = /obj/item/weapon/storage/box/shotgunshells/large
materials = list(DEFAULT_WALL_MATERIAL = 8100)
hidden = 1
/datum/design/item/autolathe/arms/ammobox/shotgun_box_scatter_large
name = "16-round 12g ammo box (scatter)"
id = "shotgun_ammobox_scatter_large"
build_path = /obj/item/weapon/storage/box/scattershot/large
materials = list(DEFAULT_WALL_MATERIAL = 8100)
hidden = 1
*/

View File

@@ -0,0 +1,502 @@
#define AUTOLATHE_MAIN_MENU 1
#define AUTOLATHE_CATEGORY_MENU 2
#define AUTOLATHE_SEARCH_MENU 3
/obj/machinery/autolathe
name = "autolathe"
desc = "It produces items using metal and glass."
icon = 'icons/obj/stationobjs_vr.dmi'
icon_state = "autolathe"
density = 1
anchored = 1
use_power = USE_POWER_IDLE
idle_power_usage = 10
active_power_usage = 2000
clicksound = "keyboard"
clickvol = 30
circuit = /obj/item/weapon/circuitboard/autolathe
var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0)
var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0)
var/hacked = 0
var/disabled = 0
var/shocked = 0
var/busy = 0
var/operating = 0.0
var/list/queue = list()
var/queue_max_len = 12
var/turf/BuildTurf
var/list/L = list()
var/list/LL = list()
var/prod_coeff
var/list/being_built = list()
var/datum/research/files
var/mat_efficiency = 1
var/build_time = 50
var/list/datum/design/item/autolathe/matching_designs
var/temp_search
var/selected_category
var/screen = 1
var/list/categories = list("Arms and Ammunition", "Devices", "Engineering", "General", "Medical", "Tools")
var/datum/wires/autolathe/wires = null
/obj/machinery/autolathe/New()
..()
wires = new(src)
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
RefreshParts()
files = new /datum/research/autolathe(src)
matching_designs = list()
/obj/machinery/autolathe/Destroy()
qdel(wires)
wires = null
return ..()
/obj/machinery/autolathe/attack_hand(mob/user)
if(..() || (disabled && !panel_open))
to_chat(user, "<span class='danger'>\The [src] is disabled!</span>")
return
if(shocked)
shock(user, 50)
else
ui_interact(user)
/obj/machinery/autolathe/dismantle()
for(var/mat in stored_material)
var/material/M = get_material_by_name(mat)
if(!istype(M))
continue
var/obj/item/stack/material/S = new M.stack_type(get_turf(src))
if(stored_material[mat] > S.perunit)
S.amount = round(stored_material[mat] / S.perunit)
else
qdel(S)
..()
return 1
/obj/machinery/autolathe/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
user.set_machine(src)
var/data[0]
data["screen"] = screen
data["total_amount"] = (stored_material[DEFAULT_WALL_MATERIAL] + stored_material["glass"])
data["max_amount"] = (storage_capacity[DEFAULT_WALL_MATERIAL] + storage_capacity["glass"])
data["metal_amount"] = stored_material[DEFAULT_WALL_MATERIAL]
data["glass_amount"] = stored_material["glass"]
switch(screen)
if(AUTOLATHE_MAIN_MENU)
data["uid"] = "\ref[src]"
data["categories"] = categories
if(AUTOLATHE_CATEGORY_MENU)
data["selected_category"] = selected_category
var/list/designs = list()
data["designs"] = designs
for(var/datum/design/item/autolathe/D in files.known_designs)
if(!D.build_path || D.hidden && !hacked || selected_category != D.category)
continue
var/list/design = list()
designs[++designs.len] = design
design["name"] = D.name
design["id"] = D.id
design["disabled"] = disabled || !can_build(D) ? "disabled" : null
if(ispath(D.build_path, /obj/item/stack))
design["max_multiplier"] = min(D.maxstack, D.materials[DEFAULT_WALL_MATERIAL] ? round(stored_material[DEFAULT_WALL_MATERIAL] / D.materials[DEFAULT_WALL_MATERIAL]) : INFINITY, D.materials["glass"] ? round(stored_material["glass"] / D.materials["glass"]) : INFINITY)
else
design["max_multiplier"] = null
design["materials"] = design_cost_data(D)
if(AUTOLATHE_SEARCH_MENU)
data["search"] = temp_search
var/list/designs = list()
data["designs"] = designs
for(var/datum/design/item/autolathe/D in matching_designs)
var/list/design = list()
designs[++designs.len] = design
design["name"] = D.name
design["id"] = D.id
design["disabled"] = disabled || !can_build(D) ? "disabled" : null
if(ispath(D.build_path, /obj/item/stack))
design["max_multiplier"] = min(D.maxstack, D.materials[DEFAULT_WALL_MATERIAL] ? round(stored_material[DEFAULT_WALL_MATERIAL] / D.materials[DEFAULT_WALL_MATERIAL]) : INFINITY, D.materials["glass"] ? round(stored_material["glass"] / D.materials["glass"]) : INFINITY)
else
design["max_multiplier"] = null
design["materials"] = design_cost_data(D)
data = queue_data(data)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "autolathe.tmpl", name, 800, 550)
ui.set_initial_data(data)
ui.open()
return data
/obj/machinery/autolathe/Topic(href, href_list)
if(..())
return
add_fingerprint(usr)
if(href_list["menu"])
screen = text2num(href_list["menu"])
if(href_list["category"])
selected_category = href_list["category"]
screen = AUTOLATHE_CATEGORY_MENU
if(href_list["make"])
BuildTurf = loc
/////////////////
//href protection
var/datum/design/design_last_ordered
design_last_ordered = FindDesign(href_list["make"]) //check if it's a valid design
if(!design_last_ordered)
return
if(!(design_last_ordered.build_type & AUTOLATHE))
return
//multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier
var/multiplier = text2num(href_list["multiplier"])
var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[DEFAULT_WALL_MATERIAL] ?round(stored_material[DEFAULT_WALL_MATERIAL]/design_last_ordered.materials[DEFAULT_WALL_MATERIAL]):INFINITY,design_last_ordered.materials["glass"]?round(stored_material["glass"]/design_last_ordered.materials["glass"]):INFINITY)
var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack)
if(!is_stack && (multiplier > 1))
return
if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc
return
/////////////////
if((queue.len + 1) < queue_max_len)
add_to_queue(design_last_ordered,multiplier)
else
to_chat(usr, "<span class='warning'>The autolathe queue is full!</span>")
if(!busy)
busy = 1
process_queue()
busy = 0
if(href_list["remove_from_queue"])
var/index = text2num(href_list["remove_from_queue"])
if(isnum(index) && ISINRANGE(index, 1, queue.len))
remove_from_queue(index)
if(href_list["queue_move"] && href_list["index"])
var/index = text2num(href_list["index"])
var/new_index = index + text2num(href_list["queue_move"])
if(isnum(index) && isnum(new_index))
if(ISINRANGE(new_index, 1, queue.len))
queue.Swap(index,new_index)
if(href_list["clear_queue"])
queue = list()
if(href_list["search"])
if(href_list["to_search"])
temp_search = href_list["to_search"]
if(!temp_search)
return
matching_designs.Cut()
for(var/datum/design/item/autolathe/D in files.known_designs)
if(findtext(D.name, temp_search))
matching_designs.Add(D)
screen = AUTOLATHE_SEARCH_MENU
SSnanoui.update_uis(src)
return 1
/obj/machinery/autolathe/update_icon()
if(panel_open)
icon_state = "autolathe_t"
else if(busy)
icon_state = "autolathe_n"
else
if(icon_state == "autolathe_n")
flick("autolathe_u", src) // If lid WAS closed, show opening animation
icon_state = "autolathe"
/obj/machinery/autolathe/RefreshParts()
..()
var/mb_rating = 0
var/man_rating = 0
for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts)
mb_rating += MB.rating
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
man_rating += M.rating
storage_capacity[DEFAULT_WALL_MATERIAL] = mb_rating * 25000
storage_capacity["glass"] = mb_rating * 12500
build_time = 50 / man_rating
mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5
/obj/machinery/autolathe/proc/design_cost_data(datum/design/D)
var/list/data = list()
var/coeff = get_coeff(D)
var/has_metal = 1
if(D.materials[DEFAULT_WALL_MATERIAL] && (stored_material[DEFAULT_WALL_MATERIAL] < (D.materials[DEFAULT_WALL_MATERIAL] * coeff)))
has_metal = 0
var/has_glass = 1
if(D.materials["glass"] && (stored_material["glass"] < (D.materials["glass"] * coeff)))
has_glass = 0
data[++data.len] = list("name" = "metal", "amount" = D.materials[DEFAULT_WALL_MATERIAL] * coeff, "is_red" = !has_metal)
data[++data.len] = list("name" = "glass", "amount" = D.materials["glass"] * coeff, "is_red" = !has_glass)
return data
/obj/machinery/autolathe/proc/queue_data(list/data)
var/temp_metal = stored_material[DEFAULT_WALL_MATERIAL]
var/temp_glass = stored_material["glass"]
data["processing"] = being_built.len ? get_processing_line() : null
if(istype(queue) && queue.len)
var/list/data_queue = list()
for(var/list/L in queue)
var/datum/design/item/autolathe/D = L[1]
var/list/LL = get_design_cost_as_list(D, L[2])
data_queue[++data_queue.len] = list("name" = initial(D.name), "can_build" = can_build(D, L[2], temp_metal, temp_glass), "multiplier" = L[2])
temp_metal = max(temp_metal - LL[1], 1)
temp_glass = max(temp_glass - LL[2], 1)
data["queue"] = data_queue
data["queue_len"] = data_queue.len
else
data["queue"] = null
return data
/obj/machinery/autolathe/proc/get_coeff(datum/design/D)
var/coeff = (ispath(D.build_path,/obj/item/stack) ? 1 : mat_efficiency)//stacks are unaffected by production coefficient
return coeff
/obj/machinery/autolathe/proc/build_item(datum/design/D, multiplier)
desc = initial(desc)+"\nIt's building \a [initial(D.name)]."
var/is_stack = ispath(D.build_path, /obj/item/stack)
var/coeff = get_coeff(D)
var/metal_cost = D.materials[DEFAULT_WALL_MATERIAL]
var/glass_cost = D.materials["glass"]
var/power = max(2000, (metal_cost+glass_cost)*multiplier/5)
if(can_build(D, multiplier))
being_built = list(D, multiplier)
use_power(power)
icon_state = "autolathe"
flick("autolathe_n",src)
if(is_stack)
var/list/materials_used = list(DEFAULT_WALL_MATERIAL=metal_cost*multiplier, "glass"=glass_cost*multiplier)
//stored_material = list(DEFAULT_WALL_MATERIAL -= materials_used[DEFAULT_WALL_MATERIAL], "glass" -= materials_used["glass"])
stored_material[DEFAULT_WALL_MATERIAL] -= materials_used[DEFAULT_WALL_MATERIAL]
stored_material["glass"] -= materials_used["glass"]
else
var/list/materials_used = list(DEFAULT_WALL_MATERIAL=metal_cost*coeff, "glass"=glass_cost*coeff)
stored_material[DEFAULT_WALL_MATERIAL] -= materials_used[DEFAULT_WALL_MATERIAL]
stored_material["glass"] -= materials_used["glass"]
SSnanoui.update_uis(src)
sleep(32*coeff)
if(is_stack)
var/obj/item/stack/S = new D.build_path(BuildTurf)
S.amount = multiplier
else
var/obj/item/new_item = new D.build_path(BuildTurf)
new_item.matter[DEFAULT_WALL_MATERIAL] *= coeff
new_item.matter["glass"] *= coeff
SSnanoui.update_uis(src)
desc = initial(desc)
/obj/machinery/autolathe/proc/can_build(var/datum/design/D, var/multiplier = 1, custom_metal, custom_glass)
if(D.chemicals.len)
return 0
var/coeff = get_coeff(D)
var/metal_amount = stored_material[DEFAULT_WALL_MATERIAL]
if(custom_metal)
metal_amount = custom_metal
var/glass_amount = stored_material["glass"]
if(custom_glass)
glass_amount = custom_glass
if(D.materials[DEFAULT_WALL_MATERIAL] && (metal_amount < (multiplier*D.materials[DEFAULT_WALL_MATERIAL] * coeff)))
return 0
if(D.materials["glass"] && (glass_amount < (multiplier*D.materials["glass"] * coeff)))
return 0
return 1
/obj/machinery/autolathe/proc/get_design_cost_as_list(datum/design/D, multiplier = 1)
var/list/OutputList = list(0,0)
var/coeff = get_coeff(D)
if(D.materials[DEFAULT_WALL_MATERIAL])
OutputList[1] = (D.materials[DEFAULT_WALL_MATERIAL] * coeff)*multiplier
if(D.materials["glass"])
OutputList[2] = (D.materials["glass"] * coeff)*multiplier
return OutputList
/obj/machinery/autolathe/proc/get_processing_line()
var/datum/design/D = being_built[1]
var/multiplier = being_built[2]
var/is_stack = (multiplier>1)
var/output = "PROCESSING: [initial(D.name)][is_stack?" (x[multiplier])":null]"
return output
/obj/machinery/autolathe/proc/add_to_queue(D, multiplier)
if(!istype(queue))
queue = list()
if(D)
queue.Add(list(list(D,multiplier)))
return queue.len
/obj/machinery/autolathe/proc/remove_from_queue(index)
if(!isnum(index) || !istype(queue) || (index<1 || index>queue.len))
return 0
queue.Cut(index,++index)
return 1
/obj/machinery/autolathe/proc/process_queue()
var/datum/design/D = queue[1][1]
var/multiplier = queue[1][2]
if(!D)
remove_from_queue(1)
if(queue.len)
return process_queue()
else
return
while(D)
if(stat & (NOPOWER|BROKEN))
being_built = new /list()
return 0
if(!can_build(D, multiplier))
visible_message("[bicon(src)] <b>\The [src]</b> beeps, \"Not enough resources. Queue processing terminated.\"")
queue = list()
being_built = new /list()
return 0
remove_from_queue(1)
build_item(D,multiplier)
D = listgetindex(listgetindex(queue, 1),1)
multiplier = listgetindex(listgetindex(queue,1),2)
being_built = new /list()
/datum/research/autolathe
/datum/research/autolathe/DesignHasReqs(var/datum/design/D)
return D && (D.build_type & AUTOLATHE)
/datum/research/autolathe/AddDesign2Known(var/datum/design/D)
if(!(D.build_type & AUTOLATHE))
return
..()
//datum/research/proc/FindDesignByID(var/id)
//return known_designs[id]
///obj/machinery/autolathe/proc/FindDesignByID(var/id)
//return files.known_designs[id]
/obj/machinery/autolathe/proc/FindDesign(var/id)
for(var/datum/design/item/autolathe/desired_design in files.known_designs)
if(desired_design.id == id)
return desired_design
return
/obj/machinery/autolathe/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(busy)
to_chat(user, "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>")
return
if(default_deconstruction_screwdriver(user, O))
updateUsrDialog()
return
if(default_deconstruction_crowbar(user, O))
return
if(default_part_replacement(user, O))
return
if(stat)
return
if(panel_open)
//Don't eat multitools or wirecutters used on an open lathe.
if(O.is_multitool() || O.is_wirecutter())
wires.Interact(user)
return
if(O.loc != user && !(istype(O,/obj/item/stack)))
return 0
if(is_robot_module(O))
return 0
if(istype(O,/obj/item/ammo_magazine/clip) || istype(O,/obj/item/ammo_magazine/s357) || istype(O,/obj/item/ammo_magazine/s38) || istype (O,/obj/item/ammo_magazine/s44)/* VOREstation Edit*/) // Prevents ammo recycling exploit with speedloaders.
to_chat(user, "\The [O] is too hazardous to recycle with the autolathe!")
return
/* ToDo: Make this actually check for ammo and change the value of the magazine if it's empty. -Spades
var/obj/item/ammo_magazine/speedloader = O
if(speedloader.stored_ammo)
to_chat(user, "\The [speedloader] is too hazardous to put back into the autolathe while there's ammunition inside of it!")
return
else
speedloader.matter = list(DEFAULT_WALL_MATERIAL = 75) // It's just a hunk of scrap metal now.
if(istype(O,/obj/item/ammo_magazine)) // This was just for immersion consistency with above.
var/obj/item/ammo_magazine/mag = O
if(mag.stored_ammo)
to_chat(user, "\The [mag] is too hazardous to put back into the autolathe while there's ammunition inside of it!")
return*/
//Resources are being loaded.
var/obj/item/eating = O
if(!eating.matter)
to_chat(user, "\The [eating] does not contain significant amounts of useful materials and cannot be accepted.")
return
var/filltype = 0 // Used to determine message.
var/total_used = 0 // Amount of material used.
var/mass_per_sheet = 0 // Amount of material constituting one sheet.
for(var/material in eating.matter)
if(isnull(stored_material[material]) || isnull(storage_capacity[material]))
continue
if(stored_material[material] >= storage_capacity[material])
continue
var/total_material = eating.matter[material]
//If it's a stack, we eat multiple sheets.
if(istype(eating,/obj/item/stack))
var/obj/item/stack/stack = eating
total_material *= stack.get_amount()
if(stored_material[material] + total_material > storage_capacity[material])
total_material = storage_capacity[material] - stored_material[material]
filltype = 1
else
filltype = 2
stored_material[material] += total_material
total_used += total_material
mass_per_sheet += eating.matter[material]
if(!filltype)
to_chat(user, "<span class='notice'>\The [src] is full. Please remove material from the autolathe in order to insert more.</span>")
return
else if(filltype == 1)
to_chat(user, "You fill \the [src] to capacity with \the [eating].")
else
to_chat(user, "You fill \the [src] with \the [eating].")
flick("autolathe_o", src) // Plays metal insertion animation. Work out a good way to work out a fitting animation. ~Z
if(istype(eating,/obj/item/stack))
var/obj/item/stack/stack = eating
stack.use(max(1, round(total_used/mass_per_sheet))) // Always use at least 1 to prevent infinite materials.
else
user.remove_from_mob(O)
qdel(O)
updateUsrDialog()
return

View File

@@ -0,0 +1,51 @@
/datum/design/item/autolathe/devices //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "Devices" //category item goes to
/datum/design/item/autolathe/devices/consolescreen
name = "console screen"
id = "console_screen"
build_path = /obj/item/weapon/stock_parts/console_screen
materials = list("glass" = 200)
/datum/design/item/autolathe/devices/igniter
name = "igniter"
id = "igniter"
build_path = /obj/item/device/assembly/igniter
materials = list(DEFAULT_WALL_MATERIAL = 625, "glass" = 62)
/datum/design/item/autolathe/devices/signaler
name = "signaler"
id = "signaler"
build_path = /obj/item/device/assembly/signaler
materials = list(DEFAULT_WALL_MATERIAL = 1250, "glass" = 250)
/datum/design/item/autolathe/devices/sensor_infra
name = "infrared sensor"
id = "infrared_sensor"
build_path = /obj/item/device/assembly/infra
materials = list(DEFAULT_WALL_MATERIAL = 1250, "glass" = 625)
/datum/design/item/autolathe/devices/sensor_prox
name = "proximity sensor"
id = "proximity_sensor"
build_path = /obj/item/device/assembly/prox_sensor
materials = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 250)
/datum/design/item/autolathe/devices/beartrap
name = "mechanical trap"
id = "beartrap"
build_path = /obj/item/weapon/beartrap
materials = list(DEFAULT_WALL_MATERIAL = 23437)
/datum/design/item/autolathe/devices/electropack
name = "electropack"
id = "electropack"
build_path = /obj/item/device/radio/electropack
materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 3125)
hidden = 1
/datum/design/item/autolathe/devices/timer
name = "timer"
id = "timer"
build_path = /obj/item/device/assembly/timer
materials = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 250)

View File

@@ -0,0 +1,5 @@
/datum/design/item/autolathe/devices/sleevecard
name = "sleevecard"
id = "sleevecard"
build_path = /obj/item/device/sleevecard
materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 5000)

View File

@@ -0,0 +1,140 @@
/datum/design/item/autolathe/engineering //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "Engineering" //category item goes to
/datum/design/item/autolathe/engineering/airlockmodule
name = "airlock electronics"
id = "airlock_electronics"
build_path = /obj/item/weapon/airlock_electronics
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/airalarm
name = "air alarm electronics"
id = "airalarm_electronics"
build_path = /obj/item/weapon/circuitboard/airalarm
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/firealarm
name = "fire alarm electronics"
id = "firealarm_electronics"
build_path = /obj/item/weapon/circuitboard/firealarm
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/statusdisplay
name = "ai status display electronics"
id = "statusdisplay_electronics"
build_path = /obj/item/weapon/circuitboard/ai_status_display
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/newscaster
name = "newscaster electronics"
id = "newscaster_electronics"
build_path = /obj/item/weapon/circuitboard/newscaster
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/atm
name = "atm electronics"
id = "atm_electronics"
build_path = /obj/item/weapon/circuitboard/atm
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/intercom
name = "intercom electronics"
id = "intercom_electronics"
build_path = /obj/item/weapon/circuitboard/intercom
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/holopad
name = "holopad electronics"
id = "holopad_electronics"
build_path = /obj/item/weapon/circuitboard/holopad
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/guestpass
name = "guestpass console electronics"
id = "guestpass_electronics"
build_path = /obj/item/weapon/circuitboard/guestpass
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/entertainment
name = "entertainment camera electronics"
id = "entertainmentcamera_electronics"
build_path = /obj/item/weapon/circuitboard/security/telescreen/entertainment
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/keycard_auth
name = "keycard authenticator electronics"
id = "keycardauth_electronics"
build_path = /obj/item/weapon/circuitboard/keycard_auth
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/photocopier
name = "photocopíer electronics"
id = "photocopier_electronics"
build_path = /obj/item/weapon/circuitboard/photocopier
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/fax
name = "fax machine electronics"
id = "fax_machine_electronics"
build_path = /obj/item/weapon/circuitboard/fax
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/papershredder
name = "paper shredder electronics"
id = "papershredder_electronics"
build_path = /obj/item/weapon/circuitboard/papershredder
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/microwave
name = "microwave electronics"
id = "microwave_electronics"
build_path = /obj/item/weapon/circuitboard/microwave
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/washing
name = "washing machine electronics"
id = "washingmachine_electronics"
build_path = /obj/item/weapon/circuitboard/washing
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/request
name = "request console electronics"
id = "requestconsole_electronics"
build_path = /obj/item/weapon/circuitboard/request
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/motor
name = "motor"
id = "motor"
build_path = /obj/item/weapon/stock_parts/motor
materials = list(DEFAULT_WALL_MATERIAL = 75, "glass" = 12)
/datum/design/item/autolathe/engineering/gear
name = "gear"
id = "gear"
build_path = /obj/item/weapon/stock_parts/gear
materials = list(DEFAULT_WALL_MATERIAL = 62)
/datum/design/item/autolathe/engineering/spring
name = "spring"
id = "spring"
build_path = /obj/item/weapon/stock_parts/spring
materials = list(DEFAULT_WALL_MATERIAL = 50)
/datum/design/item/autolathe/engineering/rcd_ammo
name = "matter cartridge"
id = "rcd_ammo"
build_path = /obj/item/weapon/rcd_ammo
materials = list(DEFAULT_WALL_MATERIAL = 30000, "glass" = 15000)
/datum/design/item/autolathe/engineering/rcd
name = "rapid construction device"
id = "rcd"
build_path = /obj/item/weapon/rcd
materials = list(DEFAULT_WALL_MATERIAL = 62500)
/datum/design/item/autolathe/engineering/camera_assembly
name = "camera assembly"
id = "camera_assembly"
build_path = /obj/item/weapon/camera_assembly
materials = list(DEFAULT_WALL_MATERIAL = 875, "glass" = 375)

View File

@@ -0,0 +1,11 @@
/datum/design/item/autolathe/engineering/timeclock
name = "timeclock electronics"
id = "timeclock_electronics"
build_path = /obj/item/weapon/circuitboard/timeclock
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)
/datum/design/item/autolathe/engineering/id_restorer
name = "ID restoration console electronics"
id = "idrestorer_electronics"
build_path = /obj/item/weapon/circuitboard/id_restorer
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 62)

View File

@@ -0,0 +1,209 @@
/datum/design/item/autolathe/general //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "General" //category item goes to
/datum/design/item/autolathe/general/bucket
name = "bucket"
id = "bucket"
build_path = /obj/item/weapon/reagent_containers/glass/bucket
materials = list(DEFAULT_WALL_MATERIAL = 250)
/datum/design/item/autolathe/general/cooler_bottle
name = "water cooler bottle"
id = "cooler_bottle"
build_path = /obj/item/weapon/reagent_containers/glass/cooler_bottle
materials = list(DEFAULT_WALL_MATERIAL = 15000)
/datum/design/item/autolathe/general/drinkingglass_square
name = "half-pint glass"
id = "halfpint_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/square
materials = list("glass" = 75)
/datum/design/item/autolathe/general/drinkingglass_rocks
name = "rocks glass"
id = "rocks_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/rocks
materials = list("glass" = 50)
/datum/design/item/autolathe/general/drinkingglass_shake
name = "milkshake glass"
id = "milkshake_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/shake
materials = list("glass" = 37)
/datum/design/item/autolathe/general/drinkingglass_cocktail
name = "cocktail glass"
id = "cocktail_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/cocktail
materials = list("glass" = 37)
/datum/design/item/autolathe/general/drinkingglass_shot
name = "shot glass"
id = "shot_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/shot
materials = list("glass" = 75)
/datum/design/item/autolathe/general/drinkingglass_pint
name = "pint glass"
id = "pint_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/pint
materials = list("glass" = 150)
/datum/design/item/autolathe/general/drinkingglass_mug
name = "glass mug"
id = "mug_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/mug
materials = list("glass" = 100)
/datum/design/item/autolathe/general/drinkingglass_wine
name = "wine glass"
id = "wine_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/wine
materials = list("glass" = 62)
/datum/design/item/autolathe/general/flashlight
name = "flashlight"
id = "flashlight"
build_path = /obj/item/device/flashlight
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 25)
/datum/design/item/autolathe/general/floor_light
name = "floor light"
id = "floor_light"
build_path = /obj/machinery/floor_light
materials = list(DEFAULT_WALL_MATERIAL = 3125, "glass" = 3437)
/datum/design/item/autolathe/general/extinguisher
name = "fire extinguisher"
id = "fire_extinguisher"
build_path = /obj/item/weapon/extinguisher
materials = list(DEFAULT_WALL_MATERIAL = 112)
/datum/design/item/autolathe/general/jar
name = "jar"
id = "glass_jar"
build_path = /obj/item/glass_jar
materials = list(DEFAULT_WALL_MATERIAL = 250)
/datum/design/item/autolathe/general/radio_headset
name = "radio headset"
id = "radio_headset"
build_path = /obj/item/device/radio/headset
materials = list(DEFAULT_WALL_MATERIAL = 93)
/datum/design/item/autolathe/general/radio_bounced
name = "station bounced radio"
id = "radio_bounced"
build_path = /obj/item/device/radio/off
materials = list(DEFAULT_WALL_MATERIAL = 93, "glass" = 31)
/datum/design/item/autolathe/general/suit_cooler
name = "suit cooling unit"
id = "suit_cooler"
build_path = /obj/item/device/suit_cooling_unit
materials = list(DEFAULT_WALL_MATERIAL = 18750, "glass" = 4375)
/datum/design/item/autolathe/general/weldermask
name = "welding mask"
id = "weldermask"
build_path = /obj/item/clothing/head/welding
materials = list(DEFAULT_WALL_MATERIAL = 3750, "glass" = 1250)
/datum/design/item/autolathe/general/metal
name = "steel sheets"
id = "steel_sheets"
build_path = /obj/item/stack/material/steel
materials = list(DEFAULT_WALL_MATERIAL = 2000)
maxstack = 50
/datum/design/item/autolathe/general/glass
name = "glass sheets"
id = "glass_sheets"
build_path = /obj/item/stack/material/glass
materials = list("glass" = 2000)
maxstack = 50
/datum/design/item/autolathe/general/rglass
name = "reinforced glass sheets"
id = "reinforcedglass_sheets"
build_path = /obj/item/stack/material/glass/reinforced
materials = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 2000)
maxstack = 50
/datum/design/item/autolathe/general/rods
name = "metal rods"
id = "metal_rods"
build_path = /obj/item/stack/rods
materials = list(DEFAULT_WALL_MATERIAL = 500)
maxstack = 60
/datum/design/item/autolathe/general/spraybottle
name = "empty spray bottle"
id = "spraybottle"
build_path = /obj/item/weapon/reagent_containers/spray
materials = list(DEFAULT_WALL_MATERIAL = 375, "glass" = 375)
/datum/design/item/autolathe/general/knife
name = "kitchen knife"
id = "kitchen_knife"
build_path = /obj/item/weapon/material/knife
materials = list(DEFAULT_WALL_MATERIAL = 375)
/datum/design/item/autolathe/general/taperecorder
name = "tape recorder"
id = "taperecorder"
build_path = /obj/item/device/taperecorder
materials = list(DEFAULT_WALL_MATERIAL = 75, "glass" = 37)
/datum/design/item/autolathe/general/light_tube
name = "light tube"
id = "light_tube"
build_path = /obj/item/weapon/light/tube
materials = list("glass" = 125)
/datum/design/item/autolathe/general/light_bulb
name = "light bulb"
id = "light_bulb"
build_path = /obj/item/weapon/light/bulb
materials = list("glass" = 125)
/datum/design/item/autolathe/general/ashtray_glass
name = "glass ashtray"
id = "ashtray_glass"
build_path = /obj/item/weapon/material/ashtray/glass
materials = list("glass" = 250)
/datum/design/item/autolathe/general/weldinggoggles
name = "welding goggles"
id = "weldinggoggles"
build_path = /obj/item/clothing/glasses/welding
materials = list(DEFAULT_WALL_MATERIAL = 1875, "glass" = 1250)
/datum/design/item/autolathe/general/maglight
name = "maglight"
id = "maglight"
build_path = /obj/item/device/flashlight/maglight
materials = list(DEFAULT_WALL_MATERIAL = 250, "glass" = 62)
/datum/design/item/autolathe/general/emergency_cell
name = "light fixture battery"
id = "emergency_cell"
build_path = /obj/item/weapon/cell/emergency_light
materials = list("glass" = 25)
/datum/design/item/autolathe/general/handcuffs
name = "handcuffs"
id = "handcuffs"
build_path = /obj/item/weapon/handcuffs
materials = list(DEFAULT_WALL_MATERIAL = 625)
hidden = 1
/datum/design/item/autolathe/general/legcuffs
name = "legcuffs"
id = "legcuffs"
build_path = /obj/item/weapon/handcuffs/legcuffs
materials = list(DEFAULT_WALL_MATERIAL = 625)
hidden = 1

View File

@@ -0,0 +1,23 @@
/datum/design/item/autolathe/general/holocollar
name = "Holo-collar"
id = "holocollar"
build_path = /obj/item/clothing/accessory/collar/holo
materials = list(DEFAULT_WALL_MATERIAL = 62)
/datum/design/item/autolathe/general/metaglass
name = "metamorphic glass"
id = "metaglass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/metaglass
materials = list("glass" = 625)
/datum/design/item/autolathe/general/drinkingglass_carafe
name = "glass carafe"
id = "carafe_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/carafe
materials = list("glass" = 62)
/datum/design/item/autolathe/general/drinkingglass_pitcher
name = "pitcher"
id = "pitcher_glass"
build_path = /obj/item/weapon/reagent_containers/food/drinks/glass2/pitcher
materials = list(DEFAULT_WALL_MATERIAL = 62)

View File

@@ -0,0 +1,71 @@
/datum/design/item/autolathe/medical //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "Medical" //category item goes to
/datum/design/item/autolathe/medical/scalpel
name = "scalpel"
id = "scalpel"
build_path = /obj/item/weapon/surgical/scalpel
materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 6250)
/datum/design/item/autolathe/medical/circularsaw
name = "circular saw"
id = "circularsaw"
build_path = /obj/item/weapon/surgical/circular_saw
materials = list(DEFAULT_WALL_MATERIAL = 25000, "glass" = 12500)
/datum/design/item/autolathe/medical/surgicaldrill
name = "surgical drill"
id = "surgicaldrill"
build_path = /obj/item/weapon/surgical/surgicaldrill
materials = list(DEFAULT_WALL_MATERIAL = 18750, "glass" = 12500)
/datum/design/item/autolathe/medical/retractor
name = "retractor"
id = "retractor"
build_path = /obj/item/weapon/surgical/retractor
materials = list(DEFAULT_WALL_MATERIAL = 12500, "glass" = 6250)
/datum/design/item/autolathe/medical/cautery
name = "cautery"
id = "cautery"
build_path = /obj/item/weapon/surgical/cautery
materials = list(DEFAULT_WALL_MATERIAL = 6250, "glass" = 3125)
/datum/design/item/autolathe/medical/hemostat
name = "hemostat"
id = "hemostat"
build_path = /obj/item/weapon/surgical/hemostat
materials = list(DEFAULT_WALL_MATERIAL = 6250, "glass" = 3125)
/datum/design/item/autolathe/medical/beaker
name = "glass beaker"
id = "beaker"
build_path = /obj/item/weapon/reagent_containers/glass/beaker
materials = list("glass" = 625)
/datum/design/item/autolathe/medical/large_beaker
name = "large glass beaker"
id = "large_beaker"
build_path = /obj/item/weapon/reagent_containers/glass/beaker/large
materials = list("glass" = 1300)
/datum/design/item/autolathe/medical/vial
name = "glass vial"
id = "vial"
build_path = /obj/item/weapon/reagent_containers/glass/beaker/vial
materials = list("glass" = 312)
/datum/design/item/autolathe/medical/syringe
name = "syringe"
id = "syringe"
build_path = /obj/item/weapon/reagent_containers/syringe
materials = list("glass" = 187)
/datum/design/item/autolathe/medical/implanter
name = "implanter"
id = "implanter"
build_path = /obj/item/weapon/implanter
materials = list(DEFAULT_WALL_MATERIAL = 1250, "glass" = 1250)

View File

@@ -0,0 +1,5 @@
/datum/design/item/autolathe/medical/autoinjector
name = "empty autoinjector"
id = "autoinjector"
build_path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/empty
materials = list(DEFAULT_WALL_MATERIAL = 100)

View File

@@ -0,0 +1,69 @@
/datum/design/item/autolathe/tools //Datum for object designs, used in construction //IDs of that techs the object originated from and the minimum level requirements.
category = "Tools" //category item goes to
/datum/design/item/autolathe/tools/crowbar
name = "crowbar"
id = "crowbar"
build_path = /obj/item/weapon/tool/crowbar
materials = list(DEFAULT_WALL_MATERIAL = 62)
/datum/design/item/autolathe/tools/multitool
name = "multitool"
id = "multitool"
build_path = /obj/item/device/multitool
materials = list(DEFAULT_WALL_MATERIAL = 62, "glass" = 25)
/datum/design/item/autolathe/tools/t_scanner
name = "T-ray scanner"
id = "t_scanner"
build_path = /obj/item/device/t_scanner
materials = list(DEFAULT_WALL_MATERIAL = 187)
/datum/design/item/autolathe/tools/weldertool
name = "welding tool"
id = "weldertool"
build_path = /obj/item/weapon/weldingtool
materials = list(DEFAULT_WALL_MATERIAL = 87, "glass" = 37)
/datum/design/item/autolathe/tools/electric_welder
name = "electric welding tool"
id = "electric_welder"
build_path = /obj/item/weapon/weldingtool/electric/unloaded
materials = list(DEFAULT_WALL_MATERIAL = 87, "glass" = 37)
hidden = 1
/datum/design/item/autolathe/tools/screwdriver
name = "screwdriver"
id = "screwdriver"
build_path = /obj/item/weapon/tool/screwdriver
materials = list(DEFAULT_WALL_MATERIAL = 93)
/datum/design/item/autolathe/tools/wirecutters
name = "wirecutters"
id = "wirecutters"
build_path = /obj/item/weapon/tool/wirecutters
materials = list(DEFAULT_WALL_MATERIAL = 100)
/datum/design/item/autolathe/tools/wrench
name = "wrench"
id = "wrench"
build_path = /obj/item/weapon/tool/wrench
materials = list(DEFAULT_WALL_MATERIAL = 187)
/datum/design/item/autolathe/tools/hatchet
name = "hatchet"
id = "hatchet"
build_path = /obj/item/weapon/material/knife/machete/hatchet
materials = list(DEFAULT_WALL_MATERIAL = 500)
/datum/design/item/autolathe/tools/minihoe
name = "mini hoe"
id = "minihoe"
build_path = /obj/item/weapon/material/minihoe
materials = list(DEFAULT_WALL_MATERIAL = 625)
/datum/design/item/autolathe/tools/welder_industrial
name = "industrial welding tool"
id = "welder_industrial"
build_path = /obj/item/weapon/weldingtool/largetank
materials = list(DEFAULT_WALL_MATERIAL = 87, "glass" = 75)

View File

@@ -0,0 +1,5 @@
/datum/design/item/autolathe/tools/prybar
name = "prybar"
id = "prybar"
build_path = /obj/item/weapon/tool/prybar
materials = list(DEFAULT_WALL_MATERIAL = 37)

View File

@@ -0,0 +1,15 @@
/datum/design/item/autolathe/tools/ice_pick
name = "ice pick"
id = "ice_pick"
build_path = /obj/item/weapon/ice_pick
materials = list(DEFAULT_WALL_MATERIAL = 15000)
/datum/design/item/autolathe/tools/shovel
name = "shovel"
id = "shovel"
build_path = /obj/item/weapon/shovel
materials = list(DEFAULT_WALL_MATERIAL = 62)

View File

@@ -5,11 +5,16 @@
/datum/datacore
var/name = "datacore"
var/medical[] = list()
var/general[] = list()
var/security[] = list()
//For general station crew
var/static/list/medical = list()
var/static/list/general = list()
var/static/list/security = list()
//For offmap spawns so they can have records accessible by certain things
var/static/list/hidden_medical = list()
var/static/list/hidden_general = list()
var/static/list/hidden_security = list()
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
var/static/list/locked = list()
/datum/datacore/proc/get_manifest(monochrome, OOC)
@@ -22,6 +27,7 @@
var/list/pla = new() //VOREStation Edit
var/list/civ = new()
var/list/bot = new()
var/list/off = new()
var/list/misc = new()
var/list/isactive = new()
var/dat = {"
@@ -46,7 +52,7 @@
if(OOC)
var/active = 0
for(var/mob/M in player_list)
if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10)
if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES)
active = 1
break
isactive[name] = active ? "Active" : "Inactive"
@@ -84,6 +90,24 @@
if(!department && !(name in heads))
misc[name] = rank
//For the offmap spawns
if(OOC)
for(var/datum/data/record/t in hidden_general)
var/name = t.fields["name"]
var/rank = t.fields["rank"]
var/real_rank = make_list_rank(t.fields["real_rank"])
var/active = 0
for(var/mob/M in player_list)
if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES)
active = 1
break
isactive[name] = active ? "Active" : "Inactive"
var/datum/job/J = SSjob.get_job(real_rank)
if(J?.offmap_spawn)
off[name] = rank
// Synthetics don't have actual records, so we will pull them from here.
for(var/mob/living/silicon/ai/ai in mob_list)
bot[ai.name] = "Artificial Intelligence"
@@ -142,6 +166,12 @@
for(name in bot)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[bot[name]]</td><td>[isactive[name]]</td></tr>"
even = !even
// offmap spawners
if(off.len > 0)
dat += "<tr><th colspan=3>Offmap Spawns</th></tr>"
for(name in off)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[off[name]]</td><td>[isactive[name]]</td></tr>"
even = !even
// misc guys
if(misc.len > 0)
dat += "<tr><th colspan=3>Miscellaneous</th></tr>"
@@ -154,6 +184,117 @@
dat = replacetext(dat, "\t", "")
return dat
/*
We can't just insert in HTML into the nanoUI so we need the raw data to play with.
Instead of creating this list over and over when someone leaves their PDA open to the page
we'll only update it when it changes. The PDA_Manifest global list is zeroed out upon any change
using /datum/datacore/proc/manifest_inject( ), or manifest_insert( )
*/
var/global/list/PDA_Manifest = list()
/datum/datacore/proc/get_manifest_list()
if(PDA_Manifest.len)
return
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/car = list()
var/list/pla = list() // Planetside crew: Explorers, Pilots, S&S
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
for(var/datum/data/record/t in data_core.general)
var/name = sanitize(t.fields["name"])
var/rank = sanitize(t.fields["rank"])
var/real_rank = make_list_rank(t.fields["real_rank"])
var/isactive = t.fields["p_stat"]
var/department = 0
var/depthead = 0 // Department Heads will be placed at the top of their lists.
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND))
heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
depthead = 1
if(rank=="Colony Director" && heads.len != 1)
heads.Swap(1,heads.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SECURITY))
sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sec.len != 1)
sec.Swap(1,sec.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_ENGINEERING))
eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && eng.len != 1)
eng.Swap(1,eng.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_MEDICAL))
med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && med.len != 1)
med.Swap(1,med.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_RESEARCH))
sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sci.len != 1)
sci.Swap(1,sci.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_PLANET))
pla[++pla.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO))
car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && car.len != 1)
car.Swap(1,car.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN))
civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && civ.len != 1)
civ.Swap(1,civ.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SYNTHETIC))
bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(!department && !(name in heads))
misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
// Synthetics don't have actual records, so we will pull them from here.
// Synths don't have records, which is the means by which isactive is retrieved, so I'm hardcoding it to active, don't really have any better means
for(var/mob/living/silicon/ai/ai in mob_list)
bot[++bot.len] = list("name" = ai.real_name, "rank" = "Artificial Intelligence", "active" = "Active")
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones, and no AI shells.
if(robot.scrambledcodes || robot.shell || (robot.module && robot.module.hide_on_manifest))
continue
bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active")
PDA_Manifest = list(
list("cat" = "Command", "elems" = heads),
list("cat" = "Security", "elems" = sec),
list("cat" = "Engineering", "elems" = eng),
list("cat" = "Medical", "elems" = med),
list("cat" = "Science", "elems" = sci),
list("cat" = "Cargo", "elems" = car),
list("cat" = "Exploration", "elems" = pla), // VOREStation Edit
list("cat" = "Civilian", "elems" = civ),
list("cat" = "Silicon", "elems" = bot),
list("cat" = "Miscellaneous", "elems" = misc)
)
return
/datum/datacore/proc/manifest()
spawn()
for(var/mob/living/carbon/human/H in player_list)
@@ -187,10 +328,13 @@
/datum/datacore/proc/manifest_inject(var/mob/living/carbon/human/H)
if(H.mind && !player_is_antag(H.mind, only_offstation_roles = 1))
var/assignment = GetAssignment(H)
var/hidden
var/datum/job/J = SSjob.get_job(assignment)
hidden = J?.offmap_spawn
var/id = generate_record_id()
//General Record
var/datum/data/record/G = CreateGeneralRecord(H, id)
var/datum/data/record/G = CreateGeneralRecord(H, id, hidden)
G.fields["name"] = H.real_name
G.fields["real_rank"] = H.mind.assigned_role
G.fields["rank"] = assignment
@@ -212,7 +356,7 @@
G.fields["notes"] = H.gen_record
//Medical Record
var/datum/data/record/M = CreateMedicalRecord(H.real_name, id)
var/datum/data/record/M = CreateMedicalRecord(H.real_name, id, hidden)
M.fields["b_type"] = H.b_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["id_gender"] = gender2text(H.identifying_gender)
@@ -224,7 +368,7 @@
M.fields["notes"] = H.med_record
//Security Record
var/datum/data/record/S = CreateSecurityRecord(H.real_name, id)
var/datum/data/record/S = CreateSecurityRecord(H.real_name, id, hidden)
if(H.get_FBP_type())
S.fields["brain_type"] = H.get_FBP_type()
else
@@ -257,6 +401,7 @@
L.fields["image"] = icon(cached_character_icon(H), dir = SOUTH)
L.fields["antagfac"] = H.antag_faction
L.fields["antagvis"] = H.antag_vis
L.fields["offmap"] = hidden
if(H.exploit_record && !jobban_isbanned(H, "Records"))
L.fields["exploit_record"] = H.exploit_record
else
@@ -267,7 +412,7 @@
/proc/generate_record_id()
return add_zero(num2hex(rand(1, 65535)), 4) //no point generating higher numbers because of the limitations of num2hex
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id)
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id, var/hidden)
ResetPDAManifest()
var/icon/front
var/icon/side
@@ -301,11 +446,14 @@
G.fields["photo_front"] = front
G.fields["photo_side"] = side
G.fields["notes"] = "No notes found."
if(hidden)
hidden_general += G
else
general += G
return G
/datum/datacore/proc/CreateSecurityRecord(var/name, var/id)
/datum/datacore/proc/CreateSecurityRecord(var/name, var/id, var/hidden)
ResetPDAManifest()
var/datum/data/record/R = new /datum/data/record()
R.name = "Security Record #[id]"
@@ -319,11 +467,14 @@
R.fields["ma_crim_d"] = "No major crime convictions."
R.fields["notes"] = "No notes."
R.fields["notes"] = "No notes."
data_core.security += R
if(hidden)
hidden_security += R
else
security += R
return R
/datum/datacore/proc/CreateMedicalRecord(var/name, var/id)
/datum/datacore/proc/CreateMedicalRecord(var/name, var/id, var/hidden)
ResetPDAManifest()
var/datum/data/record/M = new()
M.name = "Medical Record #[id]"
@@ -342,7 +493,10 @@
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = "No notes found."
data_core.medical += M
if(hidden)
hidden_medical += M
else
medical += M
return M

View File

@@ -0,0 +1,6 @@
// Push button, receive event.
// Returns a selected event datum.
/datum/game_master/proc/choose_event()
/datum/game_master/proc/log_game_master(message)
// SSgame_master.log_game_master(message) // VOREStation Edit - We don't use SSgame_master yet.

View File

@@ -0,0 +1,89 @@
// The default game master tries to choose events with these goals in mind.
// * Don't choose an event if the crew can't take it. E.g. no meteors after half of the crew died.
// * Try to involve lots of people, particuarly in active departments.
// * Avoid giving events to the same department multiple times in a row.
/datum/game_master/default
// If an event was done for a specific department, it is written here, so it doesn't do it again.
var/last_department_used = null
/datum/game_master/default/choose_event()
log_game_master("Now starting event decision.")
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
var/list/best_events = decide_best_events(most_active_departments)
if(LAZYLEN(best_events))
log_game_master("Got [best_events.len] choice\s for the next event.")
var/list/weighted_events = list()
for(var/E in best_events)
var/datum/event2/meta/event = E
var/weight = event.get_weight()
if(weight <= 0)
continue
weighted_events[event] = weight
log_game_master("Filtered down to [weighted_events.len] choice\s.")
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
last_department_used = LAZYACCESS(choice.departments, 1)
return choice
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
if(!LAZYLEN(most_active_departments)) // Server's empty?
log_game_master("Game Master failed to find any active departments.")
return list()
var/list/best_events = list()
if(most_active_departments.len >= 2)
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
best_events = filter_events_by_departments(top_two)
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
return best_events
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
best_events = filter_events_by_departments(most_active_departments[1])
if(LAZYLEN(best_events))
return best_events
// At this point we should expand our horizons.
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
if(LAZYLEN(best_events))
return best_events
// Just give a random event if for some reason it still can't make up its mind.
best_events = filter_events_by_departments()
if(LAZYLEN(best_events))
return best_events
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
return list()
// Filters the available events down to events for specific departments.
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
// If no list is passed, all the events will be returned.
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
. = list()
for(var/E in SSgame_master.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
if(event.chaotic_threshold && !ignore_round_chaos)
if(SSgame_master.danger > event.chaotic_threshold)
continue
// An event has to involve all of these departments to pass.
var/viable = TRUE
if(LAZYLEN(departments))
for(var/department in departments)
if(!LAZYFIND(departments, department))
viable = FALSE
break
if(viable)
. += event

View File

@@ -0,0 +1,44 @@
// The `classic` game master tries to act like the old system, choosing events without any specific goals.
// * Has no goals, and instead operates purely off of the weights of the events it has.
// * Does not react to danger at all.
/datum/game_master/classic/choose_event()
var/list/weighted_events = list()
for(var/E in SSgame_master.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
weighted_events[event] = event.get_weight()
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
return choice
// The `super_random` game master chooses events purely at random, ignoring weights entirely.
// * Has no goals, and instead chooses randomly, ignoring weights.
// * Does not react to danger at all.
/datum/game_master/super_random/choose_event()
return pick(SSgame_master.available_events)
// The `brutal` game master tries to run dangerous events frequently.
// * Chaotic events have their weights artifically boosted.
// * Ignores accumulated danger.
/datum/game_master/brutal
ignore_round_chaos = TRUE
/datum/game_master/brutal/choose_event()
var/list/weighted_events = list()
for(var/E in SSgame_master.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
weighted_events[event] = event.get_weight() + (event.chaos * 2)
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
return choice

View File

@@ -0,0 +1,5 @@
/decl/hierarchy/outfit/job/security/pilot
name = OUTFIT_JOB_NAME("Security Pilot")
uniform = /obj/item/clothing/under/rank/khi/sec/pilot
id_type = /obj/item/weapon/card/id/security
pda_type = /obj/item/device/pda/security

View File

@@ -14,9 +14,24 @@ var/global/datum/repository/cameras/camera_repository = new()
networks = list()
..()
/datum/repository/cameras/proc/cameras_in_network(var/network)
/datum/repository/cameras/proc/cameras_in_network(var/network, var/list/zlevels)
setup_cache()
var/list/network_list = networks[network]
if(LAZYLEN(zlevels))
var/list/filtered_cameras = list()
for(var/list/C in network_list)
//Camera is marked as always-visible
if(C["omni"])
filtered_cameras[++filtered_cameras.len] = C
continue
//Camera might be in an adjacent zlevel
var/camz = C["z"]
if(!camz) //It's inside something (helmet, communicator, etc) or nullspace or who knows
camz = get_z(locate(C["camera"]) in cameranet.cameras)
if(camz in zlevels)
filtered_cameras[++filtered_cameras.len] = C //Can't add lists to lists with +=
return filtered_cameras
else
return network_list
/datum/repository/cameras/proc/setup_cache()

View File

@@ -48,10 +48,10 @@ var/global/datum/repository/crew/crew_repository = new()
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["area"] = sanitize(A.get_name())
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmemberData["z"] = pos.z
crewmemberData["z"] = using_map.get_zlevel_name(pos.z)
crewmembers[++crewmembers.len] = crewmemberData

View File

@@ -35,48 +35,6 @@
containertype = /obj/structure/closet/crate/engineering
containername = "Superconducting Transmission Coil crate"
/datum/supply_pack/eng/shield_capacitor
name = "Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor)
cost = 20
containertype = /obj/structure/closet/crate/engineering
containername = "shield capacitor crate"
/datum/supply_pack/eng/shield_capacitor/advanced
name = "Advanced Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor/advanced)
cost = 30
containertype = /obj/structure/closet/crate/engineering
containername = "advanced shield capacitor crate"
/datum/supply_pack/eng/bubble_shield
name = "Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen)
cost = 40
containertype = /obj/structure/closet/crate/engineering
containername = "shield bubble generator crate"
/datum/supply_pack/eng/bubble_shield/advanced
name = "Advanced Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen/advanced)
cost = 60
containertype = /obj/structure/closet/crate/engineering
containername = "advanced bubble shield generator crate"
/datum/supply_pack/eng/hull_shield
name = "Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external)
cost = 80
containertype = /obj/structure/closet/crate/engineering
containername = "shield hull generator crate"
/datum/supply_pack/eng/hull_shield/advanced
name = "Advanced Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external/advanced)
cost = 120
containertype = /obj/structure/closet/crate/engineering
containername = "advanced hull shield generator crate"
/datum/supply_pack/eng/electrical
name = "Electrical maintenance crate"
contains = list(
@@ -173,29 +131,19 @@
containername = "Particle Accelerator crate"
access = access_ce
/datum/supply_pack/eng/shield_gen
contains = list(/obj/item/weapon/circuitboard/shield_gen)
name = "Bubble shield generator circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "bubble shield generator circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_gen_ex
contains = list(/obj/item/weapon/circuitboard/shield_gen_ex)
name = "Hull shield generator circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "hull shield generator circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_cap
contains = list(/obj/item/weapon/circuitboard/shield_cap)
name = "Bubble shield capacitor circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "shield capacitor circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_generator
name = "Shield Generator Construction Kit"
contains = list(
/obj/item/weapon/circuitboard/shield_generator,
/obj/item/weapon/stock_parts/capacitor,
/obj/item/weapon/stock_parts/micro_laser,
/obj/item/weapon/smes_coil,
/obj/item/weapon/stock_parts/console_screen,
/obj/item/weapon/stock_parts/subspace/amplifier
)
cost = 80
containertype = /obj/structure/closet/crate/engineering
containername = "shield generator construction kit crate"
/datum/supply_pack/eng/smbig
name = "Supermatter Core"

View File

@@ -1,8 +1,8 @@
/datum/supply_pack/munitions/expeditionguns
name = "Frontier phaser (station-locked) crate"
contains = list(
/obj/item/weapon/gun/energy/frontier/locked = 2,
/obj/item/weapon/gun/energy/frontier/locked/holdout = 1,
/obj/item/weapon/gun/energy/locked/frontier = 2,
/obj/item/weapon/gun/energy/locked/frontier/holdout = 1,
)
cost = 35
containertype = /obj/structure/closet/crate/secure

View File

@@ -14,3 +14,10 @@
cost = 100
containertype = /obj/structure/closet/crate
containername = "Instrument crate"
/datum/supply_pack/recreation/piano
name = "Grand* Piano"
contains = list()
cost = 150
containertype = /obj/structure/largecrate/piano
containername = "Piano Crate"

View File

@@ -169,13 +169,13 @@
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 40
cost = 60
containertype = /obj/structure/closet/crate/secure
containername = "Security Crowd Control voidsuit crate"
access = access_armory
/datum/supply_pack/voidsuits/security/alt
name = "Security EVA Riot voidsuits"
name = "Security EVA voidsuits"
contains = list(
/obj/item/clothing/suit/space/void/security/alt = 2,
/obj/item/clothing/head/helmet/space/void/security/alt = 2,
@@ -183,9 +183,9 @@
/obj/item/clothing/shoes/magboots = 2,
/obj/item/weapon/tank/oxygen = 2
)
cost = 50
cost = 60
containertype = /obj/structure/closet/crate/secure
containername = "Security EVA Riot voidsuit crate"
containername = "Security EVA voidsuit crate"
access = access_armory
/datum/supply_pack/voidsuits/supply
@@ -227,7 +227,7 @@
/datum/supply_pack/voidsuits/unathi_bs_yw
name = "Unathi breacher chassis"
contains = list(/obj/item/weapon/rig/breacher/fancy)
contains = list(/obj/item/weapon/rig/breacher) //YW Edit
cost = 350
containertype = /obj/structure/closet/crate/secure
containername = "Unathi breacher chassis crate"

View File

@@ -53,6 +53,12 @@
name = "Black Ammunition Duffle Bag"
path = /obj/item/weapon/storage/backpack/dufflebag/syndie/ammo
/datum/uplink_item/item/tools/shield_diffuser
name = "Handheld Shield Diffuser"
desc = "A small device used to disrupt energy barriers, and allow passage through them."
item_cost = 16
path = /obj/item/weapon/shield_diffuser
/datum/uplink_item/item/tools/space_suit
name = "Space Suit"
item_cost = 15

View File

@@ -0,0 +1,46 @@
/datum/wires/shield_generator
holder_type = /obj/machinery/power/shield_generator
wire_count = 5
var/const/SHIELDGEN_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore.
var/const/SHIELDGEN_WIRE_HACK = 2 // Pulse to hack the generator, enabling hacked modes. Cut to unhack. Mend does nothing.
var/const/SHIELDGEN_WIRE_CONTROL = 4 // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing.
var/const/SHIELDGEN_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore.
var/const/SHIELDGEN_WIRE_NOTHING = 16 // A blank wire that doesn't have any specific function
/datum/wires/shield_generator/CanUse(var/mob/living/L)
var/obj/machinery/power/shield_generator/S = holder
if(S.panel_open)
return 1
return 0
/datum/wires/shield_generator/GetInteractWindow()
var/obj/machinery/power/shield_generator/S = holder
. += ..()
. += show_hint(0x1, S.mode_changes_locked, "The orange light is on.", "The orange light is off.")
. += show_hint(0x2, S.ai_control_disabled, "The blue light is off.", "The blue light is blinking.")
. += show_hint(0x4, S.hacked, "The violet light is pulsing.", "The violet light is steady.")
. += show_hint(0x8, S.input_cut, "The red light is off.", "The red light is on.")
/datum/wires/shield_generator/UpdateCut(index, mended)
var/obj/machinery/power/shield_generator/S = holder
switch(index)
if(SHIELDGEN_WIRE_POWER)
S.input_cut = !mended
if(SHIELDGEN_WIRE_HACK)
if(!mended)
S.hacked = 0
if(S.check_flag(MODEFLAG_BYPASS))
S.toggle_flag(MODEFLAG_BYPASS)
if(S.check_flag(MODEFLAG_OVERCHARGE))
S.toggle_flag(MODEFLAG_OVERCHARGE)
if(SHIELDGEN_WIRE_CONTROL)
S.mode_changes_locked = !mended
if(SHIELDGEN_WIRE_AICONTROL)
S.ai_control_disabled = !mended
/datum/wires/shield_generator/UpdatePulsed(var/index)
var/obj/machinery/power/shield_generator/S = holder
switch(index)
if(SHIELDGEN_WIRE_HACK)
S.hacked = 1

View File

@@ -52,120 +52,6 @@
return copytext(rank, 2+length(prefix))
return rank
/*
We can't just insert in HTML into the nanoUI so we need the raw data to play with.
Instead of creating this list over and over when someone leaves their PDA open to the page
we'll only update it when it changes. The PDA_Manifest global list is zeroed out upon any change
using /datum/datacore/proc/manifest_inject( ), or manifest_insert( )
*/
var/global/list/PDA_Manifest = list()
/datum/datacore/proc/get_manifest_list()
if(PDA_Manifest.len)
return
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/car = list()
var/list/pla = list() // Planetside crew: Explorers, Pilots, S&S
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
for(var/datum/data/record/t in data_core.general)
var/name = sanitize(t.fields["name"])
var/rank = sanitize(t.fields["rank"])
var/real_rank = make_list_rank(t.fields["real_rank"])
var/isactive = t.fields["p_stat"]
var/department = 0
var/depthead = 0 // Department Heads will be placed at the top of their lists.
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND))
heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
depthead = 1
if(rank=="Colony Director" && heads.len != 1)
heads.Swap(1,heads.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SECURITY))
sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sec.len != 1)
sec.Swap(1,sec.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_ENGINEERING))
eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && eng.len != 1)
eng.Swap(1,eng.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_MEDICAL))
med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && med.len != 1)
med.Swap(1,med.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_RESEARCH))
sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sci.len != 1)
sci.Swap(1,sci.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_PLANET))
pla[++pla.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO))
car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && car.len != 1)
car.Swap(1,car.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN))
civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && civ.len != 1)
civ.Swap(1,civ.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SYNTHETIC))
bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(!department && !(name in heads))
misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
// Synthetics don't have actual records, so we will pull them from here.
// Synths don't have records, which is the means by which isactive is retrieved, so I'm hardcoding it to active, don't really have any better means
for(var/mob/living/silicon/ai/ai in mob_list)
bot[++bot.len] = list("name" = ai.real_name, "rank" = "Artificial Intelligence", "active" = "Active")
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones, and no AI shells.
if(robot.scrambledcodes || robot.shell || (robot.module && robot.module.hide_on_manifest))
continue
bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active")
PDA_Manifest = list(
list("cat" = "Command", "elems" = heads),
list("cat" = "Security", "elems" = sec),
list("cat" = "Engineering", "elems" = eng),
list("cat" = "Medical", "elems" = med),
list("cat" = "Science", "elems" = sci),
list("cat" = "Cargo", "elems" = car),
list("cat" = "Exploration", "elems" = pla), // VOREStation Edit
list("cat" = "Civilian", "elems" = civ),
list("cat" = "Silicon", "elems" = bot),
list("cat" = "Miscellaneous", "elems" = misc)
)
return
/obj/effect/laser
name = "laser"
desc = "IT BURNS!!!"

View File

@@ -32,7 +32,7 @@
title = "Security Announcement"
announcement_type = "Security Announcement"
/datum/announcement/proc/Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0)
/datum/announcement/proc/Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0, zlevel)
if(!message)
return
var/message_title = new_title ? new_title : title
@@ -42,28 +42,32 @@
message = sanitize(message, extra = 0)
message_title = sanitizeSafe(message_title)
Message(message, message_title)
var/list/zlevels
if(zlevel)
zlevels = using_map.get_map_levels(zlevel, TRUE)
Message(message, message_title, zlevels)
if(do_newscast)
NewsCast(message, message_title)
Sound(message_sound)
Sound(message_sound, zlevels)
Log(message, message_title)
datum/announcement/proc/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/proc/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/minor/Message(message as text, message_title as text)
global_announcer.autosay(message, announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/minor/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay(message, announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/priority/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/priority/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/priority/command/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[command_name()] - [message_title]:</span> [message]", ANNOUNCER_NAME)
datum/announcement/priority/command/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[command_name()] - [message_title]:</span> [message]", ANNOUNCER_NAME, zlevels)
datum/announcement/priority/security/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", ANNOUNCER_NAME)
datum/announcement/priority/security/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", ANNOUNCER_NAME, zlevels)
datum/announcement/proc/NewsCast(message as text, message_title as text)
datum/announcement/proc/NewsCast(var/message as text, var/message_title as text)
if(!newscast)
return
@@ -75,15 +79,18 @@ datum/announcement/proc/NewsCast(message as text, message_title as text)
news.can_be_redacted = 0
announce_newscaster_news(news)
datum/announcement/proc/PlaySound(var/message_sound)
datum/announcement/proc/PlaySound(var/message_sound, var/list/zlevels)
if(!message_sound)
return
for(var/mob/M in player_list)
if(zlevels && !(M.z in zlevels))
continue
if(!istype(M,/mob/new_player) && !isdeaf(M))
M << message_sound
datum/announcement/proc/Sound(var/message_sound)
PlaySound(message_sound)
datum/announcement/proc/Sound(var/message_sound, var/list/zlevels)
PlaySound(message_sound, zlevels)
datum/announcement/priority/Sound(var/message_sound)
if(message_sound)
@@ -107,11 +114,12 @@ datum/announcement/proc/Log(message as text, message_title as text)
/proc/ion_storm_announcement()
command_announcement.Announce("It has come to our attention that \the [station_name()] passed through an ion storm. Please monitor all electronic equipment for malfunctions.", "Anomaly Alert")
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank, var/join_message)
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank, var/join_message, var/channel = "Common", var/zlevel)
if (ticker.current_state == GAME_STATE_PLAYING)
var/list/zlevels = zlevel ? using_map.get_map_levels(zlevel, TRUE) : null
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
AnnounceArrivalSimple(character.real_name, rank, join_message)
AnnounceArrivalSimple(character.real_name, rank, join_message, channel, zlevels)
/proc/AnnounceArrivalSimple(var/name, var/rank = "visitor", var/join_message = "will arrive at the station shortly", new_sound = 'sound/misc/notice3.ogg') //VOREStation Edit - Remove shuttle reference
global_announcer.autosay("[name], [rank], [join_message].", "Arrivals Announcement Computer")
/proc/AnnounceArrivalSimple(var/name, var/rank = "visitor", var/join_message = "will arrive at the station shortly", var/channel = "Common", var/list/zlevels)
global_announcer.autosay("[name], [rank], [join_message].", "Arrivals Announcement Computer", channel, zlevels)

View File

@@ -94,6 +94,7 @@ proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H)
proc/statistic_cycle()
set waitfor = 0
if(!sqllogging)
return
while(1)

View File

@@ -71,6 +71,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
flags = RAD_SHIELDED
sound_env = SMALL_ENCLOSED
base_turf = /turf/space
forbid_events = TRUE
/area/shuttle/arrival
name = "\improper Arrival Shuttle"
@@ -816,6 +817,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Construction Area"
icon_state = "construction"
/area/hallway/secondary/entry
forbid_events = TRUE
/area/hallway/secondary/entry/fore
name = "\improper Shuttle Dock Hallway - Mid"
icon_state = "entry_1"
@@ -989,6 +993,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Dormitories"
icon_state = "Sleep"
ambience = AMBIENCE_GENERIC
forbid_events = TRUE
/area/crew_quarters/toilet
name = "\improper Dormitory Toilets"
@@ -1290,6 +1295,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
icon_state = "Holodeck"
dynamic_lighting = 0
sound_env = LARGE_ENCLOSED
forbid_events = TRUE
/area/holodeck/alphadeck
name = "\improper Holodeck Alpha"
@@ -1389,6 +1395,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "\improper Engine Room"
icon_state = "engine"
sound_env = LARGE_ENCLOSED
forbid_events = TRUE
/area/engineering/engine_airlock
name = "\improper Engine Room Airlock"

View File

@@ -30,6 +30,7 @@
var/used_environ = 0
var/has_gravity = 1
var/secret_name = FALSE // This tells certain things that display areas' names that they shouldn't display this area's name.
var/obj/machinery/power/apc/apc = null
var/no_air = null
// var/list/lights // list of all lights on this area
@@ -39,14 +40,7 @@
var/list/forced_ambience = null
var/sound_env = STANDARD_STATION
var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf
var/global/global_uid = 0
var/uid
/area/New()
uid = ++global_uid
all_areas += src //Replace with /area in world? Byond optimizes X in world loops.
..()
var/forbid_events = FALSE // If true, random events will not start inside this area.
/area/Initialize()
. = ..()
@@ -365,6 +359,8 @@ var/list/mob/living/forced_ambiance_list = new
temp_airlock.prison_open()
for(var/obj/machinery/door/window/temp_windoor in src)
temp_windoor.open()
for(var/obj/machinery/door/blast/temp_blast in src)
temp_blast.open()
/area/has_gravity()
return has_gravity
@@ -397,7 +393,7 @@ var/list/mob/living/forced_ambiance_list = new
var/list/teleportlocs = list()
/hook/startup/proc/setupTeleportLocs()
for(var/area/AR in all_areas)
for(var/area/AR in world)
if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue
if(teleportlocs.Find(AR.name)) continue
var/turf/picked = pick(get_area_turfs(AR.type))
@@ -412,7 +408,7 @@ var/list/teleportlocs = list()
var/list/ghostteleportlocs = list()
/hook/startup/proc/setupGhostTeleportLocs()
for(var/area/AR in all_areas)
for(var/area/AR in world)
if(ghostteleportlocs.Find(AR.name)) continue
if(istype(AR, /area/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome) || istype(AR, /area/shuttle/specops/centcom))
ghostteleportlocs += AR.name
@@ -425,3 +421,8 @@ var/list/ghostteleportlocs = list()
ghostteleportlocs = sortAssoc(ghostteleportlocs)
return 1
/area/proc/get_name()
if(secret_name)
return "Unknown Area"
return name

View File

@@ -185,6 +185,12 @@
to_chat(user, "[bicon(src)] That's [f_name] [suffix]")
to_chat(user,desc)
if(user.client?.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
to_chat(user, description_info)
if(user.client?.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
user.client.statpanel = "Examine" // Switch to stat panel
return distance == -1 || (get_dist(src, user) <= distance)
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.
@@ -197,6 +203,20 @@
. = new_dir != dir
dir = new_dir
// Called to set the atom's density and used to add behavior to density changes.
/atom/proc/set_density(var/new_density)
if(density == new_density)
return FALSE
density = !!new_density // Sanitize to be strictly 0 or 1
return TRUE
// Called to set the atom's invisibility and usd to add behavior to invisibility changes.
/atom/proc/set_invisibility(var/new_invisibility)
if(invisibility == new_invisibility)
return FALSE
invisibility = new_invisibility
return TRUE
/atom/proc/ex_act()
return

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