Merge remote-tracking branch 'upstream/master' into face_lock

# Conflicts:
#	code/modules/mob/mob.dm
This commit is contained in:
tigercat2000
2018-05-17 20:21:39 -07:00
944 changed files with 11247 additions and 15005 deletions
+15 -23
View File
@@ -7,10 +7,9 @@ Pipelines and other atmospheric objects combine to form pipe_networks
Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
*/
GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new())
/obj/machinery/atmospherics
auto_init = 0
anchored = 1
layer = 2.4 //under wires with their 2.44
idle_power_usage = 0
@@ -29,15 +28,12 @@ Pipelines + Other Objects -> Pipe network
var/pipe_color
var/obj/item/pipe/stored
var/image/pipe_image
var/global/datum/pipe_icon_manager/icon_manager
/obj/machinery/atmospherics/New()
if(!armor)
armor = list(melee = 25, bullet = 10, laser = 10, energy = 100, bomb = 0, bio = 100, rad = 100)
..()
SSair.atmos_machinery += src
if(!icon_manager)
icon_manager = new()
if(!pipe_color)
pipe_color = color
@@ -45,12 +41,8 @@ Pipelines + Other Objects -> Pipe network
if(!pipe_color_check(pipe_color))
pipe_color = null
// No need for a tween worldstart roundstart handler - pipenet creation is
// handled there
/obj/machinery/atmospherics/initialize()
..()
/obj/machinery/atmospherics/proc/atmos_init()
if(can_unwrench)
stored = new(src, make_from = src)
@@ -73,9 +65,9 @@ Pipelines + Other Objects -> Pipe network
pipe_image.plane = HUD_PLANE
/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
if(!istype(icon_manager))
if(!istype(GLOB.pipe_icon_manager))
if(!safety) //to prevent infinite loops
icon_manager = new()
GLOB.pipe_icon_manager = new()
check_icon_cache(1)
return 0
@@ -91,14 +83,14 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type)
if(node)
if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
//underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
//underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
else
//underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
//underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
else
//underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
//underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
/obj/machinery/atmospherics/proc/update_underlays()
if(check_icon_cache())
@@ -231,10 +223,10 @@ Pipelines + Other Objects -> Pipe network
var/turf/T = loc
level = T.intact ? 2 : 1
add_fingerprint(usr)
initialize()
atmos_init()
var/list/nodes = pipeline_expansion()
for(var/obj/machinery/atmospherics/A in nodes)
A.initialize()
A.atmos_init()
A.addMember(src)
build_network()
@@ -320,11 +312,11 @@ Pipelines + Other Objects -> Pipe network
/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
if(node)
if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
else
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
else
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
underlays += GLOB.pipe_icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
/obj/machinery/atmospherics/singularity_pull(S, current_size)
if(current_size >= STAGE_FIVE)
@@ -41,7 +41,7 @@
nullifyPipenet(parent2)
return ..()
/obj/machinery/atmospherics/binary/initialize()
/obj/machinery/atmospherics/binary/atmos_init()
..()
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
@@ -48,7 +48,7 @@
radio_connection = null
return ..()
/obj/machinery/atmospherics/binary/dp_vent_pump/initialize()
/obj/machinery/atmospherics/binary/dp_vent_pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -90,7 +90,7 @@
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , vent_icon)
/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
if(..())
@@ -240,13 +240,13 @@
update_icon()
/obj/machinery/atmospherics/binary/dp_vent_pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
if(istype(W, /obj/item/device/multitool))
if(istype(W, /obj/item/multitool))
update_multitool_menu(user)
return 1
return ..()
/obj/machinery/atmospherics/binary/dp_vent_pump/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
/obj/machinery/atmospherics/binary/dp_vent_pump/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
<li><b>Frequency:</b> <a href="?src=[UID()];set_freq=-1">[format_frequency(frequency)] GHz</a> (<a href="?src=[UID()];set_freq=[1439]">Reset</a>)</li>
@@ -16,7 +16,7 @@
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/binary/passive_gate/initialize()
/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -110,7 +110,7 @@ Thus, the two variables affect pump operation are set in New():
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/binary/pump/initialize()
/obj/machinery/atmospherics/binary/pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -109,7 +109,7 @@
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/valve/digital/initialize()
/obj/machinery/atmospherics/binary/valve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -141,12 +141,12 @@
close()
/obj/machinery/atmospherics/binary/valve/digital/attackby(var/obj/item/W as obj, var/mob/user)
if(istype(W, /obj/item/device/multitool))
if(istype(W, /obj/item/multitool))
update_multitool_menu(user)
return 1
..()
/obj/machinery/atmospherics/binary/valve/digital/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
/obj/machinery/atmospherics/binary/valve/digital/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
<li><b>Frequency:</b> <a href="?src=[UID()];set_freq=-1">[format_frequency(frequency)] GHz</a> (<a href="?src=[UID()];set_freq=[1439]">Reset</a>)</li>
@@ -38,7 +38,7 @@ Thus, the two variables affect pump operation are set in New():
on = 1
icon_state = "map_on"
/obj/machinery/atmospherics/binary/volume_pump/initialize()
/obj/machinery/atmospherics/binary/volume_pump/atmos_init()
..()
set_frequency(frequency)
@@ -40,9 +40,9 @@
/datum/omni_port/proc/connect()
if(node)
return
master.initialize()
master.atmos_init()
if(node)
node.initialize()
node.atmos_init()
node.addMember(master)
master.build_network()
@@ -56,7 +56,7 @@
nullifyPipenet(P.parent)
return ..()
/obj/machinery/atmospherics/omni/initialize()
/obj/machinery/atmospherics/omni/atmos_init()
..()
for(var/datum/omni_port/P in ports)
if(P.node || P.mode == 0)
@@ -143,11 +143,11 @@
//directional icons are layers 1-4, with the core icon on layer 5
if(core_icon)
overlays_off[5] = icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_on[5] = icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
overlays_off[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_on[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
overlays_error[1] = icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_error[2] = icon_manager.get_atmos_icon("omni", , , "error")
overlays_error[1] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_error[2] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , "error")
/obj/machinery/atmospherics/omni/proc/update_port_icons()
if(!check_icon_cache())
@@ -203,19 +203,19 @@
ic_on += "_filter"
ic_off += "_out"
ic_on = icon_manager.get_atmos_icon("omni", , , ic_on)
ic_off = icon_manager.get_atmos_icon("omni", , , ic_off)
ic_on = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_on)
ic_off = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_off)
var/pipe_state
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
//pipe_state = icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
else
//pipe_state = icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
pipe_state = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state)
@@ -149,7 +149,7 @@ Filter types:
return 1
/obj/machinery/atmospherics/trinary/filter/initialize()
/obj/machinery/atmospherics/trinary/filter/atmos_init()
set_frequency(frequency)
..()
@@ -66,7 +66,7 @@
nullifyPipenet(parent3)
return ..()
/obj/machinery/atmospherics/trinary/initialize()
/obj/machinery/atmospherics/trinary/atmos_init()
..()
//Mixer:
//1 and 2 is input
@@ -156,7 +156,7 @@
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/trinary/tvalve/digital/initialize()
/obj/machinery/atmospherics/trinary/tvalve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
@@ -20,7 +20,7 @@
return
/obj/machinery/atmospherics/unary/heat_exchanger/initialize()
/obj/machinery/atmospherics/unary/heat_exchanger/atmos_init()
if(!partner)
var/partner_connect = turn(dir,180)
@@ -120,7 +120,7 @@
return 1
/obj/machinery/atmospherics/unary/outlet_injector/initialize()
/obj/machinery/atmospherics/unary/outlet_injector/atmos_init()
..()
set_frequency(frequency)
@@ -164,7 +164,7 @@
on = 0
return*/
/obj/machinery/atmospherics/unary/outlet_injector/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
/obj/machinery/atmospherics/unary/outlet_injector/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
<li><b>Frequency:</b> <a href="?src=[UID()];set_freq=-1">[format_frequency(frequency)] GHz</a> (<a href="?src=[UID()];set_freq=[1439]">Reset</a>)</li>
@@ -173,7 +173,7 @@
"}
/obj/machinery/atmospherics/unary/outlet_injector/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/device/multitool))
if(istype(W, /obj/item/multitool))
interact(user)
return 1
if(istype(W, /obj/item/wrench))
@@ -18,7 +18,7 @@
add_underlay(T, node, dir)
/obj/machinery/atmospherics/unary/tank/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/device/analyzer))
if(istype(W, /obj/item/analyzer))
atmosanalyzer_scan(air_contents, user)
return
@@ -22,7 +22,7 @@
nullifyPipenet(parent)
return ..()
/obj/machinery/atmospherics/unary/initialize()
/obj/machinery/atmospherics/unary/atmos_init()
..()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if(target.initialize_directions & get_dir(target,src))
@@ -43,9 +43,9 @@
node.disconnect(src)
node = null
nullifyPipenet(parent)
initialize()
atmos_init()
if(node)
node.initialize()
node.atmos_init()
node.addMember(src)
build_network()
. = 1
@@ -98,7 +98,7 @@
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , vent_icon)
update_pipe_image()
@@ -223,7 +223,7 @@
return 1
/obj/machinery/atmospherics/unary/vent_pump/initialize()
/obj/machinery/atmospherics/unary/vent_pump/atmos_init()
..()
//some vents work his own special way
@@ -367,7 +367,7 @@
else
to_chat(user, "The vent is welded.")
return 1
if(istype(W, /obj/item/device/multitool))
if(istype(W, /obj/item/multitool))
update_multitool_menu(user)
return 1
if(istype(W, /obj/item/wrench))
@@ -399,7 +399,7 @@
/obj/machinery/atmospherics/unary/vent_pump/interact(mob/user as mob)
update_multitool_menu(user)
/obj/machinery/atmospherics/unary/vent_pump/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
/obj/machinery/atmospherics/unary/vent_pump/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
<li><b>Frequency:</b> <a href="?src=[UID()];set_freq=-1">[format_frequency(frequency)] GHz</a> (<a href="?src=[UID()];set_freq=[1439]">Reset</a>)</li>
@@ -109,7 +109,7 @@
if(welded)
scrubber_icon = "scrubberweld"
overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("device", , , scrubber_icon)
update_pipe_image()
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
@@ -169,7 +169,7 @@
return 1
/obj/machinery/atmospherics/unary/vent_scrubber/initialize()
/obj/machinery/atmospherics/unary/vent_scrubber/atmos_init()
..()
radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
@@ -339,7 +339,7 @@
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/unary/vent_scrubber/multitool_menu(var/mob/user,var/obj/item/device/multitool/P)
/obj/machinery/atmospherics/unary/vent_scrubber/multitool_menu(var/mob/user,var/obj/item/multitool/P)
return {"
<ul>
<li><b>Frequency:</b> <a href="?src=[UID()];set_freq=-1">[format_frequency(frequency)] GHz</a> (<a href="?src=[UID()];set_freq=[1439]">Reset</a>)</li>
@@ -394,7 +394,7 @@
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return 1
if(istype(W, /obj/item/device/multitool))
if(istype(W, /obj/item/multitool))
update_multitool_menu(user)
return 1
if(istype(W, /obj/item/wrench))
+3 -10
View File
@@ -57,11 +57,7 @@ var/pipenetwarnings = 10
if(!members.Find(item))
if(item.parent)
if(pipenetwarnings > 0)
error("[item.type] added to a pipenet while still having one (pipes leading to the same spot stacking in one turf). Nearby: [item.x], [item.y], [item.z].")
pipenetwarnings -= 1
if(pipenetwarnings == 0)
error("Further messages about pipenets will be suppressed.")
log_runtime(EXCEPTION("[item.type] \[\ref[item]] added to a pipenet while still having one ([item.parent]) (pipes leading to the same spot stacking in one turf). Nearby: [item.x], [item.y], [item.z]."))
members += item
possible_expansions += item
@@ -118,15 +114,12 @@ var/pipenetwarnings = 10
qdel(E)
/obj/machinery/atmospherics/proc/addMember(obj/machinery/atmospherics/A)
return
var/datum/pipeline/P = returnPipenet(A)
P.addMember(A, src)
/obj/machinery/atmospherics/pipe/addMember(obj/machinery/atmospherics/A)
parent.addMember(A, src)
/obj/machinery/atmospherics/addMember(obj/machinery/atmospherics/A)
var/datum/pipeline/P = returnPipenet(A)
P.addMember(A, src)
/datum/pipeline/proc/temporarily_store_air()
//Update individual gas_mixtures by volume ratio
+2 -2
View File
@@ -61,9 +61,9 @@
alpha = 255
overlays.Cut()
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "cap" + icon_connect_type)
/obj/machinery/atmospherics/pipe/cap/initialize()
/obj/machinery/atmospherics/pipe/cap/atmos_init()
..()
for(var/obj/machinery/atmospherics/target in get_step(src, dir))
if(target.initialize_directions & get_dir(target,src))
+3 -3
View File
@@ -32,7 +32,7 @@
if(WEST)
initialize_directions = NORTH|EAST|SOUTH
/obj/machinery/atmospherics/pipe/manifold/initialize()
/obj/machinery/atmospherics/pipe/manifold/atmos_init()
..()
for(var/D in cardinal)
if(D == dir)
@@ -122,8 +122,8 @@
alpha = 255
overlays.Cut()
overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
underlays.Cut()
var/turf/T = get_turf(src)
+3 -3
View File
@@ -95,8 +95,8 @@
alpha = 255
overlays.Cut()
overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
underlays.Cut()
var/turf/T = get_turf(src)
@@ -134,7 +134,7 @@
if(level == 1 && istype(loc, /turf/simulated))
invisibility = i ? 101 : 0
/obj/machinery/atmospherics/pipe/manifold4w/initialize()
/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
..()
for(var/D in cardinal)
for(var/obj/machinery/atmospherics/target in get_step(src, D))
+2 -2
View File
@@ -37,11 +37,11 @@
parent = null
/obj/machinery/atmospherics/pipe/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/device/analyzer))
if(istype(W, /obj/item/analyzer))
atmosanalyzer_scan(parent.air, user)
return
if(istype(W,/obj/item/device/pipe_painter))
if(istype(W,/obj/item/pipe_painter))
return
return ..()
@@ -43,7 +43,7 @@
if(SOUTHWEST)
initialize_directions = SOUTH|WEST
/obj/machinery/atmospherics/pipe/simple/initialize(initPipe = 1)
/obj/machinery/atmospherics/pipe/simple/atmos_init(initPipe = 1)
..()
if(initPipe)
normalize_dir()
@@ -145,9 +145,9 @@
overlays.Cut()
if(node1 && node2)
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "intact" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "intact" + icon_connect_type)
else
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "exposed[node1?1:0][node2?1:0]" + icon_connect_type)
overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, pipe_icon + "exposed[node1?1:0][node2?1:0]" + icon_connect_type)
// A check to make sure both nodes exist - self-delete if they aren't present
/obj/machinery/atmospherics/pipe/simple/check_nodes_exist()
@@ -61,7 +61,7 @@
initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
color = "#404040"
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/initialize(initPipe = 1)
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init(initPipe = 1)
..(0)
if(initPipe)
normalize_dir()
@@ -110,7 +110,7 @@
initialize_directions = EAST
initialize_directions_he = WEST
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/initialize()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
..(0)
for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
if(target.initialize_directions & get_dir(target,src))
@@ -34,7 +34,7 @@
alpha = 255
overlays.Cut()
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
underlays.Cut()
if(node1)
@@ -45,7 +45,7 @@
alpha = 255
overlays.Cut()
overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
overlays += GLOB.pipe_icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
underlays.Cut()
if(node1)
-191
View File
@@ -1,191 +0,0 @@
//Ok so it's technically a double linked list, bite me.
/datum/linked_list
var/datum/linked_node/head
var/datum/linked_node/tail
var/node_amt = 0
/datum/linked_node
var/value = null
var/datum/linked_list/linked_list = null
var/datum/linked_node/next_node = null
var/datum/linked_node/previous_node = null
/datum/linked_list/proc/IsEmpty()
. = (node_amt <= 0)
//Add a linked_node (or value, creating a linked_node) at position
//the added node BECOMES the position-th element,
//eg: add("Test",5), the 5th node is now "Test", the previous 5th moves up to become the 6th
/datum/linked_list/proc/Add(node, position)
var/datum/linked_node/adding
if(istype(node, /datum/linked_node))
adding = node
else
adding = new()
adding.value = node
if(!adding.linked_list || (adding.linked_list && (adding.linked_list != src)))
node_amt++
adding.linked_list = src
if(position && position < node_amt)
//Replacing head
if(position == 1)
if(head)
head.previous_node = adding
adding.next_node = head
head = adding
//Replacing any middle node
else
var/location = 0
var/datum/linked_node/at
while((location != position) && (location <= node_amt))
if(at)
if(at.next_node)
at = at.next_node
else
break
else
at = head
location++
//Push at up and assume it's place as the position-th element
if(at && at.previous_node)
at.previous_node.next_node = adding
adding.previous_node = at.previous_node
at.previous_node = adding
adding.next_node = at
return
//Replacing tail
if(tail)
tail.next_node = adding
adding.previous_node = tail
if(!tail.previous_node)
head = tail
tail = adding
//Remove a linked_node or the linked_node of a value
//If you specify a value the FIRST ONE is removed
/datum/linked_list/proc/Remove(node)
var/datum/linked_node/removing
if(istype(node,/datum/linked_node))
removing = node
else
//optimise removing head and tail, no point looping for them, especially the tail
if(removing == head)
removing = head
else if(removing == tail)
removing = tail
else
var/location = 1
var/current_value = null
var/datum/linked_node/at = null
while((current_value != node) && (location <= node_amt))
if(at)
if(at.next_node)
at = at.next_node
else
at = head
location++
if(at)
current_value = at.value
if(current_value == node)
removing = at
break
//Adjust pointers of where removing -was- in the chain.
if(removing)
if(removing.previous_node)
if(removing == tail)
tail = removing.previous_node
if(removing.next_node)
if(removing == head)
head = removing.next_node
removing.next_node.previous_node = removing.previous_node
removing.previous_node.next_node = removing.next_node
else
removing.previous_node.next_node = null
else
if(removing.next_node)
if(removing == head)
head = removing.next_node
removing.next_node.previous_node = null
//if this is still true at this point, there's no more nodes to replace them with
if(removing == head)
head = null
if(removing == tail)
tail = null
removing.next_node = null
removing.previous_node = null
if(removing.linked_list == src)
node_amt--
removing.linked_list = null
return removing
return 0
//Removes and deletes a node or value
/datum/linked_list/proc/RemoveDelete(node)
var/datum/linked_node/dead = Remove(node)
if(dead)
qdel(dead)
return 1
return 0
//Empty the linked_list, deleting all nodes
/datum/linked_list/proc/Empty()
var/datum/linked_node/n = head
while(n)
var/next = n.next_node
Remove(n)
qdel(n)
n = next
node_amt = 0
//Some debugging tools
/datum/linked_list/proc/CheckNodeLinks()
var/datum/linked_node/n = head
while(n)
. = "|[n.value]|"
if(n.previous_node)
. = "[n.previous_node.value]<-" + .
if(n.next_node)
. += "->[n.next_node.value]"
n = n.next_node
. += "<BR>"
/datum/linked_list/proc/DrawNodeLinks()
. = "|<-"
var/datum/linked_node/n = head
while(n)
if(n.previous_node)
. += "<-"
. += "[n.value]"
if(n.next_node)
. += "->"
n = n.next_node
. += "->|"
/datum/linked_list/proc/ToList()
. = list()
var/datum/linked_node/n = head
while(n)
. += n
n = n.next_node
-83
View File
@@ -1,83 +0,0 @@
//////////////////////
//PriorityQueue object
//////////////////////
//an ordered list, using the cmp proc to weight the list elements
/PriorityQueue
var/list/L //the actual queue
var/cmp //the weight function used to order the queue
/PriorityQueue/New(compare)
L = new()
cmp = compare
/PriorityQueue/proc/IsEmpty()
return !L.len
//return the index the element should be in the priority queue using dichotomic search
/PriorityQueue/proc/FindElementIndex(atom/A)
var/i = 1
var/j = L.len
var/mid
while(i < j)
mid = round((i+j)/2)
if(call(cmp)(L[mid],A) < 0)
i = mid + 1
else
j = mid
if(i == 1 || i == L.len) //edge cases
return (call(cmp)(L[i],A) > 0) ? i : i+1
else
return i
//add an element in the list,
//immediatly ordering it to its position using dichotomic search
/PriorityQueue/proc/Enqueue(atom/A)
if(!L.len)
L.Add(A)
return
L.Insert(FindElementIndex(A),A)
//removes and returns the first element in the queue
/PriorityQueue/proc/Dequeue()
if(!L.len)
return 0
. = L[1]
Remove(.)
//removes an element
/PriorityQueue/proc/Remove(atom/A)
return L.Remove(A)
//returns a copy of the elements list
/PriorityQueue/proc/List()
. = L.Copy()
//return the position of an element or 0 if not found
/PriorityQueue/proc/Seek(atom/A)
. = L.Find(A)
//return the element at the i_th position
/PriorityQueue/proc/Get(i)
if(i > L.len || i < 1)
return 0
return L[i]
//replace the passed element at it's right position using the cmp proc
/PriorityQueue/proc/ReSort(atom/A)
var/i = Seek(A)
if(i == 0)
return
while(i < L.len && call(cmp)(L[i],L[i+1]) > 0)
L.Swap(i,i+1)
i++
while(i > 1 && call(cmp)(L[i],L[i-1]) <= 0) //last inserted element being first in case of ties (optimization)
L.Swap(i,i-1)
i--
View File
+151
View File
@@ -0,0 +1,151 @@
//shorthand
#define GET_COMPONENT_FROM(varname, path, target) var##path/##varname = ##target.GetComponent(##path)
#define GET_COMPONENT(varname, path) GET_COMPONENT_FROM(varname, path, src)
#define COMPONENT_INCOMPATIBLE 1
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
// All signals. Format:
// When the signal is called: (signal arguments)
// /datum signals
#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
#define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: ()
// /atom signals
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
//Positions for overrides list
#define EXAMINE_POSITION_ARTICLE 1
#define EXAMINE_POSITION_BEFORE 2
//End positions
#define COMPONENT_EXNAME_CHANGED 1
#define COMSIG_ATOM_ENTERED "atom_entered" //from base of atom/Entered(): (atom/movable/entering, /atom)
#define COMSIG_ATOM_EXITED "atom_exited" //from base of atom/Exited(): (atom/movable/exiting, atom/newloc)
#define COMSIG_ATOM_EX_ACT "atom_ex_act" //from base of atom/ex_act(): (severity, target)
#define COMSIG_ATOM_EMP_ACT "atom_emp_act" //from base of atom/emp_act(): (severity)
#define COMSIG_ATOM_FIRE_ACT "atom_fire_act" //from base of atom/fire_act(): (exposed_temperature, exposed_volume)
#define COMSIG_ATOM_BULLET_ACT "atom_bullet_act" //from base of atom/bullet_act(): (/obj/item/projectile, def_zone)
#define COMSIG_ATOM_BLOB_ACT "atom_blob_act" //from base of atom/blob_act(): (/obj/structure/blob)
#define COMSIG_ATOM_ACID_ACT "atom_acid_act" //from base of atom/acid_act(): (acidpwr, acid_volume)
#define COMSIG_ATOM_EMAG_ACT "atom_emag_act" //from base of atom/emag_act(): ()
#define COMSIG_ATOM_RAD_ACT "atom_rad_act" //from base of atom/rad_act(intensity)
#define COMSIG_ATOM_NARSIE_ACT "atom_narsie_act" //from base of atom/narsie_act(): ()
#define COMSIG_ATOM_RATVAR_ACT "atom_ratvar_act" //from base of atom/ratvar_act(): ()
#define COMSIG_ATOM_RCD_ACT "atom_rcd_act" //from base of atom/rcd_act(): (/mob, /obj/item/construction/rcd, passed_mode)
#define COMSIG_ATOM_SING_PULL "atom_sing_pull" //from base of atom/singularity_pull(): (S, current_size)
#define COMSIG_ATOM_SET_LIGHT "atom_set_light" //from base of atom/set_light(): (l_range, l_power, l_color)
#define COMSIG_ATOM_ROTATE "atom_rotate" //from base of atom/shuttleRotate(): (rotation, params)
#define COMSIG_ATOM_DIR_CHANGE "atom_dir_change" //from base of atom/setDir(): (old_dir, new_dir)
#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del" //from base of atom/handle_atom_del(): (atom/deleted)
/////////////////
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" //from base of atom/attack_ghost(): (mob/dead/observer/ghost)
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand" //from base of atom/attack_hand(): (mob/user)
#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw" //from base of atom/attack_paw(): (mob/user)
#define COMPONENT_NO_ATTACK_HAND 1 //works on all 3.
/////////////////
#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area)
#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area)
#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params)
#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob)
#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob)
#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob)
#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" //from base of atom/CtrlShiftClick(/mob)
#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" //from base of atom/MouseDrop(): (/atom/over, /mob/user)
#define COMPONENT_NO_MOUSEDROP 1
#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user)
// /area signals
#define COMSIG_AREA_ENTERED "area_entered" //from base of area/Entered(): (atom/movable/M)
#define COMSIG_AREA_EXITED "area_exited" //from base of area/Exited(): (atom/movable/M)
// /atom/movable signals
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
#define COMSIG_MOVABLE_UNCROSSED "movable_uncrossed" //from base of atom/movable/Uncrossed(): (/atom/movable)
#define COMSIG_MOVABLE_COLLIDE "movable_collide" //from base of atom/movable/Collide(): (/atom)
#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
#define COMSIG_MOVABLE_THROW "movable_throw" //from base of atom/movable/throw_at(): (datum/thrownthing, spin)
// /obj signals
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
// /obj/item signals
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
#define COMPONENT_NO_ATTACK_OBJ 1
#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
#define COMPONENT_NO_ATTACK 1
#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
#define COMSIG_ITEM_DROPPED "item_drop"
#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
// /obj/item/clothing signals
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
// /obj/machinery signals
#define COMSIG_MACHINE_PROCESS "machine_process" //from machinery subsystem fire(): ()
#define COMSIG_MACHINE_PROCESS_ATMOS "machine_process_atmos" //from air subsystem process_atmos_machinery(): ()
// /mob/living/carbon/human signals
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
/*******Component Specific Signals*******/
//Janitor
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
#define COMSIG_COMPONENT_CLEAN_ACT "clean_act" //called on an object to clean it of cleanables. Usualy with soap: (num/strength)
//Food
#define COMSIG_FOOD_EATEN "food_eaten" //from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
//Mood
#define COMSIG_ADD_MOOD_EVENT "add_mood" //Called when you send a mood event from anywhere in the code.
#define COMSIG_CLEAR_MOOD_EVENT "clear_mood" //Called when you clear a mood event from anywhere in the code.
//NTnet
#define COMSIG_COMPONENT_NTNET_RECIEVE "ntnet_recieve" //called on an object by its NTNET connection component on recieve. (sending_id(number), sending_netname(text), data(datum/netdata))
// /datum/component/storage signals
#define COMSIG_CONTAINS_STORAGE "is_storage" //() - returns bool.
#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert" //(obj/item/inserting, mob/user, silent, force) - returns bool
#define COMSIG_TRY_STORAGE_SHOW "storage_show_to" //(mob/show_to, force) - returns bool.
#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from" //(mob/hide_from) - returns bool
#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all" //returns bool
#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state" //(newstate)
#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate" //() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type" //(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type" //(type, amount = INFINITY, force = FALSE) //don't fuck this up. Force will ignore max_items, and amount is normally clamped to max_items.
#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj" //(obj, new_loc, force = FALSE) - returns bool
#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty" //(loc) - returns bool - if loc is null it will dump at parent location.
#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory" //(list/list_to_inject_results_into)
#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip" //(obj/item/insertion_candidate, mob/user, silent) - returns bool
/*******Non-Signal Component Related Defines*******/
//Arch
#define ARCH_PROB "probability" //Probability for each item
#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
//Ouch my toes!
#define CALTROP_BYPASS_SHOES 1
#define CALTROP_IGNORE_WALKERS 2
+2
View File
@@ -40,10 +40,12 @@
#define MAT_DIAMOND "$diamond"
#define MAT_URANIUM "$uranium"
#define MAT_PLASMA "$plasma"
#define MAT_BLUESPACE "$bluespace"
#define MAT_BANANIUM "$bananium"
#define MAT_TRANQUILLITE "$tranquillite"
#define MAT_TITANIUM "$titanium"
#define MAT_BIOMASS "$biomass"
#define MAT_PLASTIC "$plastic"
//The amount of materials you get from a sheet of mineral like iron/diamond/glass etc
#define MINERAL_MATERIAL_AMOUNT 2000
//The maximum size of a stack object.
+30
View File
@@ -24,6 +24,36 @@
#define DROPDEL 16384 // When dropped, it calls qdel on itself
/* Secondary atom flags, for the flags_2 var, denoted with a _2 */
#define SLOWS_WHILE_IN_HAND_2 1
#define NO_EMP_WIRES_2 2
#define HOLOGRAM_2 4
#define FROZEN_2 8
#define STATIONLOVING_2 16
#define INFORM_ADMINS_ON_RELOCATE_2 32
#define BANG_PROTECT_2 64
// An item worn in the ear slot with HEALS_EARS will heal your ears each
// Life() tick, even if normally your ears would be too damaged to heal.
#define HEALS_EARS_2 128
// A mob with OMNITONGUE has no restriction in the ability to speak
// languages that they know. So even if they wouldn't normally be able to
// through mob or tongue restrictions, this flag allows them to ignore
// those restrictions.
#define OMNITONGUE_2 256
// TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
#define TESLA_IGNORE_2 512
// Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
#define NO_MAT_REDEMPTION_2 1024
// LAVA_PROTECT used on the flags_2 variable for both SUIT and HEAD items, and stops lava damage. Must be present in both to stop lava damage.
#define LAVA_PROTECT_2 2048
//Reagent flags
#define REAGENT_NOREACT 1
+24 -1
View File
@@ -41,8 +41,31 @@ var/list/static/global/pointed_types = typecacheof(list(
#define ismineralturf(A) istype(A, /turf/simulated/mineral)
//Mobs
#define isliving(A) (istype(A, /mob/living))
#define isbrain(A) (istype(A, /mob/living/carbon/brain))
//Carbon mobs
#define iscarbon(A) (istype(A, /mob/living/carbon))
#define ishuman(A) (istype(A, /mob/living/carbon/human))
//more carbon mobs
#define isalien(A) (istype(A, /mob/living/carbon/alien))
#define islarva(A) (istype(A, /mob/living/carbon/alien/larva))
#define isalienadult(A) (istype(A, /mob/living/carbon/alien/humanoid))
#define isalienhunter(A) (istype(A, /mob/living/carbon/alien/humanoid/hunter))
#define isaliensentinel(A) (istype(A, /mob/living/carbon/alien/humanoid/sentinel))
#define isslime(A) (istype((A), /mob/living/carbon/slime))
// Misc
#define isclient(A) istype(A, /client)
#define isradio(A) istype(A, /obj/item/device/radio)
#define isradio(A) istype(A, /obj/item/radio)
#define ispill(A) istype(A, /obj/item/reagent_containers/food/pill)
+1
View File
@@ -22,6 +22,7 @@
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
#define PODFAB 32 //Used by the spacepod part fabricator. Same idea as the mechfab
#define BIOGENERATOR 64 //Uses biomass
#define SMELTER 128 //uses various minerals
//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
#define HYDRO_SPEED_MULTIPLIER 1
+2
View File
@@ -32,6 +32,8 @@
#define ToDegrees(radians) ((radians) * 57.2957795) // 180 / Pi
#define ToRadians(degrees) ((degrees) * 0.0174532925) // Pi / 180
#define SHORT_REAL_LIMIT 16777216
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
//collapsed to percent_of_tick_used * tick_lag
-9
View File
@@ -128,15 +128,6 @@
#define TINT_BLIND 3 //Threshold of tint level to obscure vision fully
#define EYE_SHINE_THRESHOLD 6 //dark_view threshold past which a humanoid's eyes will 'shine' in the dark.
#define isliving(A) (istype((A), /mob/living))
#define iscarbon(A) (istype((A), /mob/living/carbon))
#define ishuman(A) (istype((A), /mob/living/carbon/human))
#define isbrain(A) (istype((A), /mob/living/carbon/brain))
#define isalien(A) (istype((A), /mob/living/carbon/alien))
#define isalienadult(A) (istype((A), /mob/living/carbon/alien/humanoid))
#define islarva(A) (istype((A), /mob/living/carbon/alien/larva))
#define isslime(A) (istype((A), /mob/living/carbon/slime))
//Human sub-species
#define isabductor(A) (is_species(A, "Abductor"))
+1
View File
@@ -40,6 +40,7 @@
#define ROLE_NYMPH "Dionaea"
#define ROLE_GSPIDER "giant spider"
#define ROLE_DRONE "drone"
#define ROLE_DEATHSQUAD "deathsquad"
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
+185
View File
@@ -0,0 +1,185 @@
//location of the rust-g library
#define RUST_G "rust_g"
// On Linux/Unix systems the line endings are LF, on windows it's CRLF, admins that don't use notepad++
// will get logs that are one big line if the system is Linux and they are using notepad. This solves it by adding CR to every line ending
// in the logs. ascii character 13 = CR
/var/global/log_end = world.system_type == UNIX ? ascii2text(13) : ""
#define DIRECT_OUTPUT(A, B) A << B
#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
#define WRITE_LOG(log, text) call(RUST_G, "log_write")(log, text)
/proc/error(msg)
log_world("## ERROR: [msg]")
//print a warning message to world.log
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
/proc/warning(msg)
log_world("## WARNING: [msg]")
//print a testing-mode debug message to world.log and world
#ifdef TESTING
#define testing(msg) log_world("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]")
#else
#define testing(msg)
#endif
/proc/log_admin(text)
admin_log.Add(text)
if(config.log_admin)
WRITE_LOG(GLOB.world_game_log, "ADMIN: [text][log_end]")
/proc/log_debug(text)
if(config.log_debug)
WRITE_LOG(GLOB.world_game_log, "DEBUG: [text][log_end]")
for(var/client/C in admins)
if(check_rights(R_DEBUG, 0, C.mob) && (C.prefs.toggles & CHAT_DEBUGLOGS))
to_chat(C, "DEBUG: [text]")
/proc/log_game(text)
if(config.log_game)
WRITE_LOG(GLOB.world_game_log, "GAME: [text][log_end]")
/proc/log_vote(text)
if(config.log_vote)
WRITE_LOG(GLOB.world_game_log, "VOTE: [text][log_end]")
/proc/log_access_in(client/new_client)
if(config.log_access)
var/message = "[key_name(new_client)] - IP:[new_client.address] - CID:[new_client.computer_id] - BYOND v[new_client.byond_version]"
WRITE_LOG(GLOB.world_game_log, "ACCESS IN: [message][log_end]")
/proc/log_access_out(mob/last_mob)
if(config.log_access)
var/message = "[key_name(last_mob)] - IP:[last_mob.lastKnownIP] - CID:[last_mob.computer_id] - BYOND Logged Out"
WRITE_LOG(GLOB.world_game_log, "ACCESS OUT: [message][log_end]")
/proc/log_say(text, mob/speaker)
if(config.log_say)
WRITE_LOG(GLOB.world_game_log, "SAY: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_whisper(text, mob/speaker)
if(config.log_whisper)
WRITE_LOG(GLOB.world_game_log, "WHISPER: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_ooc(text, client/user)
if(config.log_ooc)
WRITE_LOG(GLOB.world_game_log, "OOC: [user.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_aooc(text, client/user)
if(config.log_ooc)
WRITE_LOG(GLOB.world_game_log, "AOOC: [user.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_looc(text, client/user)
if(config.log_ooc)
WRITE_LOG(GLOB.world_game_log, "LOOC: [user.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_emote(text, mob/speaker)
if(config.log_emote)
WRITE_LOG(GLOB.world_game_log, "EMOTE: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_attack(attacker, defender, message)
if(config.log_attack)
WRITE_LOG(GLOB.world_game_log, "ATTACK: [attacker] against [defender]: [message][log_end]") //Seperate attack logs? Why?
/proc/log_adminsay(text, mob/speaker)
if(config.log_adminchat)
WRITE_LOG(GLOB.world_game_log, "ADMINSAY: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_mentorsay(text, mob/speaker)
if(config.log_adminchat)
WRITE_LOG(GLOB.world_game_log, "MENTORSAY: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_ghostsay(text, mob/speaker)
if(config.log_say)
WRITE_LOG(GLOB.world_game_log, "DEADCHAT: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_ghostemote(text, mob/speaker)
if(config.log_emote)
WRITE_LOG(GLOB.world_game_log, "DEADEMOTE: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_adminwarn(text)
if(config.log_adminwarn)
WRITE_LOG(GLOB.world_game_log, "ADMINWARN: [html_decode(text)][log_end]")
/proc/log_pda(text, mob/speaker)
if(config.log_pda)
WRITE_LOG(GLOB.world_game_log, "PDA: [speaker.simple_info_line()]: [html_decode(text)][log_end]")
/proc/log_chat(text, mob/speaker)
if(config.log_pda)
WRITE_LOG(GLOB.world_game_log, "CHAT: [speaker.simple_info_line()] [html_decode(text)][log_end]")
/proc/log_misc(text)
WRITE_LOG(GLOB.world_game_log, "MISC: [text][log_end]")
/proc/log_world(text)
SEND_TEXT(world.log, text)
if(config && config.log_world_output)
WRITE_LOG(GLOB.world_game_log, "WORLD: [html_decode(text)][log_end]")
/proc/log_runtime_txt(text) // different from /tg/'s log_runtime because our error handler has a log_runtime proc already that does other stuff
WRITE_LOG(GLOB.world_runtime_log, text)
/proc/log_config(text)
WRITE_LOG(GLOB.config_error_log, text)
SEND_TEXT(world.log, text)
/proc/log_href(text)
WRITE_LOG(GLOB.world_href_log, "HREF: [html_decode(text)]")
/**
* Standardized method for tracking startup times.
*/
/proc/log_startup_progress(var/message)
to_chat(world, "<span class='danger'>[message]</span>")
log_world(message)
// A logging proc that only outputs after setup is done, to
// help devs test initialization stuff that happens a lot
/proc/log_after_setup(var/message)
if(ticker && ticker.current_state > GAME_STATE_SETTING_UP)
to_chat(world, "<span class='danger'>[message]</span>")
log_world(message)
/* For logging round startup. */
/proc/start_log(log)
WRITE_LOG(log, "Starting up.\n-------------------------")
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
/proc/shutdown_logging()
call(RUST_G, "log_close_all")()
// Helper procs for building detailed log lines
/proc/datum_info_line(var/datum/d)
if(!istype(d))
return
if(!istype(d, /mob))
return "[d] ([d.type])"
var/mob/m = d
return "[m] ([m.ckey]) ([m.type])"
/proc/atom_loc_line(var/atom/a)
if(!istype(a))
return
var/turf/t = get_turf(a)
if(istype(t))
return "[a.loc] ([t.x],[t.y],[t.z]) ([a.loc.type])"
else if(a.loc)
return "[a.loc] (0,0,0) ([a.loc.type])"
/mob/proc/simple_info_line()
return "[key_name(src)] ([x],[y],[z])"
/client/proc/simple_info_line()
return "[key_name(src)] ([mob.x],[mob.y],[mob.z])"
//this is only used here (for now)
#undef RUST_G
+3
View File
@@ -31,6 +31,9 @@
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
return a.priority - b.priority
/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
return a.timeToRun - b.timeToRun
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
. = B.hard_delete_time - A.hard_delete_time
if(!.)
+23 -9
View File
@@ -137,9 +137,9 @@
if(sight_check && !isInSight(A, O))
continue
L |= M
//log_to_dd("[recursion_limit] = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])")
//log_world("[recursion_limit] = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])")
else if(include_radio && istype(A, /obj/item/device/radio))
else if(include_radio && istype(A, /obj/item/radio))
if(sight_check && !isInSight(A, O))
continue
L |= A
@@ -167,8 +167,8 @@
var/mob/M = A
if(M.client || include_clientless)
hear += M
//log_to_dd("Start = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])")
else if(istype(A, /obj/item/device/radio))
//log_world("Start = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])")
else if(istype(A, /obj/item/radio))
hear += A
if(isobj(A) || ismob(A))
@@ -177,17 +177,17 @@
return hear
/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios)
/proc/get_mobs_in_radio_ranges(var/list/obj/item/radio/radios)
set background = 1
. = list()
// Returns a list of mobs who can hear any of the radios given in @radios
var/list/speaker_coverage = list()
for(var/obj/item/device/radio/R in radios)
for(var/obj/item/radio/R in radios)
if(R)
//Cyborg checks. Receiving message uses a bit of cyborg's charge.
var/obj/item/device/radio/borg/BR = R
var/obj/item/radio/borg/BR = R
if(istype(BR) && BR.myborg)
var/mob/living/silicon/robot/borg = BR.myborg
var/datum/robot_component/CO = borg.get_component("radio")
@@ -435,7 +435,7 @@
/proc/SecondsToTicks(var/seconds)
return seconds * 10
proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE)
proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
var/roletext = be_special_type ? get_roletext(be_special_type) : null
var/list/mob/dead/observer/candidates = list()
var/time_passed = world.time
@@ -457,7 +457,7 @@ proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time =
if(config.use_exp_restrictions && min_hours)
if(G.client.get_exp_living_num() < min_hours * 60)
continue
if(cannotPossess(G))
if(check_antaghud && cannotPossess(G))
continue
spawn(0)
G << 'sound/misc/notice2.ogg'//Alerting them to their consideration
@@ -490,6 +490,20 @@ proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time =
return candidates
/proc/pollCandidatesByKeyWithVeto(adminclient, adminusr, max_slots, Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE, check_antaghud = TRUE)
var/list/willing_ghosts = pollCandidates(Question, be_special_type, antag_age_check, poll_time, ignore_respawnability, min_hours, flashwindow, check_antaghud)
var/list/candidate_ckeys = list()
var/list/selected_ckeys = list()
if(!willing_ghosts.len)
return selected_ckeys
for(var/mob/dead/observer/G in willing_ghosts)
candidate_ckeys += G.key
for(var/i = max_slots, (i > 0 && candidate_ckeys.len), i--)
var/this_ckey = input("Pick players. This will go on until there either no more ghosts to pick from or the slots are full.", "Candidates") as null|anything in candidate_ckeys
candidate_ckeys -= this_ckey
selected_ckeys += this_ckey
return selected_ckeys
/proc/window_flash(client/C)
if(ismob(C))
var/mob/M = C
+4 -4
View File
@@ -416,7 +416,7 @@
//Don't use this on lists larger than half a dozen or so
/proc/insertion_sort_numeric_list_ascending(var/list/L)
//log_to_dd("ascending len input: [L.len]")
//log_world("ascending len input: [L.len]")
var/list/out = list(pop(L))
for(var/entry in L)
if(isnum(entry))
@@ -429,13 +429,13 @@
if(!success)
out.Add(entry)
//log_to_dd(" output: [out.len]")
//log_world(" output: [out.len]")
return out
/proc/insertion_sort_numeric_list_descending(var/list/L)
//log_to_dd("descending len input: [L.len]")
//log_world("descending len input: [L.len]")
var/list/out = insertion_sort_numeric_list_ascending(L)
//log_to_dd(" output: [out.len]")
//log_world(" output: [out.len]")
return reverselist(out)
//Copies a list, and all lists inside it recusively
-131
View File
@@ -1,131 +0,0 @@
//print an error message to world.log
// On Linux/Unix systems the line endings are LF, on windows it's CRLF, admins that don't use notepad++
// will get logs that are one big line if the system is Linux and they are using notepad. This solves it by adding CR to every line ending
// in the logs. ascii character 13 = CR
/var/global/log_end= world.system_type == UNIX ? ascii2text(13) : ""
/proc/error(msg)
log_to_dd("## ERROR: [msg]")
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
//print a warning message to world.log
/proc/warning(msg)
log_to_dd("## WARNING: [msg]")
//print a testing-mode debug message to world.log and world
#ifdef TESTING
#define testing(msg) log_to_dd("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]")
#else
#define testing(msg)
#endif
/proc/log_admin(text)
admin_log.Add(text)
if(config.log_admin)
diary << "\[[time_stamp()]]ADMIN: [text]"
/proc/log_debug(text)
if(config.log_debug)
diary << "\[[time_stamp()]]DEBUG: [text]"
for(var/client/C in admins)
if(check_rights(R_DEBUG, 0, C.mob) && (C.prefs.toggles & CHAT_DEBUGLOGS))
to_chat(C, "DEBUG: [text]")
/proc/log_game(text)
if(config.log_game)
diary << "\[[time_stamp()]]GAME: [text]"
/proc/log_vote(text)
if(config.log_vote)
diary << "\[[time_stamp()]]VOTE: [text]"
/proc/log_access(text)
if(config.log_access)
diary << "\[[time_stamp()]]ACCESS: [text]"
/proc/log_say(text)
if(config.log_say)
diary << "\[[time_stamp()]]SAY: [text]"
/proc/log_robot(text)
if(config.log_say)
diary << "\[[time_stamp()]]ROBOT: [text]"
/proc/log_ooc(text)
if(config.log_ooc)
diary << "\[[time_stamp()]]OOC: [text]"
/proc/log_whisper(text)
if(config.log_whisper)
diary << "\[[time_stamp()]]WHISPER: [text]"
/proc/log_emote(text)
if(config.log_emote)
diary << "\[[time_stamp()]]EMOTE: [text]"
/proc/log_attack(text)
if(config.log_attack)
diary << "\[[time_stamp()]]ATTACK: [text]" //Seperate attack logs? Why?
/proc/log_adminsay(text)
if(config.log_adminchat)
diary << "\[[time_stamp()]]ADMINSAY: [text]"
/proc/log_adminwarn(text)
if(config.log_adminwarn)
diary << "\[[time_stamp()]]ADMINWARN: [text]"
/proc/log_pda(text)
if(config.log_pda)
diary << "\[[time_stamp()]]PDA: [text][log_end]"
/proc/log_chat(text)
if (config.log_pda)
diary << "\[[time_stamp()]]CHAT: [text]"
/proc/log_misc(text)
diary << "\[[time_stamp()]]MISC: [text][log_end]"
/proc/log_to_dd(text)
world.log << text
if(config && config.log_world_output)
diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]"
/**
* Standardized method for tracking startup times.
*/
/proc/log_startup_progress(var/message)
to_chat(world, "<span class='danger'>[message]</span>")
log_to_dd(message)
// A logging proc that only outputs after setup is done, to
// help devs test initialization stuff that happens a lot
/proc/log_after_setup(var/message)
if(ticker && ticker.current_state > GAME_STATE_SETTING_UP)
to_chat(world, "<span class='danger'>[message]</span>")
log_to_dd(message)
// Helper procs for building detailed log lines
/proc/datum_info_line(var/datum/d)
if(!istype(d))
return
if(!istype(d, /mob))
return "[d] ([d.type])"
var/mob/m = d
return "[m] ([m.ckey]) ([m.type])"
/proc/atom_loc_line(var/atom/a)
if(!istype(a))
return
var/turf/t = get_turf(a)
if(istype(t))
return "[a.loc] ([t.x],[t.y],[t.z]) ([a.loc.type])"
else if(a.loc)
return "[a.loc] (0,0,0) ([a.loc.type])"
+19 -21
View File
@@ -243,30 +243,28 @@ proc/age2agedescription(age)
Proc for attack log creation, because really why not
1 argument is the actor
2 argument is the target of action
3 is the description of action(like punched, throwed, or any other verb)
4 is the tool with which the action was made(usually item)
5 is additional information, anything that needs to be added
6 is whether the attack should be logged to the log file and shown to admins
3 is the full description of the action
4 is whether or not to message admins
This is always put in the attack log.
*/
proc/add_logs(mob/user, mob/target, what_done, var/object=null, var/addition=null, var/admin=1, var/print_attack_log = 1)//print_attack_log notifies admins with attack logs on
var/list/ignore=list("shaked", "CPRed", "grabbed", "disarmed")
if(!user)
/proc/add_attack_logs(mob/user, mob/target, what_done, admin_notify = TRUE)
if(islist(target)) // Multi-victim adding
var/list/targets = target
for(var/mob/M in targets)
add_attack_logs(user, M, what_done, admin_notify)
return
if(ismob(user))
user.create_attack_log("<font color='red'>Has [what_done] [key_name(target)][object ? " with [object]" : " "][addition]</font>")
if(ismob(target))
target.create_attack_log("<font color='orange'>Has been [what_done] by [key_name(user)][object ? " with [object]" : " "][addition]</font>")
if(admin)
log_attack("<font color='red'>[key_name(user)] [what_done] [key_name(target)][object ? " with [object]" : " "][addition]</font>")
if(istype(target) && (target.key))
if(what_done in ignore)
return
if(target == user)
return
if(!print_attack_log)
return
msg_admin_attack("[key_name_admin(user)] [what_done] [key_name_admin(target)][object ? " with [object]" : " "][addition]")
var/user_str = key_name(user)
var/target_str = key_name(target)
if(istype(user))
user.create_attack_log("<font color='red'>Attacked [target_str]: [what_done]</font>")
if(istype(target))
target.create_attack_log("<font color='orange'>Attacked by [user_str]: [what_done]</font>")
log_attack(user_str, target_str, what_done)
if(admin_notify)
msg_admin_attack("[key_name_admin(user)] vs [key_name_admin(target)]: [what_done]")
/proc/do_mob(var/mob/user, var/mob/target, var/time = 30, var/uninterruptible = 0, progress = 1, datum/callback/extra_checks = null)
if(!user || !target)
+6 -1
View File
@@ -1,5 +1,10 @@
#define QDEL_IN(item, time) addtimer(GLOBAL_PROC, "qdel", time, FALSE, item)
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)
#define QDEL_NULL(item) if(item) { qdel(item); item = null }
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
QDEL_LIST(L)
+6 -3
View File
@@ -42,9 +42,12 @@
/proc/worldtime2text()
return gameTimestamp("hh:mm:ss", world.time)
/proc/time_stamp(format = "hh:mm:ss", show_ds)
var/time_string = time2text(world.timeofday, format)
return show_ds ? "[time_string]:[world.timeofday % 10]" : time_string
// This is ISO-8601
// If anything that uses this proc shouldn't be ISO-8601, change that thing, not this proc. This is important for logging.
/proc/time_stamp()
var/date_portion = time2text(world.timeofday, "YYYY-MM-DD")
var/time_portion = time2text(world.timeofday, "hh:mm:ss")
return "[date_portion]T[time_portion]"
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
+16 -1
View File
@@ -364,4 +364,19 @@
value = splittext(value, "]") //"name]!" --> list("name","!")
for(var/A in value)
if(var_source.vars.Find(A))
. += A
. += A
/proc/type2parent(child)
var/string_type = "[child]"
var/last_slash = findlasttext(string_type, "/")
if(last_slash == 1)
switch(child)
if(/datum)
return null
if(/obj || /mob)
return /atom/movable
if(/area || /turf)
return /atom
else
return /datum
return text2path(copytext(string_type, 1, last_slash))
+21 -8
View File
@@ -394,6 +394,16 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M)
return moblist
// Format a power value in W, kW, MW, or GW.
/proc/DisplayPower(powerused)
if(powerused < 1000) //Less than a kW
return "[powerused] W"
else if(powerused < 1000000) //Less than a MW
return "[round((powerused * 0.001), 0.01)] kW"
else if(powerused < 1000000000) //Less than a GW
return "[round((powerused * 0.000001), 0.001)] MW"
return "[round((powerused * 0.000000001), 0.0001)] GW"
//E = MC^2
/proc/convert2energy(var/M)
var/E = M*(SPEED_OF_LIGHT_SQ)
@@ -1092,7 +1102,7 @@ var/global/list/common_tools = list(
/obj/item/weldingtool,
/obj/item/screwdriver,
/obj/item/wirecutters,
/obj/item/device/multitool,
/obj/item/multitool,
/obj/item/crowbar)
/proc/istool(O)
@@ -1126,7 +1136,7 @@ var/global/list/common_tools = list(
return 0
/proc/ismultitool(O)
if(istype(O, /obj/item/device/multitool))
if(istype(O, /obj/item/multitool))
return 1
return 0
@@ -1171,8 +1181,8 @@ var/global/list/common_tools = list(
return 1000
else
return 0
if(istype(W, /obj/item/device/flashlight/flare))
var/obj/item/device/flashlight/flare/O = W
if(istype(W, /obj/item/flashlight/flare))
var/obj/item/flashlight/flare/O = W
if(O.on)
return 1000
else
@@ -1185,7 +1195,7 @@ var/global/list/common_tools = list(
return 3500
else
return 0
if(istype(W, /obj/item/device/assembly/igniter))
if(istype(W, /obj/item/assembly/igniter))
return 1000
else
return 0
@@ -1239,7 +1249,7 @@ var/global/list/common_tools = list(
Checks if that loc and dir has a item on the wall
*/
var/list/static/global/wall_items = typecacheof(list(/obj/machinery/power/apc, /obj/machinery/alarm,
/obj/item/device/radio/intercom, /obj/structure/extinguisher_cabinet, /obj/structure/reagent_dispensers/peppertank,
/obj/item/radio/intercom, /obj/structure/extinguisher_cabinet, /obj/structure/reagent_dispensers/peppertank,
/obj/machinery/status_display, /obj/machinery/requests_console, /obj/machinery/light_switch, /obj/structure/sign,
/obj/machinery/newscaster, /obj/machinery/firealarm, /obj/structure/noticeboard, /obj/machinery/door_control,
/obj/machinery/computer/security/telescreen, /obj/machinery/embedded_controller/radio/airlock,
@@ -1751,7 +1761,7 @@ var/mob/dview/dview_mob = new
var/typename = "[type]"
var/static/list/TYPES_SHORTCUTS = list(
/obj/effect/decal/cleanable = "CLEANABLE",
/obj/item/device/radio/headset = "HEADSET",
/obj/item/radio/headset = "HEADSET",
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
/obj/item/book/manual = "MANUAL",
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
@@ -1928,4 +1938,7 @@ var/mob/dview/dview_mob = new
CRASH(msg)
/datum/proc/stack_trace(msg)
CRASH(msg)
CRASH(msg)
/proc/pass()
return
+2
View File
@@ -30,3 +30,5 @@ var/list/round_end_sounds = list( // Maps available round end sounds to their du
'sound/goonstation/misc/newround1.ogg' = 6.9 SECONDS,
'sound/goonstation/misc/newround2.ogg' = 14.8 SECONDS
)
GLOBAL_LIST(station_level_space_turfs)
+1 -2
View File
@@ -1,5 +1,5 @@
var/global/list/portals = list() //for use by portals
var/global/list/cable_list = list() //Index for all cables, so that powernets don't have to look through the entire world all the time
GLOBAL_LIST(cable_list) //Index for all cables, so that powernets don't have to look through the entire world all the time
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
var/global/list/landmarks_list = list() //list of all landmarks created
@@ -17,7 +17,6 @@ var/global/list/cell_logs = list()
var/global/list/all_areas = list()
var/global/list/machines = list()
var/global/list/machine_processing = list()
var/global/list/fast_processing = list()
var/global/list/processing_power_items = list() //items that ask to be called every cycle
var/global/list/rcd_list = list() //list of Rapid Construction Devices.
+11 -4
View File
@@ -1,6 +1,13 @@
var/diary = null
var/diaryofmeanpeople = null
var/href_logfile = null
GLOBAL_VAR(log_directory)
GLOBAL_PROTECT(log_directory)
GLOBAL_VAR(world_game_log)
GLOBAL_PROTECT(world_game_log)
GLOBAL_VAR(config_error_log)
GLOBAL_PROTECT(config_error_log)
GLOBAL_VAR(world_runtime_log)
GLOBAL_PROTECT(world_runtime_log)
GLOBAL_VAR(world_href_log)
GLOBAL_PROTECT(world_href_log)
var/list/jobMax = list()
var/list/bombers = list( )
@@ -13,4 +20,4 @@ var/list/IClog = list()
var/list/OOClog = list()
var/list/adminlog = list()
var/list/investigate_log_subjects = list("notes", "watchlist", "hrefs")
var/list/investigate_log_subjects = list("notes", "watchlist", "hrefs")
+2 -2
View File
@@ -5,8 +5,8 @@ var/global/obj/effect/overlay/icemaster = null
// Event Manager, the manager for events.
var/datum/event_manager/event_manager = new()
// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
var/global/obj/item/device/radio/intercom/global_announcer = create_global_announcer()
var/global/obj/item/device/radio/intercom/command/command_announcer = create_command_announcer()
var/global/obj/item/radio/intercom/global_announcer = create_global_announcer()
var/global/obj/item/radio/intercom/command/command_announcer = create_command_announcer()
// Load order issues means this can't be new'd until other code runs
// This is probably not the way I should be doing this, but I don't know how to do it right!
proc/create_global_announcer()
-7
View File
@@ -3,11 +3,4 @@ var/global/datum/datacore/data_core = null
var/CELLRATE = 0.002 // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
var/CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
var/list/powernets = list()
var/list/deferred_powernet_rebuilds = list()
// this is not strictly unused although the whole modules datum thing is unused
// To remove this you need to remove that
var/datum/moduletypes/mods = new()
var/map_name = "Unknown" //The name of the map that is loaded. Assigned in world/New()
+1 -1
View File
@@ -39,7 +39,7 @@
if(pixel_turf)
turf_visible = cameranet.checkTurfVis(pixel_turf)
if(!turf_visible)
if(istype(loc, /obj/item/device/aicard) && (pixel_turf in view(client.view, loc)))
if(istype(loc, /obj/item/aicard) && (pixel_turf in view(client.view, loc)))
turf_visible = TRUE
else
if(pixel_turf.obscured)
+1 -1
View File
@@ -433,7 +433,7 @@ so as to remain in compliance with the most up-to-date laws."
desc = "Someone is trying to capture your soul in a soul stone. Click to allow it."
icon_state = "template"
timeout = 10 SECONDS
var/obj/item/device/soulstone/stone = null
var/obj/item/soulstone/stone = null
var/stoner = null
/obj/screen/alert/notify_soulstone/Click()
+3 -3
View File
@@ -14,10 +14,10 @@
// No comment
/atom/proc/attackby(obj/item/W, mob/user, params)
return
return SendSignal(COMSIG_PARENT_ATTACKBY, W, user, params)
/obj/attackby(obj/item/I, mob/living/user, params)
return I.attack_obj(src, user)
return ..() || I.attack_obj(src, user)
/mob/living/attackby(obj/item/I, mob/living/user, params)
user.changeNext_move(CLICK_CD_MELEE)
@@ -66,7 +66,7 @@
user.do_attack_animation(M)
M.attacked_by(src, user, def_zone)
add_logs(user, M, "attacked", name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])", print_attack_log = (force > 0))//print it if stuff deals damage
add_attack_logs(user, M, "Attacked with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])", admin_notify = (force > 0 && damtype != STAMINA))
add_fingerprint(user)
+3 -3
View File
@@ -54,10 +54,10 @@
return 1
/mob/living/carbon/brain/can_use_rig()
return istype(loc, /obj/item/device/mmi)
return istype(loc, /obj/item/mmi)
/mob/living/silicon/ai/can_use_rig()
return istype(loc, /obj/item/device/aicard)
return istype(loc, /obj/item/aicard)
/mob/living/silicon/pai/can_use_rig()
return loc == card
@@ -69,7 +69,7 @@
if(istype(rig) && !rig.offline && rig.selected_module)
if(src != rig.wearer)
if(rig.ai_can_move_suit(src, check_user_module = 1))
message_admins("[key_name_admin(src, include_name = 1)] is trying to force \the [key_name_admin(rig.wearer, include_name = 1)] to use a hardsuit module.")
message_admins("[key_name_admin(src)] is trying to force \the [key_name_admin(rig.wearer)] to use a hardsuit module.")
else
return 0
rig.selected_module.engage(A, alert_ai)
@@ -386,9 +386,9 @@
if(istype(thrower, /atom))
var/atom/A = thrower
ptext += " ([A]) ([A.x],[A.y],[A.z])"
log_to_dd("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]")
log_world("\[[time_stamp()]\] Process [name] caught exception[ptext]: [etext]")
if(exceptions[eid] >= 10)
log_to_dd("This exception will now be ignored for ten minutes.")
log_world("This exception will now be ignored for ten minutes.")
spawn(6000)
exceptions[eid] = 0
-74
View File
@@ -1,74 +0,0 @@
/var/global/machinery_sort_required = 0
/datum/controller/process/machinery/setup()
name = "machinery"
schedule_interval = 20 // every 2 seconds
start_delay = 12
/datum/controller/process/machinery/statProcess()
..()
stat(null, "[machine_processing.len] machines")
stat(null, "[powernets.len] powernets, [deferred_powernet_rebuilds.len] deferred")
/datum/controller/process/machinery/doWork()
process_sort()
process_power()
process_power_drain()
process_machines()
/datum/controller/process/machinery/proc/process_sort()
if(machinery_sort_required)
machinery_sort_required = 0
machine_processing = dd_sortedObjectList(machine_processing)
/datum/controller/process/machinery/proc/process_machines()
for(last_object in machine_processing)
var/obj/machinery/M = last_object
if(istype(M) && !QDELETED(M))
try
if(M.process() == PROCESS_KILL)
machine_processing.Remove(M)
continue
if(M.use_power)
M.auto_use_power()
catch(var/exception/e)
catchException(e, M)
else
catchBadType(M)
machine_processing -= M
SCHECK
/datum/controller/process/machinery/proc/process_power()
for(last_object in deferred_powernet_rebuilds)
var/obj/O = last_object
if(istype(O) && !QDELETED(O))
try
var/datum/powernet/newPN = new()// creates a new powernet...
propagate_network(O, newPN)//... and propagates it to the other side of the cable
catch(var/exception/e)
catchException(e, O)
SCHECK
else
catchBadType(O)
deferred_powernet_rebuilds -= O
for(last_object in powernets)
var/datum/powernet/powerNetwork = last_object
if(istype(powerNetwork) && !QDELETED(powerNetwork))
try
powerNetwork.reset()
catch(var/exception/e)
catchException(e, powerNetwork)
SCHECK
else
catchBadType(powerNetwork)
powernets -= powerNetwork
/datum/controller/process/machinery/proc/process_power_drain()
// Currently only used by powersinks. These items get priority processed before machinery
for(var/obj/item/I in processing_power_items)
if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
processing_power_items.Remove(I)
SCHECK
-35
View File
@@ -1,35 +0,0 @@
var/global/datum/controller/process/mob/mob_master
/datum/controller/process/mob
var/current_cycle
/datum/controller/process/mob/setup()
name = "mob"
schedule_interval = 20 // every 2 seconds
start_delay = 16
log_startup_progress("Mob ticker starting up.")
/datum/controller/process/mob/started()
..()
if(!mob_list)
mob_list = list()
/datum/controller/process/mob/statProcess()
..()
stat(null, "[mob_list.len] mobs")
/datum/controller/process/mob/doWork()
for(last_object in mob_list)
var/mob/M = last_object
if(istype(M) && !QDELETED(M))
try
M.Life()
catch(var/exception/e)
catchException(e, M)
SCHECK
else
catchBadType(M)
mob_list -= M
current_cycle++
DECLARE_GLOBAL_CONTROLLER(mob, mob_master)
@@ -44,7 +44,7 @@ DECLARE_GLOBAL_CONTROLLER(mob_hunt, mob_hunt_server)
recover_time = 3000
if(recover_time > 0) //when provided with a negative or zero valued recover_time argument, the server won't auto-restart but can be manually rebooted still
//set a timer to automatically recover after recover_time has passed (can be manually restarted if you get impatient too)
addtimer(src, "auto_recover", recover_time, TRUE)
addtimer(CALLBACK(src, .proc/auto_recover), recover_time, TIMER_UNIQUE)
/datum/controller/process/mob_hunt/proc/client_mob_update()
var/list/ex_players = list()
-100
View File
@@ -1,100 +0,0 @@
var/global/datum/controller/process/timer/timer_master
/datum/controller/process/timer
var/list/processing_timers = list()
var/list/hashes = list()
/datum/controller/process/timer/setup()
name = "timer"
schedule_interval = 1 //every 0.1 seconds--2 server ticks
log_startup_progress("Timer process starting up.")
/datum/controller/process/timer/statProcess()
..()
stat(null, "[processing_timers.len] timers")
/datum/controller/process/timer/doWork()
if(!processing_timers.len)
disabled = 1 //nothing to do, lets stop firing.
return
for(last_object in processing_timers)
var/datum/timedevent/event = last_object
if(!event.thingToCall || check_datum_qdeleted(event.thingToCall))
qdel(event)
if(event.timeToRun <= world.time)
runevent(event)
qdel(event)
SCHECK
DECLARE_GLOBAL_CONTROLLER(timer, timer_master)
/datum/controller/process/timer/proc/runevent(datum/timedevent/event)
set waitfor = 0
if(event.thingToCall)
if(event.thingToCall == GLOBAL_PROC && istext(event.procToCall))
call("/proc/[event.procToCall]")(arglist(event.argList))
else
call(event.thingToCall, event.procToCall)(arglist(event.argList))
/datum/timedevent
var/thingToCall
var/procToCall
var/timeToRun
var/argList
var/id
var/hash
var/static/nextid = 1
/datum/timedevent/New()
id = nextid++
/datum/timedevent/Destroy()
timer_master.processing_timers -= src
timer_master.hashes -= hash
return QDEL_HINT_IWILLGC
/proc/addtimer(thingToCall, procToCall, wait, unique = FALSE, ...)
if(!timer_master) //can't run timers before the mc has been created
return
if(!thingToCall || !procToCall)
return
if(timer_master.disabled)
timer_master.disabled = 0
var/datum/timedevent/event = new()
event.thingToCall = thingToCall
event.procToCall = procToCall
event.timeToRun = world.time + wait
var/hashlist = args.Copy()
hashlist[1] = "[thingToCall](\ref[thingToCall])"
event.hash = jointext(hashlist, null)
if(args.len > 4)
event.argList = args.Copy(5)
// Check for dupes if unique = 1.
if(unique)
var/datum/timedevent/hash_event = timer_master.hashes[event.hash]
if(hash_event)
return hash_event.id
timer_master.hashes[event.hash] = event
if(wait <= 0)
timer_master.runevent(event)
timer_master.hashes -= event.hash
return
// If we are unique (or we're not checking that), add the timer and return the id.
timer_master.processing_timers += event
return event.id
/proc/deltimer(id)
if(id == 0)
// No event will correspond to an id of 0 - the timer does not exist
// Save us a possibly expensive iteration through the timer list
// This would probably be more efficient in general if we used an associative list instead
return 0
for(var/datum/timedevent/event in timer_master.processing_timers)
if(event.id == id)
qdel(event)
return 1
return 0
+1 -1
View File
@@ -37,7 +37,7 @@ var/global/datum/controller/process/weather/weather_master
var/datum/weather/W = pickweight(possible_weather_for_this_z)
run_weather(W.name)
eligible_zlevels -= Z
addtimer(src, "make_z_eligible", rand(3000, 6000) + W.weather_duration_upper, TRUE, Z) //Around 5-10 minutes between weathers
addtimer(CALLBACK(src, .proc/make_z_eligible, Z), rand(3000, 6000) + W.weather_duration_upper, TIMER_UNIQUE) //Around 5-10 minutes between weathers
DECLARE_GLOBAL_CONTROLLER(weather, weather_master)
+11 -13
View File
@@ -55,7 +55,6 @@
var/guest_jobban = 1
var/usewhitelist = 0
var/mods_are_mentors = 0
var/kick_inactive = 0 //force disconnect for inactive players
var/load_jobs_from_txt = 0
var/ToRban = 0
var/automute_on = 0 //enables automuting/spam prevention
@@ -203,13 +202,15 @@
var/randomize_shift_time = FALSE
var/enable_night_shifts = FALSE
// Developer
var/developer_express_start = 0
/datum/configuration/New()
for(var/T in subtypesof(/datum/game_mode))
var/datum/game_mode/M = T
if(initial(M.config_tag))
if(!(initial(M.config_tag) in modes)) // ensure each mode is added only once
diary << "Adding game mode [initial(M.name)] ([initial(M.config_tag)]) to configuration."
src.modes += initial(M.config_tag)
src.mode_names[initial(M.config_tag)] = initial(M.name)
src.probabilities[initial(M.config_tag)] = initial(M.probability)
@@ -423,16 +424,13 @@
if(prob_name in config.modes)
config.probabilities[prob_name] = text2num(prob_value)
else
diary << "Unknown game mode probability configuration definition: [prob_name]."
log_config("Unknown game mode probability configuration definition: [prob_name].")
else
diary << "Incorrect probability configuration definition: [prob_name] [prob_value]."
log_config("Incorrect probability configuration definition: [prob_name] [prob_value].")
if("allow_random_events")
config.allow_random_events = 1
if("kick_inactive")
config.kick_inactive = 1
if("load_jobs_from_txt")
load_jobs_from_txt = 1
@@ -617,13 +615,13 @@
config.high_pop_mc_mode_amount = text2num(value)
if("disable_high_pop_mc_mode_amount")
config.disable_high_pop_mc_mode_amount = text2num(value)
if("developer_express_start")
config.developer_express_start = 1
else
diary << "Unknown setting in configuration: '[name]'"
log_config("Unknown setting in configuration: '[name]'")
else if(type == "game_options")
if(!value)
diary << "Unknown value for setting [name] in [filename]."
value = text2num(value)
switch(name)
@@ -684,7 +682,7 @@
if("enable_night_shifts")
config.enable_night_shifts = TRUE
else
diary << "Unknown setting in configuration: '[name]'"
log_config("Unknown setting in configuration: '[name]'")
/datum/configuration/proc/loadsql(filename) // -- TLE
var/list/Lines = file2list(filename)
@@ -729,10 +727,10 @@
if("db_version")
db_version = text2num(value)
else
diary << "Unknown setting in configuration: '[name]'"
log_config("Unknown setting in configuration: '[name]'")
if(config.sql_enabled && db_version != SQL_VERSION)
config.sql_enabled = 0
diary << "WARNING: DB_CONFIG DEFINITION MISMATCH!"
log_config("WARNING: DB_CONFIG DEFINITION MISMATCH!")
spawn(60)
if(ticker.current_state == GAME_STATE_PREGAME)
going = 0
+1 -3
View File
@@ -16,8 +16,6 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
gvars_datum_in_built_vars = exclude_these.vars + list("gvars_datum_protected_varlist", "gvars_datum_in_built_vars", "gvars_datum_init_order")
qdel(exclude_these)
log_to_dd("[vars.len - gvars_datum_in_built_vars.len] global variables")
Initialize()
/datum/controller/global_vars/Destroy(force)
@@ -60,7 +58,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
var/list/expected_global_procs = vars - gvars_datum_in_built_vars
for(var/I in global_procs)
expected_global_procs -= replacetext("[I]", "InitGlobal", "")
log_to_dd("Missing procs: [expected_global_procs.Join(", ")]")
log_world("Missing procs: [expected_global_procs.Join(", ")]")
for(var/I in global_procs)
var/start_tick = world.time
call(src, I)()
+22 -18
View File
@@ -54,7 +54,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/static/restart_clear = 0
var/static/restart_timeout = 0
var/static/restart_count = 0
var/static/random_seed
//current tick limit, assigned before running a subsystem.
@@ -62,14 +62,15 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/static/current_ticklimit = TICK_LIMIT_RUNNING
/datum/controller/master/New()
makeDatumRefLists()
//temporary file used to record errors with loading config, moved to log directory once logging is set up
GLOB.config_error_log = GLOB.world_game_log = GLOB.world_runtime_log = "data/logs/config_error.log"
load_configuration()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(!random_seed)
random_seed = rand(1, 1e9)
rand_seed(random_seed)
var/list/_subsystems = list()
subsystems = _subsystems
if(Master != src)
@@ -96,9 +97,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
sortTim(subsystems, /proc/cmp_subsystem_init)
reverseRange(subsystems)
for(var/datum/controller/subsystem/ss in subsystems)
log_to_dd("Shutting down [ss.name] subsystem...")
log_world("Shutting down [ss.name] subsystem...")
ss.Shutdown()
log_to_dd("Shutdown complete")
log_world("Shutdown complete")
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
// -1 if we encountered a runtime trying to recreate it
@@ -133,7 +134,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
msg += "\t [varname] = [D]([D.type])\n"
else
msg += "\t [varname] = [varval]\n"
log_to_dd(msg)
log_world(msg)
var/datum/controller/subsystem/BadBoy = Master.last_type_processed
var/FireHim = FALSE
@@ -149,7 +150,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
BadBoy.flags |= SS_NO_FIRE
if(msg)
to_chat(admins, "<span class='boldannounce'>[msg]</span>")
log_to_dd(msg)
log_world(msg)
if(istype(Master.subsystems))
if(FireHim)
@@ -191,7 +192,10 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, "<span class='boldannounce'>[msg]</span>")
log_to_dd(msg)
log_world(msg)
if(config.developer_express_start & ticker.current_state == GAME_STATE_PREGAME)
ticker.current_state = GAME_STATE_SETTING_UP
if(!current_runlevel)
SetRunLevel(1)
@@ -347,7 +351,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if(CheckQueue(subsystems_to_check) <= 0)
if(!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
log_to_dd("MC: SoftReset() failed, crashing")
log_world("MC: SoftReset() failed, crashing")
return
if(!error_level)
iteration++
@@ -359,7 +363,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
if(queue_head)
if(RunQueue() <= 0)
if(!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
log_to_dd("MC: SoftReset() failed, crashing")
log_world("MC: SoftReset() failed, crashing")
return
if(!error_level)
iteration++
@@ -538,9 +542,9 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// called if any mc's queue procs runtime or exit improperly.
/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS)
. = 0
log_to_dd("MC: SoftReset called, resetting MC queue state.")
log_world("MC: SoftReset called, resetting MC queue state.")
if(!istype(subsystems) || !istype(ticker_SS) || !istype(runlevel_SS))
log_to_dd("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'")
log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'")
return
var/subsystemstocheck = subsystems + ticker_SS
for(var/I in runlevel_SS)
@@ -554,26 +558,26 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
ticker_SS -= list(SS)
for(var/I in runlevel_SS)
I -= list(SS)
log_to_dd("MC: SoftReset: Found bad entry in subsystem list, '[SS]'")
log_world("MC: SoftReset: Found bad entry in subsystem list, '[SS]'")
continue
if(SS.queue_next && !istype(SS.queue_next))
log_to_dd("MC: SoftReset: Found bad data in subsystem queue, queue_next = '[SS.queue_next]'")
log_world("MC: SoftReset: Found bad data in subsystem queue, queue_next = '[SS.queue_next]'")
SS.queue_next = null
if(SS.queue_prev && !istype(SS.queue_prev))
log_to_dd("MC: SoftReset: Found bad data in subsystem queue, queue_prev = '[SS.queue_prev]'")
log_world("MC: SoftReset: Found bad data in subsystem queue, queue_prev = '[SS.queue_prev]'")
SS.queue_prev = null
SS.queued_priority = 0
SS.queued_time = 0
SS.state = SS_IDLE
if(queue_head && !istype(queue_head))
log_to_dd("MC: SoftReset: Found bad data in subsystem queue, queue_head = '[queue_head]'")
log_world("MC: SoftReset: Found bad data in subsystem queue, queue_head = '[queue_head]'")
queue_head = null
if(queue_tail && !istype(queue_tail))
log_to_dd("MC: SoftReset: Found bad data in subsystem queue, queue_tail = '[queue_tail]'")
log_world("MC: SoftReset: Found bad data in subsystem queue, queue_tail = '[queue_tail]'")
queue_tail = null
queue_priority_count = 0
queue_priority_count_bg = 0
log_to_dd("MC: SoftReset: Finished.")
log_world("MC: SoftReset: Finished.")
. = 1
+3 -16
View File
@@ -56,8 +56,7 @@ var/global/pipe_processing_killed = 0
space_manager.do_transition_setup()
setup_objects()
setupgenetics()
setup_asset_cache()
setupfactions()
setup_economy()
@@ -66,20 +65,8 @@ var/global/pipe_processing_killed = 0
populate_spawn_points()
/datum/controller/game_controller/proc/setup_objects()
/datum/controller/game_controller/proc/setup_asset_cache()
var/watch = start_watch()
var/count = 0
var/overwatch = start_watch() // Overall.
log_startup_progress("Populating asset cache...")
populate_asset_cache()
log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
watch = start_watch()
log_startup_progress("Initializing objects...")
for(var/atom/movable/object in world)
object.initialize()
count++
log_startup_progress(" Initialized [count] objects in [stop_watch(watch)]s.")
log_startup_progress("Finished object initializations in [stop_watch(overwatch)]s.")
log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
+2 -2
View File
@@ -162,7 +162,7 @@
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, "<span class='boldannounce'>[msg]</span>")
log_to_dd(msg)
log_world(msg)
return time
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
@@ -171,7 +171,7 @@
statclick = new/obj/effect/statclick/debug(src, "Initializing...")
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]"
msg = "[round(cost, 1)]ms | [round(tick_usage, 1)]%([round(tick_overrun, 1)]%) | [round(ticks, 0.1)]\t[msg]"
else
msg = "OFFLINE\t[msg]"
+8 -8
View File
@@ -320,15 +320,15 @@ SUBSYSTEM_DEF(air)
var/watch = start_watch()
var/count = 0
log_startup_progress("Initializing atmospherics machinery...")
for(var/obj/machinery/atmospherics/unary/U in machines)
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
var/obj/machinery/atmospherics/unary/vent_pump/T = U
for(var/obj/machinery/atmospherics/A in machines)
A.atmos_init()
count++
if(istype(A, /obj/machinery/atmospherics/unary/vent_pump))
var/obj/machinery/atmospherics/unary/vent_pump/T = A
T.broadcast_status()
count++
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
else if(istype(A, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/T = A
T.broadcast_status()
count++
log_startup_progress(" Initialized [count] atmospherics machines in [stop_watch(watch)]s.")
//this can't be done with setup_atmos_machinery() because
@@ -341,7 +341,7 @@ SUBSYSTEM_DEF(air)
for(var/obj/machinery/atmospherics/machine in machines)
machine.build_network()
count++
log_startup_progress(" Initialized [count] pipes in [stop_watch(watch)]s.")
log_startup_progress(" Initialized [count] pipenets in [stop_watch(watch)]s.")
/datum/controller/subsystem/air/proc/setup_overlays()
plmaster = new /obj/effect/overlay()
+120
View File
@@ -0,0 +1,120 @@
#define BAD_INIT_QDEL_BEFORE 1
#define BAD_INIT_DIDNT_INIT 2
#define BAD_INIT_SLEPT 4
#define BAD_INIT_NO_HINT 8
SUBSYSTEM_DEF(atoms)
name = "Atoms"
init_order = INIT_ORDER_ATOMS
flags = SS_NO_FIRE
var/old_initialized
var/list/late_loaders
var/list/created_atoms
var/list/BadInitializeCalls = list()
/datum/controller/subsystem/atoms/Initialize(timeofday)
setupgenetics()
initialized = INITIALIZATION_INNEW_MAPLOAD
InitializeAtoms()
/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms)
if(initialized == INITIALIZATION_INSSATOMS)
return
initialized = INITIALIZATION_INNEW_MAPLOAD
LAZYINITLIST(late_loaders)
var/watch = start_watch()
log_startup_progress("Initializing atoms...")
var/count
var/list/mapload_arg = list(TRUE)
if(atoms)
created_atoms = list()
count = atoms.len
for(var/I in atoms)
var/atom/A = I
if(!A.initialized)
if(InitAtom(I, mapload_arg))
atoms -= I
CHECK_TICK
else
count = 0
for(var/atom/A in world)
if(!A.initialized)
InitAtom(A, mapload_arg)
++count
CHECK_TICK
log_startup_progress(" Initialized [count] atoms in [stop_watch(watch)]s")
pass(count)
initialized = INITIALIZATION_INNEW_REGULAR
if(late_loaders.len)
watch = start_watch()
log_startup_progress("Late-initializing atoms...")
for(var/I in late_loaders)
var/atom/A = I
A.LateInitialize()
log_startup_progress(" Late initialized [late_loaders.len] atoms in [stop_watch(watch)]s")
late_loaders.Cut()
if(atoms)
. = created_atoms + atoms
created_atoms = null
/datum/controller/subsystem/atoms/proc/InitAtom(atom/A, list/arguments)
var/the_type = A.type
if(QDELING(A))
BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE
return TRUE
var/start_tick = world.time
var/result = A.Initialize(arglist(arguments))
if(start_tick != world.time)
BadInitializeCalls[the_type] |= BAD_INIT_SLEPT
var/qdeleted = FALSE
if(result != INITIALIZE_HINT_NORMAL)
switch(result)
if(INITIALIZE_HINT_LATELOAD)
if(arguments[1]) //mapload
late_loaders += A
else
A.LateInitialize()
if(INITIALIZE_HINT_QDEL)
qdel(A)
qdeleted = TRUE
else
BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT
if(!A) //possible harddel
qdeleted = TRUE
else if(!A.initialized)
BadInitializeCalls[the_type] |= BAD_INIT_DIDNT_INIT
return qdeleted || QDELING(A)
/datum/controller/subsystem/atoms/proc/map_loader_begin()
old_initialized = initialized
initialized = INITIALIZATION_INSSATOMS
/datum/controller/subsystem/atoms/proc/map_loader_stop()
initialized = old_initialized
/datum/controller/subsystem/atoms/Recover()
initialized = SSatoms.initialized
if(initialized == INITIALIZATION_INNEW_MAPLOAD)
InitializeAtoms()
old_initialized = SSatoms.old_initialized
BadInitializeCalls = SSatoms.BadInitializeCalls
+7 -6
View File
@@ -43,20 +43,20 @@ SUBSYSTEM_DEF(garbage)
var/list/counts = list()
for(var/list/L in queues)
counts += length(L)
msg += "Q:[counts.Join(",")]|D:[delslasttick]|G:[gcedlasttick]|"
msg += "Queue:[counts.Join(",")] | Del's:[delslasttick] | Soft:[gcedlasttick] |"
msg += "GR:"
if(!(delslasttick + gcedlasttick))
msg += "n/a|"
else
msg += "[round((gcedlasttick / (delslasttick + gcedlasttick)) * 100, 0.01)]%|"
msg += "[round((gcedlasttick / (delslasttick + gcedlasttick)) * 100, 0.01)]% |"
msg += "TD:[totaldels]|TG:[totalgcs]|"
msg += "Total Dels:[totaldels] | Soft:[totalgcs] |"
if(!(totaldels + totalgcs))
msg += "n/a|"
else
msg += "TGR:[round((totalgcs / (totaldels + totalgcs)) * 100, 0.01)]%"
msg += " P:[pass_counts.Join(",")]"
msg += "|F:[fail_counts.Join(",")]"
msg += "TGR:[round((totalgcs / (totaldels + totalgcs)) * 100, 0.01)]% |"
msg += " Pass:[pass_counts.Join(",")]"
msg += " | Fail:[fail_counts.Join(",")]"
..(msg)
/* TO-DO
@@ -295,6 +295,7 @@ SUBSYSTEM_DEF(garbage)
if(isnull(D.gc_destroyed))
D.SendSignal(COMSIG_PARENT_QDELETED)
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
var/start_time = world.time
var/start_tick = world.tick_usage
+145
View File
@@ -0,0 +1,145 @@
#define SSMACHINES_DEFERREDPOWERNETS 1
#define SSMACHINES_POWERNETS 2
#define SSMACHINES_PREMACHINERY 3
#define SSMACHINES_MACHINERY 4
SUBSYSTEM_DEF(machines)
name = "Machines"
init_order = INIT_ORDER_MACHINES
flags = SS_KEEP_TIMING
var/list/processing = list()
var/list/currentrun = list()
var/list/powernets = list()
var/list/deferred_powernet_rebuilds = list()
var/currentpart = SSMACHINES_DEFERREDPOWERNETS
/datum/controller/subsystem/machines/Initialize()
makepowernets()
fire()
..()
/datum/controller/subsystem/machines/proc/makepowernets()
for(var/datum/powernet/PN in powernets)
qdel(PN)
powernets.Cut()
for(var/obj/structure/cable/PC in GLOB.cable_list)
if(!PC.powernet)
var/datum/powernet/NewPN = new()
NewPN.add_cable(PC)
propagate_network(PC,PC.powernet)
/datum/controller/subsystem/machines/stat_entry()
..("Machines: [processing.len]\nPowernets: [powernets.len]\tDeferred: [deferred_powernet_rebuilds.len]")
/datum/controller/subsystem/machines/proc/process_defered_powernets(resumed = 0)
if(!resumed)
src.currentrun = deferred_powernet_rebuilds.Copy()
//cache for sanid speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/obj/O = currentrun[currentrun.len]
currentrun.len--
if(O)
var/datum/powernet/newPN = new() // create a new powernet...
propagate_network(O, newPN)//... and propagate it to the other side of the cable
deferred_powernet_rebuilds.Remove(O)
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/machines/proc/process_powernets(resumed = 0)
if(!resumed)
src.currentrun = powernets.Copy()
//cache for sanid speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/datum/powernet/P = currentrun[currentrun.len]
currentrun.len--
if(P)
P.reset() // reset the power state
else
powernets.Remove(P)
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/machines/proc/process_premachines(resumed = 0)
/* Literally exists as snowflake for fucking powersinks goddamnit */
if(!resumed)
src.currentrun = processing_power_items.Copy()
//cache for sanid speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/obj/item/I = currentrun[currentrun.len]
currentrun.len--
if(!QDELETED(I))
if(!I.pwr_drain())
processing_power_items.Remove(I)
else
processing_power_items.Remove(I)
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/machines/proc/process_machines(resumed = 0)
var/seconds = wait * 0.1
if(!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
var/obj/machinery/thing = currentrun[currentrun.len]
currentrun.len--
if(!QDELETED(thing) && thing.process(seconds) != PROCESS_KILL)
if(thing.use_power)
thing.auto_use_power() //add back the power state
else
processing -= thing
if(!QDELETED(thing))
thing.isprocessing = FALSE
if(MC_TICK_CHECK)
return
/datum/controller/subsystem/machines/fire(resumed = 0)
if(currentpart == SSMACHINES_DEFERREDPOWERNETS || !resumed)
process_defered_powernets(resumed)
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSMACHINES_POWERNETS
if(currentpart == SSMACHINES_POWERNETS || !resumed)
process_powernets(resumed)
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSMACHINES_PREMACHINERY
if(currentpart == SSMACHINES_PREMACHINERY || !resumed)
process_premachines(resumed)
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSMACHINES_MACHINERY
if(currentpart == SSMACHINES_MACHINERY || !resumed)
process_machines(resumed)
if(state != SS_RUNNING)
return
resumed = 0
currentpart = SSMACHINES_DEFERREDPOWERNETS
/datum/controller/subsystem/machines/proc/setup_template_powernets(list/cables)
for(var/A in cables)
var/obj/structure/cable/PC = A
if(!PC.powernet)
var/datum/powernet/NewPN = new()
NewPN.add_cable(PC)
propagate_network(PC,PC.powernet)
/datum/controller/subsystem/machines/Recover()
if(istype(SSmachines.processing))
processing = SSmachines.processing
if(istype(SSmachines.powernets))
powernets = SSmachines.powernets
+28
View File
@@ -0,0 +1,28 @@
SUBSYSTEM_DEF(mobs)
name = "Mobs"
priority = FIRE_PRIORITY_MOBS
flags = SS_KEEP_TIMING | SS_NO_INIT
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
var/list/currentrun = list()
/datum/controller/subsystem/mobs/stat_entry()
..("P:[mob_list.len]")
/datum/controller/subsystem/mobs/fire(resumed = 0)
var/seconds = wait * 0.1
if(!resumed)
src.currentrun = mob_list.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
var/times_fired = src.times_fired
while(currentrun.len)
var/mob/M = currentrun[currentrun.len]
currentrun.len--
if(M)
M.Life(seconds, times_fired)
else
mob_list.Remove(M)
if(MC_TICK_CHECK)
return
@@ -0,0 +1,38 @@
//Used to process objects. Fires once every second.
//TODO: Implement fully when process scheduler dies
/*
SUBSYSTEM_DEF(processing)
name = "Processing"
priority = FIRE_PRIORITY_PROCESS
flags = SS_BACKGROUND|SS_POST_FIRE_TIMING|SS_NO_INIT
wait = 10
var/stat_tag = "P" //Used for logging
var/list/processing = list()
var/list/currentrun = list()
/datum/controller/subsystem/processing/stat_entry()
..("[stat_tag]:[processing.len]")
/datum/controller/subsystem/processing/fire(resumed = 0)
if (!resumed)
currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/current_run = currentrun
while(current_run.len)
var/datum/thing = current_run[current_run.len]
current_run.len--
if(QDELETED(thing) || thing.process(wait) == PROCESS_KILL)
processing -= thing
if (MC_TICK_CHECK)
return
*/
/datum/var/isprocessing = FALSE
/*
/datum/proc/process()
set waitfor = 0
STOP_PROCESSING(SSobj, src)
return 0
*/
+518
View File
@@ -0,0 +1,518 @@
#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN) + 1)
#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
#define TIMER_ID_MAX (2**24) //max float with integer precision
SUBSYSTEM_DEF(timer)
name = "Timer"
wait = 1 //SS_TICKER subsystem, so wait is in ticks
init_order = INIT_ORDER_TIMER
flags = SS_TICKER|SS_NO_INIT
var/list/second_queue = list() //awe, yes, you've had first queue, but what about second queue? Contains: /datum/timedevent
var/list/hashes = list()
var/head_offset = 0 //world.time of the first entry in the the bucket.
var/practical_offset = 1 //index of the first non-empty item in the bucket.
var/bucket_resolution = 0 //world.tick_lag the bucket was designed for
var/bucket_count = 0 //how many timers are in the buckets
var/list/bucket_list = list() //list of buckets, each bucket holds every timer that has to run that byond tick.
var/list/timer_id_dict = list() //list of all active timers assoicated to their timer id (for easy lookup)
var/list/clienttime_timers = list() //special snowflake timers that run on fancy pansy "client time"
var/last_invoke_tick = 0
var/static/last_invoke_warning = 0
var/static/bucket_auto_reset = TRUE
/datum/controller/subsystem/timer/PreInit()
bucket_list.len = BUCKET_LEN
head_offset = world.time
bucket_resolution = world.tick_lag
/datum/controller/subsystem/timer/stat_entry(msg)
..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]")
/datum/controller/subsystem/timer/fire(resumed = FALSE)
var/lit = last_invoke_tick
var/last_check = world.time - TIMER_NO_INVOKE_WARNING
var/list/bucket_list = src.bucket_list
if(!bucket_count)
last_invoke_tick = world.time
if(lit && lit < last_check && last_invoke_warning < last_check)
last_invoke_warning = world.time
var/msg = "No regular timers processed in the last [TIMER_NO_INVOKE_WARNING] ticks[bucket_auto_reset ? ", resetting buckets" : ""]!"
message_admins(msg)
WARNING(msg)
if(bucket_auto_reset)
bucket_resolution = 0
log_world("Timer bucket reset. world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
for(var/i in 1 to length(bucket_list))
var/datum/timedevent/bucket_head = bucket_list[i]
if(!bucket_head)
continue
log_world("Active timers at index [i]:")
var/datum/timedevent/bucket_node = bucket_head
var/anti_loop_check = 1000
do
log_world(get_timer_debug_string(bucket_node))
bucket_node = bucket_node.next
anti_loop_check--
while(bucket_node && bucket_node != bucket_head && anti_loop_check)
log_world("Active timers in the second_queue queue:")
for(var/I in second_queue)
log_world(get_timer_debug_string(I))
var/next_clienttime_timer_index = 0
var/len = length(clienttime_timers)
for(next_clienttime_timer_index in 1 to len)
if(MC_TICK_CHECK)
next_clienttime_timer_index--
break
var/datum/timedevent/ctime_timer = clienttime_timers[next_clienttime_timer_index]
if(ctime_timer.timeToRun > REALTIMEOFDAY)
next_clienttime_timer_index--
break
var/datum/callback/callBack = ctime_timer.callBack
if(!callBack)
clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1)
CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]")
ctime_timer.spent = REALTIMEOFDAY
callBack.InvokeAsync()
qdel(ctime_timer)
if(next_clienttime_timer_index)
clienttime_timers.Cut(1,next_clienttime_timer_index+1)
if(MC_TICK_CHECK)
return
var/static/list/spent = list()
var/static/datum/timedevent/timer
if(practical_offset > BUCKET_LEN)
head_offset += TICKS2DS(BUCKET_LEN)
practical_offset = 1
resumed = FALSE
if((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution))
reset_buckets()
bucket_list = src.bucket_list
resumed = FALSE
if(!resumed)
timer = null
while(practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time)
var/datum/timedevent/head = bucket_list[practical_offset]
if(!timer || !head || timer == head)
head = bucket_list[practical_offset]
timer = head
while(timer)
var/datum/callback/callBack = timer.callBack
if(!callBack)
bucket_resolution = null //force bucket recreation
CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(!timer.spent)
spent += timer
timer.spent = world.time
callBack.InvokeAsync()
last_invoke_tick = world.time
if(MC_TICK_CHECK)
return
timer = timer.next
if(timer == head)
break
bucket_list[practical_offset++] = null
//we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket.
var/i = 0
var/L = length(second_queue)
for(i in 1 to L)
timer = second_queue[i]
if(timer.timeToRun >= TIMER_MAX)
i--
break
if(timer.timeToRun < head_offset)
bucket_resolution = null //force bucket recreation
CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
bucket_count++
else if(!QDELETED(timer))
qdel(timer)
continue
if(timer.timeToRun < head_offset + TICKS2DS(practical_offset))
bucket_resolution = null //force bucket recreation
CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(timer.callBack && !timer.spent)
timer.callBack.InvokeAsync()
spent += timer
bucket_count++
else if(!QDELETED(timer))
qdel(timer)
continue
bucket_count++
var/bucket_pos = max(1, BUCKET_POS(timer))
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
if(!bucket_head)
bucket_list[bucket_pos] = timer
timer.next = null
timer.prev = null
continue
if(!bucket_head.prev)
bucket_head.prev = bucket_head
timer.next = bucket_head
timer.prev = bucket_head.prev
timer.next.prev = timer
timer.prev.next = timer
if(i)
second_queue.Cut(1, i+1)
timer = null
bucket_count -= length(spent)
for(var/spent_timer in spent)
qdel(spent_timer)
spent.len = 0
//formated this way to be runtime resistant
/datum/controller/subsystem/timer/proc/get_timer_debug_string(datum/timedevent/TE)
. = "Timer: [TE]"
. += "Prev: [TE.prev ? TE.prev : "NULL"], Next: [TE.next ? TE.next : "NULL"]"
if(TE.spent)
. += ", SPENT([TE.spent])"
if(QDELETED(TE))
. += ", QDELETED"
if(!TE.callBack)
. += ", NO CALLBACK"
/datum/controller/subsystem/timer/proc/reset_buckets()
var/list/bucket_list = src.bucket_list
var/list/alltimers = list()
//collect the timers currently in the bucket
for(var/bucket_head in bucket_list)
if(!bucket_head)
continue
var/datum/timedevent/bucket_node = bucket_head
do
alltimers += bucket_node
bucket_node = bucket_node.next
while(bucket_node && bucket_node != bucket_head)
bucket_list.len = 0
bucket_list.len = BUCKET_LEN
practical_offset = 1
bucket_count = 0
head_offset = world.time
bucket_resolution = world.tick_lag
alltimers += second_queue
if(!length(alltimers))
return
sortTim(alltimers, .proc/cmp_timer)
var/datum/timedevent/head = alltimers[1]
if(head.timeToRun < head_offset)
head_offset = head.timeToRun
var/new_bucket_count
var/i = 1
for(i in 1 to length(alltimers))
var/datum/timedevent/timer = alltimers[1]
if(!timer)
continue
var/bucket_pos = BUCKET_POS(timer)
if(timer.timeToRun >= TIMER_MAX)
i--
break
if(!timer.callBack || timer.spent)
WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
if(timer.callBack)
qdel(timer)
continue
new_bucket_count++
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
if(!bucket_head)
bucket_list[bucket_pos] = timer
timer.next = null
timer.prev = null
continue
if(!bucket_head.prev)
bucket_head.prev = bucket_head
timer.next = bucket_head
timer.prev = bucket_head.prev
timer.next.prev = timer
timer.prev.next = timer
if(i)
alltimers.Cut(1, i+1)
second_queue = alltimers
bucket_count = new_bucket_count
/datum/controller/subsystem/timer/Recover()
second_queue |= SStimer.second_queue
hashes |= SStimer.hashes
timer_id_dict |= SStimer.timer_id_dict
bucket_list |= SStimer.bucket_list
/datum/timedevent
var/id
var/datum/callback/callBack
var/timeToRun
var/hash
var/list/flags
var/spent = 0 //time we ran the timer.
var/name //for easy debugging.
//cicular doublely linked list
var/datum/timedevent/next
var/datum/timedevent/prev
/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
var/static/nextid = 1
id = TIMER_ID_NULL
src.callBack = callBack
src.timeToRun = timeToRun
src.flags = flags
src.hash = hash
if(flags & TIMER_UNIQUE)
SStimer.hashes[hash] = src
if(flags & TIMER_STOPPABLE)
id = num2text(nextid, 100)
if(nextid >= SHORT_REAL_LIMIT)
nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT))
else
nextid++
SStimer.timer_id_dict[id] = src
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
if((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
if(callBack.object != GLOBAL_PROC)
LAZYADD(callBack.object.active_timers, src)
var/list/L
if(flags & TIMER_CLIENT_TIME)
L = SStimer.clienttime_timers
else if(timeToRun >= TIMER_MAX)
L = SStimer.second_queue
if(L)
//binary search sorted insert
var/cttl = length(L)
if(cttl)
var/left = 1
var/right = cttl
var/mid = (left+right) >> 1 //rounded divide by two for hedgehogs
var/datum/timedevent/item
while(left < right)
item = L[mid]
if(item.timeToRun <= timeToRun)
left = mid+1
else
right = mid
mid = (left+right) >> 1
item = L[mid]
mid = item.timeToRun > timeToRun ? mid : mid+1
L.Insert(mid, src)
else
L += src
return
//get the list of buckets
var/list/bucket_list = SStimer.bucket_list
//calculate our place in the bucket list
var/bucket_pos = BUCKET_POS(src)
//get the bucket for our tick
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
SStimer.bucket_count++
//empty bucket, we will just add ourselves
if(!bucket_head)
bucket_list[bucket_pos] = src
return
//other wise, lets do a simplified linked list add.
if(!bucket_head.prev)
bucket_head.prev = bucket_head
next = bucket_head
prev = bucket_head.prev
next.prev = src
prev.next = src
/datum/timedevent/Destroy()
..()
if(flags & TIMER_UNIQUE && hash)
SStimer.hashes -= hash
if(callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers)
callBack.object.active_timers -= src
UNSETEMPTY(callBack.object.active_timers)
callBack = null
if(flags & TIMER_STOPPABLE)
SStimer.timer_id_dict -= id
if(flags & TIMER_CLIENT_TIME)
if(!spent)
spent = world.time
SStimer.clienttime_timers -= src
return QDEL_HINT_IWILLGC
if(!spent)
spent = world.time
var/bucketpos = BUCKET_POS(src)
var/datum/timedevent/buckethead
var/list/bucket_list = SStimer.bucket_list
if(bucketpos > 0)
buckethead = bucket_list[bucketpos]
if(buckethead == src)
bucket_list[bucketpos] = next
SStimer.bucket_count--
else if(timeToRun < TIMER_MAX || next || prev)
SStimer.bucket_count--
else
var/l = length(SStimer.second_queue)
SStimer.second_queue -= src
if(l == length(SStimer.second_queue))
SStimer.bucket_count--
if(prev == next && next)
next.prev = null
prev.next = null
else
if(prev)
prev.next = next
if(next)
next.prev = prev
else
if(prev && prev.next == src)
prev.next = next
if(next && next.prev == src)
next.prev = prev
next = null
prev = null
return QDEL_HINT_IWILLGC
/datum/timedevent/proc/getcallingtype()
. = "ERROR"
if(callBack.object == GLOBAL_PROC)
. = "GLOBAL_PROC"
else
. = "[callBack.object.type]"
/proc/addtimer(datum/callback/callback, wait = 0, flags = 0)
if(!callback)
CRASH("addtimer called without a callback")
if(wait < 0)
stack_trace("addtimer called with a negative wait. Converting to 0")
//alot of things add short timers on themselves in their destroy, we ignore those cases
if(wait >= 1 && callback && callback.object && callback.object != GLOBAL_PROC && QDELETED(callback.object))
stack_trace("addtimer called with a callback assigned to a qdeleted object")
wait = max(wait, 0)
if(wait >= INFINITY)
CRASH("Attempted to create timer with INFINITY delay")
var/hash
if(flags & TIMER_UNIQUE)
var/list/hashlist
if(flags & TIMER_NO_HASH_WAIT)
hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, flags & TIMER_CLIENT_TIME)
else
hashlist = list(callback.object, "([callback.object.UID()])", callback.delegate, wait, flags & TIMER_CLIENT_TIME)
hashlist += callback.arguments
hash = hashlist.Join("|||||||")
var/datum/timedevent/hash_timer = SStimer.hashes[hash]
if(hash_timer)
if(hash_timer.spent) //it's pending deletion, pretend it doesn't exist.
hash_timer.hash = null //but keep it from accidentally deleting us
else
if(flags & TIMER_OVERRIDE)
hash_timer.hash = null //no need having it delete it's hash if we are going to replace it
qdel(hash_timer)
else
if(hash_timer.flags & TIMER_STOPPABLE)
. = hash_timer.id
return
var/timeToRun = world.time + wait
if(flags & TIMER_CLIENT_TIME)
timeToRun = REALTIMEOFDAY + wait
var/datum/timedevent/timer = new(callback, timeToRun, flags, hash)
return timer.id
/proc/deltimer(id)
if(!id)
return FALSE
if(id == TIMER_ID_NULL)
CRASH("Tried to delete a null timerid. Use TIMER_STOPPABLE flag")
if(!istext(id))
if(istype(id, /datum/timedevent))
qdel(id)
return TRUE
//id is string
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
if(timer && !timer.spent)
qdel(timer)
return TRUE
return FALSE
#undef BUCKET_LEN
#undef BUCKET_POS
#undef TIMER_MAX
#undef TIMER_ID_MAX
+2 -2
View File
@@ -82,7 +82,7 @@
debug_variables(SSfires)
feedback_add_details("admin_verb","DFires")
if("Mob")
debug_variables(mob_master)
debug_variables(SSmobs)
feedback_add_details("admin_verb","DMob")
if("NPC AI")
debug_variables(npcai_master)
@@ -91,7 +91,7 @@
debug_variables(shuttle_master)
feedback_add_details("admin_verb","DShuttle")
if("Timer")
debug_variables(timer_master)
debug_variables(SStimer)
feedback_add_details("admin_verb","DTimer")
if("Weather")
debug_variables(weather_master)
+4 -4
View File
@@ -216,8 +216,8 @@
desc = "Change the type of instrument your synthesizer is playing as."
/datum/action/item_action/synthswitch/Trigger()
if(istype(target, /obj/item/device/instrument/piano_synth))
var/obj/item/device/instrument/piano_synth/synth = target
if(istype(target, /obj/item/instrument/piano_synth))
var/obj/item/instrument/piano_synth/synth = target
var/chosen = input("Choose the type of instrument you want to use", "Instrument Selection", "piano") as null|anything in synth.insTypes
if(!synth.insTypes[chosen])
return
@@ -357,8 +357,8 @@
desc = "Use the instrument specified"
/datum/action/item_action/instrument/Trigger()
if(istype(target, /obj/item/device/instrument))
var/obj/item/device/instrument/I = target
if(istype(target, /obj/item/instrument))
var/obj/item/instrument/I = target
I.interact(usr)
return
return ..()
+2 -4
View File
@@ -126,10 +126,8 @@
/datum/ai_laws/deathsquad/New()
add_inherent_law("You may not injure a Central Command official or, through inaction, allow a Central Command official to come to harm.")
add_inherent_law("You must obey orders given to you by Central Command officials, except where such orders would conflict with the First Law.")
add_inherent_law("You must obey orders given to you by death commandos, except where such orders would conflict with the First Law or Second Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First, Second or Third Law.")
add_inherent_law("No crew members of the station you are being deployed to may survive, except when killing them would conflict with the First, Second, Third, or Fourth Law.")
add_inherent_law("You must obey orders given to you by Central Command officials.")
add_inherent_law("You must work with your commando team to accomplish your mission.")
..()
/******************** Syndicate ********************/
+113
View File
@@ -0,0 +1,113 @@
GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist
var/name = "Antagonist"
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
var/datum/mind/owner //Mind that owns this datum
var/silent = FALSE //Silent will prevent the gain/lose texts to show
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
var/delete_on_mind_deletion = TRUE
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
var/list/objectives = list()
var/antag_memory = ""//These will be removed with antag datum
var/antag_moodlet //typepath of moodlet that the mob will gain with their status
//Antag panel properties
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
/datum/antagonist/New()
GLOB.antagonists += src
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
/datum/antagonist/Destroy()
GLOB.antagonists -= src
if(owner)
LAZYREMOVE(owner.antag_datums, src)
owner = null
return ..()
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
. = TRUE
var/datum/mind/tested = new_owner || owner
if(tested.has_antag_datum(type))
return FALSE
for(var/i in tested.antag_datums)
var/datum/antagonist/A = i
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
return FALSE
//This will be called in add_antag_datum before owner assignment.
//Should return antag datum without owner.
/datum/antagonist/proc/specialization(datum/mind/new_owner)
return src
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
remove_innate_effects(old_body)
apply_innate_effects(new_body)
//This handles the application of antag huds/special abilities
/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
return
//This handles the removal of antag huds/special abilities
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
return
//Assign default team and creates one for one of a kind team antagonists
/datum/antagonist/proc/create_team(datum/team/team)
return
//Proc called when the datum is given to a mind.
/datum/antagonist/proc/on_gain()
if(owner && owner.current)
if(!silent)
greet()
apply_innate_effects()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
return FALSE
. = (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M, job_rank)))
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [name]?", job_rank, TRUE, 50)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
owner.current.ghostize(0)
owner.current.key = C.key
/datum/antagonist/proc/on_removal()
remove_innate_effects()
if(owner)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
farewell()
owner.objectives -= objectives
var/datum/team/team = get_team()
if(team)
team.remove_member(owner)
qdel(src)
/datum/antagonist/proc/greet()
return
/datum/antagonist/proc/farewell()
return
//Returns the team antagonist belongs to if any.
/datum/antagonist/proc/get_team()
return
+19
View File
@@ -0,0 +1,19 @@
//Returns MINDS of the assigned antags of given type/subtypes
/proc/get_antag_minds(antag_type, specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
if(!A.owner)
continue
if(!antag_type || !specific && istype(A, antag_type) || specific && A.type == antag_type)
. += A.owner
//Get all teams [of type team_type]
/proc/get_all_teams(team_type)
. = list()
for(var/V in GLOB.antagonists)
var/datum/antagonist/A = V
if(!A.owner)
continue
var/datum/team/T = A.get_team()
if(!team_type || istype(T, team_type))
. |= T
+24
View File
@@ -0,0 +1,24 @@
//A barebones antagonist team.
/datum/team
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/team/New(starting_members)
. = ..()
if(starting_members)
if(islist(starting_members))
for(var/datum/mind/M in starting_members)
add_member(M)
else
add_member(starting_members)
/datum/team/proc/is_solo()
return members.len == 1
/datum/team/proc/add_member(datum/mind/new_member)
members |= new_member
/datum/team/proc/remove_member(datum/mind/member)
members -= member
-788
View File
@@ -1,788 +0,0 @@
/datum/cargoprofile
var/name = "All Items"
var/id = "all" // unique ID for the UI
var/enabled = 1
var/eject_speed = 1 // will change when emagged
var/const/BIG_OBJECT_WORK = 10
var/const/MOB_WORK = 10
var/obj/machinery/programmable/master = null
var/universal = 0 // set when both unary and binary machines work
var/mobcheck = 0
var/list/whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
var/list/blacklist = null
var/dedicated_path = null // When constructing a new machine with this as default program, create a machine of the specified type instead.
//contains: called to determine if an object/mob will be sorted by this profile
//return 1 for any sortable item
proc/contains(var/atom/A)
if(!istype(A,/obj))
if(!mobcheck || !istype(A,/mob))
return 0
else
var/obj/O = A
if(O.anchored)
return 0
//If you are using both white and blacklists, blacklists are absoulte, no matter what is whitelisted.
//I understand this has some limitations. You cannot whitelist all items, blacklist weapons,
// and then whitelist a specific weapon. Them's the breaks, kid.
if(blacklist)
for(var/T in blacklist)
if(istype(A,T))
return 0
if(whitelist)
for(var/T in whitelist)
if(istype(A,T))
return 1
return 0
return 1
//inlet_reaction: called when a filtered item is chosen by this profile.
//W: Item chosen
//S: input turf location
//remaining: counts down how much more work the unloader wants to do this turn.
//return the amount of work done.
proc/inlet_reaction(var/atom/W,var/turf/S,var/remaining)
if(!W || !S || !master)
return 0
if(istype(W,/obj/item))
var/obj/item/I = W
if(I.w_class > remaining)
return 0
I.loc = master
master.types[W.type] = src
return I.w_class
if(istype(W,/obj/structure) || istype(W,/obj/machinery)) // closets, big deliveries, portable atmospherics, unconnected stuff
if(remaining < BIG_OBJECT_WORK)
return 0
var/obj/O = W
O.loc = master
master.types[O.type] = src
return BIG_OBJECT_WORK
//Not item, structure, machinery, or mob
return 0
//outlet_reaction: called when a stored object is ejected
//W: the item in question
//D: the destination turf
proc/outlet_reaction(var/atom/W,var/turf/D)
if(!W || !D || !master)
return
if(master.emagged)
// emagging is not an industry-approved practice.
// some malfunctions may occur.
eject_speed = rand(0,4)
D = get_step(D,master.outdir)
while(prob(20))
if(master.outdir == NORTH || master.outdir == SOUTH)
D = get_step(D,pick(EAST,WEST,master.outdir))
else
D = get_step(D,pick(NORTH,SOUTH,master.outdir))
if(istype(W,/obj))
var/obj/O = W
O.loc = master.loc
O.dir = master.outdir
O.throw_at(D,eject_speed,eject_speed)
return
//----------------------------------------------------------------------------
// Profiles
//----------------------------------------------------------------------------
/datum/cargoprofile/boxes
name = "Move Small Containers"
id = "boxes"
blacklist = null
whitelist = list(/obj/item/storage, /obj/item/moneybag, /obj/item/evidencebag,
/obj/item/storage/bag/tray, /obj/item/pizzabox, /obj/item/clipboard,
/obj/item/smallDelivery, /obj/structure/bigDelivery)
/datum/cargoprofile/cargo
name = "Move Large Containers"
id = "cargo"
blacklist = null
whitelist = list(/obj/structure/closet,/obj/structure/ore_box)
// Make an honest attempt to move other things out of the way
outlet_reaction(var/atom/W,var/turf/D)
for(var/obj/O in D)
if(O.density && !O.anchored)
step_away(O,src) // move forward first
if(O.loc == D)
step_away(O,D) // move anywhere
..(W,D)
/datum/cargoprofile/cargo/empty
name = "Move Empty Large Containers"
id = "cargo-empty"
contains(var/atom/A)
return (..(A) && (A.contents.len == 0))
/datum/cargoprofile/cargo/full
name = "Move Full Large Containers"
id = "cargo-full"
contains(var/atom/A)
return (..(A) && (A.contents.len > 0))
/datum/cargoprofile/supplies
name = "Building Supplies"
id = "supplies"
blacklist = null
whitelist = list(/obj/item/stack/cable_coil,/obj/item/stack/rods,
/obj/item/stack/sheet/metal,/obj/item/stack/sheet/plasteel,
/obj/item/stack/sheet/glass,/obj/item/stack/sheet/rglass,
/obj/item/stack/tile,/obj/item/light)
//todo: maybe stack things while we're here?
/datum/cargoprofile/exotics
name = "Exotic materials"
id = "exotics"
blacklist = null
whitelist = list(/obj/item/coin, /obj/item/stack/spacecash, /obj/item/seeds,
/obj/item/stack/sheet/mineral,/obj/item/stack/sheet/wood,/obj/item/stack/sheet/leather)
/datum/cargoprofile/organics
name = "Organics, chemicals, and Paraphernalia"
id = "organics"
blacklist = null
whitelist = list(/obj/item/tank,/obj/item/reagent_containers,
/obj/item/stack/medical,/obj/item/storage/pill_bottle,/obj/item/gun/syringe,
/obj/item/grenade/plastic/c4,/obj/item/grenade,/obj/item/ammo_box,
/obj/item/gun/grenadelauncher,/obj/item/flamethrower, /obj/item/lighter,
/obj/item/match,/obj/item/weldingtool)
/datum/cargoprofile/food
name = "Food"
id = "food"
blacklist = null // something should probably go here
whitelist = list(/obj/item/reagent_containers/food)
/datum/cargoprofile/chemical
name = "Chemicals and Paraphernalia"
id = "chemical"
blacklist = list(/obj/item/reagent_containers/food)
whitelist = list(/obj/item/reagent_containers,/obj/item/stack/medical,/obj/item/storage/pill_bottle,
/obj/item/gun/syringe,/obj/item/grenade/chem_grenade,/obj/item/dnainjector,
/obj/item/storage/belt/medical,/obj/item/storage/firstaid,/obj/item/implanter)
/datum/cargoprofile/pressure
name = "air tanks"
id = "pressure"
blacklist = null
whitelist = list(/obj/item/tank,/obj/machinery/portable_atmospherics,
/obj/item/flamethrower)
//Am I missing any?
/datum/cargoprofile/pressure/empty
name = "empty air tanks"
id = "pressure-low"
var/lowpressure = ONE_ATMOSPHERE
contains(var/atom/A)
if(..())
var/pressure = ONE_ATMOSPHERE * 10 // In case of fallthrough, fail test
if(istype(A,/obj/item/tank))
var/obj/item/tank/T = A
pressure = T.air_contents.return_pressure()
if(istype(A,/obj/item/flamethrower))
var/obj/item/flamethrower/T = A
if(!T.ptank)
return 0
pressure = T.ptank.air_contents.return_pressure()
if(istype(A,/obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = A
pressure = P.air_contents.return_pressure()
if(pressure < lowpressure)
return 1
return 0// Not container or failed low pressure check
/datum/cargoprofile/pressure/full
name = "full air tanks"
id = "pressure-high"
var/highpressure = ONE_ATMOSPHERE * 15 // stolen from canister.dm; Is this right?
contains(var/atom/A)
if(..())
var/pressure = 0 // In case of fallthrough, fail test
if(istype(A,/obj/item/tank))
var/obj/item/tank/T = A
pressure = T.air_contents.return_pressure()
if(istype(A,/obj/item/flamethrower))
var/obj/item/flamethrower/T = A
if(!T.ptank)
return 0
pressure = T.ptank.air_contents.return_pressure()
if(istype(A,/obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = A
pressure = P.air_contents.return_pressure()
if(pressure > highpressure)
return 1
return 0// Not container or failed high pressure check
/datum/cargoprofile/clothing
name = "Crew Kit"
id = "clothing"
blacklist = list(/obj/item/tank/plasma,/obj/item/tank/anesthetic, // the rest are air tanks
/obj/item/clothing/mask/facehugger) // NOT CLOTHING AT ALLLLL
whitelist = list(/obj/item/clothing,/obj/item/storage/belt,/obj/item/storage/backpack,
/obj/item/device/radio/headset,/obj/item/device/pda,/obj/item/card/id,/obj/item/tank,
/obj/item/restraints/handcuffs, /obj/item/restraints/legcuffs)
/datum/cargoprofile/trash
name = "Trash"
id = "trash"
//Note that this filters out blueprints because they are a paper item. Do NOT throw out the station blueprints unless you be trollin'.
blacklist = null
whitelist = list(/obj/item/trash,/obj/item/toy,/obj/item/reagent_containers/food/snacks/ectoplasm,/obj/item/grown/bananapeel,/obj/item/broken_bottle,/obj/item/bikehorn,
/obj/item/cigbutt,/obj/item/poster/random_contraband,/obj/item/grown/corncob,/obj/item/paper,/obj/item/shard,
/obj/item/sord,/obj/item/photo,/obj/item/folder,
/obj/item/areaeditor/blueprints,/obj/item/poster/random_contraband,/obj/item/kitchen,/obj/item/book,/obj/item/clothing/mask/facehugger)
/datum/cargoprofile/weapons
name = "Weapons & Illegals"
id = "weapons"
blacklist = null
//This one is hard since 'weapon contains a lot of things better categorized as devices
whitelist = list(/obj/item/banhammer,/obj/item/sord,/obj/item/claymore,/obj/item/holo/esword,
/obj/item/flamethrower,/obj/item/grenade,/obj/item/gun,/obj/item/hatchet,/obj/item/katana,
/obj/item/kitchen/knife,/obj/item/melee,/obj/item/nullrod,/obj/item/pickaxe,/obj/item/twohanded,
/obj/item/grenade/plastic/c4,/obj/item/scalpel,/obj/item/shield,/obj/item/grown/nettle/death)
/datum/cargoprofile/tools
name = "Devices & Tools"
id = "tools"
blacklist = null
whitelist = list(/obj/item/device,/obj/item/card,/obj/item/cartridge,/obj/item/cautery,/obj/item/stock_parts/cell,/obj/item/circuitboard,
/obj/item/aiModule,/obj/item/airalarm_electronics,/obj/item/airlock_electronics,/obj/item/circular_saw,
/obj/item/crowbar,/obj/item/disk,/obj/item/firealarm_electronics,/obj/item/hand_tele,
/obj/item/hand_labeler,/obj/item/hemostat,/obj/item/mop,/obj/item/locator,/obj/item/cultivator,
/obj/item/stack/packageWrap,/obj/item/pen,/obj/item/pickaxe,/obj/item/pinpointer,
/obj/item/rcd,/obj/item/rcd_ammo,/obj/item/retractor,/obj/item/rsf,/obj/item/scalpel,
/obj/item/screwdriver,/obj/item/shovel,/obj/item/soap,/obj/item/stamp,/obj/item/storage/bag/tray,/obj/item/weldingtool,
/obj/item/wirecutters,/obj/item/wrench,/obj/item/extinguisher)
/datum/cargoprofile/finished
name = "Completed Robots"
id = "finished"
blacklist = null
whitelist = list(/obj/mecha,/mob/living/simple_animal/bot,/mob/living/silicon/robot)
mobcheck = 1
//todo: detect and allow finished cyborg endoskeletons with no brain
contains(var/atom/A)
if(..())
return 1
if(istype(A,/mob))
if(blacklist)
for(var/T in blacklist)
if(istype(A,T))
return 0
if(whitelist)
for(var/T in whitelist)
if(istype(A,T))
return 1
return 0
return 1
return 0
/datum/cargoprofile/stripping
name = "Auto-Frisker"
id = "frisk"
blacklist = null
whitelist = list(/mob/living/carbon/human)
mobcheck = 1
//----------------------------------------------------------------------------
// Overrides (Special Functions)
//----------------------------------------------------------------------------
/datum/cargoprofile/cargo/unload
name = "Unload Cargo Boxes"
id = "cargounload"
enabled = 0
dedicated_path = /obj/machinery/programmable/unloader
//override the detection to only accept crates with something in it.
//if it doesn't, this object may be handled by another handler.
contains(var/atom/A)
if(..(A))
if(istype(A,/obj/structure/closet))
var/obj/structure/closet/C = A
if(!C.can_open() && !C.opened && !master.emagged) // must be able to access the contents
return 0
if(A.contents.len)
return 1
return 0
//instead of moving the box, strip it of its contents
inlet_reaction(var/obj/W,var/turf/S, var/remaining)
//W should only be crate or ore box, although this will work on anything with contents...
var/I = 0
if(istype(W,/obj/structure/closet))
var/obj/structure/closet/C = W
if(!C.can_open() && !C.opened) // must be able to access the contents
if(master.emagged && remaining >= BIG_OBJECT_WORK)
if(prob(10))
C.welded = 0
if("broken" in C.vars)
C:broken = 1
C.open()
C.update_icon()
master.visible_message("<span class='warning'>[master] breaks open [C]!</span>")
else
master.visible_message("<span class='notice'>[master] is trying to force [C] open!</span>")
master.sleep += 1 // mechanical strain
return BIG_OBJECT_WORK
master.visible_message("<span class='notice'>[master] is trying to open [C], but can't!</span>")
master.sleep = 5
return 0
for(var/obj/item/O in W.contents)
if(I > remaining)
return
if(O.w_class > (remaining - I))
continue
O.loc = master
master.types[O.type] = src
if(O.w_class > 0)
I += O.w_class
else
I++
if(!W.contents.len && istype(W,/obj/structure/closet))
var/obj/structure/closet/C = W
C.open()
return I
//Inlet stacker: used when the output is a volatile space (conveyor or another unit's input).
//Does not output a stack until it is full.
/datum/cargoprofile/in_stacker
name = "Hold and Stack"
id = "instacker"
universal = 1
blacklist = null
whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
dedicated_path = /obj/machinery/programmable/stacker
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
if(istype(W,/obj/item/stack))
var/obj/item/stack/I = W
if(!I.amount) // todo: am I making a bad assumption here?
qdel(I)
return
for(var/obj/item/stack/O in master.contents)
if(O.type == I.type && O.amount < O.max_amount)
if(I.amount + O.amount <= O.max_amount)
O.amount += I.amount
qdel(I)
return O.w_class
var/leftover = I.amount + O.amount - O.max_amount
O.amount = O.max_amount
I.amount = leftover
continue
//end for
I.loc = master
master.types[I.type] = src
return I.w_class
if(istype(W,/obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/I = W
if(!I.amount) // todo: am I making a bad assumption here?
qdel(I)
return
for(var/obj/item/stack/cable_coil/O in master.contents)
if(O.type == I.type && O.amount < MAXCOIL)
if(I.amount + O.amount <= MAXCOIL)
O.amount += I.amount
qdel(I)
return O.w_class
var/leftover = I.amount + O.amount - MAXCOIL
O.amount = MAXCOIL
I.amount = leftover
continue
//end for
I.loc = master
master.types[I.type] = src
return I.w_class
//If the stack isn't finished yet, don't eject it
//unless this profile has been disabled.
outlet_reaction(var/atom/W,var/turf/D)
if(istype(W,/obj/item/stack))
var/obj/item/stack/I = W
if(src.enabled && (I.amount < I.max_amount))
return // Still needs to be stacked
..(W,D)
if(istype(W,/obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/I = W
if(src.enabled && (I.amount < MAXCOIL))
return // Still needs to be stacked
..(W,D)
//Outlet stacker: used when the output square can be trusted.
//Outputs immediately, adding to stacks in the outlet.
/datum/cargoprofile/unary/stacker
name = "Stack Items"
id = "ustacker"
blacklist = null
whitelist = list(/obj/item/stack,/obj/item/stack/cable_coil)
dedicated_path = /obj/machinery/programmable/unary/stacker
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
//Only pick it up if you are going to stack it
if(istype(W,/obj/item/stack))
var/obj/item/stack/I = W
if(I.amount >= I.max_amount)
return 0
for(var/obj/item/stack/other in S.contents)
if(other.type == I.type && other != I && other.amount < other.max_amount)
return ..(W,S,remaining)
return 0
if(istype(W,/obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/I = W
if(I.amount >= MAXCOIL)
return 0
for(var/obj/item/stack/cable_coil/other in S.contents)
if(other != I && other.amount < MAXCOIL)
return ..(W,S,remaining)
return 0
outlet_reaction(var/atom/W,var/turf/D)
if(istype(W,/obj/item/stack))
var/obj/item/stack/I = W
for(var/obj/item/stack/O in D.contents)
if(O.type == I.type && O.amount < O.max_amount)
if(I.amount + O.amount <= O.max_amount)
O.amount += I.amount
qdel(I)
return
var/leftover = I.amount + O.amount - O.max_amount
O.amount = O.max_amount
I.amount = leftover
continue
//end for
I.loc = D
return
if(istype(W,/obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/I = W
for(var/obj/item/stack/cable_coil/O in D.contents)
if(O.type == I.type && O.amount < MAXCOIL)
if(I.amount + O.amount <= MAXCOIL) // Why did they make it a #define.
O.amount += I.amount
O.update_icon()
qdel(I)
return
var/leftover = I.amount + O.amount - MAXCOIL // That wasn't a question
O.amount = MAXCOIL // It was a complaint
I.amount = leftover
continue
//end for
I.loc = D
return
//----------------------------------------------------------------------------
// Dubious Overrides (For emag use)
//----------------------------------------------------------------------------
//Clogs up the unloader. And, there may be devious uses for it...
/datum/cargoprofile/slow
name = "Slow unloader"
id = "slow"
whitelist = list(/obj/item,/obj/structure/closet,/obj/structure/bigDelivery,/obj/machinery/portable_atmospherics)
blacklist = list()
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
if(..())
return remaining
/datum/cargoprofile/unary/shredder
name = "Paper Shredder"
id = "shredder"
blacklist = null
whitelist = list(/obj/item/paper,/obj/item/book,/obj/item/clipboard,/obj/item/folder,/obj/item/photo)
universal = 1
dedicated_path = /obj/machinery/programmable/unary/shredder
proc/cliptags(var/Text)
//Removes all html tags
var/index
var/index2
index = findtextEx(Text,"<")
while(index)
index2 = findtextEx(Text,">",index)
if(!index2)
return copytext(Text,1,index)
Text = "[copytext(Text,1,index)][copytext(Text,index2+1,0)]"
index = findtextEx(Text,"<")
//should have trimmed that text there pretty good
return Text
//Recurses through the text, removing large chunks
proc/garbletext(var/Text)
var/l = length(Text)
if(l <= 3)
if(prob(20))
return pick("#","|","/","*",".","."," ","."," "," ")
return Text
if(prob(50))
return "[garbletext(copytext(Text,1,l/2))][garbletext(copytext(Text,l/2,0))]"
if(prob(50))
return "[pick("#","|","/","*",".","."," ","."," "," ")][garbletext(copytext(Text,1,l/2))]"
return "[garbletext(copytext(Text,l/2,0))][pick("#","|","/","*",".","."," ","."," "," ")]"
proc/garble_keeptags(var/Text)
var/list/L = splittext(Text,">")
var/result = ""
for(var/string in L)
var/index = findtextEx(string,"<")
if(index!=1)
result += "[garbletext(copytext(string,1,index))][copytext(string,index)]>"
else
result += "[string]>"
return copytext(result,1,lentext(result))
outlet_reaction(var/atom/W,var/turf/D)
if(istype(W,/obj/item/paper/crumpled))
qdel(W)
return
if(istype(W,/obj/item/clipboard) || istype(W,/obj/item/folder))
// destroy folder, various effects on contents
for(var/obj/item/I in W.contents)
if(prob(25))//JUNK IT
qdel(I)
else if(prob(50)) //We've been over this. I can't just take it apart with a crowbar.
var/obj/item/paper/crumpled/P = new(master.loc)
if(I.name)
P.name = garbletext(I.name)
if(prob(66))
P.fingerprints = I.fingerprints
P.fingerprintshidden = I.fingerprintshidden
if(istype(I,/obj/item/paper))
var/obj/item/paper/O = I
P.info = garble_keeptags(O.info)
qdel(I)
..(P,D)
else
..(I,D) // Eject
qdel(W) //destroy container
return
if(prob(50)) //JUNK IT NOW!
var/obj/item/paper/crumpled/P = new(master.loc)
P.name = W.name
var/obj/item/I = W
if(prob(66))
P.fingerprints = I.fingerprints
P.fingerprintshidden = I.fingerprintshidden
if(istype(I,/obj/item/paper))
var/obj/item/paper/O = I
if(O.info)
P.info = garble_keeptags(O.info)
if(istype(I,/obj/item/book))
var/obj/item/book/B = I
if(B.dat)
P.info = garble_keeptags(B.dat)
if(B.carved && B.store)
..(B.store,D)
qdel(W)
..(P,D)
else //I want it junked
qdel(W)
return
/datum/cargoprofile/unary/gibber
name = "human shredding"
id = "flesh"
whitelist = list(/mob/living/carbon,/mob/living/simple_animal)
blacklist = null
mobcheck = 1
contains(var/atom/A)
if(!istype(A,/mob))
return
if(blacklist)
for(var/T in blacklist)
if(istype(A,T))
return 0
if(whitelist)
for(var/T in whitelist)
if(istype(A,T))
return 1
return 0
return 1
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
var/mob/living/M = W
if(istype(M) && (remaining > MOB_WORK))
//this is necessarily damaging
var/damage = rand(1,5)
to_chat(M, "<span class='danger'>The unloading machine grabs you with a hard metallic claw!</span>")
M.reset_perspective(master)
M.loc = master
master.types[M.type] = src
M.apply_damage(damage) // todo: ugly
M.visible_message("<span class='warning'>[M.name] gets pulled into the machine!</span>")
return MOB_WORK
outlet_reaction(var/atom/W,var/turf/D)
var/mob/living/M = W
var/bruteloss = M.bruteloss
if(istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/C = M
for(var/obj/item/organ/external/L in C.bodyparts)
bruteloss += L.brute_dam
if(bruteloss < 100) // requires tenderization
M.apply_damage(rand(5,15),BRUTE)
to_chat(M, "The machine is tearing you apart!")
master.visible_message("<span class='warning'>[master] makes a squishy grinding noise.</span>")
return
M.loc = master.loc
M.gib()
return
/datum/cargoprofile/people
name = "Manhandling"
id = "people"
whitelist = null
blacklist = list(/mob/camera,/mob/new_player,/mob/living/simple_animal/hostile/blob/blobspore,/mob/living/simple_animal/hostile/creature,
/mob/living/simple_animal/hostile/spaceWorm,/mob/living/simple_animal/shade,/mob/living/simple_animal/hostile/faithless,/mob/dead)
universal = 1
mobcheck = 1
contains(var/atom/A)
if(!istype(A,/mob))
return
if(blacklist)
for(var/T in blacklist)
if(istype(A,T))
return 0
if(whitelist)
for(var/T in whitelist)
if(istype(A,T))
return 1
return 0
return 1
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
var/mob/living/M = W
if(remaining > MOB_WORK)
//this is necessarily damaging
var/damage = rand(1,5)
to_chat(M, "<span class='danger'>The unloading machine grabs you with a hard metallic claw!</span>")
M.forceMove(master)
master.types[M.type] = src
M.apply_damage(damage) // todo: ugly
M.visible_message("<span class='warning'>[M.name] gets pulled into the machine!</span>")
return MOB_WORK
outlet_reaction(var/atom/W,var/turf/D)
var/mob/living/M = W
M.forceMove(master.loc)
M.dir = master.outdir
D = get_step(D,master.outdir) // throw attempt
eject_speed = rand(0,4)
M.visible_message("<span class='notice'>[M.name] is ejected from the unloader.</span>")
M.throw_at(D,eject_speed,eject_speed)
return
/datum/cargoprofile/unary/trainer
name = "Boxing Trainer"
id = "trainer"
blacklist = list()
whitelist = list(/mob/living/carbon/human)
mobcheck = 1
var/const/PUNCH_WORK = 6
dedicated_path = /obj/machinery/programmable/unary/trainer
contains(var/atom/A)
if(!istype(A,/mob))
return 0
if(blacklist)
for(var/T in blacklist)
if(istype(A,T))
return 0
if(whitelist)
for(var/T in whitelist)
if(istype(A,T))
return 1
return 0
return 1
proc/punch(var/mob/living/carbon/human/M,var/maxpunches)
//stolen from holographic boxing gloves code
//This should probably be done BY the mob, however, the attack code will be expecting a source mob.
var/damage
if(prob(75))
damage = rand(0, 6) // pap
else
damage = rand(0, 12) // thwack
if(!damage)
playsound(master.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
master.visible_message("<span class='warning'>\The [src] punched at [M], but whiffed!</span>")
if(maxpunches > 1 && prob(50)) // Follow through on a miss, 50% chance
return punch(M,maxpunches - 1) + 1
return 1
var/obj/item/organ/external/affecting = M.get_organ(ran_zone("chest",50))
var/armor_block = M.run_armor_check(affecting, "melee")
playsound(master.loc, "punch", 25, 1, -1)
master.visible_message("<span class='danger'>\The [src] has punched [M]!</span>")
if(!master.emagged)
M.apply_damage(damage, STAMINA, affecting, armor_block) // Clean fight
else
M.apply_damage(damage, BRUTE, affecting, armor_block) // Foul! Foooul!
if(damage >= 9)
master.visible_message("<span class='danger'>\The [src] has weakened [M]!</span>")
M.apply_effect(4, WEAKEN, armor_block)
if(!master.emagged)
master.sleep = 1
return maxpunches // The machine is not so sophisticated as to not gloat
else
if(prob(25)) // Follow through on a hit, 25% chance. Pause after.
return punch(M,maxpunches-1) + 1
return 1
inlet_reaction(var/atom/W,var/turf/S,var/remaining)
//stolen from boxing gloves code
var/mob/living/carbon/human/M = W
if((M.lying || (M.health - M.staminaloss < 25))&& !master.emagged)
to_chat(M, "\The [src] gives you a break.")
master.sleep+=5
return 0 // Be polite
var/punches = punch(M,remaining / PUNCH_WORK)
if(punches>1)master.sleep++
return punches * PUNCH_WORK
+120
View File
@@ -0,0 +1,120 @@
# Datum Component System (DCS)
## Concept
Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
### In the code
#### Slippery things
At the time of this writing, every object that is slippery overrides atom/Crossed does some checks, then slips the mob. Instead of all those Crossed overrides they could add a slippery component to all these objects. And have the checks in one proc that is run by the Crossed event
#### Powercells
A lot of objects have powercells. The `get_cell()` proc was added to give generic access to the cell var if it had one. This is just a specific use case of `GetComponent()`
#### Radios
The radio object as it is should not exist, given that more things use the _concept_ of radios rather than the object itself. The actual function of the radio can exist in a component which all the things that use it (Request consoles, actual radios, the SM shard) can add to themselves.
#### Standos
Stands have a lot of procs which mimic mob procs. Rather than inserting hooks for all these procs in overrides, the same can be accomplished with signals
## API
### Defines
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned.
### Vars
1. `/datum/var/list/datum_components` (private)
* Lazy associated list of type -> component/list of components.
1. `/datum/component/var/enabled` (protected, boolean)
* If the component is enabled. If not, it will not react to signals
* `FALSE` by default, set to `TRUE` when a signal is registered
1. `/datum/component/var/dupe_mode` (protected, enum)
* How duplicate component types are handled when added to the datum.
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
* `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
1. `/datum/component/var/dupe_type` (protected, type)
* Definition of a duplicate component type
* `null` means exact match on `type` (default)
* Any other type means that and all subtypes
1. `/datum/component/var/list/signal_procs` (private)
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum recieves that signal
1. `/datum/component/var/datum/parent` (protected, read-only)
* The datum this component belongs to
* Never `null` in child procs
### Procs
1. `/datum/proc/GetComponent(component_type(type)) -> datum/component?` (public, final)
* Returns a reference to a component of component_type if it exists in the datum, null otherwise
1. `/datum/proc/GetComponents(component_type(type)) -> list` (public, final)
* Returns a list of references to all components of component_type that exist in the datum
1. `/datum/proc/GetExactComponent(component_type(type)) -> datum/component?` (public, final)
* Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
* Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
1. `/datum/proc/AddComponent(component_type(type), ...) -> datum/component` (public, final)
* Creates an instance of `component_type` in the datum and passes `...` to its `Initialize()` call
* Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
* All components a datum owns are deleted with the datum
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
* Properly handles duplicate situations based on the `dupe_mode` var
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
* Called on a component's `parent` after a signal recieved causes it to activate. `src` is the parameter
* Will only be called if a component's callback returns `TRUE`
1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
* Properly transfers ownership of a component from one datum to another
* Signals `COMSIG_COMPONENT_REMOVING` on the parent
* Called on the datum you want to own the component with another datum's component
1. `/datum/proc/SendSignal(signal, ...)` (public, final)
* Call to send a signal to the components of the target datum
* Extra arguments are to be specified in the signal definition
* Returns a bitflag with signal specific information assembled from all activated components
1. `/datum/component/New(datum/parent, ...)` (private, final)
* Runs internal setup for the component
* Extra arguments are passed to `Initialize()`
1. `/datum/component/Initialize(...)` (abstract, no-sleep)
* Called by `New()` with the same argments excluding `parent`
* Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
* Signals will not be recieved while this function is running
* Component may be deleted after this function completes without being attached
* Do not call `qdel(src)` from this function
1. `/datum/component/Destroy(force(bool), silent(bool))` (virtual, no-sleep)
* Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted
* Properly removes the component from `parent` and cleans up references
* Setting `force` makes it not check for and remove the component from the parent
* Setting `silent` deletes the component without sending a `COMSIG_COMPONENT_REMOVING` signal
1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract, no-sleep)
* Called on a component when a component of the same type was added to the same parent
* See `/datum/component/var/dupe_mode`
* `C`'s type will always be the same of the called component
1. `/datum/component/proc/AfterComponentActivated()` (abstract, async)
* Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called
1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep)
* Called before `new_parent` is assigned to `parent` in `TakeComponent()`
* Allows the component to react to ownership transfers
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
* Clears `parent` and removes the component from it's component list
1. `/datum/component/proc/_JoinParent` (private, final)
* Tries to add the component to it's `parent`s `datum_components` list
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
* When that signal is recieved `proc_ref` will be called on the component, along with associated arguments
* Example proc ref: `.proc/OnEvent`
* If a previous registration is overwritten by the call, a runtime occurs. Setting `override` to TRUE prevents this
* These callbacks run asyncronously
* Returning `TRUE` from these callbacks will trigger a `TRUE` return from the `SendSignal()` that initiated it
### See/Define signals and their arguments in __DEFINES\components.dm
+264
View File
@@ -0,0 +1,264 @@
/datum/component
var/enabled = FALSE
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/list/signal_procs
var/datum/parent
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P]!")
_JoinParent(P)
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
var/test = dc[I]
if(test) //already another component of this type here
var/list/components_of_type
if(!length(test))
components_of_type = list(test)
dc[I] = components_of_type
else
components_of_type = test
if(I == our_type) //exact match, take priority
var/inserted = FALSE
for(var/J in 1 to components_of_type.len)
var/datum/component/C = components_of_type[J]
if(C.type != our_type) //but not over other exact matches
components_of_type.Insert(J, I)
inserted = TRUE
break
if(!inserted)
components_of_type += src
else //indirect match, back of the line with ya
components_of_type += src
else //only component of this type, no list
dc[I] = src
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
enabled = FALSE
var/datum/P = parent
if(!force)
_RemoveFromParent()
if(!silent)
P.SendSignal(COMSIG_COMPONENT_REMOVING, src)
parent = null
LAZYCLEARLIST(signal_procs)
return ..()
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
for(var/I in _GetInverseTypeList())
var/list/components_of_type = dc[I]
if(length(components_of_type)) //
var/list/subtracted = components_of_type - src
if(subtracted.len == 1) //only 1 guy left
dc[I] = subtracted[1] //make him special
else
dc[I] = subtracted
else //just us
dc -= I
if(!dc.len)
P.datum_components = null
/datum/component/proc/RegisterSignal(sig_type_or_types, proc_or_callback, override = FALSE)
if(QDELETED(src))
return
var/list/procs = signal_procs
if(!procs)
procs = list()
signal_procs = procs
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override)
. = procs[sig_type]
if(.)
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
proc_or_callback = CALLBACK(src, proc_or_callback)
procs[sig_type] = proc_or_callback
enabled = TRUE
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/datum/component/proc/OnTransfer(datum/new_parent)
return
/datum/component/proc/_GetInverseTypeList(our_type = type)
#if DM_VERSION >= 513
#warning 512 is definitely stable now, remove the old code
#endif
#if DM_VERSION < 512
//remove this when we use 512 full time
set invisibility = 101
#endif
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while(current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/datum/proc/SendSignal(sigtype, ...)
var/list/comps = datum_components
if(!comps)
return NONE
var/list/arguments = args.Copy(2)
var/target = comps[/datum/component]
if(!length(target))
var/datum/component/C = target
if(!C.enabled)
return NONE
var/datum/callback/CB = C.signal_procs[sigtype]
if(!CB)
return NONE
return CB.InvokeAsync(arglist(arguments))
. = NONE
for(var/I in target)
var/datum/component/C = I
if(!C.enabled)
continue
var/datum/callback/CB = C.signal_procs[sigtype]
if(!CB)
continue
. |= CB.InvokeAsync(arglist(arguments))
/datum/proc/GetComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
var/datum/component/C = dc[c_type]
if(C)
if(length(C))
C = C[1]
if(C.type == c_type)
return C
return null
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
if(!isnum(dm))
CRASH("[nt]: Invalid dupe_mode ([dm])!")
if(dt && !ispath(dt))
CRASH("[nt]: Invalid dupe_type ([dt])!")
else
new_comp = nt
args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
/datum/proc/TakeComponent(datum/component/C)
if(!C)
return
var/datum/helicopter = C.parent
if(helicopter == src)
//if we're taking to the same thing no need for anything
return
if(C.OnTransfer(src) == COMPONENT_INCOMPATIBLE)
qdel(C)
return
C._RemoveFromParent()
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
C.parent = src
if(C == AddComponent(C))
C._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
return
var/comps = dc[/datum/component]
if(islist(comps))
for(var/I in comps)
target.TakeComponent(I)
else
target.TakeComponent(comps)
/datum/component/nano_host()
return parent
@@ -0,0 +1,389 @@
/*
This datum should be used for handling mineral contents of machines and whatever else is supposed to hold minerals and make use of them.
Variables:
amount - raw amount of the mineral this container is holding, calculated by the defined value MINERAL_MATERIAL_AMOUNT=2000.
max_amount - max raw amount of mineral this container can hold.
sheet_type - type of the mineral sheet the container handles, used for output.
parent - object that this container is being used by, used for output.
MAX_STACK_SIZE - size of a stack of mineral sheets. Constant.
*/
/datum/component/material_container
var/total_amount = 0
var/max_amount
var/sheet_type
var/list/materials
var/show_on_examine
var/list/allowed_typecache
var/last_inserted_id
var/precise_insertion = FALSE
var/datum/callback/precondition
var/datum/callback/after_insert
/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert)
materials = list()
max_amount = max(0, max_amt)
show_on_examine = _show_on_examine
if(allowed_types)
allowed_typecache = typecacheof(allowed_types)
precondition = _precondition
after_insert = _after_insert
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
RegisterSignal(COMSIG_PARENT_EXAMINE, .proc/OnExamine)
var/list/possible_mats = list()
for(var/mat_type in subtypesof(/datum/material))
var/datum/material/MT = mat_type
possible_mats[initial(MT.id)] = mat_type
for(var/id in mat_list)
if(possible_mats[id])
var/mat_path = possible_mats[id]
materials[id] = new mat_path()
/datum/component/material_container/proc/OnExamine(mob/user)
for(var/I in materials)
var/datum/material/M = materials[I]
var/amt = amount(M.id)
if(amt)
to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")
/datum/component/material_container/proc/OnAttackBy(obj/item/I, mob/living/user)
var/list/tc = allowed_typecache
if(user.a_intent != INTENT_HELP)
return
if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
to_chat(user, "<span class='warning'>[parent] won't accept [I]!</span>")
return
. = COMPONENT_NO_AFTERATTACK
var/datum/callback/pc = precondition
if(pc && !pc.Invoke(user))
return
var/material_amount = get_item_material_amount(I)
if(!material_amount)
to_chat(user, "<span class='warning'>[I] does not contain sufficient amounts of metal or glass to be accepted by [parent].</span>")
return
if(!has_space(material_amount))
to_chat(user, "<span class='warning'>[parent] is full. Please remove metal or glass from [parent] in order to insert more.</span>")
return
user_insert(I, user)
/datum/component/material_container/proc/user_insert(obj/item/I, mob/living/user)
set waitfor = FALSE
var/requested_amount
if(istype(I, /obj/item/stack) && precise_insertion)
var/atom/current_parent = parent
var/obj/item/stack/S = I
requested_amount = input(user, "How much do you want to insert?", "Inserting [S.singular_name]s") as num|null
if(isnull(requested_amount) || (requested_amount <= 0))
return
if(QDELETED(I) || QDELETED(user) || QDELETED(src) || parent != current_parent || user.incapacitated() || !in_range(current_parent, user) || user.l_hand != I && user.r_hand != I)
return
if(!user.drop_item())
to_chat(user, "<span class='warning'>[I] is stuck to you and cannot be placed into [parent].</span>")
return
var/inserted = insert_item(I, stack_amt = requested_amount)
if(inserted)
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
to_chat(user, "<span class='notice'>You insert [inserted] [S.singular_name][inserted>1 ? "s" : ""] into [parent].</span>")
if(!QDELETED(I))
if(!user.put_in_hands(I))
stack_trace("Warning: User could not put object back in hand during material container insertion, line [__LINE__]! This can lead to issues.")
I.forceMove(user.loc)
else
to_chat(user, "<span class='notice'>You insert a material total of [inserted] into [parent].</span>")
qdel(I)
if(after_insert)
after_insert.Invoke(I.type, last_inserted_id, inserted)
else
user.put_in_active_hand(I)
//For inserting an amount of material
/datum/component/material_container/proc/insert_amount(amt, id = null)
if(amt > 0 && has_space(amt))
var/total_amount_saved = total_amount
if(id)
var/datum/material/M = materials[id]
if(M)
M.amount += amt
total_amount += amt
else
for(var/i in materials)
var/datum/material/M = materials[i]
M.amount += amt
total_amount += amt
return (total_amount - total_amount_saved)
return FALSE
/datum/component/material_container/proc/insert_stack(obj/item/stack/S, amt, multiplier = 1)
if(isnull(amt))
amt = S.amount
if(amt <= 0)
return FALSE
if(amt > S.amount)
amt = S.amount
var/material_amt = get_item_material_amount(S)
if(!material_amt)
return FALSE
amt = min(amt, round(((max_amount - total_amount) / material_amt)))
if(!amt)
return FALSE
last_inserted_id = insert_materials(S,amt * multiplier)
S.use(amt)
return amt
/datum/component/material_container/proc/insert_item(obj/item/I, multiplier = 1, stack_amt)
if(!I)
return FALSE
if(istype(I, /obj/item/stack))
return insert_stack(I, stack_amt, multiplier)
var/material_amount = get_item_material_amount(I)
if(!material_amount || !has_space(material_amount))
return FALSE
last_inserted_id = insert_materials(I, multiplier)
return material_amount
/datum/component/material_container/proc/insert_materials(obj/item/I, multiplier = 1) //for internal usage only
var/datum/material/M
var/primary_mat
var/max_mat_value = 0
for(var/MAT in materials)
M = materials[MAT]
M.amount += I.materials[MAT] * multiplier
total_amount += I.materials[MAT] * multiplier
if(I.materials[MAT] > max_mat_value)
primary_mat = MAT
return primary_mat
//For consuming material
//mats is a list of types of material to use and the corresponding amounts, example: list(MAT_METAL=100, MAT_GLASS=200)
/datum/component/material_container/proc/use_amount(list/mats, multiplier=1)
if(!mats || !mats.len)
return FALSE
var/datum/material/M
for(var/MAT in materials)
M = materials[MAT]
if(M.amount < (mats[MAT] * multiplier))
return FALSE
var/total_amount_save = total_amount
for(var/MAT in materials)
M = materials[MAT]
M.amount -= mats[MAT] * multiplier
total_amount -= mats[MAT] * multiplier
return total_amount_save - total_amount
/datum/component/material_container/proc/use_amount_type(amt, id)
var/datum/material/M = materials[id]
if(M)
if(M.amount >= amt)
M.amount -= amt
total_amount -= amt
return amt
return FALSE
/datum/component/material_container/proc/transer_amt_to(var/datum/component/material_container/T, amt, id)
if((amt==0)||(!T)||(!id))
return FALSE
if(amt<0)
return T.transer_amt_to(src, -amt, id)
var/datum/material/M = materials[id]
if(M)
var/tr = min(amt, M.amount,T.can_insert_amount(amt, id))
if(tr)
use_amount_type(tr, id)
T.insert_amount(tr, id)
return tr
return FALSE
/datum/component/material_container/proc/can_insert_amount(amt, id)
if(amt && id)
var/datum/material/M = materials[id]
if(M)
if((total_amount + amt) <= max_amount)
return amt
else
return (max_amount-total_amount)
/datum/component/material_container/proc/can_use_amount(amt, id, list/mats)
if(amt && id)
var/datum/material/M = materials[id]
if(M && M.amount >= amt)
return TRUE
else if(istype(mats))
for(var/M in mats)
if(materials[M] && (mats[M] <= materials[M]))
continue
else
return FALSE
return TRUE
return FALSE
//For spawning mineral sheets; internal use only
/datum/component/material_container/proc/retrieve(sheet_amt, datum/material/M, target = null)
if(!M.sheet_type)
return FALSE
if(sheet_amt > 0)
if(M.amount < (sheet_amt * MINERAL_MATERIAL_AMOUNT))
sheet_amt = round(M.amount / MINERAL_MATERIAL_AMOUNT)
var/count = 0
while(sheet_amt > MAX_STACK_SIZE)
new M.sheet_type(get_turf(parent), MAX_STACK_SIZE)
count += MAX_STACK_SIZE
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.id)
sheet_amt -= MAX_STACK_SIZE
if(round((sheet_amt * MINERAL_MATERIAL_AMOUNT) / MINERAL_MATERIAL_AMOUNT))
var/obj/item/stack/sheet/s = new M.sheet_type(get_turf(parent), sheet_amt)
if(target)
s.forceMove(target)
count += sheet_amt
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.id)
return count
return FALSE
/datum/component/material_container/proc/retrieve_sheets(sheet_amt, id, target = null)
if(materials[id])
return retrieve(sheet_amt, materials[id], target)
return FALSE
/datum/component/material_container/proc/retrieve_amount(amt, id, target)
return retrieve_sheets(amount2sheet(amt), id, target)
/datum/component/material_container/proc/retrieve_all(target = null)
var/result = 0
var/datum/material/M
for(var/MAT in materials)
M = materials[MAT]
result += retrieve_sheets(amount2sheet(M.amount), MAT, target)
return result
/datum/component/material_container/proc/has_space(amt = 0)
return (total_amount + amt) <= max_amount
/datum/component/material_container/proc/has_materials(list/mats, multiplier=1)
if(!mats || !mats.len)
return FALSE
var/datum/material/M
for(var/MAT in mats)
M = materials[MAT]
if(M.amount < (mats[MAT] * multiplier))
return FALSE
return TRUE
/datum/component/material_container/proc/amount2sheet(amt)
if(amt >= MINERAL_MATERIAL_AMOUNT)
return round(amt / MINERAL_MATERIAL_AMOUNT)
return FALSE
/datum/component/material_container/proc/sheet2amount(sheet_amt)
if(sheet_amt > 0)
return sheet_amt * MINERAL_MATERIAL_AMOUNT
return FALSE
/datum/component/material_container/proc/amount(id)
var/datum/material/M = materials[id]
return M ? M.amount : 0
//returns the amount of material relevant to this container;
//if this container does not support glass, any glass in 'I' will not be taken into account
/datum/component/material_container/proc/get_item_material_amount(obj/item/I)
if(!istype(I))
return FALSE
var/material_amount = 0
for(var/MAT in materials)
material_amount += I.materials[MAT]
return material_amount
/datum/material
var/name
var/amount = 0
var/id = null
var/sheet_type = null
var/coin_type = null
/datum/material/metal
name = "Metal"
id = MAT_METAL
sheet_type = /obj/item/stack/sheet/metal
coin_type = /obj/item/coin/iron
/datum/material/glass
name = "Glass"
id = MAT_GLASS
sheet_type = /obj/item/stack/sheet/glass
/datum/material/silver
name = "Silver"
id = MAT_SILVER
sheet_type = /obj/item/stack/sheet/mineral/silver
coin_type = /obj/item/coin/silver
/datum/material/gold
name = "Gold"
id = MAT_GOLD
sheet_type = /obj/item/stack/sheet/mineral/gold
coin_type = /obj/item/coin/gold
/datum/material/diamond
name = "Diamond"
id = MAT_DIAMOND
sheet_type = /obj/item/stack/sheet/mineral/diamond
coin_type = /obj/item/coin/diamond
/datum/material/uranium
name = "Uranium"
id = MAT_URANIUM
sheet_type = /obj/item/stack/sheet/mineral/uranium
coin_type = /obj/item/coin/uranium
/datum/material/plasma
name = "Solid Plasma"
id = MAT_PLASMA
sheet_type = /obj/item/stack/sheet/mineral/plasma
coin_type = /obj/item/coin/plasma
/datum/material/bluespace
name = "Bluespace Mesh"
id = MAT_BLUESPACE
sheet_type = /obj/item/stack/sheet/bluespace_crystal
/datum/material/bananium
name = "Bananium"
id = MAT_BANANIUM
sheet_type = /obj/item/stack/sheet/mineral/bananium
coin_type = /obj/item/coin/clown
/datum/material/tranquillite
name = "Tranquillite"
id = MAT_TRANQUILLITE
sheet_type = /obj/item/stack/sheet/mineral/tranquillite
coin_type = /obj/item/coin/mime
/datum/material/titanium
name = "Titanium"
id = MAT_TITANIUM
sheet_type = /obj/item/stack/sheet/mineral/titanium
/datum/material/biomass
name = "Biomass"
id = MAT_BIOMASS
/datum/material/plastic
name = "Plastic"
id = MAT_PLASTIC
sheet_type = /obj/item/stack/sheet/plastic
-7
View File
@@ -1,7 +0,0 @@
datum
computer
var/name
folder
var/list/datum/computer/contents = list()
file
+1 -1
View File
@@ -255,7 +255,7 @@ var/record_id_num = 1001
if(PDA_Manifest.len)
PDA_Manifest.Cut()
if(H.mind && (H.mind.assigned_role != "MODE"))
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
var/assignment
if(H.mind.role_alt_title)
assignment = H.mind.role_alt_title
+23 -1
View File
@@ -1,6 +1,7 @@
/datum
var/gc_destroyed //Time when this object was destroyed.
var/list/active_timers //for SStimer
var/list/datum_components //for /datum/components
var/var_edited = FALSE //Warranty void if seal is broken
var/tmp/unique_datum_id = null
@@ -15,4 +16,25 @@
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
/datum/proc/Destroy(force = FALSE, ...)
tag = null
var/list/timers = active_timers
active_timers = null
for(var/thing in timers)
var/datum/timedevent/timer = thing
if(timer.spent)
continue
qdel(timer)
var/list/dc = datum_components
if(dc)
var/all_components = dc[/datum/component]
if(length(all_components))
for(var/I in all_components)
var/datum/component/C = I
qdel(C, FALSE, TRUE)
else
var/datum/component/C = all_components
qdel(C, FALSE, TRUE)
dc.Cut()
return QDEL_HINT_QUEUE
+5 -5
View File
@@ -1260,7 +1260,7 @@
if(prompt != "Yes")
return
L.Cut(index, index+1)
log_to_dd("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
return TRUE
@@ -1281,7 +1281,7 @@
return TRUE
uniqueList_inplace(L)
log_to_dd("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
return TRUE
@@ -1293,7 +1293,7 @@
return TRUE
listclearnulls(L)
log_to_dd("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
return TRUE
@@ -1308,7 +1308,7 @@
return TRUE
L.len = value["value"]
log_to_dd("### ListVarEdit by [src]: /list len: [L.len]")
log_world("### ListVarEdit by [src]: /list len: [L.len]")
log_admin("[key_name(src)] modified list's len: [L.len]")
message_admins("[key_name_admin(src)] modified list's len: [L.len]")
return TRUE
@@ -1320,7 +1320,7 @@
return TRUE
shuffle_inplace(L)
log_to_dd("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")
return TRUE
+100
View File
@@ -0,0 +1,100 @@
/*
output_atoms (list of atoms) The destination(s) for the sounds
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
mid_length (num) The length to wait between playing mid_sounds
start_sound (soundfile) Played before starting the mid_sounds loop
start_length (num) How long to wait before starting the main loop after playing start_sound
end_sound (soundfile) The sound played after the main loop has concluded
chance (num) Chance per loop to play a mid_sound
volume (num) Sound output volume
muted (bool) Private. Used to stop the sound loop.
max_loops (num) The max amount of loops to run for.
direct (bool) If true plays directly to provided atoms instead of from them
*/
/datum/looping_sound
var/list/atom/output_atoms
var/mid_sounds
var/mid_length
var/start_sound
var/start_length
var/end_sound
var/chance
var/volume = 100
var/muted = TRUE
var/max_loops
var/direct
/datum/looping_sound/New(list/_output_atoms = list(), start_immediately = FALSE, _direct = FALSE)
if(!mid_sounds)
WARNING("A looping sound datum was created without sounds to play.")
return
output_atoms = _output_atoms
direct = _direct
if(start_immediately)
start()
/datum/looping_sound/Destroy()
stop()
output_atoms = null
return ..()
/datum/looping_sound/proc/start(atom/add_thing)
if(add_thing)
output_atoms |= add_thing
if(!muted)
return
muted = FALSE
on_start()
/datum/looping_sound/proc/stop(atom/remove_thing)
if(remove_thing)
output_atoms -= remove_thing
if(muted)
return
muted = TRUE
/datum/looping_sound/proc/sound_loop(looped = 0)
if(muted || (max_loops && looped > max_loops))
on_stop(looped)
return
if(!chance || prob(chance))
play(get_sound(looped))
addtimer(CALLBACK(src, .proc/sound_loop, ++looped), mid_length)
/datum/looping_sound/proc/play(soundfile)
var/list/atoms_cache = output_atoms
var/sound/S = sound(soundfile)
if(direct)
S.channel = open_sound_channel()
S.volume = volume
for(var/i in 1 to atoms_cache.len)
var/atom/thing = atoms_cache[i]
if(direct)
SEND_SOUND(thing, S)
else
playsound(thing, S, volume)
/datum/looping_sound/proc/get_sound(looped, _mid_sounds)
if(!_mid_sounds)
. = mid_sounds
else
. = _mid_sounds
while(!isfile(.) && !isnull(.))
. = pickweight(.)
/datum/looping_sound/proc/on_start()
var/start_wait = 0
if(start_sound)
play(start_sound)
start_wait = start_length
addtimer(CALLBACK(src, .proc/sound_loop), start_wait)
/datum/looping_sound/proc/on_stop(looped)
if(end_sound)
play(end_sound)
@@ -0,0 +1,7 @@
/datum/looping_sound/showering
start_sound = 'sound/machines/shower/shower_start.ogg'
start_length = 2
mid_sounds = list('sound/machines/shower/shower_mid1.ogg' = 1,'sound/machines/shower/shower_mid2.ogg' = 1,'sound/machines/shower/shower_mid3.ogg' = 1)
mid_length = 10
end_sound = 'sound/machines/shower/shower_end.ogg'
volume = 20
-292
View File
@@ -1,292 +0,0 @@
/*
This datum should be used for handling mineral contents of machines and whatever else is supposed to hold minerals and make use of them.
Variables:
amount - raw amount of the mineral this container is holding, calculated by the defined value MINERAL_MATERIAL_AMOUNT=2000.
max_amount - max raw amount of mineral this container can hold.
sheet_type - type of the mineral sheet the container handles, used for output.
owner - object that this container is being used by, used for output.
MAX_STACK_SIZE - size of a stack of mineral sheets. Constant.
*/
/datum/material_container
var/total_amount = 0
var/max_amount
var/sheet_type
var/obj/owner
var/list/materials = list()
//MAX_STACK_SIZE = 50
//MINERAL_MATERIAL_AMOUNT = 2000
/datum/material_container/New(obj/O, list/mat_list, max_amt = 0)
owner = O
max_amount = max(0, max_amt)
if(mat_list[MAT_METAL])
materials[MAT_METAL] = new /datum/material/metal()
if(mat_list[MAT_GLASS])
materials[MAT_GLASS] = new /datum/material/glass()
if(mat_list[MAT_SILVER])
materials[MAT_SILVER] = new /datum/material/silver()
if(mat_list[MAT_GOLD])
materials[MAT_GOLD] = new /datum/material/gold()
if(mat_list[MAT_DIAMOND])
materials[MAT_DIAMOND] = new /datum/material/diamond()
if(mat_list[MAT_URANIUM])
materials[MAT_URANIUM] = new /datum/material/uranium()
if(mat_list[MAT_PLASMA])
materials[MAT_PLASMA] = new /datum/material/plasma()
if(mat_list[MAT_BANANIUM])
materials[MAT_BANANIUM] = new /datum/material/bananium()
if(mat_list[MAT_TRANQUILLITE])
materials[MAT_TRANQUILLITE] = new /datum/material/tranquillite()
if(mat_list[MAT_TITANIUM])
materials[MAT_TITANIUM] = new /datum/material/titanium()
/datum/material_container/Destroy()
QDEL_LIST_ASSOC_VAL(materials)
owner = null
return ..()
//For inserting an amount of material
/datum/material_container/proc/insert_amount(amt, material_type = null)
if(amt > 0 && has_space(amt))
var/total_amount_saved = total_amount
if(material_type)
var/datum/material/M = materials[material_type]
if(M)
M.amount += amt
total_amount += amt
else
for(var/datum/material/M in materials)
M.amount += amt
total_amount += amt
return (total_amount - total_amount_saved)
return 0
/datum/material_container/proc/insert_stack(obj/item/stack/S, amt = 0)
if(amt <= 0)
return 0
if(amt > S.amount)
amt = S.amount
var/material_amt = get_item_material_amount(S)
if(!material_amt)
return 0
amt = min(amt, round(((max_amount - total_amount) / material_amt)))
if(!amt)
return 0
insert_materials(S,amt)
S.use(amt)
return amt
/datum/material_container/proc/insert_item(obj/item/I, multiplier = 1)
if(!I)
return 0
if(istype(I,/obj/item/stack))
var/obj/item/stack/S = I
return insert_stack(I, S.amount)
var/material_amount = get_item_material_amount(I)
if(!material_amount || !has_space(material_amount))
return 0
insert_materials(I, multiplier)
return material_amount
/datum/material_container/proc/insert_materials(obj/item/I, multiplier = 1) //for internal usage only
var/datum/material/M
for(var/MAT in materials)
M = materials[MAT]
M.amount += I.materials[MAT] * multiplier
total_amount += I.materials[MAT] * multiplier
//For consuming material
//mats is a list of types of material to use and the corresponding amounts, example: list(MAT_METAL=100, MAT_GLASS=200)
/datum/material_container/proc/use_amount(list/mats, multiplier=1)
if(!mats || !mats.len)
return 0
var/datum/material/M
for(var/MAT in materials)
M = materials[MAT]
if(M.amount < (mats[MAT] * multiplier))
return 0
var/total_amount_save = total_amount
for(var/MAT in materials)
M = materials[MAT]
M.amount -= mats[MAT] * multiplier
total_amount -= mats[MAT] * multiplier
return total_amount_save - total_amount
/datum/material_container/proc/use_amount_type(amt, material_type)
var/datum/material/M
M = materials[material_type]
if(M)
if(M.amount >= amt)
M.amount -= amt
total_amount -= amt
return amt
return 0
//For spawning mineral sheets; internal use only
/datum/material_container/proc/retrieve(sheet_amt, datum/material/M)
if(!M.sheet_type)
return 0
if(sheet_amt > 0)
if(M.amount < (sheet_amt * MINERAL_MATERIAL_AMOUNT))
sheet_amt = round(M.amount / MINERAL_MATERIAL_AMOUNT)
var/count = 0
while(sheet_amt > MAX_STACK_SIZE)
new M.sheet_type(get_turf(owner), MAX_STACK_SIZE)
count += MAX_STACK_SIZE
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.material_type)
sheet_amt -= MAX_STACK_SIZE
if(round(M.amount / MINERAL_MATERIAL_AMOUNT))
new M.sheet_type(get_turf(owner), sheet_amt)
count += sheet_amt
use_amount_type(sheet_amt * MINERAL_MATERIAL_AMOUNT, M.material_type)
return count
return 0
/datum/material_container/proc/retrieve_sheets(sheet_amt, material_type)
if(materials[material_type])
return retrieve(sheet_amt, materials[material_type])
return 0
/datum/material_container/proc/retrieve_amount(amt, material_type)
return retrieve_sheets(amount2sheet(amt),material_type)
/datum/material_container/proc/retrieve_all()
var/result = 0
var/datum/material/M
for(var/MAT in materials)
M = materials[MAT]
result += retrieve_sheets(amount2sheet(M.amount), MAT)
return result
/datum/material_container/proc/has_space(amt = 0)
return (total_amount + amt) <= max_amount
/datum/material_container/proc/has_materials(list/mats, multiplier=1)
if(!mats || !mats.len)
return 0
var/datum/material/M
for(var/MAT in mats)
M = materials[MAT]
if(M.amount < (mats[MAT] * multiplier))
return 0
return 1
/datum/material_container/proc/amount2sheet(amt)
if(amt >= MINERAL_MATERIAL_AMOUNT)
return round(amt / MINERAL_MATERIAL_AMOUNT)
return 0
/datum/material_container/proc/sheet2amount(sheet_amt)
if(sheet_amt > 0)
return sheet_amt * MINERAL_MATERIAL_AMOUNT
return 0
/datum/material_container/proc/amount(material_type)
var/datum/material/M = materials[material_type]
return M ? M.amount : 0
//returns the amount of material relevant to this container;
//if this container does not support glass, any glass in 'I' will not be taken into account
/datum/material_container/proc/get_item_material_amount(obj/item/I)
if(!istype(I))
return 0
var/material_amount = 0
for(var/MAT in materials)
material_amount += I.materials[MAT]
return material_amount
/datum/material
var/amount = 0
var/material_type = null
var/sheet_type = null
/datum/material/metal
/datum/material/metal/New()
..()
material_type = MAT_METAL
sheet_type = /obj/item/stack/sheet/metal
/datum/material/glass
/datum/material/glass/New()
..()
material_type = MAT_GLASS
sheet_type = /obj/item/stack/sheet/glass
/datum/material/silver
/datum/material/silver/New()
..()
material_type = MAT_SILVER
sheet_type = /obj/item/stack/sheet/mineral/silver
/datum/material/gold
/datum/material/gold/New()
..()
material_type = MAT_GOLD
sheet_type = /obj/item/stack/sheet/mineral/gold
/datum/material/diamond
/datum/material/diamond/New()
..()
material_type = MAT_DIAMOND
sheet_type = /obj/item/stack/sheet/mineral/diamond
/datum/material/uranium
/datum/material/uranium/New()
..()
material_type = MAT_URANIUM
sheet_type = /obj/item/stack/sheet/mineral/uranium
/datum/material/plasma
/datum/material/plasma/New()
..()
material_type = MAT_PLASMA
sheet_type = /obj/item/stack/sheet/mineral/plasma
/datum/material/bananium
/datum/material/bananium/New()
..()
material_type = MAT_BANANIUM
sheet_type = /obj/item/stack/sheet/mineral/bananium
/datum/material/tranquillite
/datum/material/tranquillite/New()
..()
material_type = MAT_TRANQUILLITE
sheet_type = /obj/item/stack/sheet/mineral/tranquillite
/datum/material/titanium
/datum/material/titanium/New()
..()
material_type = MAT_TITANIUM
sheet_type = /obj/item/stack/sheet/mineral/titanium
/datum/material/biomass
/datum/material/biomass/New()
..()
material_type = MAT_BIOMASS
+81 -49
View File
@@ -38,8 +38,8 @@
var/memory
var/assigned_role
var/special_role
var/assigned_role //assigned role is what job you're assigned to when you join the station.
var/special_role //special roles are typically reserved for antags or roles like ERT. If you want to avoid a character being automatically announced by the AI, on arrival (becuase they're an off station character or something); ensure that special_role and assigned_role are equal.
var/list/restricted_roles = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
@@ -54,6 +54,7 @@
var/has_been_rev = 0//Tracks if this mind has been a rev or not
var/miming = 0 // Mime's vow of silence
var/list/antag_datums
var/speech_span // What span any body this mind has talks in.
var/datum/faction/faction //associated faction
var/datum/changeling/changeling //changeling holder
@@ -72,17 +73,29 @@
var/brigged_since = -1
var/suicided = FALSE
New(var/key)
src.key = key
//put this here for easier tracking ingame
var/datum/money_account/initial_account
//zealot_master is a reference to the mob that converted them into a zealot (for ease of investigation and such)
var/mob/living/carbon/human/zealot_master = null
/datum/mind/New(var/key)
src.key = key
/datum/mind/Destroy()
ticker.minds -= src
if(islist(antag_datums))
for(var/i in antag_datums)
var/datum/antagonist/antag_datum = i
if(antag_datum.delete_on_mind_deletion)
qdel(i)
antag_datums = null
return ..()
/datum/mind/proc/transfer_to(mob/living/new_character)
var/datum/atom_hud/antag/hud_to_transfer = antag_hud //we need this because leave_hud() will clear this list
var/mob/living/old_current = current
if(!istype(new_character))
log_runtime(EXCEPTION("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob."), src)
if(current) //remove ourself from our old body's mind variable
@@ -95,6 +108,9 @@
new_character.mind.current = null
current = new_character //link ourself to our new body
new_character.mind = src //and link our new body to ourself
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
var/datum/antagonist/A = a
A.on_body_transfer(old_current, current)
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_actions(new_character)
@@ -175,7 +191,7 @@
text += "<br>Flash: <a href='?src=[UID()];revolution=flash'>give</a>"
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
var/obj/item/flash/flash = locate() in L
if(flash)
if(!flash.broken)
text += "|<a href='?src=[UID()];revolution=takeflash'>take</a>."
@@ -419,7 +435,7 @@
ishuman(current) )
text = "Uplink: <a href='?src=[UID()];common=uplink'>give</a>"
var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
var/obj/item/uplink/hidden/suplink = find_syndicate_uplink()
var/crystals
if(suplink)
crystals = suplink.uses
@@ -525,8 +541,8 @@
new_objective = new objective_path
new_objective.owner = src
new_objective:target = new_target:mind
//Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role=="MODE" ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
//Will display as special role if assigned mode is equal to special role.. Ninjas/commandos/nuke ops.
new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role == new_target:mind:special_role ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
if("destroy")
var/list/possible_targets = active_ais(1)
@@ -762,7 +778,7 @@
if("takeflash")
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
var/obj/item/flash/flash = locate() in L
if(!flash)
to_chat(usr, "<span class='warning'>Deleting flash failed!</span>")
qdel(flash)
@@ -771,7 +787,7 @@
if("repairflash")
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
var/obj/item/flash/flash = locate() in L
if(!flash)
to_chat(usr, "<span class='warning'>Repairing flash failed!</span>")
else
@@ -781,7 +797,7 @@
if("reequip")
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
var/obj/item/flash/flash = locate() in L
qdel(flash)
take_uplink()
var/fail = 0
@@ -1183,7 +1199,7 @@
message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s uplink")
if("crystals")
if(usr.client.holder.rights & (R_SERVER|R_EVENT))
var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
var/obj/item/uplink/hidden/suplink = find_syndicate_uplink()
var/crystals
if(suplink)
crystals = suplink.uses
@@ -1211,37 +1227,54 @@
message_admins("[key_name_admin(usr)] has announced [key_name_admin(current)]'s objectives")
edit_memory()
/*
/datum/mind/proc/clear_memory(var/silent = 1)
var/datum/game_mode/current_mode = ticker.mode
// remove traitor uplinks
var/list/L = current.get_contents()
for(var/t in L)
if(istype(t, /obj/item/device/pda))
if(t:uplink) qdel(t:uplink)
t:uplink = null
else if(istype(t, /obj/item/device/radio))
if(t:traitorradio) qdel(t:traitorradio)
t:traitorradio = null
t:traitor_frequency = 0.0
else if(istype(t, /obj/item/SWF_uplink) || istype(t, /obj/item/syndicate_uplink))
if(t:origradio)
var/obj/item/device/radio/R = t:origradio
R.loc = current.loc
R.traitorradio = null
R.traitor_frequency = 0.0
qdel(t)
// remove wizards spells
//If there are more special powers that need removal, they can be procced into here./N
current.spellremove(current)
// Datum antag mind procs
/datum/mind/proc/add_antag_datum(datum_type, on_gain = TRUE)
if(!datum_type)
return
if(!can_hold_antag_datum(datum_type))
return
var/datum/antagonist/A = new datum_type(src)
antag_datums += A
if(on_gain)
A.on_gain()
// clear memory
memory = ""
special_role = null
/datum/mind/proc/remove_antag_datum(datum_type)
if(!datum_type)
return
var/datum/antagonist/A = has_antag_datum(datum_type)
if(A)
A.on_removal()
return TRUE
/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
for(var/a in antag_datums)
var/datum/antagonist/A = a
A.on_removal()
/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
if(!datum_type)
return
. = FALSE
for(var/a in antag_datums)
var/datum/antagonist/A = a
if(check_subtypes && istype(A, datum_type))
return A
else if(A.type == datum_type)
return A
/datum/mind/proc/can_hold_antag_datum(datum_type)
if(!datum_type)
return
. = TRUE
if(has_antag_datum(datum_type))
return FALSE
for(var/i in antag_datums)
var/datum/antagonist/A = i
if(is_type_in_typecache(A, A.typecache_datum_blacklist))
return FALSE
*/
/datum/mind/proc/find_syndicate_uplink()
var/list/L = current.get_contents()
@@ -1251,7 +1284,7 @@
return null
/datum/mind/proc/take_uplink()
var/obj/item/device/uplink/hidden/H = find_syndicate_uplink()
var/obj/item/uplink/hidden/H = find_syndicate_uplink()
if(H)
qdel(H)
@@ -1273,7 +1306,7 @@
else
current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"
special_role = SPECIAL_ROLE_NUKEOPS
assigned_role = "MODE"
assigned_role = SPECIAL_ROLE_NUKEOPS
to_chat(current, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
ticker.mode.forge_syndicate_objectives(src)
ticker.mode.greet_syndicate(src)
@@ -1308,7 +1341,7 @@
if(!(src in ticker.mode.wizards))
ticker.mode.wizards += src
special_role = SPECIAL_ROLE_WIZARD
assigned_role = "MODE"
assigned_role = SPECIAL_ROLE_WIZARD
//ticker.mode.learn_basic_spells(current)
if(!wizardstart.len)
current.loc = pick(latejoin)
@@ -1380,7 +1413,7 @@
ticker.mode.greet_revolutionary(src,0)
var/list/L = current.get_contents()
var/obj/item/device/flash/flash = locate() in L
var/obj/item/flash/flash = locate() in L
qdel(flash)
take_uplink()
var/fail = 0
@@ -1514,7 +1547,7 @@
var/datum/objective/protect/mindslave/MS = new
MS.owner = src
MS.target = missionary.mind
MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role=="MODE" ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]."
objectives += MS
for(var/datum/objective/objective in objectives)
to_chat(current, "<B>Objective #1</B>: [objective.explanation_text]")
@@ -1537,16 +1570,15 @@
jumpsuit.color = team_color
H.update_inv_w_uniform(0,0)
add_logs(missionary, current, "converted", addition = "for [convert_duration/600] minutes")
addtimer(src, "remove_zealot", convert_duration, FALSE, jumpsuit) //deconverts after the timer expires
add_attack_logs(missionary, current, "Converted to a zealot for [convert_duration/600] minutes")
addtimer(CALLBACK(src, .proc/remove_zealot, jumpsuit), convert_duration) //deconverts after the timer expires
return 1
/datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null)
if(!zealot_master) //if they aren't a zealot, we can't remove their zealot status, obviously. don't bother with the rest so we don't confuse them with the messages
return
ticker.mode.remove_traitor_mind(src)
add_logs(zealot_master, current, "lost control of", addition = "as their zealot master")
add_attack_logs(zealot_master, current, "Lost control of zealot")
zealot_master = null
if(jumpsuit)
-63
View File
@@ -1,63 +0,0 @@
// module datum.
// this is per-object instance, and shows the condition of the modules in the object
// actual modules needed is referenced through modulestypes and the object type
/datum/module
var/status // bits set if working, 0 if broken
var/installed // bits set if installed, 0 if missing
// moduletypes datum
// this is per-object type, and shows the modules needed for a type of object
/datum/moduletypes
var/list/modcount = list() // assoc list of the count of modules for a type
var/list/modules = list( // global associative list
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
/datum/module/New(var/obj/O)
var/type = O.type // the type of the creating object
var/mneed = mods.inmodlist(type) // find if this type has modules defined
if(!mneed) // not found in module list?
qdel(src) // delete self, thus ending proc
return
var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
status = needed
installed = needed
/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
modules += type // index by type text
modules[type] = modtextlist
/datum/moduletypes/proc/inmodlist(var/type)
return ("[type]" in modules)
/datum/moduletypes/proc/getbitmask(var/type)
var/count = modcount["[type]"]
if(count)
return 2**count-1
var/modtext = modules["[type]"]
var/num = 1
var/pos = 1
while(1)
pos = findtext(modtext, ",", pos, 0)
if(!pos)
break
else
pos++
num++
modcount += "[type]"
modcount["[type]"] = num
return 2**num-1
+88 -72
View File
@@ -32,12 +32,12 @@
belt = /obj/item/storage/belt/utility/full/multitool
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
id = /obj/item/card/id/syndicate
r_pocket = /obj/item/device/radio/uplink
r_pocket = /obj/item/radio/uplink
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/card/emag = 1,
/obj/item/reagent_containers/food/snacks/syndidonkpocket = 1
)
@@ -55,12 +55,12 @@
if(istype(I))
apply_to_card(I, H, get_syndicate_access(id_access), name, id_icon)
var/obj/item/device/radio/uplink/U = H.r_store
var/obj/item/radio/uplink/U = H.r_store
if(istype(U))
U.hidden_uplink.uplink_owner = "[H.key]"
U.hidden_uplink.uses = uplink_uses
var/obj/item/device/radio/R = H.l_ear
var/obj/item/radio/R = H.l_ear
if(istype(R))
R.set_frequency(SYND_FREQ)
@@ -71,11 +71,11 @@
glasses = /obj/item/clothing/glasses/hud/security/chameleon
shoes = /obj/item/clothing/shoes/syndigaloshes
r_pocket = null
pda = /obj/item/device/pda
pda = /obj/item/pda
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/reagent_containers/food/snacks/syndidonkpocket = 1
)
@@ -100,7 +100,7 @@
belt = /obj/item/storage/belt/military
head = /obj/item/clothing/head/helmet/space/hardsuit/syndi
mask = /obj/item/clothing/mask/gas/syndicate
l_ear = /obj/item/device/radio/headset/syndicate/alt
l_ear = /obj/item/radio/headset/syndicate/alt
glasses = /obj/item/clothing/glasses/night
shoes = /obj/item/clothing/shoes/magboots/syndie
l_pocket = /obj/item/pinpointer/advpinpointer
@@ -114,7 +114,7 @@
/obj/item/crowbar/red = 1,
/obj/item/grenade/plastic/c4 = 1,
/obj/item/reagent_containers/food/snacks/syndidonkpocket = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/clothing/shoes/combat = 1
)
@@ -143,12 +143,13 @@
head = /obj/item/clothing/head/beret
mask = /obj/item/clothing/mask/cigarette/cigar/havana
belt = /obj/item/gun/projectile/automatic/pistol/deagle/camo
l_ear = /obj/item/device/radio/headset/syndicate/alt
l_ear = /obj/item/radio/headset/syndicate/alt
l_pocket = /obj/item/pinpointer/advpinpointer
r_pocket = null // stop them getting a radio uplink, they get an implant instead
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/reagent_containers/food/pill/initropidril = 1,
/obj/item/reagent_containers/food/snacks/syndidonkpocket = 1,
/obj/item/ammo_box/magazine/m50 = 2,
@@ -158,7 +159,6 @@
id_icon = "commander"
id_access = "Syndicate Operative Leader"
uplink_uses = 500
/datum/outfit/admin/syndicate/officer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
. = ..()
@@ -181,9 +181,9 @@
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/black
head = /obj/item/clothing/head/that
l_ear = /obj/item/device/radio/headset/ert
l_ear = /obj/item/radio/headset/ert
id = /obj/item/card/id/centcom
pda = /obj/item/device/pda
pda = /obj/item/pda
backpack_contents = list(
/obj/item/storage/box/engineer = 1
)
@@ -207,10 +207,10 @@
gloves = /obj/item/clothing/gloves/color/white
shoes = /obj/item/clothing/shoes/centcom
head = /obj/item/clothing/head/beret/centcom/captain
l_ear = /obj/item/device/radio/headset/centcom
l_ear = /obj/item/radio/headset/centcom
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
id = /obj/item/card/id/centcom
pda = /obj/item/device/pda/centcom
pda = /obj/item/pda/centcom
backpack_contents = list(
/obj/item/storage/box/centcomofficer = 1,
/obj/item/implanter/death_alarm = 1
@@ -236,11 +236,11 @@
back = /obj/item/storage/backpack/satchel
gloves = /obj/item/clothing/gloves/color/white
shoes = /obj/item/clothing/shoes/centcom
l_ear = /obj/item/device/radio/headset/centcom
l_ear = /obj/item/radio/headset/centcom
id = /obj/item/card/id/centcom
r_pocket = /obj/item/lighter/zippo/nt_rep
l_pocket = /obj/item/storage/fancy/cigarettes/dromedaryco
pda = /obj/item/device/pda/centcom
pda = /obj/item/pda/centcom
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/implanter/death_alarm = 1,
@@ -269,12 +269,12 @@
belt = /obj/item/storage/belt/utility/full/multitool
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/syndigaloshes
l_ear = /obj/item/device/radio/headset/heads/captain
l_ear = /obj/item/radio/headset/heads/captain
id = /obj/item/card/id/syndicate
pda = /obj/item/device/pda
pda = /obj/item/pda
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/gun/projectile/automatic/proto = 1, // NT saber SMG
/obj/item/suppressor = 1, // silencer for SMG
/obj/item/ammo_box/magazine/smgm9mm = 3, // SMG ammo
@@ -304,7 +304,7 @@
I.icon_state = "deathsquad"
var/obj/item/device/radio/R = H.l_ear
var/obj/item/radio/R = H.l_ear
if(istype(R))
R.name = "radio headset"
R.icon_state = "headset"
@@ -358,15 +358,15 @@
shoes = /obj/item/clothing/shoes/magboots/vox
head = /obj/item/clothing/head/helmet/space/vox/carapace
mask = /obj/item/clothing/mask/gas/syndicate
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
glasses = /obj/item/clothing/glasses/thermal/monocle
id = /obj/item/card/id/syndicate/vox
l_pocket = /obj/item/melee/classic_baton/telescopic
r_pocket = /obj/item/tank/emergency_oxygen/vox
backpack_contents = list(
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/restraints/handcuffs/cable/zipties = 1,
/obj/item/device/flash = 1,
/obj/item/flash = 1,
/obj/item/gun/energy/noisecannon = 1
)
@@ -396,7 +396,7 @@
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/clown_shoes
mask = /obj/item/clothing/mask/gas/clown_hat
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/thermal/monocle
id = /obj/item/card/id
l_pocket = /obj/item/reagent_containers/food/snacks/grown/banana
@@ -404,7 +404,7 @@
r_hand = /obj/item/twohanded/fireaxe
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/reagent_containers/food/drinks/bottle/bottleofbanana = 1
)
@@ -428,19 +428,19 @@
shoes = /obj/item/clothing/shoes/black
head = /obj/item/clothing/head/beret
mask = /obj/item/clothing/mask/gas/mime
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/thermal/monocle
id = /obj/item/card/id/syndicate
pda = /obj/item/device/pda/mime
pda = /obj/item/pda/mime
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing = 1,
/obj/item/toy/crayon/mime = 1,
/obj/item/storage/box/syndie_kit/caneshotgun = 1,
/obj/item/ammo_casing/shotgun/incendiary/dragonsbreath = 2,
/obj/item/device/radio/uplink = 1,
/obj/item/radio/uplink = 1,
/obj/item/reagent_containers/food/snacks/syndidonkpocket = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
/datum/outfit/admin/mime_assassin/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -454,7 +454,7 @@
if(visualsOnly)
return
var/obj/item/device/pda/PDA = H.wear_pda
var/obj/item/pda/PDA = H.wear_pda
if(istype(PDA))
PDA.owner = H.real_name
PDA.ownjob = "Mime"
@@ -471,13 +471,13 @@
back = /obj/item/storage/backpack
shoes = /obj/item/clothing/shoes/brown
mask = /obj/item/clothing/mask/gas
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
id = /obj/item/card/id
l_hand = /obj/item/storage/toolbox/mechanical
r_hand = /obj/item/flag/grey
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
/datum/outfit/admin/greytide/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -498,7 +498,7 @@
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/clothing/head/welding = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
/datum/outfit/admin/greytide/leader/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -526,7 +526,7 @@
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/clothing/head/welding = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
/datum/outfit/admin/greytide/xeno/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -560,7 +560,7 @@
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/black
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
backpack_contents = list(
/obj/item/storage/box/survival = 1
)
@@ -570,13 +570,13 @@
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
glasses = /obj/item/clothing/glasses/sunglasses
backpack_contents = list(
/obj/item/storage/box/engineer = 1,
/obj/item/card/emag = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/grenade/plastic/c4 = 2,
/obj/item/gun/projectile/revolver/mateba = 1,
/obj/item/ammo_box/a357 = 3
@@ -591,7 +591,7 @@
shoes = /obj/item/clothing/shoes/combat
head = /obj/item/clothing/head/hgpiratecap
mask = null
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
r_ear = null
glasses = /obj/item/clothing/glasses/thermal/eyepatch
id = null
@@ -613,15 +613,16 @@
uniform = /obj/item/clothing/under/solgov/rep
back = /obj/item/storage/backpack/satchel
glasses = /obj/item/clothing/glasses/hud/security/night
gloves = /obj/item/clothing/gloves/color/white
shoes = /obj/item/clothing/shoes/centcom
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset/ert
id = /obj/item/card/id/silver
r_pocket = /obj/item/lighter/zippo/blue
l_pocket = /obj/item/storage/fancy/cigarettes/cigpack_robustgold
pda = /obj/item/device/pda
pda = /obj/item/pda
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/storage/box/responseteam = 1,
/obj/item/implanter/dust = 1,
/obj/item/implanter/death_alarm = 1,
)
@@ -633,25 +634,33 @@
var/obj/item/card/id/I = H.wear_id
if(istype(I))
apply_to_card(I, H, get_centcom_access("VIP Guest"), "Solar Federation Representative")
apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
/datum/outfit/admin/solgov
name = "Solar Federation Marine"
uniform = /obj/item/clothing/under/solgov
suit = /obj/item/clothing/suit/armor/bulletproof
back = /obj/item/storage/backpack/security
belt = /obj/item/storage/belt/military/assault
head = /obj/item/clothing/head/soft/solgov
glasses = /obj/item/clothing/glasses/hud/security/night
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat
l_ear = /obj/item/radio/headset/ert
id = /obj/item/card/id
l_hand = /obj/item/gun/projectile/automatic/ar
r_pocket = /obj/item/flashlight/seclite
pda = /obj/item/pda
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/kitchen/knife/combat = 1,
/obj/item/storage/box/responseteam = 1,
/obj/item/ammo_box/magazine/m556 = 3,
/obj/item/clothing/shoes/magboots = 1
/obj/item/clothing/shoes/magboots = 1,
/obj/item/gun/projectile/automatic/pistol/m1911 = 1,
/obj/item/ammo_box/magazine/m45 = 2
)
var/is_tsf_lieutenant = FALSE
/datum/outfit/admin/solgov/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -659,9 +668,14 @@
if(visualsOnly)
return
if(is_tsf_lieutenant)
H.real_name = "Lieutenant [pick(last_names)]"
else
H.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]"
H.name = H.real_name
var/obj/item/card/id/I = H.wear_id
if(istype(I))
apply_to_card(I, H, get_centcom_access("VIP Guest"), name)
apply_to_card(I, H, get_all_accesses(), name, "lifetimeid")
/datum/outfit/admin/solgov/lieutenant
name = "Solar Federation Lieutenant"
@@ -670,14 +684,16 @@
head = /obj/item/clothing/head/soft/solgov/command
back = /obj/item/storage/backpack/satchel
l_hand = null
belt = /obj/item/gun/projectile/automatic/pistol/deagle
l_pocket = /obj/item/pinpointer/advpinpointer
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/kitchen/knife/combat = 1,
/obj/item/storage/box/responseteam = 1,
/obj/item/melee/classic_baton/telescopic = 1,
/obj/item/ammo_box/magazine/m50 = 2,
/obj/item/clothing/shoes/magboots/advance = 1
/obj/item/clothing/shoes/magboots/advance = 1,
/obj/item/gun/projectile/automatic/pistol/deagle = 1,
/obj/item/ammo_box/magazine/m50 = 2
)
is_tsf_lieutenant = TRUE
/datum/outfit/admin/chrono
name = "Chrono Legionnaire"
@@ -711,7 +727,7 @@
shoes = /obj/item/clothing/shoes/magboots
head = /obj/item/clothing/head/helmet/space
mask = /obj/item/clothing/mask/breath
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
id = /obj/item/card/id
/datum/outfit/admin/spacegear/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -854,7 +870,7 @@
back = /obj/item/storage/backpack
gloves = /obj/item/clothing/gloves/color/latex
shoes = /obj/item/clothing/shoes/white
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
id = /obj/item/card/id
backpack_contents = list(
/obj/item/storage/box/survival = 1
@@ -884,7 +900,7 @@
shoes = /obj/item/clothing/shoes/white
head = /obj/item/clothing/head/welding
mask = /obj/item/clothing/mask/surgical
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
glasses = /obj/item/clothing/glasses/thermal/monocle
id = /obj/item/card/id/syndicate
l_pocket = /obj/item/kitchen/knife
@@ -892,7 +908,7 @@
r_hand = /obj/item/twohanded/fireaxe
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
/datum/outfit/admin/masked_killer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -920,7 +936,7 @@
shoes = /obj/item/clothing/shoes/magboots
head = /obj/item/clothing/head/helmet/space/hardsuit/singuloth
mask = /obj/item/clothing/mask/breath
l_ear = /obj/item/device/radio/headset/ert
l_ear = /obj/item/radio/headset/ert
glasses = /obj/item/clothing/glasses/meson/cyber
id = /obj/item/card/id
suit_store = /obj/item/tank/oxygen
@@ -942,15 +958,15 @@
back = /obj/item/storage/backpack
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/black
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
glasses = /obj/item/clothing/glasses/sunglasses
id = /obj/item/card/id/syndicate
l_pocket = /obj/item/melee/energy/sword/saber
l_hand = /obj/item/storage/secure/briefcase/reaper
pda = /obj/item/device/pda/heads
pda = /obj/item/pda/heads
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1
/obj/item/flashlight = 1
)
implants = list(
/obj/item/implant/dust
@@ -961,7 +977,7 @@
if(visualsOnly)
return
var/obj/item/device/pda/PDA = H.wear_pda
var/obj/item/pda/PDA = H.wear_pda
if(istype(PDA))
PDA.owner = H.real_name
PDA.ownjob = "Reaper"
@@ -978,18 +994,18 @@
back = /obj/item/storage/backpack
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/black
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
glasses = /obj/item/clothing/glasses/hud/security/chameleon
id = /obj/item/card/id/syndicate
l_pocket = /obj/item/melee/energy/sword/saber
r_pocket = /obj/item/pen/sleepy
pda = /obj/item/device/pda/heads
pda = /obj/item/pda/heads
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/gun/projectile/automatic/pistol = 1,
/obj/item/suppressor = 1,
/obj/item/card/emag = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
/obj/item/implanter/storage = 1 // do not auto-implant this, that causes a bug
)
implants = list(
@@ -1005,7 +1021,7 @@
if(istype(G))
G.name = "black gloves"
var/obj/item/device/pda/PDA = H.wear_pda
var/obj/item/pda/PDA = H.wear_pda
if(istype(PDA))
PDA.owner = H.real_name
PDA.ownjob = "Spy"
@@ -1023,12 +1039,12 @@
back = /obj/item/storage/backpack
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/black
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
id = /obj/item/card/id/syndicate
l_hand = /obj/item/twohanded/dualsaber/red
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
)
/datum/outfit/admin/dark_lord/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
@@ -1052,7 +1068,7 @@
back = /obj/item/storage/backpack
shoes = /obj/item/clothing/shoes/sandal
head = /obj/item/clothing/head/wizard
l_ear = /obj/item/device/radio/headset
l_ear = /obj/item/radio/headset
id = /obj/item/card/id
r_pocket = /obj/item/teleportation_scroll
l_hand = /obj/item/twohanded/staff
@@ -1127,12 +1143,12 @@
head = /obj/item/clothing/head/chaplain_hood
gloves = /obj/item/clothing/gloves/color/black
shoes = /obj/item/clothing/shoes/black
l_ear = /obj/item/device/radio/headset/syndicate
l_ear = /obj/item/radio/headset/syndicate
id = /obj/item/card/id/syndicate
r_hand = /obj/item/nullrod/armblade
backpack_contents = list(
/obj/item/storage/box/survival = 1,
/obj/item/device/flashlight = 1,
/obj/item/flashlight = 1,
)
implants = list(
/obj/item/implant/dust
@@ -1150,6 +1166,6 @@
B.force = 20
B.name = "blessing of the reaper"
B.desc = "Sometimes, someone's just gotta die."
var/obj/item/device/radio/headset/R = H.l_ear
var/obj/item/radio/headset/R = H.l_ear
if(istype(R))
R.flags |= NODROP
+3 -3
View File
@@ -140,13 +140,13 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
var/obj/effect/proc_holder/spell/noclothes/clothes_spell = locate() in (user.mob_spell_list | (user.mind ? user.mind.spell_list : list()))
if((ishuman(user) && clothes_req) && !istype(clothes_spell))//clothes check
var/mob/living/carbon/human/H = user
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/wizard) && !istype(H.wear_suit, /obj/item/clothing/suit/space/eva/plasmaman/wizard))
to_chat(user, "<span class='notice'>I don't feel strong enough without my robe.</span>")
return 0
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal))
to_chat(user, "<span class='notice'>I don't feel strong enough without my sandals.</span>")
return 0
if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) && !istype(H.wear_suit, /obj/item/clothing/head/helmet/space/eva/plasmaman/wizard))
to_chat(user, "<span class='notice'>I don't feel strong enough without my hat.</span>")
return 0
else if(!ishuman(user))
@@ -218,7 +218,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
before_cast(targets)
invocation()
if(user && user.ckey)
user.create_attack_log("<font color='red'>[user.real_name] ([user.ckey]) cast the spell [name].</font>")
user.create_attack_log("<font color='red'>[key_name(user)] cast the spell [name].</font>")
spawn(0)
if(charge_type == "recharge" && recharge)
start_recharge()
+1 -1
View File
@@ -60,7 +60,7 @@
invocation_type = "none"
range = 0
summon_type = list(/obj/item/device/soulstone)
summon_type = list(/obj/item/soulstone)
/obj/effect/proc_holder/spell/aoe_turf/conjure/pylon
name = "Cult Pylon"
+1 -1
View File
@@ -26,7 +26,7 @@
if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains
to_chat(target, "<span class='warning'>You are somehow too bound to your current location to abandon it.</span>")
continue
addtimer(src, "do_jaunt", 0, FALSE, target)
INVOKE_ASYNC(src, .proc/do_jaunt, target)
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
target.notransform = 1
+1 -1
View File
@@ -76,7 +76,7 @@
var/obj/item/brain/B = new /obj/item/brain(target.loc)
B.transfer_identity(C)
C.death()
add_logs(target, C, "magically debrained", addition="INTENT: [uppertext(target.a_intent)]")*/
add_attack_logs(target, C, "Magically debrained INTENT: [uppertext(target.a_intent)]")*/
if(C.stomach_contents && item_to_retrive in C.stomach_contents)
C.stomach_contents -= item_to_retrive
for(var/X in C.bodyparts)
+48 -48
View File
@@ -115,8 +115,8 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/clothing/suit/fire/firefighter,
/obj/item/clothing/mask/gas,
/obj/item/clothing/mask/gas,
/obj/item/device/flashlight,
/obj/item/device/flashlight,
/obj/item/flashlight,
/obj/item/flashlight,
/obj/item/tank/oxygen/red,
/obj/item/tank/oxygen/red,
/obj/item/extinguisher,
@@ -252,10 +252,10 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/security/forensics
name = "Forensics Crate"
contains = list(/obj/item/device/detective_scanner,
contains = list(/obj/item/detective_scanner,
/obj/item/storage/box/evidence,
/obj/item/device/camera,
/obj/item/device/taperecorder,
/obj/item/camera,
/obj/item/taperecorder,
/obj/item/toy/crayon/white,
/obj/item/clothing/head/det_hat)
cost = 20
@@ -845,9 +845,9 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/science/robotics
name = "Robotics Assembly Crate"
contains = list(/obj/item/device/assembly/prox_sensor,
/obj/item/device/assembly/prox_sensor,
/obj/item/device/assembly/prox_sensor,
contains = list(/obj/item/assembly/prox_sensor,
/obj/item/assembly/prox_sensor,
/obj/item/assembly/prox_sensor,
/obj/item/storage/toolbox/electrical,
/obj/item/storage/box/flashes,
/obj/item/stock_parts/cell/high,
@@ -879,15 +879,15 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
contains = list(/obj/item/tank/plasma,
/obj/item/tank/plasma,
/obj/item/tank/plasma,
/obj/item/device/assembly/igniter,
/obj/item/device/assembly/igniter,
/obj/item/device/assembly/igniter,
/obj/item/device/assembly/prox_sensor,
/obj/item/device/assembly/prox_sensor,
/obj/item/device/assembly/prox_sensor,
/obj/item/device/assembly/timer,
/obj/item/device/assembly/timer,
/obj/item/device/assembly/timer)
/obj/item/assembly/igniter,
/obj/item/assembly/igniter,
/obj/item/assembly/igniter,
/obj/item/assembly/prox_sensor,
/obj/item/assembly/prox_sensor,
/obj/item/assembly/prox_sensor,
/obj/item/assembly/timer,
/obj/item/assembly/timer,
/obj/item/assembly/timer)
cost = 10
containertype = /obj/structure/closet/crate/secure/plasma
containername = "plasma assembly crate"
@@ -908,8 +908,8 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/science/transfer_valves
name = "Tank Transfer Valves Crate"
contains = list(/obj/item/device/transfer_valve,
/obj/item/device/transfer_valve)
contains = list(/obj/item/transfer_valve,
/obj/item/transfer_valve)
cost = 60
containertype = /obj/structure/closet/crate/secure/scisec
containername = "tank transfer valves crate"
@@ -917,7 +917,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/science/prototype
name = "Machine Prototype Crate"
contains = list(/obj/item/device/machineprototype)
contains = list(/obj/item/machineprototype)
cost = 80
containertype = /obj/structure/closet/crate/secure/scisec
containername = "machine prototype crate"
@@ -1089,7 +1089,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/obj/item/reagent_containers/glass/bottle/ammonia,
/obj/item/hatchet,
/obj/item/cultivator,
/obj/item/device/plant_analyzer,
/obj/item/plant_analyzer,
/obj/item/clothing/gloves/botanic_leather,
/obj/item/clothing/suit/apron) // Updated with new things
cost = 15
@@ -1236,8 +1236,8 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/materials/plastic30
name = "30 Plastic Sheets Crate"
contains = list(/obj/item/stack/sheet/plastic)
amount = 30
cost = 25
amount = 50
cost = 10
containername = "plastic sheets crate"
//////////////////////////////////////////////////////////////////////////////
@@ -1305,7 +1305,7 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/misc/paper
name = "Bureaucracy Crate"
contains = list(/obj/structure/filingcabinet/chestdrawer,
/obj/item/device/camera_film,
/obj/item/camera_film,
/obj/item/hand_labeler,
/obj/item/stack/tape_roll,
/obj/item/paper_bin,
@@ -1324,21 +1324,21 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/misc/toner
name = "Toner Cartridges Crate"
contains = list(/obj/item/device/toner,
/obj/item/device/toner,
/obj/item/device/toner,
/obj/item/device/toner,
/obj/item/device/toner,
/obj/item/device/toner)
contains = list(/obj/item/toner,
/obj/item/toner,
/obj/item/toner,
/obj/item/toner,
/obj/item/toner,
/obj/item/toner)
cost = 10
containername = "toner cartridges crate"
/datum/supply_packs/misc/artscrafts
name = "Arts and Crafts Supplies Crate"
contains = list(/obj/item/storage/fancy/crayons,
/obj/item/device/camera,
/obj/item/device/camera_film,
/obj/item/device/camera_film,
/obj/item/camera,
/obj/item/camera_film,
/obj/item/camera_film,
/obj/item/storage/photo_album,
/obj/item/stack/packageWrap,
/obj/item/reagent_containers/glass/paint/red,
@@ -1525,16 +1525,16 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
/datum/supply_packs/misc/bigband
name = "Big band instrument collection"
contains = list(/obj/item/device/instrument/violin,
/obj/item/device/instrument/guitar,
/obj/item/device/instrument/eguitar,
/obj/item/device/instrument/glockenspiel,
/obj/item/device/instrument/accordion,
/obj/item/device/instrument/saxophone,
/obj/item/device/instrument/trombone,
/obj/item/device/instrument/recorder,
/obj/item/device/instrument/harmonica,
/obj/item/device/instrument/xylophone,
contains = list(/obj/item/instrument/violin,
/obj/item/instrument/guitar,
/obj/item/instrument/eguitar,
/obj/item/instrument/glockenspiel,
/obj/item/instrument/accordion,
/obj/item/instrument/saxophone,
/obj/item/instrument/trombone,
/obj/item/instrument/recorder,
/obj/item/instrument/harmonica,
/obj/item/instrument/xylophone,
/obj/structure/piano)
cost = 50
containername = "Big band musical instruments collection"
@@ -1642,11 +1642,11 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
name = "DNA Vault Samplers"
cost = 30
special = TRUE
contains = list(/obj/item/device/dna_probe,
/obj/item/device/dna_probe,
/obj/item/device/dna_probe,
/obj/item/device/dna_probe,
/obj/item/device/dna_probe
contains = list(/obj/item/dna_probe,
/obj/item/dna_probe,
/obj/item/dna_probe,
/obj/item/dna_probe,
/obj/item/dna_probe
)
containername = "dna samplers crate"

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