fixes merge conflict

This commit is contained in:
Kyep
2020-09-16 06:54:30 -07:00
66 changed files with 747 additions and 1609 deletions
@@ -1,94 +0,0 @@
//--------------------------------------------
// Omni device port types
//--------------------------------------------
#define ATM_NONE 0
#define ATM_INPUT 1
#define ATM_OUTPUT 2
#define ATM_O2 3
#define ATM_N2 4
#define ATM_CO2 5
#define ATM_P 6 //Plasma
#define ATM_N2O 7
//--------------------------------------------
// Omni port datum
//
// Used by omni devices to manage connections
// to other atmospheric objects.
//--------------------------------------------
/datum/omni_port
var/obj/machinery/atmospherics/omni/master
var/dir
var/update = 1
var/mode = 0
var/concentration = 0
var/con_lock = 0
var/transfer_moles = 0
var/datum/gas_mixture/air
var/obj/machinery/atmospherics/node
var/datum/pipeline/parent
/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH)
..()
dir = direction
if(istype(M))
master = M
air = new
air.volume = 200
/datum/omni_port/proc/connect()
if(node)
return
master.atmos_init()
if(node)
node.atmos_init()
node.addMember(master)
master.build_network()
/datum/omni_port/proc/disconnect()
if(node)
node.disconnect(master)
node = null
master.nullifyPipenet(parent)
//--------------------------------------------
// Need to find somewhere else for these
//--------------------------------------------
//returns a text string based on the direction flag input
// if capitalize is true, it will return the string capitalized
// otherwise it will return the direction string in lower case
/proc/dir_name(var/dir, var/capitalize = 0)
var/string = null
switch(dir)
if(NORTH)
string = "North"
if(SOUTH)
string = "South"
if(EAST)
string = "East"
if(WEST)
string = "West"
if(!capitalize && string)
string = lowertext(string)
return string
//returns a direction flag based on the string passed to it
// case insensitive
/proc/dir_flag(var/dir)
dir = lowertext(dir)
switch(dir)
if("north")
return NORTH
if("south")
return SOUTH
if("east")
return EAST
if("west")
return WEST
else
return 0
@@ -1,273 +0,0 @@
//--------------------------------------------
// Gas filter - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/filter
name = "omni gas filter"
icon_state = "map_filter"
var/list/o_filters = new()
var/datum/omni_port/input
var/datum/omni_port/output
/obj/machinery/atmospherics/omni/filter/Destroy()
input = null
output = null
o_filters.Cut()
return ..()
/obj/machinery/atmospherics/omni/filter/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(input == P)
input = null
if(o_filters.Find(P))
o_filters -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
input = P
if(ATM_OUTPUT)
output = P
if(ATM_O2 to ATM_N2O)
o_filters += P
/obj/machinery/atmospherics/omni/filter/error_check()
if(!input || !output || !o_filters)
return 1
if(o_filters.len < 1 || o_filters.len > 2) //requires 1 or 2 o_filters ~otherwise why are you using a filter?
return 1
return 0
/obj/machinery/atmospherics/omni/filter/process_atmos()
..()
if(!on)
return 0
if(!input || !output)
return 0
var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference
var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug*
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure)
return 1
for(var/datum/omni_port/P in o_filters)
if(P.air.return_pressure() >= target_pressure)
return 1
var/pressure_delta = target_pressure - output_pressure
if(input_air.return_temperature() > 0)
input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION)
if(input.transfer_moles > 0)
var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles)
if(!removed)
return 1
for(var/datum/omni_port/P in o_filters)
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.return_temperature()
switch(P.mode)
if(ATM_O2)
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(ATM_N2)
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(ATM_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(ATM_P)
filtered_out.toxins = removed.toxins
removed.toxins = 0
filtered_out.agent_b = removed.agent_b
removed.agent_b = 0
if(ATM_N2O)
filtered_out.sleeping_agent = removed.sleeping_agent
removed.sleeping_agent = 0
else
filtered_out = null
P.air.merge(filtered_out)
P.parent.update = 1
output_air.merge(removed)
output.parent.update = 1
input.transfer_moles = 0
input.parent.update = 1
return 1
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
usr.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
ui.open()
/obj/machinery/atmospherics/omni/filter/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["power"] = on
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
var/filter = 1
var/f_type = null
switch(P.mode)
if(ATM_INPUT)
input = 1
filter = 0
if(ATM_OUTPUT)
output = 1
filter = 0
if(ATM_O2 to ATM_N2O)
f_type = mode_send_switch(P.mode)
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"input" = input, \
"output" = output, \
"filter" = filter, \
"f_type" = f_type)
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
return data
/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE)
switch(mode)
if(ATM_O2)
return "Oxygen"
if(ATM_N2)
return "Nitrogen"
if(ATM_CO2)
return "Carbon Dioxide"
if(ATM_P)
return "Plasma" //*cough* Plasma *cough*
if(ATM_N2O)
return "Nitrous Oxide"
else
return null
/obj/machinery/atmospherics/omni/filter/Topic(href, href_list)
if(..())
return 1
switch(href_list["command"])
if("power")
if(!configuring)
on = !on
else
on = 0
if("configure")
configuring = !configuring
if(configuring)
on = 0
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"]))
if("switch_filter")
var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Plasma", "Nitrous Oxide")
switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode)
switch(mode)
if("Oxygen")
return ATM_O2
if("Nitrogen")
return ATM_N2
if("Carbon Dioxide")
return ATM_CO2
if("Plasma")
return ATM_P
if("Nitrous Oxide")
return ATM_N2O
if("in")
return ATM_INPUT
if("out")
return ATM_OUTPUT
if("None")
return ATM_NONE
else
return null
/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode)
//check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file
for(var/datum/omni_port/P in ports)
if(P.dir == dir)
if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT)
return
switch_mode(dir, mode)
/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode)
if(mode == null || !port)
return
var/datum/omni_port/target_port = null
var/list/other_ports = new()
for(var/datum/omni_port/P in ports)
if(P.dir == port)
target_port = P
else
other_ports += P
var/previous_mode = null
if(target_port)
previous_mode = target_port.mode
target_port.mode = mode
if(target_port.mode != previous_mode)
handle_port_change(target_port)
else
return
else
return
for(var/datum/omni_port/P in other_ports)
if(P.mode == mode)
var/old_mode = P.mode
P.mode = previous_mode
if(P.mode != old_mode)
handle_port_change(P)
update_ports()
/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
@@ -1,291 +0,0 @@
//--------------------------------------------
// Gas mixer - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/mixer
name = "omni gas mixer"
icon_state = "map_mixer"
var/list/inputs = new()
var/datum/omni_port/output
//setup tags for initial concentration values (must be decimal)
var/tag_north_con
var/tag_south_con
var/tag_east_con
var/tag_west_con
/obj/machinery/atmospherics/omni/mixer/New()
..()
if(mapper_set())
var/con = 0
for(var/datum/omni_port/P in ports)
switch(P.dir)
if(NORTH)
if(tag_north_con && tag_north == 1)
P.concentration = tag_north_con
con += max(0, tag_north_con)
if(SOUTH)
if(tag_south_con && tag_south == 1)
P.concentration = tag_south_con
con += max(0, tag_south_con)
if(EAST)
if(tag_east_con && tag_east == 1)
P.concentration = tag_east_con
con += max(0, tag_east_con)
if(WEST)
if(tag_west_con && tag_west == 1)
P.concentration = tag_west_con
con += max(0, tag_west_con)
//mappers who are bad at maths will be punished (total concentration must be 100%)
if(con != 1)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
/obj/machinery/atmospherics/omni/mixer/Destroy()
inputs.Cut()
output = null
return ..()
/obj/machinery/atmospherics/omni/mixer/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(inputs.Find(P))
inputs -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
inputs += P
if(ATM_OUTPUT)
output = P
if(!mapper_set())
for(var/datum/omni_port/P in inputs)
P.concentration = 1 / max(1, inputs.len)
if(output)
output.air.volume *= 0.75 * inputs.len
output.concentration = 1
/obj/machinery/atmospherics/omni/mixer/proc/mapper_set()
return (tag_north_con || tag_south_con || tag_east_con || tag_west_con)
/obj/machinery/atmospherics/omni/mixer/error_check()
if(!output || !inputs)
return 1
if(inputs.len < 2 || inputs.len > 3) //requires 2 or 3 inputs ~otherwise why are you using a mixer?
return 1
return 0
/obj/machinery/atmospherics/omni/mixer/process_atmos()
..()
if(!on)
return 0
var/datum/gas_mixture/output_air = output.air
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure * 0.999)
//No need to mix if target is already full! - 0.1% margin of error so we minimize processing minor gas volumes
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_pressure
for(var/datum/omni_port/P in inputs)
if(P.air.return_temperature() > 0)
P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION)
var/ratio_check = null
for(var/datum/omni_port/P in inputs)
if(!P.transfer_moles)
return 1
if(P.air.total_moles() < P.transfer_moles)
ratio_check = 1
continue
if(ratio_check)
var/list/ratio_list = new()
for(var/datum/omni_port/P in inputs)
ratio_list.Add(P.air.total_moles() / P.transfer_moles)
var/ratio = min(ratio_list)
for(var/datum/omni_port/P in inputs)
P.transfer_moles *= ratio
for(var/datum/omni_port/P in inputs)
if(P.transfer_moles > 0)
output_air.merge(P.air.remove(P.transfer_moles))
P.parent.update = 1
P.transfer_moles = 0
output.parent.update = 1
return 1
/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
usr.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
ui.open()
/obj/machinery/atmospherics/omni/mixer/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["power"] = on
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
switch(P.mode)
if(ATM_INPUT)
input = 1
if(ATM_OUTPUT)
output = 1
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"concentration" = P.concentration, \
"input" = input, \
"output" = output, \
"con_lock" = P.con_lock)
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
return data
/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list)
if(..())
return 1
switch(href_list["command"])
if("power")
if(!configuring)
on = !on
else
on = 0
if("configure")
configuring = !configuring
if(configuring)
on = 0
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), href_list["mode"])
if("switch_con")
change_concentration(dir_flag(href_list["dir"]))
if("switch_conlock")
con_lock(dir_flag(href_list["dir"]))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE)
if(mode != ATM_INPUT && mode != ATM_OUTPUT)
switch(mode)
if("in")
mode = ATM_INPUT
if("out")
mode = ATM_OUTPUT
else
mode = ATM_NONE
for(var/datum/omni_port/P in ports)
var/old_mode = P.mode
if(P.dir == port)
switch(mode)
if(ATM_INPUT)
if(P.mode == ATM_OUTPUT)
return
P.mode = mode
if(ATM_OUTPUT)
P.mode = mode
if(ATM_NONE)
if(P.mode == ATM_OUTPUT)
return
if(P.mode == ATM_INPUT && inputs.len > 2)
P.mode = mode
else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT)
P.mode = ATM_INPUT
if(P.mode != old_mode)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
var/old_con = 0
var/non_locked = 0
var/remain_con = 1
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
old_con = P.concentration
else if(!P.con_lock)
non_locked++
else
remain_con -= P.concentration
//return if no adjustable ports
if(non_locked < 1)
return
var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100
//cap it between 0 and the max remaining concentration
new_con = between(0, new_con, remain_con)
//new_con = min(remain_con, new_con)
//clamp remaining concentration so we don't go into negatives
remain_con = max(0, remain_con - new_con)
//distribute remaining concentration between unlocked ports evenly
remain_con /= max(1, non_locked)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.concentration = new_con
else if(!P.con_lock)
P.concentration = remain_con
/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.con_lock = !P.con_lock
@@ -1,302 +0,0 @@
//--------------------------------------------
// Base omni device
//--------------------------------------------
/obj/machinery/atmospherics/omni
name = "omni device"
icon = 'icons/atmos/omni_devices.dmi'
icon_state = "base"
use_power = IDLE_POWER_USE
initialize_directions = 0
can_unwrench = 1
var/on = 0
var/configuring = 0
var/target_pressure = ONE_ATMOSPHERE
var/tag_north = ATM_NONE
var/tag_south = ATM_NONE
var/tag_east = ATM_NONE
var/tag_west = ATM_NONE
var/overlays_on[5]
var/overlays_off[5]
var/overlays_error[2]
var/underlays_current[4]
var/list/ports = new()
/obj/machinery/atmospherics/omni/New()
..()
icon_state = "base"
ports = new()
for(var/d in GLOB.cardinal)
var/datum/omni_port/new_port = new(src, d)
switch(d)
if(NORTH)
new_port.mode = tag_north
if(SOUTH)
new_port.mode = tag_south
if(EAST)
new_port.mode = tag_east
if(WEST)
new_port.mode = tag_west
if(new_port.mode > 0)
initialize_directions |= d
ports += new_port
build_icons()
/obj/machinery/atmospherics/omni/Destroy()
for(var/datum/omni_port/P in ports)
if(P.node)
P.node.disconnect(src)
P.node = null
nullifyPipenet(P.parent)
return ..()
/obj/machinery/atmospherics/omni/atmos_init()
..()
for(var/datum/omni_port/P in ports)
if(P.node || P.mode == 0)
continue
for(var/obj/machinery/atmospherics/target in get_step(src, P.dir))
if(target.initialize_directions & get_dir(target,src))
P.node = target
break
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/update_icon()
..()
if(stat & NOPOWER)
overlays = overlays_off
on = 0
else if(error_check())
overlays = overlays_error
on = 0
else
overlays = on ? (overlays_on) : (overlays_off)
underlays = underlays_current
/obj/machinery/atmospherics/omni/proc/error_check()
return
/obj/machinery/atmospherics/omni/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/omni/attackby(var/obj/item/W as obj, var/mob/user as mob, params)
if(!istype(W, /obj/item/wrench))
return ..()
if(can_unwrench)
var/int_pressure = 0
for(var/datum/omni_port/P in ports)
int_pressure += P.air.return_pressure()
var/datum/gas_mixture/env_air = loc.return_air()
if((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
to_chat(user, "<span class='danger'>You cannot unwrench [src], it is too exerted due to internal pressure.</span>")
add_fingerprint(user)
return 1
playsound(loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if(do_after(user, 40 * W.toolspeed, target = src))
user.visible_message( \
"[user] unfastens \the [src].", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
else
return ..()
/obj/machinery/atmospherics/omni/attack_hand(mob/user)
if(..())
return
add_fingerprint(usr)
ui_interact(user)
/obj/machinery/atmospherics/omni/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/atmospherics/omni/proc/build_icons()
if(!check_icon_cache())
return
var/core_icon = null
if(istype(src, /obj/machinery/atmospherics/omni/mixer))
core_icon = "mixer"
else if(istype(src, /obj/machinery/atmospherics/omni/filter))
core_icon = "filter"
else
return
//directional icons are layers 1-4, with the core icon on layer 5
if(core_icon)
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] = 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())
return
for(var/datum/omni_port/P in ports)
if(P.update)
var/ref_layer = 0
switch(P.dir)
if(NORTH)
ref_layer = 1
if(SOUTH)
ref_layer = 2
if(EAST)
ref_layer = 3
if(WEST)
ref_layer = 4
if(!ref_layer)
continue
var/list/port_icons = select_port_icons(P)
if(port_icons)
if(P.node)
underlays_current[ref_layer] = port_icons["pipe_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = port_icons["off_icon"]
overlays_on[ref_layer] = port_icons["on_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = null
overlays_on[ref_layer] = null
update_icon()
/obj/machinery/atmospherics/omni/proc/select_port_icons(var/datum/omni_port/P)
if(!istype(P))
return
if(P.mode > 0)
var/ic_dir = dir_name(P.dir)
var/ic_on = ic_dir
var/ic_off = ic_dir
switch(P.mode)
if(ATM_INPUT)
ic_on += "_in_glow"
ic_off += "_in"
if(ATM_OUTPUT)
ic_on += "_out_glow"
ic_off += "_out"
if(ATM_O2 to ATM_N2O)
ic_on += "_filter"
ic_off += "_out"
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 = 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 = 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)
/obj/machinery/atmospherics/omni/update_underlays()
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/omni/proc/update_ports()
sort_ports()
update_port_icons()
for(var/datum/omni_port/P in ports)
P.update = 0
/obj/machinery/atmospherics/omni/proc/sort_ports()
return
// Pipenet procs
/obj/machinery/atmospherics/omni/build_network(remove_deferral = FALSE)
for(var/datum/omni_port/P in ports)
if(!P.parent)
P.parent = new /datum/pipeline()
P.parent.build_pipeline(src)
..()
/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference)
for(var/datum/omni_port/P in ports)
if(reference == P.node)
if(istype(P.node, /obj/machinery/atmospherics/pipe))
qdel(P.parent)
P.node = null
update_ports()
/obj/machinery/atmospherics/omni/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
for(var/datum/omni_port/PO in ports)
if(P == PO.parent)
PO.parent.other_airs -= PO.air
PO.parent = null
/obj/machinery/atmospherics/omni/returnPipenetAir(datum/pipeline/P)
for(var/datum/omni_port/PO in ports)
if(P == PO.parent)
return PO.air
/obj/machinery/atmospherics/omni/pipeline_expansion(datum/pipeline/P)
if(P)
for(var/datum/omni_port/PO in ports)
if(PO.parent == P)
return list(PO.node)
else
var/list/nodes = list()
for(var/datum/omni_port/PO in ports)
nodes += PO.node
return nodes
/obj/machinery/atmospherics/omni/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
for(var/datum/omni_port/PO in ports)
if(A == PO.node)
PO.parent = P
/obj/machinery/atmospherics/omni/returnPipenet(obj/machinery/atmospherics/A)
for(var/datum/omni_port/P in ports)
if(A == P.node)
return P.parent
/obj/machinery/atmospherics/omni/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
for(var/datum/omni_port/P in ports)
if(Old == P.parent)
P.parent = New
/obj/machinery/atmospherics/omni/process_atmos()
..()
for(var/datum/omni_port/port in ports)
if(!port.parent)
return 0
return 1
@@ -1,26 +1,39 @@
/// Nothing will be filtered.
#define FILTER_NOTHING -1
/// Plasma, and Oxygen Agent B.
#define FILTER_TOXINS 0
/// Oxygen only.
#define FILTER_OXYGEN 1
/// Nitrogen only.
#define FILTER_NITROGEN 2
/// Carbon dioxide only.
#define FILTER_CO2 3
/// Nitrous oxide only.
#define FILTER_N2O 4
/obj/machinery/atmospherics/trinary/filter
name = "gas filter"
icon = 'icons/atmos/filter.dmi'
icon_state = "map"
can_unwrench = 1
name = "gas filter"
can_unwrench = TRUE
/// The amount of pressure the filter wants to operate at.
var/target_pressure = ONE_ATMOSPHERE
var/filter_type = 0
/*
Filter types:
-1: Nothing
0: Toxins: Toxins, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen ONLY
3: Carbon Dioxide: Carbon Dioxide ONLY
4: Sleeping Agent (N2O)
*/
var/frequency = 0
/// The type of gas we want to filter. Valid values that go here are from the `FILTER` defines at the top of the file.
var/filter_type = FILTER_NOTHING
/// The frequency of the filter. Used with `radio_connection`.
var/frequency = NONE
/// A reference to the filter's `datum/radio_frequency`.
var/datum/radio_frequency/radio_connection
/// A list of available filter options. Used with `tgui_data`.
var/list/filter_list = list(
"Nothing" = FILTER_NOTHING,
"Plasma" = FILTER_TOXINS,
"O2" = FILTER_OXYGEN,
"N2" = FILTER_NITROGEN,
"CO2" = FILTER_CO2,
"N2O" = FILTER_N2O
)
/obj/machinery/atmospherics/trinary/filter/CtrlClick(mob/living/user)
if(!istype(user) || user.incapacitated())
@@ -146,26 +159,26 @@ Filter types:
filtered_out.temperature = removed.temperature
switch(filter_type)
if(0) //removing hydrocarbons
if(FILTER_TOXINS)
filtered_out.toxins = removed.toxins
removed.toxins = 0
filtered_out.agent_b = removed.agent_b
removed.agent_b = 0
if(1) //removing O2
if(FILTER_OXYGEN)
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(2) //removing N2
if(FILTER_NITROGEN)
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(3) //removing CO2
if(FILTER_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(4)//removing N2O
if(FILTER_N2O)
filtered_out.sleeping_agent = removed.sleeping_agent
removed.sleeping_agent = 0
else
@@ -188,7 +201,7 @@ Filter types:
..()
/obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user)
if(..())
@@ -199,53 +212,56 @@ Filter types:
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/filter/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/trinary/filter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_filter.tmpl", name, 475, 155, state = state)
ui = new(user, src, ui_key, "AtmosFilter", name, 380, 140, master_ui, state)
ui.open()
/obj/machinery/atmospherics/trinary/filter/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
data["filter_type"] = filter_type
/obj/machinery/atmospherics/trinary/filter/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"pressure" = round(target_pressure),
"max_pressure" = round(MAX_OUTPUT_PRESSURE),
"filter_type" = filter_type
)
data["filter_type_list"] = list()
for(var/label in filter_list)
data["filter_type_list"] += list(list("label" = label, "gas_type" = filter_list[label]))
return data
/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
/obj/machinery/atmospherics/trinary/filter/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if(href_list["filter"])
filter_type = text2num(href_list["filter"])
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
. = TRUE
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
update_icon()
SSnanoui.update_uis(src)
if("set_filter")
filter_type = text2num(params["filter"])
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
return TRUE
if("max_pressure")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_pressure")
target_pressure = 0
. = TRUE
if("custom_pressure")
target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/trinary/filter/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
-17
View File
@@ -33,7 +33,6 @@
//var/list/underlays_intact[]
//var/list/pipe_underlays_exposed[]
//var/list/pipe_underlays_intact[]
var/list/omni_icons[]
/datum/pipe_icon_manager/New()
check_icons()
@@ -53,8 +52,6 @@
return manifold_icons[state + color]
if("device")
return device_icons[state]
if("omni")
return omni_icons[state]
if("underlay")
return underlays[state + dir + color]
//if("underlay_intact")
@@ -75,8 +72,6 @@
gen_manifold_icons()
if(!device_icons)
gen_device_icons()
if(!omni_icons)
gen_omni_icons()
//if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact)
if(!underlays)
gen_underlay_icons()
@@ -150,18 +145,6 @@
continue
device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_omni_icons()
if(!omni_icons)
omni_icons = new()
var/icon/omni = new('icons/atmos/omni_devices.dmi')
for(var/state in omni.IconStates())
if(!state || findtext(state, "map"))
continue
omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_underlay_icons()
if(!underlays)
-2
View File
@@ -21,8 +21,6 @@
#define PIPE_TVALVE 18
#define PIPE_MANIFOLD4W 19
#define PIPE_CAP 20
#define PIPE_OMNI_MIXER 21
#define PIPE_OMNI_FILTER 22
#define PIPE_UNIVERSAL 23
#define PIPE_SUPPLY_STRAIGHT 24
#define PIPE_SUPPLY_BENT 25
+2 -2
View File
@@ -48,7 +48,7 @@
#define INIT_ORDER_GARBAGE 21
#define INIT_ORDER_DBCORE 20
#define INIT_ORDER_BLACKBOX 19
#define INIT_ORDER_SERVER_MAINT 18
#define INIT_ORDER_CLEANUP 18
#define INIT_ORDER_INPUT 17
#define INIT_ORDER_SOUNDS 16
#define INIT_ORDER_INSTRUMENTS 15
@@ -90,7 +90,7 @@
#define FIRE_PRIORITY_NANOMOB 10
#define FIRE_PRIORITY_NIGHTSHIFT 10
#define FIRE_PRIORITY_IDLE_NPC 10
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_CLEANUP 10
#define FIRE_PRIORITY_TICKETS 10
#define FIRE_PRIORITY_RESEARCH 10
#define FIRE_PRIORITY_GARBAGE 15
+44
View File
@@ -0,0 +1,44 @@
/**
* # Cleanup Subsystem
*
* For now, all it does is periodically clean the supplied global lists of any null values they may contain.
*
* Why is this important?
*
* Sometimes, these lists can gain nulls due to errors.
* For example, when a dead player trasitions from the `dead_mob_list` to the `alive_mob_list`, a null value may get stuck in the dead mob list.
* This can cause issues when other code tries to do things with the values in the list, but are instead met with null values.
* These problems are incredibly hard to track down and fix, so this subsystem is a solution to that.
*/
SUBSYSTEM_DEF(cleanup)
name = "Null cleanup"
wait = 30 SECONDS
flags = SS_POST_FIRE_TIMING
priority = FIRE_PRIORITY_CLEANUP
init_order = INIT_ORDER_CLEANUP
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
offline_implications = "Certain global lists will no longer be cleared of nulls, which may result in runtimes. No immediate action is needed."
/// A list of global lists we want the subsystem to clean.
var/list/lists_to_clean
/datum/controller/subsystem/cleanup/Initialize(start_timeofday)
// If you want this subsystem to clean out nulls from a specific list, add it here.
lists_to_clean = list(
GLOB.clients = "clients",
GLOB.player_list = "player_list",
GLOB.mob_list = "mob_list",
GLOB.alive_mob_list = "alive_mob_list",
GLOB.dead_mob_list = "dead_mob_list",
GLOB.human_list = "human_list",
GLOB.carbon_list = "carbon_list"
)
return ..()
/datum/controller/subsystem/cleanup/fire(resumed)
for(var/L in lists_to_clean)
var/list/_list = L
var/prev_length = length(_list)
listclearnulls(_list)
if(length(_list) < prev_length)
stack_trace("Found a null value in GLOB.[lists_to_clean[_list]]!")
+4
View File
@@ -191,6 +191,10 @@
..()
desc = "That's Definitely Not [M.real_name]."
/datum/dog_fashion/head/cone
name = "REAL_NAME"
desc = "Omnicone's Chosen Champion"
/datum/dog_fashion/back/hardsuit
name = "Space Explorer REAL_NAME"
desc = "That's one small step for a corgi. One giant yap for corgikind."
-10
View File
@@ -351,16 +351,6 @@ GLOBAL_LIST_EMPTY(rpd_pipe_list) //Some pipes we don't want to be dispensable
pipe_id = PIPE_CIRCULATOR
pipe_icon = "circ"
/datum/pipes/atmospheric/omni_filter
pipe_name = "omni filter"
pipe_id = PIPE_OMNI_FILTER
pipe_icon = "omni_filter"
/datum/pipes/atmospheric/omni_mixer
pipe_name = "omni mixer"
pipe_id = PIPE_OMNI_MIXER
pipe_icon = "omni_mixer"
/datum/pipes/atmospheric/insulated
pipe_name = "insulated pipe"
pipe_id = PIPE_INSULATED_STRAIGHT
+1 -1
View File
@@ -75,7 +75,7 @@
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/fireball/hellish/cast(list/targets, mob/living/user = usr)
msg_admin_attack("[key_name_admin(usr)] has fired a fireball.", ATKLOG_FEW)
add_attack_logs(user, targets, "has fired a Hellfire ball", ATKLOG_FEW)
.=..()
+2 -14
View File
@@ -106,10 +106,6 @@
else if(istype(make_from, /obj/machinery/atmospherics/unary/passive_vent))
src.pipe_type = PIPE_PASV_VENT
else if(istype(make_from, /obj/machinery/atmospherics/omni/mixer))
src.pipe_type = PIPE_OMNI_MIXER
else if(istype(make_from, /obj/machinery/atmospherics/omni/filter))
src.pipe_type = PIPE_OMNI_FILTER
else if(istype(make_from, /obj/machinery/atmospherics/binary/circulator))
src.pipe_type = PIPE_CIRCULATOR
@@ -259,7 +255,7 @@
return dir //dir|acw
if(PIPE_CONNECTOR, PIPE_UVENT, PIPE_PASV_VENT, PIPE_SCRUBBER, PIPE_HEAT_EXCHANGE, PIPE_INJECTOR)
return dir|flip
if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER)
if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W)
return dir|flip|cw|acw
if(PIPE_MANIFOLD, PIPE_SUPPLY_MANIFOLD, PIPE_SCRUBBERS_MANIFOLD)
return flip|cw|acw
@@ -317,7 +313,7 @@
dir = 1
else if(dir==8)
dir = 4
else if(pipe_type in list(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER))
else if(pipe_type in list(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W))
dir = 2
/obj/item/pipe/attack_self(mob/user as mob)
@@ -499,14 +495,6 @@
P.name = pipename
P.on_construction(dir, pipe_dir, color)
if(PIPE_OMNI_MIXER)
var/obj/machinery/atmospherics/omni/mixer/P = new(loc)
P.on_construction(dir, pipe_dir, color)
if(PIPE_OMNI_FILTER)
var/obj/machinery/atmospherics/omni/filter/P = new(loc)
P.on_construction(dir, pipe_dir, color)
user.visible_message( \
"[user] fastens the [src].", \
"<span class='notice'>You have fastened the [src].</span>", \
+2 -2
View File
@@ -260,9 +260,9 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
if(payload && !istype(payload, /obj/item/bombcore/training))
msg_admin_attack("[key_name_admin(user)] has primed a [name] ([payload]) for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.", ATKLOG_FEW)
log_game("[key_name(user)] has primed a [name] ([payload]) for detonation at [A.name] [COORD(bombturf)]")
investigate_log("[key_name(user)] has has primed a [name] ([payload]) for detonation at [A.name] [COORD(bombturf)]", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has primed a [name] ([payload]) for detonation", ATKLOG_FEW)
payload.adminlog = "\The [src] that [key_name(user)] had primed detonated!"
///Bomb Subtypes///
@@ -652,8 +652,8 @@
var/turf/T = get_turf(src)
var/area/A = get_area(T)
detonated--
message_admins("[key_name_admin(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>[A.name] (JMP)</a>.")
investigate_log("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using", ATKLOG_FEW)
log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])")
detonated = 0
existant = 0
+239 -203
View File
@@ -1,16 +1,24 @@
#define REGIME_TELEPORT 0
#define REGIME_GATE 1
#define REGIME_GPS 2
/obj/machinery/computer/teleporter
name = "teleporter control console"
desc = "Used to control a linked teleportation Hub and Station."
icon_screen = "teleport"
icon_keyboard = "teleport_key"
circuit = /obj/item/circuitboard/teleporter
var/obj/item/gps/locked = null
var/regime_set = "Teleporter"
var/obj/item/gps/locked = null /// A GPS with a locked destination
var/regime = REGIME_TELEPORT /// Switches mode between teleporter, gate and gps
var/id = null
var/obj/machinery/teleport/station/power_station
var/calibrating
var/turf/target //Used for one-time-use teleport cards (such as clown planet coordinates.)
//Setting this to 1 will set src.locked to null after a player enters the portal and will not allow hand-teles to open portals to that location.
var/obj/machinery/teleport/station/power_station /// The power station that's connected to the console
var/calibrating = FALSE /// Whether calibration is in progress or not. Calibration prevents changes.
var/turf/target ///The target turf of the teleporter
var/target_list ///lists of suitable teleport targets, dependent on regime. Used in the UI
/* var/area_bypass is for one-time-use teleport cards (such as clown planet coordinates.)
Setting this to TRUE will set var/obj/item/gps/locked to null after a player enters the portal and will not allow hand-teles to open portals to that location.
*/
var/area_bypass = FALSE
var/cc_beacon = FALSE
@@ -24,6 +32,7 @@
..()
link_power_station()
update_icon()
target_list = targets_teleport()
/obj/machinery/computer/teleporter/Destroy()
if(power_station)
@@ -55,202 +64,238 @@
/obj/machinery/computer/teleporter/emag_act(mob/user)
if(!emagged)
emagged = 1
emagged = TRUE
to_chat(user, "<span class='notice'>The teleporter can now lock on to Syndicate beacons!</span>")
else
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/teleporter/attack_ai(mob/user)
src.attack_hand(user)
attack_hand(user)
/obj/machinery/computer/teleporter/attack_hand(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/obj/machinery/computer/teleporter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
if(stat & (NOPOWER|BROKEN))
return
// Set up the Nano UI
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "teleporter_console.tmpl", "Teleporter Console UI", 400, 400)
ui = new(user, src, ui_key, "Teleporter", "Teleporter Console", 380, 260)
ui.open()
/obj/machinery/computer/teleporter/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/computer/teleporter/tgui_data(mob/user)
var/list/data = list()
data["powerstation"] = power_station
if(power_station?.teleporter_hub)
data["teleporterhub"] = power_station.teleporter_hub
data["calibrated"] = power_station.teleporter_hub.calibrated
data["accurate"] = power_station.teleporter_hub.accurate
else
data["teleporterhub"] = null
data["calibrated"] = null
data["accurate"] = null
data["regime"] = regime_set
data["regime"] = regime
var/area/targetarea = get_area(target)
data["target"] = (!target || !targetarea) ? "None" : sanitize(targetarea.name)
data["calibrating"] = calibrating
data["locked"] = locked
data["locked"] = locked ? TRUE : FALSE
data["targetsTeleport"] = target_list
return data
/obj/machinery/computer/teleporter/Topic(href, href_list)
/obj/machinery/computer/teleporter/tgui_act(action, params)
if(..())
return 1
if(href_list["eject"])
eject()
SSnanoui.update_uis(src)
return
if(!check_hub_connection())
to_chat(usr, "<span class='warning'>Error: Unable to detect hub.</span>")
SSnanoui.update_uis(src)
atom_say("Error: Unable to detect hub.")
return
if(calibrating)
to_chat(usr, "<span class='warning'>Error: Calibration in progress. Stand by.</span>")
SSnanoui.update_uis(src)
atom_say("Error: Calibration in progress. Stand by.")
return
if(href_list["regimeset"])
power_station.engaged = 0
power_station.teleporter_hub.update_icon()
power_station.teleporter_hub.calibrated = 0
reset_regime()
SSnanoui.update_uis(src)
if(href_list["settarget"])
power_station.engaged = 0
power_station.teleporter_hub.update_icon()
power_station.teleporter_hub.calibrated = 0
set_target(usr)
SSnanoui.update_uis(src)
if(href_list["lock"])
power_station.engaged = 0
power_station.teleporter_hub.update_icon()
power_station.teleporter_hub.calibrated = 0
target = get_turf(locked.locked_location)
SSnanoui.update_uis(src)
if(href_list["calibrate"])
if(!target)
to_chat(usr, "<span class='warning'>Error: No target set to calibrate to.</span>")
SSnanoui.update_uis(src)
return
if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3)
to_chat(usr, "<span class='notice'>Hub is already calibrated.</span>")
SSnanoui.update_uis(src)
return
src.visible_message("<span class='notice'>Processing hub calibration to target...</span>")
. = TRUE
calibrating = 1
SSnanoui.update_uis(src)
spawn(50 * (3 - power_station.teleporter_hub.accurate)) //Better parts mean faster calibration
calibrating = 0
if(check_hub_connection())
power_station.teleporter_hub.calibrated = 1
src.visible_message("<span class='notice'>Calibration complete.</span>")
else
src.visible_message("<span class='warning'>Error: Unable to detect hub.</span>")
SSnanoui.update_uis(src)
switch(action)
if("eject") //eject gps device
eject()
if("load") //load gps coordinates
target = locate(locked.locked_location.x,locked.locked_location.y,locked.locked_location.z)
if("setregime")
regime = text2num(params["regime"])
if(regime == REGIME_TELEPORT)
target_list = targets_teleport()
if(regime == REGIME_GATE)
target_list = targets_gate()
if(regime == REGIME_GPS)
target_list = null //clears existing entries, target is added by load action
resetPowerstation()
target = null
if("settarget")
resetPowerstation()
var/turf/tmpTarget = locate(text2num(params["x"]),text2num(params["y"]),text2num(params["z"]))
if(!istype(tmpTarget, /turf))
atom_say("No valid targets available.")
return
target = tmpTarget
if(regime == REGIME_TELEPORT)
teleport_helper()
if(regime == REGIME_GATE)
gate_helper()
if("calibrate")
if(!target)
atom_say("Error: No target set to calibrate to.")
return
if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3)
atom_say("Hub is already calibrated.")
return
SSnanoui.update_uis(src)
atom_say("Processing hub calibration to target...")
calibrating = TRUE
addtimer(CALLBACK(src, .proc/calibrateCallback), 50 * (3 - power_station.teleporter_hub.accurate)) //Better parts mean faster calibration
/**
* Resets the connected powerstation to initial values. Helper function of tgui_act
*/
/obj/machinery/computer/teleporter/proc/resetPowerstation()
power_station.engaged = FALSE
power_station.teleporter_hub.calibrated = FALSE
power_station.teleporter_hub.update_icon()
/**
* Calibrates the hub. Helper function of tgui_act
*/
/obj/machinery/computer/teleporter/proc/calibrateCallback()
calibrating = FALSE
if(check_hub_connection())
power_station.teleporter_hub.calibrated = TRUE
atom_say("Calibration complete.")
else
atom_say("Error: Unable to detect hub.")
/obj/machinery/computer/teleporter/proc/check_hub_connection()
if(!power_station)
return
if(!power_station.teleporter_hub)
return
return 1
/obj/machinery/computer/teleporter/proc/reset_regime()
target = null
if(regime_set == "Teleporter")
regime_set = "Gate"
else
regime_set = "Teleporter"
return TRUE
/**
* Helper function of tgui_act
*
* Triggered when ejecting a gps device. Sets the gps to the ground and resets the console
*/
/obj/machinery/computer/teleporter/proc/eject()
if(locked)
locked.loc = loc
locked = null
regime = REGIME_TELEPORT
target_list = targets_teleport()
/obj/machinery/computer/teleporter/proc/set_target(mob/user)
area_bypass = FALSE
if(regime_set == "Teleporter")
var/list/L = list()
var/list/areaindex = list()
/**
* Creates a list of viable targets for the teleport. Helper function of tgui_data
*/
/obj/machinery/computer/teleporter/proc/targets_teleport()
var/list/L = list()
var/list/areaindex = list()
for(var/obj/item/radio/beacon/R in GLOB.beacons)
var/turf/T = get_turf(R)
if(!T)
continue
if(!is_teleport_allowed(T.z) && !R.cc_beacon)
continue
if(R.syndicate == 1 && emagged == 0)
continue
var/tmpname = T.loc.name
for(var/obj/item/radio/beacon/R in GLOB.beacons)
var/turf/T = get_turf(R)
if(!T)
continue
if(!is_teleport_allowed(T.z) && !R.cc_beacon)
continue
if(R.syndicate && !emagged)
continue
var/tmpname = T.loc.name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
L[tmpname] = list(
"name" = tmpname,
"x" = T.x,
"y" = T.y,
"z" = T.z)
for(var/obj/item/implant/tracking/I in GLOB.tracked_implants)
if(!I.implanted || !ismob(I.loc))
continue
else
var/mob/M = I.loc
if(M.stat == DEAD)
if(M.timeofdeath + 6000 < world.time)
continue
var/turf/T = get_turf(M)
if(!T) continue
if(!is_teleport_allowed(T.z)) continue
var/tmpname = M.real_name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
L[tmpname] = R
L[tmpname] = list(
"name" = tmpname,
"x" = T.x,
"y" = T.y,
"z" = T.z)
return L
for(var/obj/item/implant/tracking/I in GLOB.tracked_implants)
if(!I.implanted || !ismob(I.loc))
continue
else
var/mob/M = I.loc
if(M.stat == DEAD)
if(M.timeofdeath + 6000 < world.time)
continue
var/turf/T = get_turf(M)
if(!T) continue
if(!is_teleport_allowed(T.z)) continue
var/tmpname = M.real_name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
L[tmpname] = I
/**
* Creates a list of viable targets for the gate. Helper function of tgui_data
*/
/obj/machinery/computer/teleporter/proc/targets_gate(mob/users)
var/list/L = list()
var/list/areaindex = list()
var/list/S = power_station.linked_stations
if(!S.len)
return L
for(var/obj/machinery/teleport/station/R in S)
var/turf/T = get_turf(R)
if(!T || !R.teleporter_hub || !R.teleporter_console)
continue
if(!is_teleport_allowed(T.z))
continue
var/tmpname = T.loc.name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
L[tmpname] = list(
"name" = tmpname,
"x" = T.x,
"y" = T.y,
"z" = T.z)
return L
var/desc = input("Please select a location to lock in.", "Locking Computer") in L
target = L[desc]
if(istype(target, /obj/item/radio/beacon))
var/obj/item/radio/beacon/B = target
/**
* Helper function of tgui_act.
*
* Called after selecting a target for the gate in the UI. Sets area_bypass and cc_beacon.
*/
/obj/machinery/computer/teleporter/proc/teleport_helper()
area_bypass = FALSE
for(var/item in target.contents)
if(istype(item, /obj/item/radio/beacon))
var/obj/item/radio/beacon/B = item
if(B.area_bypass)
area_bypass = TRUE
cc_beacon = B.cc_beacon
else
var/list/L = list()
var/list/areaindex = list()
var/list/S = power_station.linked_stations
if(!S.len)
to_chat(user, "<span class='alert'>No connected stations located.</span>")
return
for(var/obj/machinery/teleport/station/R in S)
var/turf/T = get_turf(R)
if(!T || !R.teleporter_hub || !R.teleporter_console)
continue
if(!is_teleport_allowed(T.z))
continue
var/tmpname = T.loc.name
if(areaindex[tmpname])
tmpname = "[tmpname] ([++areaindex[tmpname]])"
else
areaindex[tmpname] = 1
L[tmpname] = R
var/desc = input("Please select a station to lock in.", "Locking Computer") in L
target = L[desc]
if(target)
var/obj/machinery/teleport/station/trg = target
trg.linked_stations |= power_station
trg.stat &= ~NOPOWER
if(trg.teleporter_hub)
trg.teleporter_hub.stat &= ~NOPOWER
trg.teleporter_hub.update_icon()
if(trg.teleporter_console)
trg.teleporter_console.stat &= ~NOPOWER
trg.teleporter_console.update_icon()
return
/**
* Helper function of tgui_act.
*
* Called after selecting a target for the teleporter in the UI.
*/
/obj/machinery/computer/teleporter/proc/gate_helper()
area_bypass = FALSE
var/obj/machinery/teleport/station/trg = target
trg.linked_stations |= power_station
trg.stat &= ~NOPOWER
if(trg.teleporter_hub)
trg.teleporter_hub.stat &= ~NOPOWER
trg.teleporter_hub.update_icon()
if(trg.teleporter_console)
trg.teleporter_console.stat &= ~NOPOWER
trg.teleporter_console.update_icon()
/proc/find_loc(obj/R as obj)
if(!R) return null
@@ -263,20 +308,20 @@
/obj/machinery/teleport
name = "teleport"
icon = 'icons/obj/stationobjs.dmi'
density = 1
anchored = 1.0
density = TRUE
anchored = TRUE
/obj/machinery/teleport/hub
name = "teleporter hub"
desc = "It's the hub of a teleporting machine."
icon_state = "tele0"
var/accurate = 0
var/accurate = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 2000
var/obj/machinery/teleport/station/power_station
var/calibrated //Calibration prevents mutation
var/admin_usage = 0 // if 1, works on z2. If 0, doesn't. Used for admin room teleport.
var/admin_usage = FALSE // if 1, works on z2. If 0, doesn't. Used for admin room teleport.
/obj/machinery/teleport/hub/New()
..()
@@ -317,6 +362,7 @@
for(dir in list(NORTH,EAST,SOUTH,WEST))
power_station = locate(/obj/machinery/teleport/station, get_step(src, dir))
if(power_station)
power_station.link_console_and_hub()
break
return power_station
@@ -324,27 +370,12 @@
if(!is_teleport_allowed(z) && !admin_usage)
to_chat(M, "You can't use this here.")
return
if(power_station && power_station.engaged && !panel_open)
//--FalseIncarnate
//Prevents AI cores from using the teleporter, prints out failure messages for clarity
if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore))
visible_message("<span class='warning'>The teleporter rejects the AI unit.</span>")
if(istype(M, /mob/living/silicon/ai))
var/mob/living/silicon/ai/T = M
var/list/TPError = list("<span class='warning'>Firmware instructions dictate you must remain on your assigned station!</span>",
"<span class='warning'>You cannot interface with this technology and get rejected!</span>",
"<span class='warning'>External firewalls prevent you from utilizing this machine!</span>",
"<span class='warning'>Your AI core's anti-bluespace failsafes trigger and prevent teleportation!</span>")
to_chat(T, "[pick(TPError)]")
return
else
if(!teleport(M) && isliving(M)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub
visible_message("<span class='warning'>[src] emits a loud buzz, as its teleport portal flickers and fails!</span>")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
power_station.toggle() // turn off the portal.
use_power(5000)
//--FalseIncarnate
if(power_station && power_station.engaged && !panel_open && !blockAI(M) && !istype(M, /obj/spacepod))
if(!teleport(M) && isliving(M)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub
visible_message("<span class='warning'>[src] emits a loud buzz, as its teleport portal flickers and fails!</span>")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
power_station.toggle() // turn off the portal.
use_power(5000)
return
/obj/machinery/teleport/hub/attackby(obj/item/I, mob/user, params)
@@ -375,7 +406,7 @@
. = do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2, bypass_area_flag = com.area_bypass)
else
. = do_teleport(M, com.target, bypass_area_flag = com.area_bypass)
calibrated = 0
calibrated = FALSE
/obj/machinery/teleport/hub/update_icon()
if(panel_open)
@@ -389,7 +420,7 @@
name = "permanent teleporter"
desc = "A teleporter with the target pre-set on the circuit board."
icon_state = "tele0"
var/recalibrating = 0
var/recalibrating = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 2000
@@ -406,37 +437,42 @@
tele_delay = max(A, 0)
update_icon()
/obj/machinery/teleport/perma/Bumped(M as mob|obj)
/**
Internal helper function
Prevents AI from using the teleporter, prints out failure messages for clarity
*/
/obj/machinery/teleport/proc/blockAI(atom/A)
if(istype(A, /mob/living/silicon/ai) || istype(A, /obj/structure/AIcore))
visible_message("<span class='warning'>The teleporter rejects the AI unit.</span>")
if(istype(A, /mob/living/silicon/ai))
var/mob/living/silicon/ai/T = A
var/list/TPError = list("<span class='warning'>Firmware instructions dictate you must remain on your assigned station!</span>",
"<span class='warning'>You cannot interface with this technology and get rejected!</span>",
"<span class='warning'>External firewalls prevent you from utilizing this machine!</span>",
"<span class='warning'>Your AI core's anti-bluespace failsafes trigger and prevent teleportation!</span>")
to_chat(T, "[pick(TPError)]")
return TRUE
return FALSE
/obj/machinery/teleport/perma/Bumped(atom/A)
if(stat & (BROKEN|NOPOWER))
return
if(!is_teleport_allowed(z))
to_chat(M, "You can't use this here.")
to_chat(A, "You can't use this here.")
return
if(target && !recalibrating && !panel_open)
//--FalseIncarnate
//Prevents AI cores from using the teleporter, prints out failure messages for clarity
if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore))
visible_message("<span class='warning'>The teleporter rejects the AI unit.</span>")
if(istype(M, /mob/living/silicon/ai))
var/mob/living/silicon/ai/T = M
var/list/TPError = list("<span class='warning'>Firmware instructions dictate you must remain on your assigned station!</span>",
"<span class='warning'>You cannot interface with this technology and get rejected!</span>",
"<span class='warning'>External firewalls prevent you from utilizing this machine!</span>",
"<span class='warning'>Your AI core's anti-bluespace failsafes trigger and prevent teleportation!</span>")
to_chat(T, "[pick(TPError)]")
return
else
do_teleport(M, target)
use_power(5000)
if(tele_delay)
recalibrating = 1
update_icon()
spawn(tele_delay)
recalibrating = 0
update_icon()
//--FalseIncarnate
return
if(target && !recalibrating && !panel_open && !blockAI(A))
do_teleport(A, target)
use_power(5000)
if(tele_delay)
recalibrating = TRUE
update_icon()
addtimer(CALLBACK(src, .proc/BumpedCallback), tele_delay)
/obj/machinery/teleport/perma/proc/BumpedCallback()
recalibrating = FALSE
update_icon()
/obj/machinery/teleport/perma/power_change()
..()
@@ -467,7 +503,7 @@
name = "station"
desc = "The power control station for a bluespace teleporter."
icon_state = "controller"
var/engaged = 0
var/engaged = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 2000
@@ -568,7 +604,7 @@
/obj/machinery/teleport/station/attack_ai()
src.attack_hand()
attack_hand()
/obj/machinery/teleport/station/attack_hand(mob/user)
if(!panel_open)
@@ -583,12 +619,12 @@
to_chat(user, "<span class='notice'>Close the hub's maintenance panel first.</span>")
return
if(teleporter_console.target)
src.engaged = !src.engaged
engaged = !engaged
use_power(5000)
visible_message("<span class='notice'>Teleporter [engaged ? "" : "dis"]engaged!</span>")
else
visible_message("<span class='alert'>No target detected.</span>")
src.engaged = 0
engaged = FALSE
teleporter_hub.update_icon()
if(istype(user))
add_fingerprint(user)
+3 -3
View File
@@ -60,7 +60,7 @@
set_ready_state(0)
log_message("Fired from [name], targeting [target].")
var/turf/T = get_turf(src)
msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])")
add_attack_logs(chassis.occupant, target, "fired a [src]", ATKLOG_FEW)
log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]")
do_after_cooldown()
return
@@ -238,7 +238,7 @@
chassis.use_power(energy_drain)
log_message("Honked from [name]. HONK!")
var/turf/T = get_turf(src)
msg_admin_attack("[key_name_admin(chassis.occupant)] used a Mecha Honker in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])")
add_attack_logs(chassis.occupant, target, "used a Mecha Honker", ATKLOG_MOST)
log_game("[key_name(chassis.occupant)] used a Mecha Honker in [T.x], [T.y], [T.z]")
do_after_cooldown()
return
@@ -357,7 +357,7 @@
projectiles--
log_message("Fired from [name], targeting [target].")
var/turf/T = get_turf(src)
msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])")
add_attack_logs(chassis.occupant, target, "fired a [src]", ATKLOG_FEW)
log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]")
do_after_cooldown()
return
+1 -1
View File
@@ -481,7 +481,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
var/more = ""
if(M)
more = " "
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
add_attack_logs(M, location, "Caused a chemical smoke reaction containing [contained]. Last associated key is [carry.my_atom.fingerprintslast][more]", ATKLOG_FEW)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
@@ -83,13 +83,13 @@
var/more = ""
if(M)
more = " "
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", ATKLOG_FEW)
add_attack_logs(M, location, "Caused a chemical smoke reaction containing [contained]. Last associated key is [carry.my_atom.fingerprintslast][more]", ATKLOG_FEW)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
else
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", ATKLOG_FEW)
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. No associated key.", ATKLOG_FEW)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
else
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key. CODERS: carry.my_atom may be null.", ATKLOG_FEW)
msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. No associated key. CODERS: carry.my_atom may be null.", ATKLOG_FEW)
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key. CODERS: carry.my_atom may be null.")
+1 -2
View File
@@ -83,8 +83,7 @@
if(href_list["wipe"])
var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No")
if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE))
msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].", ATKLOG_FEW)
add_attack_logs(user, AI, "Wiped with [src].")
add_attack_logs(user, AI, "Wiped with [src].", ATKLOG_FEW)
flush = 1
AI.suiciding = 1
to_chat(AI, "Your core files are being wiped!")
@@ -64,7 +64,7 @@
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB)
msg_admin_attack("[key_name_admin(user)]attached [A] to a transfer valve.", ATKLOG_FEW)
add_attack_logs(user, src, "attached [A] to a transfer valve", ATKLOG_FEW)
log_game("[key_name_admin(user)] attached [A] to a transfer valve.")
attacher = user
SSnanoui.update_uis(src) // update all UIs attached to src
@@ -128,7 +128,7 @@
if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
if("toggle")
toggle_valve()
toggle_valve(usr)
if("device")
if(attached_device)
attached_device.attack_self(usr)
@@ -190,7 +190,7 @@
it explodes properly when it gets a signal (and it does).
*/
/obj/item/transfer_valve/proc/toggle_valve()
/obj/item/transfer_valve/proc/toggle_valve(mob/user)
if(!valve_open && tank_one && tank_two)
valve_open = 1
var/turf/bombturf = get_turf(src)
@@ -207,6 +207,8 @@
investigate_log("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", INVESTIGATE_BOMB)
message_admins("Bomb valve opened at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]")
log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]")
if(user)
add_attack_logs(user, src, "Bomb valve opened with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", ATKLOG_FEW)
merge_gases()
spawn(20) // In case one tank bursts
for(var/i in 1 to 5)
+2 -2
View File
@@ -242,15 +242,15 @@
to_chat(user, "<span class='notice'>You hide [I] in the [src]. It will detonate some time after the flag is lit on fire.</span>")
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
message_admins("[key_name_admin(user)] has hidden [I] in the [src] ready for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.")
log_game("[key_name(user)] has hidden [I] in the [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).")
investigate_log("[key_name(user)] has hidden [I] in the [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has hidden [I] ready for detonation in", ATKLOG_MOST)
else if(is_hot(I) && !(resistance_flags & ON_FIRE) && boobytrap && trapper)
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
message_admins("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>.")
log_game("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).")
investigate_log("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has lit (booby trapped with [boobytrap]", ATKLOG_FEW)
burn()
else
return ..()
+1 -1
View File
@@ -189,8 +189,8 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
investigate_log("E20 detonated at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with a roll of [result]. Triggered by: [key_name(user)]", INVESTIGATE_BOMB)
message_admins("E20 detonated at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> with a roll of [result]. Triggered by: [key_name_admin(user)]")
log_game("E20 detonated at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with a roll of [result]. Triggered by: [key_name(user)]")
add_attack_logs(user, src, "detonated with a roll of [result]", ATKLOG_FEW)
/obj/item/dice/update_icon()
@@ -101,9 +101,9 @@
update_icon()
else if(clown_check(user))
// This used to go before the assembly check, but that has absolutely zero to do with priming the damn thing. You could spam the admins with it.
message_admins("[key_name_admin(usr)] has primed a [name] for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> [contained].")
log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) [contained].")
investigate_log("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])[contained].", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has primed (contained [contained])", ATKLOG_FEW)
to_chat(user, "<span class='warning'>You prime the [name]! [det_time / 10] second\s!</span>")
playsound(user.loc, 'sound/weapons/armbomb.ogg', 60, 1)
active = 1
@@ -120,7 +120,7 @@
owner.visible_message("<span class='danger'>[attack_text] hits [owner]'s [src], setting it off! What a shot!</span>")
var/turf/T = get_turf(src)
log_game("A projectile ([hitby]) detonated a grenade held by [key_name(owner)] at [COORD(T)]")
message_admins("A projectile ([hitby]) detonated a grenade held by [key_name_admin(owner)] at [ADMIN_COORDJMP(T)]")
add_attack_logs(P.firer, owner, "A projectile ([hitby]) detonated a grenade held", ATKLOG_FEW)
prime()
return 1 //It hit the grenade, not them
@@ -149,16 +149,16 @@
if(!O.reagents) continue
if(istype(O,/obj/item/slime_extract))
cores += " [O]"
for(var/reagent in O.reagents.reagent_list)
contained += " [reagent] "
for(var/R in O.reagents.reagent_list)
var/datum/reagent/reagent = R
contained += "[reagent.volume] [reagent], "
if(contained)
if(cores)
contained = "\[[cores];[contained]\]"
contained = "\[[cores]; [contained]\]"
else
contained = "\[[contained]\]"
contained = "\[ [contained]\]"
var/turf/bombturf = get_turf(loc)
var/area/A = bombturf.loc
message_admins("[key_name_admin(usr)] has completed [name] at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> [contained].")
add_attack_logs(user, src, "has completed with [contained]", ATKLOG_MOST)
log_game("[key_name(usr)] has completed [name] at [bombturf.x], [bombturf.y], [bombturf.z]. [contained]")
else
to_chat(user, "<span class='notice'>You need to add at least one beaker before locking the assembly.</span>")
@@ -48,9 +48,9 @@
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
message_admins("[ADMIN_LOOKUPFLW(user)] has primed a [name] for detonation at [ADMIN_COORDJMP(bombturf)].")
log_game("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)].")
investigate_log("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)])", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.throw_mode_on()
@@ -73,6 +73,7 @@
message_admins("[key_name_admin(usr)] has primed a [name] for detonation at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a>")
log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])")
investigate_log("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.throw_mode_on()
@@ -310,6 +310,18 @@
item_state = "utility"
use_item_overlays = 1 // So it will still show tools in it in case sec get lazy and just glance at it.
/obj/item/storage/belt/military/traitor/hacker
/obj/item/storage/belt/military/traitor/hacker/New()
..()
new /obj/item/screwdriver(src, "red")
new /obj/item/wrench(src)
new /obj/item/weldingtool/largetank(src)
new /obj/item/crowbar/red(src)
new /obj/item/wirecutters(src, "red")
new /obj/item/stack/cable_coil(src, 30, COLOR_RED)
update_icon()
/obj/item/storage/belt/grenade
name = "grenadier belt"
desc = "A belt for holding grenades."
@@ -1,7 +1,7 @@
/obj/item/storage/box/syndicate/New()
..()
switch(pickweight(list("bloodyspai" = 1, "thief" = 1, "bond" = 1, "sabotage" = 1, "payday" = 1, "implant" = 1, "hacker" = 1, "darklord" = 1, "professional" = 1)))
if("bloodyspai") // 35TC + one 0TC
if("bloodyspai") // 37TC + one 0TC
new /obj/item/clothing/under/chameleon(src) // 2TC
new /obj/item/clothing/mask/chameleon(src) // 0TC
new /obj/item/card/id/syndicate(src) // 2TC
@@ -14,12 +14,12 @@
new /obj/item/storage/fancy/cigarettes/cigpack_syndicate(src) // 2TC
new /obj/item/flashlight/emp(src) // 2TC
new /obj/item/clothing/glasses/hud/security/chameleon(src) // 2TC
new /obj/item/chameleon(src) // 8TC
new /obj/item/chameleon(src) // 7TC
return
if("thief") // 40TC
if("thief") // 39TC
new /obj/item/gun/energy/kinetic_accelerator/crossbow(src) // 12TC
new /obj/item/chameleon(src) // 8TC
new /obj/item/chameleon(src) // 7TC
new /obj/item/clothing/glasses/chameleon/thermal(src) // 6TC
new /obj/item/clothing/gloves/color/black/thief(src) // 6TC
new /obj/item/card/id/syndicate(src) // 2TC
@@ -43,7 +43,7 @@
new /obj/item/CQC_manual(src) // 13TC
return
if("sabotage") // 47TC + three 0TC
if("sabotage") // 41TC + two 0TC
new /obj/item/grenade/plastic/c4(src) // 1TC
new /obj/item/grenade/plastic/c4(src) // 1TC
new /obj/item/camera_bug(src) // 1TC
@@ -53,23 +53,23 @@
new /obj/item/card/emag(src) // 6TC
new /obj/item/clothing/gloves/color/yellow(src) // 0TC
new /obj/item/grenade/syndieminibomb(src) // 6TC
new /obj/item/grenade/clusterbuster/n2o(src) // 0TC
new /obj/item/grenade/clusterbuster/n2o(src) // 4TC
new /obj/item/storage/box/syndie_kit/space(src) // 4TC
new /obj/item/encryptionkey/syndicate(src) // 2TC
return
if("payday") // 33TC + four 0TC
if("payday") // 35TC + four 0TC
new /obj/item/gun/projectile/revolver(src) // 13TC
new /obj/item/ammo_box/a357(src) // 3TC
new /obj/item/ammo_box/a357(src) // 3TC
new /obj/item/card/emag(src) // 6TC
new /obj/item/grenade/plastic/c4(src) // 1TC
new /obj/item/jammer(src) // 5TC
new /obj/item/card/id/syndicate(src) // 2TC
new /obj/item/clothing/under/suit_jacket/really_black(src) //0TC
new /obj/item/clothing/suit/storage/lawyer/blackjacket/armored(src) //0TC
new /obj/item/clothing/gloves/color/latex/nitrile(src) //0 TC
new /obj/item/clothing/mask/gas/clown_hat(src) // 0TC
new /obj/item/thermal_drill(src) // 3TC
new /obj/item/thermal_drill/diamond_drill(src) // 1TC
new /obj/item/encryptionkey/syndicate(src) // 2TC
return
@@ -83,17 +83,20 @@
new /obj/item/encryptionkey/syndicate(src) // 2TC
return
if("hacker") // 30TC + one 0TC
if("hacker") // 37TC + two 0TC
new /obj/item/aiModule/syndicate(src) // 12TC
new /obj/item/card/emag(src) // 6TC
new /obj/item/encryptionkey/syndicate(src) // 2TC
new /obj/item/encryptionkey/binary(src) // 5TC
new /obj/item/aiModule/toyAI(src) // 0TC
new /obj/item/clothing/glasses/chameleon/thermal(src) // 6TC
new /obj/item/storage/belt/military/traitor/hacker(src) // 3TC
new /obj/item/clothing/gloves/combat(src) // 0TC
new /obj/item/multitool/ai_detect(src) // 1TC
new /obj/item/storage/box/syndie_kit/c4 // 4TC
new /obj/item/flashlight/emp(src) // 2TC
return
if("darklord") // 22TC + two 0TC
if("darklord") // 24TC + two 0TC
new /obj/item/melee/energy/sword/saber/red(src) // 8TC
new /obj/item/melee/energy/sword/saber/red(src) // 8TC
new /obj/item/dnainjector/telemut/darkbundle(src) // 0TC
@@ -104,7 +107,7 @@
new /obj/item/encryptionkey/syndicate(src) // 2TC
return
if("professional") // 32 TC + two 0TC
if("professional") // 34TC + two 0TC
new /obj/item/gun/projectile/automatic/sniper_rifle/syndicate/penetrator(src) // 16TC
new /obj/item/ammo_box/magazine/sniper_rounds/penetrator(src) // 5TC
new /obj/item/ammo_box/magazine/sniper_rounds/soporific(src) // 3TC
@@ -187,6 +187,7 @@
if(user)
to_chat(user, "<span class='danger'>The crate's anti-tamper system activates!</span>")
investigate_log("[key_name(user)] has detonated a [src]", INVESTIGATE_BOMB)
add_attack_logs(user, src, "has detonated", ATKLOG_MOST)
for(var/atom/movable/AM in src)
qdel(AM)
explosion(get_turf(src), 0, 1, 5, 5)
@@ -15,7 +15,6 @@
anchored = TRUE
resistance_flags = FIRE_PROOF | LAVA_PROOF
var/gps = null
var/obj/effect/light_emitter/tendril/emitted_light
/obj/structure/spawner/lavaland/goliath
@@ -29,7 +28,6 @@ GLOBAL_LIST_INIT(tendrils, list())
/obj/structure/spawner/lavaland/Initialize(mapload)
. = ..()
emitted_light = new(loc)
gps = new /obj/item/gps/internal(src)
GLOB.tendrils += src
return INITIALIZE_HINT_LATELOAD
@@ -59,7 +57,6 @@ GLOBAL_LIST_INIT(tendrils, list())
SSmedals.SetScore(TENDRIL_CLEAR_SCORE, L.client, 1)
GLOB.tendrils -= src
QDEL_NULL(emitted_light)
QDEL_NULL(gps)
return ..()
/obj/effect/light_emitter/tendril
+2 -1
View File
@@ -52,12 +52,13 @@
if(!status)
status = TRUE
investigate_log("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB)
msg_admin_attack("[key_name_admin(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_FEW)
log_game("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature - T0C]")
to_chat(user, "<span class='notice'>A pressure hole has been bored to [bombtank] valve. [bombtank] can now be ignited.</span>")
add_attack_logs(user, src, "welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_FEW)
else
status = FALSE
investigate_log("[key_name(user)] unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB)
add_attack_logs(user, src, "unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_ALMOSTALL)
to_chat(user, "<span class='notice'>The hole has been closed.</span>")
+1 -1
View File
@@ -101,8 +101,8 @@
if(href_list["time"])
timing = !timing
if(timing && istype(holder, /obj/item/transfer_valve))
message_admins("[key_name_admin(usr)] activated [src] attachment on [holder].")
investigate_log("[key_name(usr)] activated [src] attachment for [loc]", INVESTIGATE_BOMB)
add_attack_logs(usr, holder, "activated [src] attachment on", ATKLOG_FEW)
log_game("[key_name(usr)] activated [src] attachment for [loc]")
update_icon()
if(href_list["reset"])
+1
View File
@@ -401,6 +401,7 @@
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("warned", "cautioned", "smashed")
resistance_flags = NONE
dog_fashion = /datum/dog_fashion/head/cone
/obj/item/clothing/head/jester
name = "jester hat"
+9 -14
View File
@@ -272,15 +272,6 @@
new /obj/item/reagent_containers/food/drinks/cans/cola(src)
/obj/item/instrument/guitar/jello_guitar //Pineapple Salad: Dan Jello
name = "Dan Jello's Pink Guitar"
desc = "Dan Jello's special pink guitar."
icon = 'icons/obj/custom_items.dmi'
icon_state = "jello_guitar"
item_state = "jello_guitar"
righthand_file = 'icons/mob/inhands/fluff_righthand.dmi'
lefthand_file = 'icons/mob/inhands/fluff_lefthand.dmi'
/obj/item/fluff/wingler_comb
name = "blue comb"
desc = "A blue comb, it looks like it was made to groom a Tajaran's fur."
@@ -1592,13 +1583,17 @@
item_state = "asmer_accordion"
/obj/item/clothing/head/rabbitears/fluff/pinesalad_bunny // Pineapple Salad : Dan Jello
name = "Bluespace rabbit ears"
desc = "A pair of sparkly bluespace rabbit ears, with a small tag on them that reads, 'Dan Jello~'. Yuck, \
there's some pink slime on the part that goes on your head!"
/obj/item/clothing/head/fluff/pinesalad_horns //Pineapple Salad: Dan Jello
name = "Bluespace Horns"
desc = "A pair of fake horns. Now with added bluespace!"
icon = 'icons/obj/custom_items.dmi'
icon_state = "ps_bunny"
icon_state = "ps_horns"
/obj/item/storage/backpack/fluff/hiking //Pineapple Salad: Dan Jello
name = "\improper Fancy Hiking Pack"
desc = "A black and red hiking pack with some nice little accessories."
icon = 'icons/obj/custom_items.dmi'
icon_state = "danpack"
/obj/item/clothing/under/fluff/kiaoutfit //FullOfSkittles: Kiachi
name = "Suspicious Outfit"
@@ -127,15 +127,6 @@
description_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
//Omni filters
/obj/machinery/atmospherics/omni/filter
description_info = "Filters gas from a custom input direction, with up to two filtered outputs and a 'everything else' \
output. The filtered output's arrows glow orange."
//Omni mixers
/obj/machinery/atmospherics/omni/mixer
description_info = "Combines gas from custom input and output directions. The percentage of combined gas can be defined."
//Canisters
/obj/machinery/portable_atmospherics/canister
description_info = "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \
@@ -432,6 +432,29 @@
icon_state = "jdonut1"
extra_reagent = "cherryjelly"
//////////////////////
// Pancakes //
//////////////////////
/obj/item/reagent_containers/food/snacks/pancake
name = "pancake"
desc = "A plain pancake."
icon_state = "pancake"
filling_color = "#E7D8AB"
bitesize = 2
list_reagents = list("nutriment" = 3, "sugar" = 3)
/obj/item/reagent_containers/food/snacks/pancake/berry_pancake
name = "berry pancake"
desc = "A pancake loaded with berries."
icon_state = "berry_pancake"
list_reagents = list("nutriment" = 3, "sugar" = 3, "berryjuice" = 3)
/obj/item/reagent_containers/food/snacks/pancake/choc_chip_pancake
name = "choc-chip pancake"
desc = "A pancake loaded with chocolate chips."
icon_state = "choc_chip_pancake"
list_reagents = list("nutriment" = 3, "sugar" = 3, "cocoa" = 3)
//////////////////////
// Misc //
@@ -234,7 +234,7 @@
return
if(UserOverride)
msg_admin_attack("[key_name_admin(occupant)] was gibbed by an autogibber (\the [src]) [ADMIN_JMP(src)]")
add_attack_logs(user, occupant, "gibbed by an autogibber ([src])")
log_game("[key_name(occupant)] was gibbed by an autogibber ([src]) (X:[x] Y:[y] Z:[z])")
if(operating)
@@ -249,3 +249,23 @@
/obj/item/stack/rods,
)
result = /obj/item/reagent_containers/food/snacks/fish_skewer
/datum/recipe/grill/pancake
items = list(
/obj/item/reagent_containers/food/snacks/cookiedough
)
result = /obj/item/reagent_containers/food/snacks/pancake
/datum/recipe/grill/berry_pancake
items = list(
/obj/item/reagent_containers/food/snacks/cookiedough,
/obj/item/reagent_containers/food/snacks/grown/berries
)
result = /obj/item/reagent_containers/food/snacks/pancake/berry_pancake
/datum/recipe/grill/choc_chip_pancake
items = list(
/obj/item/reagent_containers/food/snacks/cookiedough,
/obj/item/reagent_containers/food/snacks/choc_pile
)
result = /obj/item/reagent_containers/food/snacks/pancake/choc_chip_pancake
+1 -2
View File
@@ -116,9 +116,8 @@
/obj/item/reagent_containers/food/snacks/grown/firelemon/attack_self(mob/living/user)
var/area/A = get_area(user)
user.visible_message("<span class='warning'>[user] primes the [src]!</span>", "<span class='userdanger'>You prime the [src]!</span>")
var/message = "[ADMIN_LOOKUPFLW(user)] primed a combustible lemon for detonation at [A] [ADMIN_COORDJMP(user)]"
investigate_log("[key_name(user)] primed a combustible lemon for detonation at [A] [COORD(user)].", INVESTIGATE_BOMB)
message_admins(message)
add_attack_logs(user, src, "primed a combustible lemon for detonation", ATKLOG_FEW)
log_game("[key_name(user)] primed a combustible lemon for detonation at [A] [COORD(user)].")
if(iscarbon(user))
var/mob/living/carbon/C = user
+11 -3
View File
@@ -167,6 +167,8 @@
hearing_mobs.len = 0
var/turf/source = get_turf(parent)
for(var/mob/M in GLOB.player_list)
if(M.z != source.z) // Z-level check
continue
var/dist = get_dist(M, source)
if(dist > instrument_range) // Distance check
continue
@@ -253,16 +255,20 @@
* Processes our song.
*/
/datum/song/proc/process_song(wait)
if(!length(compiled_chords) || current_chord > length(compiled_chords) || should_stop_playing(user_playing))
if(!length(compiled_chords) || should_stop_playing(user_playing))
stop_playing()
return
var/list/chord = compiled_chords[current_chord]
if(++elapsed_delay >= delay_by)
// We were sustaining the final note but not anymore
if(current_chord > length(compiled_chords))
stop_playing()
return
var/list/chord = compiled_chords[current_chord]
play_chord(chord)
elapsed_delay = 0
delay_by = tempodiv_to_delay(chord[length(chord)])
current_chord++
if(current_chord > length(compiled_chords))
if(current_chord > length(compiled_chords) + 1)
if(repeat)
repeat--
current_chord = 1
@@ -284,6 +290,8 @@
*/
/datum/song/proc/compile_chords()
legacy ? compile_legacy() : compile_synthesized()
// Some chords may be null for some reason - exclude them.
listclearnulls(compiled_chords)
/**
* Plays a chord.
+2
View File
@@ -927,6 +927,8 @@
. += T.slowdown
if(slowed)
. += 10
if(forced_look)
. += 3
if(ignorewalk)
. += config.run_speed
else
@@ -319,10 +319,9 @@
return verb
/mob/living/simple_animal/movement_delay()
. = ..()
. = speed
if(forced_look)
. += 3
. += config.animal_delay
/mob/living/simple_animal/Stat()
@@ -235,6 +235,7 @@
investigate_log("turned [active?"<font color='red'>ON</font>":"<font color='green'>OFF</font>"] by [usr ? usr.key : "outside forces"]","singulo")
if(active)
msg_admin_attack("PA Control Computer turned ON by [key_name_admin(usr)]", ATKLOG_FEW)
usr.create_log(MISC_LOG, "PA Control Computer turned ON", src)
log_game("PA Control Computer turned ON by [key_name(usr)] in ([x],[y],[z])")
use_log += text("\[[time_stamp()]\] <font color='red'>[key_name(usr)] has turned on the PA Control Computer.</font>")
if(active)
@@ -849,7 +849,7 @@
/datum/reagent/medicine/stimulants
name = "Stimulants"
id = "stimulants"
description = "Increases run speed and eliminates stuns, can heal minor damage. If overdosed it will deal toxin damage and stun."
description = "An illegal compound that dramatically enhances the body's performance and healing capabilities."
color = "#C8A5DC"
harmless = FALSE
can_synth = FALSE
@@ -886,7 +886,7 @@
/datum/reagent/medicine/stimulative_agent
name = "Stimulative Agent"
id = "stimulative_agent"
description = "An illegal compound that dramatically enhances the body's performance and healing capabilities."
description = "Increases run speed and eliminates stuns, can heal minor damage. If overdosed it will deal toxin damage and be less effective for healing stamina."
color = "#C8A5DC"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 60
@@ -57,7 +57,7 @@
var/attack_log_type = ATKLOG_MOST
if(reagents.has_reagent("sacid") || reagents.has_reagent("facid") || reagents.has_reagent("lube"))
attack_log_type = ATKLOG_FEW
msg_admin_attack("[key_name_admin(user)] used a spray bottle at [COORD(user)] - Contents: [contents_log] - Temperature: [reagents.chem_temp]K", attack_log_type)
add_attack_logs(user, A, "sprayed [contents_log] at [reagents.chem_temp]K using [src]", attack_log_type)
log_game("[key_name(user)] used a spray bottle at [COORD(user)] - Contents: [contents_log] - Temperature: [reagents.chem_temp]K")
return
+3 -6
View File
@@ -84,17 +84,15 @@
..()
if(!QDELETED(src)) //wasn't deleted by the projectile's effects.
if(!P.nodamage && ((P.damage_type == BURN) || (P.damage_type == BRUTE)))
message_admins("[key_name_admin(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)] ")
add_attack_logs(P.firer, src, "shot with [P.name]")
add_attack_logs(P.firer, src, "shot with [P.name]", ATKLOG_FEW)
log_game("[key_name(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)]")
investigate_log("[key_name(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)]", INVESTIGATE_BOMB)
boom()
/obj/structure/reagent_dispensers/fueltank/boom(rigtrigger = FALSE, log_attack = FALSE) // Prevent case where someone who rigged the tank is blamed for the explosion when the rig isn't what triggered the explosion
if(rigtrigger) // If the explosion is triggered by an assembly holder
message_admins("A fueltank, last rigged by [lastrigger], was triggered at [COORD(loc)]") // Then admin is informed of the last person who rigged the fuel tank
log_game("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]")
add_attack_logs(lastrigger, src, "rigged fuel tank exploded")
add_attack_logs(lastrigger, src, "rigged fuel tank exploded", ATKLOG_FEW)
investigate_log("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]", INVESTIGATE_BOMB)
if(log_attack)
add_attack_logs(usr, src, "blew up", ATKLOG_FEW)
@@ -142,9 +140,8 @@
var/obj/item/assembly_holder/H = I
if(istype(H.a_left, /obj/item/assembly/igniter) || istype(H.a_right, /obj/item/assembly/igniter))
msg_admin_attack("[key_name_admin(user)] rigged [src.name] with [I.name] for explosion (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)", ATKLOG_FEW)
log_game("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]")
add_attack_logs(user, src, "rigged fuel tank")
add_attack_logs(user, src, "rigged fuel tank with [I.name] for explosion", ATKLOG_FEW)
investigate_log("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]", INVESTIGATE_BOMB)
lastrigger = "[key_name(user)]"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 972 B

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 99 KiB

-24
View File
@@ -1,24 +0,0 @@
<div class="item">
<div class="itemLabel">Power:</div>
<div class="itemContent">{{:helper.link(data.on ? 'On' : 'Off', data.on ? 'power-off' : 'times', {'power' : 1}, null, data.on ? 'selected' : null)}}</div>
</div>
<div class="item">
<div class="itemLabel">Output Pressure:</div>
<div class="itemContent">
{{:helper.link('Set', 'pencil', {'pressure' : 'input'})}}
{{:helper.link('Max', 'plus', {'pressure' : 'max'}, data.pressure == data.max_pressure ? 'disabled' : null)}}
{{:helper.smoothRound(data.pressure)}} kPa
</div>
</div>
<div class="item">
<div class="itemLabel">Filter:</div>
<div class="itemContent">
{{:helper.link('Nothing', null, {'filter' : -1}, data.filter_type == -1 ? 'selected' : null)}}
{{:helper.link('Plasma', null, {'filter' : 0}, data.filter_type == 0 ? 'selected' : null)}}
{{:helper.link('O2', null, {'filter' : 1}, data.filter_type == 1 ? 'selected' : null)}}
{{:helper.link('N2', null, {'filter' : 2}, data.filter_type == 2 ? 'selected' : null)}}
{{:helper.link('CO2', null, {'filter' : 3}, data.filter_type == 3 ? 'selected' : null)}}
{{:helper.link('N2O', null, {'filter' : 4}, data.filter_type == 4 ? 'selected' : null)}}
</div>
</div>
-86
View File
@@ -1,86 +0,0 @@
<div class="item">
<div class="itemContent" style="padding: 5px">
{{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}}
</div>
<div class="itemContent" style="padding: 5px">
{{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}}
</div>
{{if data.config}}
<div style="width: 315px; text-align: center">
<div style="float: left">
<div class="white" style="height: 26">Port</div>
{{for data.ports}}
<div class="average" style="height: 26">{{:value.dir}} Port</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Input</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, null, value.input ? 'selected' : null)}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Output</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Filter</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(value.f_type ? value.f_type : 'None', null, {'command' : 'switch_filter', 'mode' : value.f_type, 'dir' : value.dir}, value.filter ? null : 'disabled', value.f_type ? 'selected' : null)}}
</div>
{{/for}}
</div>
</div>
<div class="itemContent" style="padding: 5px">
Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s
</div>
<div class="itemContent" style="padding: 5px">
{{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}}
</div>
{{else}}
<div style="width: 315px; text-align: center">
<div style="float: left">
<div class="white" style="height: 26">Port</div>
{{for data.ports}}
<div class="average" style="height: 26">{{:value.dir}} Port</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Mode</div>
{{for data.ports}}
<div style="height: 26">
{{if value.input}}
Input
{{else value.output}}
Output
{{else value.f_type}}
{{:value.f_type}}
{{else}}
Disabled
{{/if}}
</div>
{{/for}}
</div>
</div>
<div class="itemContent" style="padding: 5px">
Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s
</div>
<div class="itemContent" style="padding: 5px">
Flow Rate: {{:(data.last_flow_rate/10)}} L/s
</div>
{{/if}}
</div>
-101
View File
@@ -1,101 +0,0 @@
<div class="item">
<div class="itemContent" style="padding: 5px">
{{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}}
</div>
<div class="itemContent" style="padding: 5px">
{{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}}
</div>
{{if data.config}}
<div style="width: 315px; text-align: center">
<div style="float: left">
<div class="white" style="height: 26">Port</div>
{{for data.ports}}
<div class="average" style="height: 26">{{:value.dir}} Port</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Input</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(' ', null, value.input ? {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir} : {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, value.output ? 'disabled' : null, value.input ? 'selected' : null)}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Output</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(' ', null, value.output ? null : {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Concentration</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link( value.input ? helper.round(value.concentration*100)+' %' : '-', null, {'command' : 'switch_con', 'dir' : value.dir}, value.input ? null : 'disabled')}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Lock</div>
{{for data.ports}}
<div style="height: 26">
{{:helper.link(' ', value.con_lock ? 'lock' : 'unlock', {'command' : 'switch_conlock', 'dir' : value.dir}, value.input ? null : 'disabled', value.con_lock ? 'selected' : null)}}
</div>
{{/for}}
</div>
</div>
<div class="itemContent" style="padding: 5px">
Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s
</div>
<div class="itemContent" style="padding: 5px">
{{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}}
</div>
{{else}}
<div style="width: 315px; text-align: center">
<div style="float: left">
<div class="white" style="height: 26">Port</div>
{{for data.ports}}
<div class="average" style="height: 26">{{:value.dir}} Port</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Mode</div>
{{for data.ports}}
<div style="height: 26">
{{if value.input}}
Input
{{else value.output}}
Output
{{else}}
Disabled
{{/if}}
</div>
{{/for}}
</div>
<div style="float: left; margin-left: 10">
<div class="white" style="height: 26">Concentration</div>
{{for data.ports}}
<div style="height: 26">
{{if value.input}}
{{:helper.round(value.concentration*100)}} %
{{else}}
-
{{/if}}
</div>
{{/for}}
</div>
</div>
<div class="itemContent" style="padding: 5px">
Flow Rate: {{:(data.last_flow_rate/10)}} L/s
</div>
{{/if}}
</div>
-36
View File
@@ -1,36 +0,0 @@
<!--
Title: Teleporter Console UI
Used In File(s): \code\game\machinery\teleporter.dm
-->
<h1>Teleporter Status</h1>
{{if !data.powerstation}}
<div class="bad">No power station linked.</div>
{{else !data.teleporterhub}}
<div class="bad">No hub linked.</div>
{{else}}
<div class="block">
<div class="item">
<div class="itemLabel">Current Regime</div>
<div class="itemContent">{{:data.regime}}</div>
</div>
<div class="item">
<div class="itemLabel">Current Target</div>
<div class="itemContent">{{:data.target}}{{if data.target != "None"}}{{if data.regime == "Gate"}} Teleporter{{/if}}{{/if}}</div>
</div>
<div class="item">
<div class="itemLabel">Calibration</div>
<div class="itemContent">{{if data.calibrating}}<span class="average">In Progress</span>{{else data.calibrated}}<span class="good">Optimal</span>{{else data.accurate > 2}}<span class="good">Optimal</span>{{else}}<span class="bad">Sub-Optimal</span>{{/if}}</div>
</div>
</div>
<div style="margin-top:10px;" class="item">
<div class="item">{{:helper.link('Change regime', 'gear', {'regimeset': 1})}}</div>
<div class="item">{{:helper.link('Set target', 'gear', {'settarget': 1})}}</div>
</div>
<div style="margin-top:10px;" class="item">
<div class="item">{{:helper.link('Get target from memory', 'arrow-circle-down', {'lock': 1}, data.locked ? '' : 'disabled')}}</div>
<div class="item">{{:helper.link('Eject GPS device', 'eject', {'eject': 1}, data.locked ? '' : 'disabled')}}</div>
</div>
<div style="margin-top:10px;" class="item">
<div class="item">{{:helper.link('Calibrate hub', 'arrows-alt', {'calibrate': 1}, data.target == 'None' ? 'disabled' : '')}}</div>
</div>
{{/if}}
+1 -4
View File
@@ -174,10 +174,6 @@
#include "code\ATMOSPHERICS\components\binary_devices\pump.dm"
#include "code\ATMOSPHERICS\components\binary_devices\valve.dm"
#include "code\ATMOSPHERICS\components\binary_devices\volume_pump.dm"
#include "code\ATMOSPHERICS\components\omni_devices\_omni_extras.dm"
#include "code\ATMOSPHERICS\components\omni_devices\filter.dm"
#include "code\ATMOSPHERICS\components\omni_devices\mixer.dm"
#include "code\ATMOSPHERICS\components\omni_devices\omni_base.dm"
#include "code\ATMOSPHERICS\components\trinary_devices\filter.dm"
#include "code\ATMOSPHERICS\components\trinary_devices\mixer.dm"
#include "code\ATMOSPHERICS\components\trinary_devices\trinary_base.dm"
@@ -218,6 +214,7 @@
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\changelog.dm"
#include "code\controllers\subsystem\cleanup.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\fires.dm"
#include "code\controllers\subsystem\garbage.dm"
@@ -0,0 +1,70 @@
import { useBackend } from "../backend";
import { Button, Section, NumberInput, LabeledList } from "../components";
import { Window } from "../layouts";
export const AtmosFilter = (props, context) => {
const { act, data } = useBackend(context);
const {
on,
pressure,
max_pressure,
filter_type,
filter_type_list,
} = data;
return (
<Window>
<Window.Content>
<Section>
<LabeledList>
<LabeledList.Item label="Power">
<Button
icon={on ? "power-off" : "power-off"}
content={on ? "On" : "Off"}
color={on ? null : "red"}
selected={on}
onClick={() => act('power')} />
</LabeledList.Item>
<LabeledList.Item label="Rate">
<Button
icon="fast-backward"
textAlign="center"
disabled={pressure === 0}
width={2.2}
onClick={() => act('min_pressure')} />
<NumberInput
animated
unit="kPa"
width={6.1}
lineHeight={1.5}
step={10}
minValue={0}
maxValue={max_pressure}
value={pressure}
onDrag={(e, value) => act('custom_pressure', {
pressure: value,
})} />
<Button
icon="fast-forward"
textAlign="center"
disabled={pressure === max_pressure}
width={2.2}
onClick={() => act('max_pressure')} />
</LabeledList.Item>
<LabeledList.Item label="Filter">
{filter_type_list.map(filter => (
<Button
key={filter.label}
selected={filter.gas_type === filter_type}
content={filter.label}
onClick={() => act('set_filter', {
filter: filter.gas_type,
})} />
))}
</LabeledList.Item>
</LabeledList>
</Section>
</Window.Content>
</Window>
);
};
+167
View File
@@ -0,0 +1,167 @@
import { useBackend } from '../backend';
import { Box, Button, LabeledList, Section, Grid, Dropdown, Flex } from '../components';
import { Window } from '../layouts';
import { GridColumn } from '../components/Grid';
export const Teleporter = (props, context) => {
const { act, data } = useBackend(context);
let targetsTeleport = data.targetsTeleport ? data.targetsTeleport : {};
const REGIME_TELEPORT = 0;
const REGIME_GATE = 1;
const REGIME_GPS = 2;
const {
calibrated,
calibrating,
powerstation,
regime,
teleporterhub,
target,
locked,
} = data;
return (
<Window>
<Window.Content>
{(!powerstation || !teleporterhub)
&& (
<Section
title="Error">
{teleporterhub}
{!powerstation
&& (
<Box color="bad"> Powerstation not linked </Box>
)}
{powerstation && !teleporterhub
&& (
<Box color="bad"> Teleporter hub not linked </Box>
)}
</Section>
)}
{(powerstation && teleporterhub)
&& (
<Section title="Status">
<LabeledList>
<LabeledList.Item label="Regime">
<Button
tooltip="Teleport to another teleport hub. "
color={regime === REGIME_GATE ? 'good' : null}
onClick={() =>
act('setregime', { regime: REGIME_GATE })}>
Gate
</Button>
<Button
tooltip="One-way teleport. "
color={regime === REGIME_TELEPORT ? 'good' : null}
onClick={() =>
act('setregime', { regime: REGIME_TELEPORT })}>
Teleporter
</Button>
<Button
tooltip="Teleport to a location stored in a GPS device. "
color={regime === REGIME_GPS ? 'good' : null}
disabled={locked ? false : true}
onClick={() =>
act('setregime', { regime: REGIME_GPS })}>
GPS
</Button>
</LabeledList.Item>
<LabeledList.Item label="Teleport target">
{/* The duplication of the dropdowns is due to the
updates of selected not affecting the state
of the dropdown */}
{regime === REGIME_TELEPORT && (
<Dropdown
width="220px"
selected={target}
options={Object.keys(targetsTeleport)}
color={target !== "None" ? "default" : "bad"}
onSelected={val => act('settarget',
{
x: targetsTeleport[val]["x"],
y: targetsTeleport[val]["y"],
z: targetsTeleport[val]["z"],
})} />
)}
{regime === REGIME_GATE && (
<Dropdown
width="220px"
selected={target}
options={Object.keys(targetsTeleport)}
color={target !== "None" ? "default" : "bad"}
onSelected={val => act('settarget',
{
x: targetsTeleport[val]["x"],
y: targetsTeleport[val]["y"],
z: targetsTeleport[val]["z"],
})} />
)}
{regime === REGIME_GPS && (
<Box>
{target}
</Box>
)}
</LabeledList.Item>
<LabeledList.Item label="Calibration">
{target !== 'None'
&& (
<Grid>
<GridColumn size="2">
{calibrating
&& (
<Box color="average">
In Progress
</Box>
) || (calibrated
&& (
<Box color="good">
Optimal
</Box>
) || (
<Box color="bad">
Sub-Optimal
</Box>
))}
</GridColumn>
<GridColumn size="3">
<Box class="ml-1">
<Button
icon="sync-alt"
tooltip="Calibrates the hub. \
Accidents may occur when the \
calibration is not optimal."
disabled={(calibrated || calibrating) ? true : false}
onClick={() => act('calibrate')} />
</Box>
</GridColumn>
</Grid>
)}
{target === 'None'
&& (
<Box lineHeight="21px">
No target set
</Box>
)}
</LabeledList.Item>
</LabeledList>
</Section>
)}
{!!(locked && powerstation && teleporterhub && regime === REGIME_GPS)
&& (
<Section title="GPS">
<Flex direction="row" justify="space-around">
<Button
content="Upload GPS data"
tooltip="Loads the GPS data from the device."
icon="upload"
onClick={() => act('load')} />
<Button
content="Eject"
tooltip="Ejects the GPS device"
icon="eject"
onClick={() => act('eject')} />
</Flex>
</Section>
)}
</Window.Content>
</Window>
);
};
File diff suppressed because one or more lines are too long