mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 23:53:47 +01:00
Merge remote-tracking branch 'upstream/master' into face_lock
# Conflicts: # code/modules/mob/mob.dm
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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--
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
@@ -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
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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")
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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.")
|
||||
@@ -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]"
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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 ********************/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,7 +0,0 @@
|
||||
datum
|
||||
computer
|
||||
var/name
|
||||
folder
|
||||
var/list/datum/computer/contents = list()
|
||||
|
||||
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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user