Merge remote-tracking branch 'upstream/master' into tgui-filter

This commit is contained in:
SteelSlayer
2020-09-15 20:25:24 -05:00
195 changed files with 11814 additions and 8154 deletions
@@ -167,7 +167,7 @@
/turf/simulated/floor/wood,
/area/ruin/powered/snow_cabin)
"aL" = (
/obj/structure/displaycase/captain,
/obj/mecha/working/ripley/mining,
/turf/simulated/floor/wood,
/area/ruin/powered/snow_cabin)
"aM" = (
@@ -392,12 +392,6 @@
/obj/structure/filingcabinet,
/turf/simulated/floor/pod/dark,
/area/ruin/powered/snow_biodome)
"UM" = (
/obj/machinery/computer/monitor/secret{
dir = 1
},
/turf/simulated/floor/pod/dark,
/area/ruin/powered/snow_biodome)
"Wg" = (
/turf/simulated/wall/r_wall,
/area/ruin/powered/snow_biodome)
@@ -484,7 +478,7 @@ HP
tl
PK
gz
UM
HP
Wg
ak
ak
@@ -68,7 +68,6 @@
"an" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDNW";
invisibility = 100;
location = "SDNE"
},
/turf/simulated/floor/plating/asteroid/airless,
@@ -292,15 +291,13 @@
"aU" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDSW";
invisibility = 100;
location = "SDNW"
},
/turf/simulated/floor/plating/asteroid/airless,
/area/syndicate_depot/outer)
"aV" = (
/obj/machinery/light{
dir = 4;
icon_state = "tube1"
dir = 4
},
/turf/simulated/floor/plating/asteroid/airless,
/area/syndicate_depot/outer)
@@ -429,8 +426,7 @@
/area/syndicate_depot/core)
"bo" = (
/obj/machinery/light{
dir = 4;
icon_state = "tube1"
dir = 4
},
/obj/effect/spawner/random_spawners/syndicate/loot,
/turf/simulated/floor/plasteel{
@@ -512,7 +508,6 @@
id = "syndi_depot_rear";
idle_power_usage = 0;
name = "mysterious button";
normaldoorcontrol = 0;
pixel_x = 24;
use_power = 0
},
@@ -663,8 +658,8 @@
/obj/machinery/turretid/syndicate{
name = "external turret controls";
pixel_x = -32;
pixel_y = 0;
req_access = list(150)
req_access = null;
req_access_txt = "150"
},
/turf/simulated/floor/plasteel{
icon_state = "dark"
@@ -745,9 +740,8 @@
/area/syndicate_depot/core)
"ce" = (
/obj/machinery/light/small{
tag = "icon-bulb1 (EAST)";
icon_state = "bulb1";
dir = 4
dir = 4;
tag = "icon-bulb1 (EAST)"
},
/turf/simulated/floor/mineral/silver,
/area/syndicate_depot/core)
@@ -757,7 +751,6 @@
id = "syndi_depot_rear";
idle_power_usage = 0;
name = "mysterious button";
normaldoorcontrol = 0;
use_power = 0
},
/obj/structure/sign/poster/contraband/syndicate_recruitment,
@@ -774,8 +767,8 @@
/area/syndicate_depot/core)
"ci" = (
/obj/structure/cable{
icon_state = "0-2";
d2 = 2
d2 = 2;
icon_state = "0-2"
},
/obj/machinery/power/smes/upgraded{
charge = 5e+006;
@@ -845,7 +838,6 @@
"cr" = (
/obj/structure/sink{
dir = 4;
icon_state = "sink";
pixel_x = 12
},
/turf/simulated/floor/mineral/silver,
@@ -1154,7 +1146,6 @@
"dc" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDSE";
invisibility = 100;
location = "SDSW"
},
/turf/simulated/floor/plating/asteroid/airless,
@@ -1179,7 +1170,6 @@
"df" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDNE";
invisibility = 100;
location = "SDSE"
},
/turf/simulated/floor/plating/asteroid/airless,
@@ -137,51 +137,56 @@
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/passive_gate/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/binary/passive_gate/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_pump.tmpl", name, 385, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/passive_gate/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
/obj/machinery/atmospherics/binary/passive_gate/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(target_pressure),
"max_rate" = MAX_OUTPUT_PRESSURE,
"gas_unit" = "kPa",
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
if("max_rate")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_rate")
target_pressure = 0
. = TRUE
if("custom_rate")
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/passive_gate/proc/toggle()
if(powered())
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")
update_icon()
SSnanoui.update_uis(src)
update_icon()
/obj/machinery/atmospherics/binary/passive_gate/attackby(obj/item/W, mob/user, params)
if(!istype(W, /obj/item/wrench))
@@ -192,51 +192,51 @@ Thus, the two variables affect pump operation are set in New():
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/pump/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/binary/pump/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_pump.tmpl", name, 385, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/pump/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
/obj/machinery/atmospherics/binary/pump/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(target_pressure),
"max_rate" = MAX_OUTPUT_PRESSURE,
"gas_unit" = "kPa",
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
/obj/machinery/atmospherics/binary/pump/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")
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("max_rate")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_rate")
target_pressure = 0
. = TRUE
if("custom_rate")
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/pump/power_change()
var/old_stat = stat
@@ -188,51 +188,51 @@ Thus, the two variables affect pump operation are set in New():
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/volume_pump/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/binary/volume_pump/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_pump.tmpl", name, 310, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/volume_pump/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["rate"] = round(transfer_rate)
data["max_rate"] = round(MAX_TRANSFER_RATE)
/obj/machinery/atmospherics/binary/volume_pump/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(transfer_rate),
"max_rate" = round(MAX_TRANSFER_RATE),
"gas_unit" = "L/s",
"step" = 1 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list)
/obj/machinery/atmospherics/binary/volume_pump/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["rate"])
var/rate = href_list["rate"]
if(rate == "max")
rate = MAX_TRANSFER_RATE
. = TRUE
else if(rate == "input")
rate = input("New transfer rate (0-[MAX_TRANSFER_RATE] L/s):", name, transfer_rate) as num|null
if(!isnull(rate))
. = TRUE
else if(text2num(rate) != null)
rate = text2num(rate)
. = TRUE
if(.)
transfer_rate = clamp(rate, 0, MAX_TRANSFER_RATE)
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
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("max_rate")
transfer_rate = MAX_TRANSFER_RATE
. = TRUE
if("min_rate")
transfer_rate = 0
. = TRUE
if("custom_rate")
transfer_rate = clamp(text2num(params["rate"]), 0 , MAX_TRANSFER_RATE)
. = TRUE
if(.)
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/volume_pump/power_change()
var/old_stat = stat
+5
View File
@@ -92,3 +92,8 @@
// Firelock states
#define FD_OPEN 1
#define FD_CLOSED 2
// Computer login types
#define LOGIN_TYPE_NORMAL 1
#define LOGIN_TYPE_AI 2
#define LOGIN_TYPE_ROBOT 3
+8
View File
@@ -0,0 +1,8 @@
// TGUI defines
#define TGUI_MODAL_INPUT_MAX_LENGTH 1024
#define TGUI_MODAL_INPUT_MAX_LENGTH_NAME 64 // Names for generally anything don't go past 32, let alone 64.
#define TGUI_MODAL_OPEN 1
#define TGUI_MODAL_DELEGATE 2
#define TGUI_MODAL_ANSWER 3
#define TGUI_MODAL_CLOSE 4
+1 -1
View File
@@ -95,7 +95,7 @@ proc/isDay(var/month, var/day)
/proc/seconds_to_time(var/seconds as num)
var/numSeconds = seconds % 60
var/numMinutes = (seconds - numSeconds) / 60
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds."
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds"
//Take a value in seconds and makes it display like a clock
/proc/seconds_to_clock(var/seconds as num)
+13 -5
View File
@@ -182,13 +182,14 @@
// TURRETCONTROL
// These two will be changed with TGUI turrets/turretcontrol.
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
Topic(src, list("src" = UID(), "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets
enabled = !enabled
updateTurrets()
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
Topic(src, list("src" = UID(), "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
if(lethal_is_configurable)
lethal = !lethal
updateTurrets()
// AIRLOCKS
@@ -230,6 +231,13 @@
to_chat(user, "<span class='notice'>The door bolt lights have been enabled.</span>")
update_icon()
// FIRE ALARMS
/obj/machinery/firealarm/AICtrlClick()
if(enabled)
reset()
else
alarm()
// AI-CONTROLLED SLIP GENERATOR IN AI CORE
+3
View File
@@ -170,6 +170,9 @@
/obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on
Activate()
/obj/machinery/firealarm/BorgCtrlClick()
AICtrlClick()
/*
As with AI, these are not used in click code,
because the code for robots is specific, not generic.
+8 -3
View File
@@ -93,6 +93,11 @@ SUBSYSTEM_DEF(shuttle)
return S
WARNING("couldn't find dock with id: [id]")
/datum/controller/subsystem/shuttle/proc/secondsToRefuel()
var/elapsed = world.time - SSticker.round_start_time
var/remaining = round((config.shuttle_refuel_delay - elapsed) / 10)
return remaining > 0 ? remaining : 0
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
if(!emergency)
WARNING("requestEvac(): There is no emergency shuttle, but the shuttle was called. Using the backup shuttle instead.")
@@ -107,7 +112,7 @@ SUBSYSTEM_DEF(shuttle)
return
emergency = backup_shuttle
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
if(secondsToRefuel())
to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.")
return
@@ -131,7 +136,7 @@ SUBSYSTEM_DEF(shuttle)
call_reason = trim(html_encode(call_reason))
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
to_chat(user, "You must provide a reason.")
to_chat(user, "Reason is too short. [CALL_SHUTTLE_REASON_LENGTH] character minimum.")
return
var/area/signal_origin = get_area(user)
@@ -192,7 +197,7 @@ SUBSYSTEM_DEF(shuttle)
var/obj/machinery/computer/communications/C = thing
if(C.stat & BROKEN)
continue
else if(istype(thing, /datum/computer_file/program/comm) || istype(thing, /obj/item/circuitboard/communications))
else if(istype(thing, /obj/item/circuitboard/communications))
continue
var/turf/T = get_turf(thing)
+1 -1
View File
@@ -16,7 +16,7 @@
name = "Biodome Winter"
id = "biodome-winter"
description = "For those getaways where you want to get back to nature, but you don't want to leave the fortified military compound where you spend your days. \
Includes a unique(*) laser pistol display case, and the recently introduced I.C.E(tm)."
Includes the recently introduced I.C.E(tm)."
suffix = "lavaland_biodome_winter.dmm"
/datum/map_template/ruin/lavaland/biodome/clown
+15 -12
View File
@@ -6,44 +6,47 @@
qdel(src)
owner = new_owner
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = FALSE, datum/topic_state/state = GLOB.ghost_state, datum/nanoui/master_ui = null)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/datum/spawners_menu/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui_state/state = GLOB.tgui_observer_state, datum/tgui/master_ui = null)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "spawners_menu.tmpl", "Spawners Menu", 700, 600, master_ui, state = state)
ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state = state)
ui.open()
/datum/spawners_menu/ui_data(mob/user)
/datum/spawners_menu/tgui_data(mob/user)
var/list/data = list()
data["spawners"] = list()
for(var/spawner in GLOB.mob_spawners)
var/list/this = list()
this["name"] = spawner
this["desc"] = ""
this["important_info"] = ""
this["fluff"] = ""
this["uids"] = list()
for(var/spawner_obj in GLOB.mob_spawners[spawner])
for(var/spawner_obj in GLOB.mob_spawners[spawner])//each spawner can contain multiple actual spawners, we use only one desc/info
this["uids"] += "\ref[spawner_obj]"
if(!this["desc"])
if(!this["desc"]) //haven't set descriptions yet
if(istype(spawner_obj, /obj/effect/mob_spawn))
var/obj/effect/mob_spawn/MS = spawner_obj
this["desc"] = MS.flavour_text
this["desc"] = MS.description
this["important_info"] = MS.important_info
this["fluff"] = MS.flavour_text
else
var/obj/O = spawner_obj
this["desc"] = O.desc
this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner])
data["spawners"] += list(this)
return data
/datum/spawners_menu/Topic(href, href_list)
/datum/spawners_menu/tgui_act(action, params)
if(..())
return 1
var/spawners = replacetext(href_list["uid"], ",", ";")
return
var/spawners = replacetext(params["ID"], ",", ";")
var/list/possible_spawners = params2list(spawners)
var/obj/effect/mob_spawn/MS = locate(pick(possible_spawners))
if(!MS || !istype(MS))
log_runtime(EXCEPTION("A ghost tried to interact with an invalid spawner, or the spawner didn't exist."))
return
switch(href_list["action"])
switch(action)
if("jump")
owner.forceMove(get_turf(MS))
. = TRUE
+343 -403
View File
@@ -7,6 +7,11 @@
#define NEGATE_MUTATION_THRESHOLD 30 // Occupants with over ## percent radiation threshold will not gain mutations
#define PAGE_UI "ui"
#define PAGE_SE "se"
#define PAGE_BUFFER "buffer"
#define PAGE_REJUVENATORS "rejuvenators"
//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
/datum/dna2/record
var/datum/dna/dna = null
@@ -161,6 +166,7 @@
occupant = usr
icon_state = "scanner_occupied"
add_fingerprint(usr)
SStgui.update_uis(src)
/obj/machinery/dna_scannernew/MouseDrop_T(atom/movable/O, mob/user)
if(!istype(O))
@@ -214,6 +220,7 @@
return
beaker = I
SStgui.update_uis(src)
I.forceMove(src)
user.visible_message("[user] adds \a [I] to \the [src]!", "You add \a [I] to \the [src]!")
return
@@ -260,6 +267,7 @@
M.forceMove(src)
occupant = M
icon_state = "scanner_occupied"
SStgui.update_uis(src)
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
@@ -281,6 +289,7 @@
occupant.forceMove(loc)
occupant = null
icon_state = "scanner_open"
SStgui.update_uis(src)
/obj/machinery/dna_scannernew/force_eject_occupant()
go_out(null, TRUE)
@@ -296,6 +305,7 @@
occupant = null
updateUsrDialog()
update_icon()
SStgui.update_uis(src)
// Checks if occupants can be irradiated/mutated - prevents exploits where wearing full rad protection would still let you gain mutations
/obj/machinery/dna_scannernew/proc/radiation_check()
@@ -333,12 +343,11 @@
var/injector_ready = FALSE //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
var/obj/machinery/dna_scannernew/connected = null
var/obj/item/disk/data/disk = null
var/selected_menu_key = null
var/selected_menu_key = PAGE_UI
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 400
var/waiting_for_user_input = 0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/disk/data)) //INSERT SOME diskS
@@ -347,7 +356,7 @@
I.forceMove(src)
disk = I
to_chat(user, "You insert [I].")
SSnanoui.update_uis(src) // update all UIs attached to src()
SStgui.update_uis(src)
return
else
return ..()
@@ -399,35 +408,18 @@
if(stat & (NOPOWER|BROKEN))
return
ui_interact(user)
tgui_interact(user)
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
*/
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
/obj/machinery/computer/scan_consolenew/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)
if(user == connected.occupant)
return
// update the ui if it exists, returns null if no ui is passed/found
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)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700)
// open the new ui window
ui = new(user, src, ui_key, "DNAModifier", name, 660, 700, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/computer/scan_consolenew/ui_data(mob/user, datum/topic_state/state)
/obj/machinery/computer/scan_consolenew/tgui_data(mob/user)
var/data[0]
data["selectedMenuKey"] = selected_menu_key
data["locked"] = connected.locked
@@ -501,9 +493,12 @@
for(var/datum/reagent/R in connected.beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
// Transfer modal information if there is one
data["modal"] = tgui_modal_data(src)
return data
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
if(..())
return FALSE // don't update uis
if(!istype(usr.loc, /turf))
@@ -512,405 +507,350 @@
return FALSE // don't update uis
if(irradiating) // Make sure that it isn't already irradiating someone...
return FALSE // don't update uis
if(stat & (NOPOWER|BROKEN))
return
add_fingerprint(usr)
if(href_list["selectMenuKey"])
selected_menu_key = href_list["selectMenuKey"]
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["toggleLock"])
if((connected && connected.occupant))
connected.locked = !(connected.locked)
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseRadiation"])
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(!connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
if(prob(95))
if(prob(75))
randmutb(connected.occupant)
else
randmuti(connected.occupant)
else
if(prob(95))
randmutg(connected.occupant)
else
randmuti(connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["radiationDuration"])
if(text2num(href_list["radiationDuration"]) > 0)
if(radiation_duration < 20)
radiation_duration += 2
else
if(radiation_duration > 2)
radiation_duration -= 2
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["radiationIntensity"])
if(text2num(href_list["radiationIntensity"]) > 0)
if(radiation_intensity < 10)
radiation_intensity++
else
if(radiation_intensity > 1)
radiation_intensity--
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) > 0)
if(selected_ui_target < 15)
selected_ui_target++
selected_ui_target_hex = selected_ui_target
switch(selected_ui_target)
if(10)
selected_ui_target_hex = "A"
if(11)
selected_ui_target_hex = "B"
if(12)
selected_ui_target_hex = "C"
if(13)
selected_ui_target_hex = "D"
if(14)
selected_ui_target_hex = "E"
if(15)
selected_ui_target_hex = "F"
else
selected_ui_target = 0
selected_ui_target_hex = 0
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) < 1)
if(selected_ui_target > 0)
selected_ui_target--
selected_ui_target_hex = selected_ui_target
switch(selected_ui_target)
if(10)
selected_ui_target_hex = "A"
if(11)
selected_ui_target_hex = "B"
if(12)
selected_ui_target_hex = "C"
if(13)
selected_ui_target_hex = "D"
if(14)
selected_ui_target_hex = "E"
else
selected_ui_target = 15
selected_ui_target_hex = "F"
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["selectUIBlock"] && href_list["selectUISubblock"]) // This chunk of code updates selected block / sub-block based on click
var/select_block = text2num(href_list["selectUIBlock"])
var/select_subblock = text2num(href_list["selectUISubblock"])
if((select_block <= DNA_UI_LENGTH) && (select_block >= 1))
selected_ui_block = select_block
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
selected_ui_subblock = select_subblock
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseUIRadiation"])
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(!connected.occupant)
return TRUE
if(prob((80 + (radiation_duration / 2))))
var/radiation = (radiation_intensity + radiation_duration)
connected.occupant.apply_effect(radiation,IRRADIATE,0)
if(connected.radiation_check())
return TRUE
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
connected.occupant.UpdateAppearance()
else
var/radiation = ((radiation_intensity * 2) + radiation_duration)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
if(prob(20 + radiation_intensity))
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
connected.occupant.UpdateAppearance()
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["injectRejuvenators"])
if(!connected.occupant)
return FALSE
var/inject_amount = round(text2num(href_list["injectRejuvenators"]), 5) // round to nearest 5
if(inject_amount < 0) // Since the user can actually type the commands himself, some sanity checking
inject_amount = 0
if(inject_amount > 50)
inject_amount = 50
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
connected.beaker.reagents.reaction(connected.occupant)
return TRUE // return 1 forces an update to all Nano uis attached to src
////////////////////////////////////////////////////////
if(href_list["selectSEBlock"] && href_list["selectSESubblock"]) // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
var/select_block = text2num(href_list["selectSEBlock"])
var/select_subblock = text2num(href_list["selectSESubblock"])
if((select_block <= DNA_SE_LENGTH) && (select_block >= 1))
selected_se_block = select_block
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
selected_se_subblock = select_subblock
//testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["pulseSERadiation"])
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
//var/original_block=block
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(connected.occupant)
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
var/real_SE_block=selected_se_block
block = miniscramble(block, radiation_intensity, radiation_duration)
if(prob(20))
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
real_SE_block++
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
real_SE_block--
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
domutcheck(connected.occupant, connected)
else
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
if(prob(80 - radiation_duration))
//testing("Random bad mut!")
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
//testing("Random identity mut!")
connected.occupant.UpdateAppearance()
return TRUE // return 1 forces an update to all Nano uis attached to src
if(href_list["ejectBeaker"])
if(connected.beaker)
var/obj/item/reagent_containers/glass/B = connected.beaker
B.forceMove(connected.loc)
connected.beaker = null
if(tgui_act_modal(action, params))
return TRUE
if(href_list["ejectOccupant"])
connected.eject_occupant(usr)
return TRUE
// Transfer Buffer Management
if(href_list["bufferOption"])
var/bufferOption = href_list["bufferOption"]
// These bufferOptions do not require a bufferId
if(bufferOption == "wipeDisk")
if((isnull(disk)) || (disk.read_only))
//temphtml = "Invalid disk. Please try again."
return FALSE
disk.buf = null
//temphtml = "Data saved."
return TRUE
if(bufferOption == "ejectDisk")
if(!disk)
. = TRUE
switch(action)
if("selectMenuKey")
var/key = params["key"]
if(!(key in list(PAGE_UI, PAGE_SE, PAGE_BUFFER, PAGE_REJUVENATORS)))
return
disk.forceMove(get_turf(src))
disk = null
return TRUE
// All bufferOptions from here on require a bufferId
if(!href_list["bufferId"])
return FALSE
var/bufferId = text2num(href_list["bufferId"])
if(bufferId < 1 || bufferId > 3)
return FALSE // Not a valid buffer id
if(bufferOption == "saveUI")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.name
databuf.name = "Unique Identifier"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "saveUIAndUE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.dna.real_name
databuf.name = "Unique Identifier + Unique Enzymes"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "saveSE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_SE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name = connected.occupant.dna.real_name
databuf.name = "Structural Enzymes"
buffers[bufferId] = databuf
return TRUE
if(bufferOption == "clear")
buffers[bufferId] = new /datum/dna2/record()
return TRUE
if(bufferOption == "changeLabel")
var/datum/dna2/record/buf = buffers[bufferId]
var/text = sanitize(input(usr, "New Label:", "Edit Label", buf.name) as text|null)
buf.name = text
buffers[bufferId] = buf
return TRUE
if(bufferOption == "transfer")
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
return TRUE
irradiating = 2
selected_menu_key = key
if("toggleLock")
if(connected && connected.occupant)
connected.locked = !(connected.locked)
if("pulseRadiation")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SSnanoui.update_uis(src) // update all UIs attached to src
sleep(2 SECONDS)
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
var/radiation = (rand(20,50) / connected.damage_coeff)
if(!connected.occupant)
return
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return TRUE
return
var/datum/dna2/record/buf = buffers[bufferId]
if((buf.types & DNA2_BUF_UI))
if((buf.types & DNA2_BUF_UE))
connected.occupant.real_name = buf.dna.real_name
connected.occupant.name = buf.dna.real_name
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
else if(buf.types & DNA2_BUF_SE)
connected.occupant.dna.SE = buf.dna.SE.Copy()
connected.occupant.dna.UpdateSE()
domutcheck(connected.occupant, connected)
return TRUE
if(bufferOption == "createInjector")
if(injector_ready && !waiting_for_user_input)
var/success = 1
var/obj/item/dnainjector/I = new /obj/item/dnainjector
var/datum/dna2/record/buf = buffers[bufferId]
buf = buf.copy()
if(href_list["createBlockInjector"])
waiting_for_user_input=1
var/list/selectedbuf
if(buf.types & DNA2_BUF_SE)
selectedbuf=buf.dna.SE
else
selectedbuf=buf.dna.UI
var/blk = input(usr,"Select Block","Block") as null|anything in all_dna_blocks(selectedbuf)
success = setInjectorBlock(I,blk,buf)
if(prob(95))
if(prob(75))
randmutb(connected.occupant)
else
I.buf = buf
waiting_for_user_input = 0
if(success)
I.forceMove(loc)
I.name += " ([buf.name])"
if(connected)
I.damage_coeff = connected.damage_coeff
injector_ready = FALSE
spawn(300)
injector_ready = TRUE
return TRUE
randmuti(connected.occupant)
else
if(prob(95))
randmutg(connected.occupant)
else
randmuti(connected.occupant)
if("radiationDuration")
radiation_duration = clamp(text2num(params["value"]), 1, 20)
if("radiationIntensity")
radiation_intensity = clamp(text2num(params["value"]), 1, 10)
////////////////////////////////////////////////////////
if("changeUITarget")
selected_ui_target = clamp(text2num(params["value"]), 1, 15)
selected_ui_target_hex = num2text(selected_ui_target, 1, 16)
if("selectUIBlock") // This chunk of code updates selected block / sub-block based on click
var/select_block = text2num(params["block"])
var/select_subblock = text2num(params["subblock"])
if(!select_block || !select_subblock)
return
if(bufferOption == "loadDisk")
if((isnull(disk)) || (!disk.buf))
//temphtml = "Invalid disk. Please try again."
return FALSE
selected_ui_block = clamp(select_block, 1, DNA_UI_LENGTH)
selected_ui_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
if("pulseUIRadiation")
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
buffers[bufferId] = disk.buf.copy()
//temphtml = "Data loaded."
return TRUE
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
if(bufferOption == "saveDisk")
if((isnull(disk)) || (disk.read_only))
//temphtml = "Invalid disk. Please try again."
return FALSE
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
var/datum/dna2/record/buf = buffers[bufferId]
irradiating = 0
connected.locked = lock_state
disk.buf = buf.copy()
disk.name = "data disk - '[buf.dna.real_name]'"
//temphtml = "Data saved."
return TRUE
if(!connected.occupant)
return
if(prob((80 + (radiation_duration / 2))))
var/radiation = (radiation_intensity + radiation_duration)
connected.occupant.apply_effect(radiation,IRRADIATE,0)
if(connected.radiation_check())
return
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
connected.occupant.UpdateAppearance()
else
var/radiation = ((radiation_intensity * 2) + radiation_duration)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
if(prob(20 + radiation_intensity))
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
connected.occupant.UpdateAppearance()
////////////////////////////////////////////////////////
if("injectRejuvenators")
if(!connected.occupant || !connected.beaker)
return
var/inject_amount = clamp(round(text2num(params["amount"]), 5), 0, 50) // round to nearest 5 and clamp to 0-50
if(!inject_amount)
return
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
connected.beaker.reagents.reaction(connected.occupant)
////////////////////////////////////////////////////////
if("selectSEBlock") // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
var/select_block = text2num(params["block"])
var/select_subblock = text2num(params["subblock"])
if(!select_block || !select_subblock)
return
selected_se_block = clamp(select_block, 1, DNA_SE_LENGTH)
selected_se_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
if("pulseSERadiation")
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
//var/original_block=block
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
irradiating = radiation_duration
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SStgui.update_uis(src)
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
irradiating = 0
connected.locked = lock_state
if(connected.occupant)
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return 1
var/real_SE_block=selected_se_block
block = miniscramble(block, radiation_intensity, radiation_duration)
if(prob(20))
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
real_SE_block++
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
real_SE_block--
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
domutcheck(connected.occupant, connected)
else
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
if(prob(80 - radiation_duration))
//testing("Random bad mut!")
randmutb(connected.occupant)
domutcheck(connected.occupant, connected)
else
randmuti(connected.occupant)
//testing("Random identity mut!")
connected.occupant.UpdateAppearance()
if("ejectBeaker")
if(connected.beaker)
var/obj/item/reagent_containers/glass/B = connected.beaker
B.forceMove(connected.loc)
connected.beaker = null
if("ejectOccupant")
connected.eject_occupant()
// Transfer Buffer Management
if("bufferOption")
var/bufferOption = params["option"]
var/bufferId = text2num(params["id"])
if(bufferId < 1 || bufferId > 3) // Not a valid buffer id
return
var/datum/dna2/record/buffer = buffers[bufferId]
switch(bufferOption)
if("saveUI")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.name
databuf.name = "Unique Identifier"
buffers[bufferId] = databuf
if("saveUIAndUE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name=connected.occupant.dna.real_name
databuf.name = "Unique Identifier + Unique Enzymes"
buffers[bufferId] = databuf
if("saveSE")
if(connected.occupant && connected.occupant.dna)
var/datum/dna2/record/databuf = new
databuf.types = DNA2_BUF_SE
databuf.dna = connected.occupant.dna.Clone()
if(ishuman(connected.occupant))
databuf.dna.real_name = connected.occupant.dna.real_name
databuf.name = "Structural Enzymes"
buffers[bufferId] = databuf
if("clear")
buffers[bufferId] = new /datum/dna2/record()
if("changeLabel")
tgui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.name, TGUI_MODAL_INPUT_MAX_LENGTH_NAME)
if("transfer")
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
return
irradiating = 2
var/lock_state = connected.locked
connected.locked = TRUE //lock it
SStgui.update_uis(src)
sleep(2 SECONDS)
irradiating = 0
connected.locked = lock_state
var/radiation = (rand(20,50) / connected.damage_coeff)
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
if(connected.radiation_check())
return
var/datum/dna2/record/buf = buffers[bufferId]
if((buf.types & DNA2_BUF_UI))
if((buf.types & DNA2_BUF_UE))
connected.occupant.real_name = buf.dna.real_name
connected.occupant.name = buf.dna.real_name
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
else if(buf.types & DNA2_BUF_SE)
connected.occupant.dna.SE = buf.dna.SE.Copy()
connected.occupant.dna.UpdateSE()
domutcheck(connected.occupant, connected)
if("createInjector")
if(!injector_ready)
return
if(text2num(params["block"]) > 0)
var/list/choices = all_dna_blocks((buffer.types & DNA2_BUF_SE) ? buffer.dna.SE : buffer.dna.UI)
tgui_modal_choice(src, "createInjectorBlock", "Please select the block to create an injector from:", null, list("id" = bufferId), null, choices)
else
create_injector(bufferId, TRUE)
if("loadDisk")
if(isnull(disk) || disk.read_only)
return
buffers[bufferId] = disk.buf.copy()
if("saveDisk")
if(isnull(disk) || disk.read_only)
return
var/datum/dna2/record/buf = buffers[bufferId]
disk.buf = buf.copy()
disk.name = "data disk - '[buf.dna.real_name]'"
if("wipeDisk")
if(isnull(disk) || disk.read_only)
return
disk.buf = null
if("ejectDisk")
if(!disk)
return
disk.forceMove(get_turf(src))
disk = null
/**
* Creates a blank injector with the name of the buffer at the given buffer_id
*
* Arguments:
* * buffer_id - The ID of the buffer
* * copy_buffer - Whether the injector should copy the buffer contents
*/
/obj/machinery/computer/scan_consolenew/proc/create_injector(buffer_id, copy_buffer = FALSE)
if(buffer_id < 1 || buffer_id > length(buffers))
return
// Cooldown
injector_ready = FALSE
addtimer(CALLBACK(src, .proc/injector_cooldown_finish), 30 SECONDS)
// Create it
var/datum/dna2/record/buf = buffers[buffer_id]
var/obj/item/dnainjector/I = new()
I.forceMove(loc)
I.name += " ([buf.name])"
if(copy_buffer)
I.buf = buf.copy()
if(connected)
I.damage_coeff = connected.damage_coeff
return I
/**
* Called when the injector creation cooldown finishes
*/
/obj/machinery/computer/scan_consolenew/proc/injector_cooldown_finish()
injector_ready = TRUE
/**
* Called in tgui_act() to process modal actions
*
* Arguments:
* * action - The action passed by tgui
* * params - The params passed by tgui
*/
/obj/machinery/computer/scan_consolenew/proc/tgui_act_modal(action, params)
. = TRUE
var/id = params["id"] // The modal's ID
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_ANSWER)
var/answer = params["answer"]
switch(id)
if("createInjectorBlock")
var/buffer_id = text2num(arguments["id"])
if(buffer_id < 1 || buffer_id > length(buffers))
return
var/datum/dna2/record/buf = buffers[buffer_id]
var/obj/item/dnainjector/I = create_injector(buffer_id)
setInjectorBlock(I, answer, buf.copy())
if("changeBufferLabel")
var/buffer_id = text2num(arguments["id"])
if(buffer_id < 1 || buffer_id > length(buffers))
return
var/datum/dna2/record/buf = buffers[buffer_id]
buf.name = answer
buffers[buffer_id] = buf
else
return FALSE
else
return FALSE
#undef PAGE_UI
#undef PAGE_SE
#undef PAGE_BUFFER
#undef PAGE_REJUVENATORS
/////////////////////////// DNA MACHINES
+2 -2
View File
@@ -18,7 +18,7 @@
intercepttext += "<BR>Note in the event of a quarantine breach or uncontrolled spread of the biohazard, the directive 7-10 may be upgraded to a directive 7-12.<BR>"
intercepttext += "Message ends."
if(2)
var/nukecode = "[rand(10000, 99999)]"
var/nukecode = rand(10000, 99999)
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb && bomb.r_code)
if(is_station_level(bomb.z))
@@ -40,7 +40,7 @@
aiPlayer.set_zeroth_law(law)
to_chat(aiPlayer, "Laws Updated: [law]")
print_command_report(intercepttext, interceptname)
print_command_report(intercepttext, interceptname, FALSE)
GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg', from = "[command_name()] Update")
/datum/station_state
@@ -17,7 +17,8 @@
/obj/effect/mob_spawn/human/demonic_friend/Initialize(mapload, datum/mind/owner_mind, obj/effect/proc_holder/spell/targeted/summon_friend/summoning_spell)
. = ..()
owner = owner_mind
flavour_text = "<span class='big bold'>You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil.</span><b> Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell.</b>"
description = "Be someone's loyal friend/slave. If they die, you die as well." //best I could think of in the moment, not sure how this role plays in practise, have never seen it.
flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell."
var/area/A = get_area(src)
if(!mapload && A)
notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = TRUE)
+1 -1
View File
@@ -507,7 +507,7 @@ proc/display_roundstart_logout_report()
message_text += G.get_report()
message_text += "<hr>"
print_command_report(message_text, "[command_name()] Orders")
print_command_report(message_text, "[command_name()] Orders", FALSE)
/datum/game_mode/proc/declare_station_goal_completion()
for(var/V in station_goals)
@@ -19,15 +19,13 @@
mob_name = "a swarmer"
death = FALSE
roundstart = FALSE
flavour_text = {"
<b>You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate.</b>
<b>Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful.</b>
<b>Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage.</b>
<b>Objectives:</b>
important_info = "Follow your objectives, do not make the station inhospitable or try and kill crew."
flavour_text = "You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate."
description = {" Your goal is to create more of yourself by consuming the station. Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful. Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage.
Objectives:
1. Consume resources and replicate until there are no more resources left.
2. Ensure that this location is fit for invasion at a later date; do not perform actions that would render it dangerous or inhospitable.
3. Biological resources will be harvested at a later date; do not harm them.
"}
3. Biological resources will be harvested at a later date; do not harm them."}
/obj/effect/mob_spawn/swarmer/Initialize(mapload)
. = ..()
@@ -7,7 +7,7 @@
var/swarmer_report = "<font size=3><b>[command_name()] High-Priority Update</b></span>"
swarmer_report += "<br><br>Our long-range sensors have detected an odd signal emanating from your station's gateway. We recommend immediate investigation of your gateway, as something may have come \
through."
print_command_report(swarmer_report, "Classified [command_name()] Update")
print_command_report(swarmer_report, "Classified [command_name()] Update", FALSE)
GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
/datum/event/spawn_swarmer/start()
@@ -363,7 +363,7 @@
if("Protector")
pickedtype = /mob/living/simple_animal/hostile/guardian/protector
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user)
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user, user)
G.summoner = user
G.summoned = TRUE
G.key = key
@@ -3,12 +3,12 @@
layer = LYING_MOB_LAYER
/mob/living/simple_animal/hostile/guardian/beam
melee_damage_lower = 7
melee_damage_upper = 7
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "shocks"
melee_damage_type = BURN
attack_sound = 'sound/machines/defib_zap.ogg'
damage_transfer = 0.7
damage_transfer = 0.6
range = 7
playstyle_string = "As a <b>Lightning</b> type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them."
magic_fluff_string = "..And draw the Tesla, a shocking, lethal source of power."
@@ -18,6 +18,17 @@
var/list/enemychains = list()
var/successfulshocks = 0
/mob/living/simple_animal/hostile/guardian/beam/New(loc, mob/living/user)
. = ..()
if(!user)
return
summoner = user
if(!(NO_SHOCK in summoner.mutations))
summoner.mutations.Add(NO_SHOCK)
/mob/living/simple_animal/hostile/guardian/beam/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
return FALSE //You are lightning, you should not be hurt by such things.
/mob/living/simple_animal/hostile/guardian/beam/AttackingTarget()
. = ..()
if(. && isliving(target) && target != src && target != summoner)
@@ -106,3 +117,8 @@
)
L.adjustFireLoss(1.2) //adds up very rapidly
. = 1
/mob/living/simple_animal/hostile/guardian/beam/death(gibbed)
if(summoner && (NO_SHOCK in summoner.mutations))
summoner.mutations.Remove(NO_SHOCK)
return ..()
+1 -1
View File
@@ -103,7 +103,7 @@ proc/issyndicate(mob/living/M as mob)
var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")
var/nuke_code = "[rand(10000, 99999)]"
var/nuke_code = rand(10000, 99999)
var/leader_selected = 0
var/agent_number = 1
var/spawnpos = 1
+139 -164
View File
@@ -14,29 +14,29 @@ GLOBAL_VAR(bomb_set)
icon_state = "nuclearbomb0"
density = 1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/deployable = 0
var/extended = 0
var/lighthack = 0
var/extended = FALSE
var/lighthack = FALSE
var/timeleft = 120
var/timing = 0
var/timing = FALSE
var/exploded = FALSE
var/r_code = "ADMIN"
var/code = ""
var/yes_code = 0
var/safety = 1
var/code
var/yes_code = FALSE
var/safety = TRUE
var/obj/item/disk/nuclear/auth = null
var/removal_stage = NUKE_INTACT
var/lastentered
var/is_syndicate = 0
var/is_syndicate = FALSE
use_power = NO_POWER_USE
var/previous_level = ""
var/datum/wires/nuclearbomb/wires = null
/obj/machinery/nuclearbomb/syndicate
is_syndicate = 1
is_syndicate = TRUE
/obj/machinery/nuclearbomb/New()
..()
r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn.
r_code = rand(10000, 99999.0) // Creates a random code upon object spawn.
wires = new/datum/wires/nuclearbomb(src)
previous_level = get_security_level()
GLOB.poi_list |= src
@@ -49,25 +49,24 @@ GLOBAL_VAR(bomb_set)
/obj/machinery/nuclearbomb/process()
if(timing)
GLOB.bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed.
GLOB.bomb_set = TRUE // So long as there is one nuke timing, it means one nuke is armed.
timeleft = max(timeleft - 2, 0) // 2 seconds per process()
if(timeleft <= 0)
INVOKE_ASYNC(src, .proc/explode)
SSnanoui.update_uis(src)
return
/obj/machinery/nuclearbomb/attackby(obj/item/O as obj, mob/user as mob, params)
if(istype(O, /obj/item/disk/nuclear))
if(extended)
if(!user.drop_item())
to_chat(user, "<span class='notice'>\The [O] is stuck to your hand!</span>")
to_chat(user, "<span class='notice'>[O] is stuck to your hand!</span>")
return
O.forceMove(src)
auth = O
add_fingerprint(user)
return attack_hand(user)
else
to_chat(user, "<span class='notice'>You need to deploy \the [src] first. Right click on the sprite, select 'Make Deployable' then click on \the [src] with an empty hand.</span>")
to_chat(user, "<span class='notice'>You need to deploy [src] first.</span>")
return
return ..()
@@ -171,181 +170,157 @@ GLOBAL_VAR(bomb_set)
removal_stage = NUKE_SEALANT_OPEN
/obj/machinery/nuclearbomb/attack_ghost(mob/user as mob)
if(extended)
attack_hand(user)
attack_hand(user)
/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
if(extended)
if(panel_open)
wires.Interact(user)
else
ui_interact(user)
else if(deployable)
if(removal_stage != NUKE_MOBILE)
anchored = 1
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring!</span>")
else
visible_message("<span class='warning'>\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
if(!lighthack)
flick("nuclearbombc", src)
icon_state = "nuclearbomb1"
extended = 1
return
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 450, 550, state = GLOB.physical_state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/nuclearbomb/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["is_syndicate"] = is_syndicate
data["hacking"] = 0
data["auth"] = is_auth(user)
if(is_auth(user))
if(yes_code)
data["authstatus"] = timing ? "Functional/Set" : "Functional"
else
data["authstatus"] = "Auth. S2"
if(panel_open)
wires.Interact(user)
else
if(timing)
data["authstatus"] = "Set"
else
data["authstatus"] = "Auth. S1"
tgui_interact(user)
/obj/machinery/nuclearbomb/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_physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "NuclearBomb", name, 450, 300, master_ui, state)
ui.open()
/obj/machinery/nuclearbomb/tgui_data(mob/user)
var/list/data = list()
data["extended"] = extended
data["authdisk"] = is_auth(user)
data["diskname"] = auth ? auth.name : FALSE
data["authcode"] = yes_code
data["authfull"] = data["authdisk"] && data["authcode"]
data["safe"] = safety ? "Safe" : "Engaged"
data["time"] = timeleft
data["timer"] = timing
data["safety"] = safety
data["anchored"] = anchored
data["yescode"] = yes_code
data["message"] = "AUTH"
if(is_auth(user))
data["message"] = code
if(yes_code)
data["message"] = "*****"
return data
/obj/machinery/nuclearbomb/verb/make_deployable()
set category = "Object"
set name = "Make Deployable"
set src in oview(1)
if(usr.stat || !usr.canmove || usr.restrained())
return
if(deployable)
to_chat(usr, "<span class='warning'>You close several panels to make [src] undeployable.</span>")
deployable = 0
data["codemsg"] = "CLEAR CODE"
else if(code)
data["codemsg"] = "RE-ENTER CODE"
else
data["codemsg"] = "ENTER CODE"
else
to_chat(usr, "<span class='warning'>You adjust some panels to make [src] deployable.</span>")
deployable = 1
return
data["codemsg"] = "-----"
return data
/obj/machinery/nuclearbomb/proc/is_auth(var/mob/user)
if(auth)
return 1
return TRUE
else if(user.can_admin_interact())
return 1
return TRUE
else
return 0
return FALSE
/obj/machinery/nuclearbomb/Topic(href, href_list)
/obj/machinery/nuclearbomb/tgui_act(action, params)
if(..())
return 1
if(href_list["auth"])
if(auth)
auth.loc = loc
yes_code = 0
auth = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/disk/nuclear))
usr.drop_item()
I.loc = src
auth = I
if(is_auth(usr))
if(href_list["type"])
if(href_list["type"] == "E")
return
. = TRUE
if(exploded)
return
switch(action)
if("deploy")
if(removal_stage != NUKE_MOBILE)
anchored = TRUE
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring!</span>")
else
visible_message("<span class='warning'>[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
if(!lighthack)
flick("nuclearbombc", src)
icon_state = "nuclearbomb1"
extended = TRUE
return
if("auth")
if(auth)
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(auth)
else
auth.forceMove(get_turf(src))
yes_code = FALSE
auth = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/disk/nuclear))
usr.drop_item()
I.forceMove(src)
auth = I
return
if(!is_auth(usr)) // All requests below here require NAD inserted.
return FALSE
switch(action)
if("code")
if(yes_code) // Clear code
code = null
yes_code = FALSE
return
// If no code set, enter new one
var/tempcode = input(usr, "Code", "Input Code", null) as num|null
if(tempcode)
code = min(max(round(tempcode), 0), 999999)
if(code == r_code)
yes_code = 1
yes_code = TRUE
code = null
else
code = "ERROR"
return
if(!yes_code) // All requests below here require both NAD inserted AND code correct
return
switch(action)
if("toggle_anchor")
if(removal_stage == NUKE_MOBILE)
anchored = FALSE
visible_message("<span class='warning'>[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
else if(isinspace())
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
return FALSE
else
if(href_list["type"] == "R")
yes_code = 0
code = null
else
lastentered = text("[]", href_list["type"])
if(text2num(lastentered) == null)
var/turf/LOC = get_turf(usr)
message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: <a href='?_src_=vars;Vars=[UID()]'>[lastentered]</a>! ([LOC ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[LOC.x];Y=[LOC.y];Z=[LOC.z]'>JMP</a>" : "null"])", 0)
log_admin("EXPLOIT: [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]!")
else
code += lastentered
if(length(code) > 5)
code = "ERROR"
if(yes_code)
if(href_list["time"])
var/time = text2num(href_list["time"])
timeleft += time
timeleft = min(max(round(src.timeleft), 120), 600)
if(href_list["timer"])
if(timing == -1.0)
SSnanoui.update_uis(src)
return
if(safety)
to_chat(usr, "<span class='warning'>The safety is still on.</span>")
SSnanoui.update_uis(src)
return
timing = !(timing)
if(timing)
if(!lighthack)
icon_state = "nuclearbomb2"
if(!safety)
message_admins("[key_name_admin(usr)] engaged a nuclear bomb (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
if(!is_syndicate)
set_security_level("delta")
GLOB.bomb_set = 1 //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N
else
GLOB.bomb_set = 0
anchored = !(anchored)
if(anchored)
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring.</span>")
else
visible_message("<span class='warning'>The anchoring bolts slide back into the depths of [src].</span>")
return
if("set_time")
var/time = input(usr, "Detonation time (seconds, min 120, max 600)", "Input Time", 120) as num|null
if(time)
timeleft = min(max(round(time), 120), 600)
if("toggle_safety")
safety = !(safety)
if(safety)
if(!is_syndicate)
set_security_level(previous_level)
timing = FALSE
GLOB.bomb_set = FALSE
if("toggle_armed")
if(safety)
to_chat(usr, "<span class='notice'>The safety is still on.</span>")
return
timing = !(timing)
if(timing)
if(!lighthack)
icon_state = "nuclearbomb2"
if(!safety)
message_admins("[key_name_admin(usr)] engaged a nuclear bomb [ADMIN_JMP(src)]")
if(!is_syndicate)
set_security_level(previous_level)
GLOB.bomb_set = 0
if(!lighthack)
icon_state = "nuclearbomb1"
if(href_list["safety"])
safety = !(safety)
if(safety)
if(!is_syndicate)
set_security_level(previous_level)
timing = 0
GLOB.bomb_set = 0
if(href_list["anchor"])
if(removal_stage == NUKE_MOBILE)
anchored = 0
visible_message("<span class='warning'>\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
SSnanoui.update_uis(src)
return
if(!isinspace())
anchored = !(anchored)
if(anchored)
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring.</span>")
else
visible_message("<span class='warning'>The anchoring bolts slide back into the depths of [src].</span>")
set_security_level("delta")
GLOB.bomb_set = TRUE // There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke
else
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
GLOB.bomb_set = TRUE
else
if(!is_syndicate)
set_security_level(previous_level)
GLOB.bomb_set = FALSE
if(!lighthack)
icon_state = "nuclearbomb1"
SSnanoui.update_uis(src)
/obj/machinery/nuclearbomb/blob_act(obj/structure/blob/B)
if(timing == -1.0)
if(exploded)
return
if(timing) //boom
INVOKE_ASYNC(src, .proc/explode)
@@ -360,11 +335,11 @@ GLOBAL_VAR(bomb_set)
#define NUKERANGE 80
/obj/machinery/nuclearbomb/proc/explode()
if(safety)
timing = 0
timing = FALSE
return
timing = -1.0
yes_code = 0
safety = 1
exploded = TRUE
yes_code = FALSE
safety = TRUE
if(!lighthack)
icon_state = "nuclearbomb3"
playsound(src,'sound/machines/alarm.ogg',100,0,5)
+13 -4
View File
@@ -279,6 +279,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
var/blood = 0
var/old_bloodtotal = 0 //used to see if we increased our blood total
var/old_bloodusable = 0 //used to see if we increased our blood usable
var/blood_volume_warning = 9999 //Blood volume threshold for warnings
if(owner.is_muzzled())
to_chat(owner, "<span class='warning'>[owner.wear_mask] prevents you from biting [H]!</span>")
draining = null
@@ -291,13 +292,10 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
H.LAssailant = owner
while(do_mob(owner, H, 50))
if(!(owner.mind in SSticker.mode.vampires))
to_chat(owner, "<span class='warning'>Your fangs have disappeared!</span>")
to_chat(owner, "<span class='userdanger'>Your fangs have disappeared!</span>")
return
old_bloodtotal = bloodtotal
old_bloodusable = bloodusable
if(!H.blood_volume)
to_chat(owner, "<span class='warning'>They've got no blood left to give.</span>")
break
if(H.stat < DEAD)
if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died
blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood
@@ -312,6 +310,17 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].</b></span>")
check_vampire_upgrade()
H.blood_volume = max(H.blood_volume - 25, 0)
//Blood level warnings (Code 'borrowed' from Fulp)
if(H.blood_volume)
if(H.blood_volume <= BLOOD_VOLUME_BAD && blood_volume_warning > BLOOD_VOLUME_BAD)
to_chat(owner, "<span class='danger'>Your victim's blood volume is dangerously low.</span>")
else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY)
to_chat(owner, "<span class='warning'>Your victim's blood is at an unsafe level.</span>")
blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once
else
to_chat(owner, "<span class='warning'>You have bled your victim dry!</span>")
break
if(ishuman(owner))
var/mob/living/carbon/human/V = owner
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
+23
View File
@@ -510,3 +510,26 @@ proc/get_all_job_icons() //For all existing HUD icons
return rankName
return "Unknown" //Return unknown if none of the above apply
proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND)
var/list/retval
for(var/i in num_min_region to num_max_region)
var/list/accesses = list()
var/list/available_accesses
if(i == REGION_CENTCOMM) // Override necessary, because get_region_accesses(REGION_CENTCOM) returns BOTH CC and crew accesses.
available_accesses = get_all_centcom_access()
else
available_accesses = get_region_accesses(i)
for(var/access in available_accesses)
var/access_desc = (i == REGION_CENTCOMM) ? get_centcom_access_desc(access) : get_access_desc(access)
if (access_desc)
accesses += list(list(
"desc" = replacetext(access_desc, "&nbsp", " "),
"ref" = access,
))
retval += list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"accesses" = accesses
))
return retval
+1 -1
View File
@@ -18,7 +18,7 @@
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINISAT, ACCESS_MECHANIC, ACCESS_MINERAL_STOREROOM)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_ENGINEERING
outfit = /datum/outfit/job/chief_engineer
+1 -1
View File
@@ -16,7 +16,7 @@
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_PSYCHIATRIST, ACCESS_MAINT_TUNNELS, ACCESS_PARAMEDIC, ACCESS_MINERAL_STOREROOM)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_MEDICAL
outfit = /datum/outfit/job/cmo
+1 -1
View File
@@ -18,7 +18,7 @@
ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_GATEWAY, ACCESS_XENOARCH, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_NETWORK)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_SCIENCE
// All science-y guys get bonuses for maxing out their tech.
required_objectives = list(
+2 -2
View File
@@ -18,7 +18,7 @@
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_PILOT, ACCESS_WEAPONS)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_SECURITY
disabilities_allowed = 0
outfit = /datum/outfit/job/hos
@@ -64,7 +64,7 @@
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_WEAPONS)
minimal_player_age = 21
exp_requirements = 600
exp_type = EXP_TYPE_CREW
exp_type = EXP_TYPE_SECURITY
outfit = /datum/outfit/job/warden
/datum/outfit/job/warden
+2 -2
View File
@@ -13,7 +13,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
access = list() //See get_access()
minimal_access = list() //See get_access()
minimal_player_age = 30
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_COMMAND
disabilities_allowed = 0
outfit = /datum/outfit/job/captain
@@ -67,7 +67,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
req_admin_notify = 1
is_command = 1
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_COMMAND
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
+64 -88
View File
@@ -104,59 +104,46 @@
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
return
src.ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/atmospherics/unary/cold_sink/freezer/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 540, 300)
// open the new ui window
ui = new(user, src, ui_key, "GasFreezer", "Gas Cooling System", 540, 200)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1)
/obj/machinery/atmospherics/unary/cold_sink/freezer/tgui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(air_contents.return_pressure())
data["temperature"] = round(air_contents.temperature)
data["temperatureCelsius"] = round(air_contents.temperature - T0C, 1)
if(air_contents.total_moles() == 0 && air_contents.temperature == 0)
data["gasTemperatureCelsius"] = 0
data["minGasTemperature"] = round(min_temperature)
data["maxGasTemperature"] = round(T20C)
data["targetGasTemperature"] = round(current_temperature)
data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1)
var/temp_class = "good"
if(air_contents.temperature > (T0C - 20))
temp_class = "bad"
else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100))
temp_class = "average"
data["gasTemperatureClass"] = temp_class
data["temperatureCelsius"] = 0
data["min"] = round(min_temperature)
data["max"] = round(T20C)
data["target"] = round(current_temperature)
data["targetCelsius"] = round(current_temperature - T0C, 1)
return data
/obj/machinery/atmospherics/unary/cold_sink/freezer/Topic(href, href_list)
/obj/machinery/atmospherics/unary/cold_sink/freezer/tgui_act(action, params)
if(..())
return 1
if(href_list["toggleStatus"])
src.on = !src.on
update_icon()
else if(href_list["minimum"])
current_temperature = min_temperature
else if(href_list["maximum"])
current_temperature = T20C
else if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
src.current_temperature = min(T20C, src.current_temperature+amount)
else
src.current_temperature = max(min_temperature, src.current_temperature+amount)
src.add_fingerprint(usr)
return 1
return
add_fingerprint(usr)
. = TRUE
switch(action)
if("power")
on = !on
update_icon()
if("minimum")
current_temperature = min_temperature
if("maximum")
current_temperature = T20C
if("temp")
var/amount = params["temp"]
amount = text2num(amount)
current_temperature = clamp(amount, T20C, min_temperature)
/obj/machinery/atmospherics/unary/cold_sink/freezer/power_change()
..()
@@ -273,57 +260,46 @@
if(panel_open)
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
return
src.ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 540, 300)
// open the new ui window
ui = new(user, src, ui_key, "GasFreezer", "Gas Heating System", 540, 200)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/tgui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(air_contents.return_pressure())
data["temperature"] = round(air_contents.temperature)
data["temperatureCelsius"] = round(air_contents.temperature - T0C, 1)
if(air_contents.total_moles() == 0 && air_contents.temperature == 0)
data["gasTemperatureCelsius"] = 0
data["minGasTemperature"] = round(T20C)
data["maxGasTemperature"] = round(T20C+max_temperature)
data["targetGasTemperature"] = round(current_temperature)
data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1)
var/temp_class = "normal"
if(air_contents.temperature > (T20C+40))
temp_class = "bad"
data["gasTemperatureClass"] = temp_class
data["temperatureCelsius"] = 0
data["min"] = round(T20C)
data["max"] = round(T20C + max_temperature)
data["target"] = round(current_temperature)
data["targetCelsius"] = round(current_temperature - T0C, 1)
return data
/obj/machinery/atmospherics/unary/heat_reservoir/heater/Topic(href, href_list)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/tgui_act(action, params)
if(..())
return 1
if(href_list["toggleStatus"])
src.on = !src.on
update_icon()
else if(href_list["minimum"])
current_temperature = T20C
else if(href_list["maximum"])
current_temperature = max_temperature + T20C
else if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
src.current_temperature = min((T20C+max_temperature), src.current_temperature+amount)
else
src.current_temperature = max(T20C, src.current_temperature+amount)
src.add_fingerprint(usr)
return 1
return
add_fingerprint(usr)
. = TRUE
switch(action)
if("power")
on = !on
update_icon()
if("minimum")
current_temperature = T20C
if("maximum")
current_temperature = max_temperature + T20C
if("temp")
var/amount = params["temp"]
amount = text2num(amount)
current_temperature = clamp(amount, T20C, T20C + max_temperature)
/obj/machinery/atmospherics/unary/heat_reservoir/heater/power_change()
..()
+54 -43
View File
@@ -125,7 +125,7 @@
return attack_hand(user)
/obj/machinery/sleeper/attack_ghost(mob/user)
return attack_hand(user)
tgui_interact(user)
/obj/machinery/sleeper/attack_hand(mob/user)
if(stat & (NOPOWER|BROKEN))
@@ -135,17 +135,17 @@
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/sleeper/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "sleeper.tmpl", "Sleeper", 550, 770)
ui = new(user, src, ui_key, "Sleeper", "Sleeper", 550, 775)
ui.open()
ui.set_auto_update(1)
/obj/machinery/sleeper/ui_data(mob/user, datum/topic_state/state)
/obj/machinery/sleeper/tgui_data(mob/user)
var/data[0]
data["amounts"] = amounts
data["hasOccupant"] = occupant ? 1 : 0
var/occupantData[0]
var/crisis = 0
@@ -210,9 +210,13 @@
if(beaker)
data["isBeakerLoaded"] = 1
if(beaker.reagents)
data["beakerMaxSpace"] = beaker.reagents.maximum_volume
data["beakerFreeSpace"] = round(beaker.reagents.maximum_volume - beaker.reagents.total_volume)
else
data["beakerMaxSpace"] = 0
data["beakerFreeSpace"] = 0
else
data["isBeakerLoaded"] = FALSE
var/chemicals[0]
for(var/re in possible_chems)
@@ -234,51 +238,52 @@
if(temp.id in occupant.reagents.overdose_list())
overdosing = 1
// Because I don't know how to do this on the nano side
pretty_amount = round(reagent_amount, 0.05)
chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("chemical" = temp.id), "occ_amount" = reagent_amount, "pretty_amount" = pretty_amount, "injectable" = injectable, "overdosing" = overdosing, "od_warning" = caution)))
data["chemicals"] = chemicals
return data
/obj/machinery/sleeper/Topic(href, href_list)
if(!controls_inside && usr == occupant)
return 0
/obj/machinery/sleeper/tgui_act(action, params)
if(..())
return 1
return
if(!controls_inside && usr == occupant)
return
if(panel_open)
to_chat(usr, "<span class='notice'>Close the maintenance panel first.</span>")
return 0
return
if(stat & (NOPOWER|BROKEN))
return
if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon/ai)))
if(href_list["chemical"])
if(occupant)
if(occupant.stat == DEAD)
to_chat(usr, "<span class='danger'>This person has no life for to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
else if(occupant.health > min_health || (href_list["chemical"] in emergency_chems))
inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"]))
else
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
if(href_list["removebeaker"])
. = TRUE
switch(action)
if("chemical")
if(!occupant)
return
if(occupant.stat == DEAD)
to_chat(usr, "<span class='danger'>This person has no life to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
return
var/chemical = params["chemid"]
var/amount = text2num(params["amount"])
if(!length(chemical) || amount <= 0)
return
if(occupant.health > min_health || (chemical in emergency_chems))
inject_chemical(usr, chemical, amount)
else
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
if("removebeaker")
remove_beaker()
if(href_list["togglefilter"])
if("togglefilter")
toggle_filter()
if(href_list["ejectify"])
if("ejectify")
eject()
if(href_list["auto_eject_dead_on"])
if("auto_eject_dead_on")
auto_eject_dead = TRUE
if(href_list["auto_eject_dead_off"])
if("auto_eject_dead_off")
auto_eject_dead = FALSE
add_fingerprint(usr)
return 1
else
return FALSE
add_fingerprint(usr)
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/glass))
@@ -290,6 +295,7 @@
beaker = I
I.forceMove(src)
user.visible_message("[user] adds \a [I] to [src]!", "You add \a [I] to [src]!")
SStgui.update_uis(src)
return
else
@@ -328,6 +334,7 @@
to_chat(M, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
add_fingerprint(user)
qdel(G)
SStgui.update_uis(src)
return
return ..()
@@ -374,9 +381,11 @@
occupant = null
updateUsrDialog()
update_icon()
SStgui.update_uis(src)
if(A == beaker)
beaker = null
updateUsrDialog()
SStgui.update_uis(src)
/obj/machinery/sleeper/emp_act(severity)
if(filtering)
@@ -394,7 +403,7 @@
qdel(src)
/obj/machinery/sleeper/proc/toggle_filter()
if(filtering)
if(filtering || !beaker)
filtering = 0
else
filtering = 1
@@ -410,29 +419,28 @@
// eject trash the occupant dropped
for(var/atom/movable/A in contents - component_parts - list(beaker))
A.forceMove(loc)
SStgui.update_uis(src)
/obj/machinery/sleeper/force_eject_occupant()
go_out()
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user as mob, chemical, amount)
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user, chemical, amount)
if(!(chemical in possible_chems))
to_chat(user, "<span class='notice'>The sleeper does not offer that chemical!</span>")
return
if(!(amount in amounts))
return
if(occupant)
if(occupant.reagents)
if(occupant.reagents.get_reagent_amount(chemical) + amount <= max_chem)
occupant.reagents.add_reagent(chemical, amount)
return
else
to_chat(user, "You can not inject any more of this chemical.")
return
else
to_chat(user, "The patient rejects the chemicals!")
return
else
to_chat(user, "There's no occupant in the sleeper!")
return
/obj/machinery/sleeper/verb/eject()
set name = "Eject Sleeper"
@@ -459,6 +467,7 @@
filtering = 0
beaker.forceMove(usr.loc)
beaker = null
SStgui.update_uis(src)
add_fingerprint(usr)
return
@@ -511,6 +520,7 @@
add_fingerprint(user)
if(user.pulling == L)
user.stop_pulling()
SStgui.update_uis(src)
return
return
@@ -547,6 +557,7 @@
for(var/obj/O in src)
qdel(O)
add_fingerprint(usr)
SStgui.update_uis(src)
return
return
+38 -30
View File
@@ -65,6 +65,7 @@
icon_state = "body_scanner_1"
add_fingerprint(user)
qdel(TYPECAST_YOUR_SHIT)
SStgui.update_uis(src)
return
return ..()
@@ -127,12 +128,13 @@
occupant = H
icon_state = "bodyscanner"
add_fingerprint(user)
SStgui.update_uis(src)
/obj/machinery/bodyscanner/attack_ai(user)
return attack_hand(user)
/obj/machinery/bodyscanner/attack_ghost(user)
return attack_hand(user)
tgui_interact(user)
/obj/machinery/bodyscanner/attack_hand(user)
if(stat & (NOPOWER|BROKEN))
@@ -145,7 +147,7 @@
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/bodyscanner/relaymove(mob/user)
if(user.incapacitated())
@@ -171,6 +173,7 @@
// eject trash the occupant dropped
for(var/atom/movable/A in contents - component_parts)
A.forceMove(loc)
SStgui.update_uis(src)
/obj/machinery/bodyscanner/force_eject_occupant()
go_out()
@@ -192,17 +195,16 @@
new /obj/effect/gibspawner/generic(get_turf(loc)) //I REPLACE YOUR TECHNOLOGY WITH FLESH!
qdel(src)
/obj/machinery/bodyscanner/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/bodyscanner/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 600)
ui = new(user, src, ui_key, "BodyScanner", "Body Scanner", 690, 600)
ui.open()
ui.set_auto_update(1)
/obj/machinery/bodyscanner/ui_data(mob/user, datum/topic_state/state)
/obj/machinery/bodyscanner/tgui_data(mob/user)
var/data[0]
data["occupied"] = occupant ? 1 : 0
data["occupied"] = occupant ? TRUE : FALSE
var/occupantData[0]
if(occupant)
@@ -236,9 +238,9 @@
occupantData["hasBorer"] = occupant.has_brain_worms()
var/bloodData[0]
bloodData["hasBlood"] = 0
bloodData["hasBlood"] = FALSE
if(!(NO_BLOOD in occupant.dna.species.species_traits))
bloodData["hasBlood"] = 1
bloodData["hasBlood"] = TRUE
bloodData["volume"] = occupant.blood_volume
bloodData["percent"] = round(((occupant.blood_volume / BLOOD_VOLUME_NORMAL)*100))
bloodData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
@@ -282,19 +284,19 @@
if(E.status & ORGAN_BROKEN)
organStatus["broken"] = E.broken_description
if(E.is_robotic())
organStatus["robotic"] = 1
organStatus["robotic"] = TRUE
if(E.status & ORGAN_SPLINTED)
organStatus["splinted"] = 1
organStatus["splinted"] = TRUE
if(E.status & ORGAN_DEAD)
organStatus["dead"] = 1
organStatus["dead"] = TRUE
organData["status"] = organStatus
if(istype(E, /obj/item/organ/external/chest) && occupant.is_lung_ruptured())
organData["lungRuptured"] = 1
organData["lungRuptured"] = TRUE
if(E.internal_bleeding)
organData["internalBleeding"] = 1
organData["internalBleeding"] = TRUE
extOrganData.Add(list(organData))
@@ -319,27 +321,33 @@
occupantData["blind"] = (BLINDNESS in occupant.mutations)
occupantData["colourblind"] = (COLOURBLIND in occupant.mutations)
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
data["occupant"] = occupantData
return data
/obj/machinery/bodyscanner/Topic(href, href_list)
/obj/machinery/bodyscanner/tgui_act(action, params)
if(..())
return 1
return
if(stat & (NOPOWER|BROKEN))
return
if(href_list["ejectify"])
eject()
if(href_list["print_p"])
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
var/obj/item/paper/P = new /obj/item/paper(loc)
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
P.info = "<CENTER><B>Body Scan - [href_list["name"]]</B></CENTER><BR>"
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
P.info += "[generate_printing_text()]"
P.info += "<br><br><b>Notes:</b><br>"
P.name = "Body Scan - [href_list["name"]]"
. = TRUE
switch(action)
if("ejectify")
eject()
if("print_p")
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
var/obj/item/paper/P = new /obj/item/paper(loc)
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
var/name = occupant ? occupant.name : "Unknown"
P.info = "<CENTER><B>Body Scan - [name]</B></CENTER><BR>"
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
P.info += "[generate_printing_text()]"
P.info += "<br><br><b>Notes:</b><br>"
P.name = "Body Scan - [name]"
else
return FALSE
/obj/machinery/bodyscanner/proc/generate_printing_text()
var/dat = ""
+129 -222
View File
@@ -11,6 +11,7 @@
list("name" = "\[SPECIAL\]", "icon" = "whiters")
)
possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
list("name" = "\[None\]", "icon" = "none"),
list("name" = "\[N2\]", "icon" = "red-c"),
list("name" = "\[O2\]", "icon" = "blue-c"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c"),
@@ -19,6 +20,7 @@
list("name" = "\[CAUTION\]", "icon" = "yellow-c")
)
possibletertcolor = list(
list("name" = "\[None\]", "icon" = "none"),
list("name" = "\[N2\]", "icon" = "red-c-1"),
list("name" = "\[O2\]", "icon" = "blue-c-1"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-1"),
@@ -27,6 +29,7 @@
list("name" = "\[CAUTION\]", "icon" = "yellow-c-1")
)
possiblequartcolor = list(
list("name" = "\[None\]", "icon" = "none"),
list("name" = "\[N2\]", "icon" = "red-c-2"),
list("name" = "\[O2\]", "icon" = "blue-c-2"),
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-2"),
@@ -34,12 +37,6 @@
list("name" = "\[Air\]", "icon" = "grey-c-2"),
list("name" = "\[CAUTION\]", "icon" = "yellow-c-2")
)
possibledecals = list( //var that stores all possible decals, used by ui
list("name" = "Low temperature canister", "icon" = "cold"),
list("name" = "High temperature canister", "icon" = "hot"),
list("name" = "Plasma containing canister", "icon" = "plasma")
)
GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
/obj/machinery/portable_atmospherics/canister
@@ -52,22 +49,17 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
max_integrity = 250
integrity_failure = 100
var/menu = 0
//used by nanoui: 0 = main menu, 1 = relabel
var/valve_open = 0
var/release_pressure = ONE_ATMOSPHERE
var/list/canister_color //variable that stores colours
var/list/decals //list that stores the decals
var/list/color_index // list which stores tgui color indexes for the recoloring options, to enable previously-set colors to show up right
//lists for check_change()
var/list/oldcolor
var/list/olddecals
//passed to the ui to render the color lists
var/list/colorcontainer
var/list/possibledecals
var/can_label = 1
var/filled = 0.5
@@ -82,18 +74,12 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
/obj/machinery/portable_atmospherics/canister/New()
..()
canister_color = list(
"prim" = "yellow",
"sec" = "none",
"ter" = "none",
"quart" = "none")
"prim" = "yellow",
"sec" = "none",
"ter" = "none",
"quart" = "none"
)
oldcolor = new /list()
decals = list("cold" = 0, "hot" = 0, "plasma" = 0)
colorcontainer = list()
possibledecals = list()
update_icon()
/obj/machinery/portable_atmospherics/canister/proc/init_data_vars()
//passed to the ui to render the color lists
colorcontainer = list(
"prim" = list(
"options" = GLOB.canister_icon_container.possiblemaincolor,
@@ -112,26 +98,8 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
"name" = "Quaternary color",
)
)
//var/anycolor used by the nanoUI, 0: no color applied. 1: color applied
for(var/C in colorcontainer)
if(C == "prim") continue
var/list/L = colorcontainer[C]
if(!(canister_color[C]) || (canister_color[C] == "none"))
L.Add(list("anycolor" = 0))
else
L.Add(list("anycolor" = 1))
colorcontainer[C] = L
possibledecals = list()
var/i
var/list/L = GLOB.canister_icon_container.possibledecals
for(i=1;i<=L.len;i++)
var/list/LL = L[i]
LL = LL.Copy() //make sure we don't edit the datum list
LL.Add(list("active" = decals[LL["icon"]])) //"active" used by nanoUI
possibledecals.Add(LL)
color_index = list()
update_icon()
/obj/machinery/portable_atmospherics/canister/proc/check_change()
var/old_flag = update_flag
@@ -155,10 +123,6 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
update_flag |= 64
oldcolor = canister_color.Copy()
if(list2params(olddecals) != list2params(decals))
update_flag |= 128
olddecals = decals.Copy()
if(update_flag == old_flag)
return 1
else
@@ -174,17 +138,16 @@ update_flag
16 = tank_pressure < 15*ONE_ATMOS
32 = tank_pressure go boom.
64 = colors
128 = decals
(note: colors and decals has to be applied every icon update)
(note: colors has to be applied every icon update)
*/
if(src.destroyed)
src.overlays = 0
src.icon_state = text("[]-1", src.canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
if(destroyed)
overlays = 0
icon_state = text("[]-1", canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
return
if(icon_state != src.canister_color["prim"])
icon_state = src.canister_color["prim"]
if(icon_state != canister_color["prim"])
icon_state = canister_color["prim"]
if(check_change()) //Returns 1 if no change needed to icons.
return
@@ -192,14 +155,12 @@ update_flag
overlays.Cut()
for(var/C in canister_color)
if(C == "prim") continue
if(canister_color[C] == "none") continue
if(C == "prim")
continue
if(canister_color[C] == "none")
continue
overlays.Add(canister_color[C])
for(var/D in decals)
if(decals[D])
overlays.Add("decal-" + D)
if(update_flag & 1)
overlays += "can-open"
if(update_flag & 2)
@@ -213,35 +174,9 @@ update_flag
else if(update_flag & 32)
overlays += "can-o3"
update_flag &= ~196 //the flags 128 and 64 represent change, not states. As such, we have to reset them to be able to detect a change on the next go.
update_flag &= ~68 //the flag 64 represents change, not states. As such, we have to reset them to be able to detect a change on the next go.
return
//template modification exploit prevention, used in Topic()
/obj/machinery/portable_atmospherics/canister/proc/is_a_color(var/inputVar, var/checkColor = "all")
if(checkColor == "prim" || checkColor == "all")
for(var/list/L in GLOB.canister_icon_container.possiblemaincolor)
if(L["icon"] == inputVar)
return 1
if(checkColor == "sec" || checkColor == "all")
for(var/list/L in GLOB.canister_icon_container.possibleseccolor)
if(L["icon"] == inputVar)
return 1
if(checkColor == "ter" || checkColor == "all")
for(var/list/L in GLOB.canister_icon_container.possibletertcolor)
if(L["icon"] == inputVar)
return 1
if(checkColor == "quart" || checkColor == "all")
for(var/list/L in GLOB.canister_icon_container.possiblequartcolor)
if(L["icon"] == inputVar)
return 1
return 0
/obj/machinery/portable_atmospherics/canister/proc/is_a_decal(var/inputVar)
for(var/list/L in GLOB.canister_icon_container.possibledecals)
if(L["icon"] == inputVar)
return 1
return 0
/obj/machinery/portable_atmospherics/canister/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
..()
if(exposed_temperature > temperature_resistance)
@@ -271,7 +206,7 @@ update_flag
stat |= BROKEN
density = FALSE
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
update_icon()
if(holding)
@@ -297,7 +232,7 @@ update_flag
var/transfer_moles = 0
if((air_contents.temperature > 0) && (pressure_delta > 0))
transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
@@ -307,7 +242,7 @@ update_flag
else
loc.assume_air(removed)
air_update_turf()
src.update_icon()
update_icon()
if(air_contents.return_pressure() < 1)
@@ -315,20 +250,20 @@ update_flag
else
can_label = 0
src.updateDialog()
updateDialog()
return
/obj/machinery/portable_atmospherics/canister/return_air()
return air_contents
/obj/machinery/portable_atmospherics/canister/proc/return_temperature()
var/datum/gas_mixture/GM = src.return_air()
var/datum/gas_mixture/GM = return_air()
if(GM && GM.volume>0)
return GM.temperature
return 0
/obj/machinery/portable_atmospherics/canister/proc/return_pressure()
var/datum/gas_mixture/GM = src.return_air()
var/datum/gas_mixture/GM = return_air()
if(GM && GM.volume>0)
return GM.return_pressure()
return 0
@@ -343,141 +278,114 @@ update_flag
else if(valve_open && holding)
investigate_log("[key_name(user)] started a transfer into [holding].<br>", "atmos")
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob)
src.add_hiddenprint(user)
return src.attack_hand(user)
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user)
add_hiddenprint(user)
return attack_hand(user)
/obj/machinery/portable_atmospherics/canister/attack_ghost(var/mob/user as mob)
return src.ui_interact(user)
/obj/machinery/portable_atmospherics/canister/attack_ghost(var/mob/user)
return tgui_interact(user)
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob)
return src.ui_interact(user)
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user)
return tgui_interact(user)
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.physical_state)
if(src.destroyed)
return
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/portable_atmospherics/canister/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_physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400, state = state)
// open the new ui window
ui = new(user, src, ui_key, "Canister", name, 600, 350, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/portable_atmospherics/canister/ui_data(mob/user, datum/topic_state/state)
init_data_vars() //set up var/colorcontainer and var/possibledecals
// this is the data which will be sent to the ui
var/data[0]
data["name"] = name
data["menu"] = menu ? 1 : 0
data["canLabel"] = can_label ? 1 : 0
data["canister_color"] = canister_color
data["colorContainer"] = colorcontainer.Copy()
colorcontainer.Cut()
data["possibleDecals"] = possibledecals.Copy()
possibledecals.Cut()
/obj/machinery/portable_atmospherics/canister/tgui_data()
var/data = list()
data["portConnected"] = connected_port ? 1 : 0
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
data["minReleasePressure"] = round(ONE_ATMOSPHERE/10)
data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE)
data["defaultReleasePressure"] = ONE_ATMOSPHERE
data["minReleasePressure"] = round(ONE_ATMOSPHERE / 10)
data["maxReleasePressure"] = round(ONE_ATMOSPHERE * 10)
data["valveOpen"] = valve_open ? 1 : 0
data["name"] = name
data["canLabel"] = can_label ? 1 : 0
data["colorContainer"] = colorcontainer.Copy()
data["color_index"] = color_index
data["hasHoldingTank"] = holding ? 1 : 0
if(holding)
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
return data
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
/obj/machinery/portable_atmospherics/canister/tgui_act(action, params)
if(..())
return 1
if(href_list["choice"] == "menu")
menu = text2num(href_list["mode_target"])
if(href_list["toggle"])
var/logmsg
if(valve_open)
if(holding)
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding]<br>"
else
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the <font color='red'><b>air</b></font><br>"
else
if(holding)
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting the transfer into the [holding]<br>"
else
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting the transfer into the <font color='red'><b>air</b></font><br>"
if(air_contents.toxins > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
if(air_contents.sleeping_agent > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains N2O in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
log_admin("[key_name(usr)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
investigate_log(logmsg, "atmos")
release_log += logmsg
valve_open = !valve_open
if(href_list["remove_tank"])
if(holding)
if(valve_open)
valve_open = 0
release_log += "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding]<br>"
holding.loc = loc
holding = null
if(href_list["pressure_adj"])
var/diff = text2num(href_list["pressure_adj"])
if(diff > 0)
release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff)
else
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
if(href_list["rename"])
if(can_label)
var/T = sanitize(copytext(input("Choose canister label", "Name", name) as text|null,1,MAX_NAME_LEN))
if(can_label) //Exploit prevention
if(T)
name = T
return
var/can_min_release_pressure = round(ONE_ATMOSPHERE / 10)
var/can_max_release_pressure = round(ONE_ATMOSPHERE * 10)
. = TRUE
switch(action)
if("relabel")
if(can_label)
var/T = sanitize(copytext(input("Choose canister label", "Name", name) as text|null, 1, MAX_NAME_LEN))
if(can_label) //Exploit prevention
if(T)
name = T
else
name = "canister"
else
name = "canister"
to_chat(usr, "<span class='warning'>As you attempted to rename it the pressure rose!</span>")
. = FALSE
if("pressure")
var/pressure = params["pressure"]
if(pressure == "reset")
pressure = ONE_ATMOSPHERE
else if(pressure == "min")
pressure = can_min_release_pressure
else if(pressure == "max")
pressure = can_max_release_pressure
else if(pressure == "input")
pressure = input("New release pressure ([can_min_release_pressure]-[can_max_release_pressure] kPa):", name, release_pressure) as num|null
if(isnull(pressure))
. = FALSE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
if(.)
release_pressure = clamp(round(pressure), can_min_release_pressure, can_max_release_pressure)
investigate_log("was set to [release_pressure] kPa by [key_name(usr)].", "atmos")
if("valve")
var/logmsg
valve_open = !valve_open
if(valve_open)
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting a transfer into the [holding || "air"].<br>"
if(!holding)
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting a transfer into the air.<br>"
if(air_contents.toxins > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
if(air_contents.sleeping_agent > 0)
message_admins("[key_name_admin(usr)] opened a canister that contains N2O in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
log_admin("[key_name(usr)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
else
to_chat(usr, "<span class='warning'>As you attempted to rename it the pressure rose!</span>")
if(href_list["choice"] == "Primary color")
if(is_a_color(href_list["icon"],"prim"))
canister_color["prim"] = href_list["icon"]
if(href_list["choice"] == "Secondary color")
if(href_list["icon"] == "none")
canister_color["sec"] = "none"
else if(is_a_color(href_list["icon"],"sec"))
canister_color["sec"] = href_list["icon"]
if(href_list["choice"] == "Tertiary color")
if(href_list["icon"] == "none")
canister_color["ter"] = "none"
else if(is_a_color(href_list["icon"],"ter"))
canister_color["ter"] = href_list["icon"]
if(href_list["choice"] == "Quaternary color")
if(href_list["icon"] == "none")
canister_color["quart"] = "none"
else if(is_a_color(href_list["icon"],"quart"))
canister_color["quart"] = href_list["icon"]
if(href_list["choice"] == "decals")
if(is_a_decal(href_list["icon"]))
decals[href_list["icon"]] = (decals[href_list["icon"]] == 0)
src.add_fingerprint(usr)
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding || "air"].<br>"
investigate_log(logmsg, "atmos")
release_log += logmsg
if("eject")
if(holding)
if(valve_open)
if(air_contents && (air_contents.toxins > 0 || air_contents.sleeping_agent > 0))
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span>.")
release_log += "[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air<br>"
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span>.", "atmos")
replace_tank(usr, FALSE)
if("recolor")
if(can_label)
var/ctype = params["ctype"]
var/cnum = text2num(params["nc"])
if(isnull(colorcontainer[ctype]))
message_admins("[key_name_admin(usr)] passed an invalid ctype var to a canister.")
return
var/newcolor = sanitize_integer(cnum, 0, length(colorcontainer[ctype]["options"]))
color_index[ctype] = newcolor
newcolor++ // javascript starts arrays at 0, byond (for some reason) starts them at 1, this converts JS values to byond values
canister_color[ctype] = colorcontainer[ctype]["options"][newcolor]["icon"]
add_fingerprint(usr)
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/toxins
name = "Canister \[Toxin (Plasma)\]"
@@ -513,19 +421,18 @@ update_flag
..()
canister_color["prim"] = "orange"
decals["plasma"] = 1
src.air_contents.toxins = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.toxins = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/oxygen/New()
..()
canister_color["prim"] = "blue"
src.air_contents.oxygen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.oxygen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/sleeping_agent/New()
@@ -534,25 +441,25 @@ update_flag
canister_color["prim"] = "redws"
air_contents.sleeping_agent = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/nitrogen/New()
..()
canister_color["prim"] = "red"
src.air_contents.nitrogen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.nitrogen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New()
..()
canister_color["prim"] = "black"
src.air_contents.carbon_dioxide = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.carbon_dioxide = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
@@ -560,17 +467,17 @@ update_flag
..()
canister_color["prim"] = "grey"
src.air_contents.oxygen = (O2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
src.air_contents.nitrogen = (N2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.oxygen = (O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
air_contents.nitrogen = (N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
src.update_icon()
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/custom_mix/New()
..()
canister_color["prim"] = "whiters"
src.update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
return 1
/obj/machinery/portable_atmospherics/canister/welder_act(mob/user, obj/item/I)
+120 -128
View File
@@ -24,7 +24,7 @@
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
var/busy = 0
var/busy = FALSE
var/prod_coeff
var/datum/wires/autolathe/wires = null
@@ -33,7 +33,7 @@
var/list/datum/design/matching_designs
var/temp_search
var/selected_category
var/screen = 1
var/list/recipiecache = list()
var/list/categories = list("Tools", "Electronics", "Construction", "Communication", "Security", "Machinery", "Medical", "Miscellaneous", "Dinnerware", "Imported")
@@ -79,63 +79,121 @@
if(panel_open)
wires.Interact(user)
else
ui_interact(user)
tgui_interact(user)
/obj/machinery/autolathe/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/autolathe/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "autolathe.tmpl", name, 800, 550)
ui = new(user, src, ui_key, "Autolathe", name, 750, 700, master_ui, state)
ui.open()
/obj/machinery/autolathe/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/autolathe/tgui_static_data(mob/user)
var/list/data = list()
data["categories"] = categories
if(!recipiecache.len)
var/list/recipes = list()
for(var/v in files.known_designs)
var/datum/design/D = files.known_designs[v]
var/list/cost_list = design_cost_data(D)
var/list/matreq = list()
for(var/list/x in cost_list)
if(!x["amount"])
continue
if(x["name"] == "metal") // Do not use MAT_METAL or MAT_GLASS here.
matreq["metal"] = x["amount"]
if(x["name"] == "glass")
matreq["glass"] = x["amount"]
var/obj/item/I = D.build_path
var/maxmult = 1
if(ispath(D.build_path, /obj/item/stack))
maxmult = D.maxstack
recipes.Add(list(list(
"name" = D.name,
"category" = D.category,
"uid" = D.UID(),
"requirements" = matreq,
"hacked" = ("hacked" in D.category) ? TRUE : FALSE,
"max_multiplier" = maxmult,
"image" = "[icon2base64(icon(initial(I.icon), initial(I.icon_state), SOUTH, 1))]"
)))
recipiecache = recipes
data["recipes"] = recipiecache
return data
/obj/machinery/autolathe/tgui_data(mob/user)
var/list/data = list() //..()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/data[0]
data["screen"] = screen
data["total_amount"] = materials.total_amount
data["max_amount"] = materials.max_amount
data["fill_percent"] = round((materials.total_amount / materials.max_amount) * 100)
data["metal_amount"] = materials.amount(MAT_METAL)
data["glass_amount"] = materials.amount(MAT_GLASS)
switch(screen)
if(AUTOLATHE_MAIN_MENU)
data["uid"] = UID()
data["categories"] = categories
if(AUTOLATHE_CATEGORY_MENU)
data["selected_category"] = selected_category
var/list/designs = list()
data["designs"] = designs
for(var/v in files.known_designs)
var/datum/design/D = files.known_designs[v]
if(!(selected_category in D.category))
continue
var/list/design = list()
designs[++designs.len] = design
design["name"] = D.name
design["id"] = D.id
design["disabled"] = disabled || !can_build(D) ? "disabled" : null
if(ispath(D.build_path, /obj/item/stack))
design["max_multiplier"] = min(D.maxstack, D.materials[MAT_METAL] ? round(materials.amount(MAT_METAL) / D.materials[MAT_METAL]) : INFINITY, D.materials[MAT_GLASS] ? round(materials.amount(MAT_GLASS) / D.materials[MAT_GLASS]) : INFINITY)
else
design["max_multiplier"] = null
design["materials"] = design_cost_data(D)
if(AUTOLATHE_SEARCH_MENU)
data["search"] = temp_search
var/list/designs = list()
data["designs"] = designs
for(var/datum/design/D in matching_designs)
var/list/design = list()
designs[++designs.len] = design
design["name"] = D.name
design["id"] = D.id
design["disabled"] = disabled || !can_build(D) ? "disabled" : null
if(ispath(D.build_path, /obj/item/stack))
design["max_multiplier"] = min(D.maxstack, D.materials[MAT_METAL] ? round(materials.amount(MAT_METAL) / D.materials[MAT_METAL]) : INFINITY, D.materials[MAT_GLASS] ? round(materials.amount(MAT_GLASS) / D.materials[MAT_GLASS]) : INFINITY)
else
design["max_multiplier"] = null
design["materials"] = design_cost_data(D)
data = queue_data(data)
data["busyname"] = FALSE
data["busyamt"] = 1
if(length(being_built) > 0)
var/datum/design/D = being_built[1]
data["busyname"] = istype(D) && D.name ? D.name : FALSE
data["busyamt"] = length(being_built) > 1 ? being_built[2] : 1
data["showhacked"] = hacked ? TRUE : FALSE
data["buildQueue"] = queue
data["buildQueueLen"] = queue.len
return data
/obj/machinery/autolathe/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return FALSE
add_fingerprint(usr)
. = TRUE
switch(action)
if("clear_queue")
queue = list()
if("remove_from_queue")
var/index = text2num(params["remove_from_queue"])
if(isnum(index) && ISINRANGE(index, 1, queue.len))
remove_from_queue(index)
to_chat(usr, "<span class='notice'>Removed item from queue.</span>")
if("make")
BuildTurf = loc
var/datum/design/design_last_ordered
design_last_ordered = locateUID(params["make"])
if(!istype(design_last_ordered))
to_chat(usr, "<span class='warning'>Invalid design</span>")
return
if(!(design_last_ordered.build_type & AUTOLATHE))
to_chat(usr, "<span class='warning'>Invalid design (not buildable in autolathe, report this error.)</span>")
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(design_last_ordered.materials["$metal"] > materials.amount(MAT_METAL))
to_chat(usr, "<span class='warning'>Invalid design (not enough metal)</span>")
return
if(design_last_ordered.materials["$glass"] > materials.amount(MAT_GLASS))
to_chat(usr, "<span class='warning'>Invalid design (not enough glass)</span>")
return
if(!hacked && ("hacked" in design_last_ordered.category))
to_chat(usr, "<span class='warning'>Invalid design (lathe requires hacking)</span>")
return
//multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier
var/multiplier = text2num(params["multiplier"])
var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY)
var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack)
if(!is_stack && (multiplier > 1))
return
if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc
message_admins("Player [key_name_admin(usr)] attempted to pass invalid multiplier [multiplier] to an autolathe in tgui_act. Possible href exploit.")
return
if((queue.len + 1) < queue_max_len)
add_to_queue(design_last_ordered, multiplier)
else
to_chat(usr, "<span class='warning'>The autolathe queue is full!</span>")
if(!busy)
busy = TRUE
process_queue()
busy = FALSE
/obj/machinery/autolathe/proc/design_cost_data(datum/design/D)
var/list/data = list()
var/coeff = get_coeff(D)
@@ -185,14 +243,21 @@
if(istype(O, /obj/item/disk/design_disk))
var/obj/item/disk/design_disk/D = O
if(D.blueprint)
if(!(D.blueprint.build_type & AUTOLATHE)) // otherwise, would silently fail in AddDesign2Known
to_chat(user, "<span class='warning'>This design is not compatible with the autolathe.</span>")
return 1
user.visible_message("[user] begins to load \the [O] in \the [src]...",
"You begin to load a design from \the [O]...",
"You hear the chatter of a floppy drive.")
playsound(get_turf(src), 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
busy = 1
busy = TRUE
if(do_after(user, 14.4, target = src))
if(!("Imported" in D.blueprint.category)) // R&D should always ensure this is set on design disks, but it doesn't.
D.blueprint.category += "Imported" // now it will actually show up in the list.
files.AddDesign2Known(D.blueprint)
busy = 0
recipiecache = list()
SStgui.close_uis(src) // forces all connected users to re-open the TGUI. Imported entries won't show otherwise due to static_data
busy = FALSE
else
to_chat(user, "<span class='warning'>That disk does not have a design on it!</span>")
return 1
@@ -222,7 +287,6 @@
to_chat(user, "<span class='alert'>The autolathe is busy. Please wait for completion of previous operation.</span>")
return
if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", I))
SSnanoui.update_uis(src)
I.play_tool_sound(user, I.tool_volume)
/obj/machinery/autolathe/wirecutter_act(mob/user, obj/item/I)
@@ -254,7 +318,7 @@
if(MAT_GLASS)
flick("autolathe_r", src)//plays glass insertion animation
use_power(min(1000, amount_inserted / 100))
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/autolathe/attack_ghost(mob/user)
interact(user)
@@ -264,79 +328,6 @@
return
interact(user)
/obj/machinery/autolathe/Topic(href, href_list)
if(..())
return 1
if(href_list["menu"])
screen = text2num(href_list["menu"])
if(href_list["category"])
selected_category = href_list["category"]
screen = AUTOLATHE_CATEGORY_MENU
if(href_list["make"])
BuildTurf = loc
/////////////////
//href protection
var/datum/design/design_last_ordered
design_last_ordered = files.FindDesignByID(href_list["make"]) //check if it's a valid design
if(!design_last_ordered)
return
if(!(design_last_ordered.build_type & AUTOLATHE))
return
//multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier
var/multiplier = text2num(href_list["multiplier"])
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY)
var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack)
if(!is_stack && (multiplier > 1))
return
if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc
return
/////////////////
if((queue.len + 1) < queue_max_len)
add_to_queue(design_last_ordered,multiplier)
else
to_chat(usr, "<span class='warning'>The autolathe queue is full!</span>")
if(!busy)
busy = 1
process_queue()
busy = 0
if(href_list["remove_from_queue"])
var/index = text2num(href_list["remove_from_queue"])
if(isnum(index) && ISINRANGE(index, 1, queue.len))
remove_from_queue(index)
if(href_list["queue_move"] && href_list["index"])
var/index = text2num(href_list["index"])
var/new_index = index + text2num(href_list["queue_move"])
if(isnum(index) && isnum(new_index))
if(ISINRANGE(new_index, 1, queue.len))
queue.Swap(index,new_index)
if(href_list["clear_queue"])
queue = list()
if(href_list["search"])
if(href_list["to_search"])
temp_search = href_list["to_search"]
if(!temp_search)
return
matching_designs.Cut()
for(var/v in files.known_designs)
var/datum/design/D = files.known_designs[v]
if(findtext(D.name, temp_search))
matching_designs.Add(D)
screen = AUTOLATHE_SEARCH_MENU
SSnanoui.update_uis(src)
return 1
/obj/machinery/autolathe/RefreshParts()
var/tot_rating = 0
prod_coeff = 0
@@ -371,7 +362,7 @@
else
var/list/materials_used = list(MAT_METAL=metal_cost/coeff, MAT_GLASS=glass_cost/coeff)
materials.use_amount(materials_used)
SSnanoui.update_uis(src)
SStgui.update_uis(src)
sleep(32/coeff)
if(is_stack)
var/obj/item/stack/S = new D.build_path(BuildTurf)
@@ -380,7 +371,7 @@
var/obj/item/new_item = new D.build_path(BuildTurf)
new_item.materials[MAT_METAL] /= coeff
new_item.materials[MAT_GLASS] /= coeff
SSnanoui.update_uis(src)
SStgui.update_uis(src)
desc = initial(desc)
/obj/machinery/autolathe/proc/can_build(datum/design/D, multiplier = 1, custom_metal, custom_glass)
@@ -455,7 +446,6 @@
D = listgetindex(listgetindex(queue, 1),1)
multiplier = listgetindex(listgetindex(queue,1),2)
being_built = new /list()
//visible_message("[bicon(src)] <b>\The [src]</b> beeps, \"Queue processing finished successfully.\"")
/obj/machinery/autolathe/proc/adjust_hacked(hack)
hacked = hack
@@ -468,6 +458,8 @@
for(var/datum/design/D in files.known_designs)
if("hacked" in D.category)
files.known_designs -= D.id
SStgui.close_uis(src) // forces all connected users to re-open the TGUI, thus adding/removing hacked entries from lists
recipiecache = list()
/obj/machinery/autolathe/proc/check_hacked_callback()
if(!wires.is_cut(WIRE_AUTOLATHE_HACK))
+40 -36
View File
@@ -40,8 +40,7 @@
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/operating/attack_hand(mob/user)
if(..(user))
@@ -52,16 +51,15 @@
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)//ui is mostly copy pasta from the sleeper ui
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/operating/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "op_computer.tmpl", "Patient Monitor", 650, 455)
ui = new(user, src, ui_key, "OperatingComputer", "Patient Monitor", 650, 455, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/operating/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/computer/operating/tgui_data(mob/user)
var/data[0]
var/mob/living/carbon/human/occupant
if(table)
@@ -136,38 +134,43 @@
return data
/obj/machinery/computer/operating/Topic(href, href_list)
/obj/machinery/computer/operating/tgui_act(action, params)
if(..())
return 1
return
if(stat & (NOPOWER|BROKEN))
return
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)
if(href_list["verboseOn"])
verbose=1
if(href_list["verboseOff"])
verbose=0
if(href_list["healthOn"])
healthAnnounce=1
if(href_list["healthOff"])
healthAnnounce=0
if(href_list["critOn"])
crit=1
if(href_list["critOff"])
crit=0
if(href_list["oxyOn"])
oxy=1
if(href_list["oxyOff"])
oxy=0
if(href_list["oxy_adj"]!=0)
oxyAlarm=oxyAlarm+text2num(href_list["oxy_adj"])
if(href_list["choiceOn"])
choice=1
if(href_list["choiceOff"])
choice=0
if(href_list["health_adj"]!=0)
healthAlarm=healthAlarm+text2num(href_list["health_adj"])
return
. = TRUE
switch(action)
if("verboseOn")
verbose = TRUE
if("verboseOff")
verbose = FALSE
if("healthOn")
healthAnnounce = TRUE
if("healthOff")
healthAnnounce = FALSE
if("critOn")
crit = TRUE
if("critOff")
crit = FALSE
if("oxyOn")
oxy = TRUE
if("oxyOff")
oxy = FALSE
if("oxy_adj")
oxyAlarm = clamp(text2num(params["new"]), -100, 100)
if("choiceOn")
choice = TRUE
if("choiceOff")
choice = FALSE
if("health_adj")
healthAlarm = clamp(text2num(params["new"]), -100, 100)
else
return FALSE
/obj/machinery/computer/operating/process()
@@ -178,6 +181,7 @@
atom_say("New patient detected, loading stats")
victim = table.victim
atom_say("[victim.real_name], [victim.dna.blood_type] blood, [victim.stat ? "Non-Responsive" : "Awake"]")
SStgui.update_uis(src)
if(nextTick < world.time)
nextTick=world.time + OP_COMPUTER_COOLDOWN
if(crit && victim.health <= -50 )
+41 -38
View File
@@ -22,23 +22,22 @@
return ..()
/obj/machinery/computer/aifixer/attack_ai(var/mob/user as mob)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/aifixer/attack_hand(var/mob/user as mob)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/aifixer/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ai_fixer.tmpl", "AI System Integrity Restorer", 550, 500)
ui = new(user, src, ui_key, "AIFixer", name, 550, 500, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/aifixer/ui_data(mob/user, datum/topic_state/state)
/obj/machinery/computer/aifixer/tgui_data(mob/user, datum/topic_state/state)
var/data[0]
data["occupant"] = (occupant ? occupant.name : null) // a null occupant isn't passed on if this is below the if.
if(occupant)
data["occupant"] = occupant.name
data["reference"] = "\ref[occupant]"
data["integrity"] = (occupant.health+100)/2
data["stat"] = occupant.stat
@@ -48,45 +47,49 @@
var/laws[0]
for(var/datum/ai_law/law in occupant.laws.all_laws())
laws.Add(list(list("law" = law.law, "number" = law.get_index())))
if(law in occupant.laws.ion_laws) // If we're an ion law, give it an ion index code
laws.Add(ionnum() + ". " + law.law)
else
laws.Add(num2text(law.get_index()) + ". " + law.law)
data["laws"] = laws
data["has_laws"] = length(laws)
return data
/obj/machinery/computer/aifixer/Topic(href, href_list)
/obj/machinery/computer/aifixer/tgui_act(action, params)
if(..())
return 1
return
switch(action)
if("fix")
if(active) // Prevent from starting a fix while fixing.
to_chat(usr, "<span class='warning'>You are already fixing this AI!</span>")
return
active = TRUE
INVOKE_ASYNC(src, .proc/fix_ai)
add_fingerprint(usr)
if(href_list["fix"])
active = 1
while(occupant.health < 100)
occupant.adjustOxyLoss(-1, FALSE)
occupant.adjustFireLoss(-1, FALSE)
occupant.adjustToxLoss(-1, FALSE)
occupant.adjustBruteLoss(-1, FALSE)
occupant.updatehealth()
if(occupant.health >= 0 && occupant.stat == DEAD)
occupant.update_revive()
occupant.lying = 0
update_icon()
sleep(10)
active = 0
add_fingerprint(usr)
if("wireless")
occupant.control_disabled = !occupant.control_disabled
if(href_list["wireless"])
var/wireless = text2num(href_list["wireless"])
if(wireless == 0 || wireless == 1)
occupant.control_disabled = wireless
if("radio")
occupant.aiRadio.disabledAi = !occupant.aiRadio.disabledAi
if(href_list["radio"])
var/radio = text2num(href_list["radio"])
if(radio == 0 || radio == 1)
occupant.aiRadio.disabledAi = radio
SSnanoui.update_uis(src)
update_icon()
return
return TRUE
/obj/machinery/computer/aifixer/proc/fix_ai() // Can we fix it? Probrably.
while(occupant.health < 100)
occupant.adjustOxyLoss(-1, FALSE)
occupant.adjustFireLoss(-1, FALSE)
occupant.adjustToxLoss(-1, FALSE)
occupant.adjustBruteLoss(-1, FALSE)
occupant.updatehealth()
if(occupant.health >= 0 && occupant.stat == DEAD)
occupant.update_revive()
occupant.lying = FALSE
update_icon()
sleep(10)
active = FALSE
/obj/machinery/computer/aifixer/update_icon()
..()
+247 -199
View File
@@ -1,3 +1,6 @@
#define MENU_MAIN 1
#define MENU_RECORDS 2
/obj/machinery/computer/cloning
name = "cloning console"
icon = 'icons/obj/computer.dmi'
@@ -6,11 +9,11 @@
circuit = /obj/item/circuitboard/cloning
req_access = list(ACCESS_HEADS) //Only used for record deletion right now.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods = list() //Linked cloning pods.
var/temp = ""
var/scantemp = "Scanner ready."
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/list/pods = null //Linked cloning pods.
var/list/temp = null
var/list/scantemp = null
var/menu = MENU_MAIN //Which menu screen to display
var/list/records = null
var/datum/dna2/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
@@ -24,6 +27,9 @@
/obj/machinery/computer/cloning/Initialize()
..()
pods = list()
records = list()
set_scan_temp("Scanner ready.", "good")
updatemodules()
/obj/machinery/computer/cloning/Destroy()
@@ -91,7 +97,7 @@
W.loc = src
src.diskette = W
to_chat(user, "You insert [W].")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
return
else if(istype(W, /obj/item/multitool))
var/obj/item/multitool/M = W
@@ -117,19 +123,21 @@
return
updatemodules()
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/cloning/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/obj/machinery/computer/cloning/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)
if(stat & (NOPOWER|BROKEN))
return
// Set up the Nano UI
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
var/datum/asset/cloning/assets = get_asset_datum(/datum/asset/cloning)
assets.send(user)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "cloning_console.tmpl", "Cloning Console UI", 640, 520)
ui = new(user, src, ui_key, "CloningConsole", "Cloning Console", 640, 520)
ui.open()
/obj/machinery/computer/cloning/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/computer/cloning/tgui_data(mob/user)
var/data[0]
data["menu"] = src.menu
data["scanner"] = sanitize("[src.scanner]")
@@ -143,7 +151,18 @@
if(pod.efficiency > 5)
canpodautoprocess = 1
tempods.Add(list(list("pod" = "\ref[pod]", "name" = sanitize(capitalize(pod.name)), "biomass" = pod.biomass)))
var/status = "idle"
if(pod.mess)
status = "mess"
else if(pod.occupant && !(pod.stat & NOPOWER))
status = "cloning"
tempods.Add(list(list(
"pod" = "\ref[pod]",
"name" = sanitize(capitalize(pod.name)),
"biomass" = pod.biomass,
"status" = status,
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
)))
data["pods"] = tempods
data["loading"] = loading
@@ -168,188 +187,190 @@
temprecords.Add(list(list("record" = "\ref[R]", "realname" = sanitize(tempRealName))))
data["records"] = temprecords
if(src.menu == 3)
if(src.active_record)
data["activerecord"] = "\ref[src.active_record]"
var/obj/item/implant/health/H = null
if(src.active_record.implant)
H = locate(src.active_record.implant)
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
data["podready"] = 1
else
data["podready"] = 0
if((H) && (istype(H)))
data["health"] = H.sensehealth()
data["realname"] = sanitize(src.active_record.dna.real_name)
data["unidentity"] = src.active_record.dna.uni_identity
data["strucenzymes"] = src.active_record.dna.struc_enzymes
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
data["podready"] = 1
else
data["podready"] = 0
data["modal"] = tgui_modal_data(src)
return data
/obj/machinery/computer/cloning/Topic(href, href_list)
/obj/machinery/computer/cloning/tgui_act(action, params)
if(..())
return 1
if(loading)
return
if(stat & (NOPOWER|BROKEN))
return
if(href_list["scan"] && scanner && scanner.occupant)
scantemp = "Scanner ready."
loading = 1
spawn(20)
if(can_brainscan() && scan_mode)
scan_mob(scanner.occupant, scan_brain = 1)
else
scan_mob(scanner.occupant)
loading = 0
SSnanoui.update_uis(src)
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
autoprocess = 1
SSnanoui.update_uis(src)
if("stopautoprocess")
autoprocess = 0
SSnanoui.update_uis(src)
//No locking an open scanner.
else if((href_list["lock"]) && (!isnull(src.scanner)))
if((!src.scanner.locked) && (src.scanner.occupant))
src.scanner.locked = 1
else
src.scanner.locked = 0
else if(href_list["view_rec"])
src.active_record = locate(href_list["view_rec"])
if(istype(src.active_record,/datum/dna2/record))
if((isnull(src.active_record.ckey)))
qdel(src.active_record)
src.temp = "<span class=\"bad\">Error: Record corrupt.</span>"
else
src.menu = 3
else
src.active_record = null
src.temp = "<span class=\"bad\">Error: Record missing.</span>"
else if(href_list["del_rec"])
if((!src.active_record) || (src.menu < 3))
return
if(src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Please confirm that you want to delete the record?"
src.menu = 4
else if(src.menu == 4)
var/obj/item/card/id/C = usr.get_active_hand()
if(istype(C)||istype(C, /obj/item/pda))
if(src.check_access(C))
src.records.Remove(src.active_record)
qdel(src.active_record)
src.temp = "Record deleted."
src.menu = 2
. = TRUE
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_ANSWER)
if(params["id"] == "del_rec" && active_record)
var/obj/item/card/id/C = usr.get_active_hand()
if(!istype(C) && !istype(C, /obj/item/pda))
set_temp("ID not in hand.", "danger")
return
if(check_access(C))
records.Remove(active_record)
qdel(active_record)
set_temp("Record deleted.", "success")
menu = MENU_RECORDS
else
src.temp = "<span class=\"bad\">Error: Access denied.</span>"
else if(href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if((isnull(src.diskette)) || isnull(src.diskette.buf))
src.temp = "<span class=\"bad\">Error: The disk's data could not be read.</span>"
SSnanoui.update_uis(src)
return
if(isnull(src.active_record))
src.temp = "<span class=\"bad\">Error: No active record was found.</span>"
src.menu = 1
SSnanoui.update_uis(src)
return
src.active_record = src.diskette.buf.copy()
src.temp = "Load successful."
if("eject")
if(!isnull(src.diskette))
src.diskette.loc = src.loc
src.diskette = null
else if(href_list["save_disk"]) //Save to disk!
if((isnull(src.diskette)) || (src.diskette.read_only) || (isnull(src.active_record)))
src.temp = "<span class=\"bad\">Error: The data could not be saved.</span>"
SSnanoui.update_uis(src)
set_temp("Access denied.", "danger")
return
// DNA2 makes things a little simpler.
src.diskette.buf=src.active_record.copy()
src.diskette.buf.types=0
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
if("ui")
src.diskette.buf.types=DNA2_BUF_UI
if("ue")
src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE
if("se")
src.diskette.buf.types=DNA2_BUF_SE
src.diskette.name = "data disk - '[src.active_record.dna.real_name]'"
src.temp = "Save \[[href_list["save_disk"]]\] successful."
switch(action)
if("scan")
if(!scanner || !scanner.occupant || loading)
return
set_scan_temp("Scanner ready.", "good")
loading = TRUE
else if(href_list["refresh"])
SSnanoui.update_uis(src)
else if(href_list["selectpod"])
var/obj/machinery/clonepod/selected = locate(href_list["selectpod"])
if(istype(selected) && (selected in pods))
selected_pod = selected
else if(href_list["clone"])
var/datum/dna2/record/C = locate(href_list["clone"])
//Look for that player! They better be dead!
if(istype(C))
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!pods.len)
temp = "<span class=\"bad\">Error: No cloning pod detected.</span>"
else
var/obj/machinery/clonepod/pod = selected_pod
var/cloneresult
if(!selected_pod)
temp = "<span class=\"bad\">Error: No cloning pod selected.</span>"
else if(pod.occupant)
temp = "<span class=\"bad\">Error: The cloning pod is currently occupied.</span>"
else if(pod.biomass < CLONE_BIOMASS)
temp = "<span class=\"bad\">Error: Not enough biomass.</span>"
else if(pod.mess)
temp = "<span class=\"bad\">Error: The cloning pod is malfunctioning.</span>"
else if(!config.revival_cloning)
temp = "<span class=\"bad\">Error: Unable to initiate cloning cycle.</span>"
spawn(20)
if(can_brainscan() && scan_mode)
scan_mob(scanner.occupant, scan_brain = TRUE)
else
cloneresult = pod.growclone(C)
if(cloneresult)
if(cloneresult > 0)
temp = "Initiating cloning cycle..."
records.Remove(C)
qdel(C)
menu = 1
scan_mob(scanner.occupant)
loading = FALSE
SStgui.update_uis(src)
if("autoprocess")
autoprocess = text2num(params["on"]) > 0
if("lock")
if(isnull(scanner) || !scanner.occupant) //No locking an open scanner.
return
scanner.locked = !scanner.locked
if("view_rec")
var/ref = params["ref"]
if(!length(ref))
return
active_record = locate(ref)
if(istype(active_record))
if(isnull(active_record.ckey))
qdel(active_record)
set_temp("Error: Record corrupt.", "danger")
else
var/obj/item/implant/health/H = null
if(active_record.implant)
H = locate(active_record.implant)
var/list/payload = list(
activerecord = "\ref[active_record]",
health = (H && istype(H)) ? H.sensehealth() : "",
realname = sanitize(active_record.dna.real_name),
unidentity = active_record.dna.uni_identity,
strucenzymes = active_record.dna.struc_enzymes,
)
tgui_modal_message(src, action, "", null, payload)
else
active_record = null
set_temp("Error: Record missing.", "danger")
if("del_rec")
if(!active_record)
return
tgui_modal_boolean(src, action, "Please confirm that you want to delete the record by holding your ID and pressing Delete:", yes_text = "Delete", no_text = "Cancel")
if("disk") // Disk management.
if(!length(params["option"]))
return
switch(params["option"])
if("load")
if(isnull(diskette) || isnull(diskette.buf))
set_temp("Error: The disk's data could not be read.", "danger")
return
else if(isnull(active_record))
set_temp("Error: No active record was found.", "danger")
menu = MENU_MAIN
return
active_record = diskette.buf.copy()
set_temp("Successfully loaded from disk.", "success")
if("save")
if(isnull(diskette) || diskette.read_only || isnull(active_record))
set_temp("Error: The data could not be saved.", "danger")
return
// DNA2 makes things a little simpler.
var/types
switch(params["savetype"]) // Save as Ui/Ui+Ue/Se
if("ui")
types = DNA2_BUF_UI
if("ue")
types = DNA2_BUF_UI|DNA2_BUF_UE
if("se")
types = DNA2_BUF_SE
else
set_temp("Error: Invalid save format.", "danger")
return
diskette.buf = active_record.copy()
diskette.buf.types = types
diskette.name = "data disk - '[active_record.dna.real_name]'"
set_temp("Successfully saved to disk.", "success")
if("eject")
if(!isnull(diskette))
diskette.loc = loc
diskette = null
if("refresh")
SStgui.update_uis(src)
if("selectpod")
var/ref = params["ref"]
if(!length(ref))
return
var/obj/machinery/clonepod/selected = locate(ref)
if(istype(selected) && (selected in pods))
selected_pod = selected
if("clone")
var/ref = params["ref"]
if(!length(ref))
return
var/datum/dna2/record/C = locate(ref)
//Look for that player! They better be dead!
if(istype(C))
tgui_modal_clear(src)
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!length(pods))
set_temp("Error: No cloning pod detected.", "danger")
else
var/obj/machinery/clonepod/pod = selected_pod
var/cloneresult
if(!selected_pod)
set_temp("Error: No cloning pod selected.", "danger")
else if(pod.occupant)
set_temp("Error: The cloning pod is currently occupied.", "danger")
else if(pod.biomass < CLONE_BIOMASS)
set_temp("Error: Not enough biomass.", "danger")
else if(pod.mess)
set_temp("Error: The cloning pod is malfunctioning.", "danger")
else if(!config.revival_cloning)
set_temp("Error: Unable to initiate cloning cycle.", "danger")
else
temp = "[C.name] => <font class='bad'>Initialisation failure.</font>"
cloneresult = pod.growclone(C)
if(cloneresult)
set_temp("Initiating cloning cycle...", "success")
records.Remove(C)
qdel(C)
menu = MENU_MAIN
else
set_temp("Error: Initialisation failure.", "danger")
else
set_temp("Error: Data corruption.", "danger")
if("menu")
menu = clamp(text2num(params["num"]), MENU_MAIN, MENU_RECORDS)
if("toggle_mode")
if(loading)
return
if(can_brainscan())
scan_mode = !scan_mode
else
scan_mode = FALSE
if("eject")
if(usr.incapacitated() || !scanner || loading)
return
scanner.eject_occupant(usr)
scanner.add_fingerprint(usr)
if("cleartemp")
temp = null
else
temp = "<span class=\"bad\">Error: Data corruption.</span>"
else if(href_list["menu"])
src.menu = text2num(href_list["menu"])
temp = ""
scantemp = "Scanner ready."
else if(href_list["toggle_mode"])
if(can_brainscan())
scan_mode = !scan_mode
else
scan_mode = 0
return FALSE
src.add_fingerprint(usr)
SSnanoui.update_uis(src)
return
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob, var/scan_brain = 0)
if(stat & NOPOWER)
@@ -360,46 +381,46 @@
return
if(isnull(subject) || (!(ishuman(subject))) || (!subject.dna))
if(isalien(subject))
scantemp = "<span class=\"bad\">Error: Xenomorphs are not scannable.</span>"
SSnanoui.update_uis(src)
set_scan_temp("Xenomorphs are not scannable.", "bad")
SStgui.update_uis(src)
return
// can add more conditions for specific non-human messages here
else
scantemp = "<span class=\"bad\">Error: Subject species is not scannable.</span>"
SSnanoui.update_uis(src)
set_scan_temp("Subject species is not scannable.", "bad")
SStgui.update_uis(src)
return
if(subject.get_int_organ(/obj/item/organ/internal/brain))
var/obj/item/organ/internal/brain/Brn = subject.get_int_organ(/obj/item/organ/internal/brain)
if(istype(Brn))
if(NO_SCAN in Brn.dna.species.species_traits)
scantemp = "<span class=\"bad\">Error: [Brn.dna.species.name_plural] are not scannable.</span>"
SSnanoui.update_uis(src)
set_scan_temp("[Brn.dna.species.name_plural] are not scannable.", "bad")
SStgui.update_uis(src)
return
if(!subject.get_int_organ(/obj/item/organ/internal/brain))
scantemp = "<span class=\"bad\">Error: No brain detected in subject.</span>"
SSnanoui.update_uis(src)
set_scan_temp("No brain detected in subject.", "bad")
SStgui.update_uis(src)
return
if(subject.suiciding)
scantemp = "<span class=\"bad\">Error: Subject has committed suicide and is not scannable.</span>"
SSnanoui.update_uis(src)
set_scan_temp("Subject has committed suicide and is not scannable.", "bad")
SStgui.update_uis(src)
return
if((!subject.ckey) || (!subject.client))
scantemp = "<span class=\"bad\">Error: Subject's brain is not responding. Further attempts after a short delay may succeed.</span>"
SSnanoui.update_uis(src)
set_scan_temp("Subject's brain is not responding. Further attempts after a short delay may succeed.", "bad")
SStgui.update_uis(src)
return
if((NOCLONE in subject.mutations) && src.scanner.scan_level < 2)
scantemp = "<span class=\"bad\">Error: Subject has incompatible genetic mutations.</span>"
SSnanoui.update_uis(src)
set_scan_temp("Subject has incompatible genetic mutations.", "bad")
SStgui.update_uis(src)
return
if(!isnull(find_record(subject.ckey)))
scantemp = "Subject already in database."
SSnanoui.update_uis(src)
set_scan_temp("Subject already in database.")
SStgui.update_uis(src)
return
for(var/obj/machinery/clonepod/pod in pods)
if(pod.occupant && pod.clonemind == subject.mind)
scantemp = "Subject already getting cloned."
SSnanoui.update_uis(src)
set_scan_temp("Subject already getting cloned.")
SStgui.update_uis(src)
return
subject.dna.check_integrity()
@@ -434,8 +455,8 @@
R.mind = "\ref[subject.mind]"
src.records += R
scantemp = "Subject successfully scanned. " + extra_info
SSnanoui.update_uis(src)
set_scan_temp("Subject successfully scanned. [extra_info]", "good")
SStgui.update_uis(src)
//Find a specific record by key.
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
@@ -451,3 +472,30 @@
/obj/machinery/computer/cloning/proc/can_brainscan()
return (scanner && scanner.scan_level > 3)
/**
* Sets a temporary message to display to the user
*
* Arguments:
* * text - Text to display, null/empty to clear the message from the UI
* * style - The style of the message: (color name), info, success, warning, danger
*/
/obj/machinery/computer/cloning/proc/set_temp(text = "", style = "info", update_now = FALSE)
temp = list(text = text, style = style)
if(update_now)
SStgui.update_uis(src)
/**
* Sets a temporary scan message to display to the user
*
* Arguments:
* * text - Text to display, null/empty to clear the message from the UI
* * color - The color of the message: (color name)
*/
/obj/machinery/computer/cloning/proc/set_scan_temp(text = "", color = "", update_now = FALSE)
scantemp = list(text = text, color = color)
if(update_now)
SStgui.update_uis(src)
#undef MENU_MAIN
#undef MENU_RECORDS
+135 -155
View File
@@ -1,35 +1,39 @@
#define COMM_SCREEN_MAIN 1
#define COMM_SCREEN_STAT 2
#define COMM_SCREEN_MESSAGES 3
#define COMM_SCREEN_SECLEVEL 4
#define COMM_AUTHENTICATION_NONE 0
#define COMM_AUTHENTICATION_MIN 1
#define COMM_AUTHENTICATION_MAX 2
#define COMM_MSGLEN_MINIMUM 6
#define COMM_CCMSGLEN_MINIMUM 20
// The communications computer
/obj/machinery/computer/communications
name = "communications console"
desc = "This can be used for various important functions. Still under developement."
desc = "This allows the Captain to contact Central Command, or change the alert level. It also allows the command staff to call the Escape Shuttle."
icon_keyboard = "tech_key"
icon_screen = "comm"
req_access = list(ACCESS_HEADS)
circuit = /obj/item/circuitboard/communications
var/prints_intercept = 1
var/authenticated = COMM_AUTHENTICATION_NONE
var/list/messagetitle = list()
var/list/messagetext = list()
var/currmsg = 0
var/aicurrmsg = 0
var/currmsg
var/authenticated = COMM_AUTHENTICATION_NONE
var/menu_state = COMM_SCREEN_MAIN
var/ai_menu_state = COMM_SCREEN_MAIN
var/message_cooldown = 0
var/centcomm_message_cooldown = 0
var/aicurrmsg
var/message_cooldown
var/centcomm_message_cooldown
var/tmp_alertlevel = 0
var/stat_msg1
var/stat_msg2
var/display_type="blank"
var/display_type = "blank"
var/display_icon
var/datum/announcement/priority/crew_announcement = new
@@ -70,123 +74,113 @@
feedback_inc("alert_comms_blue",1)
tmp_alertlevel = 0
/obj/machinery/computer/communications/Topic(href, href_list)
if(..(href, href_list))
return 1
if(!is_secure_level(src.z))
/obj/machinery/computer/communications/tgui_act(action, params)
if(..())
return
if(!is_secure_level(z))
to_chat(usr, "<span class='warning'>Unable to establish a connection: You're too far away from the station!</span>")
return 1
return
if(href_list["login"])
. = TRUE
if(action == "auth")
if(!ishuman(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return FALSE
// Logout function.
if(authenticated != COMM_AUTHENTICATION_NONE)
authenticated = COMM_AUTHENTICATION_NONE
crew_announcement.announcer = null
setMenuState(usr, COMM_SCREEN_MAIN)
return
// Login function.
var/list/access = usr.get_access()
if(allowed(usr))
authenticated = COMM_AUTHENTICATION_MIN
if(ACCESS_CAPTAIN in access)
authenticated = COMM_AUTHENTICATION_MAX
var/mob/living/carbon/human/H = usr
var/obj/item/card/id = H.get_idcard(TRUE)
if(istype(id))
crew_announcement.announcer = GetNameAndAssignmentFromId(id)
SSnanoui.update_uis(src)
return
if(href_list["logout"])
authenticated = COMM_AUTHENTICATION_NONE
crew_announcement.announcer = ""
setMenuState(usr,COMM_SCREEN_MAIN)
SSnanoui.update_uis(src)
if(authenticated == COMM_AUTHENTICATION_NONE)
to_chat(usr, "<span class='warning'>You need to wear your ID.</span>")
return
// All functions below this point require authentication.
if(!is_authenticated(usr))
return 1
return FALSE
switch(href_list["operation"])
switch(action)
if("main")
setMenuState(usr,COMM_SCREEN_MAIN)
if("changeseclevel")
setMenuState(usr,COMM_SCREEN_SECLEVEL)
setMenuState(usr, COMM_SCREEN_MAIN)
if("newalertlevel")
if(isAI(usr) || isrobot(usr))
to_chat(usr, "<span class='warning'>Firewalls prevent you from changing the alert level.</span>")
return 1
return
else if(usr.can_admin_interact())
change_security_level(text2num(href_list["level"]))
return 1
change_security_level(text2num(params["level"]))
return
else if(!ishuman(usr))
to_chat(usr, "<span class='warning'>Security measures prevent you from changing the alert level.</span>")
return 1
return
var/mob/living/carbon/human/L = usr
var/obj/item/card = L.get_active_hand()
var/obj/item/card/id/I = (card && card.GetID()) || L.wear_id || L.wear_pda
if(istype(I, /obj/item/pda))
var/obj/item/pda/pda = I
I = pda.id
if(I && istype(I))
var/mob/living/carbon/human/H = usr
var/obj/item/card/id/I = H.get_idcard(TRUE)
if(istype(I))
if(ACCESS_CAPTAIN in I.access)
change_security_level(text2num(href_list["level"]))
change_security_level(text2num(params["level"]))
else
to_chat(usr, "<span class='warning'>You are not authorized to do this.</span>")
setMenuState(usr,COMM_SCREEN_MAIN)
setMenuState(usr, COMM_SCREEN_MAIN)
else
to_chat(usr, "<span class='warning'>You need to swipe your ID.</span>")
to_chat(usr, "<span class='warning'>You need to wear your ID.</span>")
if("announce")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(message_cooldown)
if(message_cooldown > world.time)
to_chat(usr, "<span class='warning'>Please allow at least one minute to pass between announcements.</span>")
SSnanoui.update_uis(src)
return
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement")
if(!input || message_cooldown || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
if(!input || message_cooldown > world.time || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
return
if(length(input) < COMM_MSGLEN_MINIMUM)
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_MSGLEN_MINIMUM] character minimum.</span>")
return
crew_announcement.Announce(input)
message_cooldown = 1
spawn(600)//One minute cooldown
message_cooldown = 0
message_cooldown = world.time + 600 //One minute
if("callshuttle")
var/input = clean_input("Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","")
if(!input || ..() || !is_authenticated(usr))
SSnanoui.update_uis(src)
return
call_shuttle_proc(usr, input)
if(SSshuttle.emergency.timer)
post_status("shuttle")
setMenuState(usr,COMM_SCREEN_MAIN)
setMenuState(usr, COMM_SCREEN_MAIN)
if("cancelshuttle")
if(isAI(usr) || isrobot(usr))
to_chat(usr, "<span class='warning'>Firewalls prevent you from recalling the shuttle.</span>")
SSnanoui.update_uis(src)
return 1
return
var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No")
if(response == "Yes")
cancel_call_proc(usr)
if(SSshuttle.emergency.timer)
post_status("shuttle")
setMenuState(usr,COMM_SCREEN_MAIN)
setMenuState(usr, COMM_SCREEN_MAIN)
if("messagelist")
currmsg = 0
if(href_list["msgid"])
setCurrentMessage(usr, text2num(href_list["msgid"]))
setMenuState(usr,COMM_SCREEN_MESSAGES)
currmsg = null
aicurrmsg = null
if(params["msgid"])
setCurrentMessage(usr, text2num(params["msgid"]))
setMenuState(usr, COMM_SCREEN_MESSAGES)
if("delmessage")
if(href_list["msgid"])
currmsg = text2num(href_list["msgid"])
if(params["msgid"])
currmsg = text2num(params["msgid"])
var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No")
if(response == "Yes")
if(currmsg)
@@ -196,95 +190,95 @@
messagetitle.Remove(title)
messagetext.Remove(text)
if(currmsg == id)
currmsg = 0
currmsg = null
if(aicurrmsg == id)
aicurrmsg = 0
setMenuState(usr,COMM_SCREEN_MESSAGES)
aicurrmsg = null
setMenuState(usr, COMM_SCREEN_MESSAGES)
if("status")
setMenuState(usr,COMM_SCREEN_STAT)
setMenuState(usr, COMM_SCREEN_STAT)
// Status display stuff
if("setstat")
display_type=href_list["statdisp"]
display_type = params["statdisp"]
switch(display_type)
if("message")
display_icon = null
post_status("message", stat_msg1, stat_msg2, usr)
if("alert")
post_status("alert", href_list["alert"], user = usr)
display_icon = params["alert"]
post_status("alert", params["alert"], user = usr)
else
post_status(href_list["statdisp"], user = usr)
setMenuState(usr,COMM_SCREEN_STAT)
display_icon = null
post_status(params["statdisp"], user = usr)
setMenuState(usr, COMM_SCREEN_STAT)
if("setmsg1")
stat_msg1 = clean_input("Line 1", "Enter Message Text", stat_msg1)
setMenuState(usr,COMM_SCREEN_STAT)
setMenuState(usr, COMM_SCREEN_STAT)
if("setmsg2")
stat_msg2 = clean_input("Line 2", "Enter Message Text", stat_msg2)
setMenuState(usr,COMM_SCREEN_STAT)
setMenuState(usr, COMM_SCREEN_STAT)
if("nukerequest")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(centcomm_message_cooldown)
if(centcomm_message_cooldown > world.time)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
SSnanoui.update_uis(src)
return
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return
if(length(input) < COMM_CCMSGLEN_MINIMUM)
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.</span>")
return
Nuke_request(input, usr)
to_chat(usr, "<span class='notice'>Request sent.</span>")
log_game("[key_name(usr)] has requested the nuclear codes from Centcomm")
GLOB.priority_announcement.Announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested",'sound/AI/commandreport.ogg')
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
centcomm_message_cooldown = world.time + 6000 // 10 minutes
setMenuState(usr, COMM_SCREEN_MAIN)
if("MessageCentcomm")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(centcomm_message_cooldown)
if(centcomm_message_cooldown > world.time)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
SSnanoui.update_uis(src)
return
var/input = stripped_input(usr, "Please choose a message to transmit to Centcomm via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return
if(length(input) < COMM_CCMSGLEN_MINIMUM)
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.</span>")
return
Centcomm_announce(input, usr)
print_centcom_report(input, station_time_timestamp() + " Captain's Message")
to_chat(usr, "Message transmitted.")
log_game("[key_name(usr)] has made a Centcomm announcement: [input]")
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
centcomm_message_cooldown = world.time + 6000 // 10 minutes
setMenuState(usr, COMM_SCREEN_MAIN)
// OMG SYNDICATE ...LETTERHEAD
if("MessageSyndicate")
if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (src.emagged))
if(centcomm_message_cooldown)
if(centcomm_message_cooldown > world.time)
to_chat(usr, "Arrays recycling. Please stand by.")
SSnanoui.update_uis(src)
return
var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return
if(length(input) < COMM_CCMSGLEN_MINIMUM)
to_chat(usr, "<span class='warning'>Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.</span>")
return
Syndicate_announce(input, usr)
to_chat(usr, "Message transmitted.")
log_game("[key_name(usr)] has made a Syndicate announcement: [input]")
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
centcomm_message_cooldown = world.time + 6000 // 10 minutes
setMenuState(usr, COMM_SCREEN_MAIN)
if("RestoreBackup")
to_chat(usr, "Backup routing data restored!")
src.emagged = 0
setMenuState(usr,COMM_SCREEN_MAIN)
setMenuState(usr, COMM_SCREEN_MAIN)
if("RestartNanoMob")
if(SSmob_hunt)
@@ -298,14 +292,13 @@
else
to_chat(usr, "<span class='danger'>Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.</span>")
SSnanoui.update_uis(src)
return 1
/obj/machinery/computer/communications/emag_act(user as mob)
if(!emagged)
src.emagged = 1
to_chat(user, "<span class='notice'>You scramble the communication routing circuits!</span>")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/computer/communications/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
@@ -321,28 +314,25 @@
to_chat(user, "<span class='warning'>Unable to establish a connection: You're too far away from the station!</span>")
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/communications/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
/obj/machinery/computer/communications/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "comm_console.tmpl", "Communications Console", 400, 500)
// open the new ui window
ui = new(user, src, ui_key, "CommunicationsComputer", name, 500, 600, master_ui, state)
ui.open()
/obj/machinery/computer/communications/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/computer/communications/tgui_data(mob/user)
var/list/data = list()
data["is_ai"] = isAI(user) || isrobot(user)
data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state
data["emagged"] = emagged
data["authenticated"] = is_authenticated(user, 0)
data["screen"] = getMenuState(usr)
data["authmax"] = data["authenticated"] == COMM_AUTHENTICATION_MAX ? TRUE : FALSE
data["stat_display"] = list(
"type" = display_type,
"icon" = display_icon,
"line_1" = (stat_msg1 ? stat_msg1 : "-----"),
"line_2" = (stat_msg2 ? stat_msg2 : "-----"),
@@ -360,12 +350,20 @@
)
)
data["security_level"] = GLOB.security_level
data["security_level"] = GLOB.security_level
switch(GLOB.security_level)
if(SEC_LEVEL_GREEN)
data["security_level_color"] = "green";
if(SEC_LEVEL_BLUE)
data["security_level_color"] = "blue";
if(SEC_LEVEL_RED)
data["security_level_color"] = "red";
else
data["security_level_color"] = "purple";
data["str_security_level"] = capitalize(get_security_level())
data["levels"] = list(
list("id" = SEC_LEVEL_GREEN, "name" = "Green"),
list("id" = SEC_LEVEL_BLUE, "name" = "Blue"),
//SEC_LEVEL_RED = list("name"="Red"),
list("id" = SEC_LEVEL_GREEN, "name" = "Green", "icon" = "dove"),
list("id" = SEC_LEVEL_BLUE, "name" = "Blue", "icon" = "eye"),
)
var/list/msg_data = list()
@@ -373,27 +371,30 @@
msg_data.Add(list(list("title" = messagetitle[i], "body" = messagetext[i], "id" = i)))
data["messages"] = msg_data
data["current_message"] = null
data["current_message_title"] = null
if((data["is_ai"] && aicurrmsg) || (!data["is_ai"] && currmsg))
data["current_message"] = data["is_ai"] ? messagetext[aicurrmsg] : messagetext[currmsg]
data["current_message_title"] = data["is_ai"] ? messagetitle[aicurrmsg] : messagetitle[currmsg]
data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null
data["msg_cooldown"] = message_cooldown ? (round((message_cooldown - world.time) / 10)) : 0
data["cc_cooldown"] = centcomm_message_cooldown ? (round((centcomm_message_cooldown - world.time) / 10)) : 0
var/shuttle[0]
switch(SSshuttle.emergency.mode)
if(SHUTTLE_IDLE, SHUTTLE_RECALL)
shuttle["callStatus"] = 2 //#define
else
shuttle["callStatus"] = 1
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
var/secondsToRefuel = SSshuttle.secondsToRefuel()
data["esc_callable"] = SSshuttle.emergency.mode == SHUTTLE_IDLE && !secondsToRefuel ? TRUE : FALSE
data["esc_recallable"] = SSshuttle.emergency.mode == SHUTTLE_CALL ? TRUE : FALSE
data["esc_status"] = FALSE
if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL)
var/timeleft = SSshuttle.emergency.timeLeft()
shuttle["eta"] = "[timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
data["shuttle"] = shuttle
data["esc_status"] = SSshuttle.emergency.mode == SHUTTLE_CALL ? "ETA:" : "RECALLING:"
data["esc_status"] += " [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
else if(secondsToRefuel)
data["esc_status"] = "Refueling: [secondsToRefuel / 60 % 60]:[add_zero(num2text(secondsToRefuel % 60), 2)]"
data["esc_section"] = data["esc_status"] || data["esc_callable"] || data["esc_recallable"] || data["lastCallLoc"]
return data
/obj/machinery/computer/communications/proc/setCurrentMessage(var/mob/user,var/value)
if(isAI(user) || isrobot(user))
aicurrmsg = value
@@ -412,12 +413,6 @@
else
menu_state=value
/obj/machinery/computer/communications/proc/getMenuState(var/mob/user)
if(isAI(user) || isrobot(user))
return ai_menu_state
else
return menu_state
/proc/call_shuttle_proc(var/mob/user, var/reason)
if(GLOB.sent_strike_team == 1)
to_chat(user, "<span class='warning'>Central Command will not allow the shuttle to be called. Consider all contracts terminated.</span>")
@@ -521,24 +516,16 @@
SSshuttle.autoEvac()
return ..()
/proc/print_command_report(text = "", title = "Central Command Update")
/proc/print_command_report(text = "", title = "Central Command Update", add_to_records = TRUE)
for(var/obj/machinery/computer/communications/C in GLOB.shuttle_caller_list)
if(!(C.stat & (BROKEN|NOPOWER)) && is_station_contact(C.z))
var/obj/item/paper/P = new /obj/item/paper(C.loc)
P.name = "paper- '[title]'"
P.info = text
P.update_icon()
C.messagetitle.Add("[title]")
C.messagetext.Add(text)
for(var/datum/computer_file/program/comm/P in GLOB.shuttle_caller_list)
var/turf/T = get_turf(P.computer)
if(T && P.program_state != PROGRAM_STATE_KILLED && is_station_contact(T.z))
if(P.computer)
var/obj/item/computer_hardware/printer/printer = P.computer.all_components[MC_PRINT]
if(printer)
printer.print_text(text, "paper- '[title]'")
P.messagetitle.Add("[title]")
P.messagetext.Add(text)
if(add_to_records)
C.messagetitle.Add("[title]")
C.messagetext.Add(text)
/proc/print_centcom_report(text = "", title = "Incoming Message")
for(var/obj/machinery/computer/communications/C in GLOB.shuttle_caller_list)
@@ -549,12 +536,5 @@
P.update_icon()
C.messagetitle.Add("[title]")
C.messagetext.Add(text)
for(var/datum/computer_file/program/comm/P in GLOB.shuttle_caller_list)
var/turf/T = get_turf(P.computer)
if(T && P.program_state != PROGRAM_STATE_KILLED && is_admin_level(T.z))
if(P.computer)
var/obj/item/computer_hardware/printer/printer = P.computer.all_components[MC_PRINT]
if(printer)
printer.print_text(text, "paper- '[title]'")
P.messagetitle.Add("[title]")
P.messagetext.Add(text)
+331 -392
View File
@@ -1,10 +1,12 @@
#define MED_DATA_MAIN 1 // Main menu
#define MED_DATA_R_LIST 2 // Record list
#define MED_DATA_MAINT 3 // Records maintenance
#define MED_DATA_RECORD 4 // Record
#define MED_DATA_V_DATA 5 // Virus database
#define MED_DATA_MEDBOT 6 // Medbot monitor
#define FIELD(N, V, E) list(field = N, value = V, edit = E)
#define MED_FIELD(N, V, E, LB) list(field = N, value = V, edit = E, line_break = LB)
/obj/machinery/computer/med_data //TODO:SANITY
name = "medical records console"
desc = "This can be used to check medical records."
@@ -18,11 +20,45 @@
var/screen = null
var/datum/data/record/active1 = null
var/datum/data/record/active2 = null
var/temp = null
var/list/temp = null
var/printing = null
// The below are used to make modal generation more convenient
var/static/list/field_edit_questions
var/static/list/field_edit_choices
light_color = LIGHT_COLOR_DARKBLUE
/obj/machinery/computer/med_data/Initialize()
..()
field_edit_questions = list(
// General
"sex" = "Please select new sex:",
"age" = "Please input new age:",
"fingerprint" = "Please input new fingerprint hash:",
"p_stat" = "Please select new physical status:",
"m_stat" = "Please select new mental status:",
// Medical
"blood_type" = "Please select new blood type:",
"b_dna" = "Please input new DNA:",
"mi_dis" = "Please input new minor disabilities:",
"mi_dis_d" = "Please summarize minor disabilities:",
"ma_dis" = "Please input new major disabilities:",
"ma_dis_d" = "Please summarize major disabilities:",
"alg" = "Please input new allergies:",
"alg_d" = "Please summarize allergies:",
"cdi" = "Please input new current diseases:",
"cdi_d" = "Please summarize current diseases:",
"notes" = "Please input new important notes:",
)
field_edit_choices = list(
// General
"sex" = list("Male", "Female"),
"p_stat" = list("*Deceased*", "*SSD*", "Active", "Physically Unfit", "Disabled"),
"m_stat" = list("*Insane*", "*Unstable*", "*Watch*", "Stable"),
// Medical
"blood_type" = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"),
)
/obj/machinery/computer/med_data/Destroy()
active1 = null
active2 = null
@@ -33,7 +69,7 @@
usr.drop_item()
O.forceMove(src)
scan = O
ui_interact(user)
tgui_interact(user)
return
return ..()
@@ -44,20 +80,25 @@
to_chat(user, "<span class='danger'>Unable to establish a connection</span>: You're too far away from the station!")
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/med_data/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/med_data/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "med_data.tmpl", name, 800, 380)
ui = new(user, src, ui_key, "MedicalRecords", "Medical Records", 800, 380, master_ui, state)
ui.open()
ui.set_autoupdate(FALSE)
/obj/machinery/computer/med_data/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/computer/med_data/tgui_data(mob/user)
var/data[0]
data["temp"] = temp
data["scan"] = scan ? scan.name : null
data["authenticated"] = authenticated
data["rank"] = rank
data["screen"] = screen
data["printing"] = printing
data["isAI"] = isAI(user)
data["isRobot"] = isrobot(user)
if(authenticated)
switch(screen)
if(MED_DATA_R_LIST)
@@ -72,17 +113,17 @@
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
var/list/fields = list()
general["fields"] = fields
fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "edit" = null)
fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "edit" = null)
fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "edit" = "sex")
fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "edit" = "age")
fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "edit" = "fingerprint")
fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"], "edit" = "p_stat")
fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"], "edit" = "m_stat")
fields[++fields.len] = FIELD("Name", active1.fields["name"], null)
fields[++fields.len] = FIELD("ID", active1.fields["id"], null)
fields[++fields.len] = FIELD("Sex", active1.fields["sex"], "sex")
fields[++fields.len] = FIELD("Age", active1.fields["age"], "age")
fields[++fields.len] = FIELD("Fingerprint", active1.fields["fingerprint"], "fingerprint")
fields[++fields.len] = FIELD("Physical Status", active1.fields["p_stat"], "p_stat")
fields[++fields.len] = FIELD("Mental Status", active1.fields["m_stat"], "m_stat")
var/list/photos = list()
general["photos"] = photos
photos[++photos.len] = list("photo" = active1.fields["photo-south"])
photos[++photos.len] = list("photo" = active1.fields["photo-west"])
photos[++photos.len] = active1.fields["photo-south"]
photos[++photos.len] = active1.fields["photo-west"]
general["has_photos"] = (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0)
general["empty"] = 0
else
@@ -93,17 +134,17 @@
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
var/list/fields = list()
medical["fields"] = fields
fields[++fields.len] = list("field" = "Blood Type:", "value" = active2.fields["blood_type"], "edit" = "blood_type", "line_break" = 0)
fields[++fields.len] = list("field" = "DNA:", "value" = active2.fields["b_dna"], "edit" = "b_dna", "line_break" = 1)
fields[++fields.len] = list("field" = "Minor Disabilities:", "value" = active2.fields["mi_dis"], "edit" = "mi_dis", "line_break" = 0)
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["mi_dis_d"], "edit" = "mi_dis_d", "line_break" = 1)
fields[++fields.len] = list("field" = "Major Disabilities:", "value" = active2.fields["ma_dis"], "edit" = "ma_dis", "line_break" = 0)
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["ma_dis_d"], "edit" = "ma_dis_d", "line_break" = 1)
fields[++fields.len] = list("field" = "Allergies:", "value" = active2.fields["alg"], "edit" = "alg", "line_break" = 0)
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["alg_d"], "edit" = "alg_d", "line_break" = 1)
fields[++fields.len] = list("field" = "Current Diseases:", "value" = active2.fields["cdi"], "edit" = "cdi", "line_break" = 0)
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["cdi_d"], "edit" = "cdi_d", "line_break" = 1)
fields[++fields.len] = list("field" = "Important Notes:", "value" = active2.fields["notes"], "edit" = "notes", "line_break" = 0)
fields[++fields.len] = MED_FIELD("Blood Type", active2.fields["blood_type"], "blood_type", FALSE)
fields[++fields.len] = MED_FIELD("DNA", active2.fields["b_dna"], "b_dna", TRUE)
fields[++fields.len] = MED_FIELD("Minor Disabilities", active2.fields["mi_dis"], "mi_dis", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["mi_dis_d"], "mi_dis_d", TRUE)
fields[++fields.len] = MED_FIELD("Major Disabilities", active2.fields["ma_dis"], "ma_dis", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["ma_dis_d"], "ma_dis_d", TRUE)
fields[++fields.len] = MED_FIELD("Allergies", active2.fields["alg"], "alg", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["alg_d"], "alg_d", TRUE)
fields[++fields.len] = MED_FIELD("Current Diseases", active2.fields["cdi"], "cdi", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["cdi_d"], "cdi_d", TRUE)
fields[++fields.len] = MED_FIELD("Important Notes", active2.fields["notes"], "notes", TRUE)
if(!active2.fields["comments"] || !islist(active2.fields["comments"]))
active2.fields["comments"] = list()
medical["comments"] = active2.fields["comments"]
@@ -127,7 +168,9 @@
var/turf/T = get_turf(M)
if(T)
var/medbot = list()
var/area/A = get_area(T)
medbot["name"] = M.name
medbot["area"] = A.name
medbot["x"] = T.x
medbot["y"] = T.y
medbot["on"] = M.on
@@ -138,395 +181,290 @@
else
medbot["use_beaker"] = 0
data["medbots"] += list(medbot)
data["modal"] = tgui_modal_data(src)
return data
/obj/machinery/computer/med_data/Topic(href, href_list)
/obj/machinery/computer/med_data/tgui_act(action, params)
if(..())
return 1
return
if(stat & (NOPOWER|BROKEN))
return
if(!GLOB.data_core.general.Find(active1))
active1 = null
if(!GLOB.data_core.medical.Find(active2))
active2 = null
if(href_list["temp"])
temp = null
. = TRUE
if(tgui_act_modal(action, params))
return
if(href_list["temp_action"])
if(href_list["temp_action"])
var/temp_href = splittext(href_list["temp_action"], "=")
switch(temp_href[1])
if("del_all2")
for(var/datum/data/record/R in GLOB.data_core.medical)
qdel(R)
setTemp("<h3>All records deleted.</h3>")
if("p_stat")
if(active1)
switch(temp_href[2])
if("deceased")
active1.fields["p_stat"] = "*Deceased*"
if("ssd")
active1.fields["p_stat"] = "*SSD*"
if("active")
active1.fields["p_stat"] = "Active"
if("unfit")
active1.fields["p_stat"] = "Physically Unfit"
if("disabled")
active1.fields["p_stat"] = "Disabled"
if("m_stat")
if(active1)
switch(temp_href[2])
if("insane")
active1.fields["m_stat"] = "*Insane*"
if("unstable")
active1.fields["m_stat"] = "*Unstable*"
if("watch")
active1.fields["m_stat"] = "*Watch*"
if("stable")
active1.fields["m_stat"] = "Stable"
if("blood_type")
if(active2)
switch(temp_href[2])
if("an")
active2.fields["blood_type"] = "A-"
if("bn")
active2.fields["blood_type"] = "B-"
if("abn")
active2.fields["blood_type"] = "AB-"
if("on")
active2.fields["blood_type"] = "O-"
if("ap")
active2.fields["blood_type"] = "A+"
if("bp")
active2.fields["blood_type"] = "B+"
if("abp")
active2.fields["blood_type"] = "AB+"
if("op")
active2.fields["blood_type"] = "O+"
if("del_r2")
QDEL_NULL(active2)
if(href_list["scan"])
if(scan)
scan.forceMove(loc)
if(ishuman(usr) && !usr.get_active_hand())
usr.put_in_hands(scan)
scan = null
switch(action)
if("cleartemp")
temp = null
if("scan")
if(scan)
scan.forceMove(loc)
if(ishuman(usr) && !usr.get_active_hand())
usr.put_in_hands(scan)
scan = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/card/id))
usr.drop_item()
I.forceMove(src)
scan = I
if("login")
var/login_type = text2num(params["login_type"])
if(login_type == LOGIN_TYPE_NORMAL && istype(scan))
if(check_access(scan))
authenticated = scan.registered_name
rank = scan.assignment
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
authenticated = usr.name
rank = "AI"
else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr))
authenticated = usr.name
var/mob/living/silicon/robot/R = usr
rank = "[R.modtype] [R.braintype]"
if(authenticated)
active1 = null
active2 = null
screen = MED_DATA_R_LIST
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/card/id))
usr.drop_item()
I.forceMove(src)
scan = I
. = FALSE
if(href_list["login"])
if(isAI(usr))
authenticated = usr.name
rank = "AI"
else if(isrobot(usr))
authenticated = usr.name
var/mob/living/silicon/robot/R = usr
rank = "[R.modtype] [R.braintype]"
else if(istype(scan, /obj/item/card/id))
if(check_access(scan))
authenticated = scan.registered_name
rank = scan.assignment
if(authenticated)
active1 = null
active2 = null
screen = MED_DATA_MAIN
if(.)
return
if(authenticated)
if(href_list["logout"])
authenticated = null
screen = null
active1 = null
active2 = null
. = TRUE
switch(action)
if("logout")
if(scan)
scan.forceMove(loc)
if(ishuman(usr) && !usr.get_active_hand())
usr.put_in_hands(scan)
scan = null
authenticated = null
screen = null
active1 = null
active2 = null
if("screen")
screen = clamp(text2num(params["screen"]) || 0, MED_DATA_R_LIST, MED_DATA_MEDBOT)
active1 = null
active2 = null
if("vir")
var/type = text2path(params["vir"] || "")
if(!ispath(type, /datum/disease))
return
if(href_list["screen"])
screen = text2num(href_list["screen"])
if(screen < 1)
screen = MED_DATA_MAIN
var/datum/disease/D = new type(0)
var/list/payload = list(
name = D.name,
max_stages = D.max_stages,
spread_text = D.spread_text,
cure = D.cure_text || "None",
desc = D.desc,
severity = D.severity
);
tgui_modal_message(src, "virus", "", null, payload)
qdel(D)
if("del_all")
for(var/datum/data/record/R in GLOB.data_core.medical)
qdel(R)
set_temp("All medical records deleted.")
if("del_r")
if(active2)
set_temp("Medical record deleted.")
qdel(active2)
if("d_rec")
var/datum/data/record/general_record = locate(params["d_rec"] || "")
if(!GLOB.data_core.general.Find(general_record))
set_temp("Record not found.", "danger")
return
active1 = null
active2 = null
var/datum/data/record/medical_record
for(var/datum/data/record/M in GLOB.data_core.medical)
if(M.fields["name"] == general_record.fields["name"] && M.fields["id"] == general_record.fields["id"])
medical_record = M
break
if(href_list["vir"])
var/type = href_list["vir"]
var/datum/disease/D = new type(0)
var/afs = ""
for(var/mob/M in D.viable_mobtypes)
afs += "[initial(M.name)];"
var/severity = D.severity
switch(severity)
if("Harmful", "Minor")
severity = "<span class='good'>[severity]</span>"
if("Medium")
severity = "<span class='average'>[severity]</span>"
if("Dangerous!")
severity = "<span class='bad'>[severity]</span>"
if("BIOHAZARD THREAT!")
severity = "<h4><span class='bad'>[severity]</span></h4>"
setTemp({"<b>Name:</b> [D.name]
<BR><b>Number of stages:</b> [D.max_stages]
<BR><b>Spread:</b> [D.spread_text] Transmission
<BR><b>Possible Cure:</b> [(D.cure_text||"none")]
<BR><b>Affected Lifeforms:</b>[afs]<BR>
<BR><b>Notes:</b> [D.desc]<BR>
<BR><b>Severity:</b> [severity]"})
qdel(D)
if(href_list["del_all"])
var/list/buttons = list()
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_all2=1")
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null)
setTemp("<h3>Are you sure you wish to delete all records?</h3>", buttons)
if(href_list["field"])
if(..())
return 1
var/a1 = active1
var/a2 = active2
switch(href_list["field"])
if("fingerprint")
if(istype(active1, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active1 != a1)
return 1
active1.fields["fingerprint"] = t1
if("sex")
if(istype(active1, /datum/data/record))
if(active1.fields["sex"] == "Male")
active1.fields["sex"] = "Female"
else
active1.fields["sex"] = "Male"
if("age")
if(istype(active1, /datum/data/record))
var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num
if(!t1 || ..() || active1 != a1)
return 1
active1.fields["age"] = t1
if("mi_dis")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["mi_dis"] = t1
if("mi_dis_d")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["mi_dis_d"] = t1
if("ma_dis")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please input major diabilities list:", "Med. records", active2.fields["ma_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["ma_dis"] = t1
if("ma_dis_d")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["ma_dis_d"] = t1
if("alg")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please state allergies:", "Med. records", active2.fields["alg"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["alg"] = t1
if("alg_d")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["alg_d"] = t1
if("cdi")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please state diseases:", "Med. records", active2.fields["cdi"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["cdi"] = t1
if("cdi_d")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["cdi_d"] = t1
if("notes")
if(istype(active2, /datum/data/record))
var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Med. records", html_decode(active2.fields["notes"]), null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["notes"] = t1
if("p_stat")
if(istype(active1, /datum/data/record))
var/list/buttons = list()
buttons[++buttons.len] = list("name" = "*Deceased*", "icon" = "stethoscope", "href" = "p_stat=deceased", "status" = (active1.fields["p_stat"] == "*Deceased*" ? "selected" : null))
buttons[++buttons.len] = list("name" = "*SSD*", "icon" = "stethoscope", "href" = "p_stat=ssd", "status" = (active1.fields["p_stat"] == "*SSD*" ? "selected" : null))
buttons[++buttons.len] = list("name" = "Active", "icon" = "stethoscope", "href" = "p_stat=active", "status" = (active1.fields["p_stat"] == "Active" ? "selected" : null))
buttons[++buttons.len] = list("name" = "Physically Unfit", "icon" = "stethoscope", "href" = "p_stat=unfit", "status" = (active1.fields["p_stat"] == "Physically Unfit" ? "selected" : null))
buttons[++buttons.len] = list("name" = "Disabled", "icon" = "stethoscope", "href" = "p_stat=disabled", "status" = (active1.fields["p_stat"] == "Disabled" ? "selected" : null))
setTemp("<h3>Physical Condition</h3>", buttons)
if("m_stat")
if(istype(active1, /datum/data/record))
var/list/buttons = list()
buttons[++buttons.len] = list("name" = "*Insane*", "icon" = "stethoscope", "href" = "m_stat=insane", "status" = (active1.fields["m_stat"] == "*Insane*" ? "selected" : null))
buttons[++buttons.len] = list("name" = "*Unstable*", "icon" = "stethoscope", "href" = "m_stat=unstable", "status" = (active1.fields["m_stat"] == "*Unstable*" ? "selected" : null))
buttons[++buttons.len] = list("name" = "*Watch*", "icon" = "stethoscope", "href" = "m_stat=watch", "status" = (active1.fields["m_stat"] == "*Watch*" ? "selected" : null))
buttons[++buttons.len] = list("name" = "Stable", "icon" = "stethoscope", "href" = "m_stat=stable", "status" = (active1.fields["m_stat"] == "Stable" ? "selected" : null))
setTemp("<h3>Mental Condition</h3>", buttons)
if("blood_type")
if(istype(active2, /datum/data/record))
var/list/buttons = list()
buttons[++buttons.len] = list("name" = "A-", "icon" = "tint", "href" = "blood_type=an", "status" = (active2.fields["blood_type"] == "A-" ? "selected" : null))
buttons[++buttons.len] = list("name" = "A+", "icon" = "tint", "href" = "blood_type=ap", "status" = (active2.fields["blood_type"] == "A+" ? "selected" : null))
buttons[++buttons.len] = list("name" = "B-", "icon" = "tint", "href" = "blood_type=bn", "status" = (active2.fields["blood_type"] == "B-" ? "selected" : null))
buttons[++buttons.len] = list("name" = "B+", "icon" = "tint", "href" = "blood_type=bp", "status" = (active2.fields["blood_type"] == "B+" ? "selected" : null))
buttons[++buttons.len] = list("name" = "AB-", "icon" = "tint", "href" = "blood_type=abn", "status" = (active2.fields["blood_type"] == "AB-" ? "selected" : null))
buttons[++buttons.len] = list("name" = "AB+", "icon" = "tint", "href" = "blood_type=abp", "status" = (active2.fields["blood_type"] == "AB+" ? "selected" : null))
buttons[++buttons.len] = list("name" = "O-", "icon" = "tint", "href" = "blood_type=on", "status" = (active2.fields["blood_type"] == "O-" ? "selected" : null))
buttons[++buttons.len] = list("name" = "O+", "icon" = "tint", "href" = "blood_type=op", "status" = (active2.fields["blood_type"] == "O+" ? "selected" : null))
setTemp("<h3>Blood Type</h3>", buttons)
if("b_dna")
if(istype(active2, /datum/data/record))
var/t1 = copytext(trim(sanitize(input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["b_dna"] = t1
if("vir_name")
var/datum/data/record/v = locate(href_list["edit_vir"])
if(v)
var/t1 = copytext(trim(sanitize(input("Please input pathogen name:", "VirusDB", v.fields["name"], null) as text)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active1 != a1)
return 1
v.fields["name"] = t1
if("vir_desc")
var/datum/data/record/v = locate(href_list["edit_vir"])
if(v)
var/t1 = copytext(trim(sanitize(input("Please input information about pathogen:", "VirusDB", v.fields["description"], null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active1 != a1)
return 1
v.fields["description"] = t1
if(href_list["del_r"])
if(active2)
var/list/buttons = list()
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_r2=1", "status" = null)
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
setTemp("<h3>Are you sure you wish to delete the record (Medical Portion Only)?</h3>", buttons)
if(href_list["d_rec"])
var/datum/data/record/R = locate(href_list["d_rec"])
var/datum/data/record/M = locate(href_list["d_rec"])
if(!GLOB.data_core.general.Find(R))
setTemp("<h3 class='bad'>Record not found!</h3>")
return 1
for(var/datum/data/record/E in GLOB.data_core.medical)
if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])
M = E
active1 = R
active2 = M
screen = MED_DATA_RECORD
if(href_list["new"])
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
var/datum/data/record/R = new /datum/data/record()
R.fields["name"] = active1.fields["name"]
R.fields["id"] = active1.fields["id"]
R.name = "Medical Record #[R.fields["id"]]"
R.fields["blood_type"] = "Unknown"
R.fields["b_dna"] = "Unknown"
R.fields["mi_dis"] = "None"
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
R.fields["ma_dis"] = "None"
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
R.fields["alg"] = "None"
R.fields["alg_d"] = "No allergies have been detected in this patient."
R.fields["cdi"] = "None"
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
R.fields["notes"] = "No notes."
GLOB.data_core.medical += R
active2 = R
active1 = general_record
active2 = medical_record
screen = MED_DATA_RECORD
if(href_list["add_c"])
if(!istype(active2, /datum/data/record))
return 1
var/a2 = active2
var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)), 1, MAX_MESSAGE_LEN)
if(!t1 || ..() || active2 != a2)
return 1
active2.fields["comments"] += "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]<BR>[t1]"
if(href_list["del_c"])
var/index = min(max(text2num(href_list["del_c"]) + 1, 1), length(active2.fields["comments"]))
if(istype(active2, /datum/data/record) && active2.fields["comments"][index])
active2.fields["comments"] -= active2.fields["comments"][index]
if(href_list["search"])
var/t1 = clean_input("Search String: (Name, DNA, or ID)", "Med. records", null, null)
if(!t1 || ..())
return 1
active1 = null
active2 = null
t1 = lowertext(t1)
for(var/datum/data/record/R in GLOB.data_core.medical)
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
if("new")
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
var/datum/data/record/R = new /datum/data/record()
R.fields["name"] = active1.fields["name"]
R.fields["id"] = active1.fields["id"]
R.name = "Medical Record #[R.fields["id"]]"
R.fields["blood_type"] = "Unknown"
R.fields["b_dna"] = "Unknown"
R.fields["mi_dis"] = "None"
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
R.fields["ma_dis"] = "None"
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
R.fields["alg"] = "None"
R.fields["alg_d"] = "No allergies have been detected in this patient."
R.fields["cdi"] = "None"
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
R.fields["notes"] = "No notes."
GLOB.data_core.medical += R
active2 = R
if(!active2)
setTemp("<h3 class='bad'>Could not locate record [t1].</h3>")
else
screen = MED_DATA_RECORD
set_temp("Medical record created.", "success")
if("del_c")
var/index = text2num(params["del_c"] || "")
if(!index || !istype(active2, /datum/data/record))
return
var/list/comments = active2.fields["comments"]
index = clamp(index, 1, length(comments))
if(comments[index])
comments.Cut(index, index + 1)
if("search")
active1 = null
active2 = null
var/t1 = lowertext(params["t1"] || "")
if(!length(t1))
return
for(var/datum/data/record/R in GLOB.data_core.medical)
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
active2 = R
break
if(!active2)
set_temp("Medical record not found. You must enter the person's exact name, ID or DNA.", "danger")
return
for(var/datum/data/record/E in GLOB.data_core.general)
if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"])
active1 = E
break
screen = MED_DATA_RECORD
if("print_p")
if(!printing)
printing = TRUE
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
SStgui.update_uis(src)
addtimer(CALLBACK(src, .proc/print_finish), 5 SECONDS)
else
return FALSE
if(href_list["print_p"])
if(!printing)
printing = 1
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
sleep(50)
var/obj/item/paper/P = new /obj/item/paper(loc)
P.info = "<CENTER><B>Medical Record</B></CENTER><BR>"
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
<BR>\nSex: [active1.fields["sex"]]
<BR>\nAge: [active1.fields["age"]]
<BR>\nFingerprint: [active1.fields["fingerprint"]]
<BR>\nPhysical Status: [active1.fields["p_stat"]]
<BR>\nMental Status: [active1.fields["m_stat"]]<BR>"}
/**
* Called in tgui_act() to process modal actions
*
* Arguments:
* * action - The action passed by tgui
* * params - The params passed by tgui
*/
/obj/machinery/computer/med_data/proc/tgui_act_modal(action, params)
. = TRUE
var/id = params["id"] // The modal's ID
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_OPEN)
switch(id)
if("edit")
var/field = arguments["field"]
if(!length(field) || !field_edit_questions[field])
return
var/question = field_edit_questions[field]
var/choices = field_edit_choices[field]
if(length(choices))
tgui_modal_choice(src, id, question, arguments = arguments, value = arguments["value"], choices = choices)
else
tgui_modal_input(src, id, question, arguments = arguments, value = arguments["value"])
if("add_c")
tgui_modal_input(src, id, "Please enter your message:")
else
P.info += "<B>General Record Lost!</B><BR>"
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
P.info += {"<BR>\n<CENTER><B>Medical Data</B></CENTER>
<BR>\nBlood Type: [active2.fields["blood_type"]]
<BR>\nDNA: [active2.fields["b_dna"]]<BR>\n
<BR>\nMinor Disabilities: [active2.fields["mi_dis"]]
<BR>\nDetails: [active2.fields["mi_dis_d"]]<BR>\n
<BR>\nMajor Disabilities: [active2.fields["ma_dis"]]
<BR>\nDetails: [active2.fields["ma_dis_d"]]<BR>\n
<BR>\nAllergies: [active2.fields["alg"]]
<BR>\nDetails: [active2.fields["alg_d"]]<BR>\n
<BR>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
<BR>\nDetails: [active2.fields["cdi_d"]]<BR>\n
<BR>\nImportant Notes:
<BR>\n\t[active2.fields["notes"]]<BR>\n
<BR>\n
<CENTER><B>Comments/Log</B></CENTER><BR>"}
for(var/c in active2.fields["comments"])
P.info += "[c]<BR>"
else
P.info += "<B>Medical Record Lost!</B><BR>"
P.info += "</TT>"
P.name = "paper- 'Medical Record: [active1.fields["name"]]'"
printing = 0
return 1
return FALSE
if(TGUI_MODAL_ANSWER)
var/answer = params["answer"]
switch(id)
if("edit")
var/field = arguments["field"]
if(!length(field) || !field_edit_questions[field])
return
var/list/choices = field_edit_choices[field]
if(length(choices) && !(answer in choices))
return
/obj/machinery/computer/med_data/proc/setTemp(text, list/buttons = list())
temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0)
if(field == "age")
var/new_age = text2num(answer)
if(new_age < AGE_MIN || new_age > AGE_MAX)
set_temp("Invalid age. It must be between [AGE_MIN] and [AGE_MAX].", "danger")
return
answer = new_age
if(istype(active2) && (field in active2.fields))
active2.fields[field] = answer
else if(istype(active1) && (field in active1.fields))
active1.fields[field] = answer
if("add_c")
if(!length(answer) || !istype(active2) || !length(authenticated))
return
active2.fields["comments"] += list(list(
header = "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]",
text = answer
))
else
return FALSE
else
return FALSE
/**
* Called when the print timer finishes
*/
/obj/machinery/computer/med_data/proc/print_finish()
var/obj/item/paper/P = new /obj/item/paper(loc)
P.info = "<center></b>Medical Record</b></center><br>"
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
<br>\nSex: [active1.fields["sex"]]
<br>\nAge: [active1.fields["age"]]
<br>\nFingerprint: [active1.fields["fingerprint"]]
<br>\nPhysical Status: [active1.fields["p_stat"]]
<br>\nMental Status: [active1.fields["m_stat"]]<br>"}
else
P.info += "</b>General Record Lost!</b><br>"
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
P.info += {"<br>\n<center></b>Medical Data</b></center>
<br>\nBlood Type: [active2.fields["blood_type"]]
<br>\nDNA: [active2.fields["b_dna"]]<br>\n
<br>\nMinor Disabilities: [active2.fields["mi_dis"]]
<br>\nDetails: [active2.fields["mi_dis_d"]]<br>\n
<br>\nMajor Disabilities: [active2.fields["ma_dis"]]
<br>\nDetails: [active2.fields["ma_dis_d"]]<br>\n
<br>\nAllergies: [active2.fields["alg"]]
<br>\nDetails: [active2.fields["alg_d"]]<br>\n
<br>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
<br>\nDetails: [active2.fields["cdi_d"]]<br>\n
<br>\nImportant Notes:
<br>\n\t[active2.fields["notes"]]<br>\n
<br>\n
<center></b>Comments/Log</b></center><br>"}
for(var/c in active2.fields["comments"])
P.info += "[c]<br>"
else
P.info += "</b>Medical Record Lost!</b><br>"
P.info += "</tt>"
P.name = "paper - 'Medical Record: [active1.fields["name"]]'"
printing = FALSE
SStgui.update_uis(src)
/**
* Sets a temporary message to display to the user
*
* Arguments:
* * text - Text to display, null/empty to clear the message from the UI
* * style - The style of the message: (color name), info, success, warning, danger, virus
*/
/obj/machinery/computer/med_data/proc/set_temp(text = "", style = "info", update_now = FALSE)
temp = list(text = text, style = style)
if(update_now)
SStgui.update_uis(src)
/obj/machinery/computer/med_data/emp_act(severity)
if(stat & (BROKEN|NOPOWER))
@@ -564,9 +502,10 @@
icon_screen = "medlaptop"
density = 0
#undef MED_DATA_MAIN
#undef MED_DATA_R_LIST
#undef MED_DATA_MAINT
#undef MED_DATA_RECORD
#undef MED_DATA_V_DATA
#undef MED_DATA_MEDBOT
#undef FIELD
#undef MED_FIELD
+193 -204
View File
@@ -20,221 +20,210 @@
return
if(stat & (NOPOWER|BROKEN))
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/robotics/proc/is_authenticated(var/mob/user as mob)
/obj/machinery/computer/robotics/proc/is_authenticated(mob/user)
if(!istype(user))
return FALSE
if(user.can_admin_interact())
return 1
else if(allowed(user))
return 1
return 0
return TRUE
if(allowed(user))
return TRUE
return FALSE
/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/**
* Does this borg show up in the console
*
* Returns TRUE if a robot will show up in the console
* Returns FALSE if a robot will not show up in the console
* Arguments:
* * R - The [mob/living/silicon/robot] to be checked
*/
/obj/machinery/computer/robotics/proc/console_shows(mob/living/silicon/robot/R)
if(!istype(R))
return FALSE
if(istype(R, /mob/living/silicon/robot/drone))
return FALSE
if(R.scrambledcodes)
return FALSE
if(!atoms_share_level(src, R))
return FALSE
return TRUE
/**
* Check if a user can send a lockdown/detonate command to a specific borg
*
* Returns TRUE if a user can send the command (does not guarantee it will work)
* Returns FALSE if a user cannot
* Arguments:
* * user - The [mob/user] to be checked
* * R - The [mob/living/silicon/robot] to be checked
* * telluserwhy - Bool of whether the user should be sent a to_chat message if they don't have access
*/
/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R, telluserwhy = FALSE)
if(!istype(user))
return FALSE
if(!console_shows(R))
return FALSE
if(isAI(user))
if(R.connected_ai != user)
if(telluserwhy)
to_chat(user, "<span class='warning'>AIs can only control cyborgs which are linked to them.</span>")
return FALSE
if(isrobot(user))
if(R != user)
if(telluserwhy)
to_chat(user, "<span class='warning'>Cyborgs cannot control other cyborgs.</span>")
return FALSE
return TRUE
/**
* Check if the user is the right kind of entity to be able to hack borgs
*
* Returns TRUE if a user is a traitor AI, or aghost
* Returns FALSE otherwise
* Arguments:
* * user - The [mob/user] to be checked
*/
/obj/machinery/computer/robotics/proc/can_hack_any(mob/user)
if(!istype(user))
return FALSE
if(user.can_admin_interact())
return TRUE
if(!isAI(user))
return FALSE
return (user.mind.special_role && user.mind.original == user)
/**
* Check if the user is allowed to hack a specific borg
*
* Returns TRUE if a user can hack the specific cyborg
* Returns FALSE if a user cannot
* Arguments:
* * user - The [mob/user] to be checked
* * R - The [mob/living/silicon/robot] to be checked
*/
/obj/machinery/computer/robotics/proc/can_hack(mob/user, mob/living/silicon/robot/R)
if(!can_hack_any(user))
return FALSE
if(!istype(R))
return FALSE
if(R.emagged)
return FALSE
if(R.connected_ai != user)
return FALSE
return TRUE
/obj/machinery/computer/robotics/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500)
ui = new(user, src, ui_key, "RoboticsControlConsole", name, 500, 460, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/robotics/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
var/list/robots = get_cyborgs(user)
if(robots.len)
data["robots"] = robots
/obj/machinery/computer/robotics/tgui_data(mob/user)
var/list/data = list()
data["auth"] = is_authenticated(user)
data["can_hack"] = can_hack_any(user)
data["cyborgs"] = list()
data["safety"] = safety
// Also applies for cyborgs. Hides the manual self-destruct button.
data["is_ai"] = issilicon(user)
data["allowed"] = is_authenticated(user)
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
if(!console_shows(R))
continue
var/area/A = get_area(R)
var/turf/T = get_turf(R)
var/list/cyborg_data = list(
name = R.name,
uid = R.UID(),
locked_down = R.lockcharge,
locstring = "[A.name] ([T.x], [T.y])",
status = R.stat,
health = round(R.health * 100 / R.maxHealth, 0.1),
charge = R.cell ? round(R.cell.percent()) : null,
cell_capacity = R.cell ? R.cell.maxcharge : null,
module = R.module ? R.module.name : "No Module Detected",
synchronization = R.connected_ai,
is_hacked = R.connected_ai && R.emagged,
hackable = can_hack(user, R),
)
data["cyborgs"] += list(cyborg_data)
data["show_detonate_all"] = (data["auth"] && length(data["cyborgs"]) > 0 && ishuman(user))
return data
/obj/machinery/computer/robotics/Topic(href, href_list)
/obj/machinery/computer/robotics/tgui_act(action, params)
if(..())
return 1
var/mob/user = usr
if(!is_authenticated(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
// Destroys the cyborg
if(href_list["detonate"])
var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["detonate"])
if(!target || !istype(target))
return
if(isAI(user) && (target.connected_ai != user))
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
return
// Cyborgs may blow up themselves via the console
if((isrobot(user) && user != target) || !is_authenticated(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
var/choice = input("Really detonate [target.name]?") in list ("Yes", "No")
if(choice != "Yes")
return
if(!target || !istype(target))
return
// Antagonistic cyborgs? Left here for downstream
if(target.mind && target.mind.special_role && target.emagged)
to_chat(target, "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered.")
target.ResetSecurityCodes()
else
message_admins("<span class='notice'>[key_name_admin(usr)] detonated [key_name_admin(target)] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[target.x];Y=[target.y];Z=[target.z]'>JMP</a>)!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(target)]!</span>")
to_chat(target, "<span class='danger'>Self-destruct command received.</span>")
if(target.connected_ai)
to_chat(target.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [target.name]</span><br>")
spawn(10)
target.self_destruct()
// Locks or unlocks the cyborg
else if(href_list["lockdown"])
var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"])
if(!target || !istype(target))
return
if(isAI(user) && (target.connected_ai != user))
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
return
if(isrobot(user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No")
if(choice != "Yes")
return
if(!target || !istype(target))
return
message_admins("<span class='notice'>[key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [key_name_admin(target)]!</span>")
log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [key_name(target)]!")
target.SetLockdown(!target.lockcharge)
to_chat(target, "[!target.lockcharge ? "<span class='notice'>Your lockdown has been lifted!</span>" : "<span class='alert'>You have been locked down!</span>"]")
if(target.connected_ai)
to_chat(target.connected_ai, "[!target.lockcharge ? "<span class='notice'>NOTICE - Cyborg lockdown lifted</span>" : "<span class='alert'>ALERT - Cyborg lockdown detected</span>"]: <a href='?src=[target.connected_ai.UID()];track=[html_encode(target.name)]'>[target.name]</a></span><br>")
// Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs.
else if(href_list["hack"])
var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"])
if(!target || !istype(target))
return
// Antag AI checks
if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
if(target.connected_ai != user)
to_chat(user, "<span class='warning'>Access Denied. This robot is not linked to you.</span>")
return
if(target.emagged)
to_chat(user, "<span class='warning'>Robot is already hacked.</span>")
return
var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No")
if(choice != "Yes")
return
if(!target || !istype(target))
return
message_admins("<span class='notice'>[key_name_admin(usr)] emagged [key_name_admin(target)] using robotic console!</span>")
log_game("[key_name(usr)] emagged [key_name(target)] using robotic console!")
target.emagged = 1
to_chat(target, "<span class='notice'>Failsafe protocols overriden. New tools available.</span>")
// Arms the emergency self-destruct system
else if(href_list["arm"])
if(istype(user, /mob/living/silicon))
to_chat(user, "<span class='warning'>Access Denied.</span>")
return
safety = !safety
to_chat(user, "<span class='notice'>You [safety ? "disarm" : "arm"] the emergency self destruct.</span>")
// Destroys all accessible cyborgs if safety is disabled
else if(href_list["nuke"])
if(istype(user, /mob/living/silicon))
to_chat(user, "Access Denied")
return
if(safety)
to_chat(user, "Self-destruct aborted - safety active")
return
message_admins("<span class='notice'>[key_name_admin(usr)] detonated all cyborgs!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated all cyborgs!</span>")
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
if(istype(R, /mob/living/silicon/robot/drone))
continue
// Ignore antagonistic cyborgs
if(R.scrambledcodes)
continue
. = FALSE
if(!is_authenticated(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
switch(action)
if("arm") // Arms the emergency self-destruct system
if(issilicon(usr))
to_chat(usr, "<span class='danger'>Access Denied (silicon detected)</span>")
return
safety = !safety
to_chat(usr, "<span class='notice'>You [safety ? "disarm" : "arm"] the emergency self destruct.</span>")
. = TRUE
if("nuke") // Destroys all accessible cyborgs if safety is disabled
if(issilicon(usr))
to_chat(usr, "<span class='danger'>Access Denied (silicon detected)</span>")
return
if(safety)
to_chat(usr, "<span class='danger'>Self-destruct aborted - safety active</span>")
return
message_admins("<span class='notice'>[key_name_admin(usr)] detonated all cyborgs!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated all cyborgs!</span>")
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
if(istype(R, /mob/living/silicon/robot/drone))
continue
// Ignore antagonistic cyborgs
if(R.scrambledcodes)
continue
to_chat(R, "<span class='danger'>Self-destruct command received.</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
R.self_destruct()
. = TRUE
if("killbot") // destroys one specific cyborg
var/mob/living/silicon/robot/R = locateUID(params["uid"])
if(!can_control(usr, R, TRUE))
return
if(R.mind && R.mind.special_role && R.emagged)
to_chat(R, "<span class='userdanger'>Extreme danger! Termination codes detected. Scrambling security codes and automatic AI unlink triggered.</span>")
R.ResetSecurityCodes()
. = TRUE
return
var/turf/T = get_turf(R)
message_admins("<span class='notice'>[key_name_admin(usr)] detonated [key_name_admin(R)] ([ADMIN_COORDJMP(T)])!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(R)]!</span>")
to_chat(R, "<span class='danger'>Self-destruct command received.</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
spawn(10)
R.self_destruct()
// Proc: get_cyborgs()
// Parameters: 1 (operator - mob which is operating the console.)
// Description: Returns NanoUI-friendly list of accessible cyborgs.
/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator)
var/list/robots = list()
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
// Ignore drones
if(istype(R, /mob/living/silicon/robot/drone))
continue
// Ignore antagonistic cyborgs
if(R.scrambledcodes)
continue
var/list/robot = list()
robot["name"] = R.name
if(R.stat)
robot["status"] = "Not Responding"
else if(!R.canmove)
robot["status"] = "Lockdown"
else
robot["status"] = "Operational"
if(R.cell)
robot["cell"] = 1
robot["cell_capacity"] = R.cell.maxcharge
robot["cell_current"] = R.cell.charge
robot["cell_percentage"] = round(R.cell.percent())
else
robot["cell"] = 0
var/turf/pos = get_turf(R)
var/area/bot_area = get_area(R)
robot["xpos"] = pos.x
robot["ypos"] = pos.y
robot["zpos"] = pos.z
robot["area"] = format_text(bot_area.name)
robot["health"] = round(R.health * 100 / R.maxHealth,0.1)
robot["module"] = R.module ? R.module.name : "None"
robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None"
robot["hackable"] = 0
// Antag AIs know whether linked cyborgs are hacked or not.
if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator))
robot["hacked"] = R.emagged ? 1 : 0
robot["hackable"] = R.emagged? 0 : 1
robots.Add(list(robot))
return robots
// Proc: get_cyborg_by_name()
// Parameters: 1 (name - Cyborg we are trying to find)
// Description: Helper proc for finding cyborg by name
/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name)
if(!name)
return
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
if(R.name == name)
return R
R.self_destruct()
. = TRUE
if("stopbot") // lock or unlock the borg
if(isrobot(usr))
to_chat(usr, "<span class='danger'>Access Denied.</span>")
return
var/mob/living/silicon/robot/R = locateUID(params["uid"])
if(!can_control(usr, R, TRUE))
return
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!</span>")
log_game("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!")
R.SetLockdown(!R.lockcharge)
to_chat(R, "[!R.lockcharge ? "<span class='notice'>Your lockdown has been lifted!" : "<span class='alert'>You have been locked down!"]</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "[!R.lockcharge ? "<span class='notice'>NOTICE - Cyborg lockdown lifted</span>" : "<span class='alert'>ALERT - Cyborg lockdown detected</span>"]: <a href='?src=[R.connected_ai.UID()];track=[html_encode(R.name)]'>[R.name]</a></span><br>")
. = TRUE
if("hackbot") // AIs hacking/emagging a borg
var/mob/living/silicon/robot/R = locateUID(params["uid"])
if(!can_hack(usr, R))
return
var/choice = input("Really hack [R.name]? This cannot be undone.") in list("Yes", "No")
if(choice != "Yes")
return
log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!")
message_admins("<span class='notice'>[key_name_admin(usr)] emagged [key_name_admin(R)] using robotic console!</span>")
R.emagged = TRUE
to_chat(R, "<span class='notice'>Failsafe protocols overriden. New tools available.</span>")
. = TRUE
+48 -67
View File
@@ -103,7 +103,7 @@
beaker.forceMove(drop_location())
beaker = null
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob)
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O, mob/living/user)
if(O.loc == user) //no you can't pull things out of your ass
return
if(user.incapacitated()) //are you cuffed, dying, lying, stunned or other
@@ -140,6 +140,7 @@
add_attack_logs(user, L, "put into a cryo cell at [COORD(src)].", ATKLOG_ALL)
if(user.pulling == L)
user.stop_pulling()
SStgui.update_uis(src)
/obj/machinery/atmospherics/unary/cryo_cell/process()
..()
@@ -177,14 +178,14 @@
return FALSE
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user)
if(user.stat)
return
go_out()
return
/obj/machinery/atmospherics/unary/cryo_cell/attack_ghost(mob/user)
return attack_hand(user)
tgui_interact(user)
/obj/machinery/atmospherics/unary/cryo_cell/attack_hand(mob/user)
if(user == occupant)
@@ -194,36 +195,18 @@
to_chat(usr, "<span class='boldnotice'>Close the maintenance panel first.</span>")
return
ui_interact(user)
tgui_interact(user)
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
* ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
*/
/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/atmospherics/unary/cryo_cell/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 480)
// open the new ui window
ui = new(user, src, ui_key, "Cryo", "Cryo Cell", 520, 490)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/unary/cryo_cell/tgui_data(mob/user)
var/data[0]
data["isOperating"] = on
data["hasOccupant"] = occupant ? 1 : 0
data["hasOccupant"] = occupant ? TRUE : FALSE
var/occupantData[0]
if(occupant)
@@ -246,7 +229,7 @@
else if(air_contents.temperature > TCRYO)
data["cellTemperatureStatus"] = "average"
data["isBeakerLoaded"] = beaker ? 1 : 0
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
data["beakerLabel"] = null
data["beakerVolume"] = 0
if(beaker)
@@ -259,48 +242,44 @@
data["auto_eject_dead"] = (auto_eject_prefs & AUTO_EJECT_DEAD) ? TRUE : FALSE
return data
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
if(usr == occupant)
return 0 // don't update UIs attached to this object
/obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params)
if(..() || usr == occupant)
return
if(stat & (NOPOWER|BROKEN))
return
if(..())
return 0 // don't update UIs attached to this object
if(href_list["switchOn"])
on = TRUE
update_icon()
if(href_list["switchOff"])
on = FALSE
update_icon()
if(href_list["auto_eject_healthy_on"])
auto_eject_prefs |= AUTO_EJECT_HEALTHY
if(href_list["auto_eject_healthy_off"])
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
if(href_list["auto_eject_dead_on"])
auto_eject_prefs |= AUTO_EJECT_DEAD
if(href_list["auto_eject_dead_off"])
auto_eject_prefs &= ~AUTO_EJECT_DEAD
if(href_list["ejectBeaker"])
if(beaker)
. = TRUE
switch(action)
if("switchOn")
on = TRUE
update_icon()
if("switchOff")
on = FALSE
update_icon()
if("auto_eject_healthy_on")
auto_eject_prefs |= AUTO_EJECT_HEALTHY
if("auto_eject_healthy_off")
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
if("auto_eject_dead_on")
auto_eject_prefs |= AUTO_EJECT_DEAD
if("auto_eject_dead_off")
auto_eject_prefs &= ~AUTO_EJECT_DEAD
if("ejectBeaker")
if(!beaker)
return
beaker.forceMove(get_step(loc, SOUTH))
beaker = null
if(href_list["ejectOccupant"])
if(!occupant || isslime(usr) || ispAI(usr))
return 0 // don't update UIs attached to this object
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
go_out()
if("ejectOccupant")
if(!occupant || isslime(usr) || ispAI(usr))
return
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
go_out()
else
return FALSE
add_fingerprint(usr)
return 1 // update UIs attached to this object
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G as obj, var/mob/user as mob, params)
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G, var/mob/user, params)
if(istype(G, /obj/item/reagent_containers/glass))
var/obj/item/reagent_containers/B = G
if(beaker)
@@ -313,6 +292,7 @@
beaker = B
add_attack_logs(user, null, "Added [B] containing [B.reagents.log_list()] to a cryo cell at [COORD(src)]")
user.visible_message("[user] adds \a [B] to [src]!", "You add \a [B] to [src]!")
SStgui.update_uis(src)
return
if(exchange_parts(user, G))
@@ -357,7 +337,7 @@
return
if(occupant)
var/image/pickle = image(occupant.icon, occupant.icon_state)
var/mutable_appearance/pickle = mutable_appearance(occupant.icon, occupant.icon_state)
pickle.overlays = occupant.overlays
pickle.pixel_y = 22
@@ -455,8 +435,9 @@
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
if(AUTO_EJECT_DEAD)
playsound(loc, 'sound/machines/buzz-sigh.ogg', 40)
SStgui.update_uis(src)
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M)
if(!istype(M))
to_chat(usr, "<span class='danger'>The cryo cell cannot handle such a lifeform!</span>")
return
@@ -530,7 +511,7 @@
/datum/data/function/proc/reset()
return
/datum/data/function/proc/r_input(href, href_list, mob/user as mob)
/datum/data/function/proc/r_input(href, href_list, mob/user)
return
/datum/data/function/proc/display()
+3
View File
@@ -784,6 +784,9 @@
if(free_cryopods.len)
target_cryopod = safepick(free_cryopods)
if(target_cryopod.check_occupant_allowed(person_to_cryo))
var/turf/T = get_turf(person_to_cryo)
var/obj/effect/portal/SP = new /obj/effect/portal(T, null, null, 40)
SP.name = "NT SSD Teleportation Portal"
target_cryopod.take_occupant(person_to_cryo, 1)
return 1
return 0
+104 -55
View File
@@ -36,9 +36,10 @@
var/crimes = CELL_NONE
var/time = 0
var/officer = CELL_NONE
var/prisoner_name = ""
var/prisoner_charge = ""
var/prisoner_time = ""
var/prisoner_name
var/prisoner_charge
var/prisoner_time
var/prisoner_hasrecord = FALSE
/obj/machinery/door_timer/New()
GLOB.celltimers_list += src
@@ -82,10 +83,15 @@
var/datum/data/record/R = find_security_record("name", occupant)
var/announcetext = "Detainee [occupant] ([prisoner_drank]) has been incarcerated for [seconds_to_time(timetoset / 10)] for the charges of: '[crimes]'. \
var/timetext = seconds_to_time(timetoset / 10)
var/announcetext = "Detainee [occupant] ([prisoner_drank]) has been incarcerated for [timetext] for the crime of: '[crimes]'. \
Arresting Officer: [usr.name].[R ? "" : " Detainee record not found, manual record update required."]"
Radio.autosay(announcetext, name, "Security", list(z))
// Notify the actual criminal being brigged. This is a QOL thing to ensure they always know the charges against them.
// Announcing it on radio isn't enough, as they're unlikely to have sec radio.
notify_prisoner("You have been incarcerated for [timetext] for the crime of: '[crimes]'.")
if(prisoner_trank != "unknown" && prisoner_trank != "Civilian")
SSjobs.notify_dept_head(prisoner_trank, announcetext)
@@ -104,6 +110,13 @@
update_all_mob_security_hud()
return 1
/obj/machinery/door_timer/proc/notify_prisoner(notifytext)
for(var/mob/living/carbon/human/H in range(4, get_turf(src)))
if(occupant == H.name)
to_chat(H, "[src] beeps, \"[notifytext]\"")
return
atom_say("[src] beeps, \"[occupant]: [notifytext]\"")
/obj/machinery/door_timer/Initialize()
..()
@@ -261,13 +274,11 @@
return
//Allows AIs to use door_timer, see human attack_hand function below
/obj/machinery/door_timer/attack_ai(mob/user)
attack_hand(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/door_timer/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
//Allows humans to use door_timer
//Opens dialog window when someone clicks on door timer
@@ -276,71 +287,109 @@
/obj/machinery/door_timer/attack_hand(mob/user)
if(..())
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/door_timer/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "brig_timer.tmpl", "Brig Timer", 500, 400)
ui = new(user, src, ui_key, "BrigTimer", name, 500, 450, master_ui, state)
ui.open()
ui.set_auto_update(TRUE)
/obj/machinery/door_timer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/door_timer/tgui_static_data(mob/user)
var/list/data = list()
data["spns"] = list()
for(var/mob/living/carbon/human/H in range(4, get_turf(src)))
if(H.handcuffed)
data["spns"] += H.name
return data
/obj/machinery/door_timer/tgui_data(mob/user)
var/list/data = list()
data["cell_id"] = name
data["occupant"] = occupant
data["crimes"] = crimes
data["brigged_by"] = officer
data["time_set"] = seconds_to_clock(time / 10)
data["time_set"] = seconds_to_clock(timetoset / 10)
data["time_left"] = seconds_to_clock(timeleft())
data["timing"] = timing
data["isAllowed"] = allowed(user)
data["prisoner_name"] = prisoner_name
data["prisoner_charge"] = prisoner_charge
data["prisoner_time"] = prisoner_time
data["prisoner_hasrec"] = prisoner_hasrecord
return data
/obj/machinery/door_timer/Topic(href, href_list)
if(!allowed(usr) && !usr.can_admin_interact())
return 1
/obj/machinery/door_timer/allowed(mob/user)
if(user.can_admin_interact())
return TRUE
return ..()
if(href_list["flash"])
for(var/obj/machinery/flasher/F in targets)
if(F.last_flash && (F.last_flash + 150) > world.time)
to_chat(usr, "<span class='warning'>Flash still charging.</span>")
/obj/machinery/door_timer/tgui_act(action, params)
if(..())
return
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
. = TRUE
switch(action)
if("prisoner_name")
if(params["prisoner_name"])
prisoner_name = params["prisoner_name"]
else
F.flash()
if(href_list["release"])
if(timing)
timer_end()
Radio.autosay("Timer stopped manually from cell control.", name, "Security", list(z))
ui_interact(usr)
if(href_list["prisoner_name"])
prisoner_name = input("Prisoner Name:", name, prisoner_name) as text|null
if(href_list["prisoner_charge"])
prisoner_charge = input("Prisoner Charge:", name, prisoner_charge) as text|null
if(href_list["prisoner_time"])
prisoner_time = input("Prisoner Time (in minutes):", name, prisoner_time) as num|null
prisoner_time = min(max(round(prisoner_time), 0), 60)
if(href_list["set_timer"])
if(!prisoner_name || !prisoner_charge || !prisoner_time)
return
timeset(prisoner_time * 60)
occupant = prisoner_name
crimes = prisoner_charge
prisoner_name = ""
prisoner_charge = ""
prisoner_time = ""
timing = TRUE
timer_start()
ui_interact(usr)
update_icon()
prisoner_name = input("Prisoner Name:", name, prisoner_name) as text|null
if(prisoner_name)
var/datum/data/record/R = find_security_record("name", prisoner_name)
if(istype(R))
prisoner_hasrecord = TRUE
else
prisoner_hasrecord = FALSE
if("prisoner_charge")
prisoner_charge = input("Prisoner Charge:", name, prisoner_charge) as text|null
if("prisoner_time")
prisoner_time = input("Prisoner Time (in minutes):", name, prisoner_time) as num|null
prisoner_time = min(max(round(prisoner_time), 0), 60)
if("start")
if(!prisoner_name || !prisoner_charge || !prisoner_time)
return FALSE
timeset(prisoner_time * 60)
occupant = prisoner_name
crimes = prisoner_charge
prisoner_name = null
prisoner_charge = null
prisoner_time = null
timing = TRUE
timer_start()
update_icon()
if("restart_timer")
if(timing)
var/reset_reason = sanitize(copytext(input(usr, "Reason for resetting timer:", name, "") as text|null, 1, MAX_MESSAGE_LEN))
if(!reset_reason)
to_chat(usr, "<span class='warning'>Cancelled reset: reason field is required.</span>")
return FALSE
releasetime = world.timeofday + timetoset
var/resettext = isobserver(usr) ? "for: [reset_reason]." : "by [usr.name] for: [reset_reason]."
Radio.autosay("Prisoner [occupant] had their timer reset [resettext]", name, "Security", list(z))
notify_prisoner("Your brig timer has been reset for: '[reset_reason]'.")
var/datum/data/record/R = find_security_record("name", occupant)
if(istype(R))
R.fields["comments"] += "Autogenerated by [name] on [GLOB.current_date_string] [station_time_timestamp()]<BR>Timer reset [resettext]"
else
. = FALSE
if("stop")
if(timing)
timer_end()
var/stoptext = isobserver(usr) ? "from cell control." : "by [usr.name]."
Radio.autosay("Timer stopped manually [stoptext]", name, "Security", list(z))
else
. = FALSE
if("flash")
for(var/obj/machinery/flasher/F in targets)
if(F.last_flash && (F.last_flash + 150) > world.time)
to_chat(usr, "<span class='warning'>Flash still charging.</span>")
else
F.flash()
else
. = FALSE
//icon update function
+1
View File
@@ -33,6 +33,7 @@ FIRE ALARM
var/last_process = 0
var/wiresexposed = 0
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
var/enabled = FALSE
var/report_fire_alarms = TRUE // Should triggered fire alarms also trigger an actual alarm?
var/show_alert_level = TRUE // Should fire alarms display the current alert level?
+16 -36
View File
@@ -6,6 +6,14 @@
// Reasonable defaults, in case someone manually spawns us
var/lasercolor = "r" //Something to do with lasertag turrets, blame Sieve for not adding a comment.
installation = /obj/item/gun/energy/laser/tag/red
targetting_is_configurable = FALSE
lethal_is_configurable = FALSE
shot_delay = 30
iconholder = 1
has_cover = FALSE
always_up = TRUE
raised = TRUE
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
/obj/machinery/porta_turret/tag/red
@@ -18,43 +26,15 @@
icon_state = "[lasercolor]grey_target_prism"
/obj/machinery/porta_turret/tag/weapon_setup(var/obj/item/gun/energy/E)
switch(E.type)
if(/obj/item/gun/energy/laser/tag/blue)
eprojectile = /obj/item/gun/energy/laser/tag/blue
lasercolor = "b"
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
check_arrest = 0
check_records = 0
check_weapons = 1
check_access = 0
check_anomalies = 0
shot_delay = 30
return
if(/obj/item/gun/energy/laser/tag/red)
eprojectile = /obj/item/gun/energy/laser/tag/red
lasercolor = "r"
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
check_arrest = 0
check_records = 0
check_weapons = 1
check_access = 0
check_anomalies = 0
shot_delay = 30
iconholder = 1
/obj/machinery/porta_turret/tag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
ui.open()
ui.set_auto_update(1)
/obj/machinery/porta_turret/tag/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["access"] = !isLocked(user)
data["locked"] = locked
data["enabled"] = enabled
data["is_lethal"] = 0
/obj/machinery/porta_turret/tag/tgui_data(mob/user)
var/list/data = list(
"locked" = isLocked(user), // does the current user have access?
"on" = enabled, // is turret turned on?
"lethal" = FALSE,
"lethal_is_configurable" = lethal_is_configurable
)
return data
/obj/machinery/porta_turret/tag/update_icon()
+234 -225
View File
@@ -7,18 +7,18 @@
name = "turret"
icon = 'icons/obj/turrets.dmi'
icon_state = "turretCover"
anchored = 1
density = 0
anchored = TRUE
density = FALSE
use_power = IDLE_POWER_USE //this turret uses and requires power
idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
power_channel = EQUIP //drains power from the EQUIPMENT channel
armor = list(melee = 50, bullet = 30, laser = 30, energy = 30, bomb = 30, bio = 0, rad = 0, fire = 90, acid = 90)
var/raised = 0 //if the turret cover is "open" and the turret is raised
var/raising= 0 //if the turret is currently opening or closing its cover
var/raised = FALSE //if the turret cover is "open" and the turret is raised
var/raising= FALSE //if the turret is currently opening or closing its cover
var/health = 80 //the turret's health
var/locked = 1 //if the turret's behaviour control access is locked
var/controllock = 0 //if the turret responds to control panels
var/locked = TRUE //if the turret's behaviour control access is locked
var/controllock = FALSE //if the turret responds to control panels. TRUE = does NOT respond
var/installation = /obj/item/gun/energy/gun/turret //the type of weapon installed
var/gun_charge = 0 //the charge of the gun inserted
@@ -31,68 +31,49 @@
var/last_fired = 0 //1: if the turret is cooling down from a shot, 0: turret is ready to fire
var/shot_delay = 15 //1.5 seconds between each shot
var/check_arrest = 1 //checks if the perp is set to arrest
var/check_records = 1 //checks if a security record exists at all
var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
var/ailock = 0 // AI cannot use this
var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
var/check_arrest = TRUE //checks if the perp is set to arrest
var/check_records = TRUE //checks if a security record exists at all
var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
var/check_borgs = FALSE //if TRUE, target all cyborgs.
var/ailock = FALSE // if TRUE, AI cannot use this
var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
var/attacked = FALSE //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
var/enabled = 1 //determines if the turret is on
var/lethal = 0 //whether in lethal or stun mode
var/disabled = 0
var/enabled = TRUE //determines if the turret is on
var/lethal = FALSE //whether in lethal or stun mode
var/lethal_is_configurable = TRUE // if false, its lethal setting cannot be changed
var/disabled = FALSE
var/shot_sound //what sound should play when the turret fires
var/eshot_sound //what sound should play when the emagged turret fires
var/datum/effect_system/spark_spread/spark_system //the spark system, used for generating... sparks?
var/wrenching = 0
var/wrenching = FALSE
var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range
var/screen = 0 // Screen 0: main control, screen 1: access levels
var/one_access = 0 // Determines if access control is set to req_one_access or req_access
var/one_access = FALSE // Determines if access control is set to req_one_access or req_access
var/region_min = REGION_GENERAL
var/region_max = REGION_COMMAND
var/syndicate = 0 //is the turret a syndicate turret?
var/syndicate = FALSE //is the turret a syndicate turret?
var/faction = ""
var/emp_vulnerable = 1 // Can be empd
var/emp_vulnerable = TRUE // Can be empd
var/scan_range = 7
var/always_up = 0 //Will stay active
var/has_cover = 1 //Hides the cover
var/always_up = FALSE //Will stay active
var/has_cover = TRUE //Hides the cover
/obj/machinery/porta_turret/centcom
name = "Centcom Turret"
enabled = 0
ailock = 1
check_synth = 0
check_access = 1
check_arrest = 1
check_records = 1
check_weapons = 1
check_anomalies = 1
/obj/machinery/porta_turret/centcom/pulse
name = "Pulse Turret"
health = 200
enabled = 1
lethal = 1
req_access = list(ACCESS_CENT_COMMANDER)
installation = /obj/item/gun/energy/pulse/turret
/obj/machinery/porta_turret/stationary
ailock = 1
lethal = 1
installation = /obj/item/gun/energy/laser
/obj/machinery/porta_turret/Initialize(mapload)
. = ..()
if(req_access && req_access.len)
req_access.Cut()
req_one_access = list(ACCESS_SECURITY, ACCESS_HEADS)
one_access = 1
one_access = TRUE
//Sets up a spark system
spark_system = new /datum/effect_system/spark_spread
@@ -110,7 +91,7 @@
if(req_one_access && req_one_access.len)
req_one_access.Cut()
req_access = list(ACCESS_CENT_SPECOPS)
one_access = 0
one_access = FALSE
/obj/machinery/porta_turret/proc/setup()
var/obj/item/gun/energy/E = new installation //All energy-based weapons are applicable
@@ -185,152 +166,151 @@ GLOBAL_LIST_EMPTY(turret_icons)
else
icon_state = "turretCover"
/obj/machinery/porta_turret/proc/isLocked(mob/user)
if(ailock && (isrobot(user) || isAI(user)))
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
return 1
if(locked && !(isrobot(user) || isAI(user) || isobserver(user)))
to_chat(user, "<span class='notice'>Access denied.</span>")
return 1
return 0
/obj/machinery/porta_turret/attack_ai(mob/user)
if(isLocked(user))
return
ui_interact(user)
/obj/machinery/porta_turret/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/porta_turret/attack_hand(mob/user)
if(isLocked(user))
return
ui_interact(user)
/obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 320)
ui.open()
ui.set_auto_update(1)
/obj/machinery/porta_turret/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["access"] = !isLocked(user)
data["screen"] = screen
data["locked"] = locked
data["enabled"] = enabled
data["lethal_control"] = !syndicate ? 1 : 0
data["lethal"] = lethal
if(data["access"] && !syndicate)
var/settings[0]
settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
settings[++settings.len] = list("category" = "Check Misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
data["settings"] = settings
if(!syndicate)
data["one_access"] = one_access
var/accesses[0]
var/list/access_list = get_all_accesses()
for(var/access in access_list)
var/name = get_access_desc(access)
var/active
if(one_access)
active = (access in req_one_access)
else
active = (access in req_access)
accesses[++accesses.len] = list("name" = name, "active" = active, "number" = access)
data["accesses"] = accesses
return data
/obj/machinery/porta_turret/proc/HasController()
var/area/A = get_area(src)
return A && A.turret_controls.len > 0
/obj/machinery/porta_turret/CanUseTopic(var/mob/user)
/obj/machinery/porta_turret/proc/access_is_configurable()
return targetting_is_configurable && !HasController()
/obj/machinery/porta_turret/proc/isLocked(mob/user)
if(HasController())
to_chat(user, "<span class='notice'>Turrets can only be controlled using the assigned turret controller.</span>")
return STATUS_CLOSE
return TRUE
if(isrobot(user) || isAI(user))
if(ailock)
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
return TRUE
else
return FALSE
if(isobserver(user))
if(user.can_admin_interact())
return FALSE
else
return TRUE
if(locked)
return TRUE
return FALSE
if(isLocked(user))
return STATUS_CLOSE
/obj/machinery/porta_turret/attack_ai(mob/user)
tgui_interact(user)
if(!anchored)
to_chat(usr, "<span class='notice'>\The [src] has to be secured first!</span>")
return STATUS_CLOSE
/obj/machinery/porta_turret/attack_ghost(mob/user)
tgui_interact(user)
return ..()
/obj/machinery/porta_turret/attack_hand(mob/user)
tgui_interact(user)
/obj/machinery/porta_turret/Topic(href, href_list, var/nowindow = 0)
if(..())
return 1
if(href_list["command"] && href_list["value"])
var/value = text2num(href_list["value"])
if(href_list["command"] == "enable")
enabled = value
else if(syndicate)
return 1
else if(href_list["command"] == "screen")
screen = value
else if(href_list["command"] == "lethal")
lethal = value
else if(href_list["command"] == "check_synth")
check_synth = value
else if(href_list["command"] == "check_weapons")
check_weapons = value
else if(href_list["command"] == "check_records")
check_records = value
else if(href_list["command"] == "check_arrest")
check_arrest = value
else if(href_list["command"] == "check_access")
check_access = value
else if(href_list["command"] == "check_anomalies")
check_anomalies = value
if(!syndicate)
if(href_list["one_access"])
toggle_one_access(href_list["one_access"])
if(href_list["access"])
toggle_access(href_list["access"])
return 1
/obj/machinery/porta_turret/proc/toggle_one_access(var/access)
one_access = text2num(access)
if(one_access == 1)
req_one_access = req_access.Copy()
req_access.Cut()
else if(one_access == 0)
req_access = req_one_access.Copy()
req_one_access.Cut()
/obj/machinery/porta_turret/proc/toggle_access(var/access)
var/required = text2num(access)
if(!(required in get_all_accesses()))
/obj/machinery/porta_turret/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(HasController())
to_chat(user, "<span class='notice'>[src] can only be controlled using the assigned turret controller.</span>")
return
if(!anchored)
to_chat(user, "<span class='notice'>[src] has to be secured first!</span>")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "PortableTurret", name, 500, access_is_configurable() ? 800 : 400)
ui.open()
if(one_access)
if((required in req_one_access))
req_one_access -= required
else
req_one_access += required
else
if((required in req_access))
req_access -= required
else
req_access += required
/obj/machinery/porta_turret/tgui_data(mob/user)
var/list/data = list(
"locked" = isLocked(user), // does the current user have access?
"on" = enabled,
"targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up
"lethal" = lethal,
"lethal_is_configurable" = lethal_is_configurable,
"check_weapons" = check_weapons,
"neutralize_noaccess" = check_access,
"one_access" = one_access,
"selectedAccess" = one_access ? req_one_access : req_access,
"access_is_configurable" = access_is_configurable(),
"neutralize_norecord" = check_records,
"neutralize_criminals" = check_arrest,
"neutralize_all" = check_synth,
"neutralize_unidentified" = check_anomalies,
"neutralize_cyborgs" = check_borgs
)
return data
/obj/machinery/porta_turret/tgui_static_data(mob/user)
var/list/data = list()
data["regions"] = get_accesslist_static_data(region_min, region_max)
return data
/obj/machinery/porta_turret/tgui_act(action, params)
if (..())
return
if(isLocked(usr))
return
. = TRUE
switch(action)
if("power")
enabled = !enabled
if("lethal")
if(lethal_is_configurable)
lethal = !lethal
if(targetting_is_configurable)
switch(action)
if("authweapon")
check_weapons = !check_weapons
if("authaccess")
check_access = !check_access
if("authnorecord")
check_records = !check_records
if("autharrest")
check_arrest = !check_arrest
if("authxeno")
check_anomalies = !check_anomalies
if("authsynth")
check_synth = !check_synth
if("authborgs")
check_borgs = !check_borgs
if("set")
var/access = text2num(params["access"])
if(one_access)
if(!(access in req_one_access))
req_one_access += access
else
req_one_access -= access
else
if(!(access in req_access))
req_access += access
else
req_access -= access
if(access_is_configurable())
switch(action)
if("grant_region")
var/region = text2num(params["region"])
if(isnull(region))
return
if(one_access)
req_one_access |= get_region_accesses(region)
else
req_access |= get_region_accesses(region)
if("deny_region")
var/region = text2num(params["region"])
if(isnull(region))
return
if(one_access)
req_one_access -= get_region_accesses(region)
else
req_access -= get_region_accesses(region)
if("clear_all")
if(one_access)
req_one_access = list()
else
req_access = list()
if("grant_all")
if(one_access)
req_one_access = get_all_accesses()
else
req_access = get_all_accesses()
if("one_access")
if(one_access)
req_one_access = list()
else
req_access = list()
one_access = !one_access
/obj/machinery/porta_turret/power_change()
if(powered() || !use_power)
@@ -379,23 +359,25 @@ GLOBAL_LIST_EMPTY(turret_icons)
"<span class='notice'>You begin [anchored ? "un" : ""]securing the turret.</span>" \
)
wrenching = 1
wrenching = TRUE
if(do_after(user, 50 * I.toolspeed, target = src))
//This code handles moving the turret around. After all, it's a portable turret!
if(!anchored)
playsound(loc, I.usesound, 100, 1)
anchored = 1
anchored = TRUE
update_icon()
to_chat(user, "<span class='notice'>You secure the exterior bolts on the turret.</span>")
else if(anchored)
playsound(loc, I.usesound, 100, 1)
anchored = 0
anchored = FALSE
to_chat(user, "<span class='notice'>You unsecure the exterior bolts on the turret.</span>")
update_icon()
wrenching = 0
wrenching = FALSE
else if(istype(I, /obj/item/card/id) || istype(I, /obj/item/pda))
if(allowed(user))
if(HasController())
to_chat(user, "<span class='notice'>Turrets regulated by a nearby turret controller are not unlockable.</span>")
else if(allowed(user))
locked = !locked
to_chat(user, "<span class='notice'>Controls are now [locked ? "locked" : "unlocked"].</span>")
updateUsrDialog()
@@ -409,9 +391,9 @@ GLOBAL_LIST_EMPTY(turret_icons)
playsound(src.loc, 'sound/weapons/smash.ogg', 60, 1)
if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off
if(!attacked && !emagged)
attacked = 1
attacked = TRUE
spawn(60)
attacked = 0
attacked = FALSE
..()
@@ -445,12 +427,12 @@ GLOBAL_LIST_EMPTY(turret_icons)
if(user)
to_chat(user, "<span class='warning'>You short out [src]'s threat assessment circuits.</span>")
visible_message("[src] hums oddly...")
emagged = 1
emagged = TRUE
iconholder = 1
controllock = 1
enabled = 0 //turns off the turret temporarily
controllock = TRUE
enabled = FALSE //turns off the turret temporarily
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
/obj/machinery/porta_turret/take_damage(force)
if(!raised && !raising)
@@ -470,9 +452,9 @@ GLOBAL_LIST_EMPTY(turret_icons)
if(enabled)
if(!attacked && !emagged)
attacked = 1
attacked = TRUE
spawn(60)
attacked = 0
attacked = FALSE
..()
@@ -489,12 +471,12 @@ GLOBAL_LIST_EMPTY(turret_icons)
check_access = prob(20) // check_access is a pretty big deal, so it's least likely to get turned on
check_anomalies = prob(50)
if(prob(5))
emagged = 1
emagged = TRUE
enabled=0
spawn(rand(60,600))
spawn(rand(60, 600))
if(!enabled)
enabled=1
enabled = TRUE
..()
@@ -585,8 +567,8 @@ GLOBAL_LIST_EMPTY(turret_icons)
if(get_turf(L) == get_turf(src))
return TURRET_NOT_TARGET
if(!emagged && !syndicate && (issilicon(L) || isbot(L))) // Don't target silica
return TURRET_NOT_TARGET
if(!emagged && !syndicate && (issilicon(L) || isbot(L)))
return (check_borgs && isrobot(L)) ? TURRET_PRIORITY_TARGET : TURRET_NOT_TARGET
if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really
return TURRET_NOT_TARGET //move onto next potential victim!
@@ -643,7 +625,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
return
if(stat & BROKEN)
return
set_raised_raising(raised, 1)
set_raised_raising(raised, TRUE)
playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1)
update_icon()
@@ -653,7 +635,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
sleep(10)
qdel(flick_holder)
set_raised_raising(1, 0)
set_raised_raising(TRUE, FALSE)
update_icon()
/obj/machinery/porta_turret/proc/popDown() //pops the turret down
@@ -664,7 +646,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
return
if(stat & BROKEN)
return
set_raised_raising(raised, 1)
set_raised_raising(raised, TRUE)
playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1)
update_icon()
@@ -674,7 +656,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
sleep(10)
qdel(flick_holder)
set_raised_raising(0, 0)
set_raised_raising(FALSE, FALSE)
update_icon()
/obj/machinery/porta_turret/on_assess_perp(mob/living/carbon/human/perp)
@@ -739,6 +721,27 @@ GLOBAL_LIST_EMPTY(turret_icons)
A.throw_at(target, scan_range, 1)
return A
/obj/machinery/porta_turret/centcom
name = "Centcom Turret"
enabled = FALSE
ailock = TRUE
check_synth = FALSE
check_access = TRUE
check_arrest = TRUE
check_records = TRUE
check_weapons = TRUE
check_anomalies = TRUE
region_max = REGION_CENTCOMM // Non-turretcontrolled turrets at CC can have their access customized to check for CC accesses.
/obj/machinery/porta_turret/centcom/pulse
name = "Pulse Turret"
health = 200
enabled = TRUE
lethal = TRUE
lethal_is_configurable = FALSE
req_access = list(ACCESS_CENT_COMMANDER)
installation = /obj/item/gun/energy/pulse/turret
/datum/turret_checks
var/enabled
var/lethal
@@ -748,6 +751,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
var/check_arrest
var/check_weapons
var/check_anomalies
var/check_borgs
var/ailock
/obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC)
@@ -763,6 +767,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
check_arrest = TC.check_arrest
check_weapons = TC.check_weapons
check_anomalies = TC.check_anomalies
check_borgs = TC.check_borgs
ailock = TC.ailock
power_change()
@@ -791,7 +796,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
if(istype(I, /obj/item/wrench) && !anchored)
playsound(loc, I.usesound, 100, 1)
to_chat(user, "<span class='notice'>You secure the external bolts.</span>")
anchored = 1
anchored = TRUE
build_step = 1
return
@@ -816,7 +821,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
else if(istype(I, /obj/item/wrench))
playsound(loc, I.usesound, 75, 1)
to_chat(user, "<span class='notice'>You unfasten the external bolts.</span>")
anchored = 0
anchored = FALSE
build_step = 0
return
@@ -841,8 +846,10 @@ GLOBAL_LIST_EMPTY(turret_icons)
gun_charge = E.cell.charge //the gun's charge is stored in gun_charge
to_chat(user, "<span class='notice'>You add [I] to the turret.</span>")
if(istype(installation, /obj/item/gun/energy/laser/tag/blue) || istype(installation, /obj/item/gun/energy/laser/tag/red))
target_type = /obj/machinery/porta_turret/tag
if(istype(E, /obj/item/gun/energy/laser/tag/blue))
target_type = /obj/machinery/porta_turret/tag/blue
else if(istype(E, /obj/item/gun/energy/laser/tag/red))
target_type = /obj/machinery/porta_turret/tag/red
else
target_type = /obj/machinery/porta_turret
@@ -934,7 +941,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
Turret.name = finish_name
Turret.installation = installation
Turret.gun_charge = gun_charge
Turret.enabled = 0
Turret.enabled = FALSE
Turret.setup()
qdel(src)
@@ -981,25 +988,27 @@ GLOBAL_LIST_EMPTY(turret_icons)
var/icon_state_active = "syndieturret1"
var/icon_state_destroyed = "syndieturret2"
syndicate = 1
syndicate = TRUE
installation = null
always_up = 1
always_up = TRUE
use_power = NO_POWER_USE
has_cover = 0
raised = 1
has_cover = FALSE
raised = TRUE
scan_range = 9
faction = "syndicate"
emp_vulnerable = 0
emp_vulnerable = FALSE
lethal = 1
check_arrest = 0
check_records = 0
check_weapons = 0
check_access = 0
check_anomalies = 1
check_synth = 1
ailock = 1
lethal = TRUE
lethal_is_configurable = FALSE
targetting_is_configurable = FALSE
check_arrest = FALSE
check_records = FALSE
check_weapons = FALSE
check_access = FALSE
check_anomalies = TRUE
check_synth = TRUE
ailock = TRUE
var/area/syndicate_depot/core/depotarea
/obj/machinery/porta_turret/syndicate/die()
@@ -1018,7 +1027,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
if(req_one_access && req_one_access.len)
req_one_access.Cut()
req_access = list(ACCESS_SYNDICATE)
one_access = 0
one_access = FALSE
/obj/machinery/porta_turret/syndicate/update_icon()
if(stat & BROKEN)
+102 -102
View File
@@ -11,51 +11,56 @@
desc = "Used to control a room's automated defenses."
icon = 'icons/obj/machines/turret_control.dmi'
icon_state = "control_standby"
anchored = 1
density = 0
anchored = TRUE
density = FALSE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/enabled = 0
var/lethal = 0
var/locked = 1
var/enabled = FALSE
var/lethal = FALSE
var/lethal_is_configurable = TRUE
var/locked = TRUE
var/area/control_area //can be area name, path or nothing.
var/check_arrest = 1 //checks if the perp is set to arrest
var/check_records = 1 //checks if a security record exists at all
var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
var/ailock = 0 //Silicons cannot use this
var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
var/check_arrest = TRUE //checks if the perp is set to arrest
var/check_records = TRUE //checks if a security record exists at all
var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
var/check_borgs = FALSE //if TRUE, target all cyborgs.
var/ailock = FALSE //Silicons cannot use this
var/syndicate = 0
var/syndicate = FALSE
var/faction = "" // Turret controls can only access turrets that are in the same faction
req_access = list(ACCESS_AI_UPLOAD)
/obj/machinery/turretid/stun
enabled = 1
enabled = TRUE
icon_state = "control_stun"
/obj/machinery/turretid/lethal
enabled = 1
lethal = 1
enabled = TRUE
lethal = TRUE
icon_state = "control_kill"
/obj/machinery/turretid/syndicate
enabled = 1
lethal = 1
enabled = TRUE
lethal = TRUE
lethal_is_configurable = FALSE
targetting_is_configurable = FALSE
icon_state = "control_kill"
lethal = 1
check_arrest = 0
check_records = 0
check_weapons = 0
check_access = 0
check_anomalies = 1
check_synth = 1
ailock = 1
check_arrest = FALSE
check_records = FALSE
check_weapons = FALSE
check_access = FALSE
check_anomalies = TRUE
check_synth = TRUE
check_borgs = FALSE
ailock = TRUE
syndicate = 1
syndicate = TRUE
faction = "syndicate"
req_access = list(ACCESS_SYNDICATE_LEADER)
@@ -87,21 +92,23 @@
return
/obj/machinery/turretid/proc/isLocked(mob/user)
if(ailock && (isrobot(user) || isAI(user)))
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
return 1
if(isrobot(user) || isAI(user))
if(ailock)
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
return TRUE
else
return FALSE
if(locked && !(isrobot(user) || isAI(user) || isobserver(user)))
to_chat(user, "<span class='notice'>Access denied.</span>")
return 1
if(isobserver(user))
if(user.can_admin_interact())
return FALSE
else
return TRUE
return 0
if(locked)
return TRUE
/obj/machinery/turretid/CanUseTopic(mob/user)
if(isLocked(user))
return STATUS_CLOSE
return ..()
return FALSE
/obj/machinery/turretid/attackby(obj/item/W, mob/user)
if(stat & BROKEN)
@@ -120,89 +127,82 @@
/obj/machinery/turretid/emag_act(user as mob)
if(!emagged)
to_chat(user, "<span class='danger'>You short out the turret controls' access analysis module.</span>")
emagged = 1
locked = 0
ailock = 0
emagged = TRUE
locked = FALSE
ailock = FALSE
return
/obj/machinery/turretid/attack_ai(mob/user as mob)
if(isLocked(user))
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/turretid/attack_ghost(mob/user as mob)
ui_interact(user)
tgui_interact(user)
/obj/machinery/turretid/attack_hand(mob/user as mob)
if(isLocked(user))
return
tgui_interact(user)
ui_interact(user)
/obj/machinery/turretid/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/turretid/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 350)
ui = new(user, src, ui_key, "PortableTurret", name, 500, 400)
ui.open()
ui.set_auto_update(1)
/obj/machinery/turretid/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["access"] = !isLocked(user)
data["locked"] = locked
data["enabled"] = enabled
data["lethal_control"] = !syndicate ? 1 : 0
data["lethal"] = lethal
if(data["access"] && !syndicate)
var/settings[0]
settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
settings[++settings.len] = list("category" = "Check Misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
data["settings"] = settings
/obj/machinery/turretid/tgui_data(mob/user)
var/list/data = list(
"locked" = isLocked(user), // does the current user have access?
"on" = enabled,
"targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up
"lethal" = lethal,
"lethal_is_configurable" = lethal_is_configurable,
"check_weapons" = check_weapons,
"neutralize_noaccess" = check_access,
"one_access" = FALSE,
"selectedAccess" = list(),
"access_is_configurable" = FALSE,
"neutralize_norecord" = check_records,
"neutralize_criminals" = check_arrest,
"neutralize_all" = check_synth,
"neutralize_unidentified" = check_anomalies,
"neutralize_cyborgs" = check_borgs
)
return data
/obj/machinery/turretid/Topic(href, href_list, var/nowindow = 0)
if(..())
return 1
/obj/machinery/turretid/tgui_act(action, params)
if (..())
return
if(isLocked(usr))
return 1
if(href_list["command"] && href_list["value"])
var/value = text2num(href_list["value"])
if(href_list["command"] == "enable")
enabled = value
else if(syndicate)
return 1
else if(href_list["command"] == "lethal")
lethal = value
else if(href_list["command"] == "check_synth")
check_synth = value
else if(href_list["command"] == "check_weapons")
check_weapons = value
else if(href_list["command"] == "check_records")
check_records = value
else if(href_list["command"] == "check_arrest")
check_arrest = value
else if(href_list["command"] == "check_access")
check_access = value
else if(href_list["command"] == "check_anomalies")
check_anomalies = value
updateTurrets()
return 1
return
. = TRUE
switch(action)
if("power")
enabled = !enabled
if("lethal")
if(lethal_is_configurable)
lethal = !lethal
if(targetting_is_configurable)
switch(action)
if("authweapon")
check_weapons = !check_weapons
if("authaccess")
check_access = !check_access
if("authnorecord")
check_records = !check_records
if("autharrest")
check_arrest = !check_arrest
if("authxeno")
check_anomalies = !check_anomalies
if("authsynth")
check_synth = !check_synth
if("authborgs")
check_borgs = !check_borgs
updateTurrets()
/obj/machinery/turretid/proc/updateTurrets()
var/datum/turret_checks/TC = new
TC.enabled = enabled
TC.lethal = lethal
TC.check_synth = check_synth
TC.check_borgs = check_borgs
TC.check_access = check_access
TC.check_records = check_records
TC.check_arrest = check_arrest
+275 -249
View File
@@ -11,9 +11,6 @@
var/max_amount = 0
var/price = 0 // Price to buy one
/**
* A vending machine
*/
/obj/machinery/vending
name = "\improper Vendomat"
desc = "A generic vending machine."
@@ -25,8 +22,10 @@
max_integrity = 300
integrity_failure = 100
armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70)
var/icon_vend //Icon_state when vending
var/icon_deny //Icon_state when denying access
/// Icon_state when vending
var/icon_vend
/// Icon_state when denying access
var/icon_deny
// Power
use_power = IDLE_POWER_USE
@@ -34,12 +33,14 @@
var/vend_power_usage = 150
// Vending-related
var/active = 1 //No sales pitches if off!
var/vend_ready = 1 //Are we ready to vend?? Is it time??
var/vend_delay = 10 //How long does it take to vend?
var/datum/data/vending_product/currently_vending = null // What we're requesting payment for right now
var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI
var/status_error = 0 // Set to 1 if status_message is an error
/// No sales pitches if off
var/active = 1
/// If off, vendor is busy and unusable until current action finishes
var/vend_ready = TRUE
/// How long vendor takes to vend one item.
var/vend_delay = 10
/// Item currently being bought
var/datum/data/vending_product/currently_vending = null
// To be filled out at compile time
var/list/products = list() // For each, use the following pattern:
@@ -51,16 +52,19 @@
var/list/product_records = list()
var/list/hidden_records = list()
var/list/coin_records = list()
var/list/imagelist = list()
var/list/ads_list = list() //Small ad messages in the vending screen - random chance, TODO: implementation
/// Unimplemented list of ads that are meant to show up somewhere, but don't.
var/list/ads_list = list()
// Stuff relating vocalizations
var/list/slogan_list = list() //List of slogans the vendor will say, optional
/// List of slogans the vendor will say, optional
var/list/slogan_list = list()
var/vend_reply //Thank you for shopping!
var/shut_up = 0 //Stop spouting those godawful pitches!
/// If true, prevent saying sales pitches
var/shut_up = FALSE
///can we access the hidden inventory?
var/extended_inventory = 0
var/extended_inventory = FALSE
var/last_reply = 0
var/last_slogan = 0 //When did we last pitch?
var/slogan_delay = 6000 //How long until we can pitch again?
@@ -69,17 +73,26 @@
var/obj/item/vending_refill/refill_canister = null
// Things that can go wrong
emagged = 0 //Ignores if somebody doesn't have card access to that machine.
var/seconds_electrified = 0 //Shock customers like an airlock.
var/shoot_inventory = 0 //Fire items at customers! We're broken!
var/shoot_speed = 3 //How hard are we firing the items?
var/shoot_chance = 2 //How often are we firing the items?
/// Allows people to access a vendor that's normally access restricted.
emagged = 0
/// Shocks people like an airlock
var/seconds_electrified = 0
/// Fire items at customers! We're broken!
var/shoot_inventory = FALSE
/// How hard are we firing the items?
var/shoot_speed = 3
/// How often are we firing the items? (prob(...))
var/shoot_chance = 2
var/scan_id = 1
/// If true, enforce access checks on customers. Disabled by messing with wires.
var/scan_id = TRUE
/// Holder for a coin inserted into the vendor
var/obj/item/coin/coin
var/datum/wires/vending/wires = null
/// boolean, whether this vending machine can accept people inserting items into it, used for coffee vendors
var/item_slot = FALSE
/// the actual item inserted
var/obj/item/inserted_item = null
/obj/machinery/vending/Initialize(mapload)
@@ -92,6 +105,10 @@
build_inventory(products, product_records)
build_inventory(contraband, hidden_records)
build_inventory(premium, coin_records)
for (var/datum/data/vending_product/R in (product_records + coin_records + hidden_records))
var/obj/item/I = R.product_path
var/pp = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-")
imagelist[pp] = "[icon2base64(icon(initial(I.icon), initial(I.icon_state)))]"
if(LAZYLEN(slogan_list))
// So not all machines speak at the exact same time.
// The first time this machine says something will be at slogantime + this random value,
@@ -214,37 +231,16 @@
..()
/obj/machinery/vending/attackby(obj/item/I, mob/user, params)
if(currently_vending && GLOB.vendor_account && !GLOB.vendor_account.suspended)
var/paid = 0
var/handled = 0
if(istype(I, /obj/item/card/id))
var/obj/item/card/id/C = I
paid = pay_with_card(C)
handled = 1
if(istype(I, /obj/item/pda))
var/obj/item/pda/PDA = I
if(PDA.id)
paid = pay_with_card(PDA.id)
handled = 1
else if(istype(I, /obj/item/stack/spacecash))
var/obj/item/stack/spacecash/C = I
paid = pay_with_cash(C, user)
handled = 1
if(paid)
vend(currently_vending, usr)
if(istype(I, /obj/item/coin))
if(!premium.len)
to_chat(user, "<span class='warning'>[src] does not accept coins.</span>")
return
else if(handled)
SSnanoui.update_uis(src)
return // don't smack that machine with your 2 thalers
if(istype(I, /obj/item/coin) && premium.len)
if(!user.drop_item())
return
I.forceMove(src)
coin = I
to_chat(user, "<span class='notice'>You insert the [I] into the [src]</span>")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
return
if(refill_canister && istype(I, refill_canister))
if(!panel_open)
@@ -295,7 +291,7 @@
else
SCREWDRIVER_CLOSE_PANEL_MESSAGE
overlays.Cut()
SSnanoui.update_uis(src) // Speaker switch is on the main UI, not wires UI
SStgui.update_uis(src)
/obj/machinery/vending/wirecutter_act(mob/user, obj/item/I)
. = TRUE
@@ -359,12 +355,10 @@
if(!user.drop_item())
to_chat(user, "<span class='warning'>[I] is stuck to your hand, you can't seem to put it down!</span>")
return
inserted_item = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/vending/proc/eject_item(mob/user)
if(!item_slot || !inserted_item)
@@ -377,23 +371,19 @@
var/turf/T = get_turf(src)
inserted_item.forceMove(T)
inserted_item = null
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/vending/emag_act(user as mob)
emagged = TRUE
to_chat(user, "You short out the product lock on [src]")
/**
* Receive payment with cashmoney.
*
* usr is the mob who gets the change.
*/
/obj/machinery/vending/proc/pay_with_cash(obj/item/stack/spacecash/cashmoney, mob/user)
if(currently_vending.price > cashmoney.amount)
// This is not a status display message, since it's something the character
// themselves is meant to see BEFORE putting the money in
to_chat(usr, "[bicon(cashmoney)] <span class='warning'>That is not enough money.</span>")
return 0
return FALSE
// Bills (banknotes) cannot really have worth different than face value,
// so we have to eat the bill and spit out change in a bundle
@@ -405,50 +395,36 @@
// Vending machines have no idea who paid with cash
GLOB.vendor_account.credit(currently_vending.price, "Sale of [currently_vending.name]", name, "(cash)")
return 1
return TRUE
/**
* Scan a card and attempt to transfer payment from associated account.
*
* Takes payment for whatever is the currently_vending item. Returns 1 if
* successful, 0 if failed
*/
/obj/machinery/vending/proc/pay_with_card(var/obj/item/card/id/I)
visible_message("<span class='info'>[usr] swipes a card through [src].</span>")
return pay_with_account(get_card_account(I))
/obj/machinery/vending/proc/pay_with_account(var/datum/money_account/customer_account)
/obj/machinery/vending/proc/pay_with_card(obj/item/card/id/I, mob/M)
visible_message("<span class='info'>[M] swipes a card through [src].</span>")
return pay_with_account(get_card_account(I), M)
/obj/machinery/vending/proc/pay_with_account(datum/money_account/customer_account, mob/M)
if(!customer_account)
src.status_message = "Error: Unable to access account. Please contact technical support if problem persists."
src.status_error = 1
return 0
to_chat(M, "<span class='warning'>Error: Unable to access account. Please contact technical support if problem persists.</span>")
return FALSE
if(customer_account.suspended)
src.status_message = "Unable to access account: account suspended."
src.status_error = 1
return 0
// Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
// empty at high security levels
if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2)
to_chat(M, "<span class='warning'>Unable to access account: account suspended.</span>")
return FALSE
// Have the customer punch in the PIN before checking if there's enough money.
// Prevents people from figuring out acct is empty at high security levels
if(customer_account.security_level != 0)
// If card requires pin authentication (ie seclevel 1 or 2)
var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
if(!attempt_account_access(customer_account.account_number, attempt_pin, 2))
src.status_message = "Unable to access account: incorrect credentials."
src.status_error = 1
return 0
to_chat(M, "<span class='warning'>Unable to access account: incorrect credentials.</span>")
return FALSE
if(currently_vending.price > customer_account.money)
src.status_message = "Insufficient funds in account."
src.status_error = 1
return 0
else
// Okay to move the money at this point
customer_account.charge(currently_vending.price, GLOB.vendor_account,
"Purchase of [currently_vending.name]", name, GLOB.vendor_account.owner_name,
"Sale of [currently_vending.name]", customer_account.owner_name)
return TRUE
to_chat(M, "<span class='warning'>Your bank account has insufficient money to purchase this.</span>")
return FALSE
// Okay to move the money at this point
customer_account.charge(currently_vending.price, GLOB.vendor_account,
"Purchase of [currently_vending.name]", name, GLOB.vendor_account.owner_name,
"Sale of [currently_vending.name]", customer_account.owner_name)
return TRUE
/obj/machinery/vending/attack_ai(mob/user)
@@ -465,174 +441,238 @@
if(src.shock(user, 100))
return
ui_interact(user)
tgui_interact(user)
wires.Interact(user)
/**
* Display the NanoUI window for the vending machine.
*
* See NanoUI documentation for details.
*/
/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/vending/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "vending_machine.tmpl", src.name, 440, 600)
var/estimated_height = 100 + (length(product_records) * 34)
if(length(prices) > 0)
estimated_height += 100 // to account for the "current user" interface
ui = new(user, src, ui_key, "Vending", name, 470, estimated_height, master_ui, state)
ui.open()
/obj/machinery/vending/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/vending/tgui_data(mob/user)
var/list/data = list()
if(currently_vending)
data["mode"] = 1
data["product"] = sanitize(currently_vending.name)
data["price"] = currently_vending.price
data["message_err"] = 0
data["message"] = src.status_message
data["message_err"] = src.status_error
else
data["mode"] = 0
var/list/listed_products = list()
var/list/display_records = product_records + coin_records
if(extended_inventory)
display_records = product_records + coin_records + hidden_records
for(var/key = 1 to display_records.len)
var/datum/data/vending_product/I = display_records[key]
if(coin_records.Find(I) && !coin)
continue
if(hidden_records.Find(I) && !extended_inventory)
continue
listed_products.Add(list(list(
"key" = key,
"name" = sanitize(I.name),
"price" = I.price,
"amount" = I.amount)))
data["products"] = listed_products
if(coin)
data["coin"] = coin.name
if(item_slot)
data["item_slot"] = 1
if(inserted_item)
data["inserted_item"] = inserted_item
else
data["inserted_item"] = null
else
data["item_slot"] = 0
if(panel_open)
data["panel"] = 1
data["speaker"] = shut_up ? 0 : 1
else
data["panel"] = 0
var/mob/living/carbon/human/H
var/obj/item/card/id/C
data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
data["userMoney"] = 0
data["user"] = null
if(ishuman(user))
H = user
C = H.get_idcard(TRUE)
var/obj/item/stack/spacecash/S = H.get_active_hand()
if(istype(S))
data["userMoney"] = S.amount
data["guestNotice"] = "Accepting Cash. You have: [S.amount] credits."
else if(istype(C))
var/datum/money_account/A = get_card_account(C)
if(istype(A))
data["user"] = list()
data["user"]["name"] = A.owner_name
data["userMoney"] = A.money
data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
else
data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
data["stock"] = list()
for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
data["stock"][R.name] = R.amount
data["extended_inventory"] = extended_inventory
data["vend_ready"] = vend_ready
data["coin_name"] = coin ? coin.name : FALSE
data["panel_open"] = panel_open ? TRUE : FALSE
data["speaker"] = shut_up ? FALSE : TRUE
data["item_slot"] = item_slot // boolean
data["inserted_item_name"] = inserted_item ? inserted_item.name : FALSE
return data
/obj/machinery/vending/Topic(href, href_list)
if(..())
return 1
if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon))
if(!coin)
to_chat(usr, "There is no coin in this machine.")
return
/obj/machinery/vending/tgui_static_data(mob/user)
var/list/data = list()
data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
data["product_records"] = list()
var/i = 1
for (var/datum/data/vending_product/R in product_records)
var/list/data_pr = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
price = (R.product_path in prices) ? prices[R.product_path] : 0,
max_amount = R.max_amount,
req_coin = FALSE,
is_hidden = FALSE,
inum = i
)
data["product_records"] += list(data_pr)
i++
data["coin_records"] = list()
for (var/datum/data/vending_product/R in coin_records)
var/list/data_cr = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
price = (R.product_path in prices) ? prices[R.product_path] : 0,
max_amount = R.max_amount,
req_coin = TRUE,
is_hidden = FALSE,
inum = i,
premium = TRUE
)
data["coin_records"] += list(data_cr)
i++
data["hidden_records"] = list()
for (var/datum/data/vending_product/R in hidden_records)
var/list/data_hr = list(
path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"),
name = R.name,
price = (R.product_path in prices) ? prices[R.product_path] : 0,
max_amount = R.max_amount,
req_coin = FALSE,
is_hidden = TRUE,
inum = i,
premium = TRUE
)
data["hidden_records"] += list(data_hr)
i++
data["imagelist"] = imagelist
return data
usr.put_in_hands(coin)
coin = null
to_chat(usr, "<span class='notice'>You remove [coin] from [src].</span>")
/obj/machinery/vending/tgui_act(action, params)
. = ..()
if(.)
return
if(issilicon(usr) && !isrobot(usr))
to_chat(usr, "<span class='warning'>The vending machine refuses to interface with you, as you are not in its target demographic!</span>")
return
switch(action)
if("toggle_voice")
if(panel_open)
shut_up = !shut_up
. = TRUE
if("eject_item")
eject_item(usr)
. = TRUE
if("remove_coin")
if(!coin)
to_chat(usr, "<span class='warning'>There is no coin in this machine.</span>")
return
if(istype(usr, /mob/living/silicon))
to_chat(usr, "<span class='warning'>You lack hands.</span>")
return
to_chat(usr, "<span class='notice'>You remove [coin] from [src].</span>")
usr.put_in_hands(coin)
coin = null
. = TRUE
if("vend")
if(!vend_ready)
to_chat(usr, "<span class='warning'>The vending machine is busy!</span>")
return
if(panel_open)
to_chat(usr, "<span class='warning'>The vending machine cannot dispense products while its service panel is open!</span>")
return
var/key = text2num(params["inum"])
var/list/display_records = product_records + coin_records
if(extended_inventory)
display_records = product_records + coin_records + hidden_records
if(key < 1 || key > length(display_records))
to_chat(usr, "<span class='warning'>ERROR: invalid inum passed to vendor. Report this bug.</span>")
return
var/datum/data/vending_product/R = display_records[key]
if(!istype(R))
to_chat(usr, "<span class='warning'>ERROR: unknown vending_product record. Report this bug.</span>")
return
var/list/record_to_check = product_records + coin_records
if(extended_inventory)
record_to_check = product_records + coin_records + hidden_records
if(!R || !istype(R) || !R.product_path)
to_chat(usr, "<span class='warning'>ERROR: unknown product record. Report this bug.</span>")
return
if(R in hidden_records)
if(!extended_inventory)
// Exploit prevention, stop the user purchasing hidden stuff if they haven't hacked the machine.
to_chat(usr, "<span class='warning'>ERROR: machine does not allow extended_inventory in current state. Report this bug.</span>")
return
else if (!(R in record_to_check))
// Exploit prevention, stop the user
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!")
return
if (R.amount <= 0)
to_chat(usr, "Sold out of [R.name].")
flick(icon_deny, src)
return
if(href_list["remove_item"])
eject_item(usr)
vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
if(href_list["pay"])
if(currently_vending && GLOB.vendor_account && !GLOB.vendor_account.suspended)
var/paid = 0
var/handled = 0
var/datum/money_account/A = usr.get_worn_id_account()
if(A)
paid = pay_with_account(A)
handled = 1
else if(istype(usr.get_active_hand(), /obj/item/card))
paid = pay_with_card(usr.get_active_hand())
handled = 1
else if(usr.can_admin_interact())
paid = 1
handled = 1
if(!ishuman(usr) || R.price <= 0)
// Either the purchaser is not human, or the item is free.
// Skip all payment logic.
vend(R, usr)
add_fingerprint(usr)
vend_ready = TRUE
. = TRUE
return
// --- THE REST OF THIS PROC IS JUST PAYMENT LOGIC ---
var/mob/living/carbon/human/H = usr
var/obj/item/card/id/C = H.get_idcard(TRUE)
if(!GLOB.vendor_account || GLOB.vendor_account.suspended)
to_chat(usr, "Vendor account offline. Unable to process transaction.")
flick(icon_deny, src)
vend_ready = TRUE
return
currently_vending = R
var/paid = FALSE
if(istype(usr.get_active_hand(), /obj/item/stack/spacecash))
var/obj/item/stack/spacecash/S = usr.get_active_hand()
paid = pay_with_cash(S)
else if(istype(C, /obj/item/card))
// Because this uses H.get_idcard(TRUE), it will attempt to use:
// active hand, inactive hand, pda.id, and then wear_id ID in that order
// this is important because it lets people buy stuff with someone else's ID by holding it while using the vendor
paid = pay_with_card(C, usr)
else if(usr.can_advanced_admin_interact())
to_chat(usr, "<span class='notice'>Vending object due to admin interaction.</span>")
paid = TRUE
else
to_chat(usr, "<span class='warning'>Payment failure: you have no ID or other method of payment.")
vend_ready = TRUE
flick(icon_deny, src)
. = TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
return
if(paid)
vend(currently_vending, usr)
return
else if(handled)
SSnanoui.update_uis(src)
return // don't smack that machine with your 2 credits
if((href_list["vend"]) && vend_ready && !currently_vending)
if(issilicon(usr) && !isrobot(usr))
to_chat(usr, "<span class='warning'>The vending machine refuses to interface with you, as you are not in its target demographic!</span>")
return
if(!allowed(usr) && !usr.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
to_chat(usr, "<span class='warning'>Access denied.</span>") //Unless emagged of course
flick(icon_deny,src)
return
var/key = text2num(href_list["vend"])
var/list/display_records = product_records + coin_records
if(extended_inventory)
display_records = product_records + coin_records + hidden_records
var/datum/data/vending_product/R = display_records[key]
// This should not happen unless the request from NanoUI was bad
if(coin_records.Find(R) && !coin)
return
if(hidden_records.Find(R) && !extended_inventory)
return
if(R.price <= 0)
vend(R, usr)
else
currently_vending = R
if(!GLOB.vendor_account || GLOB.vendor_account.suspended)
status_message = "This machine is currently unable to process payments due to problems with the associated account."
status_error = 1
. = TRUE
else
status_message = "Please swipe a card or insert cash to pay for the item."
status_error = 0
to_chat(usr, "<span class='warning'>Payment failure: unable to process payment.")
vend_ready = TRUE
if(.)
add_fingerprint(usr)
else if(href_list["cancelpurchase"])
currently_vending = null
else if(href_list["togglevoice"] && panel_open)
shut_up = !src.shut_up
add_fingerprint(usr)
SSnanoui.update_uis(src)
/obj/machinery/vending/proc/vend(datum/data/vending_product/R, mob/user)
if(!allowed(usr) && !usr.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
to_chat(usr, "<span class='warning'>Access denied.</span>")//Unless emagged of course
flick(icon_deny,src)
if(!allowed(user) && !user.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
to_chat(user, "<span class='warning'>Access denied.</span>")//Unless emagged of course
flick(icon_deny, src)
vend_ready = TRUE
return
if(!R.amount)
to_chat(user, "<span class='warning'>The vending machine has ran out of that product.</span>")
vend_ready = TRUE
return
vend_ready = 0 //One thing at a time!!
status_message = "Vending..."
status_error = 0
SSnanoui.update_uis(src)
vend_ready = FALSE //One thing at a time!!
if(coin_records.Find(R))
if(!coin)
to_chat(user, "<span class='notice'>You need to insert a coin to get this item.</span>")
vend_ready = TRUE
return
if(coin.string_attached)
if(prob(50))
@@ -652,15 +692,13 @@
use_power(vend_power_usage) //actuators and stuff
if(icon_vend) //Show the vending animation if needed
flick(icon_vend, src)
playsound(get_turf(src), 'sound/machines/machine_vend.ogg', 50, TRUE)
addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
/obj/machinery/vending/proc/delayed_vend(datum/data/vending_product/R, mob/user)
do_vend(R, user)
status_message = ""
status_error = 0
vend_ready = 1
vend_ready = TRUE
currently_vending = null
SSnanoui.update_uis(src)
//override this proc to add handling for what to do with the vended product when you have a inserted item and remember to include a parent call for this generic handling
/obj/machinery/vending/proc/do_vend(datum/data/vending_product/R, mob/user)
@@ -796,17 +834,6 @@
*/
/*
/obj/machinery/vending/atmospherics //Commenting this out until someone ponies up some actual working, broken, and unpowered sprites - Quarxink
name = "\improper Tank Vendor"
desc = "A vendor with a wide variety of masks and gas tanks."
icon = 'icons/obj/objects.dmi'
icon_state = "dispenser"
product_paths = "/obj/item/tank/oxygen;/obj/item/tank/plasma;/obj/item/tank/emergency_oxygen;/obj/item/tank/emergency_oxygen/engi;/obj/item/clothing/mask/breath"
product_amounts = "10;10;10;5;25"
vend_delay = 0
*/
/obj/machinery/vending/assist
products = list( /obj/item/assembly/prox_sensor = 5,/obj/item/assembly/igniter = 3,/obj/item/assembly/signaler = 4,
/obj/item/wirecutters = 1, /obj/item/cartridge/signal = 4)
@@ -1553,7 +1580,6 @@
desc = "Tools for tools."
icon_state = "tool"
icon_deny = "tool-deny"
//req_access_txt = "12" //Maintenance access
products = list(/obj/item/stack/cable_coil/random = 10,/obj/item/crowbar = 5,/obj/item/weldingtool = 3,/obj/item/wirecutters = 5,
/obj/item/wrench = 5,/obj/item/analyzer = 5,/obj/item/t_scanner = 5,/obj/item/screwdriver = 5)
contraband = list(/obj/item/weldingtool/hugetank = 2,/obj/item/clothing/gloves/color/fyellow = 2)
+20 -20
View File
@@ -158,36 +158,36 @@
/obj/machinery/computer/mech_bay_power_console/attack_hand(mob/user as mob)
if(..())
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/mech_bay_power_console/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "mech_bay_console.tmpl", "Mech Bay Control Console", 500, 325)
// open the new ui window
ui = new(user, src, ui_key, "MechBayConsole", name, 400, 150, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/computer/mech_bay_power_console/tgui_act(action, params)
if(..())
return
switch(action)
if("reconnect")
reconnect()
. = TRUE
update_icon()
/obj/machinery/computer/mech_bay_power_console/tgui_data(mob/user)
var/data = list()
if(!recharge_port)
reconnect()
if(recharge_port && !QDELETED(recharge_port))
data["recharge_port"] = list("mech" = null)
if(recharge_port.recharging_mecha && !QDELETED(recharge_port.recharging_mecha))
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mecha.obj_integrity, "maxhealth" = initial(recharge_port.recharging_mecha.max_integrity), "cell" = null)
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mecha.obj_integrity, "maxhealth" = recharge_port.recharging_mecha.max_integrity, "cell" = null, "name" = recharge_port.recharging_mecha.name)
if(recharge_port.recharging_mecha.cell && !QDELETED(recharge_port.recharging_mecha.cell))
data["has_mech"] = 1
data["mecha_name"] = recharge_port.recharging_mecha || "None"
data["mecha_charge"] = isnull(recharge_port.recharging_mecha) ? 0 : recharge_port.recharging_mecha.cell.charge
data["mecha_maxcharge"] = isnull(recharge_port.recharging_mecha) ? 0 : recharge_port.recharging_mecha.cell.maxcharge
data["mecha_charge_percentage"] = isnull(recharge_port.recharging_mecha) ? 0 : round(recharge_port.recharging_mecha.cell.percent())
else
data["has_mech"] = 0
data["recharge_port"]["mech"]["cell"] = list(
"charge" = recharge_port.recharging_mecha.cell.charge,
"maxcharge" = recharge_port.recharging_mecha.cell.maxcharge
)
return data
/obj/machinery/computer/mech_bay_power_console/Initialize()
-1
View File
@@ -159,7 +159,6 @@
radio.name = "[src] radio"
radio.icon = icon
radio.icon_state = icon_state
radio.subspace_transmission = 1
/obj/mecha/examine(mob/user)
. = ..()
@@ -10,8 +10,6 @@
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
var/code = 2
is_special = 1
/obj/item/radio/electropack/attack_hand(mob/user as mob)
if(src == user.back)
to_chat(user, "<span class='notice'>You need help taking this off!</span>")
@@ -54,23 +52,6 @@
if(src.flags & NODROP)
A.flags |= NODROP
/obj/item/radio/electropack/Topic(href, href_list)
if(..())
return 1
if(href_list["freq"])
var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
set_frequency(new_frequency)
else if(href_list["code"])
code += text2num(href_list["code"])
code = round(code)
code = clamp(code, 1, 100)
else if(href_list["power"])
on = !on
add_fingerprint(usr)
/obj/item/radio/electropack/receive_signal(datum/signal/signal)
if(!signal || signal.encryption != code)
@@ -96,18 +77,48 @@
return
/obj/item/radio/electropack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/radio/electropack/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_inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio_electro.tmpl", "[name]", 400, 500)
ui = new(user, src, ui_key, "Electropack", name, 360, 150, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/item/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/item/radio/electropack/tgui_data(mob/user)
var/list/data = list()
data["power"] = on
data["freq"] = format_frequency(frequency)
data["frequency"] = frequency
data["code"] = code
data["minFrequency"] = PUBLIC_LOW_FREQ
data["maxFrequency"] = PUBLIC_HIGH_FREQ
return data
/obj/item/radio/electropack/tgui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("power")
on = !on
if("freq")
var/value = params["freq"]
if(value)
frequency = sanitize_frequency(value)
set_frequency(frequency)
else
. = FALSE
if("code")
var/value = text2num(params["code"])
if(value)
value = round(value)
code = clamp(value, 1, 100)
else
. = FALSE
if("reset")
if(params["reset"] == "freq")
frequency = initial(frequency)
else if(params["reset"] == "code")
code = initial(code)
else
. = FALSE
if(.)
add_fingerprint(usr)
@@ -9,7 +9,6 @@
"Vox Armalis" = 'icons/mob/species/armalis/ears.dmi'
) //We read you loud and skree-er.
materials = list(MAT_METAL=75)
subspace_transmission = TRUE
canhear_range = 0 // can't hear headsets from very far away
slot_flags = SLOT_EARS
@@ -91,6 +90,7 @@
ks1type = /obj/item/encryptionkey/syndicate/nukeops
requires_tcomms = FALSE
instant = TRUE // Work instantly if there are no comms
freqlock = TRUE
/obj/item/radio/headset/syndicate/alt //undisguised bowman with flash protection
name = "syndicate headset"
@@ -289,6 +289,7 @@
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/ert
freqlock = TRUE
/obj/item/radio/headset/ert/alt
name = "\proper emergency response team's bowman headset"
@@ -367,7 +368,7 @@
else
to_chat(user, "This headset doesn't have any encryption keys! How useless...")
/obj/item/radio/headset/proc/recalculateChannels(var/setDescription = FALSE)
/obj/item/radio/headset/recalculateChannels(setDescription = FALSE)
channels = list()
translate_binary = FALSE
translate_hive = FALSE
@@ -75,7 +75,6 @@
name = "illicit intercom"
desc = "Talk through this. Evilly"
frequency = SYND_FREQ
subspace_transmission = TRUE
syndiekey = new /obj/item/encryptionkey/syndicate/nukeops
/obj/item/radio/intercom/syndicate/New()
@@ -85,7 +84,6 @@
/obj/item/radio/intercom/pirate
name = "pirate radio intercom"
desc = "You wouldn't steal a space shuttle. Piracy. It's a crime!"
subspace_transmission = 1
/obj/item/radio/intercom/pirate/New()
..()
@@ -109,13 +107,13 @@
GLOB.global_intercoms.Remove(src)
return ..()
/obj/item/radio/intercom/attack_ai(mob/user as mob)
/obj/item/radio/intercom/attack_ai(mob/user)
add_hiddenprint(user)
add_fingerprint(user)
spawn(0)
attack_self(user)
/obj/item/radio/intercom/attack_hand(mob/user as mob)
/obj/item/radio/intercom/attack_hand(mob/user)
add_fingerprint(user)
spawn(0)
attack_self(user)
+106 -149
View File
@@ -26,21 +26,37 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
suffix = "\[3\]"
icon_state = "walkietalkie"
item_state = "walkietalkie"
var/on = 1 // 0 for off
/// boolean for radio enabled or not
var/on = TRUE
var/last_transmission
var/frequency = PUB_FREQ //common chat
var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies
var/canhear_range = 3 // the range which mobs can hear this radio from
var/frequency = PUB_FREQ
/// tune to frequency to unlock traitor supplies
var/traitor_frequency = 0
/// the range which mobs can hear this radio from
var/canhear_range = 3
var/datum/wires/radio/wires = null
var/b_stat = 0
var/broadcasting = 0
var/listening = 1
var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h
var/subspace_transmission = 0
var/obj/item/encryptionkey/syndicate/syndiekey = null //Holder for the syndicate encryption key if present
var/disable_timer = 0 //How many times this is disabled by EMPs
var/is_special = 0 //For electropacks mostly, skips Topic() checks
/// Whether the radio will broadcast stuff it hears, out over the radio
var/broadcasting = FALSE
/// Whether the radio is currently receiving
var/listening = TRUE
/// Whether the radio can be re-tuned to restricted channels it has no key for
var/freerange = FALSE
/// Whether the radio is able to have its primary frequency changed. Used for radios with weird primary frequencies, like DS, syndi, etc
var/freqlock = FALSE
/// Whether the radio broadcasts to everyone within a few tiles, or not
var/loudspeaker = FALSE
/// Whether loudspeaker can be toggled by the user
var/has_loudspeaker = FALSE
/// see communications.dm for full list. First channes is a "default" for :h
var/list/channels = list()
/// Holder for the syndicate encryption key if present
var/obj/item/encryptionkey/syndicate/syndiekey = null
/// How many times this is disabled by EMPs
var/disable_timer = 0
flags = CONDUCT
slot_flags = SLOT_BELT
@@ -100,47 +116,87 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
/obj/item/radio/attack_ghost(mob/user)
return interact(user)
/obj/item/radio/attack_self(mob/user as mob)
user.set_machine(src)
interact(user)
/obj/item/radio/attack_self(mob/user)
tgui_interact(user)
/obj/item/radio/interact(mob/user)
if(!user)
return 0
if(b_stat)
wires.Interact(user)
tgui_interact(user)
return ui_interact(user)
/obj/item/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/radio/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 550)
ui = new(user, src, ui_key, "Radio", name, 360, 150 + (length(channels) * 20), master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/item/radio/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/item/radio/tgui_data(mob/user)
var/list/data = list()
data["mic_status"] = broadcasting
data["speaker"] = listening
data["freq"] = format_frequency(frequency)
data["rawfreq"] = num2text(frequency)
data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
var/list/chanlist = list_channels(user)
if(islist(chanlist) && chanlist.len)
data["chan_list"] = chanlist
data["chan_list_len"] = chanlist.len
if(syndiekey)
data["useSyndMode"] = 1
data["broadcasting"] = broadcasting
data["listening"] = listening
data["frequency"] = frequency
data["minFrequency"] = freerange ? RADIO_LOW_FREQ : PUBLIC_LOW_FREQ
data["maxFrequency"] = freerange ? RADIO_HIGH_FREQ : PUBLIC_HIGH_FREQ
data["canReset"] = frequency == initial(frequency) ? FALSE : TRUE
data["freqlock"] = freqlock
data["channels"] = list()
for(var/channel in channels)
data["channels"][channel] = channels[channel] & FREQ_LISTENING
data["has_loudspeaker"] = has_loudspeaker
data["loudspeaker"] = loudspeaker
return data
/obj/item/radio/tgui_act(action, params, datum/tgui/ui)
if(..())
return
. = TRUE
switch(action)
if("frequency")
if(freqlock)
return
var/tune = params["tune"]
var/adjust = text2num(params["adjust"])
if(tune == "reset")
tune = initial(frequency)
else if(adjust)
tune = frequency + adjust * 10
else if(text2num(tune) != null)
tune = tune * 10
else
. = FALSE
if(hidden_uplink)
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
usr << browse(null, "window=radio")
if(.)
set_frequency(sanitize_frequency(tune, freerange))
if("listen")
listening = !listening
if("broadcast")
broadcasting = !broadcasting
if("channel")
var/channel = params["channel"]
if(!(channel in channels))
return
if(channels[channel] & FREQ_LISTENING)
channels[channel] &= ~FREQ_LISTENING
else
channels[channel] |= FREQ_LISTENING
if("loudspeaker")
// Toggle loudspeaker mode, AKA everyone around you hearing your radio.
if(has_loudspeaker)
loudspeaker = !loudspeaker
if(loudspeaker)
canhear_range = 3
else
canhear_range = 0
else
. = FALSE
if(.)
add_fingerprint(usr)
/obj/item/radio/proc/list_channels(var/mob/user)
return list_internal_channels(user)
@@ -190,53 +246,6 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
/obj/item/radio/proc/ToggleReception()
listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
/obj/item/radio/Topic(href, href_list)
if(..())
return 1
if(is_special)
return 0
if(href_list["track"])
var/mob/target = locate(href_list["track"])
var/mob/living/silicon/ai/A = locate(href_list["track2"])
if(A && target)
A.ai_actual_track(target)
. = 1
else if(href_list["freq"])
var/new_frequency = (frequency + text2num(href_list["freq"]))
if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ))
new_frequency = sanitize_frequency(new_frequency)
set_frequency(new_frequency)
if(hidden_uplink)
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
usr << browse(null, "window=radio")
. = 1
else if(href_list["talk"])
ToggleBroadcast()
. = 1
else if(href_list["listen"])
var/chan_name = href_list["ch_name"]
if(!chan_name)
ToggleReception()
else
if(channels[chan_name] & FREQ_LISTENING)
channels[chan_name] &= ~FREQ_LISTENING
else
channels[chan_name] |= FREQ_LISTENING
. = 1
else if(href_list["spec_freq"])
var/freq = href_list["spec_freq"]
if(has_channel_access(usr, freq))
set_frequency(text2num(freq))
. = 1
if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk
return 1
add_fingerprint(usr)
/obj/item/radio/proc/autosay(message, from, channel, role = "Unknown") //BS12 EDIT
var/datum/radio_frequency/connection = null
if(channel && channels && channels.len > 0)
@@ -582,19 +591,24 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
if(!disable_timer)
on = 1
/obj/item/radio/proc/recalculateChannels()
/// Exists so that borg radios and headsets can override it.
stack_trace("recalculateChannels() called on a radio which does not implement the proc.")
///////////////////////////////
//////////Borg Radios//////////
///////////////////////////////
//Giving borgs their own radio to have some more room to work with -Sieve
/obj/item/radio/borg
name = "Cyborg Radio"
var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks
var/obj/item/encryptionkey/keyslot = null//Borg radios can handle a single encryption key
var/shut_up = 1
icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component.
icon_state = "radio"
has_loudspeaker = TRUE
loudspeaker = FALSE
canhear_range = 0
subspace_transmission = 1
dog_fashion = null
/obj/item/radio/borg/syndicate
@@ -616,12 +630,14 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
..()
syndiekey = keyslot
set_frequency(SYND_FREQ)
freqlock = TRUE
/obj/item/radio/borg/deathsquad
/obj/item/radio/borg/deathsquad/New()
..()
set_frequency(DTH_FREQ)
freqlock = TRUE
/obj/item/radio/borg/ert
keyslot = new /obj/item/encryptionkey/ert
@@ -629,6 +645,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
/obj/item/radio/borg/ert/New()
..()
set_frequency(ERT_FREQ)
freqlock = TRUE
/obj/item/radio/borg/ert/specops
keyslot = new /obj/item/encryptionkey/centcom
@@ -673,7 +690,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
else
to_chat(user, "This radio doesn't have any encryption keys!")
/obj/item/radio/borg/proc/recalculateChannels()
/obj/item/radio/borg/recalculateChannels()
channels = list()
syndiekey = null
@@ -706,72 +723,12 @@ GLOBAL_LIST_INIT(default_medbay_channels, list(
return
/obj/item/radio/borg/Topic(href, href_list)
if(..())
return 1
if(href_list["mode"])
var/enable_subspace_transmission = text2num(href_list["mode"])
if(enable_subspace_transmission != subspace_transmission)
subspace_transmission = !subspace_transmission
if(subspace_transmission)
to_chat(usr, "<span class='notice'>Subspace Transmission is enabled.</span>")
else
to_chat(usr, "<span class='notice'>Subspace Transmission is disabled.</span>")
if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled
channels = list()
else
recalculateChannels()
. = 1
if(href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio.
var/do_shut_up = text2num(href_list["shutup"])
if(do_shut_up != shut_up)
shut_up = !shut_up
if(shut_up)
canhear_range = 0
to_chat(usr, "<span class='notice'>Loudspeaker disabled.</span>")
else
canhear_range = 3
to_chat(usr, "<span class='notice'>Loudspeaker enabled.</span>")
. = 1
/obj/item/radio/borg/interact(mob/user as mob)
/obj/item/radio/borg/interact(mob/user)
if(!on)
return
. = ..()
/obj/item/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 430, 500)
ui.open()
ui.set_auto_update(1)
/obj/item/radio/borg/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["mic_status"] = broadcasting
data["speaker"] = listening
data["freq"] = format_frequency(frequency)
data["rawfreq"] = num2text(frequency)
var/list/chanlist = list_channels(user)
if(islist(chanlist) && chanlist.len)
data["chan_list"] = chanlist
data["chan_list_len"] = chanlist.len
if(syndiekey)
data["useSyndMode"] = 1
data["has_loudspeaker"] = 1
data["loudspeaker"] = !shut_up
data["has_subspace"] = 1
data["subspace"] = subspace_transmission
return data
/obj/item/radio/proc/config(op)
if(SSradio)
for(var/ch_name in channels)
@@ -86,64 +86,64 @@
O.hear_message(M, msg)
/obj/item/transfer_valve/attack_self(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/transfer_valve/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_inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280)
// open the new ui window
ui = new(user, src, ui_key, "TransferValve", name, 460, 320, master_ui, state)
ui.open()
// auto update every Master Controller tick
//ui.set_auto_update(1)
/obj/item/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["attachmentOne"] = tank_one ? tank_one.name : null
data["attachmentTwo"] = tank_two ? tank_two.name : null
data["valveAttachment"] = attached_device ? attached_device.name : null
data["valveOpen"] = valve_open ? 1 : 0
/obj/item/transfer_valve/tgui_data(mob/user)
var/list/data = list()
data["tank_one"] = tank_one ? tank_one.name : null
data["tank_two"] = tank_two ? tank_two.name : null
data["attached_device"] = attached_device ? attached_device.name : null
data["valve"] = valve_open
return data
/obj/item/transfer_valve/Topic(href, href_list)
..()
if(usr.incapacitated())
return 0
if(loc != usr)
return 0
if(tank_one && href_list["tankone"])
split_gases()
valve_open = 0
tank_one.forceMove(get_turf(src))
tank_one = null
/obj/item/transfer_valve/tgui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("tankone")
if(tank_one)
split_gases()
valve_open = FALSE
tank_one.forceMove(get_turf(src))
tank_one = null
update_icon()
if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
if("tanktwo")
if(tank_two)
split_gases()
valve_open = FALSE
tank_two.forceMove(get_turf(src))
tank_two = null
update_icon()
if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
if("toggle")
toggle_valve()
if("device")
if(attached_device)
attached_device.attack_self(usr)
if("remove_device")
if(attached_device)
attached_device.forceMove(get_turf(src))
attached_device.holder = null
attached_device = null
update_icon()
else
. = FALSE
if(.)
update_icon()
if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(tank_two && href_list["tanktwo"])
split_gases()
valve_open = 0
tank_two.forceMove(get_turf(src))
tank_two = null
update_icon()
if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(href_list["open"])
toggle_valve()
else if(attached_device)
if(href_list["rem_device"])
attached_device.forceMove(get_turf(src))
attached_device.holder = null
attached_device = null
update_icon()
if(href_list["device"])
attached_device.attack_self(usr)
add_fingerprint(usr)
return 1 // Returning 1 sends an update to attached UIs
add_fingerprint(usr)
/obj/item/transfer_valve/proc/process_activation(obj/item/D)
if(toggle)
+4
View File
@@ -66,6 +66,10 @@ LIGHTERS ARE IN LIGHTERS.DM
..()
light()
/obj/item/clothing/mask/cigarette/catch_fire()
if(!lit)
light("<span class='warning'>The [name] is lit by the flames!</span>")
/obj/item/clothing/mask/cigarette/welder_act(mob/user, obj/item/I)
. = TRUE
if(I.tool_use_check(user, 0)) //Don't need to flash eyes because you are a badass
+37 -52
View File
@@ -138,70 +138,55 @@
if(!(air_contents))
return
ui_interact(user)
tgui_interact(user)
/obj/item/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/tank/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_inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "tanks.tmpl", "Tank", 500, 300)
// open the new ui window
ui = new(user, src, ui_key, "Tank", name, 300, 150, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/item/tank/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/using_internal
if(iscarbon(loc))
var/mob/living/carbon/C = loc
if(C.internal == src)
using_internal = 1
var/data[0]
/obj/item/tank/tgui_data(mob/user)
var/list/data = list()
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0)
data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE)
data["minReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE)
data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
data["valveOpen"] = using_internal ? 1 : 0
data["maskConnected"] = 0
if(iscarbon(loc))
var/mob/living/carbon/C = loc
if(C.internal == src)
data["maskConnected"] = 1
else
if(C.wear_mask && (C.wear_mask.flags & AIRTIGHT))
data["maskConnected"] = 1
else if(ishuman(C))
var/mob/living/carbon/human/H = C
if(H.head && (H.head.flags & AIRTIGHT))
data["maskConnected"] = 1
var/mob/living/carbon/C = user
if(!istype(C))
C = loc.loc
if(!istype(C))
return data
data["has_mask"] = C.wear_mask ? TRUE : FALSE
data["connected"] = (C.internal && C.internal == src) ? TRUE : FALSE
return data
/obj/item/tank/Topic(href, href_list)
/obj/item/tank/tgui_act(action, params)
if(..())
return 1
if(href_list["dist_p"])
if(href_list["dist_p"] == "reset")
distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
else if(href_list["dist_p"] == "max")
distribute_pressure = TANK_MAX_RELEASE_PRESSURE
return
. = TRUE
switch(action)
if("pressure")
var/pressure = params["pressure"]
if(pressure == "reset")
pressure = initial(distribute_pressure)
else if(pressure == "min")
pressure = TANK_DEFAULT_RELEASE_PRESSURE
else if(pressure == "max")
pressure = TANK_MAX_RELEASE_PRESSURE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
else
. = FALSE
if(.)
distribute_pressure = clamp(round(pressure), TANK_DEFAULT_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
if("internals")
toggle_internals(usr)
else
var/cp = text2num(href_list["dist_p"])
distribute_pressure += cp
distribute_pressure = min(max(round(distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE)
if(href_list["stat"])
toggle_internals(usr)
add_fingerprint(usr)
return 1
. = FALSE
if(.)
add_fingerprint(usr)
/obj/item/tank/remove_air(amount)
return air_contents.remove(amount)
@@ -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
+1 -1
View File
@@ -242,7 +242,7 @@ client/proc/one_click_antag()
var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")
var/obj/effect/landmark/closet_spawn = locate("landmark*Nuclear-Closet")
var/nuke_code = "[rand(10000, 99999)]"
var/nuke_code = rand(10000, 99999)
if(nuke_spawn)
var/obj/item/paper/P = new
+2 -2
View File
@@ -624,11 +624,11 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/beepsound = input(usr, "What sound should the announcement make?", "Announcement Sound", "") as anything in MsgSound
GLOB.command_announcement.Announce(input, customname, MsgSound[beepsound], , , type)
print_command_report(input, "[command_name()] Update")
print_command_report(input, customname)
if("No")
//same thing as the blob stuff - it's not public, so it's classified, dammit
GLOB.command_announcer.autosay("A classified message has been printed out at all communication consoles.")
print_command_report(input, "Classified [command_name()] Update")
print_command_report(input, "Classified: [customname]")
else
return
+1
View File
@@ -164,6 +164,7 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
R.set_frequency(DTH_FREQ)
R.requires_tcomms = FALSE
R.instant = TRUE
R.freqlock = TRUE
equip_to_slot_or_del(R, slot_l_ear)
if(is_leader)
equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(src), slot_w_uniform)
+12 -5
View File
@@ -16,7 +16,9 @@
var/death = TRUE //Kill the mob
var/roundstart = TRUE //fires on initialize
var/instant = FALSE //fires on New
var/flavour_text = "The mapper forgot to set this!"
var/flavour_text = "" //flavour/fluff about the role, optional.
var/description = "A description for this has not been set. This is either an oversight or an admin-spawned spawner not in normal use." //intended as OOC info about the role
var/important_info = "" //important info such as rules that apply to you, etc. Optional.
var/faction = null
var/permanent = FALSE //If true, the spawner will not disappear upon running out of uses.
var/random = FALSE //Don't set a name or gender, just go random
@@ -336,7 +338,7 @@
name = "sleeper"
icon = 'icons/obj/cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "<span class='big bold'>You are a space doctor!</span>"
flavour_text = "You are a space doctor!"
assignedrole = "Space Doctor"
/obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/H)
@@ -470,11 +472,14 @@
name = "bartender sleeper"
icon = 'icons/obj/cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "<span class='big bold'>You are a space bartender!</span><b> Time to mix drinks and change lives.</b>"
description = "Stuck on Lavaland, you could try getting back to civilisation...or serve drinks to those that wander by."
flavour_text = "You are a space bartender! Time to mix drinks and change lives. Wait, where did your bar just get transported to?"
assignedrole = "Space Bartender"
/obj/effect/mob_spawn/human/beach/alive/lifeguard
flavour_text = "<span class='big bold'>You're a spunky lifeguard!</span><b> It's up to you to make sure nobody drowns or gets eaten by sharks and stuff.</b>"
flavour_text = "You're a spunky lifeguard! It's up to you to make sure nobody drowns or gets eaten by sharks and stuff. Then suddenly your entire beach was transported to this strange hell.\
You aren't trained for this, but you'll still keep your guests alive!"
description = "Try to survive on lavaland with the pitiful equipment of a lifeguard. Or hide in your biodome."
mob_gender = "female"
name = "lifeguard sleeper"
id_job = "Lifeguard"
@@ -502,7 +507,8 @@
name = "beach bum sleeper"
icon = 'icons/obj/cryogenic2.dmi'
icon_state = "sleeper"
flavour_text = "You are a beach bum!"
flavour_text = "You are a beach bum! You think something just happened to the beach but you don't really pay too much attention."
description = "Try to survive on lavaland or just enjoy the beach, waiting for visitors."
assignedrole = "Beach Bum"
/datum/outfit/beachbum
@@ -523,6 +529,7 @@
roundstart = FALSE
icon = 'icons/effects/blood.dmi'
icon_state = "remains"
description = "Be a spooky scary skeleton." //not mapped in anywhere so admin spawner, who knows what they'll use this for.
flavour_text = "By unknown powers, your skeletal remains have been reanimated! Walk this mortal plain and terrorize all living adventurers who dare cross your path."
assignedrole = "Skeleton"
@@ -64,9 +64,11 @@
var/has_owner = FALSE
var/can_transfer = TRUE //if golems can switch bodies to this new shell
var/mob/living/owner = null //golem's owner if it has one
flavour_text = "<span class='big bold'>You are a Free Golem.</span><b> Your family worships <span class='danger'>The Liberator</span>. In his infinite and divine wisdom, he set your clan free to \
important_info = "You are not an antag. Do not mess with the station or create AIs."
description = "As a Free Golem on lavaland, you are unable to use most weapons, but you can mine, research and make more of your kind. Earn enough mining points and you can even move your shuttle out of there."
flavour_text = "You are a Free Golem. Your family worships The Liberator. In his infinite and divine wisdom, he set your clan free to \
travel the stars with a single declaration: \"Yeah go do whatever.\" Though you are bound to the one who created you, it is customary in your society to repeat those same words to newborn \
golems, so that no golem may ever be forced to serve again.</b>"
golems, so that no golem may ever be forced to serve again."
/obj/effect/mob_spawn/human/golem/Initialize(mapload, datum/species/golem/species = null, mob/creator = null)
if(species) //spawners list uses object name to register so this goes before ..()
@@ -77,8 +79,10 @@
if(!mapload && A)
notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in [A.name].", source = src)
if(has_owner && creator)
flavour_text = "<span class='big bold'>You are a Golem.</span><b> You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. \
Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost.</b>"
important_info = "Serve your creator, even if they are an antag."
flavour_text = "You are a golem created to serve your creator."
description = "You are a Golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. \
Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost."
owner = creator
/obj/effect/mob_spawn/human/golem/special(mob/living/new_spawn, name)
@@ -10,10 +10,11 @@
death = FALSE
random = TRUE
mob_species = /datum/species/human
flavour_text = "<span class='big bold'>You are a security officer working for Nanotrasen,</span><b> stationed onboard a state of the art research station. You vaguely recall rushing into a \
description = "Work as a team with your fellow survivors aboard a ruined, ancient space station."
important_info = ""
flavour_text = "You are a security officer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \
cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \
Work as a team with your fellow survivors and do not abandon them.</b>"
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod."
uniform = /obj/item/clothing/under/retro/security
shoes = /obj/item/clothing/shoes/jackboots
id = /obj/item/card/id/away/old/sec
@@ -35,10 +36,11 @@
death = FALSE
random = TRUE
mob_species = /datum/species/human
flavour_text = "<span class='big bold'>You are a medical working for Nanotrasen,</span><b> stationed onboard a state of the art research station. You vaguely recall rushing into a \
description = "Work as a team with your fellow survivors aboard a ruined, ancient space station."
important_info = ""
flavour_text = "You are a medical doctor working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \
cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \
Work as a team with your fellow survivors and do not abandon them.</b>"
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod."
uniform = /obj/item/clothing/under/retro/medical
shoes = /obj/item/clothing/shoes/black
id = /obj/item/card/id/away/old/med
@@ -60,10 +62,11 @@
death = FALSE
random = TRUE
mob_species = /datum/species/human
flavour_text = "<span class='big bold'>You are an engineer working for Nanotrasen,</span><b> stationed onboard a state of the art research station. You vaguely recall rushing into a \
description = "Work as a team with your fellow survivors aboard a ruined, ancient space station."
important_info = ""
flavour_text = "You are an engineer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \
cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \
Work as a team with your fellow survivors and do not abandon them.</b>"
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod."
uniform = /obj/item/clothing/under/retro/engineering
shoes = /obj/item/clothing/shoes/workboots
id = /obj/item/card/id/away/old/eng
@@ -85,10 +88,11 @@
death = FALSE
random = TRUE
mob_species = /datum/species/human
flavour_text = "<span class='big bold'>You are a scientist working for Nanotrasen,</span><b> stationed onboard a state of the art research station. You vaguely recall rushing into a \
description = "Work as a team with your fellow survivors aboard a ruined, ancient space station."
important_info = ""
flavour_text = "You are a scientist working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \
cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \
Work as a team with your fellow survivors and do not abandon them.</b>"
your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod."
uniform = /obj/item/clothing/under/retro/science
shoes = /obj/item/clothing/shoes/laceup
id = /obj/item/card/id/away/old/sci
+14
View File
@@ -309,6 +309,20 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/chem_master/send(client)
send_asset_list(client, assets, verify)
//Cloning pod sprites for UIs
/datum/asset/cloning
var/assets = list()
var/verify = FALSE
/datum/asset/cloning/register()
assets["pod_idle.gif"] = icon('icons/obj/cloning.dmi', "pod_idle")
assets["pod_cloning.gif"] = icon('icons/obj/cloning.dmi', "pod_cloning")
assets["pod_mess.gif"] = icon('icons/obj/cloning.dmi', "pod_mess")
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
/datum/asset/cloning/send(client)
send_asset_list(client, assets, verify)
//Pipe sprites for UIs
/datum/asset/rpd
+6
View File
@@ -120,6 +120,12 @@
else
icon = initial(icon)
/**
* Used for any clothing interactions when the user is on fire. (e.g. Cigarettes getting lit.)
*/
/obj/item/clothing/proc/catch_fire() //Called in handle_fire()
return
//Ears: currently only used for headsets and earmuffs
/obj/item/clothing/ears
name = "ears"
+1 -1
View File
@@ -39,7 +39,7 @@
SA.health = SA.maxHealth
SA.del_on_death = FALSE
greet_sentient(SA)
print_command_report(sentience_report, "[command_name()] Update")
print_command_report(sentience_report, "[command_name()] Update", FALSE)
processing = TRUE // Let it naturally end, if it runs successfully
/datum/event/sentience/proc/greet_sentient(var/mob/living/carbon/human/M)
@@ -13,15 +13,3 @@
possible_destinations = "laborcamp_away"
circuit = /obj/item/circuitboard/labor_shuttle/one_way
req_access = list( )
/obj/machinery/computer/shuttle/labor/one_way/Topic(href, href_list)
if(href_list["move"])
var/obj/docking_port/mobile/M = SSshuttle.getShuttle("laborcamp")
if(!M)
to_chat(usr, "<span class='warning'>Cannot locate shuttle!</span>")
return 0
var/obj/docking_port/stationary/S = M.get_docked()
if(S && S.name == "laborcamp_away")
to_chat(usr, "<span class='warning'>Shuttle is already at the outpost!</span>")
return 0
..()
+1 -1
View File
@@ -780,4 +780,4 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set category = "Ghost"
var/datum/spawners_menu/menu = new /datum/spawners_menu(src)
menu.ui_interact(src)
menu.tgui_interact(src)
+1 -3
View File
@@ -66,9 +66,7 @@
if(!is_station_level(T.z))
return
var/area/A = get_area(src)
if(cryo_ssd(src))
var/obj/effect/portal/P = new /obj/effect/portal(T, null, null, 40)
P.name = "NT SSD Teleportation Portal"
cryo_ssd(src)
if(A.fast_despawn)
force_cryo_human(src)
@@ -186,6 +186,8 @@
return 1
if(fire_stacks > 0)
adjust_fire_stacks(-0.1) //the fire is slowly consumed
for(var/obj/item/clothing/C in contents)
C.catch_fire()
else
ExtinguishMob()
return
+24 -11
View File
@@ -83,6 +83,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
var/lockcharge //Used when locking down a borg to preserve cell charge
var/speed = 0 //Cause sec borgs gotta go fast //No they dont!
var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
var/can_lock_cover = FALSE //Used to set if a borg can re-lock its cover.
var/has_camera = TRUE
var/pdahide = 0 //Used to hide the borg from the messenger list
var/tracking_entities = 0 //The number of known entities currently accessing the internal camera
@@ -752,6 +753,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
if(allowed(W))
locked = !locked
to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.")
to_chat(src, "<span class='notice'>[user] [ locked ? "locked" : "unlocked"] your interface.</span>")
update_icons()
else
to_chat(user, "<span class='warning'>Access denied.</span>")
@@ -768,7 +770,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
if(!user.drop_item())
return
if(U.action(src))
to_chat(user, "<span class='notice'>You apply the upgrade to [src].</span>")
user.visible_message("<span class = 'notice'>[user] applied [U] to [src].</span>", "<span class='notice'>You apply [U] to [src].</span>")
U.forceMove(src)
else
to_chat(user, "<span class='danger'>Upgrade error.</span>")
@@ -964,16 +966,24 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
update_icons()
return
/mob/living/silicon/robot/verb/unlock_own_cover()
/mob/living/silicon/robot/verb/toggle_own_cover()
set category = "Robot Commands"
set name = "Unlock Cover"
set desc = "Unlocks your own cover if it is locked. You can not lock it again. A human will have to lock it for you."
if(locked)
switch(alert("You can not lock your cover again, are you sure?\n (You can still ask for a human to lock it)", "Unlock Own Cover", "Yes", "No"))
if("Yes")
locked = 0
update_icons()
to_chat(usr, "You unlock your cover.")
set name = "Toggle Cover"
set desc = "Toggles the lock on your cover."
if(can_lock_cover)
if(alert("Are you sure?", locked ? "Unlock Cover" : "Lock Cover", "Yes", "No") == "Yes")
locked = !locked
update_icons()
to_chat(usr, "<span class='notice'>You [locked ? "lock" : "unlock"] your cover.</span>")
return
if(!locked)
to_chat(usr, "<span class='warning'>You cannot lock your cover yourself. Find a robotocist.</span>")
return
if(alert("You cannnot lock your own cover again. Are you sure?\n You will need a robotocist to re-lock you.", "Unlock Own Cover", "Yes", "No") == "Yes")
locked = !locked
update_icons()
to_chat(usr, "<span class='notice'>You unlock your cover.</span>")
/mob/living/silicon/robot/attack_ghost(mob/user)
if(wiresexposed)
@@ -1119,7 +1129,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
return 1
/mob/living/silicon/robot/proc/radio_menu()
radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code
radio.interact(src)
/mob/living/silicon/robot/proc/control_headlamp()
if(stat || lamp_recharging || low_power_mode)
@@ -1403,6 +1413,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
modtype = "Commando"
faction = list("nanotrasen")
is_emaggable = FALSE
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/deathsquad/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
@@ -1431,6 +1442,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
static_radio_channels = 1
allow_rename = FALSE
weapons_unlock = TRUE
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/super
var/eprefix = "Amber"
@@ -1487,6 +1499,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
ear_protection = 1 // Immunity to the audio part of flashbangs
emp_protection = TRUE // Immunity to EMP, due to heavy shielding
damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg.
can_lock_cover = TRUE
default_cell_type = /obj/item/stock_parts/cell/bluespace
/mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null)
@@ -11,6 +11,7 @@
modtype = "Syndicate"
req_access = list(ACCESS_SYNDICATE)
ionpulse = 1
can_lock_cover = TRUE
lawchannel = "State"
var/playstyle_string = "<span class='userdanger'>You are a Syndicate assault cyborg!</span><br>\
<b>You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
@@ -94,7 +94,6 @@
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)//Diagnostic HUD views
/obj/item/radio/headset/bot
subspace_transmission = 1
requires_tcomms = FALSE
canhear_range = 0
@@ -47,7 +47,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/purple/Life(seconds, times_fired)
. = ..()
if(.) // if mob is NOT dead
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(!degenerate && spider_myqueen)
if(dcheck_counter >= 10)
dcheck_counter = 0
@@ -66,7 +66,7 @@
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired)
. = ..()
if(.) // if mob is NOT dead
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
if(world.time > (spider_lastspawn + spider_spawnfrequency))
if(eggslaid >= 20)
@@ -298,7 +298,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
/mob/living/simple_animal/hostile/poison/terror_spider/Life(seconds, times_fired)
. = ..()
if(!.) // if mob is dead
if(stat == DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
if(prob(2))
// 2% chance every cycle to decompose
visible_message("<span class='notice'>\The dead body of the [src] decomposes!</span>")
@@ -63,7 +63,6 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
hard_drive.store_file(new/datum/computer_file/program/card_mod())
hard_drive.store_file(new/datum/computer_file/program/comm())
// ===== CIVILIAN CONSOLE =====
/obj/machinery/modular_computer/console/preset/civilian
@@ -1,385 +0,0 @@
/datum/computer_file/program/comm
filename = "comm"
filedesc = "Command and communications"
program_icon_state = "comm"
extended_desc = "Used to command and control the station. Can relay long-range communications. This program can not be run on tablet computers."
required_access = ACCESS_HEADS
requires_ntnet = 1
size = 12
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
network_destination = "station long-range communication array"
var/authenticated = COMM_AUTHENTICATION_NONE
var/list/messagetitle = list()
var/list/messagetext = list()
var/currmsg = 0
var/aicurrmsg = 0
var/menu_state = COMM_SCREEN_MAIN
var/ai_menu_state = COMM_SCREEN_MAIN
var/message_cooldown = 0
var/centcomm_message_cooldown = 0
var/tmp_alertlevel = 0
var/stat_msg1
var/stat_msg2
var/display_type="blank"
var/datum/announcement/priority/crew_announcement = new
/datum/computer_file/program/comm/New()
GLOB.shuttle_caller_list += src
..()
crew_announcement.newscast = 0
/datum/computer_file/program/comm/Destroy()
GLOB.shuttle_caller_list -= src
SSshuttle.autoEvac()
return ..()
/datum/computer_file/program/comm/proc/is_authenticated(mob/user, loud = 1)
if(authenticated == COMM_AUTHENTICATION_MAX)
return COMM_AUTHENTICATION_MAX
else if(user.can_admin_interact())
return COMM_AUTHENTICATION_MAX
else if(authenticated)
return COMM_AUTHENTICATION_MIN
else
if(loud)
to_chat(user, "<span class='warning'>Access denied.</span>")
return COMM_AUTHENTICATION_NONE
/datum/computer_file/program/comm/proc/change_security_level(mob/user, new_level)
tmp_alertlevel = new_level
var/old_level = GLOB.security_level
if(!tmp_alertlevel)
tmp_alertlevel = SEC_LEVEL_GREEN
if(tmp_alertlevel < SEC_LEVEL_GREEN)
tmp_alertlevel = SEC_LEVEL_GREEN
if(tmp_alertlevel > SEC_LEVEL_BLUE)
tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
set_security_level(tmp_alertlevel)
if(GLOB.security_level != old_level)
log_game("[key_name(user)] has changed the security level to [get_security_level()].")
message_admins("[key_name_admin(user)] has changed the security level to [get_security_level()].")
switch(GLOB.security_level)
if(SEC_LEVEL_GREEN)
feedback_inc("alert_comms_green", 1)
if(SEC_LEVEL_BLUE)
feedback_inc("alert_comms_blue", 1)
tmp_alertlevel = 0
/datum/computer_file/program/comm/proc/setCurrentMessage(mob/user, value)
if(isAI(user) || isrobot(user))
aicurrmsg = value
else
currmsg = value
/datum/computer_file/program/comm/proc/getCurrentMessage(mob/user)
if(isAI(user) || isrobot(user))
return aicurrmsg
else
return currmsg
/datum/computer_file/program/comm/proc/setMenuState(mob/user, value)
if(isAI(user) || isrobot(user))
ai_menu_state=value
else
menu_state=value
/datum/computer_file/program/comm/proc/getMenuState(mob/user)
if(isAI(user) || isrobot(user))
return ai_menu_state
else
return menu_state
/datum/computer_file/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "comm_program.tmpl", "Command and communications program", 575, 500)
ui.set_layout_key("program")
ui.open()
/datum/computer_file/program/comm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/list/data = get_header_data()
data["is_ai"] = isAI(user) || isrobot(user)
data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state
data["emagged"] = computer ? computer.emagged : null
data["authenticated"] = is_authenticated(user, 0)
data["screen"] = getMenuState(usr)
data["stat_display"] = list(
"type" = display_type,
"line_1" = (stat_msg1 ? stat_msg1 : "-----"),
"line_2" = (stat_msg2 ? stat_msg2 : "-----"),
"presets" = list(
list("name" = "blank", "label" = "Clear", "desc" = "Blank slate"),
list("name" = "shuttle", "label" = "Shuttle ETA", "desc" = "Display how much time is left."),
list("name" = "message", "label" = "Message", "desc" = "A custom message.")
),
"alerts"=list(
list("alert" = "default", "label" = "Nanotrasen", "desc" = "Oh god."),
list("alert" = "redalert", "label" = "Red Alert", "desc" = "Nothing to do with communists."),
list("alert" = "lockdown", "label" = "Lockdown", "desc" = "Let everyone know they're on lockdown."),
list("alert" = "biohazard", "label" = "Biohazard", "desc" = "Great for virus outbreaks and parties."),
)
)
data["security_level"] = GLOB.security_level
data["str_security_level"] = capitalize(get_security_level())
data["levels"] = list(
list("id" = SEC_LEVEL_GREEN, "name" = "Green"),
list("id" = SEC_LEVEL_BLUE, "name" = "Blue"),
)
var/list/msg_data = list()
for(var/i = 1; i <= messagetext.len; i++)
msg_data.Add(list(list("title" = messagetitle[i], "body" = messagetext[i], "id" = i)))
data["messages"] = msg_data
if((data["is_ai"] && aicurrmsg) || (!data["is_ai"] && currmsg))
data["current_message"] = data["is_ai"] ? messagetext[aicurrmsg] : messagetext[currmsg]
data["current_message_title"] = data["is_ai"] ? messagetitle[aicurrmsg] : messagetitle[currmsg]
data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null
var/shuttle[0]
switch(SSshuttle.emergency.mode)
if(SHUTTLE_IDLE, SHUTTLE_RECALL)
shuttle["callStatus"] = 2 //#define
else
shuttle["callStatus"] = 1
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
var/timeleft = SSshuttle.emergency.timeLeft()
shuttle["eta"] = "[timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
data["shuttle"] = shuttle
return data
/datum/computer_file/program/comm/Topic(href, href_list)
if(..())
return 1
var/turf/T = get_turf(computer)
if(!is_secure_level(T.z))
to_chat(usr, "<span class='warning'>Unable to establish a connection: You're too far away from the station!</span>")
return 1
if(href_list["PRG_login"])
if(!ishuman(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
var/list/access = usr.get_access()
if(ACCESS_HEADS in access)
authenticated = COMM_AUTHENTICATION_MIN
if(ACCESS_CAPTAIN in access)
authenticated = COMM_AUTHENTICATION_MAX
var/mob/living/carbon/human/H = usr
var/obj/item/card/id = H.get_idcard(TRUE)
if(istype(id))
crew_announcement.announcer = GetNameAndAssignmentFromId(id)
SSnanoui.update_uis(src)
return 1
if(href_list["PRG_logout"])
authenticated = COMM_AUTHENTICATION_NONE
crew_announcement.announcer = ""
setMenuState(usr, COMM_SCREEN_MAIN)
SSnanoui.update_uis(src)
return 1
if(is_authenticated(usr))
switch(href_list["PRG_operation"])
if("main")
setMenuState(usr, COMM_SCREEN_MAIN)
if("changeseclevel")
setMenuState(usr,COMM_SCREEN_SECLEVEL)
if("newalertlevel")
if(isAI(usr) || isrobot(usr))
to_chat(usr, "<span class='warning'>Firewalls prevent you from changing the alert level.</span>")
return 1
else if(usr.can_admin_interact())
change_security_level(usr, text2num(href_list["level"]))
return 1
else if(!ishuman(usr))
to_chat(usr, "<span class='warning'>Security measures prevent you from changing the alert level.</span>")
return 1
var/mob/living/carbon/human/L = usr
var/obj/item/card = L.get_active_hand()
var/obj/item/card/id/I = (card && card.GetID()) || L.wear_id || L.wear_pda
if(istype(I, /obj/item/pda))
var/obj/item/pda/pda = I
I = pda.id
if(I && istype(I))
if(ACCESS_CAPTAIN in I.access)
change_security_level(usr, text2num(href_list["level"]))
else
to_chat(usr, "<span class='warning'>You are not authorized to do this.</span>")
setMenuState(usr, COMM_SCREEN_MAIN)
else
to_chat(usr, "<span class='warning'>You need to swipe your ID.</span>")
if("announce")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(message_cooldown)
to_chat(usr, "<span class='warning'>Please allow at least one minute to pass between announcements.</span>")
SSnanoui.update_uis(src)
return 1
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement")
if(!input || message_cooldown || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return 1
crew_announcement.Announce(input)
message_cooldown = 1
spawn(600)//One minute cooldown
message_cooldown = 0
if("callshuttle")
var/input = clean_input("Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","")
if(!input || ..() || !is_authenticated(usr))
SSnanoui.update_uis(src)
return 1
call_shuttle_proc(usr, input)
if(SSshuttle.emergency.timer)
post_status("shuttle")
setMenuState(usr, COMM_SCREEN_MAIN)
if("cancelshuttle")
if(isAI(usr) || isrobot(usr))
to_chat(usr, "<span class='warning'>Firewalls prevent you from recalling the shuttle.</span>")
SSnanoui.update_uis(src)
return 1
var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No")
if(response == "Yes")
cancel_call_proc(usr)
if(SSshuttle.emergency.timer)
post_status("shuttle")
setMenuState(usr, COMM_SCREEN_MAIN)
if("messagelist")
currmsg = 0
if(href_list["msgid"])
setCurrentMessage(usr, text2num(href_list["msgid"]))
setMenuState(usr,COMM_SCREEN_MESSAGES)
if("delmessage")
if(href_list["msgid"])
currmsg = text2num(href_list["msgid"])
var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No")
if(response == "Yes")
if(currmsg)
var/id = getCurrentMessage()
var/title = messagetitle[id]
var/text = messagetext[id]
messagetitle.Remove(title)
messagetext.Remove(text)
if(currmsg == id)
currmsg = 0
if(aicurrmsg == id)
aicurrmsg = 0
setMenuState(usr,COMM_SCREEN_MESSAGES)
if("status")
setMenuState(usr,COMM_SCREEN_STAT)
// Status display stuff
if("setstat")
display_type=href_list["statdisp"]
switch(display_type)
if("message")
post_status("message", stat_msg1, stat_msg2, usr)
if("alert")
post_status("alert", href_list["alert"], user = usr)
else
post_status(href_list["statdisp"], user = usr)
setMenuState(usr, COMM_SCREEN_STAT)
if("setmsg1")
stat_msg1 = clean_input("Line 1", "Enter Message Text", stat_msg1)
setMenuState(usr, COMM_SCREEN_STAT)
if("setmsg2")
stat_msg2 = clean_input("Line 2", "Enter Message Text", stat_msg2)
setMenuState(usr, COMM_SCREEN_STAT)
if("nukerequest")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(centcomm_message_cooldown)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
SSnanoui.update_uis(src)
return 1
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return 1
Nuke_request(input, usr)
to_chat(usr, "<span class='notice'>Request sent.</span>")
log_game("[key_name(usr)] has requested the nuclear codes from Centcomm")
GLOB.priority_announcement.Announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested",'sound/AI/commandreport.ogg')
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
if("MessageCentcomm")
if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)
if(centcomm_message_cooldown)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
SSnanoui.update_uis(src)
return 1
var/input = stripped_input(usr, "Please choose a message to transmit to Centcomm via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return 1
Centcomm_announce(input, usr)
to_chat(usr, "Message transmitted.")
log_game("[key_name(usr)] has made a Centcomm announcement: [input]")
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
// OMG SYNDICATE ...LETTERHEAD
if("MessageSyndicate")
if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (computer && computer.emagged))
if(centcomm_message_cooldown)
to_chat(usr, "Arrays recycling. Please stand by.")
SSnanoui.update_uis(src)
return 1
var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "")
if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX))
SSnanoui.update_uis(src)
return 1
Syndicate_announce(input, usr)
to_chat(usr, "Message transmitted.")
log_game("[key_name(usr)] has made a Syndicate announcement: [input]")
centcomm_message_cooldown = 1
spawn(6000)//10 minute cooldown
centcomm_message_cooldown = 0
setMenuState(usr,COMM_SCREEN_MAIN)
if("RestartNanoMob")
if(SSmob_hunt)
if(SSmob_hunt.manual_reboot())
var/loading_msg = pick("Respawning spawns", "Reticulating splines", "Flipping hat",
"Capturing all of them", "Fixing minor text issues", "Being the very best",
"Nerfing this", "Not communicating with playerbase", "Coding a ripoff in a 2D spaceman game")
to_chat(usr, "<span class='notice'>Restarting Nano-Mob Hunter GO! game server. [loading_msg]...</span>")
else
to_chat(usr, "<span class='warning'>Nano-Mob Hunter GO! game server reboot failed due to recent restart. Please wait before re-attempting.</span>")
else
to_chat(usr, "<span class='danger'>Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.</span>")
SSnanoui.update_uis(src)
return 1
-105
View File
@@ -1,105 +0,0 @@
/datum/nano_module/ert_manager
name = "ERT Manager"
var/ert_type = "Code Red"
var/commander_slots = 1
var/security_slots = 3
var/medical_slots = 3
var/engineering_slots = 3
var/janitor_slots = 0
var/paranormal_slots = 0
var/cyborg_slots = 0
var/autoclose = 0
/datum/nano_module/ert_manager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.admin_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(ui && autoclose)
ui.close()
return 0
if(!ui)
ui = new(user, src, ui_key, "ert_config.tmpl", "ERT Panel", 600, 600, state = state)
ui.open()
ui.set_auto_update(1)
/datum/nano_module/ert_manager/Topic(href, href_list)
if(..())
return 1
if(href_list["set_code"])
ert_type = href_list["set_code"]
if(href_list["set_com"])
commander_slots = text2num(href_list["set_com"])
if(href_list["set_sec"])
security_slots = text2num(href_list["set_sec"])
if(href_list["set_med"])
medical_slots = text2num(href_list["set_med"])
if(href_list["set_eng"])
engineering_slots = text2num(href_list["set_eng"])
if(href_list["set_jan"])
janitor_slots = text2num(href_list["set_jan"])
if(href_list["set_par"])
paranormal_slots = text2num(href_list["set_par"])
if(href_list["set_cyb"])
cyborg_slots = text2num(href_list["set_cyb"])
if(href_list["dispatch_ert"])
GLOB.ert_request_answered = TRUE
var/slots_list = list()
if(commander_slots > 0)
slots_list += "commander: [commander_slots]"
if(security_slots > 0)
slots_list += "security: [security_slots]"
if(medical_slots > 0)
slots_list += "medical: [medical_slots]"
if(engineering_slots > 0)
slots_list += "engineering: [engineering_slots]"
if(janitor_slots > 0)
slots_list += "janitor: [janitor_slots]"
if(paranormal_slots > 0)
slots_list += "paranormal: [paranormal_slots]"
if(cyborg_slots > 0)
slots_list += "cyborg: [cyborg_slots]"
var/slot_text = jointext(slots_list, ", ")
notify_ghosts("An ERT is being dispatched. Open positions: [slot_text]")
message_admins("[key_name_admin(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]", 1)
log_admin("[key_name(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]")
GLOB.event_announcement.Announce("Attention, [station_name()]. We are attempting to assemble an ERT. Standby.", "ERT Protocol Activated")
autoclose = 1
ui_interact(usr)
trigger_armed_response_team(convert_ert_string(ert_type), commander_slots, security_slots, medical_slots, engineering_slots, janitor_slots, paranormal_slots, cyborg_slots)
return 0
ui_interact(usr)
/proc/convert_ert_string(thestring)
switch(thestring)
if("Code Amber")
return new /datum/response_team/amber
if("Code Red")
return new /datum/response_team/red
if("Code Gamma")
return new /datum/response_team/gamma
/datum/nano_module/ert_manager/ui_data()
var/data[0]
data["alert_level"] = get_security_level()
data["ert_type"] = ert_type
data["com"] = commander_slots
data["sec"] = security_slots
data["med"] = medical_slots
data["eng"] = engineering_slots
data["jan"] = janitor_slots
data["par"] = paranormal_slots
data["cyb"] = cyborg_slots
return data
+155 -145
View File
@@ -12,24 +12,32 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
insert_anim = "faxsend"
pass_flags = PASSTABLE
var/fax_network = "Local Fax Network"
var/syndie_restricted = FALSE //is it a syndicate base fax restricted from contacting NT assets?
/// If true, prevents fax machine from sending messages to NT machines
var/syndie_restricted = FALSE
var/long_range_enabled = 0 // Can we send messages off the station?
/// Can we send messages off-station?
var/long_range_enabled = FALSE
req_one_access = list(ACCESS_LAWYER, ACCESS_HEADS, ACCESS_ARMORY)
use_power = IDLE_POWER_USE
idle_power_usage = 30
active_power_usage = 200
var/obj/item/card/id/scan = null // identification
/// ID card inserted into the machine, used to log in with
var/obj/item/card/id/scan = null
var/authenticated = 0
var/sendcooldown = 0 // to avoid spamming fax messages
/// Whether the machine is "logged in" or not
var/authenticated = FALSE
/// Next world.time at which this fax machine can send a message to CC/syndicate
var/sendcooldown = 0
/// After sending a message to CC/syndicate, cannot send another to them for this many deciseconds
var/cooldown_time = 1800
var/department = "Unknown" // our department
/// Our department, determines whether this machine gets faxes sent to a department
var/department = "Unknown"
var/destination = "Not Selected" // the department we're sending to
/// Target department to send outgoing faxes to
var/destination
/obj/machinery/photocopier/faxmachine/New()
..()
@@ -44,7 +52,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
/obj/machinery/photocopier/faxmachine/longrange
name = "long range fax machine"
fax_network = "Central Command Quantum Entanglement Network"
long_range_enabled = 1
long_range_enabled = TRUE
/obj/machinery/photocopier/faxmachine/longrange/syndie
name = "syndicate long range fax machine"
@@ -58,17 +66,17 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
GLOB.hidden_departments |= department
/obj/machinery/photocopier/faxmachine/attack_hand(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/photocopier/faxmachine/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/photocopier/faxmachine/attackby(obj/item/item, mob/user, params)
if(istype(item,/obj/item/card/id) && !scan)
scan(item)
else if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo) || istype(item, /obj/item/paper_bundle))
..()
SSnanoui.update_uis(src)
SStgui.update_uis(src)
else
return ..()
@@ -80,42 +88,6 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
else
to_chat(user, "<span class='warning'>You swipe the card through [src], but nothing happens.</span>")
/obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450)
ui.open()
/obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
var/is_authenticated = is_authenticated(user)
if(scan)
data["scan_name"] = scan.name
else
data["scan_name"] = "-----"
data["authenticated"] = is_authenticated
if(!is_authenticated)
data["network"] = "Disconnected"
else if(!emagged)
data["network"] = fax_network
else
data["network"] = "ERR*?*%!*"
if(copyitem)
data["paper"] = copyitem.name
data["paperinserted"] = 1
else
data["paper"] = "-----"
data["paperinserted"] = 0
data["destination"] = destination
data["cooldown"] = sendcooldown
if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
data["respectcooldown"] = 1
else
data["respectcooldown"] = 0
return data
/obj/machinery/photocopier/faxmachine/proc/is_authenticated(mob/user)
if(authenticated)
return TRUE
@@ -123,87 +95,134 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
return TRUE
return FALSE
/obj/machinery/photocopier/faxmachine/Topic(href, href_list)
if(..())
return 1
/obj/machinery/photocopier/faxmachine/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "FaxMachine", name, 540, 300, master_ui, state)
ui.open()
/obj/machinery/photocopier/faxmachine/tgui_data(mob/user)
var/list/data = list()
data["authenticated"] = is_authenticated(user)
data["scan_name"] = scan ? scan.name : FALSE
if(!data["authenticated"])
data["network"] = "Disconnected"
else if(!emagged)
data["network"] = fax_network
else
data["network"] = "ERR*?*%!*"
data["paper"] = copyitem ? copyitem.name : FALSE
data["paperinserted"] = copyitem ? TRUE : FALSE
data["destination"] = destination ? destination : FALSE
data["sendError"] = FALSE
if(stat & (BROKEN|NOPOWER))
data["sendError"] = "No Power"
else if(!data["authenticated"])
data["sendError"] = "Not Logged In"
else if(!data["paper"])
data["sendError"] = "Nothing Inserted"
else if(!data["destination"])
data["sendError"] = "Destination Not Set"
else if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
var/cooldown_seconds = cooldown_seconds()
if(cooldown_seconds)
data["sendError"] = "Re-aligning in [cooldown_seconds] seconds..."
return data
/obj/machinery/photocopier/faxmachine/tgui_act(action, params)
if(..())
return
var/is_authenticated = is_authenticated(usr)
if(href_list["send"])
if(copyitem && is_authenticated)
. = TRUE
switch(action)
if("scan") // insert/remove your ID card
scan()
if("auth") // log in/out
if(!is_authenticated && scan)
if(scan.registered_name in GLOB.fax_blacklist)
to_chat(usr, "<span class='warning'>Login rejected: individual is blacklisted from fax network.</span>")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
. = FALSE
else if(check_access(scan))
authenticated = TRUE
else // ID doesn't have access to this machine
to_chat(usr, "<span class='warning'>Login rejected: ID card does not have required access.</span>")
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
. = FALSE
else if(is_authenticated)
authenticated = FALSE
if("paper") // insert/eject paper/paperbundle/photo
if(copyitem)
copyitem.forceMove(get_turf(src))
if(ishuman(usr))
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(copyitem)
to_chat(usr, "<span class='notice'>You eject [copyitem] from [src].</span>")
copyitem = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
usr.drop_item()
copyitem = I
I.forceMove(src)
to_chat(usr, "<span class='notice'>You insert [I] into [src].</span>")
flick(insert_anim, src)
else
to_chat(usr, "<span class='warning'>[src] only accepts paper, paper bundles, and photos.</span>")
. = FALSE
if("rename") // rename the item that is currently in the fax machine
if(copyitem)
var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN))
if((copyitem && copyitem.loc == src && usr.stat == 0))
if(istype(copyitem, /obj/item/paper))
copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]"
copyitem.desc = "This is a paper titled '" + copyitem.name + "'."
else if(istype(copyitem, /obj/item/photo))
copyitem.name = "[(n_name ? text("[n_name]") : "photo")]"
else if(istype(copyitem, /obj/item/paper_bundle))
copyitem.name = "[(n_name ? text("[n_name]") : "paper")]"
else
. = FALSE
else
. = FALSE
else
. = FALSE
if("dept") // choose which department receives the fax
if(is_authenticated)
var/lastdestination = destination
var/list/combineddepartments = GLOB.alldepartments.Copy()
if(long_range_enabled)
combineddepartments += GLOB.admin_departments.Copy()
if(emagged)
combineddepartments += GLOB.hidden_admin_departments.Copy()
combineddepartments += GLOB.hidden_departments.Copy()
if(syndie_restricted)
combineddepartments = GLOB.hidden_admin_departments.Copy()
combineddepartments += GLOB.hidden_departments.Copy()
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.emagged)//we can contact emagged faxes on the station
combineddepartments |= F.department
destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments
if(!destination)
destination = lastdestination
if("send") // actually send the fax
if(!copyitem || !is_authenticated || !destination)
return
if(stat & (BROKEN|NOPOWER))
return
if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments))
var/cooldown_seconds = cooldown_seconds()
if(cooldown_seconds > 0)
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
to_chat(usr, "<span class='warning'>[src] is not ready for another [cooldown_seconds] seconds.</span>")
return
send_admin_fax(usr, destination)
sendcooldown = world.time + cooldown_time
else
sendfax(destination, usr)
if(sendcooldown)
spawn(sendcooldown) // cooldown time
sendcooldown = 0
SSnanoui.update_uis(src)
if(href_list["paper"])
if(copyitem)
copyitem.forceMove(get_turf(src))
if(ishuman(usr))
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(copyitem)
to_chat(usr, "<span class='notice'>You eject \the [copyitem] from \the [src].</span>")
copyitem = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle))
usr.drop_item()
copyitem = I
I.forceMove(src)
to_chat(usr, "<span class='notice'>You insert \the [I] into \the [src].</span>")
flick(insert_anim, src)
if(href_list["scan"])
scan()
if(href_list["dept"])
if(is_authenticated)
var/lastdestination = destination
var/list/combineddepartments = GLOB.alldepartments.Copy()
if(long_range_enabled)
combineddepartments += GLOB.admin_departments.Copy()
if(emagged)
combineddepartments += GLOB.hidden_admin_departments.Copy()
combineddepartments += GLOB.hidden_departments.Copy()
if(syndie_restricted)
combineddepartments = GLOB.hidden_admin_departments.Copy()
combineddepartments += GLOB.hidden_departments.Copy()
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.emagged)//we can contact emagged faxes on the station
combineddepartments |= F.department
destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments
if(!destination)
destination = lastdestination
if(href_list["auth"])
if(!is_authenticated && scan)
if(scan.registered_name in GLOB.fax_blacklist)
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
else if(check_access(scan))
authenticated = 1
else if(is_authenticated)
authenticated = 0
if(href_list["rename"])
if(copyitem)
var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN))
if((copyitem && copyitem.loc == src && usr.stat == 0))
if(istype(copyitem, /obj/item/paper))
copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]"
copyitem.desc = "This is a paper titled '" + copyitem.name + "'."
else if(istype(copyitem, /obj/item/photo))
copyitem.name = "[(n_name ? text("[n_name]") : "photo")]"
else if(istype(copyitem, /obj/item/paper_bundle))
copyitem.name = "[(n_name ? text("[n_name]") : "paper")]"
SSnanoui.update_uis(src)
if(.)
add_fingerprint(usr)
/obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/card/id/card = null)
if(scan) // Card is in machine
@@ -226,7 +245,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
usr.drop_item()
card.forceMove(src)
scan = card
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/photocopier/faxmachine/verb/eject_id()
set category = null
@@ -237,25 +256,20 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
return
if(scan)
to_chat(usr, "You remove \the [scan] from \the [src].")
to_chat(usr, "You remove [scan] from [src].")
scan.forceMove(get_turf(src))
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(scan)
scan = null
else
to_chat(usr, "There is nothing to remove from \the [src].")
to_chat(usr, "There is nothing to remove from [src].")
/obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination,var/mob/sender)
if(stat & (BROKEN|NOPOWER))
return
use_power(200)
use_power(active_power_usage)
var/success = 0
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.department == destination)
success = F.receivefax(copyitem)
if(success)
var/datum/fax/F = new /datum/fax()
F.name = copyitem.name
@@ -272,10 +286,10 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
/obj/machinery/photocopier/faxmachine/proc/receivefax(var/obj/item/incoming)
if(stat & (BROKEN|NOPOWER))
return 0
return FALSE
if(department == "Unknown")
return 0 //You can't send faxes to "Unknown"
return FALSE //You can't send faxes to "Unknown"
flick("faxreceive", src)
@@ -291,19 +305,13 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
else if(istype(incoming, /obj/item/paper_bundle))
bundlecopy(incoming)
else
return 0
return FALSE
use_power(active_power_usage)
return 1
return TRUE
/obj/machinery/photocopier/faxmachine/proc/send_admin_fax(var/mob/sender, var/destination)
if(stat & (BROKEN|NOPOWER))
return
if(sendcooldown)
return
use_power(200)
use_power(active_power_usage)
if(!(istype(copyitem, /obj/item/paper) || istype(copyitem, /obj/item/paper_bundle) || istype(copyitem, /obj/item/photo)))
visible_message("[src] beeps, \"Error transmitting message.\"")
@@ -327,10 +335,12 @@ GLOBAL_LIST_EMPTY(fax_blacklist)
for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes)
if(F.department == destination)
F.receivefax(copyitem)
sendcooldown = cooldown_time
spawn(50)
visible_message("[src] beeps, \"Message transmitted successfully.\"")
visible_message("[src] beeps, \"Message transmitted successfully.\"")
/obj/machinery/photocopier/faxmachine/proc/cooldown_seconds()
if(sendcooldown < world.time)
return 0
return round((sendcooldown - world.time) / 10)
/obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/faxtype, var/obj/item/sent, font_colour="#9A04D1")
var/msg = "<span class='boldnotice'><font color='[font_colour]'>[faxname]: </font> [key_name_admin(sender)] | REPLY: (<A HREF='?_src_=holder;[faxname == "SYNDICATE FAX" ? "SyndicateReply" : "CentcommReply"]=[sender.UID()]'>RADIO</A>) (<a href='?_src_=holder;AdminFaxCreate=\ref[sender];originfax=\ref[src];faxtype=[faxtype];replyto=\ref[sent]'>FAX</a>) ([ADMIN_SM(sender,"SM")]) | REJECT: (<A HREF='?_src_=holder;FaxReplyTemplate=[sender.UID()];originfax=\ref[src]'>TEMPLATE</A>) ([ADMIN_BSA(sender,"BSA")]) (<A HREF='?_src_=holder;EvilFax=[sender.UID()];originfax=\ref[src]'>EVILFAX</A>) </span>: Receiving '[sent.name]' via secure connection... <a href='?_src_=holder;AdminFaxView=\ref[sent]'>view message</a>"
+76 -72
View File
@@ -227,8 +227,8 @@
if(terminal)
terminal.master = null
terminal = null
return 1
return 0
return TRUE
return FALSE
/obj/machinery/power/smes/proc/make_terminal(user, tempDir, tempLoc)
// create a terminal object at the same position as original turf loc
@@ -339,89 +339,91 @@
/obj/machinery/power/smes/attack_ai(mob/user)
add_hiddenprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/power/smes/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/power/smes/attack_hand(mob/user)
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/obj/machinery/power/smes/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 & BROKEN)
return
// update the ui if it exists, returns null if no ui is passed/found
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)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "smes.tmpl", "SMES Power Storage Unit", 540, 380)
// open the new ui window
ui = new(user, src, ui_key, "Smes", name, 340, 350, master_ui, state)
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/power/smes/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["nameTag"] = name_tag
data["storedCapacity"] = round(100.0*charge/capacity, 0.1)
data["charging"] = inputting
data["chargeMode"] = input_attempt
data["chargeLevel"] = input_level
data["chargeMax"] = input_level_max
data["outputOnline"] = output_attempt
data["outputLevel"] = output_level
data["outputMax"] = output_level_max
data["outputLoad"] = round(output_used)
if(outputting)
data["outputting"] = 2 // smes is outputting
else if(!outputting && output_attempt)
data["outputting"] = 1 // smes is online but not outputting because it's charge level is too low
else
data["outputting"] = 0 // smes is not outputting
/obj/machinery/power/smes/tgui_data(mob/user)
var/list/data = list(
"capacity" = capacity,
"capacityPercent" = round(100*charge/capacity, 0.1),
"charge" = charge,
"inputAttempt" = input_attempt,
"inputting" = inputting,
"inputLevel" = input_level,
"inputLevel_text" = DisplayPower(input_level),
"inputLevelMax" = input_level_max,
"inputAvailable" = input_available,
"outputAttempt" = output_attempt,
"outputting" = outputting,
"outputLevel" = output_level,
"outputLevel_text" = DisplayPower(output_level),
"outputLevelMax" = output_level_max,
"outputUsed" = round(output_used),
)
return data
/obj/machinery/power/smes/Topic(href, href_list)
/obj/machinery/power/smes/tgui_act(action, params)
if(..())
return 1
return
. = TRUE
switch(action)
if("tryinput")
inputting(!input_attempt)
update_icon()
if("tryoutput")
outputting(!output_attempt)
update_icon()
if("input")
var/target = params["target"]
var/adjust = text2num(params["adjust"])
if(target == "min")
target = 0
else if(target == "max")
target = input_level_max
else if(adjust)
target = input_level + adjust
else if(text2num(target) != null)
target = text2num(target)
else
. = FALSE
if(.)
input_level = clamp(target, 0, input_level_max)
if("output")
var/target = params["target"]
var/adjust = text2num(params["adjust"])
if(target == "min")
target = 0
else if(target == "max")
target = output_level_max
else if(adjust)
target = output_level + adjust
else if(text2num(target) != null)
target = text2num(target)
else
. = FALSE
if(.)
output_level = clamp(target, 0, output_level_max)
else
. = FALSE
if(.)
log_smes(usr)
if( href_list["cmode"] )
inputting(!input_attempt)
update_icon()
else if( href_list["online"] )
outputting(!output_attempt)
update_icon()
else if( href_list["input"] )
switch( href_list["input"] )
if("min")
input_level = 0
if("max")
input_level = input_level_max
if("set")
input_level = input(usr, "Enter new input level (0-[input_level_max])", "SMES Input Power Control", input_level) as num
input_level = max(0, min(input_level_max, input_level)) // clamp to range
else if( href_list["output"] )
switch( href_list["output"] )
if("min")
output_level = 0
if("max")
output_level = output_level_max
if("set")
output_level = input(usr, "Enter new output level (0-[output_level_max])", "SMES Output Power Control", output_level) as num
output_level = max(0, min(output_level_max, output_level)) // clamp to range
investigate_log("input/output; [input_level>output_level?"<font color='green'>":"<font color='red'>"][input_level]/[output_level]</font> | Output-mode: [output_attempt?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [input_attempt?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [usr.key]","singulo")
return 1
/obj/machinery/power/smes/proc/log_smes(mob/user)
investigate_log("input/output; [input_level>output_level?"<font color='green'>":"<font color='red'>"][input_level]/[output_level]</font> | Charge: [charge] | Output-mode: [output_attempt?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [input_attempt?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [user ? key_name(user) : "outside forces"]", "singulo")
/obj/machinery/power/smes/proc/ion_act()
if(is_station_level(src.z))
@@ -448,6 +450,7 @@
smoke.attach(src)
smoke.start()
/obj/machinery/power/smes/proc/inputting(var/do_input)
input_attempt = do_input
if(!input_attempt)
@@ -459,14 +462,15 @@
outputting = 0
/obj/machinery/power/smes/emp_act(severity)
inputting(rand(0,1))
outputting(rand(0,1))
inputting(rand(0, 1))
outputting(rand(0, 1))
output_level = rand(0, output_level_max)
input_level = rand(0, input_level_max)
charge -= 1e6/severity
if(charge < 0)
charge = 0
update_icon()
log_smes()
..()
/obj/machinery/power/smes/engineering
+74 -81
View File
@@ -254,13 +254,17 @@
// Solar Control Computer
//
#define TRACKER_OFF 0
#define TRACKER_TIMED 1
#define TRACKER_AUTO 2
/obj/machinery/power/solar_control
name = "solar panel control"
desc = "A controller for solar panel arrays."
icon = 'icons/obj/computer.dmi'
icon_state = "computer"
anchored = 1
density = 1
anchored = TRUE
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 250
max_integrity = 200
@@ -272,17 +276,17 @@
var/targetdir = 0 // target angle in manual tracking (since it updates every game minute)
var/gen = 0
var/lastgen = 0
var/track = 0 // 0= off 1=timed 2=auto (tracker)
var/track = TRACKER_OFF
var/trackrate = 600 // 300-900 seconds
var/nexttime = 0 // time for a panel to rotate of 1? in manual tracking
var/autostart = 0 // Automatically search for connected devices
var/autostart = FALSE // Automatically search for connected devices
var/obj/machinery/power/tracker/connected_tracker = null
var/list/connected_panels = list()
// Used for mapping in solar array which automatically starts itself (telecomms, for example)
/obj/machinery/power/solar_control/autostart
track = 2 // Auto tracking mode
autostart = 1 // Automatically start
track = TRACKER_AUTO
autostart = TRUE // Automatically search for connected devices
/obj/machinery/power/solar_control/Initialize()
SSsun.solars |= src
@@ -294,7 +298,7 @@
set_panels(cdir)
if(autostart)
search_for_connected()
if(connected_tracker && track == 2)
if(connected_tracker && track == TRACKER_AUTO)
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
@@ -334,15 +338,9 @@
if(stat & (NOPOWER | BROKEN))
return
switch(track)
if(1)
if(trackrate) //we're manual tracking. If we set a rotation speed...
cdir = targetdir //...the current direction is the targetted one (and rotates panels to it)
if(2) // auto-tracking
if(connected_tracker)
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
if(track == TRACKER_AUTO && connected_tracker) // auto-tracking
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
updateDialog()
/obj/machinery/power/solar_control/update_icon()
@@ -359,44 +357,73 @@
overlays += image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(cdir))
/obj/machinery/power/solar_control/attack_ai(mob/user as mob)
src.add_hiddenprint(user)
ui_interact(user)
add_hiddenprint(user)
tgui_interact(user)
/obj/machinery/power/solar_control/attack_ghost(mob/user as mob)
ui_interact(user)
tgui_interact(user)
/obj/machinery/power/solar_control/attack_hand(mob/user)
if(..(user))
return 1
return TRUE
if(stat & BROKEN)
return
tgui_interact(user)
ui_interact(user)
/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/power/solar_control/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "solar_control.tmpl", name, 490, 420)
ui = new(user, src, ui_key, "SolarControl", name, 490, 300)
ui.open()
ui.set_auto_update(1)
/obj/machinery/power/solar_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["generated"] = round(lastgen)
data["angle"] = cdir
data["direction"] = angle2text(cdir)
data["tracking_state"] = track
data["tracking_rate"] = trackrate
data["rotating_way"] = (trackrate<0 ? "CCW" : "CW")
/obj/machinery/power/solar_control/tgui_data(mob/user)
var/list/data = list()
data["generated"] = round(lastgen) //generated power by all connected panels
data["generated_ratio"] = data["generated"] / round(max(connected_panels.len, 1) * SOLARGENRATE) //power generation ratio. Used for the power bar
data["direction"] = angle2text(cdir) //current orientation of the panels
data["cdir"] = cdir //current orientation of the of the panels in degrees
data["tracking_state"] = track //tracker status: TRACKER_OFF, TRACKER_TIMED, TRACKER_AUTO
data["tracking_rate"] = trackrate //rotation speed of tracker in degrees/h
data["rotating_direction"] = (trackrate < 0 ? "Counter clockwise" : "Clockwise") //direction of tracker
data["connected_panels"] = connected_panels.len
data["connected_tracker"] = (connected_tracker ? 1 : 0)
data["connected_tracker"] = (connected_tracker ? TRUE : FALSE)
return data
/obj/machinery/power/solar_control/tgui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("cdir") //change panel orientation
var/newAngle = text2num(params["cdir"])
if(!isnull(newAngle)) //0 is ok
cdir = clamp(newAngle, 0, 359)
targetdir = cdir
set_panels(cdir)
if("tdir") //change tracker rotation
var/newTrackrate = text2num(params["tdir"])
if(!newTrackrate)
newTrackrate = 1
trackrate = clamp(newTrackrate, -7200, 7200)
nexttime = world.time + 36000 / abs(trackrate)
if("track") //change tracker status
track = text2num(params["track"])
if(track == TRACKER_AUTO)
if(connected_tracker)
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
else if(track == TRACKER_TIMED)
targetdir = cdir
if(trackrate)
nexttime = world.time + 36000 / abs(trackrate)
set_panels(targetdir)
if("refresh")
search_for_connected()
if(connected_tracker && track == TRACKER_AUTO)
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
/obj/machinery/power/solar_control/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/screwdriver))
playsound(src.loc, I.usesound, 50, 1)
@@ -450,50 +477,16 @@
if(stat & (NOPOWER | BROKEN))
return
if(connected_tracker) //NOTE : handled here so that we don't add trackers to the processing list
if(connected_tracker.powernet != powernet)
connected_tracker.unset_control()
if(connected_tracker && connected_tracker.powernet != powernet) //NOTE : handled here so that we don't add trackers to the processing list
connected_tracker.unset_control()
if(track==1 && trackrate) //manual tracking and set a rotation speed
if(nexttime <= world.time) //every time we need to increase/decrease the angle by 1?...
targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it
nexttime += 36000/abs(trackrate) //reset the counter for the next 1?
/obj/machinery/power/solar_control/Topic(href, href_list)
if(..())
return
if(href_list["rate_control"])
if(href_list["cdir"])
src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360)
src.targetdir = src.cdir
if(track == 2) //manual update, so losing auto-tracking
track = 0
spawn(1)
set_panels(cdir)
if(href_list["tdir"])
src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"]))
if(src.trackrate) nexttime = world.time + 36000/abs(trackrate)
if(href_list["track"])
track = text2num(href_list["track"])
if(track == 2)
if(connected_tracker)
connected_tracker.set_angle(SSsun.angle)
set_panels(cdir)
else if(track == 1) //begin manual tracking
src.targetdir = src.cdir
if(src.trackrate) nexttime = world.time + 36000/abs(trackrate)
set_panels(targetdir)
if(href_list["search_connected"])
search_for_connected()
if(connected_tracker && track == 2)
connected_tracker.set_angle(SSsun.angle)
//manual tracking and set a rotation speed
if(track == TRACKER_TIMED && trackrate && nexttime <= world.time) //every time we need to increase/decrease the angle by 1?...
targetdir = (targetdir + trackrate / abs(trackrate) + 360) % 360 //... do it
nexttime += 36000 / abs(trackrate) //reset the counter for the next 1?
cdir = targetdir
set_panels(cdir)
return
//rotates the panel to the passed angle
/obj/machinery/power/solar_control/proc/set_panels(var/cdir)
+4 -2
View File
@@ -97,6 +97,7 @@
var/ammo_type = /obj/item/ammo_casing
var/max_ammo = 7
var/multiple_sprites = 0
var/icon_prefix // boxes with multiple sprites use this as their base
var/caliber
var/multiload = 1
var/list/initial_mats //For calculating refund values.
@@ -192,11 +193,12 @@
update_icon()
/obj/item/ammo_box/update_icon()
var/icon_base = initial(icon_prefix) ? initial(icon_prefix) : initial(icon_state)
switch(multiple_sprites)
if(1)
icon_state = "[initial(icon_state)]-[stored_ammo.len]"
icon_state = "[icon_base]-[stored_ammo.len]"
if(2)
icon_state = "[initial(icon_state)]-[stored_ammo.len ? "[max_ammo]" : "0"]"
icon_state = "[icon_base]-[stored_ammo.len ? "[max_ammo]" : "0"]"
desc = "[initial(desc)] There are [stored_ammo.len] shell\s left!"
/obj/item/ammo_box/proc/update_mat_value()
+5 -2
View File
@@ -1,10 +1,11 @@
/obj/item/ammo_box/a357
name = "speed loader (.357)"
desc = "Designed to quickly reload revolvers."
icon_state = "357"
ammo_type = /obj/item/ammo_casing/a357
max_ammo = 7
multiple_sprites = 1
icon_state = "357-7" // DEFAULT icon, composed of prefix + "-" + max_ammo for multiple_sprites == 1 boxes
multiple_sprites = 1 // see: /obj/item/ammo_box/update_icon()
icon_prefix = "357" // icon prefix, used in above formula to generate dynamic icons
/obj/item/ammo_box/c38
name = "speed loader (.38)"
@@ -12,7 +13,9 @@
icon_state = "38"
ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
icon_state = "38-6" // see previous entry for explanation of these vars
multiple_sprites = 1
icon_prefix = "38"
/obj/item/ammo_box/c9mm
name = "ammo box (9mm)"
@@ -24,6 +24,7 @@
var/list/hacked_reagents = list("toxin")
var/hack_message = "You disable the safety safeguards, enabling the \"Mad Scientist\" mode."
var/unhack_message = "You re-enable the safety safeguards, enabling the \"NT Standard\" mode."
var/is_drink = FALSE
/obj/machinery/chem_dispenser/get_cell()
return cell
@@ -120,7 +121,6 @@
var/usedpower = cell.give(recharge_amount)
if(usedpower)
use_power(15 * recharge_amount)
SSnanoui.update_uis(src) // update all UIs attached to src
recharge_counter = 0
return
recharge_counter++
@@ -131,7 +131,6 @@
else
spawn(rand(0, 15))
stat |= NOPOWER
SSnanoui.update_uis(src) // update all UIs attached to src
/obj/machinery/chem_dispenser/ex_act(severity)
if(severity < 3)
@@ -145,19 +144,17 @@
beaker = null
overlays.Cut()
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
/obj/machinery/chem_dispenser/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)
// update the ui if it exists, returns null if no ui is passed/found
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)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 390, 655)
// open the new ui window
ui = new(user, src, ui_key, "ChemDispenser", ui_title, 390, 655)
ui.open()
/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/chem_dispenser/tgui_data(mob/user)
var/data[0]
data["glass"] = is_drink
data["amount"] = amount
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
data["maxEnergy"] = cell.maxcharge * powerefficiency
@@ -187,63 +184,59 @@
return data
/obj/machinery/chem_dispenser/Topic(href, href_list)
/obj/machinery/chem_dispenser/tgui_act(actions, params)
if(..())
return TRUE
return
if(stat & (NOPOWER|BROKEN))
return
if(href_list["amount"])
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
if(amount < 0) // Since the user can actually type the commands himself, some sanity checking
amount = 0
if(amount > 100)
amount = 100
if(href_list["dispense"])
if(!is_operational() || QDELETED(cell))
return
if(beaker && dispensable_reagents.Find(href_list["dispense"]))
. = TRUE
switch(actions)
if("amount")
amount = clamp(round(text2num(params["amount"]), 1), 0, 50) // round to nearest 1 and clamp to 0 - 50
if("dispense")
if(!is_operational() || QDELETED(cell))
return
if(!beaker || !dispensable_reagents.Find(params["reagent"]))
return
var/datum/reagents/R = beaker.reagents
var/free = R.maximum_volume - R.total_volume
var/actual = min(amount, (cell.charge * powerefficiency) * 10, free)
if(!cell.use(actual / powerefficiency))
atom_say("Not enough energy to complete operation!")
return
R.add_reagent(href_list["dispense"], actual)
R.add_reagent(params["reagent"], actual)
overlays.Cut()
if(!icon_beaker)
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
if(href_list["remove"])
if(beaker)
if(href_list["removeamount"])
var/amount = text2num(href_list["removeamount"])
if(isnum(amount) && (amount > 0))
var/datum/reagents/R = beaker.reagents
var/id = href_list["remove"]
R.remove_reagent(id, amount)
else if(isnum(amount) && (amount == -1)) //Isolate instead
var/datum/reagents/R = beaker.reagents
var/id = href_list["remove"]
R.isolate_reagent(id)
if(href_list["ejectBeaker"])
if(beaker)
if("remove")
var/amount = text2num(params["amount"])
if(!beaker || !amount)
return
var/datum/reagents/R = beaker.reagents
var/id = params["reagent"]
if(amount > 0)
R.remove_reagent(id, amount)
else if(amount == -1) //Isolate instead
R.isolate_reagent(id)
if("ejectBeaker")
if(!beaker)
return
beaker.forceMove(loc)
if(Adjacent(usr) && !issilicon(usr))
usr.put_in_hands(beaker)
beaker = null
overlays.Cut()
else
return FALSE
add_fingerprint(usr)
return TRUE // update UIs attached to this object
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
if(exchange_parts(user, I))
SSnanoui.update_uis(src)
SStgui.update_uis(src)
return
if(isrobot(user))
@@ -263,9 +256,9 @@
beaker = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You set [I] on the machine.</span>")
SSnanoui.update_uis(src) // update all UIs attached to src
SStgui.update_uis(src) // update all UIs attached to src
if(!icon_beaker)
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
return
@@ -299,8 +292,7 @@
to_chat(user, unhack_message)
dispensable_reagents -= hacked_reagents
hackedcheck = FALSE
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/chem_dispenser/screwdriver_act(mob/user, obj/item/I)
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", "[initial(icon_state)]", I))
@@ -321,14 +313,14 @@
return attack_hand(user)
/obj/machinery/chem_dispenser/attack_ghost(mob/user)
if(user.can_admin_interact())
return attack_hand(user)
if(stat & BROKEN)
return
tgui_interact(user)
/obj/machinery/chem_dispenser/attack_hand(mob/user)
if(stat & BROKEN)
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/chem_dispenser/soda
icon_state = "soda_dispenser"
@@ -342,6 +334,7 @@
hacked_reagents = list("thirteenloko")
hack_message = "You change the mode from 'McNano' to 'Pizza King'."
unhack_message = "You change the mode from 'Pizza King' to 'McNano'."
is_drink = TRUE
/obj/machinery/chem_dispenser/soda/New()
..()
@@ -377,6 +370,7 @@
hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
hack_message = "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
unhack_message = "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
is_drink = TRUE
/obj/machinery/chem_dispenser/beer/New()
..()
@@ -1,15 +1,19 @@
/obj/machinery/chem_heater
name = "chemical heater"
density = 1
anchored = 1
density = TRUE
anchored = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "mixer0b"
use_power = IDLE_POWER_USE
idle_power_usage = 40
resistance_flags = FIRE_PROOF | ACID_PROOF
resistance_flags = FIRE_PROOF|ACID_PROOF
var/obj/item/reagent_containers/beaker = null
var/desired_temp = T0C
var/on = FALSE
/// Whether this should auto-eject the beaker once done heating/cooling.
var/auto_eject = FALSE
/// The higher this number, the faster reagents will heat/cool.
var/speed_increase = 0
/obj/machinery/chem_heater/New()
..()
@@ -19,35 +23,36 @@
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
/obj/machinery/chem_heater/RefreshParts()
speed_increase = initial(speed_increase)
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
speed_increase += 5 * (M.rating - 1)
/obj/machinery/chem_heater/process()
..()
if(stat & NOPOWER)
if(stat & (NOPOWER|BROKEN))
return
var/state_change = FALSE
if(on)
if(beaker)
if(!beaker.reagents.total_volume)
on = FALSE
SSnanoui.update_uis(src)
return
beaker.reagents.temperature_reagents(desired_temp)
beaker.reagents.temperature_reagents(desired_temp)
if(abs(beaker.reagents.chem_temp - desired_temp) <= 3)
beaker.reagents.temperature_reagents(desired_temp, max(1, 35 - speed_increase))
if(round(beaker.reagents.chem_temp) == round(desired_temp))
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
on = FALSE
state_change = TRUE
if(state_change)
SSnanoui.update_uis(src)
if(auto_eject)
eject_beaker()
/obj/machinery/chem_heater/proc/eject_beaker(mob/user)
if(beaker)
beaker.forceMove(get_turf(src))
if(Adjacent(user) && !issilicon(user))
if(user && Adjacent(user) && !issilicon(user))
user.put_in_hands(beaker)
beaker = null
icon_state = "mixer0b"
on = FALSE
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/obj/machinery/chem_heater/power_change()
if(powered())
@@ -55,7 +60,6 @@
else
spawn(rand(0, 15))
stat |= NOPOWER
SSnanoui.update_uis(src)
/obj/machinery/chem_heater/attackby(obj/item/I, mob/user)
if(isrobot(user))
@@ -71,7 +75,7 @@
I.forceMove(src)
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
icon_state = "mixer1b"
SSnanoui.update_uis(src)
SStgui.update_uis(src)
return
if(exchange_parts(user, I))
@@ -95,62 +99,62 @@
default_deconstruction_crowbar(user, I)
/obj/machinery/chem_heater/attack_hand(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/chem_heater/attack_ghost(mob/user)
if(user.can_admin_interact())
return attack_hand(user)
tgui_interact(user)
/obj/machinery/chem_heater/attack_ai(mob/user)
add_hiddenprint(user)
return attack_hand(user)
/obj/machinery/chem_heater/Topic(href, href_list)
/obj/machinery/chem_heater/tgui_act(action, params)
if(..())
return FALSE
return
if(stat & (NOPOWER|BROKEN))
return
if(href_list["toggle_on"])
if(!beaker.reagents.total_volume)
return FALSE
on = !on
. = 1
if(href_list["adjust_temperature"])
var/val = href_list["adjust_temperature"]
if(isnum(val))
desired_temp = clamp(desired_temp+val, 0, 1000)
else if(val == "input")
var/target = input("Please input the target temperature", name) as num
desired_temp = clamp(target, 0, 1000)
. = TRUE
switch(action)
if("toggle_on")
on = !on
if("adjust_temperature")
desired_temp = clamp(text2num(params["target"]), 0, 1000)
if("eject_beaker")
eject_beaker(usr)
. = FALSE
if("toggle_autoeject")
auto_eject = !auto_eject
else
return FALSE
. = 1
add_fingerprint(usr)
if(href_list["eject_beaker"])
eject_beaker(usr)
. = 0 //updated in eject_beaker() already
/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null)
/obj/machinery/chem_heater/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)
if(user.stat || user.restrained())
return
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
ui = new(user, src, ui_key, "ChemHeater", "Chemical Heater", 350, 270, master_ui, state)
ui.open()
/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/chem_heater/tgui_data(mob/user)
var/data[0]
var/cur_temp = beaker ? beaker.reagents.chem_temp : null
data["targetTemp"] = desired_temp
data["targetTempReached"] = FALSE
data["autoEject"] = auto_eject
data["isActive"] = on
data["isBeakerLoaded"] = beaker ? 1 : 0
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
data["currentTemp"] = cur_temp
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
data["beakerMaxVolume"] = beaker ? beaker.volume : null
if(cur_temp)
data["targetTempReached"] = round(cur_temp) == round(desired_temp)
//copy-pasted from chem dispenser
var/beakerContents[0]
if(beaker)
@@ -1,3 +1,9 @@
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
#define MAX_UNITS_PER_PILL 100 // Max amount of units in a pill
#define MAX_UNITS_PER_PATCH 30 // Max amount of units in a patch
#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
/obj/machinery/chem_master
name = "\improper ChemMaster 3000"
density = TRUE
@@ -14,10 +20,12 @@
var/useramount = 30 // Last used amount
var/pillamount = 10
var/patchamount = 10
var/bottlesprite = "bottle"
var/pillsprite = "1"
var/bottlesprite = 1
var/pillsprite = 1
var/client/has_sprites = list()
var/printing = FALSE
var/static/list/pill_bottle_wrappers
var/static/list/bottle_styles
/obj/machinery/chem_master/New()
..()
@@ -94,7 +102,7 @@
beaker = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
update_icon()
else if(istype(I, /obj/item/storage/pill_bottle))
@@ -109,14 +117,10 @@
loaded_pill_bottle = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You add [I] into the dispenser slot!</span>")
SSnanoui.update_uis(src)
SStgui.update_uis(src)
else
return ..()
/obj/machinery/chem_master/crowbar_act(mob/user, obj/item/I)
if(!panel_open)
return
@@ -142,319 +146,127 @@
power_change()
return TRUE
/obj/machinery/chem_master/Topic(href, href_list)
/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
if(stat & (NOPOWER|BROKEN))
return
if(tgui_act_modal(action, params, ui, state))
return TRUE
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["ejectp"])
if(loaded_pill_bottle)
loaded_pill_bottle.forceMove(loc)
loaded_pill_bottle = null
else if(href_list["change_pillbottle"])
if(loaded_pill_bottle)
var/list/wrappers = list("Default wrapper", "Red wrapper", "Green wrapper", "Pale green wrapper", "Blue wrapper", "Light blue wrapper", "Teal wrapper", "Yellow wrapper", "Orange wrapper", "Pink wrapper", "Brown wrapper")
var/chosen = input(usr, "Select a pillbottle wrapper", "Pillbottle wrapper", wrappers[1]) as null|anything in wrappers
if(!chosen)
. = TRUE
switch(action)
if("toggle")
mode = !mode
if("ejectp")
if(loaded_pill_bottle)
loaded_pill_bottle.forceMove(loc)
loaded_pill_bottle = null
if("print")
if(printing || condi)
return
var/color
switch(chosen)
if("Default wrapper")
loaded_pill_bottle.cut_overlays()
return
if("Red wrapper")
color = COLOR_RED
if("Green wrapper")
color = COLOR_GREEN
if("Pink wrapper")
color = COLOR_PINK
if("Teal wrapper")
color = COLOR_TEAL
if("Blue wrapper")
color = COLOR_BLUE
if("Brown wrapper")
color = COLOR_MAROON
if("Light blue wrapper")
color = COLOR_CYAN_BLUE
if("Yellow wrapper")
color = COLOR_YELLOW
if("Pale green wrapper")
color = COLOR_PALE_BTL_GREEN
if("Orange wrapper")
color = COLOR_ORANGE
loaded_pill_bottle.wrapper_color = color
loaded_pill_bottle.apply_wrap()
else if(href_list["close"])
usr << browse(null, "window=chem_master")
onclose(usr, "chem_master")
usr.unset_machine()
return
if(href_list["print_p"])
if(!printing)
var/idx = text2num(params["idx"]) || 0
var/from_beaker = text2num(params["beaker"]) || FALSE
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
if(idx < 1 || idx > length(reagent_list))
return
var/datum/reagent/R = reagent_list[idx]
printing = TRUE
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
var/obj/item/paper/P = new /obj/item/paper(loc)
P.info = "<CENTER><B>Chemical Analysis</B></CENTER><BR>"
P.info = "<center><b>Chemical Analysis</b></center><br>"
P.info += "<b>Time of analysis:</b> [station_time_timestamp()]<br><br>"
P.info += "<b>Chemical name:</b> [href_list["name"]]<br>"
if(href_list["name"] == "Blood")
var/datum/reagents/R = beaker.reagents
var/datum/reagent/blood/G
for(var/datum/reagent/F in R.reagent_list)
if(F.name == href_list["name"])
G = F
break
var/B = G.data["blood_type"]
var/C = G.data["blood_DNA"]
P.info += "<b>Description:</b><br>Blood Type: [B]<br>DNA: [C]"
P.info += "<b>Chemical name:</b> [R.name]<br>"
if(istype(R, /datum/reagent/blood))
var/datum/reagent/blood/B = R
P.info += "<b>Description:</b> N/A<br><b>Blood Type:</b> [B.data["blood_type"]]<br><b>DNA:</b> [B.data["blood_DNA"]]"
else
P.info += "<b>Description:</b> [href_list["desc"]]"
P.info += "<b>Description:</b> [R.description]"
P.info += "<br><br><b>Notes:</b><br>"
P.name = "Chemical Analysis - [href_list["name"]]"
printing = FALSE
P.name = "Chemical Analysis - [R.name]"
spawn(50)
printing = FALSE
else
. = FALSE
if(beaker)
var/datum/reagents/R = beaker.reagents
if(href_list["analyze"])
var/dat = ""
if(!condi)
if(href_list["name"] == "Blood")
var/datum/reagent/blood/G
for(var/datum/reagent/F in R.reagent_list)
if(F.name == href_list["name"])
G = F
break
var/A = G.name
var/B = G.data["blood_type"]
var/C = G.data["blood_DNA"]
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[A]<BR><BR>Description:<BR>Blood Type: [B]<br>DNA: [C]"
else
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]"
dat += "<BR><BR><A href='?src=[UID()];print_p=1;desc=[href_list["desc"]];name=[href_list["name"]]'>(Print Analysis)</A><BR>"
dat += "<A href='?src=[UID()];main=1'>(Back)</A>"
if(. || !beaker)
return
. = TRUE
var/datum/reagents/R = beaker.reagents
switch(action)
if("add")
var/id = params["id"]
var/amount = text2num(params["amount"])
if(!id || !amount)
return
R.trans_id_to(src, id, amount)
if("remove")
var/id = params["id"]
var/amount = text2num(params["amount"])
if(!id || !amount)
return
if(mode)
reagents.trans_id_to(beaker, id, amount)
else
dat += "<TITLE>Condimaster 3000</TITLE>Condiment infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]<BR><BR><BR><A href='?src=[UID()];main=1'>(Back)</A>"
usr << browse(dat, "window=chem_master;size=575x500")
return
else if(href_list["add"])
if(href_list["amount"])
var/id = href_list["add"]
var/amount = text2num(href_list["amount"])
R.trans_id_to(src, id, amount)
else if(href_list["addcustom"])
var/id = href_list["addcustom"]
useramount = input("Select the amount to transfer.", 30, useramount) as num
useramount = isgoodnumber(useramount)
Topic(null, list("amount" = "[useramount]", "add" = "[id]"))
else if(href_list["remove"])
if(href_list["amount"])
var/id = href_list["remove"]
var/amount = text2num(href_list["amount"])
if(mode)
reagents.trans_id_to(beaker, id, amount)
else
reagents.remove_reagent(id, amount)
else if(href_list["removecustom"])
var/id = href_list["removecustom"]
useramount = input("Select the amount to transfer.", 30, useramount) as num
useramount = isgoodnumber(useramount)
Topic(null, list("amount" = "[useramount]", "remove" = "[id]"))
else if(href_list["toggle"])
mode = !mode
else if(href_list["main"])
attack_hand(usr)
return
else if(href_list["eject"])
if(beaker)
beaker.forceMove(get_turf(src))
if(Adjacent(usr) && !issilicon(usr))
usr.put_in_hands(beaker)
beaker = null
reagents.clear_reagents()
update_icon()
else if(href_list["createpill"] || href_list["createpill_multiple"])
if(!condi)
var/count = 1
if(href_list["createpill_multiple"])
count = input("Select the number of pills to make.", 10, pillamount) as num|null
if(count == null)
return
count = isgoodnumber(count)
if(count > 20)
count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
if(count <= 0)
return
var/amount_per_pill = reagents.total_volume / count
if(amount_per_pill > 100)
amount_per_pill = 100
var/name = clean_input("Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)")
if(!name)
return
name = reject_bad_text(name)
while(count--)
if(reagents.total_volume <= 0)
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
return
var/obj/item/reagent_containers/food/pill/P = new/obj/item/reagent_containers/food/pill(loc)
if(!name)
name = reagents.get_master_reagent_name()
P.name = "[name] pill"
P.pixel_x = rand(-7, 7) //random position
P.pixel_y = rand(-7, 7)
P.icon_state = "pill"+pillsprite
reagents.trans_to(P, amount_per_pill)
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle)
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
P.forceMove(loaded_pill_bottle)
updateUsrDialog()
else
var/name = clean_input("Name:", "Name your bag!", reagents.get_master_reagent_name())
if(!name)
return
name = reject_bad_text(name)
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(loc)
if(!name) name = reagents.get_master_reagent_name()
P.originalname = name
P.name = "[name] pack"
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P, 10)
else if(href_list["createpatch"] || href_list["createpatch_multiple"])
if(!condi)
var/count = 1
if(href_list["createpatch_multiple"])
count = input("Select the number of patches to make.", 10, patchamount) as num|null
if(count == null)
return
count = isgoodnumber(count)
if(!count || count <= 0)
return
if(count > 20)
count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
var/amount_per_patch = reagents.total_volume/count
if(amount_per_patch > 30)
amount_per_patch = 30
var/name = clean_input("Name:", "Name your patch!", "[reagents.get_master_reagent_name()] ([amount_per_patch]u)")
if(!name)
return
name = reject_bad_text(name)
var/is_medical_patch = chemical_safety_check(reagents)
while(count--)
var/obj/item/reagent_containers/food/pill/patch/P = new/obj/item/reagent_containers/food/pill/patch(loc)
if(!name) name = reagents.get_master_reagent_name()
P.name = "[name] patch"
P.pixel_x = rand(-7, 7) //random position
P.pixel_y = rand(-7, 7)
reagents.trans_to(P,amount_per_patch)
if(is_medical_patch)
P.instant_application = TRUE
P.icon_state = "bandaid_med"
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle/patch_pack)
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
P.forceMove(loaded_pill_bottle)
updateUsrDialog()
else if(href_list["createbottle"])
if(!condi)
var/name = clean_input("Name:", "Name your bottle!", reagents.get_master_reagent_name())
if(!name)
return
name = reject_bad_text(name)
var/obj/item/reagent_containers/glass/bottle/reagent/P = new/obj/item/reagent_containers/glass/bottle/reagent(loc)
if(!name)
name = reagents.get_master_reagent_name()
P.name = "[name] bottle"
P.pixel_x = rand(-7, 7) //random position
P.pixel_y = rand(-7, 7)
P.icon_state = bottlesprite
reagents.trans_to(P, 50)
else
var/obj/item/reagent_containers/food/condiment/P = new/obj/item/reagent_containers/food/condiment(loc)
reagents.trans_to(P, 50)
else if(href_list["change_pill"])
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
var/dat = "<table>"
var/j = 0
for(var/i = 1 to MAX_PILL_SPRITE)
j++
if(j == 1)
dat += "<tr>"
dat += "<td><a href=\"?src=[UID()]&pill_sprite=[i]\"><img src=\"pill[i].png\" /></a></td>"
if(j == 5)
dat += "</tr>"
j = 0
dat += "</table>"
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
return
else if(href_list["change_bottle"])
var/dat = "<table>"
var/j = 0
for(var/i in list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle"))
j++
if(j == 1)
dat += "<tr>"
dat += "<td><a href=\"?src=[UID()]&bottle_sprite=[i]\"><img src=\"[i].png\" /></a></td>"
if(j == 5)
dat += "</tr>"
j = 0
dat += "</table>"
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
return
else if(href_list["pill_sprite"])
pillsprite = href_list["pill_sprite"]
usr << browse(null, "window=chem_master_iconsel")
else if(href_list["bottle_sprite"])
bottlesprite = href_list["bottle_sprite"]
usr << browse(null, "window=chem_master_iconsel")
SSnanoui.update_uis(src)
reagents.remove_reagent(id, amount)
if("eject")
if(!beaker)
return
beaker.forceMove(get_turf(src))
if(Adjacent(usr) && !issilicon(usr))
usr.put_in_hands(beaker)
beaker = null
reagents.clear_reagents()
update_icon()
if("create_condi_bottle")
if(!condi || !reagents.total_volume)
return
var/obj/item/reagent_containers/food/condiment/P = new(loc)
reagents.trans_to(P, 50)
else
return FALSE
/obj/machinery/chem_master/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/chem_master/attack_ghost(mob/user)
if(user.can_admin_interact())
return attack_hand(user)
tgui_interact(user)
/obj/machinery/chem_master/attack_hand(mob/user)
if(..())
return TRUE
ui_interact(user)
tgui_interact(user)
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
/obj/machinery/chem_master/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)
var/datum/asset/chem_master/assets = get_asset_datum(/datum/asset/chem_master)
assets.send(user)
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, "chem_master.tmpl", name, 575, 500)
ui = new(user, src, ui_key, "ChemMaster", name, 575, 500)
ui.open()
/obj/machinery/chem_master/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
/obj/machinery/chem_master/tgui_data(mob/user)
var/data[0]
data["condi"] = condi
data["loaded_pill_bottle"] = (loaded_pill_bottle ? 1 : 0)
data["loaded_pill_bottle"] = loaded_pill_bottle ? TRUE : FALSE
if(loaded_pill_bottle)
data["loaded_pill_bottle_name"] = loaded_pill_bottle.name
data["loaded_pill_bottle_contents_len"] = loaded_pill_bottle.contents.len
data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.storage_slots
data["beaker"] = (beaker ? 1 : 0)
data["beaker"] = beaker ? TRUE : FALSE
if(beaker)
var/list/beaker_reagents_list = list()
data["beaker_reagents"] = beaker_reagents_list
@@ -464,13 +276,255 @@
data["buffer_reagents"] = buffer_reagents_list
for(var/datum/reagent/R in reagents.reagent_list)
buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
else
data["beaker_reagents"] = list()
data["buffer_reagents"] = list()
data["pillsprite"] = pillsprite
data["bottlesprite"] = bottlesprite
data["mode"] = mode
data["printing"] = printing
// Transfer modal information if there is one
data["modal"] = tgui_modal_data(src)
return data
/**
* Called in tgui_act() to process modal actions
*
* Arguments:
* * action - The action passed by tgui
* * params - The params passed by tgui
*/
/obj/machinery/chem_master/proc/tgui_act_modal(action, params, datum/tgui/ui, datum/tgui_state/state)
. = TRUE
var/id = params["id"] // The modal's ID
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
switch(tgui_modal_act(src, action, params))
if(TGUI_MODAL_OPEN)
switch(id)
if("analyze")
var/idx = text2num(arguments["idx"]) || 0
var/from_beaker = text2num(arguments["beaker"]) || FALSE
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
if(idx < 1 || idx > length(reagent_list))
return
var/datum/reagent/R = reagent_list[idx]
var/list/result = list("idx" = idx, "name" = R.name, "desc" = R.description)
if(!condi && istype(R, /datum/reagent/blood))
var/datum/reagent/blood/B = R
result["blood_type"] = B.data["blood_type"]
result["blood_dna"] = B.data["blood_DNA"]
arguments["analysis"] = result
tgui_modal_message(src, id, "", null, arguments)
if("change_pill_bottle_style")
if(!loaded_pill_bottle)
return
if(!pill_bottle_wrappers)
pill_bottle_wrappers = list(
"CLEAR" = "Default",
COLOR_RED = "Red",
COLOR_GREEN = "Green",
COLOR_PALE_BTL_GREEN = "Pale green",
COLOR_BLUE = "Blue",
COLOR_CYAN_BLUE = "Light blue",
COLOR_TEAL = "Teal",
COLOR_YELLOW = "Yellow",
COLOR_ORANGE = "Orange",
COLOR_PINK = "Pink",
COLOR_MAROON = "Brown"
)
var/current = pill_bottle_wrappers[loaded_pill_bottle.wrapper_color] || "Default"
tgui_modal_choice(src, id, "Please select a pill bottle wrapper:", null, arguments, current, pill_bottle_wrappers)
if("addcustom")
if(!beaker || !beaker.reagents.total_volume)
return
tgui_modal_input(src, id, "Please enter the amount to transfer to buffer:", null, arguments, useramount)
if("removecustom")
if(!reagents.total_volume)
return
tgui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount)
if("create_condi_pack")
if(!condi || !reagents.total_volume)
return
tgui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
if("create_pill")
if(condi || !reagents.total_volume)
return
var/num = round(text2num(arguments["num"] || 1))
if(!num)
return
arguments["num"] = num
var/amount_per_pill = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PILL)
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)"
var/pills_text = num == 1 ? "new pill" : "[num] new pills"
tgui_modal_input(src, id, "Please name your [pills_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
if("create_pill_multiple")
if(condi || !reagents.total_volume)
return
tgui_modal_input(src, id, "Please enter the amount of pills to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
if("change_pill_style")
var/list/choices = list()
for(var/i = 1 to MAX_PILL_SPRITE)
choices += "pill[i].png"
tgui_modal_bento(src, id, "Please select the new style for pills:", null, arguments, pillsprite, choices)
if("create_patch")
if(condi || !reagents.total_volume)
return
var/num = round(text2num(arguments["num"] || 1))
if(!num)
return
arguments["num"] = num
var/amount_per_patch = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PATCH)
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)"
var/patches_text = num == 1 ? "new patch" : "[num] new patches"
tgui_modal_input(src, id, "Please name your [patches_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
if("create_patch_multiple")
if(condi || !reagents.total_volume)
return
tgui_modal_input(src, id, "Please enter the amount of patches to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
if("create_bottle")
if(condi || !reagents.total_volume)
return
tgui_modal_input(src, id, "Please name your bottle:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
if("change_bottle_style")
if(!bottle_styles)
bottle_styles = list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle")
var/list/bottle_styles_png = list()
for(var/style in bottle_styles)
bottle_styles_png += "[style].png"
tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, bottle_styles_png)
else
return FALSE
if(TGUI_MODAL_ANSWER)
var/answer = params["answer"]
switch(id)
if("change_pill_bottle_style")
if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
return
var/color = "CLEAR"
for(var/col in pill_bottle_wrappers)
var/col_name = pill_bottle_wrappers[col]
if(col_name == answer)
color = col
break
if(length(color) && color != "CLEAR")
loaded_pill_bottle.wrapper_color = color
loaded_pill_bottle.apply_wrap()
else
loaded_pill_bottle.wrapper_color = null
loaded_pill_bottle.cut_overlays()
if("addcustom")
var/amount = isgoodnumber(text2num(answer))
if(!amount || !arguments["id"])
return
tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
if("removecustom")
var/amount = isgoodnumber(text2num(answer))
if(!amount || !arguments["id"])
return
tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
if("create_condi_pack")
if(!condi || !reagents.total_volume)
return
if(!length(answer))
answer = reagents.get_master_reagent_name()
var/obj/item/reagent_containers/food/condiment/pack/P = new(loc)
P.originalname = answer
P.name = "[answer] pack"
P.desc = "A small condiment pack. The label says it contains [answer]."
reagents.trans_to(P, 10)
if("create_pill")
if(condi || !reagents.total_volume)
return
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
if(!count)
return
if(!length(answer))
answer = reagents.get_master_reagent_name()
var/amount_per_pill = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL)
while(count--)
if(reagents.total_volume <= 0)
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
return
var/obj/item/reagent_containers/food/pill/P = new(loc)
P.name = "[answer] pill"
P.pixel_x = rand(-7, 7) // Random position
P.pixel_y = rand(-7, 7)
P.icon_state = "pill[pillsprite]"
reagents.trans_to(P, amount_per_pill)
// Load the pills in the bottle if there's one loaded
if(istype(loaded_pill_bottle) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
P.forceMove(loaded_pill_bottle)
if("create_pill_multiple")
if(condi || !reagents.total_volume)
return
tgui_act("modal_open", list("id" = "create_pill", "arguments" = list("num" = answer)), ui, state)
if("change_pill_style")
var/new_style = clamp(text2num(answer) || 0, 0, MAX_PILL_SPRITE)
if(!new_style)
return
pillsprite = new_style
if("create_patch")
if(condi || !reagents.total_volume)
return
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
if(!count)
return
if(!length(answer))
answer = reagents.get_master_reagent_name()
var/amount_per_patch = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH)
var/is_medical_patch = chemical_safety_check(reagents)
while(count--)
if(reagents.total_volume <= 0)
to_chat(usr, "<span class='notice'>Not enough reagents to create these patches!</span>")
return
var/obj/item/reagent_containers/food/pill/patch/P = new(loc)
P.name = "[answer] patch"
P.pixel_x = rand(-7, 7) // random position
P.pixel_y = rand(-7, 7)
reagents.trans_to(P, amount_per_patch)
if(is_medical_patch)
P.instant_application = TRUE
P.icon_state = "bandaid_med"
// Load the patches in the bottle if there's one loaded
if(istype(loaded_pill_bottle, /obj/item/storage/pill_bottle/patch_pack) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
P.forceMove(loaded_pill_bottle)
if("create_patch_multiple")
if(condi || !reagents.total_volume)
return
tgui_act("modal_open", list("id" = "create_patch", "arguments" = list("num" = answer)), ui, state)
if("create_bottle")
if(condi || !reagents.total_volume)
return
if(!length(answer))
answer = reagents.get_master_reagent_name()
var/obj/item/reagent_containers/glass/bottle/reagent/P = new(loc)
P.name = "[answer] bottle"
P.pixel_x = rand(-7, 7) // random position
P.pixel_y = rand(-7, 7)
P.icon_state = length(bottle_styles) && bottle_styles[bottlesprite] || "bottle"
reagents.trans_to(P, 50)
if("change_bottle_style")
if(!bottle_styles)
return
var/new_sprite = text2num(answer) || 1
if(new_sprite < 1 || new_sprite > length(bottle_styles))
return
bottlesprite = new_sprite
else
return FALSE
else
return FALSE
/obj/machinery/chem_master/proc/isgoodnumber(num)
if(isnum(num))
if(num > 200)
@@ -481,7 +535,7 @@
num = round(num)
return num
else
return 0
return FALSE
/obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
var/all_safe = TRUE
@@ -503,3 +557,9 @@
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
RefreshParts()
#undef MAX_PILL_SPRITE
#undef MAX_MULTI_AMOUNT
#undef MAX_UNITS_PER_PILL
#undef MAX_UNITS_PER_PATCH
#undef MAX_CUSTOM_NAME_LEN
@@ -68,6 +68,7 @@
eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src))
eyeobj.origin = src
eyeobj.visible_icon = 1
eyeobj.acceleration = FALSE
eyeobj.icon = 'icons/obj/abductor.dmi'
eyeobj.icon_state = "camera_target"
+4 -3
View File
@@ -33,8 +33,8 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
to_chat(usr, "<span class='warning'>Central Command has already dispatched an emergency response team!</span>")
return
var/datum/nano_module/ert_manager/E = new()
E.ui_interact(usr)
var/datum/tgui_module/ert_manager/E = new()
E.tgui_interact(usr)
/mob/dead/observer/proc/JoinResponseTeam()
@@ -209,7 +209,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
var/paranormal_outfit
var/borg_path = /mob/living/silicon/robot/ert
/datum/response_team/proc/setSlots(com=1, sec=3, med=3, eng=3, jan=0, par=0, cyb=0)
/datum/response_team/proc/setSlots(com=1, sec=4, med=0, eng=0, jan=0, par=0, cyb=0)
slots["Commander"] = com
slots["Security"] = sec
slots["Medic"] = med
@@ -318,3 +318,4 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE)
name = "centcomm bounced radio"
frequency = ERT_FREQ
icon_state = "radio"
freqlock = TRUE
@@ -6,9 +6,10 @@
name = "broken rejuvenation pod"
desc = "A small sleeper typically used to instantly restore minor wounds. This one seems broken, and its occupant is comatose."
mob_name = "a translocated vet"
flavour_text = "<span class='big bold'>What...?</span><b> Where are you? Where are the others? This is still the animal hospital - you should know, you've been an intern here for weeks - but \
description = "You are an intern working in an animal hospital that suddenly got transported to lavaland. Good luck."
flavour_text = "What...? Where are you? Where are the others? This is still the animal hospital - you should know, you've been an intern here for weeks - but \
everyone's gone. One of the cats scratched you just a few minutes ago. That's why you were in the pod - to heal the scratch. The scabs are still fresh; you see them right now. So where is \
everyone? Where did they go? What happened to the hospital? And is that <i>smoke</i> you smell? You need to find someone else. Maybe they can tell you what happened.</b>"
everyone? Where did they go? What happened to the hospital? And is that smoke you smell? You need to find someone else. Maybe they can tell you what happened."
assignedrole = "Translocated Vet"
allow_species_pick = TRUE
@@ -67,9 +67,10 @@
anchored = FALSE
move_resist = MOVE_FORCE_NORMAL
density = FALSE
flavour_text = "<span class='big bold'>You are an ash walker.</span><b> Your tribe worships <span class='danger'>the Necropolis</span>. The wastes are sacred ground, its monsters a blessed bounty. \
You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest. \
<br><i>You are free to attack miners and other outsiders. <font size=6>DO NOT</font> leave Lavaland without admin permission! <font size=6>DO NOT</font> attack the mining outpost without being provoked.</b></i>"
important_info = "Do not leave Lavaland without admin permission. Do not attack the mining outpost without being provoked."
description = "You are an ashwalker, a native inhabitant of Lavaland. Try to survive with nothing but spears and other tribal technology. Bring dead bodies back to your tendril to create more of your kind. You are free to attack miners and other outsiders."
flavour_text = "Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. \
You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest."
assignedrole = "Ash Walker"
/obj/effect/mob_spawn/human/ash_walker/special(mob/living/carbon/human/new_spawn)
@@ -10,7 +10,8 @@
random = TRUE
allow_species_pick = TRUE
mob_species = /datum/species/human
flavour_text = "<span class='big bold'>You've been stranded in this godless prison of a planet for longer than you can remember.</span><b> Each day you barely scrape by, and between the terrible \
description = "You are a single survivor stranded on lavaland in a makeshift shelter. Try to survive with barely any equipment. For when miner is just too boring."
flavour_text = "You've been stranded in this godless prison of a planet for longer than you can remember. Each day you barely scrape by, and between the terrible \
conditions of your makeshift shelter, the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \
the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you got here... "
assignedrole = "Hermit"
@@ -22,28 +23,28 @@
if(1)
flavour_text += "you were a [pick("arms dealer", "shipwright", "docking manager")]'s assistant on a small trading station several sectors from here. Raiders attacked, and there was \
only one pod left when you got to the escape bay. You took it and launched it alone, and the crowd of terrified faces crowding at the airlock door as your pod's engines burst to \
life and sent you to this hell are forever branded into your memory.</b>"
life and sent you to this hell are forever branded into your memory."
outfit.uniform = /obj/item/clothing/under/assistantformal
outfit.shoes = /obj/item/clothing/shoes/black
outfit.back = /obj/item/storage/backpack
if(2)
flavour_text += "you're an exile from the Tiger Cooperative. Their technological fanaticism drove you to question the power and beliefs of the Exolitics, and they saw you as a \
heretic and subjected you to hours of horrible torture. You were hours away from execution when a high-ranking friend of yours in the Cooperative managed to secure you a pod, \
scrambled its destination's coordinates, and launched it. You awoke from stasis when you landed and have been surviving - barely - ever since.</b>"
scrambled its destination's coordinates, and launched it. You awoke from stasis when you landed and have been surviving - barely - ever since."
outfit.uniform = /obj/item/clothing/under/color/orange
outfit.shoes = /obj/item/clothing/shoes/orange
outfit.back = /obj/item/storage/backpack
if(3)
flavour_text += "you were a doctor on one of Nanotrasen's space stations, but you left behind that damn corporation's tyranny and everything it stood for. From a metaphorical hell \
to a literal one, you find yourself nonetheless missing the recycled air and warm floors of what you left behind... but you'd still rather be here than there.</b>"
to a literal one, you find yourself nonetheless missing the recycled air and warm floors of what you left behind... but you'd still rather be here than there."
outfit.uniform = /obj/item/clothing/under/rank/medical
outfit.suit = /obj/item/clothing/suit/storage/labcoat
outfit.back = /obj/item/storage/backpack/medic
outfit.shoes = /obj/item/clothing/shoes/black
if(4)
flavour_text += "you were always joked about by your friends for \"not playing with a full deck\", as they so <i>kindly</i> put it. It seems that they were right when you, on a tour \
flavour_text += "you were always joked about by your friends for \"not playing with a full deck\", as they so kindly put it. It seems that they were right when you, on a tour \
at one of Nanotrasen's state-of-the-art research facilities, were in one of the escape pods alone and saw the red button. It was big and shiny, and it caught your eye. You pressed \
it, and after a terrifying and fast ride for days, you landed here. You've had time to wisen up since then, and you think that your old friends wouldn't be laughing now.</b>"
it, and after a terrifying and fast ride for days, you landed here. You've had time to wisen up since then, and you think that your old friends wouldn't be laughing now."
outfit.uniform = /obj/item/clothing/under/color/grey/glorf
outfit.shoes = /obj/item/clothing/shoes/black
outfit.back = /obj/item/storage/backpack
@@ -18,9 +18,10 @@
roundstart = FALSE
death = FALSE
mob_species = /datum/species/diona/pod
flavour_text = "<span class='big bold'>You are a sentient ecosystem,</span><b> an example of the mastery over life that your creators possessed. Your masters, benevolent as they were, created uncounted \
description = "You are a diona on Lavaland with access to a full botany setup. Perfect to mess around with plants in peace."
flavour_text = "You are a sentient ecosystem, an example of the mastery over life that your creators possessed. Your masters, benevolent as they were, created uncounted \
seed vaults and spread them across the universe to every planet they could chart. You are in one such seed vault. Your goal is to cultivate and spread life wherever it will go while waiting \
for contact from your creators. Estimated time of last contact: Deployment, 5x10^3 millennia ago.</b>"
for contact from your creators. Estimated time of last contact: Deployment, 5x10^3 millennia ago."
assignedrole = "Lifebringer"
/obj/effect/mob_spawn/human/seed_vault/special(mob/living/new_spawn)
@@ -28,8 +28,10 @@
death = FALSE
icon = 'icons/obj/cryogenic2.dmi'
icon_state = "sleeper_s"
flavour_text = "<span class='big bold'>You are a syndicate agent,</span><b> employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. <b>Continue your research as best you can, and try to keep a low profile. The base is rigged with explosives, do not abandon it or let it fall into enemy hands!</b> \
<br><i>You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. <font size=6>DO NOT</font> work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. <font size=6>DO NOT</font> leave your base without admin permission.</i>"
important_info = "Do not work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. Do not leave your base without admin permission."
description = "Experiment with deadly chems and viruses in peace or help any visiting Syndicate Agent."
flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. The base is rigged with explosives, do not abandon it or let it fall into enemy hands!\
It's been made clear to you that the Syndicate will make you regret it if you disappoint them."
outfit = /datum/outfit/lavaland_syndicate
assignedrole = "Lavaland Syndicate"
del_types = list() // Necessary to prevent del_types from removing radio!
@@ -59,13 +61,13 @@
/obj/effect/mob_spawn/human/lavaland_syndicate/comms
name = "Syndicate Comms Agent sleeper"
mob_name = "Syndicate Comms Agent"
flavour_text = "<span class='big bold'>You are a syndicate agent,</span><b> employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. <b>Monitor enemy activity as best you can, and try to keep a low profile. Do not abandon the base.</b> Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!</b> \
<br><i>You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. <font size=6>DO NOT</font> work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. <font size=6>DO NOT</font> leave your base without admin permission.</i>"
important_info = "Do not work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. Do not leave your base without admin permission. Do not reveal the existence of yourself to NT."
description = "Monitor comms and cameras and try to assist any agents on station while keeping your existence a secret."
flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Monitor enemy activity as best you can, and try to keep a low profile."
outfit = /datum/outfit/lavaland_syndicate/comms
/obj/effect/mob_spawn/human/lavaland_syndicate/comms/space
flavour_text = "<span class='big bold'>You are a syndicate agent,</span><b> assigned to a small listening post station situated near your hated enemy's top secret research facility: Space Station 13. <b>Monitor enemy activity as best you can, and try to keep a low profile. Do not abandon the base.</b> Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!</b> \
<br><i>You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. <font size=6>DO NOT</font> work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. <font size=6>DO NOT</font> leave your base without admin permission.</i>"
flavour_text = "You are a syndicate agent, employed in a small listening outpost. You'd be bored to death if you couldn't listen in on those NT idiots mess up all the time."
/obj/effect/mob_spawn/human/lavaland_syndicate/comms/space/Initialize(mapload)
. = ..()
@@ -4,17 +4,17 @@
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made.
var/event = ""
var/screen = 1
var/active = FALSE // This gets set to TRUE on all devices except the one where the initial request was made.
var/event
var/swiping = FALSE // on swiping screen?
var/list/ert_chosen = list()
var/confirmed = 0 //This variable is set by the device that confirms the request.
var/confirm_delay = 20 //(2 seconds)
var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device.
var/confirmed = FALSE // This variable is set by the device that confirms the request.
var/confirm_delay = 5 SECONDS // time allowed for a second person to confirm a swipe.
var/busy = FALSE // Busy when waiting for authentication or an event request has been sent from this device.
var/obj/machinery/keycard_auth/event_source
var/mob/event_triggered_by
var/mob/event_confirmed_by
var/ert_reason = "Reason for ERT"
var/ert_reason
anchored = 1
use_power = IDLE_POWER_USE
@@ -35,16 +35,19 @@
return
if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))
if(check_access(W))
if(active == 1)
if(active)
//This is not the device that made the initial request. It is the device confirming the request.
if(event_source)
event_source.confirmed = 1
event_source.confirmed = TRUE
event_source.event_confirmed_by = usr
else if(screen == 2)
if(event == "Emergency Response Team" && ert_reason == "Reason for ERT")
to_chat(user, "<span class='notice'>Supply a reason for calling the ERT first!</span>")
SStgui.update_uis(event_source)
SStgui.update_uis(src)
else if(swiping)
if(event == "Emergency Response Team" && !ert_reason)
to_chat(user, "<span class='warning'>Supply a reason for calling the ERT first!</span>")
return
event_triggered_by = usr
SStgui.update_uis(src)
broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices
else
to_chat(user, "<span class='warning'>Access denied.</span>")
@@ -59,57 +62,58 @@
stat |= NOPOWER
/obj/machinery/keycard_auth/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/keycard_auth/attack_hand(mob/user as mob)
/obj/machinery/keycard_auth/attack_hand(mob/user)
if(..())
return 1
ui_interact(user)
return TRUE
tgui_interact(user)
/obj/machinery/keycard_auth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(busy)
to_chat(user, "This device is busy.")
return
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/keycard_auth/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 540, 320)
ui = new(user, src, ui_key, "KeycardAuth", name, 540, 300, master_ui, state)
ui.open()
/obj/machinery/keycard_auth/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["screen"] = screen
data["event"] = event
data["ertreason"] = ert_reason
/obj/machinery/keycard_auth/tgui_data()
var/list/data = list()
data["redAvailable"] = GLOB.security_level == SEC_LEVEL_RED ? FALSE : TRUE
data["swiping"] = swiping
data["busy"] = busy
data["event"] = active && event_source && event_source.event ? event_source.event : event
data["ertreason"] = active && event_source && event_source.ert_reason ? event_source.ert_reason : ert_reason
data["isRemote"] = active ? TRUE : FALSE
data["hasSwiped"] = event_triggered_by ? TRUE : FALSE
data["hasConfirm"] = event_confirmed_by || (active && event_source && event_source.event_confirmed_by) ? TRUE : FALSE
return data
/obj/machinery/keycard_auth/Topic(href, href_list)
/obj/machinery/keycard_auth/tgui_act(action, params)
if(..())
return 1
if(busy)
to_chat(usr, "This device is busy.")
return
if(busy)
to_chat(usr, "<span class='warning'>This device is busy.</span>")
return
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
. = TRUE
switch(action)
if("ert")
ert_reason = stripped_input(usr, "Reason for ERT Call:", "", "")
if("reset")
reset()
if("triggerevent")
event = params["triggerevent"]
swiping = TRUE
if(href_list["triggerevent"])
event = href_list["triggerevent"]
screen = 2
if(href_list["reset"])
reset()
if(href_list["ert"])
ert_reason = stripped_input(usr, "Reason for ERT Call:", "", "")
SSnanoui.update_uis(src)
add_fingerprint(usr)
return
/obj/machinery/keycard_auth/proc/reset()
active = 0
event = ""
screen = 1
confirmed = 0
active = FALSE
event = null
swiping = FALSE
confirmed = FALSE
event_source = null
icon_state = "auth_off"
event_triggered_by = null
@@ -125,7 +129,7 @@
sleep(confirm_delay)
if(confirmed)
confirmed = 0
confirmed = FALSE
trigger_event(event)
log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]")
message_admins("[key_name_admin(event_triggered_by)] triggered and [key_name_admin(event_confirmed_by)] confirmed event [event]", 1)
@@ -135,16 +139,17 @@
if(stat & (BROKEN|NOPOWER))
return
event_source = source
busy = 1
active = 1
busy = TRUE
active = TRUE
SStgui.update_uis(src)
icon_state = "auth_on"
sleep(confirm_delay)
event_source = null
icon_state = "auth_off"
active = 0
busy = 0
active = FALSE
busy = FALSE
/obj/machinery/keycard_auth/proc/trigger_event()
switch(event)
@@ -178,7 +183,7 @@
if(fullmin_count)
GLOB.ert_request_answered = TRUE
ERT_Announce(ert_reason , event_triggered_by, 0)
ert_reason = "Reason for ERT"
ert_reason = null
feedback_inc("alert_keycard_auth_ert",1)
spawn(3000)
if(!GLOB.ert_request_answered)
+5 -6
View File
@@ -6,13 +6,12 @@
resistance_flags = INDESTRUCTIBLE
flags = NODECONSTRUCT
/obj/machinery/computer/shuttle/ert/Topic(href, href_list)
if(href_list["move"])
/obj/machinery/computer/shuttle/ert/can_call_shuttle(mob/user, action)
if(action == "move")
var/authorized_roles = list(SPECIAL_ROLE_ERT, SPECIAL_ROLE_DEATHSQUAD)
if(!((usr.mind?.assigned_role in authorized_roles) || is_admin(usr)))
message_admins("Potential ERT shuttle hijack, ERT shuttle moved by unauthorized user: [key_name_admin(usr)]")
..()
if(!((user.mind?.assigned_role in authorized_roles) || is_admin(user)))
message_admins("Potential ERT shuttle hijack, ERT shuttle moved by unauthorized user: [key_name_admin(user)]")
return TRUE
/obj/machinery/computer/camera_advanced/shuttle_docker/ert
name = "specops navigation computer"
+38 -36
View File
@@ -727,13 +727,13 @@
name = "Shuttle Console"
icon_screen = "shuttle"
icon_keyboard = "tech_key"
req_access = list( )
req_access = list()
circuit = /obj/item/circuitboard/shuttle
var/shuttleId
var/possible_destinations = ""
var/admin_controlled
var/max_connect_range = 7
var/docking_request = 0
var/moved = FALSE //workaround for nukie shuttle, hope I find a better way to do this...
/obj/machinery/computer/shuttle/New(location, obj/item/circuitboard/shuttle/C)
..()
@@ -773,21 +773,20 @@
return
connect()
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/shuttle/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/shuttle/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)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "shuttle_console.tmpl", M ? M.name : "shuttle", 300, 200)
ui = new(user, src, ui_key, "ShuttleConsole", name, 350, 150, master_ui, state)
ui.open()
/obj/machinery/computer/shuttle/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/computer/shuttle/tgui_data(mob/user)
var/list/data = list()
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
data["status"] = M ? M.getStatusText() : null
if(M)
data["shuttle"] = 1
data["shuttle"] = TRUE //this should just be boolean, right?
var/list/docking_ports = list()
data["docking_ports"] = docking_ports
var/list/options = params2list(possible_destinations)
@@ -799,34 +798,35 @@
docking_ports[++docking_ports.len] = list("name" = S.name, "id" = S.id)
data["docking_ports_len"] = docking_ports.len
data["admin_controlled"] = admin_controlled
data["docking_request"] = docking_request
return data
/obj/machinery/computer/shuttle/Topic(href, href_list)
if(..())
return 1
/obj/machinery/computer/shuttle/tgui_act(action, params)
if(..()) //we can't actually interact, so no action
return TRUE
if(!allowed(usr))
to_chat(usr, "<span class='danger'>Access denied.</span>")
return
return TRUE
if(!can_call_shuttle(usr, action))
return TRUE
var/list/options = params2list(possible_destinations)
if(href_list["move"])
if(!options.Find(href_list["move"])) //I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING.
// Seriously, though, NEVER trust a Topic with something like this. Ever.
// Sidenote for whoever did this last. Why did you set it to echo whatever the user entered to admin chat? You solved one exploit and created another.
if(action == "move")
var/destination = params["move"]
if(!options.Find(destination))//figure out if this translation works
message_admins("<span class='boldannounce'>EXPLOIT:</span> [ADMIN_LOOKUPFLW(usr)] attempted to move [src] to an invalid location! [ADMIN_COORDJMP(src)]")
return
switch(SSshuttle.moveShuttle(shuttleId, href_list["move"], 1, usr))
switch(SSshuttle.moveShuttle(shuttleId, destination, TRUE, usr))
if(0)
atom_say("Shuttle departing! Please stand away from the doors.")
usr.create_log(MISC_LOG, "used [src] to call the [shuttleId] shuttle")
if(!moved)
moved = TRUE
add_fingerprint(usr)
return TRUE
if(1)
to_chat(usr, "<span class='warning'>Invalid shuttle requested.</span>")
else
to_chat(usr, "<span class='notice'>Unable to comply.</span>")
return 1
/obj/machinery/computer/shuttle/emag_act(mob/user)
if(!emagged)
@@ -834,6 +834,10 @@
emagged = 1
to_chat(user, "<span class='notice'>You fried the consoles ID checking system.</span>")
//for restricting when the computer can be used, needed for some console subtypes.
/obj/machinery/computer/shuttle/proc/can_call_shuttle(mob/user, action)
return TRUE
/obj/machinery/computer/shuttle/ferry
name = "transport ferry console"
circuit = /obj/item/circuitboard/ferry
@@ -844,25 +848,23 @@
/obj/machinery/computer/shuttle/ferry/request
name = "ferry console"
circuit = /obj/item/circuitboard/ferry/request
var/cooldown //prevents spamming admins
var/next_request //to prevent spamming admins
possible_destinations = "ferry_home"
admin_controlled = 1
admin_controlled = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/machinery/computer/shuttle/ferry/request/Topic(href, href_list)
if(..())
return 1
if(href_list["request"])
if(cooldown)
/obj/machinery/computer/shuttle/ferry/request/tgui_act(action, params)
if(..()) // Note that the parent handels normal shuttle movement on top of security checks
return
if(action == "request")
if(world.time < next_request)
return
cooldown = 1
next_request = world.time + 60 SECONDS //1 minute cooldown
to_chat(usr, "<span class='notice'>Your request has been recieved by Centcom.</span>")
log_admin("[key_name(usr)] requested to move the transport ferry to Centcom.")
message_admins("<b>FERRY: <font color='blue'>[key_name_admin(usr)] (<A HREF='?_src_=holder;secretsfun=moveferry'>Move Ferry</a>)</b> is requesting to move the transport ferry to Centcom.</font>")
. = 1
SSnanoui.update_uis(src)
spawn(600) //One minute cooldown
cooldown = 0
return TRUE
/obj/machinery/computer/shuttle/white_ship
name = "White Ship Console"
+9 -11
View File
@@ -11,20 +11,18 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
flags = NODECONSTRUCT
var/challenge = FALSE
var/moved = FALSE
/obj/machinery/computer/shuttle/syndicate/recall
name = "syndicate shuttle recall terminal"
circuit = /obj/item/circuitboard/shuttle/syndicate/recall
possible_destinations = "syndicate_away"
/obj/machinery/computer/shuttle/syndicate/Topic(href, href_list)
if(href_list["move"])
/obj/machinery/computer/shuttle/syndicate/can_call_shuttle(user, action)
if(action == "move")
if(challenge && world.time < SYNDICATE_CHALLENGE_TIMER)
to_chat(usr, "<span class='warning'>You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.</span>")
return 0
moved = TRUE
..()
to_chat(user, "<span class='warning'>You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.</span>")
return FALSE
return TRUE
/obj/machinery/computer/shuttle/syndicate/drop_pod
name = "syndicate assault pod control"
@@ -35,11 +33,11 @@
shuttleId = "steel_rain"
possible_destinations = null
/obj/machinery/computer/shuttle/syndicate/drop_pod/Topic(href, href_list)
if(href_list["move"])
/obj/machinery/computer/shuttle/syndicate/drop_pod/can_call_shuttle(user, action)
if(action == "move")
if(z != level_name_to_num(CENTCOMM))
to_chat(usr, "<span class='warning'>Pods are one way!</span>")
return 0
to_chat(user, "<span class='warning'>Pods are one way!</span>")
return FALSE
..()
/obj/machinery/computer/shuttle/sst

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