This commit is contained in:
Artur
2020-01-15 09:41:33 +02:00
parent 6e3206a2e4
commit 8b8a112d2c
185 changed files with 12673 additions and 11295 deletions
+5
View File
@@ -113,6 +113,11 @@ Class Procs:
var/atom/movable/occupant = null
var/speed_process = FALSE // Process as fast as possible?
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
// For storing and overriding ui id and dimensions
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
var/ui_x
var/ui_y
var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE
+28 -25
View File
@@ -46,34 +46,37 @@
new /obj/item/stack/spacecash/c200(drop_location()) // will autostack
playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
SSshuttle.points -= 200
if(next_warning < world.time && prob(15))
var/area/A = get_area(loc)
var/message = "Unauthorized credit withdrawal underway in [A.map_name]!!"
radio.talk_into(src, message, radio_channel)
next_warning = world.time + minimum_time_between_warnings
if(next_warning < world.time && prob(15))
var/area/A = get_area(loc)
var/message = "Unauthorized credit withdrawal underway in [A.map_name]!!"
radio.talk_into(src, message, radio_channel)
next_warning = world.time + minimum_time_between_warnings
/obj/machinery/computer/bank_machine/ui_interact(mob/user)
. = ..()
var/dat = "[station_name()] secure vault. Authorized personnel only.<br>"
dat += "Current Balance: [SSshuttle.points] credits.<br>"
if(!siphoning)
dat += "<A href='?src=[REF(src)];siphon=1'>Siphon Credits</A><br>"
else
dat += "<A href='?src=[REF(src)];halt=1'>Halt Credit Siphon</A><br>"
/obj/machinery/computer/bank_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "bank_machine", name, 320, 165, master_ui, state)
ui.open()
dat += "<a href='?src=[REF(user)];mach_close=computer'>Close</a>"
/obj/machinery/computer/bank_machine/ui_data(mob/user)
var/list/data = list()
data["current_balance"] = SSshuttle.points
data["siphoning"] = siphoning
data["station_name"] = station_name()
var/datum/browser/popup = new(user, "computer", "Bank Vault", 300, 200)
popup.set_content("<center>[dat]</center>")
popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return data
/obj/machinery/computer/bank_machine/Topic(href, href_list)
/obj/machinery/computer/bank_machine/ui_act(action, params)
if(..())
return
if(href_list["siphon"])
say("Siphon of station credits has begun!")
siphoning = TRUE
if(href_list["halt"])
say("Station credit withdrawal halted.")
siphoning = FALSE
switch(action)
if("siphon")
say("Siphon of station credits has begun!")
siphoning = TRUE
. = TRUE
if("halt")
say("Station credit withdrawal halted.")
siphoning = FALSE
. = TRUE
+123 -128
View File
@@ -1,128 +1,123 @@
#define MENU_OPERATION 1
#define MENU_SURGERIES 2
/obj/machinery/computer/operating
name = "operating computer"
desc = "Monitors patient vitals and displays surgery steps. Can be loaded with surgery disks to perform experimental procedures."
icon_screen = "crew"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/operating
var/mob/living/carbon/human/patient
var/obj/structure/table/optable/table
var/list/advanced_surgeries = list()
var/datum/techweb/linked_techweb
var/menu = MENU_OPERATION
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/operating/Initialize()
. = ..()
linked_techweb = SSresearch.science_tech
find_table()
/obj/machinery/computer/operating/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/disk/surgery))
user.visible_message("[user] begins to load \the [O] in \the [src]...",
"You begin to load a surgery protocol from \the [O]...",
"You hear the chatter of a floppy drive.")
var/obj/item/disk/surgery/D = O
if(do_after(user, 10, target = src))
advanced_surgeries |= D.surgeries
return TRUE
return ..()
/obj/machinery/computer/operating/proc/sync_surgeries()
for(var/i in linked_techweb.researched_designs)
var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i)
if(!istype(D))
continue
advanced_surgeries |= D.surgery
/obj/machinery/computer/operating/proc/find_table()
for(var/direction in GLOB.cardinals)
table = locate(/obj/structure/table/optable, get_step(src, direction))
if(table)
table.computer = src
break
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state)
ui.open()
/obj/machinery/computer/operating/ui_data(mob/user)
var/list/data = list()
data["table"] = table
if(table)
data["menu"] = menu
var/list/surgeries = list()
for(var/X in advanced_surgeries)
var/datum/surgery/S = X
var/list/surgery = list()
surgery["name"] = initial(S.name)
surgery["desc"] = initial(S.desc)
surgeries += list(surgery)
data["surgeries"] = surgeries
data["patient"] = list()
if(table.check_patient())
patient = table.patient
switch(patient.stat)
if(CONSCIOUS)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "good"
if(SOFT_CRIT)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "average"
if(UNCONSCIOUS)
data["patient"]["stat"] = "Unconscious"
data["patient"]["statstate"] = "average"
if(DEAD)
data["patient"]["stat"] = "Dead"
data["patient"]["statstate"] = "bad"
data["patient"]["health"] = patient.health
data["patient"]["blood_type"] = patient.dna.blood_type
data["patient"]["maxHealth"] = patient.maxHealth
data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
data["patient"]["bruteLoss"] = patient.getBruteLoss()
data["patient"]["fireLoss"] = patient.getFireLoss()
data["patient"]["toxLoss"] = patient.getToxLoss()
data["patient"]["oxyLoss"] = patient.getOxyLoss()
if(patient.surgeries.len)
data["procedures"] = list()
for(var/datum/surgery/procedure in patient.surgeries)
var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
var/chems_needed = surgery_step.get_chem_list()
var/alternative_step
var/alt_chems_needed = ""
if(surgery_step.repeatable)
var/datum/surgery_step/next_step = procedure.get_surgery_next_step()
if(next_step)
alternative_step = capitalize(next_step.name)
alt_chems_needed = next_step.get_chem_list()
else
alternative_step = "Finish operation"
data["procedures"] += list(list(
"name" = capitalize(procedure.name),
"next_step" = capitalize(surgery_step.name),
"chems_needed" = chems_needed,
"alternative_step" = alternative_step,
"alt_chems_needed" = alt_chems_needed
))
return data
/obj/machinery/computer/operating/ui_act(action, params)
if(..())
return
switch(action)
if("change_menu")
menu = text2num(params["menu"])
. = TRUE
if("sync")
sync_surgeries()
. = TRUE
. = TRUE
#undef MENU_OPERATION
#undef MENU_SURGERIES
#define MENU_OPERATION 1
#define MENU_SURGERIES 2
/obj/machinery/computer/operating
name = "operating computer"
desc = "Monitors patient vitals and displays surgery steps. Can be loaded with surgery disks to perform experimental procedures."
icon_screen = "crew"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/operating
var/mob/living/carbon/human/patient
var/obj/structure/table/optable/table
var/list/advanced_surgeries = list()
var/datum/techweb/linked_techweb
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/operating/Initialize()
. = ..()
linked_techweb = SSresearch.science_tech
find_table()
/obj/machinery/computer/operating/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/disk/surgery))
user.visible_message("[user] begins to load \the [O] in \the [src]...",
"You begin to load a surgery protocol from \the [O]...",
"You hear the chatter of a floppy drive.")
var/obj/item/disk/surgery/D = O
if(do_after(user, 10, target = src))
advanced_surgeries |= D.surgeries
return TRUE
return ..()
/obj/machinery/computer/operating/proc/sync_surgeries()
for(var/i in linked_techweb.researched_designs)
var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i)
if(!istype(D))
continue
advanced_surgeries |= D.surgery
/obj/machinery/computer/operating/proc/find_table()
for(var/direction in GLOB.cardinals)
table = locate(/obj/structure/table/optable, get_step(src, direction))
if(table)
table.computer = src
break
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state)
ui.open()
/obj/machinery/computer/operating/ui_data(mob/user)
var/list/data = list()
data["table"] = table
if(table)
var/list/surgeries = list()
for(var/X in advanced_surgeries)
var/datum/surgery/S = X
var/list/surgery = list()
surgery["name"] = initial(S.name)
surgery["desc"] = initial(S.desc)
surgeries += list(surgery)
data["surgeries"] = surgeries
if(table.check_patient())
data["patient"] = list()
patient = table.patient
switch(patient.stat)
if(CONSCIOUS)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "good"
if(SOFT_CRIT)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "average"
if(UNCONSCIOUS)
data["patient"]["stat"] = "Unconscious"
data["patient"]["statstate"] = "average"
if(DEAD)
data["patient"]["stat"] = "Dead"
data["patient"]["statstate"] = "bad"
data["patient"]["health"] = patient.health
data["patient"]["blood_type"] = patient.dna.blood_type
data["patient"]["maxHealth"] = patient.maxHealth
data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
data["patient"]["bruteLoss"] = patient.getBruteLoss()
data["patient"]["fireLoss"] = patient.getFireLoss()
data["patient"]["toxLoss"] = patient.getToxLoss()
data["patient"]["oxyLoss"] = patient.getOxyLoss()
if(patient.surgeries.len)
data["procedures"] = list()
for(var/datum/surgery/procedure in patient.surgeries)
var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
var/chems_needed = surgery_step.get_chem_list()
var/alternative_step
var/alt_chems_needed = ""
if(surgery_step.repeatable)
var/datum/surgery_step/next_step = procedure.get_surgery_next_step()
if(next_step)
alternative_step = capitalize(next_step.name)
alt_chems_needed = next_step.get_chem_list()
else
alternative_step = "Finish operation"
data["procedures"] += list(list(
"name" = capitalize(procedure.name),
"next_step" = capitalize(surgery_step.name),
"chems_needed" = chems_needed,
"alternative_step" = alternative_step,
"alt_chems_needed" = alt_chems_needed
))
else
data["patient"] = null
return data
/obj/machinery/computer/operating/ui_act(action, params)
if(..())
return
switch(action)
if("sync")
sync_surgeries()
. = TRUE
. = TRUE
#undef MENU_OPERATION
#undef MENU_SURGERIES
+99 -98
View File
@@ -1,98 +1,99 @@
/obj/machinery/computer/station_alert
name = "station alert console"
desc = "Used to access the station's automated alert system."
icon_screen = "alert:0"
icon_keyboard = "atmos_key"
circuit = /obj/item/circuitboard/computer/stationalert
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
light_color = LIGHT_COLOR_CYAN
/obj/machinery/computer/station_alert/Initialize()
. = ..()
GLOB.alert_consoles += src
/obj/machinery/computer/station_alert/Destroy()
GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "station_alert", name, 300, 500, master_ui, state)
ui.open()
/obj/machinery/computer/station_alert/ui_data(mob/user)
. = list()
.["alarms"] = list()
for(var/class in alarms)
.["alarms"][class] = list()
for(var/area in alarms[class])
.["alarms"][class] += area
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
if(source.z != z)
return
if(stat & (BROKEN))
return
var/list/L = alarms[class]
for(var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return 1
var/obj/machinery/camera/C = null
var/list/CL = null
if(O && islist(O))
CL = O
if (CL.len == 1)
C = CL[1]
else if(O && istype(O, /obj/machinery/camera))
C = O
L[A.name] = list(A, (C ? C : O), list(source))
return 1
/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
if(stat & (BROKEN))
return
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
return !cleared
/obj/machinery/computer/station_alert/update_icon()
..()
cut_overlays()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
var/overlay_state = icon_screen
if(stat & (NOPOWER|BROKEN))
add_overlay("[icon_keyboard]_off")
return
add_overlay(icon_keyboard)
var/active_alarms = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
active_alarms = TRUE
if(active_alarms)
overlay_state = "alert:2"
add_overlay("alert:2")
else
overlay_state = "alert:0"
add_overlay("alert:0")
SSvis_overlays.add_vis_overlay(src, icon, overlay_state, layer, plane, dir)
SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir, alpha=128)
/obj/machinery/computer/station_alert
name = "station alert console"
desc = "Used to access the station's automated alert system."
icon_screen = "alert:0"
icon_keyboard = "atmos_key"
circuit = /obj/item/circuitboard/computer/stationalert
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
light_color = LIGHT_COLOR_CYAN
/obj/machinery/computer/station_alert/Initialize()
. = ..()
GLOB.alert_consoles += src
/obj/machinery/computer/station_alert/Destroy()
GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "station_alert", name, 325, 500, master_ui, state)
ui.open()
/obj/machinery/computer/station_alert/ui_data(mob/user)
var/list/data = list()
data["alarms"] = list()
for(var/class in alarms)
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
if(source.z != z)
return
if(stat & (BROKEN))
return
var/list/L = alarms[class]
for(var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return 1
var/obj/machinery/camera/C = null
var/list/CL = null
if(O && islist(O))
CL = O
if (CL.len == 1)
C = CL[1]
else if(O && istype(O, /obj/machinery/camera))
C = O
L[A.name] = list(A, (C ? C : O), list(source))
return 1
/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
if(stat & (BROKEN))
return
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
return !cleared
/obj/machinery/computer/station_alert/update_icon()
..()
cut_overlays()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
var/overlay_state = icon_screen
if(stat & (NOPOWER|BROKEN))
add_overlay("[icon_keyboard]_off")
return
add_overlay(icon_keyboard)
var/active_alarms = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
active_alarms = TRUE
if(active_alarms)
overlay_state = "alert:2"
add_overlay("alert:2")
else
overlay_state = "alert:0"
add_overlay("alert:0")
SSvis_overlays.add_vis_overlay(src, icon, overlay_state, layer, plane, dir)
SSvis_overlays.add_vis_overlay(src, icon, overlay_state, ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir, alpha=128)
+27 -105
View File
@@ -1434,7 +1434,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ai_airlock", name, 550, 456, master_ui, state)
ui = new(user, src, ui_key, "ai_airlock", name, 500, 390, master_ui, state)
ui.open()
return TRUE
@@ -1503,83 +1503,24 @@
if("shock-perm")
shock_perm(usr)
. = TRUE
if("idscan-on")
if(wires.is_cut(WIRE_IDSCAN))
to_chat(usr, "You can't enable IdScan - The IdScan wire has been cut.")
else if(src.aiDisabledIdScanner)
aiDisabledIdScanner = FALSE
else
to_chat(usr, "The IdScan feature is not disabled.")
if("idscan-toggle")
aiDisabledIdScanner = !aiDisabledIdScanner
. = TRUE
if("idscan-off")
if(wires.is_cut(WIRE_IDSCAN))
to_chat(usr, "The IdScan wire has been cut - So, you can't disable it, but it is already disabled anyways.")
else if(aiDisabledIdScanner)
to_chat(usr, "You've already disabled the IdScan feature.")
else
aiDisabledIdScanner = TRUE
if("emergency-toggle")
toggle_emergency(usr)
. = TRUE
if("emergency-on")
emergency_on(usr)
if("bolt-toggle")
toggle_bolt(usr)
. = TRUE
if("emergency-off")
emergency_off(usr)
if("light-toggle")
lights = !lights
update_icon()
. = TRUE
if("bolt-raise")
bolt_raise(usr)
if("safe-toggle")
safe = !safe
. = TRUE
if("bolt-drop")
bolt_drop(usr)
. = TRUE
if("light-on")
if(wires.is_cut(WIRE_LIGHT))
to_chat(usr, "Control to door bolt lights has been severed.")
else if (!src.lights)
lights = TRUE
update_icon()
else
to_chat(usr, text("Door bolt lights are already enabled!"))
. = TRUE
if("light-off")
if(wires.is_cut(WIRE_LIGHT))
to_chat(usr, "Control to door bolt lights has been severed.")
else if (lights)
lights = FALSE
update_icon()
else
to_chat(usr, "Door bolt lights are already disabled!")
. = TRUE
if("safe-on")
if(wires.is_cut(WIRE_SAFETY))
to_chat(usr, "Control to door sensors is disabled.")
else if (!src.safe)
safe = TRUE
else
to_chat(usr, "Firmware reports safeties already in place.")
. = TRUE
if("safe-off")
if(wires.is_cut(WIRE_SAFETY))
to_chat(usr, "Control to door sensors is disabled.")
else if (safe)
safe = FALSE
else
to_chat(usr, "Firmware reports safeties already overridden.")
. = TRUE
if("speed-on")
if(wires.is_cut(WIRE_TIMING))
to_chat(usr, "Control to door timing circuitry has been severed.")
else if (!src.normalspeed)
normalspeed = 1
else
to_chat(usr,"Door timing circuitry currently operating normally.")
. = TRUE
if("speed-off")
if(wires.is_cut(WIRE_TIMING))
to_chat(usr, "Control to door timing circuitry has been severed.")
else if (normalspeed)
normalspeed = 0
else
to_chat(usr, "Door timing circuitry already accelerated.")
if("speed-toggle")
normalspeed = !normalspeed
. = TRUE
if("open-close")
@@ -1617,45 +1558,26 @@
log_combat(user, src, "electrified")
set_electrified(ELECTRIFIED_PERMANENT)
/obj/machinery/door/airlock/proc/emergency_on(mob/user)
if(!user_allowed(user))
return
if (!emergency)
emergency = TRUE
update_icon()
else
to_chat(user, "Emergency access is already enabled!")
/obj/machinery/door/airlock/proc/emergency_off(mob/user)
if(!user_allowed(user))
return
if (emergency)
emergency = FALSE
update_icon()
else
to_chat(user, "Emergency access is already disabled!")
/obj/machinery/door/airlock/proc/bolt_raise(mob/user)
/obj/machinery/door/airlock/proc/toggle_bolt(mob/user)
if(!user_allowed(user))
return
if(wires.is_cut(WIRE_BOLTS))
to_chat(user, "The door bolt drop wire is cut - you can't raise the door bolts")
else if(!src.locked)
to_chat(user, "The door bolts are already up")
else
if(src.hasPower())
unbolt()
to_chat(user, "<span class='warning'>The door bolt drop wire is cut - you can't toggle the door bolts.</span>")
return
if(locked)
if(!hasPower())
to_chat(user, "<span class='warning'>The door has no power - you can't raise the door bolts.</span>")
else
to_chat(user, "Cannot raise door bolts due to power failure")
/obj/machinery/door/airlock/proc/bolt_drop(mob/user)
if(!user_allowed(user))
return
if(wires.is_cut(WIRE_BOLTS))
to_chat(user, "You can't drop the door bolts - The door bolt dropping wire has been cut.")
unbolt()
else
bolt()
/obj/machinery/door/airlock/proc/toggle_emergency(mob/user)
if(!user_allowed(user))
return
emergency = !emergency
update_icon()
/obj/machinery/door/airlock/proc/user_toggle_open(mob/user)
if(!user_allowed(user))
return
@@ -14,7 +14,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "airlock_electronics", name, 975, 420, master_ui, state)
ui = new(user, src, ui_key, "airlock_electronics", name, 420, 485, master_ui, state)
ui.open()
/obj/item/electronics/airlock/ui_data()
@@ -43,13 +43,16 @@
if(..())
return
switch(action)
if("clear")
if("clear_all")
accesses = list()
one_access = 0
. = TRUE
if("one_access")
one_access = !one_access
. = TRUE
if("grant_all")
accesses = get_all_accesses()
. = TRUE
if("set")
var/access = text2num(params["access"])
if (!(access in accesses))
+256 -256
View File
@@ -1,256 +1,256 @@
#define CHARS_PER_LINE 5
#define FONT_SIZE "5pt"
#define FONT_COLOR "#09f"
#define FONT_STYLE "Arial Black"
#define MAX_TIMER 9000
#define PRESET_SHORT 1200
#define PRESET_MEDIUM 1800
#define PRESET_LONG 3000
///////////////////////////////////////////////////////////////////////////////////////////////
// Brig Door control displays.
// Description: This is a controls the timer for the brig doors, displays the timer on itself and
// has a popup window when used, allowing to set the timer.
// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code
// Date: 01/September/2010
// Programmer: Veryinky
/////////////////////////////////////////////////////////////////////////////////////////////////
/obj/machinery/door_timer
name = "door timer"
icon = 'icons/obj/status_display.dmi'
icon_state = "frame"
desc = "A remote control for a door."
req_access = list(ACCESS_SECURITY)
density = FALSE
var/id = null // id of linked machinery/lockers
var/activation_time = 0
var/timer_duration = 0
var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing
var/list/obj/machinery/targets = list()
var/obj/item/radio/Radio //needed to send messages to sec radio
maptext_height = 26
maptext_width = 32
/obj/machinery/door_timer/Initialize()
. = ..()
Radio = new/obj/item/radio(src)
Radio.listening = 0
/obj/machinery/door_timer/Initialize()
. = ..()
if(id != null)
for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
if (M.id == id)
targets += M
for(var/obj/machinery/flasher/F in urange(20, src))
if(F.id == id)
targets += F
for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src))
if(C.id == id)
targets += C
if(!targets.len)
stat |= BROKEN
update_icon()
//Main door timer loop, if it's timing and time is >0 reduce time by 1.
// if it's less than 0, open door, reset timer
// update the door_timer window and the icon
/obj/machinery/door_timer/process()
if(stat & (NOPOWER|BROKEN))
return
if(timing)
if(world.realtime - activation_time >= timer_duration)
timer_end() // open doors, reset timer, clear status screen
update_icon()
// has the door power sitatuation changed, if so update icon.
/obj/machinery/door_timer/power_change()
..()
update_icon()
// open/closedoor checks if door_timer has power, if so it checks if the
// linked door is open/closed (by density) then opens it/closes it.
/obj/machinery/door_timer/proc/timer_start()
if(stat & (NOPOWER|BROKEN))
return 0
activation_time = world.realtime
timing = TRUE
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(door.density)
continue
INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/close)
for(var/obj/structure/closet/secure_closet/brig/C in targets)
if(C.broken)
continue
if(C.opened && !C.close())
continue
C.locked = TRUE
C.update_icon()
return 1
/obj/machinery/door_timer/proc/timer_end(forced = FALSE)
if(stat & (NOPOWER|BROKEN))
return 0
if(!forced)
Radio.set_frequency(FREQ_SECURITY)
Radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY)
timing = FALSE
activation_time = null
set_timer(0)
update_icon()
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(!door.density)
continue
INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open)
for(var/obj/structure/closet/secure_closet/brig/C in targets)
if(C.broken)
continue
if(C.opened)
continue
C.locked = FALSE
C.update_icon()
return 1
/obj/machinery/door_timer/proc/time_left(seconds = FALSE)
. = max(0,timer_duration - (activation_time ? world.realtime - activation_time : 0))
if(seconds)
. /= 10
/obj/machinery/door_timer/proc/set_timer(value)
var/new_time = CLAMP(value,0,MAX_TIMER)
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "brig_timer", name, 300, 200, master_ui, state)
ui.open()
//icon update function
// if NOPOWER, display blank
// if BROKEN, display blue screen of death icon AI uses
// if timing=true, run update display function
/obj/machinery/door_timer/update_icon()
if(stat & (NOPOWER))
icon_state = "frame"
return
if(stat & (BROKEN))
set_picture("ai_bsod")
return
if(timing)
var/disp1 = id
var/time_left = time_left(seconds = TRUE)
var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
if(length(disp2) > CHARS_PER_LINE)
disp2 = "Error"
update_display(disp1, disp2)
else
if(maptext)
maptext = ""
return
// Adds an icon in case the screen is broken/off, stolen from status_display.dm
/obj/machinery/door_timer/proc/set_picture(state)
if(maptext)
maptext = ""
cut_overlays()
add_overlay(mutable_appearance('icons/obj/status_display.dmi', state))
//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display
// Stolen from status_display
/obj/machinery/door_timer/proc/update_display(line1, line2)
var/new_text = {"<div style="font-size:[FONT_SIZE];color:[FONT_COLOR];font:'[FONT_STYLE]';text-align:center;" valign="top">[line1]<br>[line2]</div>"}
if(maptext != new_text)
maptext = new_text
/obj/machinery/door_timer/ui_data()
var/list/data = list()
var/time_left = time_left(seconds = TRUE)
data["seconds"] = round(time_left % 60)
data["minutes"] = round((time_left - data["seconds"]) / 60)
data["timing"] = timing
data["flash_charging"] = FALSE
for(var/obj/machinery/flasher/F in targets)
if(F.last_flash && (F.last_flash + 150) > world.time)
data["flash_charging"] = TRUE
break
return data
/obj/machinery/door_timer/ui_act(action, params)
if(..())
return
. = TRUE
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return FALSE
switch(action)
if("time")
var/value = text2num(params["adjust"])
if(value)
. = set_timer(time_left()+value)
if("start")
timer_start()
if("stop")
timer_end(forced = TRUE)
if("flash")
for(var/obj/machinery/flasher/F in targets)
F.flash()
if("preset")
var/preset = params["preset"]
var/preset_time = time_left()
switch(preset)
if("short")
preset_time = PRESET_SHORT
if("medium")
preset_time = PRESET_MEDIUM
if("long")
preset_time = PRESET_LONG
. = set_timer(preset_time)
if(timing)
activation_time = world.realtime
else
. = FALSE
#undef PRESET_SHORT
#undef PRESET_MEDIUM
#undef PRESET_LONG
#undef MAX_TIMER
#undef FONT_SIZE
#undef FONT_COLOR
#undef FONT_STYLE
#undef CHARS_PER_LINE
#define CHARS_PER_LINE 5
#define FONT_SIZE "5pt"
#define FONT_COLOR "#09f"
#define FONT_STYLE "Arial Black"
#define MAX_TIMER 9000
#define PRESET_SHORT 1200
#define PRESET_MEDIUM 1800
#define PRESET_LONG 3000
///////////////////////////////////////////////////////////////////////////////////////////////
// Brig Door control displays.
// Description: This is a controls the timer for the brig doors, displays the timer on itself and
// has a popup window when used, allowing to set the timer.
// Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code
// Date: 01/September/2010
// Programmer: Veryinky
/////////////////////////////////////////////////////////////////////////////////////////////////
/obj/machinery/door_timer
name = "door timer"
icon = 'icons/obj/status_display.dmi'
icon_state = "frame"
desc = "A remote control for a door."
req_access = list(ACCESS_SECURITY)
density = FALSE
var/id = null // id of linked machinery/lockers
var/activation_time = 0
var/timer_duration = 0
var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing
var/list/obj/machinery/targets = list()
var/obj/item/radio/Radio //needed to send messages to sec radio
maptext_height = 26
maptext_width = 32
/obj/machinery/door_timer/Initialize()
. = ..()
Radio = new/obj/item/radio(src)
Radio.listening = 0
/obj/machinery/door_timer/Initialize()
. = ..()
if(id != null)
for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
if (M.id == id)
targets += M
for(var/obj/machinery/flasher/F in urange(20, src))
if(F.id == id)
targets += F
for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src))
if(C.id == id)
targets += C
if(!targets.len)
stat |= BROKEN
update_icon()
//Main door timer loop, if it's timing and time is >0 reduce time by 1.
// if it's less than 0, open door, reset timer
// update the door_timer window and the icon
/obj/machinery/door_timer/process()
if(stat & (NOPOWER|BROKEN))
return
if(timing)
if(world.realtime - activation_time >= timer_duration)
timer_end() // open doors, reset timer, clear status screen
update_icon()
// has the door power sitatuation changed, if so update icon.
/obj/machinery/door_timer/power_change()
..()
update_icon()
// open/closedoor checks if door_timer has power, if so it checks if the
// linked door is open/closed (by density) then opens it/closes it.
/obj/machinery/door_timer/proc/timer_start()
if(stat & (NOPOWER|BROKEN))
return 0
activation_time = world.realtime
timing = TRUE
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(door.density)
continue
INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/close)
for(var/obj/structure/closet/secure_closet/brig/C in targets)
if(C.broken)
continue
if(C.opened && !C.close())
continue
C.locked = TRUE
C.update_icon()
return 1
/obj/machinery/door_timer/proc/timer_end(forced = FALSE)
if(stat & (NOPOWER|BROKEN))
return 0
if(!forced)
Radio.set_frequency(FREQ_SECURITY)
Radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY)
timing = FALSE
activation_time = null
set_timer(0)
update_icon()
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(!door.density)
continue
INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open)
for(var/obj/structure/closet/secure_closet/brig/C in targets)
if(C.broken)
continue
if(C.opened)
continue
C.locked = FALSE
C.update_icon()
return 1
/obj/machinery/door_timer/proc/time_left(seconds = FALSE)
. = max(0,timer_duration - (activation_time ? world.realtime - activation_time : 0))
if(seconds)
. /= 10
/obj/machinery/door_timer/proc/set_timer(value)
var/new_time = CLAMP(value,0,MAX_TIMER)
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "brig_timer", name, 300, 138, master_ui, state)
ui.open()
//icon update function
// if NOPOWER, display blank
// if BROKEN, display blue screen of death icon AI uses
// if timing=true, run update display function
/obj/machinery/door_timer/update_icon()
if(stat & (NOPOWER))
icon_state = "frame"
return
if(stat & (BROKEN))
set_picture("ai_bsod")
return
if(timing)
var/disp1 = id
var/time_left = time_left(seconds = TRUE)
var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
if(length(disp2) > CHARS_PER_LINE)
disp2 = "Error"
update_display(disp1, disp2)
else
if(maptext)
maptext = ""
return
// Adds an icon in case the screen is broken/off, stolen from status_display.dm
/obj/machinery/door_timer/proc/set_picture(state)
if(maptext)
maptext = ""
cut_overlays()
add_overlay(mutable_appearance('icons/obj/status_display.dmi', state))
//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display
// Stolen from status_display
/obj/machinery/door_timer/proc/update_display(line1, line2)
var/new_text = {"<div style="font-size:[FONT_SIZE];color:[FONT_COLOR];font:'[FONT_STYLE]';text-align:center;" valign="top">[line1]<br>[line2]</div>"}
if(maptext != new_text)
maptext = new_text
/obj/machinery/door_timer/ui_data()
var/list/data = list()
var/time_left = time_left(seconds = TRUE)
data["seconds"] = round(time_left % 60)
data["minutes"] = round((time_left - data["seconds"]) / 60)
data["timing"] = timing
data["flash_charging"] = FALSE
for(var/obj/machinery/flasher/F in targets)
if(F.last_flash && (F.last_flash + 150) > world.time)
data["flash_charging"] = TRUE
break
return data
/obj/machinery/door_timer/ui_act(action, params)
if(..())
return
. = TRUE
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return FALSE
switch(action)
if("time")
var/value = text2num(params["adjust"])
if(value)
. = set_timer(time_left()+value)
if("start")
timer_start()
if("stop")
timer_end(forced = TRUE)
if("flash")
for(var/obj/machinery/flasher/F in targets)
F.flash()
if("preset")
var/preset = params["preset"]
var/preset_time = time_left()
switch(preset)
if("short")
preset_time = PRESET_SHORT
if("medium")
preset_time = PRESET_MEDIUM
if("long")
preset_time = PRESET_LONG
. = set_timer(preset_time)
if(timing)
activation_time = world.realtime
else
. = FALSE
#undef PRESET_SHORT
#undef PRESET_MEDIUM
#undef PRESET_LONG
#undef MAX_TIMER
#undef FONT_SIZE
#undef FONT_COLOR
#undef FONT_STYLE
#undef CHARS_PER_LINE
+1 -1
View File
@@ -31,7 +31,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "gulag_item_reclaimer", name, 455, 440, master_ui, state)
ui = new(user, src, ui_key, "gulag_item_reclaimer", name, 300, 400, master_ui, state)
ui.open()
/obj/machinery/gulag_item_reclaimer/ui_data(mob/user)
+453 -443
View File
@@ -1,443 +1,453 @@
// SUIT STORAGE UNIT /////////////////
/obj/machinery/suit_storage_unit
name = "suit storage unit"
desc = "An industrial unit made to hold and decontaminate irradiated equipment. It comes with a built-in UV cauterization mechanism. A small warning label advises that organic matter should not be placed into the unit."
icon = 'icons/obj/machines/suit_storage.dmi'
icon_state = "close"
density = TRUE
max_integrity = 250
var/obj/item/clothing/suit/space/suit = null
var/obj/item/clothing/head/helmet/space/helmet = null
var/obj/item/clothing/mask/mask = null
var/obj/item/storage = null
var/suit_type = null
var/helmet_type = null
var/mask_type = null
var/storage_type = null
state_open = FALSE
var/locked = FALSE
panel_open = FALSE
var/safeties = TRUE
var/uv = FALSE
var/uv_super = FALSE
var/uv_cycles = 6
var/message_cooldown
var/breakout_time = 300
/obj/machinery/suit_storage_unit/standard_unit
suit_type = /obj/item/clothing/suit/space/eva
helmet_type = /obj/item/clothing/head/helmet/space/eva
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/captain
suit_type = /obj/item/clothing/suit/space/hardsuit/captain
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/jetpack/oxygen/captain
/obj/machinery/suit_storage_unit/engine
suit_type = /obj/item/clothing/suit/space/hardsuit/engine
mask_type = /obj/item/clothing/mask/breath
storage_type= /obj/item/clothing/shoes/magboots
/obj/machinery/suit_storage_unit/ce
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite
mask_type = /obj/item/clothing/mask/breath
storage_type= /obj/item/clothing/shoes/magboots/advance
/obj/machinery/suit_storage_unit/security
suit_type = /obj/item/clothing/suit/space/hardsuit/security
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/jetpack/oxygen/security
/obj/machinery/suit_storage_unit/hos
suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/internals/oxygen
/obj/machinery/suit_storage_unit/atmos
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
mask_type = /obj/item/clothing/mask/gas
storage_type = /obj/item/watertank/atmos
/obj/machinery/suit_storage_unit/mining
suit_type = /obj/item/clothing/suit/hooded/explorer/standard
mask_type = /obj/item/clothing/mask/gas/explorer
/obj/machinery/suit_storage_unit/mining/eva
suit_type = /obj/item/clothing/suit/space/hardsuit/mining
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/cmo
suit_type = /obj/item/clothing/suit/space/hardsuit/medical
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/rd
suit_type = /obj/item/clothing/suit/space/hardsuit/rd
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/syndicate
suit_type = /obj/item/clothing/suit/space/hardsuit/syndi
mask_type = /obj/item/clothing/mask/gas/syndicate
storage_type = /obj/item/tank/jetpack/oxygen/harness
/obj/machinery/suit_storage_unit/ert/command
suit_type = /obj/item/clothing/suit/space/hardsuit/ert
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/security
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/engineer
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/medical
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/radsuit
name = "radiation suit storage unit"
suit_type = /obj/item/clothing/suit/radiation
helmet_type = /obj/item/clothing/head/radiation
storage_type = /obj/item/geiger_counter
/obj/machinery/suit_storage_unit/open
state_open = TRUE
density = FALSE
/obj/machinery/suit_storage_unit/Initialize()
. = ..()
wires = new /datum/wires/suit_storage_unit(src)
if(suit_type)
suit = new suit_type(src)
if(helmet_type)
helmet = new helmet_type(src)
if(mask_type)
mask = new mask_type(src)
if(storage_type)
storage = new storage_type(src)
update_icon()
/obj/machinery/suit_storage_unit/Destroy()
QDEL_NULL(suit)
QDEL_NULL(helmet)
QDEL_NULL(mask)
QDEL_NULL(storage)
return ..()
/obj/machinery/suit_storage_unit/update_icon()
cut_overlays()
if(uv)
if(uv_super)
add_overlay("super")
else if(occupant)
add_overlay("uvhuman")
else
add_overlay("uv")
else if(state_open)
if(stat & BROKEN)
add_overlay("broken")
else
add_overlay("open")
if(suit)
add_overlay("suit")
if(helmet)
add_overlay("helm")
if(storage)
add_overlay("storage")
else if(occupant)
add_overlay("human")
/obj/machinery/suit_storage_unit/power_change()
..()
if(!is_operational() && state_open)
open_machine()
dump_contents()
update_icon()
/obj/machinery/suit_storage_unit/proc/dump_contents()
dropContents()
helmet = null
suit = null
mask = null
storage = null
occupant = null
/obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
open_machine()
dump_contents()
new /obj/item/stack/sheet/metal (loc, 2)
qdel(src)
/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A))
return
var/mob/living/target = A
if(!state_open)
to_chat(user, "<span class='warning'>The unit's doors are shut!</span>")
return
if(!is_operational())
to_chat(user, "<span class='warning'>The unit is not operational!</span>")
return
if(occupant || helmet || suit || storage)
to_chat(user, "<span class='warning'>It's too cluttered inside to fit in!</span>")
return
if(target == user)
user.visible_message("<span class='warning'>[user] starts squeezing into [src]!</span>", "<span class='notice'>You start working your way into [src]...</span>")
else
target.visible_message("<span class='warning'>[user] starts shoving [target] into [src]!</span>", "<span class='userdanger'>[user] starts shoving you into [src]!</span>")
if(do_mob(user, target, 30))
if(occupant || helmet || suit || storage)
return
if(target == user)
user.visible_message("<span class='warning'>[user] slips into [src] and closes the door behind [user.p_them()]!</span>", "<span class=notice'>You slip into [src]'s cramped space and shut its door.</span>")
else
target.visible_message("<span class='warning'>[user] pushes [target] into [src] and shuts its door!<span>", "<span class='userdanger'>[user] shoves you into [src] and shuts the door!</span>")
close_machine(target)
add_fingerprint(user)
/obj/machinery/suit_storage_unit/proc/cook()
var/mob/living/mob_occupant = occupant
if(uv_cycles)
uv_cycles--
uv = TRUE
locked = TRUE
update_icon()
if(occupant)
if(uv_super)
mob_occupant.adjustFireLoss(rand(20, 36))
else
mob_occupant.adjustFireLoss(rand(10, 16))
mob_occupant.emote("scream")
addtimer(CALLBACK(src, .proc/cook), 50)
else
uv_cycles = initial(uv_cycles)
uv = FALSE
locked = FALSE
if(uv_super)
visible_message("<span class='warning'>[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.</span>")
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1)
helmet = null
qdel(helmet)
suit = null
qdel(suit) // Delete everything but the occupant.
mask = null
qdel(mask)
storage = null
qdel(storage)
// The wires get damaged too.
wires.cut_all()
else
if(!occupant)
visible_message("<span class='notice'>[src]'s door slides open. The glowing yellow lights dim to a gentle green.</span>")
else
visible_message("<span class='warning'>[src]'s door slides open, barraging you with the nauseating smell of charred flesh.</span>")
mob_occupant.radiation = 0
playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
var/list/things_to_clear = list() //Done this way since using GetAllContents on the SSU itself would include circuitry and such.
if(suit)
things_to_clear += suit
things_to_clear += suit.GetAllContents()
if(helmet)
things_to_clear += helmet
things_to_clear += helmet.GetAllContents()
if(mask)
things_to_clear += mask
things_to_clear += mask.GetAllContents()
if(storage)
things_to_clear += storage
things_to_clear += storage.GetAllContents()
if(occupant)
things_to_clear += occupant
things_to_clear += occupant.GetAllContents()
for(var/atom/movable/AM in things_to_clear) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG)
AM.clean_blood()
AM.fingerprints = list()
var/datum/component/radioactive/contamination = AM.GetComponent(/datum/component/radioactive)
if(contamination)
qdel(contamination)
open_machine(FALSE)
if(occupant)
dump_contents()
/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
if(!prob(prb))
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
s.start()
if(electrocute_mob(user, src, src, 1, TRUE))
return 1
/obj/machinery/suit_storage_unit/relaymove(mob/user)
if(locked)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
return
open_machine()
dump_contents()
/obj/machinery/suit_storage_unit/container_resist(mob/living/user)
if(!locked)
open_machine()
dump_contents()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the doors of [src]!</span>", \
"<span class='notice'>You start kicking against the doors... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a thump from [src].</span>")
if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src )
return
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
"<span class='notice'>You successfully break out of [src]!</span>")
open_machine()
dump_contents()
add_fingerprint(user)
if(locked)
visible_message("<span class='notice'>You see [user] kicking against the doors of [src]!</span>", \
"<span class='notice'>You start kicking against the doors...</span>")
addtimer(CALLBACK(src, .proc/resist_open, user), 300)
else
open_machine()
dump_contents()
/obj/machinery/suit_storage_unit/proc/resist_open(mob/user)
if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here.
visible_message("<span class='notice'>You see [user] burst out of [src]!</span>", \
"<span class='notice'>You escape the cramped confines of [src]!</span>")
open_machine()
/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
if(state_open && is_operational())
if(istype(I, /obj/item/clothing/head/mob_holder))
to_chat(user, "<span class='warning'>You can't quite fit that in while you hold it!</span>")
return
if(istype(I, /obj/item/clothing/suit))
if(suit)
to_chat(user, "<span class='warning'>The unit already contains a suit!.</span>")
return
if(!user.transferItemToLoc(I, src))
return
suit = I
else if(istype(I, /obj/item/clothing/head))
if(helmet)
to_chat(user, "<span class='warning'>The unit already contains a helmet!</span>")
return
if(!user.transferItemToLoc(I, src))
return
helmet = I
else if(istype(I, /obj/item/clothing/mask))
if(mask)
to_chat(user, "<span class='warning'>The unit already contains a mask!</span>")
return
if(!user.transferItemToLoc(I, src))
return
mask = I
else
if(storage)
to_chat(user, "<span class='warning'>The auxiliary storage compartment is full!</span>")
return
if(!user.transferItemToLoc(I, src))
return
storage = I
visible_message("<span class='notice'>[user] inserts [I] into [src]</span>", "<span class='notice'>You load [I] into [src].</span>")
update_icon()
return
if(panel_open && is_wire_tool(I))
wires.interact(user)
return
if(!state_open)
if(default_deconstruction_screwdriver(user, "panel", "close", I))
return
if(default_pry_open(I))
dump_contents()
return
return ..()
/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state)
ui.open()
/obj/machinery/suit_storage_unit/ui_data()
var/list/data = list()
data["locked"] = locked
data["open"] = state_open
data["safeties"] = safeties
data["uv_active"] = uv
data["uv_super"] = uv_super
if(helmet)
data["helmet"] = helmet.name
if(suit)
data["suit"] = suit.name
if(mask)
data["mask"] = mask.name
if(storage)
data["storage"] = storage.name
if(occupant)
data["occupied"] = 1
return data
/obj/machinery/suit_storage_unit/ui_act(action, params)
if(..() || uv)
return
switch(action)
if("door")
if(state_open)
close_machine()
else
open_machine(0)
if(occupant)
dump_contents() // Dump out contents if someone is in there.
. = TRUE
if("lock")
if(state_open)
return
locked = !locked
. = TRUE
if("uv")
if(occupant && safeties)
return
else if(!helmet && !mask && !suit && !storage && !occupant)
return
else
if(occupant)
var/mob/living/mob_occupant = occupant
to_chat(mob_occupant, "<span class='userdanger'>[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!</span>")
cook()
. = TRUE
if("dispense")
if(!state_open)
return
var/static/list/valid_items = list("helmet", "suit", "mask", "storage")
var/item_name = params["item"]
if(item_name in valid_items)
var/obj/item/I = vars[item_name]
vars[item_name] = null
if(I)
I.forceMove(loc)
. = TRUE
update_icon()
// SUIT STORAGE UNIT /////////////////
/obj/machinery/suit_storage_unit
name = "suit storage unit"
desc = "An industrial unit made to hold and decontaminate irradiated equipment. It comes with a built-in UV cauterization mechanism. A small warning label advises that organic matter should not be placed into the unit."
icon = 'icons/obj/machines/suit_storage.dmi'
icon_state = "close"
density = TRUE
max_integrity = 250
var/obj/item/clothing/suit/space/suit = null
var/obj/item/clothing/head/helmet/space/helmet = null
var/obj/item/clothing/mask/mask = null
var/obj/item/storage = null
var/suit_type = null
var/helmet_type = null
var/mask_type = null
var/storage_type = null
state_open = FALSE
var/locked = FALSE
panel_open = FALSE
var/safeties = TRUE
var/uv = FALSE
var/uv_super = FALSE
var/uv_cycles = 6
var/message_cooldown
var/breakout_time = 300
/obj/machinery/suit_storage_unit/standard_unit
suit_type = /obj/item/clothing/suit/space/eva
helmet_type = /obj/item/clothing/head/helmet/space/eva
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/captain
suit_type = /obj/item/clothing/suit/space/hardsuit/captain
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/jetpack/oxygen/captain
/obj/machinery/suit_storage_unit/engine
suit_type = /obj/item/clothing/suit/space/hardsuit/engine
mask_type = /obj/item/clothing/mask/breath
storage_type= /obj/item/clothing/shoes/magboots
/obj/machinery/suit_storage_unit/ce
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite
mask_type = /obj/item/clothing/mask/breath
storage_type= /obj/item/clothing/shoes/magboots/advance
/obj/machinery/suit_storage_unit/security
suit_type = /obj/item/clothing/suit/space/hardsuit/security
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/jetpack/oxygen/security
/obj/machinery/suit_storage_unit/hos
suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos
mask_type = /obj/item/clothing/mask/gas/sechailer
storage_type = /obj/item/tank/internals/oxygen
/obj/machinery/suit_storage_unit/atmos
suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
mask_type = /obj/item/clothing/mask/gas
storage_type = /obj/item/watertank/atmos
/obj/machinery/suit_storage_unit/mining
suit_type = /obj/item/clothing/suit/hooded/explorer/standard
mask_type = /obj/item/clothing/mask/gas/explorer
/obj/machinery/suit_storage_unit/mining/eva
suit_type = /obj/item/clothing/suit/space/hardsuit/mining
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/cmo
suit_type = /obj/item/clothing/suit/space/hardsuit/medical
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/rd
suit_type = /obj/item/clothing/suit/space/hardsuit/rd
mask_type = /obj/item/clothing/mask/breath
/obj/machinery/suit_storage_unit/syndicate
suit_type = /obj/item/clothing/suit/space/hardsuit/syndi
mask_type = /obj/item/clothing/mask/gas/syndicate
storage_type = /obj/item/tank/jetpack/oxygen/harness
/obj/machinery/suit_storage_unit/ert/command
suit_type = /obj/item/clothing/suit/space/hardsuit/ert
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/security
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/engineer
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/ert/medical
suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/internals/emergency_oxygen/double
/obj/machinery/suit_storage_unit/radsuit
name = "radiation suit storage unit"
suit_type = /obj/item/clothing/suit/radiation
helmet_type = /obj/item/clothing/head/radiation
storage_type = /obj/item/geiger_counter
/obj/machinery/suit_storage_unit/open
state_open = TRUE
density = FALSE
/obj/machinery/suit_storage_unit/Initialize()
. = ..()
wires = new /datum/wires/suit_storage_unit(src)
if(suit_type)
suit = new suit_type(src)
if(helmet_type)
helmet = new helmet_type(src)
if(mask_type)
mask = new mask_type(src)
if(storage_type)
storage = new storage_type(src)
update_icon()
/obj/machinery/suit_storage_unit/Destroy()
QDEL_NULL(suit)
QDEL_NULL(helmet)
QDEL_NULL(mask)
QDEL_NULL(storage)
return ..()
/obj/machinery/suit_storage_unit/update_icon()
cut_overlays()
if(uv)
if(uv_super)
add_overlay("super")
else if(occupant)
add_overlay("uvhuman")
else
add_overlay("uv")
else if(state_open)
if(stat & BROKEN)
add_overlay("broken")
else
add_overlay("open")
if(suit)
add_overlay("suit")
if(helmet)
add_overlay("helm")
if(storage)
add_overlay("storage")
else if(occupant)
add_overlay("human")
/obj/machinery/suit_storage_unit/power_change()
..()
if(!is_operational() && state_open)
open_machine()
dump_contents()
update_icon()
/obj/machinery/suit_storage_unit/proc/dump_contents()
dropContents()
helmet = null
suit = null
mask = null
storage = null
occupant = null
/obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
open_machine()
dump_contents()
new /obj/item/stack/sheet/metal (loc, 2)
qdel(src)
/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A))
return
var/mob/living/target = A
if(!state_open)
to_chat(user, "<span class='warning'>The unit's doors are shut!</span>")
return
if(!is_operational())
to_chat(user, "<span class='warning'>The unit is not operational!</span>")
return
if(occupant || helmet || suit || storage)
to_chat(user, "<span class='warning'>It's too cluttered inside to fit in!</span>")
return
if(target == user)
user.visible_message("<span class='warning'>[user] starts squeezing into [src]!</span>", "<span class='notice'>You start working your way into [src]...</span>")
else
target.visible_message("<span class='warning'>[user] starts shoving [target] into [src]!</span>", "<span class='userdanger'>[user] starts shoving you into [src]!</span>")
if(do_mob(user, target, 30))
if(occupant || helmet || suit || storage)
return
if(target == user)
user.visible_message("<span class='warning'>[user] slips into [src] and closes the door behind [user.p_them()]!</span>", "<span class=notice'>You slip into [src]'s cramped space and shut its door.</span>")
else
target.visible_message("<span class='warning'>[user] pushes [target] into [src] and shuts its door!<span>", "<span class='userdanger'>[user] shoves you into [src] and shuts the door!</span>")
close_machine(target)
add_fingerprint(user)
/obj/machinery/suit_storage_unit/proc/cook()
var/mob/living/mob_occupant = occupant
if(uv_cycles)
uv_cycles--
uv = TRUE
locked = TRUE
update_icon()
if(occupant)
if(uv_super)
mob_occupant.adjustFireLoss(rand(20, 36))
else
mob_occupant.adjustFireLoss(rand(10, 16))
mob_occupant.emote("scream")
addtimer(CALLBACK(src, .proc/cook), 50)
else
uv_cycles = initial(uv_cycles)
uv = FALSE
locked = FALSE
if(uv_super)
visible_message("<span class='warning'>[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.</span>")
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1)
helmet = null
qdel(helmet)
suit = null
qdel(suit) // Delete everything but the occupant.
mask = null
qdel(mask)
storage = null
qdel(storage)
// The wires get damaged too.
wires.cut_all()
else
if(!occupant)
visible_message("<span class='notice'>[src]'s door slides open. The glowing yellow lights dim to a gentle green.</span>")
else
visible_message("<span class='warning'>[src]'s door slides open, barraging you with the nauseating smell of charred flesh.</span>")
mob_occupant.radiation = 0
playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
var/list/things_to_clear = list() //Done this way since using GetAllContents on the SSU itself would include circuitry and such.
if(suit)
things_to_clear += suit
things_to_clear += suit.GetAllContents()
if(helmet)
things_to_clear += helmet
things_to_clear += helmet.GetAllContents()
if(mask)
things_to_clear += mask
things_to_clear += mask.GetAllContents()
if(storage)
things_to_clear += storage
things_to_clear += storage.GetAllContents()
if(occupant)
things_to_clear += occupant
things_to_clear += occupant.GetAllContents()
for(var/atom/movable/AM in things_to_clear) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
SEND_SIGNAL(AM, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRONG)
AM.clean_blood()
AM.fingerprints = list()
var/datum/component/radioactive/contamination = AM.GetComponent(/datum/component/radioactive)
if(contamination)
qdel(contamination)
open_machine(FALSE)
if(occupant)
dump_contents()
/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
if(!prob(prb))
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(5, 1, src)
s.start()
if(electrocute_mob(user, src, src, 1, TRUE))
return 1
/obj/machinery/suit_storage_unit/relaymove(mob/user)
if(locked)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
return
open_machine()
dump_contents()
/obj/machinery/suit_storage_unit/container_resist(mob/living/user)
if(!locked)
open_machine()
dump_contents()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the doors of [src]!</span>", \
"<span class='notice'>You start kicking against the doors... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a thump from [src].</span>")
if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src )
return
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
"<span class='notice'>You successfully break out of [src]!</span>")
open_machine()
dump_contents()
add_fingerprint(user)
if(locked)
visible_message("<span class='notice'>You see [user] kicking against the doors of [src]!</span>", \
"<span class='notice'>You start kicking against the doors...</span>")
addtimer(CALLBACK(src, .proc/resist_open, user), 300)
else
open_machine()
dump_contents()
/obj/machinery/suit_storage_unit/proc/resist_open(mob/user)
if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here.
visible_message("<span class='notice'>You see [user] burst out of [src]!</span>", \
"<span class='notice'>You escape the cramped confines of [src]!</span>")
open_machine()
/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
if(state_open && is_operational())
if(istype(I, /obj/item/clothing/head/mob_holder))
to_chat(user, "<span class='warning'>You can't quite fit that in while you hold it!</span>")
return
if(istype(I, /obj/item/clothing/suit))
if(suit)
to_chat(user, "<span class='warning'>The unit already contains a suit!.</span>")
return
if(!user.transferItemToLoc(I, src))
return
suit = I
else if(istype(I, /obj/item/clothing/head))
if(helmet)
to_chat(user, "<span class='warning'>The unit already contains a helmet!</span>")
return
if(!user.transferItemToLoc(I, src))
return
helmet = I
else if(istype(I, /obj/item/clothing/mask))
if(mask)
to_chat(user, "<span class='warning'>The unit already contains a mask!</span>")
return
if(!user.transferItemToLoc(I, src))
return
mask = I
else
if(storage)
to_chat(user, "<span class='warning'>The auxiliary storage compartment is full!</span>")
return
if(!user.transferItemToLoc(I, src))
return
storage = I
visible_message("<span class='notice'>[user] inserts [I] into [src]</span>", "<span class='notice'>You load [I] into [src].</span>")
update_icon()
return
if(panel_open && is_wire_tool(I))
wires.interact(user)
return
if(!state_open)
if(default_deconstruction_screwdriver(user, "panel", "close", I))
return
if(default_pry_open(I))
dump_contents()
return
return ..()
/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state)
ui.open()
/obj/machinery/suit_storage_unit/ui_data()
var/list/data = list()
data["locked"] = locked
data["open"] = state_open
data["safeties"] = safeties
data["uv_active"] = uv
data["uv_super"] = uv_super
if(helmet)
data["helmet"] = helmet.name
else
data["helmet"] = null
if(suit)
data["suit"] = suit.name
else
data["suit"] = null
if(mask)
data["mask"] = mask.name
else
data["mask"] = null
if(storage)
data["storage"] = storage.name
else
data["storage"] = null
if(occupant)
data["occupied"] = TRUE
else
data["occupied"] = FALSE
return data
/obj/machinery/suit_storage_unit/ui_act(action, params)
if(..() || uv)
return
switch(action)
if("door")
if(state_open)
close_machine()
else
open_machine(0)
if(occupant)
dump_contents() // Dump out contents if someone is in there.
. = TRUE
if("lock")
if(state_open)
return
locked = !locked
. = TRUE
if("uv")
if(occupant && safeties)
return
else if(!helmet && !mask && !suit && !storage && !occupant)
return
else
if(occupant)
var/mob/living/mob_occupant = occupant
to_chat(mob_occupant, "<span class='userdanger'>[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!</span>")
cook()
. = TRUE
if("dispense")
if(!state_open)
return
var/static/list/valid_items = list("helmet", "suit", "mask", "storage")
var/item_name = params["item"]
if(item_name in valid_items)
var/obj/item/I = vars[item_name]
vars[item_name] = null
if(I)
I.forceMove(loc)
. = TRUE
update_icon()
+2 -2
View File
@@ -79,7 +79,7 @@
/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "mech_bay_power_console", "Mech Bay Power Control Console", 400, 170, master_ui, state)
ui = new(user, src, ui_key, "mech_bay_power_console", "Mech Bay Power Control Console", 400, 200, master_ui, state)
ui.open()
/obj/machinery/computer/mech_bay_power_console/ui_act(action, params)
@@ -96,7 +96,7 @@
if(recharge_port && !QDELETED(recharge_port))
data["recharge_port"] = list("mech" = null)
if(recharge_port.recharging_mech && !QDELETED(recharge_port.recharging_mech))
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null)
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,)
if(recharge_port.recharging_mech.cell && !QDELETED(recharge_port.recharging_mech.cell))
data["recharge_port"]["mech"]["cell"] = list(
"critfail" = recharge_port.recharging_mech.cell.crit_fail,
+3 -4
View File
@@ -246,7 +246,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/pipes)
assets.send(user)
ui = new(user, src, ui_key, "rpd", name, 300, 550, master_ui, state)
ui = new(user, src, ui_key, "rpd", name, 425, 472, master_ui, state)
ui.open()
/obj/item/pipe_dispenser/ui_data(mob/user)
@@ -313,9 +313,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
playeffect = FALSE
if("mode")
var/n = text2num(params["mode"])
if(n == 2 && !(mode&1) && !(mode&2))
mode |= 3
else if(mode&n)
if(mode & n)
mode &= ~n
else
mode |= n
@@ -324,6 +322,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
spark_system.start()
effectcooldown = world.time + 100
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
return TRUE
/obj/item/pipe_dispenser/pre_attack(atom/A, mob/user)
if(!user.IsAdvancedToolUser() || istype(A, /turf/open/space/transit))
+226 -228
View File
@@ -1,228 +1,226 @@
GLOBAL_LIST_EMPTY(GPS_list)
/obj/item/gps
name = "global positioning system"
desc = "Helping lost spacemen find their way through the planets since 2016."
icon = 'icons/obj/telescience.dmi'
icon_state = "gps-c"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
obj_flags = UNIQUE_RENAME
var/gpstag = "COM0"
var/emped = FALSE
var/tracking = TRUE
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
/obj/item/gps/examine(mob/user)
. = ..()
var/turf/curr = get_turf(src)
. += "The screen says: [get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
. += "<span class='notice'>Alt-click to switch it [tracking ? "off":"on"].</span>"
/obj/item/gps/Initialize()
. = ..()
GLOB.GPS_list += src
name = "global positioning system ([gpstag])"
add_overlay("working")
/obj/item/gps/Destroy()
GLOB.GPS_list -= src
return ..()
/obj/item/gps/emp_act(severity)
. = ..()
if (. & EMP_PROTECT_SELF)
return
emped = TRUE
cut_overlay("working")
add_overlay("emp")
addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
SStgui.close_uis(src) //Close the UI control if it is open.
/obj/item/gps/proc/reboot()
emped = FALSE
cut_overlay("emp")
add_overlay("working")
/obj/item/gps/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE))
return
toggletracking(user)
return TRUE
/obj/item/gps/proc/toggletracking(mob/user)
if(!user.canUseTopic(src, BE_CLOSE))
return //user not valid to use gps
if(emped)
to_chat(user, "It's busted!")
return
if(tracking)
cut_overlay("working")
to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
tracking = FALSE
else
add_overlay("working")
to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
tracking = TRUE
/obj/item/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
if(emped)
to_chat(user, "[src] fizzles weakly.")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/gps_window_height = 300 + GLOB.GPS_list.len * 20 // Variable window height, depending on how many GPS units there are to show
ui = new(user, src, ui_key, "gps", "Global Positioning System", 600, gps_window_height, master_ui, state) //width, height
ui.open()
ui.set_autoupdate(state = updating)
/obj/item/gps/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(src)
data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
var/list/signals = list()
data["signals"] = list()
for(var/gps in GLOB.GPS_list)
var/obj/item/gps/G = gps
if(G.emped || !G.tracking || G == src)
continue
var/turf/pos = get_turf(G)
if(!global_mode && pos.z != curr.z)
continue
var/list/signal = list()
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
signal["area"] = get_area_name(G, TRUE)
signal["coord"] = "[pos.x], [pos.y], [pos.z]"
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
var/direction = uppertext(dir2text(get_dir(curr, pos))) //Direction text (East, etc). Not as precise, but still helpful.
if(!direction)
direction = "CENTER"
signal["degrees"] = "N/A"
signal["direction"] = direction
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/obj/item/gps/ui_act(action, params)
if(..())
return
switch(action)
if("rename")
var/a = input("Please enter desired tag.", name, gpstag) as text
a = copytext(sanitize(a), 1, 20)
gpstag = a
. = TRUE
name = "global positioning system ([gpstag])"
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE
/obj/item/gps/science
icon_state = "gps-s"
gpstag = "SCI0"
/obj/item/gps/engineering
icon_state = "gps-e"
gpstag = "ENG0"
/obj/item/gps/mining
icon_state = "gps-m"
gpstag = "MINE0"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
/obj/item/gps/cyborg
icon_state = "gps-b"
gpstag = "BORG0"
desc = "A mining cyborg internal positioning system. Used as a recovery beacon for damaged cyborg assets, or a collaboration tool for mining teams."
/obj/item/gps/cyborg/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
/obj/item/gps/internal
icon_state = null
item_flags = ABSTRACT
gpstag = "Eerie Signal"
desc = "Report to a coder immediately."
invisibility = INVISIBILITY_MAXIMUM
var/obj/item/implant/gps/implant
/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant)
. = ..()
implant = _implant
/obj/item/gps/internal/Destroy()
if(implant?.imp_in)
qdel(implant)
else
return ..()
/obj/item/gps/internal/mining
icon_state = "gps-m"
gpstag = "MINER"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
/obj/item/gps/internal/base
gpstag = "NT_AUX"
desc = "A homing signal from Nanotrasen's mining base."
/obj/item/gps/visible_debug
name = "visible GPS"
gpstag = "ADMIN"
desc = "This admin-spawn GPS unit leaves the coordinates visible \
on any turf that it passes over, for debugging. Especially useful \
for marking the area around the transition edges."
var/list/turf/tagged
/obj/item/gps/visible_debug/Initialize()
. = ..()
tagged = list()
START_PROCESSING(SSfastprocess, src)
/obj/item/gps/visible_debug/process()
var/turf/T = get_turf(src)
if(T)
// I assume it's faster to color,tag and OR the turf in, rather
// then checking if its there
T.color = RANDOM_COLOUR
T.maptext = "[T.x],[T.y],[T.z]"
tagged |= T
/obj/item/gps/visible_debug/proc/clear()
while(tagged.len)
var/turf/T = pop(tagged)
T.color = initial(T.color)
T.maptext = initial(T.maptext)
/obj/item/gps/visible_debug/Destroy()
if(tagged)
clear()
tagged = null
STOP_PROCESSING(SSfastprocess, src)
. = ..()
GLOBAL_LIST_EMPTY(GPS_list)
/obj/item/gps
name = "global positioning system"
desc = "Helping lost spacemen find their way through the planets since 2016."
icon = 'icons/obj/telescience.dmi'
icon_state = "gps-c"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
obj_flags = UNIQUE_RENAME
var/gpstag = "COM0"
var/emped = FALSE
var/tracking = TRUE
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
/obj/item/gps/examine(mob/user)
. = ..()
var/turf/curr = get_turf(src)
. += "The screen says: [get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
. += "<span class='notice'>Alt-click to switch it [tracking ? "off":"on"].</span>"
/obj/item/gps/Initialize()
. = ..()
GLOB.GPS_list += src
name = "global positioning system ([gpstag])"
add_overlay("working")
/obj/item/gps/Destroy()
GLOB.GPS_list -= src
return ..()
/obj/item/gps/emp_act(severity)
. = ..()
if (. & EMP_PROTECT_SELF)
return
emped = TRUE
cut_overlay("working")
add_overlay("emp")
addtimer(CALLBACK(src, .proc/reboot), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
SStgui.close_uis(src) //Close the UI control if it is open.
/obj/item/gps/proc/reboot()
emped = FALSE
cut_overlay("emp")
add_overlay("working")
/obj/item/gps/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, BE_CLOSE))
return
toggletracking(user)
return TRUE
/obj/item/gps/proc/toggletracking(mob/user)
if(!user.canUseTopic(src, BE_CLOSE))
return //user not valid to use gps
if(emped)
to_chat(user, "It's busted!")
return
if(tracking)
cut_overlay("working")
to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
tracking = FALSE
else
add_overlay("working")
to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
tracking = TRUE
/obj/item/gps/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
if(emped)
to_chat(user, "[src] fizzles weakly.")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// Variable window height, depending on how many GPS units there are
// to show, clamped to relatively safe range.
var/gps_window_height = CLAMP(325 + GLOB.GPS_list.len * 14, 325, 700)
ui = new(user, src, ui_key, "gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
ui.open()
ui.set_autoupdate(state = updating)
/obj/item/gps/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(src)
data["current"] = "[get_area_name(curr, TRUE)] ([curr.x], [curr.y], [curr.z])"
data["currentArea"] = "[get_area_name(curr, TRUE)]"
data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
var/list/signals = list()
data["signals"] = list()
for(var/gps in GLOB.GPS_list)
var/obj/item/gps/G = gps
if(G.emped || !G.tracking || G == src)
continue
var/turf/pos = get_turf(G)
if(!global_mode && pos.z != curr.z)
continue
var/list/signal = list()
signal["entrytag"] = G.gpstag //Name or 'tag' of the GPS
signal["coords"] = "[pos.x], [pos.y], [pos.z]"
if(pos.z == curr.z) //Distance/Direction calculations for same z-level only
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(Get_Angle(curr, pos)) //0-360 degree directional bearing, for more precision.
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/obj/item/gps/ui_act(action, params)
if(..())
return
switch(action)
if("rename")
var/a = input("Please enter desired tag.", name, gpstag) as text
a = copytext(sanitize(a), 1, 20)
gpstag = a
. = TRUE
name = "global positioning system ([gpstag])"
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE
/obj/item/gps/science
icon_state = "gps-s"
gpstag = "SCI0"
/obj/item/gps/engineering
icon_state = "gps-e"
gpstag = "ENG0"
/obj/item/gps/mining
icon_state = "gps-m"
gpstag = "MINE0"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
/obj/item/gps/cyborg
icon_state = "gps-b"
gpstag = "BORG0"
desc = "A mining cyborg internal positioning system. Used as a recovery beacon for damaged cyborg assets, or a collaboration tool for mining teams."
/obj/item/gps/cyborg/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
/obj/item/gps/internal
icon_state = null
item_flags = ABSTRACT
gpstag = "Eerie Signal"
desc = "Report to a coder immediately."
invisibility = INVISIBILITY_MAXIMUM
var/obj/item/implant/gps/implant
/obj/item/gps/internal/Initialize(mapload, obj/item/implant/gps/_implant)
. = ..()
implant = _implant
/obj/item/gps/internal/Destroy()
if(implant?.imp_in)
qdel(implant)
else
return ..()
/obj/item/gps/internal/mining
icon_state = "gps-m"
gpstag = "MINER"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
/obj/item/gps/internal/base
gpstag = "NT_AUX"
desc = "A homing signal from Nanotrasen's mining base."
/obj/item/gps/visible_debug
name = "visible GPS"
gpstag = "ADMIN"
desc = "This admin-spawn GPS unit leaves the coordinates visible \
on any turf that it passes over, for debugging. Especially useful \
for marking the area around the transition edges."
var/list/turf/tagged
/obj/item/gps/visible_debug/Initialize()
. = ..()
tagged = list()
START_PROCESSING(SSfastprocess, src)
/obj/item/gps/visible_debug/process()
var/turf/T = get_turf(src)
if(T)
// I assume it's faster to color,tag and OR the turf in, rather
// then checking if its there
T.color = RANDOM_COLOUR
T.maptext = "[T.x],[T.y],[T.z]"
tagged |= T
/obj/item/gps/visible_debug/proc/clear()
while(tagged.len)
var/turf/T = pop(tagged)
T.color = initial(T.color)
T.maptext = initial(T.maptext)
/obj/item/gps/visible_debug/Destroy()
if(tagged)
clear()
tagged = null
STOP_PROCESSING(SSfastprocess, src)
. = ..()
+436 -429
View File
@@ -1,429 +1,436 @@
/obj/item/radio
icon = 'icons/obj/radio.dmi'
name = "station bounced radio"
icon_state = "walkietalkie"
item_state = "walkietalkie"
desc = "A basic handheld radio that communicates with local telecommunication networks."
dog_fashion = /datum/dog_fashion/back
flags_1 = CONDUCT_1 | HEAR_1
slot_flags = ITEM_SLOT_BELT
throw_speed = 3
throw_range = 7
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=75, MAT_GLASS=25)
obj_flags = USES_TGUI
var/on = TRUE
var/frequency = FREQ_COMMON
var/canhear_range = 3 // The range around the radio in which mobs can hear what it receives.
var/emped = 0 // Tracks the number of EMPs currently stacked.
var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby.
var/listening = TRUE // Whether the radio is currently receiving.
var/prison_radio = FALSE // If true, the transmit wire starts cut.
var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering.
var/freerange = FALSE // If true, the radio has access to the full spectrum.
var/subspace_transmission = FALSE // If true, the radio transmits and receives on subspace exclusively.
var/subspace_switchable = FALSE // If true, subspace_transmission can be toggled at will.
var/freqlock = FALSE // Frequency lock to stop the user from untuning specialist radios.
var/use_command = FALSE // If true, broadcasts will be large and BOLD.
var/command = FALSE // If true, use_command can be toggled at will.
var/commandspan = SPAN_COMMAND //allow us to set what the fuck we want for headsets
// Encryption key handling
var/obj/item/encryptionkey/keyslot
var/translate_binary = FALSE // If true, can hear the special binary channel.
var/independent = FALSE // If true, can say/hear on the special CentCom channel.
var/syndie = FALSE // If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel.
var/list/channels = list() // Map from name (see communications.dm) to on/off. First entry is current department (:h).
var/list/secure_radio_connections
var/const/FREQ_LISTENING = 1
//FREQ_BROADCASTING = 2
/obj/item/radio/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return BRUTELOSS
/obj/item/radio/proc/set_frequency(new_frequency)
SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args)
remove_radio(src, frequency)
frequency = add_radio(src, new_frequency)
/obj/item/radio/proc/recalculateChannels()
channels = list()
translate_binary = FALSE
syndie = FALSE
independent = FALSE
if(keyslot)
for(var/ch_name in keyslot.channels)
if(!(ch_name in channels))
channels[ch_name] = keyslot.channels[ch_name]
if(keyslot.translate_binary)
translate_binary = TRUE
if(keyslot.syndie)
syndie = TRUE
if(keyslot.independent)
independent = TRUE
for(var/ch_name in channels)
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
/obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
qdel(keyslot)
keyslot = new /obj/item/encryptionkey/syndicate
syndie = 1
recalculateChannels()
/obj/item/radio/Destroy()
remove_radio_all(src) //Just to be sure
QDEL_NULL(wires)
QDEL_NULL(keyslot)
return ..()
/obj/item/radio/Initialize()
wires = new /datum/wires/radio(src)
if(prison_radio)
wires.cut(WIRE_TX) // OH GOD WHY
secure_radio_connections = new
. = ..()
frequency = sanitize_frequency(frequency, freerange)
set_frequency(frequency)
for(var/ch_name in channels)
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
/obj/item/radio/ComponentInitialize()
. = ..()
AddComponent(/datum/component/empprotection, EMP_PROTECT_WIRES)
/obj/item/radio/interact(mob/user)
if(unscrewed && !isAI(user))
wires.interact(user)
add_fingerprint(user)
else
..()
/obj/item/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
. = ..()
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio", name, 370, 220 + channels.len * 22, master_ui, state)
ui.open()
/obj/item/radio/ui_data(mob/user)
var/list/data = list()
data["broadcasting"] = broadcasting
data["listening"] = listening
data["frequency"] = frequency
data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
data["freqlock"] = freqlock
data["channels"] = list()
for(var/channel in channels)
data["channels"][channel] = channels[channel] & FREQ_LISTENING
data["command"] = command
data["useCommand"] = use_command
data["subspace"] = subspace_transmission
data["subspaceSwitchable"] = subspace_switchable
data["headset"] = istype(src, /obj/item/radio/headset)
return data
/obj/item/radio/ui_act(action, params, datum/tgui/ui)
if(..())
return
switch(action)
if("frequency")
if(freqlock)
return
var/tune = params["tune"]
var/adjust = text2num(params["adjust"])
if(tune == "input")
var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ)
var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ)
tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num
if(!isnull(tune) && !..())
if (tune < MIN_FREE_FREQ && tune <= MAX_FREE_FREQ / 10)
// allow typing 144.7 to get 1447
tune *= 10
. = TRUE
else if(adjust)
tune = frequency + adjust * 10
. = TRUE
else if(text2num(tune) != null)
tune = tune * 10
. = TRUE
if(.)
set_frequency(sanitize_frequency(tune, freerange))
if("listen")
listening = !listening
. = TRUE
if("broadcast")
broadcasting = !broadcasting
. = TRUE
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
. = TRUE
if("command")
use_command = !use_command
. = TRUE
if("subspace")
if(subspace_switchable)
subspace_transmission = !subspace_transmission
if(!subspace_transmission)
channels = list()
else
recalculateChannels()
. = TRUE
/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
if(!spans)
spans = list(M.speech_span)
if(!language)
language = M.get_default_language()
INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
return ITALICS | REDUCE_RANGE
/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language)
if(!on)
return // the device has to be on
if(!M || !message)
return
if(wires.is_cut(WIRE_TX)) // Permacell and otherwise tampered-with radios
return
if(!M.IsVocal())
return
if(use_command)
spans |= commandspan
/*
Roughly speaking, radios attempt to make a subspace transmission (which
is received, processed, and rebroadcast by the telecomms satellite) and
if that fails, they send a mundane radio transmission.
Headsets cannot send/receive mundane transmissions, only subspace.
Syndicate radios can hear transmissions on all well-known frequencies.
CentCom radios can hear the CentCom frequency no matter what.
*/
// From the channel, determine the frequency and get a reference to it.
var/freq
if(channel && channels && channels.len > 0)
if(channel == MODE_DEPARTMENT)
channel = channels[1]
freq = secure_radio_connections[channel]
if (!channels[channel]) // if the channel is turned off, don't broadcast
return
else
freq = frequency
channel = null
// Nearby active jammers severely gibberish the message
var/turf/position = get_turf(src)
for(var/obj/item/jammer/jammer in GLOB.active_jammers)
var/turf/jammer_turf = get_turf(jammer)
if(position.z == jammer_turf.z && (get_dist(position, jammer_turf) < jammer.range))
message = Gibberish(message,100)
break
// Determine the identity information which will be attached to the signal.
var/atom/movable/virtualspeaker/speaker = new(null, M, src)
// Construct the signal
var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans)
// Independent radios, on the CentCom frequency, reach all independent radios
if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE))
signal.data["compression"] = 0
signal.transmission_method = TRANSMISSION_SUPERSPACE
signal.levels = list(0) // reaches all Z-levels
signal.broadcast()
return
// All radios make an attempt to use the subspace system first
signal.send_to_receivers()
// If the radio is subspace-only, that's all it can do
if (subspace_transmission)
return
// Non-subspace radios will check in a couple of seconds, and if the signal
// was never received, send a mundane broadcast (no headsets).
addtimer(CALLBACK(src, .proc/backup_transmission, signal), 20)
/obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal)
var/turf/T = get_turf(src)
if (signal.data["done"] && (T.z in signal.levels))
return
// Okay, the signal was never processed, send a mundane broadcast.
signal.data["compression"] = 0
signal.transmission_method = TRANSMISSION_RADIO
signal.levels = list(T.z)
signal.broadcast()
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
return
if(message_mode == MODE_WHISPER || message_mode == MODE_WHISPER_CRIT)
// radios don't pick up whispers very well
raw_message = stars(raw_message)
else if(message_mode == MODE_L_HAND || message_mode == MODE_R_HAND)
// try to avoid being heard double
if (loc == speaker && ismob(speaker))
var/mob/M = speaker
var/idx = M.get_held_index_of_item(src)
// left hands are odd slots
if (idx && (idx % 2) == (message_mode == MODE_L_HAND))
return
talk_into(speaker, raw_message, , spans, language=message_language)
// Checks if this radio can receive on the given frequency.
/obj/item/radio/proc/can_receive(freq, level)
// deny checks
if (!on || !listening || wires.is_cut(WIRE_RX))
return FALSE
if (freq == FREQ_SYNDICATE && !syndie)
return FALSE
if (freq == FREQ_CENTCOM)
return independent // hard-ignores the z-level check
if (!(0 in level))
var/turf/position = get_turf(src)
if(!position || !(position.z in level))
return FALSE
// allow checks: are we listening on that frequency?
if (freq == frequency)
return TRUE
for(var/ch_name in channels)
if(channels[ch_name] & FREQ_LISTENING)
//the GLOB.radiochannels list is located in communications.dm
if(GLOB.radiochannels[ch_name] == text2num(freq) || syndie)
return TRUE
return FALSE
/obj/item/radio/examine(mob/user)
. = ..()
if (unscrewed)
. += "<span class='notice'>It can be attached and modified.</span>"
else
. += "<span class='notice'>It cannot be modified or attached.</span>"
/obj/item/radio/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
if(istype(W, /obj/item/screwdriver))
unscrewed = !unscrewed
if(unscrewed)
to_chat(user, "<span class='notice'>The radio can now be attached and modified!</span>")
else
to_chat(user, "<span class='notice'>The radio can no longer be modified or attached!</span>")
else
return ..()
/obj/item/radio/emp_act(severity)
. = ..()
if (. & EMP_PROTECT_SELF)
return
emped++ //There's been an EMP; better count it
var/curremp = emped //Remember which EMP this was
if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice
to_chat(loc, "<span class='warning'>\The [src] overloads.</span>")
broadcasting = FALSE
listening = FALSE
for (var/ch_name in channels)
channels[ch_name] = 0
on = FALSE
spawn(200)
if(emped == curremp) //Don't fix it if it's been EMP'd again
emped = 0
if (!istype(src, /obj/item/radio/intercom)) // intercoms will turn back on on their own
on = TRUE
///////////////////////////////
//////////Borg Radios//////////
///////////////////////////////
//Giving borgs their own radio to have some more room to work with -Sieve
/obj/item/radio/borg
name = "cyborg radio"
subspace_switchable = TRUE
dog_fashion = null
/obj/item/radio/borg/Initialize(mapload)
. = ..()
/obj/item/radio/borg/syndicate
syndie = 1
keyslot = new /obj/item/encryptionkey/syndicate
/obj/item/radio/borg/syndicate/Initialize()
. = ..()
set_frequency(FREQ_SYNDICATE)
/obj/item/radio/borg/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/screwdriver))
if(keyslot)
for(var/ch_name in channels)
SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
if(keyslot)
var/turf/T = get_turf(user)
if(T)
keyslot.forceMove(T)
keyslot = null
recalculateChannels()
to_chat(user, "<span class='notice'>You pop out the encryption key in the radio.</span>")
else
to_chat(user, "<span class='warning'>This radio doesn't have any encryption keys!</span>")
else if(istype(W, /obj/item/encryptionkey/))
if(keyslot)
to_chat(user, "<span class='warning'>The radio can't hold another key!</span>")
return
if(!keyslot)
if(!user.transferItemToLoc(W, src))
return
keyslot = W
recalculateChannels()
/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
listening = 0 // And it's nice to have a subtype too for future features.
dog_fashion = /datum/dog_fashion/back
/obj/item/radio/internal
var/obj/item/implant/radio/implant
/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant)
. = ..()
implant = _implant
/obj/item/radio/internal/Destroy()
if(implant?.imp_in)
qdel(implant)
else
return ..()
/obj/item/radio
icon = 'icons/obj/radio.dmi'
name = "station bounced radio"
icon_state = "walkietalkie"
item_state = "walkietalkie"
desc = "A basic handheld radio that communicates with local telecommunication networks."
dog_fashion = /datum/dog_fashion/back
flags_1 = CONDUCT_1 | HEAR_1
slot_flags = ITEM_SLOT_BELT
throw_speed = 3
throw_range = 7
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=75, MAT_GLASS=25)
obj_flags = USES_TGUI
var/on = TRUE
var/frequency = FREQ_COMMON
var/canhear_range = 3 // The range around the radio in which mobs can hear what it receives.
var/emped = 0 // Tracks the number of EMPs currently stacked.
var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby.
var/listening = TRUE // Whether the radio is currently receiving.
var/prison_radio = FALSE // If true, the transmit wire starts cut.
var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering.
var/freerange = FALSE // If true, the radio has access to the full spectrum.
var/subspace_transmission = FALSE // If true, the radio transmits and receives on subspace exclusively.
var/subspace_switchable = FALSE // If true, subspace_transmission can be toggled at will.
var/freqlock = FALSE // Frequency lock to stop the user from untuning specialist radios.
var/use_command = FALSE // If true, broadcasts will be large and BOLD.
var/command = FALSE // If true, use_command can be toggled at will.
var/commandspan = SPAN_COMMAND //allow us to set what the fuck we want for headsets
// Encryption key handling
var/obj/item/encryptionkey/keyslot
var/translate_binary = FALSE // If true, can hear the special binary channel.
var/independent = FALSE // If true, can say/hear on the special CentCom channel.
var/syndie = FALSE // If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel.
var/list/channels = list() // Map from name (see communications.dm) to on/off. First entry is current department (:h).
var/list/secure_radio_connections
var/const/FREQ_LISTENING = 1
//FREQ_BROADCASTING = 2
/obj/item/radio/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return BRUTELOSS
/obj/item/radio/proc/set_frequency(new_frequency)
SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args)
remove_radio(src, frequency)
frequency = add_radio(src, new_frequency)
/obj/item/radio/proc/recalculateChannels()
channels = list()
translate_binary = FALSE
syndie = FALSE
independent = FALSE
if(keyslot)
for(var/ch_name in keyslot.channels)
if(!(ch_name in channels))
channels[ch_name] = keyslot.channels[ch_name]
if(keyslot.translate_binary)
translate_binary = TRUE
if(keyslot.syndie)
syndie = TRUE
if(keyslot.independent)
independent = TRUE
for(var/ch_name in channels)
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
/obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
qdel(keyslot)
keyslot = new /obj/item/encryptionkey/syndicate
syndie = 1
recalculateChannels()
/obj/item/radio/Destroy()
remove_radio_all(src) //Just to be sure
QDEL_NULL(wires)
QDEL_NULL(keyslot)
return ..()
/obj/item/radio/Initialize()
wires = new /datum/wires/radio(src)
if(prison_radio)
wires.cut(WIRE_TX) // OH GOD WHY
secure_radio_connections = new
. = ..()
frequency = sanitize_frequency(frequency, freerange)
set_frequency(frequency)
for(var/ch_name in channels)
secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name])
/obj/item/radio/ComponentInitialize()
. = ..()
AddComponent(/datum/component/empprotection, EMP_PROTECT_WIRES)
/obj/item/radio/interact(mob/user)
if(unscrewed && !isAI(user))
wires.interact(user)
add_fingerprint(user)
else
..()
/obj/item/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
. = ..()
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/ui_width = 360
var/ui_height = 106
if(subspace_transmission)
if(channels.len > 0)
ui_height += 6 + channels.len * 21
else
ui_height += 24
ui = new(user, src, ui_key, "radio", name, ui_width, ui_height, master_ui, state)
ui.open()
/obj/item/radio/ui_data(mob/user)
var/list/data = list()
data["broadcasting"] = broadcasting
data["listening"] = listening
data["frequency"] = frequency
data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
data["freqlock"] = freqlock
data["channels"] = list()
for(var/channel in channels)
data["channels"][channel] = channels[channel] & FREQ_LISTENING
data["command"] = command
data["useCommand"] = use_command
data["subspace"] = subspace_transmission
data["subspaceSwitchable"] = subspace_switchable
data["headset"] = istype(src, /obj/item/radio/headset)
return data
/obj/item/radio/ui_act(action, params, datum/tgui/ui)
if(..())
return
switch(action)
if("frequency")
if(freqlock)
return
var/tune = params["tune"]
var/adjust = text2num(params["adjust"])
if(tune == "input")
var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ)
var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ)
tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num
if(!isnull(tune) && !..())
if (tune < MIN_FREE_FREQ && tune <= MAX_FREE_FREQ / 10)
// allow typing 144.7 to get 1447
tune *= 10
. = TRUE
else if(adjust)
tune = frequency + adjust * 10
. = TRUE
else if(text2num(tune) != null)
tune = tune * 10
. = TRUE
if(.)
set_frequency(sanitize_frequency(tune, freerange))
if("listen")
listening = !listening
. = TRUE
if("broadcast")
broadcasting = !broadcasting
. = TRUE
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
. = TRUE
if("command")
use_command = !use_command
. = TRUE
if("subspace")
if(subspace_switchable)
subspace_transmission = !subspace_transmission
if(!subspace_transmission)
channels = list()
else
recalculateChannels()
. = TRUE
/obj/item/radio/talk_into(atom/movable/M, message, channel, list/spans, datum/language/language)
if(!spans)
spans = list(M.speech_span)
if(!language)
language = M.get_default_language()
INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language)
return ITALICS | REDUCE_RANGE
/obj/item/radio/proc/talk_into_impl(atom/movable/M, message, channel, list/spans, datum/language/language)
if(!on)
return // the device has to be on
if(!M || !message)
return
if(wires.is_cut(WIRE_TX)) // Permacell and otherwise tampered-with radios
return
if(!M.IsVocal())
return
if(use_command)
spans |= commandspan
/*
Roughly speaking, radios attempt to make a subspace transmission (which
is received, processed, and rebroadcast by the telecomms satellite) and
if that fails, they send a mundane radio transmission.
Headsets cannot send/receive mundane transmissions, only subspace.
Syndicate radios can hear transmissions on all well-known frequencies.
CentCom radios can hear the CentCom frequency no matter what.
*/
// From the channel, determine the frequency and get a reference to it.
var/freq
if(channel && channels && channels.len > 0)
if(channel == MODE_DEPARTMENT)
channel = channels[1]
freq = secure_radio_connections[channel]
if (!channels[channel]) // if the channel is turned off, don't broadcast
return
else
freq = frequency
channel = null
// Nearby active jammers severely gibberish the message
var/turf/position = get_turf(src)
for(var/obj/item/jammer/jammer in GLOB.active_jammers)
var/turf/jammer_turf = get_turf(jammer)
if(position.z == jammer_turf.z && (get_dist(position, jammer_turf) < jammer.range))
message = Gibberish(message,100)
break
// Determine the identity information which will be attached to the signal.
var/atom/movable/virtualspeaker/speaker = new(null, M, src)
// Construct the signal
var/datum/signal/subspace/vocal/signal = new(src, freq, speaker, language, message, spans)
// Independent radios, on the CentCom frequency, reach all independent radios
if (independent && (freq == FREQ_CENTCOM || freq == FREQ_CTF_RED || freq == FREQ_CTF_BLUE))
signal.data["compression"] = 0
signal.transmission_method = TRANSMISSION_SUPERSPACE
signal.levels = list(0) // reaches all Z-levels
signal.broadcast()
return
// All radios make an attempt to use the subspace system first
signal.send_to_receivers()
// If the radio is subspace-only, that's all it can do
if (subspace_transmission)
return
// Non-subspace radios will check in a couple of seconds, and if the signal
// was never received, send a mundane broadcast (no headsets).
addtimer(CALLBACK(src, .proc/backup_transmission, signal), 20)
/obj/item/radio/proc/backup_transmission(datum/signal/subspace/vocal/signal)
var/turf/T = get_turf(src)
if (signal.data["done"] && (T.z in signal.levels))
return
// Okay, the signal was never processed, send a mundane broadcast.
signal.data["compression"] = 0
signal.transmission_method = TRANSMISSION_RADIO
signal.levels = list(T.z)
signal.broadcast()
/obj/item/radio/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
. = ..()
if(radio_freq || !broadcasting || get_dist(src, speaker) > canhear_range)
return
if(message_mode == MODE_WHISPER || message_mode == MODE_WHISPER_CRIT)
// radios don't pick up whispers very well
raw_message = stars(raw_message)
else if(message_mode == MODE_L_HAND || message_mode == MODE_R_HAND)
// try to avoid being heard double
if (loc == speaker && ismob(speaker))
var/mob/M = speaker
var/idx = M.get_held_index_of_item(src)
// left hands are odd slots
if (idx && (idx % 2) == (message_mode == MODE_L_HAND))
return
talk_into(speaker, raw_message, , spans, language=message_language)
// Checks if this radio can receive on the given frequency.
/obj/item/radio/proc/can_receive(freq, level)
// deny checks
if (!on || !listening || wires.is_cut(WIRE_RX))
return FALSE
if (freq == FREQ_SYNDICATE && !syndie)
return FALSE
if (freq == FREQ_CENTCOM)
return independent // hard-ignores the z-level check
if (!(0 in level))
var/turf/position = get_turf(src)
if(!position || !(position.z in level))
return FALSE
// allow checks: are we listening on that frequency?
if (freq == frequency)
return TRUE
for(var/ch_name in channels)
if(channels[ch_name] & FREQ_LISTENING)
//the GLOB.radiochannels list is located in communications.dm
if(GLOB.radiochannels[ch_name] == text2num(freq) || syndie)
return TRUE
return FALSE
/obj/item/radio/examine(mob/user)
. = ..()
if (unscrewed)
. += "<span class='notice'>It can be attached and modified.</span>"
else
. += "<span class='notice'>It cannot be modified or attached.</span>"
/obj/item/radio/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
if(istype(W, /obj/item/screwdriver))
unscrewed = !unscrewed
if(unscrewed)
to_chat(user, "<span class='notice'>The radio can now be attached and modified!</span>")
else
to_chat(user, "<span class='notice'>The radio can no longer be modified or attached!</span>")
else
return ..()
/obj/item/radio/emp_act(severity)
. = ..()
if (. & EMP_PROTECT_SELF)
return
emped++ //There's been an EMP; better count it
var/curremp = emped //Remember which EMP this was
if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice
to_chat(loc, "<span class='warning'>\The [src] overloads.</span>")
broadcasting = FALSE
listening = FALSE
for (var/ch_name in channels)
channels[ch_name] = 0
on = FALSE
spawn(200)
if(emped == curremp) //Don't fix it if it's been EMP'd again
emped = 0
if (!istype(src, /obj/item/radio/intercom)) // intercoms will turn back on on their own
on = TRUE
///////////////////////////////
//////////Borg Radios//////////
///////////////////////////////
//Giving borgs their own radio to have some more room to work with -Sieve
/obj/item/radio/borg
name = "cyborg radio"
subspace_switchable = TRUE
dog_fashion = null
/obj/item/radio/borg/Initialize(mapload)
. = ..()
/obj/item/radio/borg/syndicate
syndie = 1
keyslot = new /obj/item/encryptionkey/syndicate
/obj/item/radio/borg/syndicate/Initialize()
. = ..()
set_frequency(FREQ_SYNDICATE)
/obj/item/radio/borg/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/screwdriver))
if(keyslot)
for(var/ch_name in channels)
SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
if(keyslot)
var/turf/T = get_turf(user)
if(T)
keyslot.forceMove(T)
keyslot = null
recalculateChannels()
to_chat(user, "<span class='notice'>You pop out the encryption key in the radio.</span>")
else
to_chat(user, "<span class='warning'>This radio doesn't have any encryption keys!</span>")
else if(istype(W, /obj/item/encryptionkey/))
if(keyslot)
to_chat(user, "<span class='warning'>The radio can't hold another key!</span>")
return
if(!keyslot)
if(!user.transferItemToLoc(W, src))
return
keyslot = W
recalculateChannels()
/obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
listening = 0 // And it's nice to have a subtype too for future features.
dog_fashion = /datum/dog_fashion/back
/obj/item/radio/internal
var/obj/item/implant/radio/implant
/obj/item/radio/internal/Initialize(mapload, obj/item/implant/radio/_implant)
. = ..()
implant = _implant
/obj/item/radio/internal/Destroy()
if(implant?.imp_in)
qdel(implant)
else
return ..()
+1 -1
View File
@@ -156,7 +156,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "tanks", name, 420, 200, master_ui, state)
ui = new(user, src, ui_key, "tanks", name, 400, 120, master_ui, state)
ui.open()
/obj/item/tank/ui_data(mob/user)
@@ -12,9 +12,11 @@
roundstart = FALSE
death = FALSE
mob_species = /datum/species/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 \
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>"
short_desc = "You are a sentient ecosystem, an example of the mastery over life that your creators possessed."
flavour_text = "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, 5000 millennia ago."
assignedrole = "Lifebringer"
/obj/effect/mob_spawn/human/seed_vault/special(mob/living/new_spawn)
@@ -47,8 +49,10 @@
death = FALSE
anchored = FALSE
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 would never leave its beautiful expanse. \
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.</b>"
short_desc = "You are an ash walker. Your tribe worships the Necropolis."
flavour_text = "The wastes are sacred ground, its monsters a blessed bounty. You would never leave its sacred ground. \
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/new_spawn)
@@ -87,8 +91,9 @@
roundstart = FALSE
death = FALSE
mob_species = /datum/species/shadow
flavour_text = "<span class='big bold'>You are cursed.</span><b> Years ago, you sacrificed the lives of your trusted friends and the humanity of yourself to reach the Wish Granter. Though you \
did so, it has come at a cost: your very body rejects the light, dooming you to wander endlessly in this horrible wasteland.</b>"
short_desc = "You are cursed."
flavour_text = "Years ago, you sacrificed the lives of your trusted friends and the humanity of yourself to reach the Wish Granter. Though you \
did so, it has come at a cost: your very body rejects the light, dooming you to wander endlessly in this horrible wasteland."
assignedrole = "Exile"
/obj/effect/mob_spawn/human/exile/Destroy()
@@ -124,9 +129,10 @@
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 \
short_desc = "You are a Free Golem. Your family worships The Liberator."
flavour_text = "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 ..()
@@ -137,8 +143,9 @@
if(!mapload && A)
notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_GOLEM, ignore_dnr_observers = TRUE)
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>"
short_desc = "You are a golem."
flavour_text = "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."
important_info = "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)
@@ -211,8 +218,9 @@
death = FALSE
random = 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 \
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 \
short_desc = "You've been stranded in this godless prison of a planet for longer than you can remember."
flavour_text = "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"
@@ -223,20 +231,20 @@
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/sneakers/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/rank/prisoner
outfit.shoes = /obj/item/clothing/shoes/sneakers/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/toggle/labcoat
outfit.back = /obj/item/storage/backpack/medic
@@ -244,7 +252,7 @@
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 \
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/sneakers/black
outfit.back = /obj/item/storage/backpack
@@ -283,8 +291,9 @@
outfit = /datum/outfit/lavalandprisoner
roundstart = FALSE
death = FALSE
flavour_text = "<b>Good. It seems as though your ship crashed. <span class='big bold'>You're a prisoner,</span> sentenced to hard work in one of Nanotrasen's labor camps, but it seems as \
though fate has other plans for you. You remember that you were convicted of "
short_desc = "You're a prisoner, sentenced to hard work in one of Nanotrasen's labor camps, but it seems as \
though fate has other plans for you."
flavour_text = "Good. It seems as though your ship crashed. You remember that you were convicted of "
assignedrole = "Escaped Prisoner"
/obj/effect/mob_spawn/human/prisoner_transport/special(mob/living/L)
@@ -296,7 +305,7 @@
var/list/crimes = list("murder", "larceny", "embezzlement", "unionization", "dereliction of duty", "kidnapping", "gross incompetence", "grand theft", "collaboration with the Syndicate", \
"worship of a forbidden deity", "interspecies relations", "mutiny")
flavour_text += "[pick(crimes)]. but regardless of that, it seems like your crime doesn't matter now. You don't know where you are, but you know that it's out to kill you, and you're not going \
to lose this opportunity. Find a way to get out of this mess and back to where you rightfully belong - your [pick("house", "apartment", "spaceship", "station")]</b>."
to lose this opportunity. Find a way to get out of this mess and back to where you rightfully belong - your [pick("house", "apartment", "spaceship", "station")]."
/datum/outfit/lavalandprisoner
name = "Lavaland Prisoner"
@@ -323,8 +332,9 @@
roundstart = FALSE
random = TRUE
outfit = /datum/outfit/hotelstaff
flavour_text = "<span class='big bold'>You are a staff member of a top-of-the-line space hotel!</span><b> Cater to guests and <font size=6><b>DON'T</b></font> leave the hotel, lest the manager fire you for\
dereliction of duty!</b>"
short_desc = "You are a staff member of a top-of-the-line space hotel!"
flavour_text = "You are a staff member of a top-of-the-line space hotel! Cater to guests and make sure the manager doesn't fire you."
important_info = "DON'T leave the hotel"
assignedrole = "Hotel Staff"
/datum/outfit/hotelstaff
@@ -341,8 +351,10 @@
mob_name = "hotel security member"
job_description = "Hotel Security"
outfit = /datum/outfit/hotelstaff/security
flavour_text = "<span class='big bold'>You are a peacekeeper</span><b> assigned to this hotel to protect the interests of the company while keeping the peace between \
guests and the staff. Do <font size=6>NOT</font> leave the hotel, as that is grounds for contract termination.</b>"
short_desc = "You are a peacekeeper."
flavour_text = "You have been assigned to this hotel to protect the interests of the company while keeping the peace between \
guests and the staff."
important_info = "Do NOT leave the hotel, as that is grounds for contract termination."
objectives = "Do not leave your assigned hotel. Try and keep the peace between staff and guests, non-lethal force heavily advised if possible."
/datum/outfit/hotelstaff/security
@@ -381,7 +393,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, they can send you back to hell with a single thought. [owner.name]'s death will also return you to hell.</b>"
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."
important_info = "Be aware that if you do not live up to [owner.name]'s expectations, 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 = FALSE, ignore_dnr_observers = TRUE)
@@ -439,9 +452,9 @@
/obj/effect/mob_spawn/human/syndicate/battlecruiser
name = "Syndicate Battlecruiser Ship Operative"
flavour_text = "<span class='big bold'>You are a crewmember aboard the syndicate flagship: the SBC Starfury.</span><span class='big'> <span class='danger'><b>Your job is to follow your captain's orders, maintain the ship, and keep the engine running.</b></span> If you are not familiar with how the supermatter engine functions: <b>do not attempt to start it.</b><br>\
<br>\
<span class='danger'><b>The armory is not a candy store, and your role is not to assault the station directly, leave that work to the assault operatives.</b></span></font>"
short_desc = "You are a crewmember aboard the syndicate flagship: the SBC Starfury."
flavour_text = "Your job is to follow your captain's orders, maintain the ship, and keep the engine running. If you are not familiar with how the supermatter engine functions: do not attempt to start it."
important_info = "The armory is not a candy store, and your role is not to assault the station directly, leave that work to the assault operatives."
outfit = /datum/outfit/syndicate_empty/SBC
/datum/outfit/syndicate_empty/SBC
@@ -451,10 +464,9 @@
belt = /obj/item/storage/belt/military/assault
/obj/effect/mob_spawn/human/syndicate/battlecruiser/assault
name = "Syndicate Battlecruiser Assault Operative"
flavour_text = "<span class='big bold'>You are an assault operative aboard the syndicate flagship: the SBC Starfury.</span><span class='big'> <span class='danger'><b>Your job is to follow your captain's orders, keep intruders out of the ship, and assault Space Station 13.</b></span> There is an armory, multiple assault ships, and beam cannons to attack the station with.<br>\
<br>\
<span class='danger'><b>Work as a team with your fellow operatives and work out a plan of attack. If you are overwhelmed, escape back to your ship!</b></span></span>"
short_desc = "You are an assault operative aboard the syndicate flagship: the SBC Starfury."
flavour_text = "Your job is to follow your captain's orders, keep intruders out of the ship, and assault Space Station 13. There is an armory, multiple assault ships, and beam cannons to attack the station with."
important_info = "Work as a team with your fellow operatives and work out a plan of attack. If you are overwhelmed, escape back to your ship!"
outfit = /datum/outfit/syndicate_empty/SBC/assault
/datum/outfit/syndicate_empty/SBC/assault
@@ -470,9 +482,9 @@
/obj/effect/mob_spawn/human/syndicate/battlecruiser/captain
name = "Syndicate Battlecruiser Captain"
flavour_text = "<span class='big bold'>You are the captain aboard the syndicate flagship: the SBC Starfury.</span><span class='big'> <span class='danger'><b>Your job is to oversee your crew, defend the ship, and destroy Space Station 13.</b></span> The ship has an armory, multiple ships, beam cannons, and multiple crewmembers to accomplish this goal.<br>\
<br>\
<span class='danger'><b>As the captain, this whole operation falls on your shoulders.</b></span> You do not need to nuke the station, causing sufficient damage and preventing your ship from being destroyed will be enough.</span>"
short_desc = "You are the captain aboard the syndicate flagship: the SBC Starfury."
flavour_text = "Your job is to oversee your crew, defend the ship, and destroy Space Station 13. The ship has an armory, multiple ships, beam cannons, and multiple crewmembers to accomplish this goal."
important_info = "As the captain, this whole operation falls on your shoulders. You do not need to nuke the station, causing sufficient damage and preventing your ship from being destroyed will be enough."
outfit = /datum/outfit/syndicate_empty/SBC/assault/captain
id_access_list = list(150,151)
@@ -498,10 +510,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 \
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>"
short_desc = "You are a security officer working for Nanotrasen, stationed onboard a state of the art research station."
flavour_text = "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."
important_info = "Work as a team with your fellow survivors and do not abandon them."
uniform = /obj/item/clothing/under/rank/security
shoes = /obj/item/clothing/shoes/jackboots
id = /obj/item/card/id/away/old/sec
@@ -525,10 +538,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 \
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>"
short_desc = "You are an engineer working for Nanotrasen, stationed onboard a state of the art research station."
flavour_text = "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."
important_info = "Work as a team with your fellow survivors and do not abandon them."
uniform = /obj/item/clothing/under/rank/engineer
shoes = /obj/item/clothing/shoes/workboots
id = /obj/item/card/id/away/old/eng
@@ -550,10 +564,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 \
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>"
short_desc = "You are a scientist working for Nanotrasen, stationed onboard a state of the art research station."
flavour_text = "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."
important_info = "Work as a team with your fellow survivors and do not abandon them."
uniform = /obj/item/clothing/under/rank/scientist
shoes = /obj/item/clothing/shoes/laceup
id = /obj/item/card/id/away/old/sci
@@ -580,7 +595,8 @@
anchored = TRUE
density = FALSE
show_flavour = FALSE //Flavour only exists for spawners menu
flavour_text = "<span class='big bold'>You are a space pirate.</span><b> The station refused to pay for your protection, protect the ship, siphon the credits from the station and raid it for even more loot.</b>"
short_desc = "You are a space pirate."
flavour_text = "The station refused to pay for your protection, protect the ship, siphon the credits from the station and raid it for even more loot."
assignedrole = "Space Pirate"
var/rank = "Mate"
+111 -111
View File
@@ -1,111 +1,111 @@
#define TANK_DISPENSER_CAPACITY 10
/obj/structure/tank_dispenser
name = "tank dispenser"
desc = "A simple yet bulky storage device for gas tanks. Holds up to 10 oxygen tanks and 10 plasma tanks."
icon = 'icons/obj/objects.dmi'
icon_state = "dispenser"
density = TRUE
anchored = TRUE
max_integrity = 300
var/oxygentanks = TANK_DISPENSER_CAPACITY
var/plasmatanks = TANK_DISPENSER_CAPACITY
/obj/structure/tank_dispenser/oxygen
plasmatanks = 0
/obj/structure/tank_dispenser/plasma
oxygentanks = 0
/obj/structure/tank_dispenser/Initialize()
. = ..()
for(var/i in 1 to oxygentanks)
new /obj/item/tank/internals/oxygen(src)
for(var/i in 1 to plasmatanks)
new /obj/item/tank/internals/plasma(src)
update_icon()
/obj/structure/tank_dispenser/update_icon()
cut_overlays()
switch(oxygentanks)
if(1 to 3)
add_overlay("oxygen-[oxygentanks]")
if(4 to TANK_DISPENSER_CAPACITY)
add_overlay("oxygen-4")
switch(plasmatanks)
if(1 to 4)
add_overlay("plasma-[plasmatanks]")
if(5 to TANK_DISPENSER_CAPACITY)
add_overlay("plasma-5")
/obj/structure/tank_dispenser/attackby(obj/item/I, mob/user, params)
var/full
if(istype(I, /obj/item/tank/internals/plasma))
if(plasmatanks < TANK_DISPENSER_CAPACITY)
plasmatanks++
else
full = TRUE
else if(istype(I, /obj/item/tank/internals/oxygen))
if(oxygentanks < TANK_DISPENSER_CAPACITY)
oxygentanks++
else
full = TRUE
else if(istype(I, /obj/item/wrench))
default_unfasten_wrench(user, I, time = 20)
return
else if(user.a_intent != INTENT_HARM)
to_chat(user, "<span class='notice'>[I] does not fit into [src].</span>")
return
else
return ..()
if(full)
to_chat(user, "<span class='notice'>[src] can't hold any more of [I].</span>")
return
if(!user.transferItemToLoc(I, src))
return
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
update_icon()
/obj/structure/tank_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "tank_dispenser", name, 275, 100, master_ui, state)
ui.open()
/obj/structure/tank_dispenser/ui_data(mob/user)
var/list/data = list()
data["oxygen"] = oxygentanks
data["plasma"] = plasmatanks
return data
/obj/structure/tank_dispenser/ui_act(action, params)
if(..())
return
switch(action)
if("plasma")
var/obj/item/tank/internals/plasma/tank = locate() in src
if(tank && Adjacent(usr))
usr.put_in_hands(tank)
plasmatanks--
. = TRUE
if("oxygen")
var/obj/item/tank/internals/oxygen/tank = locate() in src
if(tank && Adjacent(usr))
usr.put_in_hands(tank)
oxygentanks--
. = TRUE
update_icon()
/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
for(var/X in src)
var/obj/item/I = X
I.forceMove(loc)
new /obj/item/stack/sheet/metal (loc, 2)
qdel(src)
#undef TANK_DISPENSER_CAPACITY
#define TANK_DISPENSER_CAPACITY 10
/obj/structure/tank_dispenser
name = "tank dispenser"
desc = "A simple yet bulky storage device for gas tanks. Holds up to 10 oxygen tanks and 10 plasma tanks."
icon = 'icons/obj/objects.dmi'
icon_state = "dispenser"
density = TRUE
anchored = TRUE
max_integrity = 300
var/oxygentanks = TANK_DISPENSER_CAPACITY
var/plasmatanks = TANK_DISPENSER_CAPACITY
/obj/structure/tank_dispenser/oxygen
plasmatanks = 0
/obj/structure/tank_dispenser/plasma
oxygentanks = 0
/obj/structure/tank_dispenser/Initialize()
. = ..()
for(var/i in 1 to oxygentanks)
new /obj/item/tank/internals/oxygen(src)
for(var/i in 1 to plasmatanks)
new /obj/item/tank/internals/plasma(src)
update_icon()
/obj/structure/tank_dispenser/update_icon()
cut_overlays()
switch(oxygentanks)
if(1 to 3)
add_overlay("oxygen-[oxygentanks]")
if(4 to TANK_DISPENSER_CAPACITY)
add_overlay("oxygen-4")
switch(plasmatanks)
if(1 to 4)
add_overlay("plasma-[plasmatanks]")
if(5 to TANK_DISPENSER_CAPACITY)
add_overlay("plasma-5")
/obj/structure/tank_dispenser/attackby(obj/item/I, mob/user, params)
var/full
if(istype(I, /obj/item/tank/internals/plasma))
if(plasmatanks < TANK_DISPENSER_CAPACITY)
plasmatanks++
else
full = TRUE
else if(istype(I, /obj/item/tank/internals/oxygen))
if(oxygentanks < TANK_DISPENSER_CAPACITY)
oxygentanks++
else
full = TRUE
else if(istype(I, /obj/item/wrench))
default_unfasten_wrench(user, I, time = 20)
return
else if(user.a_intent != INTENT_HARM)
to_chat(user, "<span class='notice'>[I] does not fit into [src].</span>")
return
else
return ..()
if(full)
to_chat(user, "<span class='notice'>[src] can't hold any more of [I].</span>")
return
if(!user.transferItemToLoc(I, src))
return
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
update_icon()
/obj/structure/tank_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "tank_dispenser", name, 275, 103, master_ui, state)
ui.open()
/obj/structure/tank_dispenser/ui_data(mob/user)
var/list/data = list()
data["oxygen"] = oxygentanks
data["plasma"] = plasmatanks
return data
/obj/structure/tank_dispenser/ui_act(action, params)
if(..())
return
switch(action)
if("plasma")
var/obj/item/tank/internals/plasma/tank = locate() in src
if(tank && Adjacent(usr))
usr.put_in_hands(tank)
plasmatanks--
. = TRUE
if("oxygen")
var/obj/item/tank/internals/oxygen/tank = locate() in src
if(tank && Adjacent(usr))
usr.put_in_hands(tank)
oxygentanks--
. = TRUE
update_icon()
/obj/structure/tank_dispenser/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
for(var/X in src)
var/obj/item/I = X
I.forceMove(loc)
new /obj/item/stack/sheet/metal (loc, 2)
qdel(src)
#undef TANK_DISPENSER_CAPACITY
+322 -319
View File
@@ -1,319 +1,322 @@
#define RESTART_COUNTER_PATH "data/round_counter.txt"
GLOBAL_VAR(restart_counter)
GLOBAL_VAR(topic_status_lastcache)
GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
SetupExternalRSC()
GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
TgsNew()
GLOB.revdata = new
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
//SetupLogs depends on the RoundID, so lets check
//DB schema and set RoundID if we can
SSdbcore.CheckSchemaVersion()
SSdbcore.SetRoundID()
SetupLogs()
#ifndef USE_CUSTOM_ERROR_HANDLER
world.log = file("[GLOB.log_directory]/dd.log")
#endif
load_admins()
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
if(fexists(RESTART_COUNTER_PATH))
GLOB.restart_counter = text2num(trim(file2text(RESTART_COUNTER_PATH)))
fdel(RESTART_COUNTER_PATH)
if(NO_INIT_PARAMETER in params)
return
cit_initialize()
Master.Initialize(10, FALSE, TRUE)
if(TEST_RUN_PARAMETER in params)
HandleTestRun()
/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
SSticker.start_immediately = TRUE
CONFIG_SET(number/round_end_countdown, 0)
var/datum/callback/cb
#ifdef UNIT_TESTS
cb = CALLBACK(GLOBAL_PROC, /proc/RunUnitTests)
#else
cb = VARSET_CALLBACK(SSticker, force_ending, TRUE)
#endif
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS))
/world/proc/SetupExternalRSC()
#if (PRELOAD_RSC == 0)
GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n")
var/i=1
while(i<=GLOB.external_rsc_urls.len)
if(GLOB.external_rsc_urls[i])
i++
else
GLOB.external_rsc_urls.Cut(i,i+1)
#endif
/world/proc/SetupLogs()
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
if(!override_dir)
var/realtime = world.realtime
var/texttime = time2text(realtime, "YYYY/MM/DD")
GLOB.log_directory = "data/logs/[texttime]/round-"
GLOB.picture_logging_prefix = "L_[time2text(realtime, "YYYYMMDD")]_"
GLOB.picture_log_directory = "data/picture_logs/[texttime]/round-"
if(GLOB.round_id)
GLOB.log_directory += "[GLOB.round_id]"
GLOB.picture_logging_prefix += "R_[GLOB.round_id]_"
GLOB.picture_log_directory += "[GLOB.round_id]"
else
var/timestamp = replacetext(TIME_STAMP("hh:mm:ss", FALSE), ":", ".")
GLOB.log_directory += "[timestamp]"
GLOB.picture_log_directory += "[timestamp]"
GLOB.picture_logging_prefix += "T_[timestamp]_"
else
GLOB.log_directory = "data/logs/[override_dir]"
GLOB.picture_logging_prefix = "O_[override_dir]_"
GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
GLOB.world_game_log = "[GLOB.log_directory]/game.log"
GLOB.world_virus_log = "[GLOB.log_directory]/virus.log"
GLOB.world_attack_log = "[GLOB.log_directory]/attack.log"
GLOB.world_pda_log = "[GLOB.log_directory]/pda.log"
GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log"
GLOB.world_manifest_log = "[GLOB.log_directory]/manifest.log"
GLOB.world_href_log = "[GLOB.log_directory]/hrefs.log"
GLOB.sql_error_log = "[GLOB.log_directory]/sql.log"
GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log"
GLOB.world_map_error_log = "[GLOB.log_directory]/map_errors.log"
GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log"
GLOB.query_debug_log = "[GLOB.log_directory]/query_debug.log"
GLOB.world_job_debug_log = "[GLOB.log_directory]/job_debug.log"
GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log"
#ifdef UNIT_TESTS
GLOB.test_log = file("[GLOB.log_directory]/tests.log")
start_log(GLOB.test_log)
#endif
start_log(GLOB.world_game_log)
start_log(GLOB.world_attack_log)
start_log(GLOB.world_pda_log)
start_log(GLOB.world_telecomms_log)
start_log(GLOB.world_manifest_log)
start_log(GLOB.world_href_log)
start_log(GLOB.world_qdel_log)
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_job_debug_log)
start_log(GLOB.subsystem_log)
GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently
if(fexists(GLOB.config_error_log))
fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
fdel(GLOB.config_error_log)
if(GLOB.round_id)
log_game("Round ID: [GLOB.round_id]")
// This was printed early in startup to the world log and config_error.log,
// but those are both private, so let's put the commit info in the runtime
// log which is ultimately public.
log_runtime(GLOB.revdata.get_log_message())
/world/Topic(T, addr, master, key)
TGS_TOPIC //redirect to server tools if necessary
if(!SSfail2topic)
return "Server not initialized."
else if(SSfail2topic.IsRateLimited(addr))
return "Rate limited."
if(length(T) > CONFIG_GET(number/topic_max_size))
return "Payload too large!"
var/static/list/topic_handlers = TopicHandlers()
var/list/input = params2list(T)
var/datum/world_topic/handler
for(var/I in topic_handlers)
if(I in input)
handler = topic_handlers[I]
break
if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic))
log_topic("\"[T]\", from:[addr], master:[master], key:[key]")
if(!handler)
return
handler = new handler()
return handler.TryRun(input, addr)
/world/proc/AnnouncePR(announcement, list/payload)
var/static/list/PRcounts = list() //PR id -> number of times announced this round
var/id = "[payload["pull_request"]["id"]]"
if(!PRcounts[id])
PRcounts[id] = 1
else
++PRcounts[id]
if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND)
return
var/final_composed = "<span class='announce'>PR: [announcement]</span>"
for(var/client/C in GLOB.clients)
C.AnnouncePR(final_composed)
/world/proc/FinishTestRun()
set waitfor = FALSE
var/list/fail_reasons
if(GLOB)
if(GLOB.total_runtimes != 0)
fail_reasons = list("Total runtimes: [GLOB.total_runtimes]")
#ifdef UNIT_TESTS
if(GLOB.failed_any_test)
LAZYADD(fail_reasons, "Unit Tests failed!")
#endif
if(!GLOB.log_directory)
LAZYADD(fail_reasons, "Missing GLOB.log_directory!")
else
fail_reasons = list("Missing GLOB!")
if(!fail_reasons)
text2file("Success!", "[GLOB.log_directory]/clean_run.lk")
else
log_world("Test run failed!\n[fail_reasons.Join("\n")]")
sleep(0) //yes, 0, this'll let Reboot finish and prevent byond memes
qdel(src) //shut it down
/world/Reboot(reason = 0, fast_track = FALSE)
TgsReboot()
if (reason || fast_track) //special reboot, do none of the normal stuff
if (usr)
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
to_chat(world, "<span class='boldannounce'>Rebooting World immediately due to host request</span>")
else
to_chat(world, "<span class='boldannounce'>Rebooting world...</span>")
Master.Shutdown() //run SS shutdowns
if(TEST_RUN_PARAMETER in params)
FinishTestRun()
return
if(TgsAvailable())
var/do_hard_reboot
// check the hard reboot counter
var/ruhr = CONFIG_GET(number/rounds_until_hard_restart)
switch(ruhr)
if(-1)
do_hard_reboot = FALSE
if(0)
do_hard_reboot = TRUE
else
if(GLOB.restart_counter >= ruhr)
do_hard_reboot = TRUE
else
text2file("[++GLOB.restart_counter]", RESTART_COUNTER_PATH)
do_hard_reboot = FALSE
if(do_hard_reboot)
log_world("World hard rebooted at [TIME_STAMP("hh:mm:ss", FALSE)]")
shutdown_logging() // See comment below.
TgsEndProcess()
log_world("World rebooted at [TIME_STAMP("hh:mm:ss", FALSE)]")
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
..()
/world/proc/update_status()
var/list/features = list()
/*if(GLOB.master_mode) CIT CHANGE - hides the gamemode from the hub entry, removes some useless info from the hub entry
features += GLOB.master_mode
if (!GLOB.enter_allowed)
features += "closed"*/
var/s = ""
var/hostedby
if(config)
var/server_name = CONFIG_GET(string/servername)
if (server_name)
s += "<b>[server_name]</b> &#8212; "
/*features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn" CIT CHANGE - removes some useless info from the hub entry
if(CONFIG_GET(flag/allow_vote_mode))
features += "vote"
if(CONFIG_GET(flag/allow_ai))
features += "AI allowed"*/
hostedby = CONFIG_GET(string/hostedby)
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"https://citadel-station.net/home/\">" //Change this to wherever you want the hub to link to. CIT CHANGE - links to cit's website on the hub
s += "Citadel" //Replace this with something else. Or ever better, delete it and uncomment the game version. CIT CHANGE - modifies the hub entry link
s += "</a>"
s += ")\]" //CIT CHANGE - encloses the server title in brackets to make the hub entry fancier
s += "<br>[CONFIG_GET(string/servertagline)]<br>" //CIT CHANGE - adds a tagline!
var/n = 0
for (var/mob/M in GLOB.player_list)
if (M.client)
n++
if(SSmapping.config) // this just stops the runtime, honk.
features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map
if(get_security_level())//CIT CHANGE - makes the hub entry show the security level
features += "[get_security_level()] alert"
if (n > 1)
features += "~[n] players"
else if (n > 0)
features += "~[n] player"
if (!host && hostedby)
features += "hosted by <b>[hostedby]</b>"
if (features)
s += "\[[jointext(features, ", ")]" //CIT CHANGE - replaces the colon here with a left bracket
status = s
/world/proc/update_hub_visibility(new_visibility)
if(new_visibility == GLOB.hub_visibility)
return
GLOB.hub_visibility = new_visibility
if(GLOB.hub_visibility)
hub_password = "kMZy3U5jJHSiBQjr"
else
hub_password = "SORRYNOPASSWORD"
/world/proc/incrementMaxZ()
maxz++
SSmobs.MaxZChanged()
SSidlenpcpool.MaxZChanged()
#define RESTART_COUNTER_PATH "data/round_counter.txt"
GLOBAL_VAR(restart_counter)
GLOBAL_VAR(topic_status_lastcache)
GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
SetupExternalRSC()
GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.world_job_debug_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
TgsNew()
GLOB.revdata = new
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
//SetupLogs depends on the RoundID, so lets check
//DB schema and set RoundID if we can
SSdbcore.CheckSchemaVersion()
SSdbcore.SetRoundID()
SetupLogs()
#ifndef USE_CUSTOM_ERROR_HANDLER
world.log = file("[GLOB.log_directory]/dd.log")
#endif
load_admins()
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
if(fexists(RESTART_COUNTER_PATH))
GLOB.restart_counter = text2num(trim(file2text(RESTART_COUNTER_PATH)))
fdel(RESTART_COUNTER_PATH)
if(NO_INIT_PARAMETER in params)
return
cit_initialize()
Master.Initialize(10, FALSE, TRUE)
if(TEST_RUN_PARAMETER in params)
HandleTestRun()
/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
SSticker.start_immediately = TRUE
CONFIG_SET(number/round_end_countdown, 0)
var/datum/callback/cb
#ifdef UNIT_TESTS
cb = CALLBACK(GLOBAL_PROC, /proc/RunUnitTests)
#else
cb = VARSET_CALLBACK(SSticker, force_ending, TRUE)
#endif
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, cb, 10 SECONDS))
/world/proc/SetupExternalRSC()
#if (PRELOAD_RSC == 0)
GLOB.external_rsc_urls = world.file2list("[global.config.directory]/external_rsc_urls.txt","\n")
var/i=1
while(i<=GLOB.external_rsc_urls.len)
if(GLOB.external_rsc_urls[i])
i++
else
GLOB.external_rsc_urls.Cut(i,i+1)
#endif
/world/proc/SetupLogs()
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
if(!override_dir)
var/realtime = world.realtime
var/texttime = time2text(realtime, "YYYY/MM/DD")
GLOB.log_directory = "data/logs/[texttime]/round-"
GLOB.picture_logging_prefix = "L_[time2text(realtime, "YYYYMMDD")]_"
GLOB.picture_log_directory = "data/picture_logs/[texttime]/round-"
if(GLOB.round_id)
GLOB.log_directory += "[GLOB.round_id]"
GLOB.picture_logging_prefix += "R_[GLOB.round_id]_"
GLOB.picture_log_directory += "[GLOB.round_id]"
else
var/timestamp = replacetext(TIME_STAMP("hh:mm:ss", FALSE), ":", ".")
GLOB.log_directory += "[timestamp]"
GLOB.picture_log_directory += "[timestamp]"
GLOB.picture_logging_prefix += "T_[timestamp]_"
else
GLOB.log_directory = "data/logs/[override_dir]"
GLOB.picture_logging_prefix = "O_[override_dir]_"
GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
GLOB.world_game_log = "[GLOB.log_directory]/game.log"
GLOB.world_virus_log = "[GLOB.log_directory]/virus.log"
GLOB.world_attack_log = "[GLOB.log_directory]/attack.log"
GLOB.world_pda_log = "[GLOB.log_directory]/pda.log"
GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log"
GLOB.world_manifest_log = "[GLOB.log_directory]/manifest.log"
GLOB.world_href_log = "[GLOB.log_directory]/hrefs.log"
GLOB.sql_error_log = "[GLOB.log_directory]/sql.log"
GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log"
GLOB.world_map_error_log = "[GLOB.log_directory]/map_errors.log"
GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log"
GLOB.query_debug_log = "[GLOB.log_directory]/query_debug.log"
GLOB.world_job_debug_log = "[GLOB.log_directory]/job_debug.log"
GLOB.tgui_log = "[GLOB.log_directory]/tgui.log"
GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log"
#ifdef UNIT_TESTS
GLOB.test_log = file("[GLOB.log_directory]/tests.log")
start_log(GLOB.test_log)
#endif
start_log(GLOB.world_game_log)
start_log(GLOB.world_attack_log)
start_log(GLOB.world_pda_log)
start_log(GLOB.world_telecomms_log)
start_log(GLOB.world_manifest_log)
start_log(GLOB.world_href_log)
start_log(GLOB.world_qdel_log)
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_job_debug_log)
start_log(GLOB.tgui_log)
start_log(GLOB.subsystem_log)
GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently
if(fexists(GLOB.config_error_log))
fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
fdel(GLOB.config_error_log)
if(GLOB.round_id)
log_game("Round ID: [GLOB.round_id]")
// This was printed early in startup to the world log and config_error.log,
// but those are both private, so let's put the commit info in the runtime
// log which is ultimately public.
log_runtime(GLOB.revdata.get_log_message())
/world/Topic(T, addr, master, key)
TGS_TOPIC //redirect to server tools if necessary
if(!SSfail2topic)
return "Server not initialized."
else if(SSfail2topic.IsRateLimited(addr))
return "Rate limited."
if(length(T) > CONFIG_GET(number/topic_max_size))
return "Payload too large!"
var/static/list/topic_handlers = TopicHandlers()
var/list/input = params2list(T)
var/datum/world_topic/handler
for(var/I in topic_handlers)
if(I in input)
handler = topic_handlers[I]
break
if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic))
log_topic("\"[T]\", from:[addr], master:[master], key:[key]")
if(!handler)
return
handler = new handler()
return handler.TryRun(input, addr)
/world/proc/AnnouncePR(announcement, list/payload)
var/static/list/PRcounts = list() //PR id -> number of times announced this round
var/id = "[payload["pull_request"]["id"]]"
if(!PRcounts[id])
PRcounts[id] = 1
else
++PRcounts[id]
if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND)
return
var/final_composed = "<span class='announce'>PR: [announcement]</span>"
for(var/client/C in GLOB.clients)
C.AnnouncePR(final_composed)
/world/proc/FinishTestRun()
set waitfor = FALSE
var/list/fail_reasons
if(GLOB)
if(GLOB.total_runtimes != 0)
fail_reasons = list("Total runtimes: [GLOB.total_runtimes]")
#ifdef UNIT_TESTS
if(GLOB.failed_any_test)
LAZYADD(fail_reasons, "Unit Tests failed!")
#endif
if(!GLOB.log_directory)
LAZYADD(fail_reasons, "Missing GLOB.log_directory!")
else
fail_reasons = list("Missing GLOB!")
if(!fail_reasons)
text2file("Success!", "[GLOB.log_directory]/clean_run.lk")
else
log_world("Test run failed!\n[fail_reasons.Join("\n")]")
sleep(0) //yes, 0, this'll let Reboot finish and prevent byond memes
qdel(src) //shut it down
/world/Reboot(reason = 0, fast_track = FALSE)
TgsReboot()
if (reason || fast_track) //special reboot, do none of the normal stuff
if (usr)
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
to_chat(world, "<span class='boldannounce'>Rebooting World immediately due to host request</span>")
else
to_chat(world, "<span class='boldannounce'>Rebooting world...</span>")
Master.Shutdown() //run SS shutdowns
if(TEST_RUN_PARAMETER in params)
FinishTestRun()
return
if(TgsAvailable())
var/do_hard_reboot
// check the hard reboot counter
var/ruhr = CONFIG_GET(number/rounds_until_hard_restart)
switch(ruhr)
if(-1)
do_hard_reboot = FALSE
if(0)
do_hard_reboot = TRUE
else
if(GLOB.restart_counter >= ruhr)
do_hard_reboot = TRUE
else
text2file("[++GLOB.restart_counter]", RESTART_COUNTER_PATH)
do_hard_reboot = FALSE
if(do_hard_reboot)
log_world("World hard rebooted at [TIME_STAMP("hh:mm:ss", FALSE)]")
shutdown_logging() // See comment below.
TgsEndProcess()
log_world("World rebooted at [TIME_STAMP("hh:mm:ss", FALSE)]")
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
..()
/world/proc/update_status()
var/list/features = list()
/*if(GLOB.master_mode) CIT CHANGE - hides the gamemode from the hub entry, removes some useless info from the hub entry
features += GLOB.master_mode
if (!GLOB.enter_allowed)
features += "closed"*/
var/s = ""
var/hostedby
if(config)
var/server_name = CONFIG_GET(string/servername)
if (server_name)
s += "<b>[server_name]</b> &#8212; "
/*features += "[CONFIG_GET(flag/norespawn) ? "no " : ""]respawn" CIT CHANGE - removes some useless info from the hub entry
if(CONFIG_GET(flag/allow_vote_mode))
features += "vote"
if(CONFIG_GET(flag/allow_ai))
features += "AI allowed"*/
hostedby = CONFIG_GET(string/hostedby)
s += "<b>[station_name()]</b>";
s += " ("
s += "<a href=\"https://citadel-station.net/home/\">" //Change this to wherever you want the hub to link to. CIT CHANGE - links to cit's website on the hub
s += "Citadel" //Replace this with something else. Or ever better, delete it and uncomment the game version. CIT CHANGE - modifies the hub entry link
s += "</a>"
s += ")\]" //CIT CHANGE - encloses the server title in brackets to make the hub entry fancier
s += "<br>[CONFIG_GET(string/servertagline)]<br>" //CIT CHANGE - adds a tagline!
var/n = 0
for (var/mob/M in GLOB.player_list)
if (M.client)
n++
if(SSmapping.config) // this just stops the runtime, honk.
features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map
if(get_security_level())//CIT CHANGE - makes the hub entry show the security level
features += "[get_security_level()] alert"
if (n > 1)
features += "~[n] players"
else if (n > 0)
features += "~[n] player"
if (!host && hostedby)
features += "hosted by <b>[hostedby]</b>"
if (features)
s += "\[[jointext(features, ", ")]" //CIT CHANGE - replaces the colon here with a left bracket
status = s
/world/proc/update_hub_visibility(new_visibility)
if(new_visibility == GLOB.hub_visibility)
return
GLOB.hub_visibility = new_visibility
if(GLOB.hub_visibility)
hub_password = "kMZy3U5jJHSiBQjr"
else
hub_password = "SORRYNOPASSWORD"
/world/proc/incrementMaxZ()
maxz++
SSmobs.MaxZChanged()
SSidlenpcpool.MaxZChanged()