Merge remote-tracking branch 'upstream/master' into TFF-Mining_Ops_Move

This commit is contained in:
TheFurryFeline
2020-04-15 07:34:44 -04:00
613 changed files with 152134 additions and 22225 deletions
@@ -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("|")
+11 -1
View File
@@ -209,8 +209,18 @@ Pipelines + Other Objects -> Pipe network
connect_types = CONNECT_TYPE_SUPPLY
layer = PIPES_SUPPLY_LAYER
icon_connect_type = "-supply"
if(PIPING_LAYER_FUEL)
icon_state = "[icon_state]-fuel"
connect_types = CONNECT_TYPE_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
if(PIPING_LAYER_AUX)
icon_state = "[icon_state]-aux"
connect_types = CONNECT_TYPE_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
if(pipe_flags & PIPING_ALL_LAYER)
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
// Or if we were to do it the TG way...
// pixel_x = PIPE_PIXEL_OFFSET_X(piping_layer)
// pixel_y = PIPE_PIXEL_OFFSET_Y(piping_layer)
@@ -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,
+40
View File
@@ -93,6 +93,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/cap/visible/fuel
name = "fuel pipe endcap"
desc = "An endcap for fuel pipes"
icon_state = "cap-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/cap/visible/aux
name = "aux pipe endcap"
desc = "An endcap for aux pipes"
icon_state = "cap-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/cap/hidden
level = 1
icon_state = "cap"
@@ -117,3 +137,23 @@
layer = PIPES_SUPPLY_LAYER
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/cap/visible/fuel
name = "fuel pipe endcap"
desc = "An endcap for fuel pipes"
icon_state = "cap-f-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/cap/hidden/aux
name = "aux pipe endcap"
desc = "An endcap for aux pipes"
icon_state = "cap-f-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
+54 -7
View File
@@ -108,16 +108,23 @@
underlays.Cut()
var/turf/T = get_turf(src)
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
var/node3_direction = get_dir(src, node3)
// Unfortunately our nodes are not in consistent directions (see atmos_init()) so do the dance...
var/list/directions = list(NORTH, SOUTH, EAST, WEST) // UN-connected directions
directions -= dir
if(node1)
var/node1_direction = get_dir(src, node1)
add_underlay(T, node1, node1_direction, icon_connect_type)
directions -= node1_direction
if(node2)
var/node2_direction = get_dir(src, node2)
add_underlay(T, node2, node2_direction, icon_connect_type)
directions -= node2_direction
if(node3)
var/node3_direction = get_dir(src, node3)
add_underlay(T, node3, node3_direction, icon_connect_type)
directions -= node3_direction
directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
for(var/D in directions)
add_underlay(T,,D,icon_connect_type)
@@ -195,6 +202,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold/visible/fuel
name="Fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold/visible/aux
name="Aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -241,6 +268,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold/hidden/fuel
name="Fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold/hidden/aux
name="Aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
color = PIPE_COLOR_YELLOW
+45 -29
View File
@@ -107,36 +107,12 @@
overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
underlays.Cut()
/*
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
directions -= add_underlay(node1)
directions -= add_underlay(node2)
directions -= add_underlay(node3)
directions -= add_underlay(node4)
for(var/D in directions)
add_underlay(,D)
*/
var/turf/T = get_turf(src)
var/list/directions = list(NORTH, SOUTH, EAST, WEST)
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
var/node3_direction = get_dir(src, node3)
var/node4_direction = get_dir(src, node4)
directions -= dir
directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
for(var/D in directions)
add_underlay(T,,D,icon_connect_type)
// Take advantage of the fact that our nodes are *always* in the same directions (see atmos_init())
add_underlay(T, node1, NORTH, icon_connect_type)
add_underlay(T, node2, SOUTH, icon_connect_type)
add_underlay(T, node3, EAST, icon_connect_type)
add_underlay(T, node4, WEST, icon_connect_type)
/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
..()
@@ -197,6 +173,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold4w/visible/fuel
name="4-way fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map_4way-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold4w/visible/aux
name="4-way aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map_4way-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -243,6 +239,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/manifold4w/hidden/fuel
name="4-way fuel pipe manifold"
desc = "A manifold composed of fuel pipes"
icon_state = "map_4way-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/manifold4w/hidden/aux
name="4-way aux pipe manifold"
desc = "A manifold composed of aux pipes"
icon_state = "map_4way-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
color = PIPE_COLOR_YELLOW
+40
View File
@@ -203,6 +203,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/simple/visible/fuel
name = "Fuel pipe"
desc = "A one meter section of fuel pipe"
icon_state = "intact-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/simple/visible/aux
name = "Aux pipe"
desc = "A one meter section of aux pipe"
icon_state = "intact-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/simple/visible/yellow
color = PIPE_COLOR_YELLOW
@@ -249,6 +269,26 @@
icon_connect_type = "-supply"
color = PIPE_COLOR_BLUE
/obj/machinery/atmospherics/pipe/simple/hidden/fuel
name = "Fuel pipe"
desc = "A one meter section of fuel pipe"
icon_state = "intact-fuel"
connect_types = CONNECT_TYPE_FUEL
piping_layer = PIPING_LAYER_FUEL
layer = PIPES_FUEL_LAYER
icon_connect_type = "-fuel"
color = PIPE_COLOR_YELLOW
/obj/machinery/atmospherics/pipe/simple/hidden/aux
name = "Aux pipe"
desc = "A one meter section of aux pipe"
icon_state = "intact-aux"
connect_types = CONNECT_TYPE_AUX
piping_layer = PIPING_LAYER_AUX
layer = PIPES_AUX_LAYER
icon_connect_type = "-aux"
color = PIPE_COLOR_CYAN
/obj/machinery/atmospherics/pipe/simple/hidden/yellow
color = PIPE_COLOR_YELLOW
+1
View File
@@ -136,6 +136,7 @@
/obj/machinery/atmospherics/pipe/tank/phoron
name = "Pressure Tank (Phoron)"
icon_state = "phoron_map"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL
/obj/machinery/atmospherics/pipe/tank/phoron/New()
air_temporary = new
+35 -14
View File
@@ -4,7 +4,7 @@
/obj/machinery/atmospherics/pipe/simple/visible/universal
name="Universal pipe adapter"
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
icon_state = "map_universal"
pipe_flags = PIPING_ALL_LAYER|PIPING_CARDINAL_AUTONORMALIZE
construction_type = /obj/item/pipe/binary
@@ -42,7 +42,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/universal
name="Universal pipe adapter"
desc = "An adapter for regular, supply and scrubbers pipes"
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_FUEL|CONNECT_TYPE_AUX
icon_state = "map_universal"
pipe_flags = PIPING_ALL_LAYER|PIPING_CARDINAL_AUTONORMALIZE
construction_type = /obj/item/pipe/binary
@@ -81,21 +81,42 @@
var/turf/T = loc
if(node)
var/node_dir = get_dir(src,node)
if(node.icon_connect_type == "-supply")
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
+1 -1
View File
@@ -16,7 +16,7 @@
initialize_directions = SOUTH
pipe_flags = PIPING_DEFAULT_LAYER_ONLY
construction_type = /obj/item/pipe/directional
pipe_state = "passive vent"
pipe_state = "passive_vent"
var/build_killswitch = 1
+1
View File
@@ -1,4 +1,5 @@
#define MC_TICK_CHECK ( ( TICK_USAGE > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
#define CURRENT_RUNLEVEL (2 ** (Master.current_runlevel - 1))
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
#define MC_SPLIT_TICK \
+1 -1
View File
@@ -1,5 +1,5 @@
#define TICK_LIMIT_RUNNING 85 //VOREStation Emergency Edit
#define TICK_LIMIT_RUNNING 80
#define TICK_LIMIT_TO_RUN 70
#define TICK_LIMIT_MC 70
#define TICK_LIMIT_MC_INIT_DEFAULT 98
+11 -5
View File
@@ -34,19 +34,25 @@
#define PIPE_TRIN_T 7 //8 directions: N->S+E, S->N+E, N->S+W, S->N+W, E->W+S, W->E+S, E->W+N, W->E+N
// Pipe connectivity bit flags
#define CONNECT_TYPE_REGULAR 1
#define CONNECT_TYPE_SUPPLY 2
#define CONNECT_TYPE_SCRUBBER 4
#define CONNECT_TYPE_HE 8
#define CONNECT_TYPE_FUEL 16 // TODO - Implement this! Its piping so better ask Leshana
#define CONNECT_TYPE_REGULAR 1 //Center of tile, 'normal'
#define CONNECT_TYPE_SUPPLY 2 //Atmos air supply pipes
#define CONNECT_TYPE_SCRUBBER 4 //Atmos air scrubber pipes
#define CONNECT_TYPE_HE 8 //Heat exchanger pipes
#define CONNECT_TYPE_FUEL 16 //Fuel pipes for overmap ships
#define CONNECT_TYPE_AUX 32 //Aux pipes for 'other' things (airlocks, etc)
// We are based on the three named layers of supply, regular, and scrubber.
#define PIPING_LAYER_SUPPLY 1
#define PIPING_LAYER_REGULAR 2
#define PIPING_LAYER_SCRUBBER 3
#define PIPING_LAYER_FUEL 4
#define PIPING_LAYER_AUX 5
#define PIPING_LAYER_DEFAULT PIPING_LAYER_REGULAR
// We offset the layer values of the different pipe types to ensure they look nice
#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.05)
#define PIPES_AUX_LAYER (PIPES_LAYER - 0.04)
#define PIPES_FUEL_LAYER (PIPES_LAYER - 0.03)
#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.02)
#define PIPES_SUPPLY_LAYER (PIPES_LAYER - 0.01)
#define PIPES_HE_LAYER (PIPES_LAYER + 0.01)
+13 -4
View File
@@ -1,7 +1,16 @@
#define GAME_STATE_PREGAME 1
#define GAME_STATE_SETTING_UP 2
#define GAME_STATE_PLAYING 3
#define GAME_STATE_FINISHED 4
// Ticker game states, turns out these are equivilent to runlevels1
#define GAME_STATE_INIT 0 // RUNLEVEL_INIT
#define GAME_STATE_PREGAME 1 // RUNLEVEL_LOBBY
#define GAME_STATE_SETTING_UP 2 // RUNLEVEL_SETUP
#define GAME_STATE_PLAYING 3 // RUNLEVEL_GAME
#define GAME_STATE_FINISHED 4 // RUNLEVEL_POSTGAME
//End game state, to manage round end.
#define END_GAME_NOT_OVER 1 // Still playing normally
#define END_GAME_MODE_FINISHED 2 // Mode has finished but game has not, wait for game to end too.
#define END_GAME_READY_TO_END 3 // Game and Mode have finished, do rounded stuff.
#define END_GAME_ENDING 4 // Just waiting for ending timer.
#define END_GAME_DELAYED 5 // Admin has delayed the round.
// Security levels.
#define SEC_LEVEL_GREEN 0
+1
View File
@@ -52,3 +52,4 @@
//---------------
//#define isturf(D) istype(D, /turf) //Built in
#define isopenspace(A) istype(A, /turf/simulated/open)
#define isspace(A) istype(A, /turf/space)
+17
View File
@@ -70,10 +70,27 @@ 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
// 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)
#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
+3 -1
View File
@@ -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
View File
@@ -0,0 +1,6 @@
#define EXAMINE_MODE_DEFAULT 0
#define EXAMINE_MODE_INCLUDE_USAGE 1
#define EXAMINE_MODE_SWITCH_TO_PANEL 2
// Should be one higher than the above
#define EXAMINE_MODE_MAX 3
+49
View File
@@ -0,0 +1,49 @@
#define SHIELD_DAMTYPE_PHYSICAL 1 // Physical damage - bullets, meteors, various hand objects - aka. "brute" damtype.
#define SHIELD_DAMTYPE_EM 2 // Electromagnetic damage - Ion weaponry, stun beams, ...
#define SHIELD_DAMTYPE_HEAT 3 // Heat damage - Lasers, fire
// TODO - Thats power not energy you silly goose! I think we mean 45 kilojoules
#define ENERGY_PER_HP (45 KILOWATTS)// Base amount energy that will be deducted from the generator's internal reserve per 1 HP of damage taken
#define ENERGY_UPKEEP_PER_TILE (4 KILOWATTS) // Base upkeep per tile protected. Multiplied by various enabled shield modes. Without them the field does literally nothing.
#define ENERGY_UPKEEP_IDLE 45 // Base upkeep when idle; modified by other factors.
// This shield model is slightly inspired by Sins of a Solar Empire series. In short, shields are designed to analyze what hits them, and adapt themselves against that type of damage.
// This means shields will become increasingly effective against things like emitters - as they will adapt to heat damage, however they will be vulnerable to brute and EM damage.
// In a theoretical assault scenario, it is best to combine all damage types, so mitigation can't build up. The value is capped to prevent full scale invulnerability.
#define MAX_MITIGATION_BASE 40 // % Base maximal reachable mitigation.
#define MAX_MITIGATION_RESEARCH 10 // % Added to MAX_MITIGATION_BASE when generator is built using more advanced components. This value is added for each "tier" of used component, ie. basic one has 1, the best one has 5. Actual maximum should be 90% in this case (with best components). Make sure you won't get above 100%!
#define MITIGATION_HIT_GAIN 5 // Mitigation gain per hit of respective damage type.
#define MITIGATION_HIT_LOSS 4 // Mitigation loss per hit. If we get hit once by EM damage type, EM mitigation will grow, while Physical and Heat mitigation values drop.
#define MITIGATION_LOSS_PASSIVE 0.5 // Mitigation of all damage types will drop by this every tick, up to 0.
// Shield modes allow you to calibrate the field to fit specific needs. It is, for example, possible to create a field that will block airflow, but let people pass.
// Relevant mode bitflags (maximal of 16 flags due to current BYOND limitations)
#define MODEFLAG_HYPERKINETIC 1
#define MODEFLAG_PHOTONIC 2
#define MODEFLAG_NONHUMANS 4
#define MODEFLAG_HUMANOIDS 8
#define MODEFLAG_ANORGANIC 16
#define MODEFLAG_ATMOSPHERIC 32
#define MODEFLAG_HULL 64
#define MODEFLAG_BYPASS 128
#define MODEFLAG_OVERCHARGE 256
#define MODEFLAG_MODULATE 512
#define MODEFLAG_MULTIZ 1024
#define MODEFLAG_EM 2048
// Return codes for shield hits.
#define SHIELD_ABSORBED 1 // The shield has completely absorbed the hit
#define SHIELD_BREACHED_MINOR 2 // The hit was absorbed, but a small gap will be created in the field (1-3 tiles)
#define SHIELD_BREACHED_MAJOR 3 // Same as above, with 2-5 tile gap
#define SHIELD_BREACHED_CRITICAL 4 // Same as above, with 4-8 tile gap
#define SHIELD_BREACHED_FAILURE 5 // Same as above, with 8-16 tile gap. Occurs when the hit exhausts all remaining shield energy.
#define SHIELD_OFF 0 // The shield is offline
#define SHIELD_DISCHARGING 1 // The shield is shutting down and discharging.
#define SHIELD_RUNNING 2 // The shield is running
#define SHIELD_IDLE 3 // The shield is being kept at an idle state
#define SHIELD_SPINNING_UP 4 // Going from idle to running
#define SHIELD_SHUTDOWN_DISPERSION_RATE (10000 KILOWATTS) // The rate at which shield energy disperses when shutdown is initiated.
+1
View File
@@ -53,6 +53,7 @@
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
#define LANGUAGE_BLOB "Blob"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.
+5 -1
View File
@@ -57,6 +57,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_SKYBOX 30
#define INIT_ORDER_MAPPING 25
#define INIT_ORDER_DECALS 20
#define INIT_ORDER_JOB 17
#define INIT_ORDER_ATOMS 15
#define INIT_ORDER_MACHINES 10
#define INIT_ORDER_SHUTTLES 3
@@ -69,10 +70,12 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_HOLOMAPS -5
#define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_ALARM -7
#define INIT_ORDER_OPENSPACE -10
#define INIT_ORDER_XENOARCH -20
#define INIT_ORDER_CIRCUIT -21
#define INIT_ORDER_AI -22
#define INIT_ORDER_JOB -23
#define INIT_ORDER_GAME_MASTER -24
#define INIT_ORDER_TICKER -50
#define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init.
@@ -91,6 +94,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_PROCESS 45
#define FIRE_PRIORITY_DEFAULT 50
#define FIRE_PRIORITY_TICKER 60
#define FIRE_PRIORITY_PLANETS 75
#define FIRE_PRIORITY_MACHINES 100
#define FIRE_PRIORITY_PROJECTILES 150
+1 -1
View File
@@ -2,5 +2,5 @@
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, length(ref)-6) ) )
#define GET_TYPEID(ref) ( ( (length(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, -7) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
+11 -1
View File
@@ -27,7 +27,7 @@
#define VV_NORMAL_LIST_NO_EXPAND_THRESHOLD 50
#define VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD 150
#define IS_VALID_ASSOC_KEY(V) (istext(V) || isdatum(V) || islist(V))
#define IS_VALID_ASSOC_KEY(V) (!isnum(V))
//Helpers for vv_get_dropdown()
#define VV_DROPDOWN_OPTION(href_key, name) . += "<option value='?_src_=vars;[href_key]=TRUE;target=\ref[src]'>[name]</option>"
@@ -35,6 +35,16 @@
//Helpers for vv_do_topic(list/href_list)
#define IF_VV_OPTION(href_key) if(href_list[href_key])
// vv_do_list() keys
#define VV_HK_LIST_ADD "listadd"
#define VV_HK_LIST_EDIT "listedit"
#define VV_HK_LIST_CHANGE "listchange"
#define VV_HK_LIST_REMOVE "listremove"
#define VV_HK_LIST_ERASE_NULLS "listnulls"
#define VV_HK_LIST_ERASE_DUPES "listdupes"
#define VV_HK_LIST_SHUFFLE "listshuffle"
#define VV_HK_LIST_SET_LENGTH "listlen"
// /datum
#define VV_HK_DELETE "delete"
#define VV_HK_EXPOSE "expose"
+13 -1
View File
@@ -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
+1 -1
View File
@@ -246,7 +246,7 @@
var/turf/speaker = get_turf(R)
if(speaker)
for(var/turf/T in hear(R.canhear_range,speaker))
speaker_coverage[T] = T
speaker_coverage[T] = R
// Try to find all the players who can hear the message
+4 -4
View File
@@ -676,7 +676,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
@@ -694,7 +694,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
@@ -708,7 +708,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
@@ -723,7 +723,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
+1 -1
View File
@@ -43,7 +43,7 @@
next_click = world.time + 1
if(client.buildmode)
if(client && client.buildmode)
build_click(src, client.buildmode, params, A)
return
+6 -4
View File
@@ -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
+4 -11
View File
@@ -44,17 +44,10 @@
. = ..()
client.update_skybox(TRUE)
/mob/Move()
var/old_z = get_z(src)
. = ..()
if(. && client)
client.update_skybox(old_z != get_z(src))
/mob/forceMove()
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/set_viewsize()
. = ..()
@@ -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()
-42
View File
@@ -1,42 +0,0 @@
var/global/datum/controller/process/ticker/tickerProcess
/datum/controller/process/ticker
var/lastTickerTimeDuration
var/lastTickerTime
/datum/controller/process/ticker/setup()
name = "ticker"
schedule_interval = 20 // every 2 seconds
lastTickerTime = world.timeofday
if(!ticker)
ticker = new
tickerProcess = src
spawn(0)
if(ticker)
ticker.pregame()
/datum/controller/process/ticker/doWork()
var/currentTime = world.timeofday
if(currentTime < lastTickerTime) // check for midnight rollover
lastTickerTimeDuration = (currentTime - (lastTickerTime - TICKS_IN_DAY)) / TICKS_IN_SECOND
else
lastTickerTimeDuration = (currentTime - lastTickerTime) / TICKS_IN_SECOND
lastTickerTime = currentTime
ticker.process()
/datum/controller/process/ticker/proc/getLastTickerTimeDuration()
return lastTickerTimeDuration
// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem!
/datum/controller/process/ticker/proc/HasRoundStarted()
return (ticker && ticker.current_state >= GAME_STATE_PLAYING)
/datum/controller/process/ticker/proc/IsRoundInProgress()
return (ticker && ticker.current_state == GAME_STATE_PLAYING)
+10 -2
View File
@@ -125,6 +125,8 @@ var/const/EXP_FREQ = 1361
var/const/MED_I_FREQ = 1485
var/const/SEC_I_FREQ = 1475
var/const/TALON_FREQ = 1481 //VOREStation Add
var/list/radiochannels = list(
"Common" = PUB_FREQ,
"Science" = SCI_FREQ,
@@ -142,7 +144,8 @@ var/list/radiochannels = list(
"AI Private" = AI_FREQ,
"Entertainment" = ENT_FREQ,
"Medical(I)" = MED_I_FREQ,
"Security(I)" = SEC_I_FREQ
"Security(I)" = SEC_I_FREQ,
"Talon" = TALON_FREQ //VOREStation Add
)
// central command channels, i.e deathsquid & response teams
@@ -154,6 +157,8 @@ var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ)
//Department channels, arranged lexically
var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ)
var/list/OFFMAP_FREQS = list(TALON_FREQ) //VOREStation Add
#define TRANSMISSION_WIRE 0
#define TRANSMISSION_RADIO 1
@@ -189,7 +194,10 @@ var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC
return "entradio"
if(frequency in DEPT_FREQS)
return "deptradio"
//VOREStation Add
if(frequency in OFFMAP_FREQS)
return "expradio"
//VOREStation Add End
return "radio"
/* filters */
+9 -1
View File
@@ -264,10 +264,12 @@ var/list/gamemode_cache = list()
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/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes.
var/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
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -877,6 +879,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
@@ -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
-4
View File
@@ -50,8 +50,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/current_runlevel //for scheduling different subsystems for different stages of the round
var/dbg_is_running_subsystem = FALSE // TEMPORARY DEBUGGING - true only while we are actually waiting on a subsystem
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
@@ -476,11 +474,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
+17 -4
View File
@@ -168,11 +168,12 @@
statclick = new/obj/effect/statclick/debug(null, "Initializing...", src)
if(can_fire && !(SS_NO_FIRE & flags))
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
else
if(SS_NO_FIRE & flags)
msg = "NO FIRE\t[msg]"
else if(can_fire <= 0)
msg = "OFFLINE\t[msg]"
else
msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]"
var/title = name
if (can_fire)
@@ -202,3 +203,15 @@
//usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
//should attempt to salvage what it can from the old instance of subsystem
/datum/controller/subsystem/Recover()
// Suspends this subsystem from being queued for running. If already in the queue, sleeps until idle. Returns FALSE if the subsystem was already suspended.
/datum/controller/subsystem/proc/suspend()
. = (can_fire > 0) // Return true if we were previously runnable, false if previously suspended.
can_fire = FALSE
// Safely sleep in a loop until the subsystem is idle, (or its been un-suspended somehow)
while(can_fire <= 0 && state != SS_IDLE)
stoplag() // Safely sleep in a loop until
// Wakes a suspended subsystem.
/datum/controller/subsystem/proc/wake()
can_fire = TRUE
+1 -1
View File
@@ -1,5 +1,5 @@
SUBSYSTEM_DEF(events)
name = "Events"
name = "Events" // VOREStation Edit - This is still the main events subsystem for us.
wait = 2 SECONDS
var/tmp/list/currentrun = null
+37
View File
@@ -0,0 +1,37 @@
// This is a simple ticker for the new event system.
// The logic that determines what events get chosen is held inside a seperate subsystem.
SUBSYSTEM_DEF(event_ticker)
name = "Events (Ticker)"
wait = 2 SECONDS
runlevels = RUNLEVEL_GAME
// List of `/datum/event2/event`s that are currently active, and receiving process() ticks.
var/list/active_events = list()
// List of `/datum/event2/event`s that finished, and are here for showing at roundend, if that's desired.
var/list/finished_events = list()
// Process active events.
/datum/controller/subsystem/event_ticker/fire(resumed)
for(var/E in active_events)
var/datum/event2/event/event = E
event.process()
if(event.finished)
event_finished(event)
// Starts an event, independent of the GM system.
// This means it will always run, and won't affect the GM system in any way, e.g. not putting the event off limits after one use.
/datum/controller/subsystem/event_ticker/proc/start_event(event_type)
var/datum/event2/event/E = new event_type()
E.execute()
event_started(E)
/datum/controller/subsystem/event_ticker/proc/event_started(datum/event2/event/E)
log_debug("Event [E.type] is now being ran.")
active_events += E
/datum/controller/subsystem/event_ticker/proc/event_finished(datum/event2/event/E)
log_debug("Event [E.type] has finished.")
active_events -= E
finished_events += E
+369
View File
@@ -0,0 +1,369 @@
// This is a sort of successor to the various event systems created over the years. It is designed to be just a tad smarter than the
// previous ones, checking various things like player count, department size and composition, individual player activity,
// individual player (IC) skill, and such, in order to try to choose the best events to take in order to add spice or variety to
// the round.
// This subsystem holds the logic that chooses events. Actual event processing is handled in a seperate subsystem.
SUBSYSTEM_DEF(game_master)
name = "Events (Game Master)"
wait = 1 MINUTE
runlevels = RUNLEVEL_GAME
// The GM object is what actually chooses events.
// It's held in a seperate object for better encapsulation, and allows for different 'flavors' of GMs to be made, that choose events differently.
var/datum/game_master/GM = null
var/game_master_type = /datum/game_master/default
var/list/available_events = list() // A list of meta event objects.
var/danger = 0 // The GM's best guess at how chaotic the round is. High danger makes it hold back.
var/staleness = -20 // Determines liklihood of the GM doing something, increases over time.
var/next_event = 0 // Minimum amount of time of nothingness until the GM can pick something again.
var/debug_messages = FALSE // If true, debug information is written to `log_debug()`.
/datum/controller/subsystem/game_master/Initialize()
var/list/subtypes = subtypesof(/datum/event2/meta)
for(var/T in subtypes)
var/datum/event2/meta/M = new T()
if(!M.name)
continue
available_events += M
GM = new game_master_type()
if(config && !config.enable_game_master)
can_fire = FALSE
return ..()
/datum/controller/subsystem/game_master/fire(resumed)
adjust_staleness(1)
adjust_danger(-1)
var/global_afk = metric.assess_all_living_mobs()
global_afk = abs(global_afk - 100)
global_afk = round(global_afk / 100, 0.1)
adjust_staleness(global_afk) // Staleness increases faster if more people are less active.
if(GM.ignore_time_restrictions || next_event < world.time)
if(prob(staleness) && pre_event_checks())
do_event_decision()
/datum/controller/subsystem/game_master/proc/do_event_decision()
log_game_master("Going to choose an event.")
var/datum/event2/meta/event_picked = GM.choose_event()
if(event_picked)
run_event(event_picked)
next_event = world.time + rand(GM.decision_cooldown_lower_bound, GM.decision_cooldown_upper_bound)
/datum/controller/subsystem/game_master/proc/debug_gm()
can_fire = TRUE
staleness = 100
debug_messages = TRUE
/datum/controller/subsystem/game_master/proc/run_event(datum/event2/meta/chosen_event)
var/datum/event2/event/E = chosen_event.make_event()
chosen_event.times_ran++
if(!chosen_event.reusable)
// Disable this event, so it only gets picked once.
chosen_event.enabled = FALSE
if(chosen_event.event_class)
// Disable similar events, too.
for(var/M in available_events)
var/datum/event2/meta/meta = M
if(meta.event_class == chosen_event.event_class)
meta.enabled = FALSE
SSevent_ticker.event_started(E)
adjust_danger(chosen_event.chaos)
adjust_staleness(-(10 + chosen_event.chaos)) // More chaotic events reduce staleness more, e.g. a 25 chaos event will reduce it by 35.
// Tell the game master that something dangerous happened, e.g. someone dying, station explosions.
/datum/controller/subsystem/game_master/proc/adjust_danger(amount)
amount *= GM.danger_modifier
danger = round(between(0, danger + amount, 1000), 0.1)
// Tell the game master that things are getting boring if positive, or something interesting if negative..
/datum/controller/subsystem/game_master/proc/adjust_staleness(amount)
amount *= GM.staleness_modifier
staleness = round( between(-20, staleness + amount, 100), 0.1)
// These are ran before committing to an event.
// Returns TRUE if the system is allowed to procede, otherwise returns FALSE.
/datum/controller/subsystem/game_master/proc/pre_event_checks(quiet = FALSE)
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
if(!quiet)
log_game_master("Unable to start event: Ticker is nonexistant, or the game is not ongoing.")
return FALSE
if(GM.ignore_time_restrictions)
return TRUE
if(next_event > world.time) // Sanity.
if(!quiet)
log_game_master("Unable to start event: Time until next event is approximately [round((next_event - world.time) / (1 MINUTE))] minute(s)")
return FALSE
// Last minute antagging is bad for humans to do, so the GM will respect the start and end of the round.
var/mills = round_duration_in_ticks
var/mins = round((mills % 36000) / 600)
var/hours = round(mills / 36000)
// if(hours < 1 && mins <= 20) // Don't do anything for the first twenty minutes of the round.
// if(!quiet)
// log_debug("Game Master unable to start event: It is too early.")
// return FALSE
if(hours >= 2 && mins >= 40) // Don't do anything in the last twenty minutes of the round, as well.
if(!quiet)
log_game_master("Unable to start event: It is too late.")
return FALSE
return TRUE
/datum/controller/subsystem/game_master/proc/choose_game_master(mob/user)
var/list/subtypes = subtypesof(/datum/game_master)
var/new_gm_path = input(user, "What kind of Game Master do you want?", "New Game Master", /datum/game_master/default) as null|anything in subtypes
if(new_gm_path)
log_and_message_admins("has swapped the current GM ([GM.type]) for a new GM ([new_gm_path]).")
GM = new new_gm_path(src)
/datum/controller/subsystem/game_master/proc/log_game_master(message)
if(debug_messages)
log_debug("GAME MASTER: [message]")
// This object makes the actual decisions.
/datum/game_master
// Multiplier for how much 'danger' is accumulated. Higer generally makes it possible for more dangerous events to be picked.
var/danger_modifier = 1.0
// Ditto. Higher numbers generally result in more events occuring in a round.
var/staleness_modifier = 1.0
var/decision_cooldown_lower_bound = 5 MINUTES // Lower bound for how long to wait until -the potential- for another event being decided.
var/decision_cooldown_upper_bound = 20 MINUTES // Same, but upper bound.
var/ignore_time_restrictions = FALSE // Useful for debugging without needing to wait 20 minutes each time.
var/ignore_round_chaos = FALSE // If true, the system will happily choose back to back intense events like meteors and blobs, Dwarf Fortress style.
/client/proc/show_gm_status()
set category = "Debug"
set name = "Show GM Status"
set desc = "Shows you what the GM is thinking. If only that existed in real life..."
if(check_rights(R_ADMIN|R_EVENT|R_DEBUG))
SSgame_master.interact(usr)
else
to_chat(usr, span("warning", "You do not have sufficent rights to view the GM panel, sorry."))
/datum/controller/subsystem/game_master/proc/interact(var/client/user)
if(!user)
return
// Using lists for string tree conservation.
var/list/dat = list("<html><head><title>Automated Game Master Event System</title></head><body>")
// Makes the system turn on or off.
dat += href(src, list("toggle" = 1), "\[Toggle GM\]")
dat += " | "
// Makes the system not care about staleness or being near round-end.
dat += href(src, list("toggle_time_restrictions" = 1), "\[Toggle Time Restrictions\]")
dat += " | "
// Makes the system not care about how chaotic the round might be.
dat += href(src, list("toggle_chaos_throttle" = 1), "\[Toggle Chaos Throttling\]")
dat += " | "
// Makes the system immediately choose an event, while still bound to factors like danger, weights, and department staffing.
dat += href(src, list("force_choose_event" = 1), "\[Force Event Decision\]")
dat += "<br>"
// Swaps out the current GM for a new one with different ideas on what a good event might be.
dat += href(src, list("change_gm" = 1), "\[Change GM\]")
dat += "<br>"
dat += "Current GM Type: [GM.type]<br>"
dat += "State: [can_fire ? "Active": "Inactive"]<br>"
dat += "Status: [pre_event_checks(TRUE) ? "Ready" : "Suppressed"]<br><br>"
dat += "Staleness: [staleness] "
dat += href(src, list("set_staleness" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Staleness is an estimate of how boring the round might be, and if an event should be done. It is increased passively over time, \
and increases faster if people are AFK. It deceases when events and certain 'interesting' things happen in the round.</i><br>"
dat += "Danger: [danger] "
dat += href(src, list("set_danger" = 1), "\[Set\]")
dat += "<br>"
dat += "<i>Danger is an estimate of how chaotic the round has been so far. It is decreased passively over time, and is increased by having \
certain chaotic events be selected, or chaotic things happen in the round. A sufficently high amount of danger will make the system \
avoid using destructive events, to avoid pushing the station over the edge.</i><br>"
dat += "<h2>Player Activity:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Category</th>"
dat += "<th>Activity Percentage</th>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Living Mobs</td>"
dat += "<td>[metric.assess_all_living_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<td>All Ghosts</td>"
dat += "<td>[metric.assess_all_dead_mobs()]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Departments</td>"
dat += "</tr>"
for(var/D in metric.departments)
dat += "<tr>"
dat += "<td>[D]</td>"
dat += "<td>[metric.assess_department(D)]%</td>"
dat += "</tr>"
dat += "<tr>"
dat += "<th colspan='2'>Players</td>"
dat += "</tr>"
for(var/P in player_list)
var/mob/M = P
dat += "<tr>"
dat += "<td>[M] ([M.ckey])</td>"
dat += "<td>[metric.assess_player_activity(M)]%</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events available:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Name</th>"
dat += "<th>Involved Departments</th>"
dat += "<th>Chaos</th>"
dat += "<th>Chaotic Threshold</th>"
dat += "<th>Weight</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in available_events)
var/datum/event2/meta/event = E
dat += "<tr>"
if(!event.enabled)
dat += "<td><strike>[event.name]</strike></td>"
else
dat += "<td>[event.name]</td>"
dat += "<td>[english_list(event.departments)]</td>"
dat += "<td>[event.chaos]</td>"
dat += "<td>[event.chaotic_threshold]</td>"
dat += "<td>[event.get_weight()]</td>"
dat += "<td>[href(event, list("force" = 1), "\[Force\]")] [href(event, list("toggle" = 1), "\[Toggle\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "<h2>Events active:</h2>"
dat += "Current time: [world.time]"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Time Started</th>"
dat += "<th>Time to Announce</th>"
dat += "<th>Time to End</th>"
dat += "<th>Announced</th>"
dat += "<th>Started</th>"
dat += "<th>Ended</th>"
dat += "<th>Buttons</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.active_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_to_announce ? event.time_to_announce : "NULL"]</td>"
dat += "<td>[event.time_to_end ? event.time_to_end : "NULL"]</td>"
dat += "<td>[event.announced ? "Yes" : "No"]</td>"
dat += "<td>[event.started ? "Yes" : "No"]</td>"
dat += "<td>[event.ended ? "Yes" : "No"]</td>"
dat += "<td>[href(event, list("abort" = 1), "\[Abort\]")]</td>"
dat += "</tr>"
dat += "</table>"
dat += "</body></html>"
dat += "<h2>Events completed:</h2>"
dat += "<table border='1' style='width:100%'>"
dat += "<tr>"
dat += "<th>Event Type</th>"
dat += "<th>Start Time</th>"
dat += "<th>Finish Time</th>"
dat += "</tr>"
for(var/E in SSevent_ticker.finished_events)
var/datum/event2/event/event = E
dat += "<tr>"
dat += "<td>[event.type]</td>"
dat += "<td>[event.time_started]</td>"
dat += "<td>[event.time_finished]</td>"
dat += "</tr>"
dat += "</body></html>"
var/datum/browser/popup = new(user, "game_master_debug", "Automated Game Master Event System", 800, 500, src)
popup.set_content(dat.Join())
popup.open()
/datum/controller/subsystem/game_master/Topic(href, href_list)
if(..())
return
if(href_list["close"]) // Needed or the window re-opens after closing, making it last forever.
return
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
message_admins("[usr] has attempted to modify the Game Master values without sufficent privilages.")
return
if(href_list["toggle"])
can_fire = !can_fire
message_admins("GM was [!can_fire ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_time_restrictions"])
GM.ignore_time_restrictions = !GM.ignore_time_restrictions
message_admins("GM event time restrictions was [GM.ignore_time_restrictions ? "dis" : "en"]abled by [usr.key].")
if(href_list["toggle_chaos_throttle"])
GM.ignore_round_chaos = !GM.ignore_round_chaos
message_admins("GM event chaos restrictions was [GM.ignore_round_chaos ? "dis" : "en"]abled by [usr.key].")
if(href_list["force_choose_event"])
do_event_decision()
message_admins("[usr.key] forced the Game Master to choose an event immediately.")
if(href_list["change_gm"])
choose_game_master(usr)
if(href_list["set_staleness"])
var/amount = input(usr, "How much staleness should there be?", "Game Master") as null|num
if(!isnull(amount))
staleness = amount
message_admins("GM staleness was set to [amount] by [usr.key].")
if(href_list["set_danger"])
var/amount = input(usr, "How much danger should there be?", "Game Master") as null|num
if(!isnull(amount))
danger = amount
message_admins("GM danger was set to [amount] by [usr.key].")
interact(usr) // To refresh the UI.
+123
View File
@@ -0,0 +1,123 @@
//
// Controller handling icon updates of open space turfs
//
GLOBAL_VAR_INIT(open_space_initialised, FALSE)
SUBSYSTEM_DEF(open_space)
name = "Open Space"
wait = 2 // 5 times per second.
init_order = INIT_ORDER_OPENSPACE
var/list/turfs_to_process = list() // List of turfs queued for update.
var/list/turfs_to_process_old = null // List of turfs currently being updated.
var/counter = 1 // Can't use .len because we need to iterate in order
var/static/image/over_OS_darkness // Image overlayed over the bottom turf with stuff in it.
/datum/controller/subsystem/open_space/Initialize(timeofday)
over_OS_darkness = image('icons/turf/open_space.dmi', "black_open")
over_OS_darkness.plane = OVER_OPENSPACE_PLANE
over_OS_darkness.layer = MOB_LAYER
initialize_open_space()
// Pre-process open space turfs once before the round starts.
fire(FALSE, TRUE)
return ..()
/datum/controller/subsystem/open_space/Recover()
flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
. = ..()
/datum/controller/subsystem/open_space/fire(resumed = 0, init_tick_checks = FALSE)
// We use a different list so any additions to the update lists during a delay from MC_TICK_CHECK
// don't cause things to be cut from the list without being updated.
//If we're not resuming, this must mean it's a new iteration so we have to grab the turfs
if (!resumed)
src.counter = 1
src.turfs_to_process_old = turfs_to_process
turfs_to_process = list()
//cache for sanic speed (lists are references anyways)
var/list/turfs_to_process_old = src.turfs_to_process_old
var/counter = src.counter
while(counter <= turfs_to_process_old.len)
var/turf/T = turfs_to_process_old[counter]
counter += 1
if(!QDELETED(T))
update_turf(T)
if (init_tick_checks)
CHECK_TICK // Used during initialization processing
else if (MC_TICK_CHECK)
src.counter = counter // Save for when we're resumed
return // Used during normal MC processing.
/datum/controller/subsystem/open_space/proc/update_turf(var/turf/T)
for(var/atom/movable/A in T)
A.fall()
T.update_icon()
/datum/controller/subsystem/open_space/proc/add_turf(var/turf/T, var/recursive = 0)
ASSERT(isturf(T))
// Check for multiple additions
// Pointless to process the same turf twice. But we need to push it to the end of the list
// because any turfs below it need to process first.
turfs_to_process -= T
turfs_to_process += T
if(recursive > 0)
var/turf/above = GetAbove(T)
if(above && isopenspace(above))
add_turf(above, recursive)
// Queue the initial updates of open space turfs when the game starts. This will lag!
/datum/controller/subsystem/open_space/proc/initialize_open_space()
// Do initial setup from bottom to top.
for(var/zlevel = 1 to world.maxz)
for(var/turf/simulated/open/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
add_turf(T)
CHECK_TICK
GLOB.open_space_initialised = TRUE
/datum/controller/subsystem/open_space/stat_entry(msg_prefix)
return ..("T [turfs_to_process.len]")
/turf/Entered(atom/movable/AM)
. = ..()
if(GLOB.open_space_initialised && !AM.invisibility && isobj(AM))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Entered([AM])")
SSopen_space.add_turf(T, 1)
/turf/Exited(atom/movable/AM)
. = ..()
if(GLOB.open_space_initialised && !AM.invisibility && isobj(AM))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Exited([AM])")
SSopen_space.add_turf(T, 1)
/obj/update_icon()
. = ..()
if(GLOB.open_space_initialised && !invisibility && isturf(loc))
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()")
SSopen_space.add_turf(T, 1)
// Ouch... this is painful. But is there any other way?
/* - No for now
/obj/New()
. = ..()
if(open_space_initialised && !invisibility)
var/turf/T = GetAbove(src)
if(isopenspace(T))
// log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src]New()")
OS_controller.add_turf(T, 1)
*/
// We probably should hook Destroy() If we can think of something more efficient, lets hear it.
/obj/Destroy()
if(GLOB.open_space_initialised && !invisibility && isturf(loc))
var/turf/T = GetAbove(src)
if(isopenspace(T))
SSopen_space.add_turf(T, 1)
. = ..() // Important that this be at the bottom, or we will have been moved to nullspace.
+7 -1
View File
@@ -84,6 +84,7 @@ SUBSYSTEM_DEF(shuttles)
if(shuttle)
shuttles_made += shuttle
hook_up_motherships(shuttles_made)
hook_up_shuttle_objects(shuttles_made)
shuttles_to_initialize = null
/datum/controller/subsystem/shuttles/proc/initialize_sectors()
@@ -103,7 +104,7 @@ SUBSYSTEM_DEF(shuttles)
try_add_landmark_tag(shuttle_landmark_tag, O)
landmarks_still_needed -= shuttle_landmark_tag
else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically
O = map_sectors["[shuttle_landmark.z]"]
O = get_overmap_sector(get_z(shuttle_landmark))
O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
/datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag)
@@ -165,6 +166,11 @@ SUBSYSTEM_DEF(shuttles)
else
error("Shuttle [S] was unable to find mothership [mothership]!")
// Let shuttles scan their owned areas for objects they want to configure (Called after mothership hookup)
/datum/controller/subsystem/shuttles/proc/hook_up_shuttle_objects(shuttles_list)
for(var/datum/shuttle/S in shuttles_list)
S.populate_shuttle_objects()
// Admin command to halt/resume overmap
/datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting)
if(overmap_halted == new_setting)
+6 -7
View File
@@ -68,11 +68,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 +87,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 +109,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
+560
View File
@@ -0,0 +1,560 @@
//
// 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
*/
processScheduler.start()
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
+2
View File
@@ -13,6 +13,7 @@ SUBSYSTEM_DEF(vote)
var/duration
var/mode
var/question
var/gamemode_vote_called = FALSE // Have we had a gamemode vote this round? Only auto-call if we haven't
var/list/choices = list()
var/list/gamemode_names = list()
var/list/voted = list()
@@ -257,6 +258,7 @@ SUBSYSTEM_DEF(vote)
world << sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)
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>")
+3
View File
@@ -99,6 +99,9 @@ SUBSYSTEM_DEF(xenoarch)
if(isnull(M.artifact_find) && digsite != DIGSITE_GARDEN && digsite != DIGSITE_ANIMAL)
artifact_spawning_turfs.Add(archeo_turf)
//Larger maps will convince byond this is an infinite loop, so let go for a second
CHECK_TICK
//create artifact machinery
var/num_artifacts_spawn = rand(ARTIFACTSPAWNNUM_LOWER, ARTIFACTSPAWNNUM_UPPER)
while(artifact_spawning_turfs.len > num_artifacts_spawn)
-2
View File
@@ -89,8 +89,6 @@
//Goon PS stuff, and other yet-to-be-subsystem things.
options["LEGACY: master_controller"] = master_controller
options["LEGACY: ticker"] = ticker
options["LEGACY: tickerProcess"] = tickerProcess
options["LEGACY: air_master"] = air_master
options["LEGACY: job_master"] = job_master
options["LEGACY: radio_controller"] = radio_controller
+168 -14
View File
@@ -5,11 +5,16 @@
/datum/datacore
var/name = "datacore"
var/medical[] = list()
var/general[] = list()
var/security[] = list()
//For general station crew
var/static/list/medical = list()
var/static/list/general = list()
var/static/list/security = list()
//For offmap spawns so they can have records accessible by certain things
var/static/list/hidden_medical = list()
var/static/list/hidden_general = list()
var/static/list/hidden_security = list()
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
var/static/list/locked = list()
/datum/datacore/proc/get_manifest(monochrome, OOC)
@@ -22,6 +27,7 @@
var/list/pla = new() //VOREStation Edit
var/list/civ = new()
var/list/bot = new()
var/list/off = new()
var/list/misc = new()
var/list/isactive = new()
var/dat = {"
@@ -46,7 +52,7 @@
if(OOC)
var/active = 0
for(var/mob/M in player_list)
if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10)
if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES)
active = 1
break
isactive[name] = active ? "Active" : "Inactive"
@@ -84,6 +90,24 @@
if(!department && !(name in heads))
misc[name] = rank
//For the offmap spawns
if(OOC)
for(var/datum/data/record/t in hidden_general)
var/name = t.fields["name"]
var/rank = t.fields["rank"]
var/real_rank = make_list_rank(t.fields["real_rank"])
var/active = 0
for(var/mob/M in player_list)
if(M.real_name == name && M.client && M.client.inactivity <= 10 MINUTES)
active = 1
break
isactive[name] = active ? "Active" : "Inactive"
var/datum/job/J = SSjob.get_job(real_rank)
if(J?.offmap_spawn)
off[name] = rank
// Synthetics don't have actual records, so we will pull them from here.
for(var/mob/living/silicon/ai/ai in mob_list)
bot[ai.name] = "Artificial Intelligence"
@@ -142,6 +166,12 @@
for(name in bot)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[bot[name]]</td><td>[isactive[name]]</td></tr>"
even = !even
// offmap spawners
if(off.len > 0)
dat += "<tr><th colspan=3>Offmap Spawns</th></tr>"
for(name in off)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[off[name]]</td><td>[isactive[name]]</td></tr>"
even = !even
// misc guys
if(misc.len > 0)
dat += "<tr><th colspan=3>Miscellaneous</th></tr>"
@@ -154,6 +184,117 @@
dat = replacetext(dat, "\t", "")
return dat
/*
We can't just insert in HTML into the nanoUI so we need the raw data to play with.
Instead of creating this list over and over when someone leaves their PDA open to the page
we'll only update it when it changes. The PDA_Manifest global list is zeroed out upon any change
using /datum/datacore/proc/manifest_inject( ), or manifest_insert( )
*/
var/global/list/PDA_Manifest = list()
/datum/datacore/proc/get_manifest_list()
if(PDA_Manifest.len)
return
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/car = list()
var/list/pla = list() // Planetside crew: Explorers, Pilots, S&S
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
for(var/datum/data/record/t in data_core.general)
var/name = sanitize(t.fields["name"])
var/rank = sanitize(t.fields["rank"])
var/real_rank = make_list_rank(t.fields["real_rank"])
var/isactive = t.fields["p_stat"]
var/department = 0
var/depthead = 0 // Department Heads will be placed at the top of their lists.
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND))
heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
depthead = 1
if(rank=="Colony Director" && heads.len != 1)
heads.Swap(1,heads.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SECURITY))
sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sec.len != 1)
sec.Swap(1,sec.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_ENGINEERING))
eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && eng.len != 1)
eng.Swap(1,eng.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_MEDICAL))
med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && med.len != 1)
med.Swap(1,med.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_RESEARCH))
sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sci.len != 1)
sci.Swap(1,sci.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_PLANET))
pla[++pla.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO))
car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && car.len != 1)
car.Swap(1,car.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN))
civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && civ.len != 1)
civ.Swap(1,civ.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SYNTHETIC))
bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(!department && !(name in heads))
misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
// Synthetics don't have actual records, so we will pull them from here.
// Synths don't have records, which is the means by which isactive is retrieved, so I'm hardcoding it to active, don't really have any better means
for(var/mob/living/silicon/ai/ai in mob_list)
bot[++bot.len] = list("name" = ai.real_name, "rank" = "Artificial Intelligence", "active" = "Active")
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones, and no AI shells.
if(robot.scrambledcodes || robot.shell || (robot.module && robot.module.hide_on_manifest))
continue
bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active")
PDA_Manifest = list(
list("cat" = "Command", "elems" = heads),
list("cat" = "Security", "elems" = sec),
list("cat" = "Engineering", "elems" = eng),
list("cat" = "Medical", "elems" = med),
list("cat" = "Science", "elems" = sci),
list("cat" = "Cargo", "elems" = car),
list("cat" = "Exploration", "elems" = pla), // VOREStation Edit
list("cat" = "Civilian", "elems" = civ),
list("cat" = "Silicon", "elems" = bot),
list("cat" = "Miscellaneous", "elems" = misc)
)
return
/datum/datacore/proc/manifest()
spawn()
for(var/mob/living/carbon/human/H in player_list)
@@ -187,10 +328,13 @@
/datum/datacore/proc/manifest_inject(var/mob/living/carbon/human/H)
if(H.mind && !player_is_antag(H.mind, only_offstation_roles = 1))
var/assignment = GetAssignment(H)
var/hidden
var/datum/job/J = SSjob.get_job(assignment)
hidden = J?.offmap_spawn
var/id = generate_record_id()
//General Record
var/datum/data/record/G = CreateGeneralRecord(H, id)
var/datum/data/record/G = CreateGeneralRecord(H, id, hidden)
G.fields["name"] = H.real_name
G.fields["real_rank"] = H.mind.assigned_role
G.fields["rank"] = assignment
@@ -212,7 +356,7 @@
G.fields["notes"] = H.gen_record
//Medical Record
var/datum/data/record/M = CreateMedicalRecord(H.real_name, id)
var/datum/data/record/M = CreateMedicalRecord(H.real_name, id, hidden)
M.fields["b_type"] = H.b_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["id_gender"] = gender2text(H.identifying_gender)
@@ -224,7 +368,7 @@
M.fields["notes"] = H.med_record
//Security Record
var/datum/data/record/S = CreateSecurityRecord(H.real_name, id)
var/datum/data/record/S = CreateSecurityRecord(H.real_name, id, hidden)
if(H.get_FBP_type())
S.fields["brain_type"] = H.get_FBP_type()
else
@@ -257,6 +401,7 @@
L.fields["image"] = icon(cached_character_icon(H), dir = SOUTH)
L.fields["antagfac"] = H.antag_faction
L.fields["antagvis"] = H.antag_vis
L.fields["offmap"] = hidden
if(H.exploit_record && !jobban_isbanned(H, "Records"))
L.fields["exploit_record"] = H.exploit_record
else
@@ -267,7 +412,7 @@
/proc/generate_record_id()
return add_zero(num2hex(rand(1, 65535)), 4) //no point generating higher numbers because of the limitations of num2hex
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id)
/datum/datacore/proc/CreateGeneralRecord(var/mob/living/carbon/human/H, var/id, var/hidden)
ResetPDAManifest()
var/icon/front
var/icon/side
@@ -301,11 +446,14 @@
G.fields["photo_front"] = front
G.fields["photo_side"] = side
G.fields["notes"] = "No notes found."
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
View File
@@ -0,0 +1,6 @@
// Push button, receive event.
// Returns a selected event datum.
/datum/game_master/proc/choose_event()
/datum/game_master/proc/log_game_master(message)
// SSgame_master.log_game_master(message) // VOREStation Edit - We don't use SSgame_master yet.
+89
View File
@@ -0,0 +1,89 @@
// The default game master tries to choose events with these goals in mind.
// * Don't choose an event if the crew can't take it. E.g. no meteors after half of the crew died.
// * Try to involve lots of people, particuarly in active departments.
// * Avoid giving events to the same department multiple times in a row.
/datum/game_master/default
// If an event was done for a specific department, it is written here, so it doesn't do it again.
var/last_department_used = null
/datum/game_master/default/choose_event()
log_game_master("Now starting event decision.")
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
var/list/best_events = decide_best_events(most_active_departments)
if(LAZYLEN(best_events))
log_game_master("Got [best_events.len] choice\s for the next event.")
var/list/weighted_events = list()
for(var/E in best_events)
var/datum/event2/meta/event = E
var/weight = event.get_weight()
if(weight <= 0)
continue
weighted_events[event] = weight
log_game_master("Filtered down to [weighted_events.len] choice\s.")
var/datum/event2/meta/choice = pickweight(weighted_events)
if(choice)
log_game_master("[choice.name] was chosen, and is now being ran.")
last_department_used = LAZYACCESS(choice.departments, 1)
return choice
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
if(!LAZYLEN(most_active_departments)) // Server's empty?
log_game_master("Game Master failed to find any active departments.")
return list()
var/list/best_events = list()
if(most_active_departments.len >= 2)
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
best_events = filter_events_by_departments(top_two)
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
return best_events
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
best_events = filter_events_by_departments(most_active_departments[1])
if(LAZYLEN(best_events))
return best_events
// At this point we should expand our horizons.
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
if(LAZYLEN(best_events))
return best_events
// Just give a random event if for some reason it still can't make up its mind.
best_events = filter_events_by_departments()
if(LAZYLEN(best_events))
return best_events
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
return list()
// Filters the available events down to events for specific departments.
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
// If no list is passed, all the events will be returned.
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
. = list()
for(var/E in SSgame_master.available_events)
var/datum/event2/meta/event = E
if(!event.enabled)
continue
if(event.chaotic_threshold && !ignore_round_chaos)
if(SSgame_master.danger > event.chaotic_threshold)
continue
// An event has to involve all of these departments to pass.
var/viable = TRUE
if(LAZYLEN(departments))
for(var/department in departments)
if(!LAZYFIND(departments, department))
viable = FALSE
break
if(viable)
. += event
@@ -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
+17 -2
View File
@@ -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)
+13 -65
View File
@@ -35,48 +35,6 @@
containertype = /obj/structure/closet/crate/engineering
containername = "Superconducting Transmission Coil crate"
/datum/supply_pack/eng/shield_capacitor
name = "Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor)
cost = 20
containertype = /obj/structure/closet/crate/engineering
containername = "shield capacitor crate"
/datum/supply_pack/eng/shield_capacitor/advanced
name = "Advanced Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor/advanced)
cost = 30
containertype = /obj/structure/closet/crate/engineering
containername = "advanced shield capacitor crate"
/datum/supply_pack/eng/bubble_shield
name = "Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen)
cost = 40
containertype = /obj/structure/closet/crate/engineering
containername = "shield bubble generator crate"
/datum/supply_pack/eng/bubble_shield/advanced
name = "Advanced Bubble Shield Generator"
contains = list(/obj/machinery/shield_gen/advanced)
cost = 60
containertype = /obj/structure/closet/crate/engineering
containername = "advanced bubble shield generator crate"
/datum/supply_pack/eng/hull_shield
name = "Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external)
cost = 80
containertype = /obj/structure/closet/crate/engineering
containername = "shield hull generator crate"
/datum/supply_pack/eng/hull_shield/advanced
name = "Advanced Hull Shield Generator"
contains = list(/obj/machinery/shield_gen/external/advanced)
cost = 120
containertype = /obj/structure/closet/crate/engineering
containername = "advanced hull shield generator crate"
/datum/supply_pack/eng/electrical
name = "Electrical maintenance crate"
contains = list(
@@ -173,29 +131,19 @@
containername = "Particle Accelerator crate"
access = access_ce
/datum/supply_pack/eng/shield_gen
contains = list(/obj/item/weapon/circuitboard/shield_gen)
name = "Bubble shield generator circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "bubble shield generator circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_gen_ex
contains = list(/obj/item/weapon/circuitboard/shield_gen_ex)
name = "Hull shield generator circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "hull shield generator circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_cap
contains = list(/obj/item/weapon/circuitboard/shield_cap)
name = "Bubble shield capacitor circuitry"
cost = 30
containertype = /obj/structure/closet/crate/secure/engineering
containername = "shield capacitor circuitry crate"
access = access_ce
/datum/supply_pack/eng/shield_generator
name = "Shield Generator Construction Kit"
contains = list(
/obj/item/weapon/circuitboard/shield_generator,
/obj/item/weapon/stock_parts/capacitor,
/obj/item/weapon/stock_parts/micro_laser,
/obj/item/weapon/smes_coil,
/obj/item/weapon/stock_parts/console_screen,
/obj/item/weapon/stock_parts/subspace/amplifier
)
cost = 80
containertype = /obj/structure/closet/crate/engineering
containername = "shield generator construction kit crate"
/datum/supply_pack/eng/smbig
name = "Supermatter Core"
+2 -2
View File
@@ -1,8 +1,8 @@
/datum/supply_pack/munitions/expeditionguns
name = "Frontier phaser (station-locked) crate"
contains = list(
/obj/item/weapon/gun/energy/frontier/locked = 2,
/obj/item/weapon/gun/energy/frontier/locked/holdout = 1,
/obj/item/weapon/gun/energy/locked/frontier = 2,
/obj/item/weapon/gun/energy/locked/frontier/holdout = 1,
)
cost = 35
containertype = /obj/structure/closet/crate/secure
+6
View File
@@ -53,6 +53,12 @@
name = "Black Ammunition Duffle Bag"
path = /obj/item/weapon/storage/backpack/dufflebag/syndie/ammo
/datum/uplink_item/item/tools/shield_diffuser
name = "Handheld Shield Diffuser"
desc = "A small device used to disrupt energy barriers, and allow passage through them."
item_cost = 16
path = /obj/item/weapon/shield_diffuser
/datum/uplink_item/item/tools/space_suit
name = "Space Suit"
item_cost = 15
+46
View File
@@ -0,0 +1,46 @@
/datum/wires/shield_generator
holder_type = /obj/machinery/power/shield_generator
wire_count = 5
var/const/SHIELDGEN_WIRE_POWER = 1 // Cut to disable power input into the generator. Pulse does nothing. Mend to restore.
var/const/SHIELDGEN_WIRE_HACK = 2 // Pulse to hack the generator, enabling hacked modes. Cut to unhack. Mend does nothing.
var/const/SHIELDGEN_WIRE_CONTROL = 4 // Cut to lock most shield controls. Mend to unlock them. Pulse does nothing.
var/const/SHIELDGEN_WIRE_AICONTROL = 8 // Cut to disable AI control. Mend to restore.
var/const/SHIELDGEN_WIRE_NOTHING = 16 // A blank wire that doesn't have any specific function
/datum/wires/shield_generator/CanUse(var/mob/living/L)
var/obj/machinery/power/shield_generator/S = holder
if(S.panel_open)
return 1
return 0
/datum/wires/shield_generator/GetInteractWindow()
var/obj/machinery/power/shield_generator/S = holder
. += ..()
. += show_hint(0x1, S.mode_changes_locked, "The orange light is on.", "The orange light is off.")
. += show_hint(0x2, S.ai_control_disabled, "The blue light is off.", "The blue light is blinking.")
. += show_hint(0x4, S.hacked, "The violet light is pulsing.", "The violet light is steady.")
. += show_hint(0x8, S.input_cut, "The red light is off.", "The red light is on.")
/datum/wires/shield_generator/UpdateCut(index, mended)
var/obj/machinery/power/shield_generator/S = holder
switch(index)
if(SHIELDGEN_WIRE_POWER)
S.input_cut = !mended
if(SHIELDGEN_WIRE_HACK)
if(!mended)
S.hacked = 0
if(S.check_flag(MODEFLAG_BYPASS))
S.toggle_flag(MODEFLAG_BYPASS)
if(S.check_flag(MODEFLAG_OVERCHARGE))
S.toggle_flag(MODEFLAG_OVERCHARGE)
if(SHIELDGEN_WIRE_CONTROL)
S.mode_changes_locked = !mended
if(SHIELDGEN_WIRE_AICONTROL)
S.ai_control_disabled = !mended
/datum/wires/shield_generator/UpdatePulsed(var/index)
var/obj/machinery/power/shield_generator/S = holder
switch(index)
if(SHIELDGEN_WIRE_HACK)
S.hacked = 1
-114
View File
@@ -52,120 +52,6 @@
return copytext(rank, 2+length(prefix))
return rank
/*
We can't just insert in HTML into the nanoUI so we need the raw data to play with.
Instead of creating this list over and over when someone leaves their PDA open to the page
we'll only update it when it changes. The PDA_Manifest global list is zeroed out upon any change
using /datum/datacore/proc/manifest_inject( ), or manifest_insert( )
*/
var/global/list/PDA_Manifest = list()
/datum/datacore/proc/get_manifest_list()
if(PDA_Manifest.len)
return
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/car = list()
var/list/pla = list() // Planetside crew: Explorers, Pilots, S&S
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
for(var/datum/data/record/t in data_core.general)
var/name = sanitize(t.fields["name"])
var/rank = sanitize(t.fields["rank"])
var/real_rank = make_list_rank(t.fields["real_rank"])
var/isactive = t.fields["p_stat"]
var/department = 0
var/depthead = 0 // Department Heads will be placed at the top of their lists.
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_COMMAND))
heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
depthead = 1
if(rank=="Colony Director" && heads.len != 1)
heads.Swap(1,heads.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SECURITY))
sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sec.len != 1)
sec.Swap(1,sec.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_ENGINEERING))
eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && eng.len != 1)
eng.Swap(1,eng.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_MEDICAL))
med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && med.len != 1)
med.Swap(1,med.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_RESEARCH))
sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && sci.len != 1)
sci.Swap(1,sci.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_PLANET))
pla[++pla.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CARGO))
car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && car.len != 1)
car.Swap(1,car.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_CIVILIAN))
civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(depthead && civ.len != 1)
civ.Swap(1,civ.len)
if(SSjob.is_job_in_department(real_rank, DEPARTMENT_SYNTHETIC))
bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
department = 1
if(!department && !(name in heads))
misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
// Synthetics don't have actual records, so we will pull them from here.
// Synths don't have records, which is the means by which isactive is retrieved, so I'm hardcoding it to active, don't really have any better means
for(var/mob/living/silicon/ai/ai in mob_list)
bot[++bot.len] = list("name" = ai.real_name, "rank" = "Artificial Intelligence", "active" = "Active")
for(var/mob/living/silicon/robot/robot in mob_list)
// No combat/syndicate cyborgs, no drones, and no AI shells.
if(robot.scrambledcodes || robot.shell || (robot.module && robot.module.hide_on_manifest))
continue
bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active")
PDA_Manifest = list(
list("cat" = "Command", "elems" = heads),
list("cat" = "Security", "elems" = sec),
list("cat" = "Engineering", "elems" = eng),
list("cat" = "Medical", "elems" = med),
list("cat" = "Science", "elems" = sci),
list("cat" = "Cargo", "elems" = car),
list("cat" = "Exploration", "elems" = pla), // VOREStation Edit
list("cat" = "Civilian", "elems" = civ),
list("cat" = "Silicon", "elems" = bot),
list("cat" = "Miscellaneous", "elems" = misc)
)
return
/obj/effect/laser
name = "laser"
desc = "IT BURNS!!!"
+29 -21
View File
@@ -32,7 +32,7 @@
title = "Security Announcement"
announcement_type = "Security Announcement"
/datum/announcement/proc/Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0)
/datum/announcement/proc/Announce(var/message as text, var/new_title = "", var/new_sound = null, var/do_newscast = newscast, var/msg_sanitized = 0, zlevel)
if(!message)
return
var/message_title = new_title ? new_title : title
@@ -42,28 +42,32 @@
message = sanitize(message, extra = 0)
message_title = sanitizeSafe(message_title)
Message(message, message_title)
var/list/zlevels
if(zlevel)
zlevels = using_map.get_map_levels(zlevel, TRUE)
Message(message, message_title, zlevels)
if(do_newscast)
NewsCast(message, message_title)
Sound(message_sound)
Sound(message_sound, zlevels)
Log(message, message_title)
datum/announcement/proc/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/proc/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/minor/Message(message as text, message_title as text)
global_announcer.autosay(message, announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/minor/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay(message, announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/priority/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME)
datum/announcement/priority/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", announcer ? announcer : ANNOUNCER_NAME, zlevels)
datum/announcement/priority/command/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[command_name()] - [message_title]:</span> [message]", ANNOUNCER_NAME)
datum/announcement/priority/command/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[command_name()] - [message_title]:</span> [message]", ANNOUNCER_NAME, zlevels)
datum/announcement/priority/security/Message(message as text, message_title as text)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", ANNOUNCER_NAME)
datum/announcement/priority/security/Message(var/message as text, var/message_title as text, var/list/zlevels)
global_announcer.autosay("<span class='alert'>[message_title]:</span> [message]", ANNOUNCER_NAME, zlevels)
datum/announcement/proc/NewsCast(message as text, message_title as text)
datum/announcement/proc/NewsCast(var/message as text, var/message_title as text)
if(!newscast)
return
@@ -75,15 +79,18 @@ datum/announcement/proc/NewsCast(message as text, message_title as text)
news.can_be_redacted = 0
announce_newscaster_news(news)
datum/announcement/proc/PlaySound(var/message_sound)
datum/announcement/proc/PlaySound(var/message_sound, var/list/zlevels)
if(!message_sound)
return
for(var/mob/M in player_list)
if(zlevels && !(M.z in zlevels))
continue
if(!istype(M,/mob/new_player) && !isdeaf(M))
M << message_sound
datum/announcement/proc/Sound(var/message_sound)
PlaySound(message_sound)
datum/announcement/proc/Sound(var/message_sound, var/list/zlevels)
PlaySound(message_sound, zlevels)
datum/announcement/priority/Sound(var/message_sound)
if(message_sound)
@@ -107,11 +114,12 @@ datum/announcement/proc/Log(message as text, message_title as text)
/proc/ion_storm_announcement()
command_announcement.Announce("It has come to our attention that \the [station_name()] passed through an ion storm. Please monitor all electronic equipment for malfunctions.", "Anomaly Alert")
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank, var/join_message)
/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank, var/join_message, var/channel = "Common", var/zlevel)
if (ticker.current_state == GAME_STATE_PLAYING)
var/list/zlevels = zlevel ? using_map.get_map_levels(zlevel, TRUE) : null
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
AnnounceArrivalSimple(character.real_name, rank, join_message)
AnnounceArrivalSimple(character.real_name, rank, join_message, channel, zlevels)
/proc/AnnounceArrivalSimple(var/name, var/rank = "visitor", var/join_message = "will arrive at the station shortly", new_sound = 'sound/misc/notice3.ogg') //VOREStation Edit - Remove shuttle reference
global_announcer.autosay("[name], [rank], [join_message].", "Arrivals Announcement Computer")
/proc/AnnounceArrivalSimple(var/name, var/rank = "visitor", var/join_message = "will arrive at the station shortly", var/channel = "Common", var/list/zlevels)
global_announcer.autosay("[name], [rank], [join_message].", "Arrivals Announcement Computer", channel, zlevels)
+1
View File
@@ -94,6 +94,7 @@ proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H)
proc/statistic_cycle()
set waitfor = 0
if(!sqllogging)
return
while(1)
+7
View File
@@ -70,6 +70,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"
@@ -807,6 +808,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"
@@ -981,6 +985,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
icon_state = "Sleep"
flags = RAD_SHIELDED
ambience = AMBIENCE_GENERIC
forbid_events = TRUE
/area/crew_quarters/toilet
name = "\improper Dormitory Toilets"
@@ -1281,6 +1286,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"
@@ -1380,6 +1386,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"
+5 -10
View File
@@ -40,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()
. = ..()
@@ -366,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
@@ -398,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))
@@ -413,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
+20
View File
@@ -185,6 +185,12 @@
to_chat(user, "[bicon(src)] That's [f_name] [suffix]")
to_chat(user,desc)
if(user.client?.examine_text_mode == EXAMINE_MODE_INCLUDE_USAGE)
to_chat(user, description_info)
if(user.client?.examine_text_mode == EXAMINE_MODE_SWITCH_TO_PANEL)
user.client.statpanel = "Examine" // Switch to stat panel
return distance == -1 || (get_dist(src, user) <= distance)
// called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set.
@@ -197,6 +203,20 @@
. = new_dir != dir
dir = new_dir
// Called to set the atom's density and used to add behavior to density changes.
/atom/proc/set_density(var/new_density)
if(density == new_density)
return FALSE
density = !!new_density // Sanitize to be strictly 0 or 1
return TRUE
// Called to set the atom's invisibility and usd to add behavior to invisibility changes.
/atom/proc/set_invisibility(var/new_invisibility)
if(invisibility == new_invisibility)
return FALSE
invisibility = new_invisibility
return TRUE
/atom/proc/ex_act()
return
+4 -3
View File
@@ -538,7 +538,8 @@
cloak_animation(animation_time)
//Needs to be last so people can actually see the effect before we become invisible
plane = CLOAKED_PLANE
if(cloaked) // Ensure we are still cloaked after the animation delay
plane = CLOAKED_PLANE
/atom/movable/proc/uncloak()
if(!cloaked)
@@ -573,7 +574,7 @@
sleep(length+5)
//Remove those
filters -= filters[our_filter]
filters -= filter(type="wave", x = 0, y = 16, size = 8, offset = 1, flags = WAVE_SIDEWAYS)
//Back to original alpha
alpha = initial_alpha
@@ -597,7 +598,7 @@
sleep(length+5)
//Remove those
filters -= filters[our_filter]
filters -= filter(type="wave", x=0, y = 16, size = 0, offset = 0, flags = WAVE_SIDEWAYS)
// So cloaked things can see themselves, if necessary
+1 -1
View File
@@ -54,7 +54,7 @@ In short:
/datum/universal_state/hell/proc/AreaSet()
for(var/area/A in all_areas)
for(var/area/A in world)
if(!istype(A,/area) || istype(A, /area/space))
continue
@@ -84,7 +84,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked
return
/datum/universal_state/supermatter_cascade/proc/AreaSet()
for(var/area/A in all_areas)
for(var/area/A in world)
if(!istype(A,/area) || istype(A, /area/space) || istype(A,/area/beach))
continue
+1 -1
View File
@@ -169,7 +169,7 @@ var/hadevent = 0
var/list/area/areas = list()
for(var/area/A in all_areas)
for(var/area/A in world)
if(istype(A, /area/security/prison) || istype(A, /area/security/brig))
areas += A
-467
View File
@@ -1,467 +0,0 @@
var/global/datum/controller/gameticker/ticker
/datum/controller/gameticker
var/const/restart_timeout = 3 MINUTES //One minute is 600.
var/current_state = GAME_STATE_PREGAME
var/hide_mode = 0
var/datum/game_mode/mode = null
var/post_game = 0
var/event_time = null
var/event = 0
// 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.
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 = 0 // if set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
var/list/syndicate_coalition = list() // list of traitor-compatible factions
var/list/factions = list() // list of all factions
var/list/availablefactions = list() // list of factions with openings
var/pregame_timeleft = 0
var/delay_end = 0 //if set to nonzero, the round will not restart on it's own
var/triai = 0//Global holder for Triumvirate
var/round_end_announced = 0 // Spam Prevention. Announce round end only once.
/datum/controller/gameticker/proc/pregame()
/* VOREStation Edit - We do music differently
login_music = pick(\
'sound/music/halloween/skeletons.ogg',\
'sound/music/halloween/halloween.ogg',\
'sound/music/halloween/ghosts.ogg'
'sound/music/space.ogg',\
'sound/music/traitor.ogg',\
'sound/music/title2.ogg',\
'sound/music/clouds.s3m',\
'sound/music/space_oddity.ogg') //Ground Control to Major Tom, this song is cool, what's going on?
*/ //VOREStation Edit End
send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]")
do
pregame_timeleft = config.pregame_time
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.")
while(current_state == GAME_STATE_PREGAME)
if(round_progressing)
pregame_timeleft--
if(pregame_timeleft == config.vote_autogamemode_timeleft)
if(!SSvote.time_remaining)
SSvote.autogamemode() //Quit calling this over and over and over and over.
while(SSvote.time_remaining)
sleep(1)
if(pregame_timeleft <= 0)
current_state = GAME_STATE_SETTING_UP
Master.SetRunLevel(RUNLEVEL_SETUP)
sleep(10)
while (!setup())
/datum/controller/gameticker/proc/setup()
//Create and announce mode
if(master_mode=="secret")
src.hide_mode = 1
var/list/runnable_modes = config.get_runnable_modes()
if((master_mode=="random") || (master_mode=="secret"))
if(!runnable_modes.len)
current_state = GAME_STATE_PREGAME
Master.SetRunLevel(RUNLEVEL_LOBBY)
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)
current_state = GAME_STATE_PREGAME
Master.SetRunLevel(RUNLEVEL_LOBBY)
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.")
current_state = GAME_STATE_PREGAME
Master.SetRunLevel(RUNLEVEL_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()
setup_economy()
current_state = GAME_STATE_PLAYING
create_characters() //Create player characters and transfer them.
collect_minds()
equip_characters()
//data_core.manifest() //VOREStation Removal
callHook("roundstart")
// TODO - Leshana - Dear God Fix This. Fix all of this. Not just this line, this entire proc. This entire file!
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()
//start_events() //handles random events and space dust.
//new random event system is handled from the MC.
var/admins_number = 0
for(var/client/C)
if(C.holder)
admins_number++
if(admins_number == 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
*/
processScheduler.start()
Master.SetRunLevel(RUNLEVEL_GAME)
if(config.sql_enabled)
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
return 1
/datum/controller/gameticker
//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
//Plus it provides an easy way to make cinematics for other events. Just use this as a template :)
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
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
proc/collect_minds()
for(var/mob/living/player in player_list)
if(player.mind)
ticker.minds += player.mind
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.")
process()
if(current_state != GAME_STATE_PLAYING)
return 0
mode.process()
// emergency_shuttle.process() //handled in scheduler
var/game_finished = 0
var/mode_finished = 0
if (config.continous_rounds)
game_finished = (emergency_shuttle.returned() || mode.station_was_nuked)
mode_finished = (!post_game && mode.check_finished())
else
game_finished = (mode.check_finished() || (emergency_shuttle.returned() && emergency_shuttle.evac == 1)) || universe_has_ended
mode_finished = game_finished
if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game))
current_state = GAME_STATE_FINISHED
Master.SetRunLevel(RUNLEVEL_POSTGAME)
spawn
declare_completion()
spawn(50)
callHook("roundend")
var/time_left
if (mode.station_was_nuked)
feedback_set_details("end_proper","nuke")
time_left = 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 in [round(time_left/600)] minutes.</b></span>")
else
feedback_set_details("end_proper","proper completion")
time_left = round(restart_timeout)
if(blackbox)
blackbox.save_all_data_to_sql()
if(!delay_end)
while(time_left > 0)
if(delay_end)
break
to_chat(world, "<span class='notice'><b>Restarting in [round(time_left/600)] minute\s.</b></span>")
time_left -= 1 MINUTES
sleep(600)
if(!delay_end)
world.Reboot()
else
to_chat(world, "<span class='notice'><b>An admin has delayed the round end.</b></span>")
else
to_chat(world, "<span class='notice'><b>An admin has delayed the round end.</b></span>")
else if (mode_finished)
post_game = 1
mode.cleanup()
//call a transfer shuttle vote
spawn(50)
if(!round_end_announced) // Spam Prevention. Now it should announce only once.
to_chat(world, "<span class='danger'>The round has ended!</span>")
round_end_announced = 1
SSvote.autotransfer()
return 1
/datum/controller/gameticker/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
+5
View File
@@ -183,6 +183,8 @@
var/turf/simulated/wall/W = T
W.take_damage(wall_power) // Stronger walls can halt asteroids.
/obj/effect/meteor/proc/get_shield_damage()
return max(((max(hits, 2)) * (heavy + 1) * rand(6, 12)) / hitpwr , 0)
//process getting 'hit' by colliding with a dense object
//or randomly when ramming turfs
@@ -307,6 +309,9 @@
// Worst case scenario: Comparable to a standard yield EMP grenade.
empulse(src, rand(1, 3), rand(2, 4), rand(3, 7), rand(5, 10))
/obj/effect/meteor/emp/get_shield_damage()
return ..() * rand(2,4)
//Station buster Tunguska
/obj/effect/meteor/tunguska
name = "tunguska meteor"
+111 -113
View File
@@ -12,45 +12,51 @@
var/obj/item/weapon/disk/nuclear/the_disk = null
var/active = 0
attack_self()
if(!active)
active = 1
workdisk()
to_chat(usr, "<span class='notice'>You activate the pinpointer</span>")
else
active = 0
icon_state = "pinoff"
to_chat(usr, "<span>You deactivate the pinpointer</span>")
proc/workdisk()
if(!active) return
if(!the_disk)
the_disk = locate()
if(!the_disk)
icon_state = "pinonnull"
return
set_dir(get_dir(src,the_disk))
switch(get_dist(src,the_disk))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5) .()
examine(mob/user)
..(user)
for(var/obj/machinery/nuclearbomb/bomb in machines)
if(bomb.timing)
to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.timeleft]")
/obj/item/weapon/pinpointer/Destroy()
active = 0
..()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/weapon/pinpointer/attack_self()
if(!active)
active = 1
START_PROCESSING(SSobj, src)
to_chat(usr, "<span class='notice'>You activate the pinpointer</span>")
else
active = 0
STOP_PROCESSING(SSobj, src)
icon_state = "pinoff"
to_chat(usr, "<span class='notice'>You deactivate the pinpointer</span>")
/obj/item/weapon/pinpointer/process()
if(!active)
return PROCESS_KILL
if(!the_disk)
the_disk = locate()
if(!the_disk)
icon_state = "pinonnull"
return
set_dir(get_dir(src,the_disk))
switch(get_dist(src,the_disk))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
/obj/item/weapon/pinpointer/examine(mob/user)
..(user)
for(var/obj/machinery/nuclearbomb/bomb in machines)
if(bomb.timing)
to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.timeleft]")
/obj/item/weapon/pinpointer/advpinpointer
name = "Advanced Pinpointer"
@@ -60,58 +66,49 @@
var/turf/location = null
var/obj/target = null
attack_self()
if(!active)
active = 1
if(mode == 0)
workdisk()
if(mode == 1)
worklocation()
if(mode == 2)
workobj()
to_chat(usr, "<span class='notice'>You activate the pinpointer</span>")
else
active = 0
icon_state = "pinoff"
to_chat(usr, "<span class='notice'>You deactivate the pinpointer</span>")
/obj/item/weapon/pinpointer/advpinpointer/process()
if(!active)
return PROCESS_KILL
if(mode == 0)
..()
if(mode == 1)
worklocation()
if(mode == 2)
workobj()
/obj/item/weapon/pinpointer/advpinpointer/proc/worklocation()
if(!location)
icon_state = "pinonnull"
return
proc/worklocation()
if(!active)
return
if(!location)
icon_state = "pinonnull"
return
set_dir(get_dir(src,location))
switch(get_dist(src,location))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5) .()
set_dir(get_dir(src,location))
switch(get_dist(src,location))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
proc/workobj()
if(!active)
return
if(!target)
icon_state = "pinonnull"
return
set_dir(get_dir(src,target))
switch(get_dist(src,target))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5) .()
/obj/item/weapon/pinpointer/advpinpointer/proc/workobj()
if(!target)
icon_state = "pinonnull"
return
set_dir(get_dir(src,target))
switch(get_dist(src,target))
if(0)
icon_state = "pinondirect"
if(1 to 8)
icon_state = "pinonclose"
if(9 to 16)
icon_state = "pinonmedium"
if(16 to INFINITY)
icon_state = "pinonfar"
/obj/item/weapon/pinpointer/advpinpointer/verb/toggle_mode()
set category = "Object"
@@ -140,7 +137,6 @@
to_chat(usr, "You set the pinpointer to locate [locationx],[locationy]")
return attack_self()
if("Disk Recovery")
@@ -150,9 +146,10 @@
if("Other Signature")
mode = 2
switch(alert("Search for item signature or DNA fragment?" , "Signature Mode Select" , "" , "Item" , "DNA"))
if("Item")
var/datum/objective/steal/itemlist
itemlist = itemlist // To supress a 'variable defined but not used' error.
itemlist = itemlist
var/targetitem = input("Select item to search for.", "Item Mode Select","") as null|anything in itemlist.possible_items
if(!targetitem)
return
@@ -161,6 +158,7 @@
to_chat(usr, "Failed to locate [targetitem]!")
return
to_chat(usr, "You set the pinpointer to locate [targetitem]")
if("DNA")
var/DNAstring = input("Input DNA string to search for." , "Please Enter String." , "")
if(!DNAstring)
@@ -187,6 +185,7 @@
/obj/item/weapon/pinpointer/nukeop/attack_self(mob/user as mob)
if(!active)
active = 1
START_PROCESSING(SSobj, src)
if(!mode)
workdisk()
to_chat(user, "<span class='notice'>Authentication Disk Locator active.</span>")
@@ -195,30 +194,35 @@
to_chat(user, "<span class='notice'>Shuttle Locator active.</span>")
else
active = 0
STOP_PROCESSING(SSobj, src)
icon_state = "pinoff"
to_chat(user, "<span class='notice'>You deactivate the pinpointer.</span>")
/obj/item/weapon/pinpointer/nukeop/process()
if(!active)
return PROCESS_KILL
/obj/item/weapon/pinpointer/nukeop/workdisk()
if(!active) return
if(mode) //Check in case the mode changes while operating
worklocation()
return
switch(mode)
if(0)
workdisk()
if(1)
worklocation()
/obj/item/weapon/pinpointer/nukeop/proc/workdisk()
if(bomb_set) //If the bomb is set, lead to the shuttle
mode = 1 //Ensures worklocation() continues to work
worklocation()
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1) //Plays a beep
visible_message("Shuttle Locator active.") //Lets the mob holding it know that the mode has changed
visible_message("<span class='notice'>Shuttle Locator active.</span>") //Lets the mob holding it know that the mode has changed
return //Get outta here
if(!the_disk)
the_disk = locate()
if(!the_disk)
icon_state = "pinonnull"
return
// if(loc.z != the_disk.z) //If you are on a different z-level from the disk
// icon_state = "pinonnull"
// else
set_dir(get_dir(src, the_disk))
switch(get_dist(src, the_disk))
if(0)
icon_state = "pinondirect"
@@ -229,29 +233,25 @@
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5) .()
/obj/item/weapon/pinpointer/nukeop/proc/worklocation()
if(!active) return
if(!mode)
workdisk()
return
if(!bomb_set)
mode = 0
workdisk()
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
visible_message("<span class='notice'>Authentication Disk Locator active.</span>")
return
if(!home)
home = locate()
if(!home)
icon_state = "pinonnull"
return
if(loc.z != home.z) //If you are on a different z-level from the shuttle
icon_state = "pinonnull"
else
set_dir(get_dir(src, home))
switch(get_dist(src, home))
if(0)
icon_state = "pinondirect"
@@ -262,8 +262,6 @@
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5) .()
// This one only points to the ship. Useful if there is no nuking to occur today.
/obj/item/weapon/pinpointer/shuttle
@@ -273,16 +271,17 @@
/obj/item/weapon/pinpointer/shuttle/attack_self(mob/user as mob)
if(!active)
active = TRUE
find_shuttle()
START_PROCESSING(SSobj, src)
to_chat(user, "<span class='notice'>Shuttle Locator active.</span>")
else
active = FALSE
STOP_PROCESSING(SSobj, src)
icon_state = "pinoff"
to_chat(user, "<span class='notice'>You deactivate the pinpointer.</span>")
/obj/item/weapon/pinpointer/shuttle/proc/find_shuttle()
/obj/item/weapon/pinpointer/shuttle/process()
if(!active)
return
return PROCESS_KILL
if(!our_shuttle)
for(var/obj/machinery/computer/shuttle_control/S in machines)
@@ -296,8 +295,10 @@
if(loc.z != our_shuttle.z) //If you are on a different z-level from the shuttle
icon_state = "pinonnull"
else
set_dir(get_dir(src, our_shuttle))
switch(get_dist(src, our_shuttle))
if(0)
icon_state = "pinondirect"
@@ -308,9 +309,6 @@
if(16 to INFINITY)
icon_state = "pinonfar"
spawn(5)
.()
/obj/item/weapon/pinpointer/shuttle/merc
shuttle_comp_id = "Mercenary"
+13 -2
View File
@@ -25,7 +25,7 @@ var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) -
/obj/item/weapon/technomancer_catalog
name = "catalog"
desc = "A \"book\" featuring a holographic display, metal cover, and miniaturized teleportation device, allowing the user to \
requisition various things from.. where ever they came from."
requisition various things from... wherever they came from."
icon = 'icons/obj/storage.dmi'
icon_state ="scientology" //placeholder
w_class = ITEMSIZE_SMALL
@@ -40,6 +40,7 @@ var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) -
var/tab = 4 // Info tab, so new players can read it before doing anything.
var/spell_tab = ALL_SPELLS
var/show_scepter_text = 0
var/universal = FALSE //VOREStation Add - Allows non-technomancers to use this catalog
/obj/item/weapon/technomancer_catalog/apprentice
name = "apprentice's catalog"
@@ -51,12 +52,22 @@ var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) -
budget = 2000
max_budget = 2000
//VOREStation Add
/obj/item/weapon/technomancer_catalog/universal
name = "universal catalog"
desc = "A catalog to be used with the KHI 'Universal Core', shamelessly \
copied by a Kitsuhana designer from some group of 'technomancers' or another.<br>\
The back of the book has <i>'Export Edition'</i> stamped on it."
budget = 700
max_budget = 700
universal = TRUE
//VOREStation Add End
// Proc: bind_to_owner()
// Parameters: 1 (new_owner - mob that the book is trying to bind to)
// Description: Links the catalog to hopefully the technomancer, so that only they can access it.
/obj/item/weapon/technomancer_catalog/proc/bind_to_owner(var/mob/living/carbon/human/new_owner)
if(!owner && technomancers.is_antagonist(new_owner.mind))
if(!owner && (technomancers.is_antagonist(new_owner.mind) || universal)) //VOREStation Edit - Universal catalogs
owner = new_owner
// Proc: New()
+18 -2
View File
@@ -35,6 +35,7 @@
var/list/summoned_mobs = list() // Maintained horribly with maintain_summon_list().
var/list/wards_in_use = list() // Wards don't count against the cap for other summons.
var/max_summons = 10 // Maximum allowed summoned entities. Some cores will have different caps.
var/universal = FALSE // Allows non-technomancers to use the core - VOREStation Add
/obj/item/weapon/technomancer_core/New()
..()
@@ -88,7 +89,7 @@
if(world.time % 5 == 0) // Maintaining fat lists is expensive, I imagine.
maintain_summon_list()
if(wearer && wearer.mind)
if(!(technomancers.is_antagonist(wearer.mind))) // In case someone tries to wear a stolen core.
if(!(technomancers.is_antagonist(wearer.mind)) && !universal) // In case someone tries to wear a stolen core. //VOREStation Edit - Add universal cores
wearer.adjust_instability(20)
if(!wearer || wearer.stat == DEAD) // Unlock if we're dead or not worn.
canremove = TRUE
@@ -349,4 +350,19 @@
set desc = "Toggles the locking mechanism on your manipulation core."
canremove = !canremove
to_chat(usr, "<span class='notice'>You [canremove ? "de" : ""]activate the locking mechanism on \the [src].</span>")
to_chat(usr, "<span class='notice'>You [canremove ? "de" : ""]activate the locking mechanism on \the [src].</span>")
//For the adminbuse! VOREStation Add
/obj/item/weapon/technomancer_core/universal
name = "universal core"
desc = "A bewilderingly complex 'black box' that allows the wearer to accomplish amazing feats. \
This one is a copy of a 'technomancer' core, shamelessly ripped off by a Kitsuhana pattern designer \
for fun, so that he could perform impressive 'magic'. The pack sloshes slightly if you shake it.<br>\
Under the straps, <i>'Export Edition'</i> is printed."
energy = 7000
max_energy = 7000
regen_rate = 30 //233 seconds to full
instability_modifier = 0.3
spell_power_modifier = 0.7
universal = TRUE
//VOREStation Add End
@@ -188,7 +188,7 @@
if(core.loc != owner || owner.back != core) //Make sure the core's being worn.
to_chat(owner, "<span class='danger'>You need to be wearing a core on your back!</span>")
return 0
if(!technomancers.is_antagonist(owner.mind)) //Now make sure the person using this is the actual antag.
if(!technomancers.is_antagonist(owner.mind) && !core.universal) //Now make sure the person using this is the actual antag. //VOREStation Edit - Universal cores
to_chat(owner, "<span class='danger'>You can't seem to figure out how to make the machine work properly.</span>")
return 0
return 1
@@ -8,16 +8,30 @@
ability_icon_state = "tech_mark"
category = UTILITY_SPELLS
//The object to teleport to when Recall is used.
/obj/effect/mark_spell
name = "mark"
desc = "This is a strange looking disturbance."
opacity = 0
density = 0
anchored = 1
/datum/technomancer_marker
var/weakref/U
var/image/I
var/turf/T
/datum/technomancer_marker/New(var/mob/user)
U = weakref(user)
T = get_turf(user)
I = image('icons/goonstation/featherzone.dmi', T, "spawn-wall")
I.plane = TURF_PLANE
I.layer = ABOVE_TURF_LAYER
user.client?.images |= I
spawn(23) //That's just how long the animation is
I.icon_state = "spawn-wall-loop"
/datum/technomancer_marker/Destroy()
var/mob/user = U?.resolve()
user?.client?.images -= I
I?.loc = null
U = T = I = null
return ..()
//This is global, to avoid looping through a list of all objects, or god forbid, looping through world.
/var/global/obj/effect/mark_spell/mark_spell_ref = null
GLOBAL_LIST_INIT(mark_spells, list())
/obj/item/weapon/spell/mark
name = "mark"
@@ -26,17 +40,20 @@
cast_methods = CAST_USE
aspect = ASPECT_TELE
/obj/item/weapon/spell/mark/on_use_cast(mob/living/user)
/obj/item/weapon/spell/mark/on_use_cast(var/mob/living/user)
if(!allowed_to_teleport()) // Otherwise you could teleport back to the admin Z-level.
to_chat(user, "<span class='warning'>You can't teleport here!</span>")
return 0
if(pay_energy(1000))
if(!mark_spell_ref)
mark_spell_ref = new(get_turf(user))
to_chat(user, "<span class='notice'>You mark \the [get_turf(user)] under you.</span>")
else
mark_spell_ref.forceMove(get_turf(user))
var/datum/technomancer_marker/marker = GLOB.mark_spells[weakref(user)]
//They have one in the list
if(istype(marker))
qdel(marker)
to_chat(user, "<span class='notice'>Your mark is moved from its old position to \the [get_turf(user)] under you.</span>")
//They don't have one yet
else
to_chat(user, "<span class='notice'>You mark \the [get_turf(user)] under you.</span>")
GLOB.mark_spells[weakref(user)] = new /datum/technomancer_marker(user)
adjust_instability(5)
return 1
else
@@ -62,9 +79,10 @@
cast_methods = CAST_USE
aspect = ASPECT_TELE
/obj/item/weapon/spell/recall/on_use_cast(mob/living/user)
/obj/item/weapon/spell/recall/on_use_cast(var/mob/living/user)
if(pay_energy(3000))
if(!mark_spell_ref)
var/datum/technomancer_marker/marker = GLOB.mark_spells[weakref(user)]
if(!istype(marker))
to_chat(user, "<span class='danger'>There's no Mark!</span>")
return 0
else
@@ -86,7 +104,7 @@
time_left--
sleep(1 SECOND)
var/turf/target_turf = get_turf(mark_spell_ref)
var/turf/target_turf = marker.T
var/turf/old_turf = get_turf(user)
for(var/obj/item/weapon/grab/G in user.contents) // People the Technomancer is grabbing come along for the ride.
+7
View File
@@ -10,3 +10,10 @@ var/const/access_pilot = 67
id = access_pilot
desc = "Pilot"
region = ACCESS_REGION_SUPPLY
/var/const/access_talon = 301
/datum/access/talon
id = access_talon
desc = "Talon"
access_type = ACCESS_TYPE_PRIVATE
+3 -1
View File
@@ -30,6 +30,8 @@
var/outfit_type // What outfit datum does this job use in its default title?
var/offmap_spawn = FALSE // Do we require weird and special spawning and datacore handling?
// Description of the job's role and minimum responsibilities.
var/job_description = "This Job doesn't have a description! Please report it!"
@@ -67,7 +69,7 @@
//give them an account in the station database
var/money_amount = (rand(15,40) + rand(15,40)) * income * economic_modifier * ECO_MODIFIER //VOREStation Edit - Smoothed peaks, ECO_MODIFIER rather than per-species ones.
var/datum/money_account/M = create_account(H.real_name, money_amount, null)
var/datum/money_account/M = create_account(H.real_name, money_amount, null, offmap_spawn)
if(H.mind)
var/remembered_info = ""
remembered_info += "<b>Your account number is:</b> #[M.account_number]<br>"
+22 -6
View File
@@ -357,7 +357,11 @@ var/global/datum/controller/occupations/job_master
else
var/list/spawn_props = LateSpawn(H.client, rank)
var/turf/T = spawn_props["turf"]
H.forceMove(T)
if(!T)
to_chat(H, "<span class='critical'>You were unable to be spawned at your chosen late-join spawnpoint. Please verify your job/spawn point combination makes sense, and try another one.</span>")
return
else
H.forceMove(T)
// Moving wheelchair if they have one
if(H.buckled && istype(H.buckled, /obj/structure/bed/chair/wheelchair))
@@ -458,8 +462,8 @@ var/global/datum/controller/occupations/job_master
if("AI")
return H
if("Colony Director")
var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP)? null : sound('sound/misc/boatswain.ogg', volume=20)
captain_announcement.Announce("All hands, [alt_title ? alt_title : "Colony Director"] [H.real_name] on deck!", new_sound=announce_sound)
var/sound/announce_sound = (ticker.current_state <= GAME_STATE_SETTING_UP) ? null : sound('sound/misc/boatswain.ogg', volume=20)
captain_announcement.Announce("All hands, [alt_title ? alt_title : "Colony Director"] [H.real_name] on deck!", new_sound = announce_sound, zlevel = H.z)
//Deferred item spawning.
if(spawn_in_storage && spawn_in_storage.len)
@@ -608,12 +612,20 @@ var/global/datum/controller/occupations/job_master
/datum/controller/occupations/proc/LateSpawn(var/client/C, var/rank)
var/datum/spawnpoint/spawnpos
var/fail_deadly = FALSE
var/datum/job/J = SSjob.get_job(rank)
fail_deadly = J?.offmap_spawn
//Spawn them at their preferred one
if(C && C.prefs.spawnpoint)
if(!(C.prefs.spawnpoint in using_map.allowed_spawns))
to_chat(C, "<span class='warning'>Your chosen spawnpoint ([C.prefs.spawnpoint]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead.</span>")
spawnpos = null
if(fail_deadly)
to_chat(C, "<span class='warning'>Your chosen spawnpoint is unavailable for this map and your job requires a specific spawnpoint. Please correct your spawn point choice.</span>")
return
else
to_chat(C, "<span class='warning'>Your chosen spawnpoint ([C.prefs.spawnpoint]) is unavailable for the current map. Spawning you at one of the enabled spawn points instead.</span>")
spawnpos = null
else
spawnpos = spawntypes[C.prefs.spawnpoint]
@@ -623,12 +635,16 @@ var/global/datum/controller/occupations/job_master
if(spawnpos.check_job_spawning(rank))
.["turf"] = spawnpos.get_spawn_position()
.["msg"] = spawnpos.msg
.["channel"] = spawnpos.announce_channel
else
if(fail_deadly)
to_chat(C, "<span class='warning'>Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Please correct your spawn point choice.</span>")
return
to_chat(C, "Your chosen spawnpoint ([spawnpos.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")
var/spawning = pick(latejoin)
.["turf"] = get_turf(spawning)
.["msg"] = "will arrive at the station shortly" //VOREStation Edit - Grammar but mostly 'shuttle' reference removal, and this also applies to notified spawn-character verb use
else
else if(!fail_deadly)
var/spawning = pick(latejoin)
.["turf"] = get_turf(spawning)
.["msg"] = "has arrived on the station"
+10
View File
@@ -45,6 +45,16 @@ var/const/BRIDGE =(1<<12)
var/const/CLOWN =(1<<13) //VOREStation Add
var/const/MIME =(1<<14) //VOREStation Add
//VOREStation Add
var/const/TALON =(1<<3)
var/const/TALCAP =(1<<0)
var/const/TALPIL =(1<<1)
var/const/TALDOC =(1<<2)
var/const/TALSEC =(1<<3)
var/const/TALENG =(1<<4)
//VOREStation Add End
/proc/guest_jobbans(var/job)
return ( (job in SSjob.get_job_titles_in_department(DEPARTMENT_COMMAND)) || (job in SSjob.get_job_titles_in_department(DEPARTMENT_SYNTHETIC)) || (job in SSjob.get_job_titles_in_department(DEPARTMENT_SECURITY)) )
-2
View File
@@ -254,8 +254,6 @@
return
if(occupant)
occupant.Stasis(stasis_level)
if(stasis_level >= 100 && occupant.timeofdeath)
occupant.timeofdeath += 1 SECOND
if(filtering > 0)
if(beaker)
+3 -3
View File
@@ -116,7 +116,7 @@
/obj/machinery/alarm/proc/first_run()
alarm_area = get_area(src)
area_uid = alarm_area.uid
area_uid = "\ref[alarm_area]"
if(name == "alarm")
name = "[alarm_area.name] Air Alarm"
@@ -387,7 +387,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 = command
@@ -449,7 +449,7 @@
var/datum/signal/alert_signal = new
alert_signal.source = src
alert_signal.transmission_method = 1
alert_signal.transmission_method = TRANSMISSION_RADIO
alert_signal.data["zone"] = alarm_area.name
alert_signal.data["type"] = "Atmospheric"
+7 -7
View File
@@ -29,7 +29,7 @@
/obj/machinery/air_sensor/process()
if(on)
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.data["tag"] = id_tag
signal.data["timestamp"] = world.time
@@ -212,7 +212,7 @@ obj/machinery/computer/general_air_control/Destroy()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
if(href_list["in_refresh_status"])
input_info = null
@@ -322,7 +322,7 @@ obj/machinery/computer/general_air_control/Destroy()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
if(href_list["in_refresh_status"])
input_info = null
@@ -383,7 +383,7 @@ obj/machinery/computer/general_air_control/Destroy()
injecting = 1
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.source = src
signal.data = list(
@@ -445,7 +445,7 @@ obj/machinery/computer/general_air_control/Destroy()
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(
"tag" = device_tag,
@@ -463,7 +463,7 @@ obj/machinery/computer/general_air_control/Destroy()
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(
"tag" = device_tag,
@@ -478,7 +478,7 @@ obj/machinery/computer/general_air_control/Destroy()
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(
"tag" = device_tag,
+1 -1
View File
@@ -67,7 +67,7 @@
var/datum/signal/signal = new
signal.source = src
signal.transmission_method = 1
signal.transmission_method = TRANSMISSION_RADIO
signal.data = list(
"tag" = id,
"device" = "AM",
+2
View File
@@ -33,6 +33,7 @@
var/busy = 0
var/on_open_network = 0
var/always_visible = FALSE //Visable from any map, good for entertainment network cameras
var/affected_by_emp_until = 0
@@ -472,6 +473,7 @@
cam["name"] = sanitize(c_tag)
cam["deact"] = !can_use()
cam["camera"] = "\ref[src]"
cam["omni"] = always_visible
cam["x"] = x
cam["y"] = y
cam["z"] = z
+1
View File
@@ -102,6 +102,7 @@ var/global/list/engineering_networks = list(
/obj/machinery/camera/network/thunder
network = list(NETWORK_THUNDER)
invuln = 1
always_visible = TRUE
// EMP
+5 -5
View File
@@ -43,11 +43,14 @@
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
data["current_network"] = current_network
data["networks"] = network ? network : list()
var/map_levels = using_map.get_map_levels(src.z, TRUE)
data["map_levels"] = map_levels
if(current_network)
data["cameras"] = camera_repository.cameras_in_network(current_network)
data["cameras"] = camera_repository.cameras_in_network(current_network, map_levels)
if(current_camera)
switch_to_camera(user, current_camera)
data["map_levels"] = using_map.get_map_levels(src.z)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
@@ -91,9 +94,6 @@
. = ..()
/obj/machinery/computer/security/attack_hand(var/mob/user as mob)
if (using_map && !(src.z in using_map.contact_levels))
to_chat(user, "<span class='danger'>Unable to establish a connection:</span> You're too far away from the station!")
return
if(stat & (NOPOWER|BROKEN)) return
if(!isAI(user))
@@ -546,7 +546,7 @@
var/datum/signal/status_signal = new
status_signal.source = src
status_signal.transmission_method = 1
status_signal.transmission_method = TRANSMISSION_RADIO
status_signal.data["command"] = command
switch(command)
+1 -1
View File
@@ -8,7 +8,7 @@
idle_power_usage = 250
active_power_usage = 500
circuit = /obj/item/weapon/circuitboard/crew
var/datum/nano_module/crew_monitor/crew_monitor
var/datum/nano_module/program/crew_monitor/crew_monitor
/obj/machinery/computer/crew/New()
crew_monitor = new(src)
@@ -121,7 +121,7 @@ var/prison_shuttle_timeleft = 0
if(!frequency) return
var/datum/signal/status_signal = new
status_signal.source = src
status_signal.transmission_method = 1
status_signal.transmission_method = TRANSMISSION_RADIO
status_signal.data["command"] = command
frequency.post_signal(src, status_signal)
return
+41 -13
View File
@@ -91,19 +91,28 @@
var/icon/side = active1.fields["photo_side"]
user << browse_rsc(front, "front.png")
user << browse_rsc(side, "side.png")
dat += text("<table><tr><td> \
Name: <A href='?src=\ref[src];choice=Edit Field;field=name'>[active1.fields["name"]]</A><BR> \
ID: <A href='?src=\ref[src];choice=Edit Field;field=id'>[active1.fields["id"]]</A><BR>\n \
Entity Classification: <A href='?src=\ref[src];field=brain_type'>[active1.fields["brain_type"]]</A><BR>\n \
Sex: <A href='?src=\ref[src];choice=Edit Field;field=sex'>[active1.fields["sex"]]</A><BR>\n \
Age: <A href='?src=\ref[src];choice=Edit Field;field=age'>[active1.fields["age"]]</A><BR>\n \
Rank: <A href='?src=\ref[src];choice=Edit Field;field=rank'>[active1.fields["rank"]]</A><BR>\n \
Fingerprint: <A href='?src=\ref[src];choice=Edit Field;field=fingerprint'>[active1.fields["fingerprint"]]</A><BR>\n \
Physical Status: [active1.fields["p_stat"]]<BR>\n \
Mental Status: [active1.fields["m_stat"]]<BR><BR>\n \
Employment/skills summary:<BR> [decode(active1.fields["notes"])]<BR></td> \
<td align = center valign = top>Photo:<br><img src=front.png height=80 width=80 border=4> \
<img src=side.png height=80 width=80 border=4></td></tr></table>")
dat += "<table><tr><td>"
dat += "Name: <A href='?src=\ref[src];choice=Edit Field;field=name'>[active1.fields["name"]]</A><BR>"
dat += "ID: <A href='?src=\ref[src];choice=Edit Field;field=id'>[active1.fields["id"]]</A><BR>\n"
dat += "Entity Classification: <A href='?src=\ref[src];field=brain_type'>[active1.fields["brain_type"]]</A><BR>\n"
dat += "Sex: <A href='?src=\ref[src];choice=Edit Field;field=sex'>[active1.fields["sex"]]</A><BR>\n"
dat += "Age: <A href='?src=\ref[src];choice=Edit Field;field=age'>[active1.fields["age"]]</A><BR>\n"
dat += "Rank: <A href='?src=\ref[src];choice=Edit Field;field=rank'>[active1.fields["rank"]]</A><BR>\n"
dat += "Fingerprint: <A href='?src=\ref[src];choice=Edit Field;field=fingerprint'>[active1.fields["fingerprint"]]</A><BR>\n"
dat += "Physical Status: [active1.fields["p_stat"]]<BR>\n"
dat += "Mental Status: [active1.fields["m_stat"]]<BR><BR>\n"
dat += "Employment/skills summary:<BR>"
dat += decode(active1.fields["notes"])
dat += "<BR><BR><BR>"
var/counter = 1
while(src.active1.fields[text("com_[]", counter)])
dat += text("[]<BR><A href='?src=\ref[];choice=del_c;del_c=[]'>Delete Entry</A><BR><BR>", src.active1.fields[text("com_[]", counter)], src, counter)
counter++
dat += "<A href='?src=\ref[src];choice=add_c'>Add Entry</A><BR><BR></td>"
dat += "<td align = center valign = top>Photo:<br><img src=front.png height=80 width=80 border=4>"
dat += "<img src=side.png height=80 width=80 border=4></td></tr></table>"
else
dat += "<B>General Record Lost!</B><BR>"
dat += text("\n<A href='?src=\ref[];choice=Delete Record (ALL)'>Delete Record (ALL)</A><BR><BR>\n<A href='?src=\ref[];choice=Print Record'>Print Record</A><BR>\n<A href='?src=\ref[];choice=Return'>Back</A><BR>", src, src, src)
@@ -285,6 +294,25 @@ What a mess.*/
P.name = "Employment Record (Unknown/Invald Entry)"
log_debug("[usr] ([usr.ckey]) attempted to print a null employee record, this should be investigated.")
printing = null
// Add comment
if ("add_c")
if (!( istype(src.active1, /datum/data/record) ))
return
var/a1 = src.active1
var/t1 = sanitize(input("Add Comment:", "Emp. records", null, null) as message)
if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1))
return
var/counter = 1
while(src.active1.fields[text("com_[]", counter)])
counter++
src.active1.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD")] [stationtime2text()], [game_year]<BR>[t1]")
// Delete comment
if ("del_c")
var/target = href_list["del_c"]
if (istype(src.active1, /datum/data/record) && src.active1.fields["com_[target]"])
src.active1.fields["com_[target]"] = "<B>Deleted</B>"
//RECORD DELETE
if ("Delete All Records")
temp = ""
+1 -1
View File
@@ -421,7 +421,7 @@
var/datum/signal/status_signal = new
status_signal.source = src
status_signal.transmission_method = 1
status_signal.transmission_method = TRANSMISSION_RADIO
status_signal.data["command"] = command
frequency.post_signal(src, status_signal)
+2 -1
View File
@@ -219,6 +219,7 @@
var/on_enter_occupant_message = "You feel cool air surround you. You go numb as your senses turn inward."
var/on_store_visible_message_1 = "hums and hisses as it moves" //We need two variables because byond doesn't let us have variables inside strings at compile-time.
var/on_store_visible_message_2 = "into storage."
var/announce_channel = "Common"
var/allow_occupant_types = list(/mob/living/carbon/human)
var/disallow_occupant_types = list()
@@ -519,7 +520,7 @@
control_computer._admin_logs += "[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) at [stationtime2text()]"
log_and_message_admins("[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) entered cryostorage.")
announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]")
announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]", announce_channel, using_map.get_map_levels(z, TRUE))
//visible_message("<span class='notice'>\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.</span>", 3)
visible_message("<span class='notice'>\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2].</span>", 3)
+4 -4
View File
@@ -91,7 +91,7 @@ obj/machinery/door/airlock/proc/command_completed(var/command)
obj/machinery/door/airlock/proc/send_status(var/bumped = 0)
if(radio_connection)
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.data["tag"] = id_tag
signal.data["timestamp"] = world.time
@@ -172,7 +172,7 @@ obj/machinery/airlock_sensor/update_icon()
obj/machinery/airlock_sensor/attack_hand(mob/user)
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.data["tag"] = master_tag
signal.data["command"] = command
@@ -186,7 +186,7 @@ obj/machinery/airlock_sensor/process()
if(abs(pressure - previousPressure) > 0.001 || previousPressure == null)
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.data["tag"] = id_tag
signal.data["timestamp"] = world.time
signal.data["pressure"] = num2text(pressure)
@@ -263,7 +263,7 @@ obj/machinery/access_button/attack_hand(mob/user)
else if(radio_connection)
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.transmission_method = TRANSMISSION_RADIO //radio signal
signal.data["tag"] = master_tag
signal.data["command"] = command
+2 -3
View File
@@ -91,7 +91,7 @@
src.density = 1
update_nearby_tiles()
src.update_icon()
src.set_opacity(initial(opacity))
src.set_opacity(1)
sleep(15)
src.operating = 0
@@ -244,8 +244,7 @@
force_open()
if(autoclose && src.operating && !(stat & BROKEN || stat & NOPOWER))
spawn(150)
close()
addtimer(CALLBACK(src, .proc/close, 15 SECONDS))
return 1
// Proc: close()
+1
View File
@@ -290,6 +290,7 @@
FA.anchored = 1
FA.density = 1
FA.wired = 1
FA.glass = glass
FA.update_icon()
qdel(src)
return

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