mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Merge branch 'master' of https://github.com/Yawn-Wider/YWPolarisVore into May2020UpstreamPull
This commit is contained in:
@@ -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("|")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
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, "")
|
||||
add_underlay_adapter(T, , node_dir, "-supply")
|
||||
add_underlay_adapter(T, node, node_dir, "-scrubbers")
|
||||
else
|
||||
add_underlay_adapter(T, node, node_dir, "")
|
||||
add_underlay_adapter(T, , node_dir, "-supply")
|
||||
add_underlay_adapter(T, , node_dir, "-scrubbers")
|
||||
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")
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -55,4 +55,6 @@
|
||||
#define PTO_SCIENCE "Science"
|
||||
#define PTO_EXPLORATION "Exploration"
|
||||
#define PTO_CARGO "Cargo"
|
||||
#define PTO_CIVILIAN "Civilian"
|
||||
#define PTO_CIVILIAN "Civilian"
|
||||
|
||||
#define DEPARTMENT_TALON "ITV Talon"
|
||||
|
||||
6
code/__defines/preferences.dm
Normal file
6
code/__defines/preferences.dm
Normal 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
|
||||
@@ -17,4 +17,5 @@
|
||||
#define PROTOLATHE 0x0002 //New stuff. Uses glass/metal/chemicals
|
||||
#define MECHFAB 0x0004 //Mechfab
|
||||
#define CHASSIS 0x0008 //For protolathe, but differently
|
||||
#define PROSFAB 0x0010 //For prosthetics fab
|
||||
#define PROSFAB 0x0010 //For prosthetics fab
|
||||
#define AUTOLATHE 32 //YW add, for autolathe
|
||||
49
code/__defines/shields.dm
Normal file
49
code/__defines/shields.dm
Normal 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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,4 +24,16 @@
|
||||
if(A == myarea) //The loc of a turf is the area it is in.
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client.buildmode)
|
||||
if(client && client.buildmode)
|
||||
build_click(src, client.buildmode, params, A)
|
||||
return
|
||||
|
||||
|
||||
@@ -358,11 +358,13 @@
|
||||
mymob.radio_use_icon.color = ui_color
|
||||
mymob.radio_use_icon.alpha = ui_alpha
|
||||
|
||||
mymob.client.screen = list()
|
||||
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
|
||||
|
||||
mymob.client.screen += hud_elements
|
||||
mymob.client.screen += src.adding + src.hotkeybuttons
|
||||
mymob.client.screen += mymob.client.void
|
||||
inventory_shown = 0
|
||||
|
||||
return
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
6
code/controllers/ProcessScheduler/.gitignore
vendored
6
code/controllers/ProcessScheduler/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
/bower_components
|
||||
/node_modules
|
||||
/ProcessScheduler.dmb
|
||||
/ProcessScheduler.int
|
||||
/ProcessScheduler.rsc
|
||||
/*.lk
|
||||
@@ -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/>.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
[](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.
|
||||
|
||||
|
||||
[](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.
|
||||
|
||||
@@ -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": "*"
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
@@ -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]
|
||||
@@ -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": "*"
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
37
code/controllers/subsystems/events2.dm
Normal file
37
code/controllers/subsystems/events2.dm
Normal 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
|
||||
369
code/controllers/subsystems/game_master.dm
Normal file
369
code/controllers/subsystems/game_master.dm
Normal 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.
|
||||
123
code/controllers/subsystems/open_space.dm
Normal file
123
code/controllers/subsystems/open_space.dm
Normal 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.
|
||||
@@ -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)
|
||||
|
||||
@@ -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,7 +133,11 @@ SUBSYSTEM_DEF(skybox)
|
||||
skybox_cache["[z]"] = generate_skybox(z)
|
||||
|
||||
for(var/client/C)
|
||||
C.update_skybox(1)
|
||||
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
|
||||
/datum/skybox_settings
|
||||
|
||||
559
code/controllers/subsystems/ticker.dm
Normal file
559
code/controllers/subsystems/ticker.dm
Normal 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
|
||||
@@ -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,7 +353,8 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
if("cancel")
|
||||
if(usr.client.holder)
|
||||
reset()
|
||||
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)
|
||||
config.allow_vote_restart = !config.allow_vote_restart
|
||||
|
||||
@@ -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
|
||||
344
code/datums/autolathe/arms_1.dm
Normal file
344
code/datums/autolathe/arms_1.dm
Normal 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
|
||||
|
||||
|
||||
56
code/datums/autolathe/arms_1_vr.dm
Normal file
56
code/datums/autolathe/arms_1_vr.dm
Normal 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
|
||||
|
||||
74
code/datums/autolathe/arms_1_yw.dm
Normal file
74
code/datums/autolathe/arms_1_yw.dm
Normal 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
|
||||
*/
|
||||
502
code/datums/autolathe/autolathe_yw.dm
Normal file
502
code/datums/autolathe/autolathe_yw.dm
Normal 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
|
||||
51
code/datums/autolathe/devices_1.dm
Normal file
51
code/datums/autolathe/devices_1.dm
Normal 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)
|
||||
5
code/datums/autolathe/devices_1_vr.dm
Normal file
5
code/datums/autolathe/devices_1_vr.dm
Normal 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)
|
||||
140
code/datums/autolathe/engineering_1.dm
Normal file
140
code/datums/autolathe/engineering_1.dm
Normal 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)
|
||||
11
code/datums/autolathe/engineering_1_vr.dm
Normal file
11
code/datums/autolathe/engineering_1_vr.dm
Normal 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)
|
||||
209
code/datums/autolathe/general_1.dm
Normal file
209
code/datums/autolathe/general_1.dm
Normal 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
|
||||
|
||||
23
code/datums/autolathe/general_1_vr.dm
Normal file
23
code/datums/autolathe/general_1_vr.dm
Normal 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)
|
||||
71
code/datums/autolathe/medical_1.dm
Normal file
71
code/datums/autolathe/medical_1.dm
Normal 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)
|
||||
|
||||
|
||||
|
||||
5
code/datums/autolathe/medical_1_vr.dm
Normal file
5
code/datums/autolathe/medical_1_vr.dm
Normal 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)
|
||||
69
code/datums/autolathe/tools_1.dm
Normal file
69
code/datums/autolathe/tools_1.dm
Normal 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)
|
||||
5
code/datums/autolathe/tools_1_vr.dm
Normal file
5
code/datums/autolathe/tools_1_vr.dm
Normal 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)
|
||||
15
code/datums/autolathe/tools_1_yw.dm
Normal file
15
code/datums/autolathe/tools_1_yw.dm
Normal 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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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."
|
||||
general += G
|
||||
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
|
||||
|
||||
|
||||
6
code/datums/game_masters/_common.dm
Normal file
6
code/datums/game_masters/_common.dm
Normal 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.
|
||||
89
code/datums/game_masters/default.dm
Normal file
89
code/datums/game_masters/default.dm
Normal 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
|
||||
44
code/datums/game_masters/other_game_masters.dm
Normal file
44
code/datums/game_masters/other_game_masters.dm
Normal 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
|
||||
5
code/datums/outfits/jobs/security_yw.dm
Normal file
5
code/datums/outfits/jobs/security_yw.dm
Normal 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
|
||||
@@ -14,10 +14,25 @@ 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]
|
||||
return network_list
|
||||
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()
|
||||
if(!invalidated)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,8 +227,8 @@
|
||||
|
||||
/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"
|
||||
access = access_armory
|
||||
access = access_armory
|
||||
|
||||
@@ -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
|
||||
|
||||
46
code/datums/wires/shield_generator.dm
Normal file
46
code/datums/wires/shield_generator.dm
Normal 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
|
||||
@@ -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!!!"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
@@ -76,7 +70,7 @@
|
||||
// NOTE: There probably won't be any atoms in these turfs, but just in case we should call these procs.
|
||||
A.contents.Add(T)
|
||||
if(old_area)
|
||||
// Handle dynamic lighting update if
|
||||
// Handle dynamic lighting update if
|
||||
if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting)
|
||||
if(A.dynamic_lighting)
|
||||
T.lighting_build_overlay()
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user