Merge branch 'master' into Borg-tweaks-1
@@ -28,6 +28,12 @@
|
||||
#define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1
|
||||
#define AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER 2
|
||||
|
||||
//used by airlocks and airlock wires.
|
||||
#define AICONTROLDISABLED_OFF 0 // Silicons can control the airlock normally.
|
||||
#define AICONTROLDISABLED_ON 1 // Silicons cannot control the airlock, but can hack the airlock.
|
||||
#define AICONTROLDISABLED_BYPASS 2 // Silicons can control the airlock because they succeeded on the hack
|
||||
#define AICONTROLDISABLED_PERMA 3 // Wire cutting an airlock on AICONTROLDISABLED_BYPASS toggles it between AICONTROLDISABLED_BYPASS and this.
|
||||
|
||||
//plastic flaps construction states
|
||||
#define PLASTIC_FLAPS_NORMAL 0
|
||||
#define PLASTIC_FLAPS_DETACHED 1
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#define INSTRUMENT_MIN_OCTAVE 1
|
||||
#define INSTRUMENT_MAX_OCTAVE 9
|
||||
#define INSTRUMENT_MIN_KEY 0
|
||||
#define INSTRUMENT_MAX_KEY 127
|
||||
|
||||
/// Max number of playing notes per instrument.
|
||||
#define CHANNELS_PER_INSTRUMENT 128
|
||||
|
||||
/// Distance multiplier that makes us not be impacted by 3d sound as much. This is a multiplier so lower it is the closer we will pretend to be to people.
|
||||
#define INSTRUMENT_DISTANCE_FALLOFF_BUFF 0.2
|
||||
/// How many tiles instruments have no falloff for
|
||||
#define INSTRUMENT_DISTANCE_NO_FALLOFF 3
|
||||
|
||||
/// Maximum length a note should ever go for
|
||||
#define INSTRUMENT_MAX_TOTAL_SUSTAIN (5 SECONDS)
|
||||
|
||||
/// These are per decisecond.
|
||||
#define INSTRUMENT_EXP_FALLOFF_MIN 1.025 //100/(1.025^50) calculated for [INSTRUMENT_MIN_SUSTAIN_DROPOFF] to be 30.
|
||||
#define INSTRUMENT_EXP_FALLOFF_MAX 10
|
||||
|
||||
/// Minimum volume for when the sound is considered dead.
|
||||
#define INSTRUMENT_MIN_SUSTAIN_DROPOFF 0.1
|
||||
|
||||
#define SUSTAIN_LINEAR 1
|
||||
#define SUSTAIN_EXPONENTIAL 2
|
||||
|
||||
// /datum/instrument instrument_flags
|
||||
#define INSTRUMENT_LEGACY (1<<0) //Legacy instrument. Implies INSTRUMENT_DO_NOT_AUTOSAMPLE
|
||||
#define INSTRUMENT_DO_NOT_AUTOSAMPLE (1<<1) //Do not automatically sample
|
||||
@@ -92,3 +92,8 @@
|
||||
// Firelock states
|
||||
#define FD_OPEN 1
|
||||
#define FD_CLOSED 2
|
||||
|
||||
// Computer login types
|
||||
#define LOGIN_TYPE_NORMAL 1
|
||||
#define LOGIN_TYPE_AI 2
|
||||
#define LOGIN_TYPE_ROBOT 3
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#define CHANNEL_HIGHEST_AVAILABLE 1017
|
||||
|
||||
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
|
||||
|
||||
#define SOUND_MINIMUM_PRESSURE 10
|
||||
#define FALLOFF_SOUNDS 0.5
|
||||
|
||||
@@ -45,11 +45,13 @@
|
||||
// Subsystems shutdown in the reverse of the order they initialize in
|
||||
// The numbers just define the ordering, they are meaningless otherwise.
|
||||
#define INIT_ORDER_TITLE 100 // This **MUST** load first or people will se blank lobby screens
|
||||
#define INIT_ORDER_GARBAGE 19
|
||||
#define INIT_ORDER_DBCORE 18
|
||||
#define INIT_ORDER_BLACKBOX 17
|
||||
#define INIT_ORDER_SERVER_MAINT 16
|
||||
#define INIT_ORDER_INPUT 15
|
||||
#define INIT_ORDER_GARBAGE 21
|
||||
#define INIT_ORDER_DBCORE 20
|
||||
#define INIT_ORDER_BLACKBOX 19
|
||||
#define INIT_ORDER_SERVER_MAINT 18
|
||||
#define INIT_ORDER_INPUT 17
|
||||
#define INIT_ORDER_SOUNDS 16
|
||||
#define INIT_ORDER_INSTRUMENTS 15
|
||||
#define INIT_ORDER_RESEARCH 14
|
||||
#define INIT_ORDER_EVENTS 13
|
||||
#define INIT_ORDER_JOBS 12
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// TGUI defines
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH 1024
|
||||
#define TGUI_MODAL_INPUT_MAX_LENGTH_NAME 64 // Names for generally anything don't go past 32, let alone 64.
|
||||
|
||||
#define TGUI_MODAL_OPEN 1
|
||||
#define TGUI_MODAL_DELEGATE 2
|
||||
#define TGUI_MODAL_ANSWER 3
|
||||
#define TGUI_MODAL_CLOSE 4
|
||||
@@ -145,12 +145,10 @@
|
||||
/mob/living/silicon/ai/MiddleClickOn(var/atom/A)
|
||||
A.AIMiddleClick(src)
|
||||
|
||||
/*
|
||||
The following criminally helpful code is just the previous code cleaned up;
|
||||
I have no idea why it was in atoms.dm instead of respective files.
|
||||
*/
|
||||
|
||||
/atom/proc/AICtrlShiftClick(var/mob/user) // Examines
|
||||
// DEFAULT PROCS TO OVERRIDE
|
||||
|
||||
/atom/proc/AICtrlShiftClick(mob/user) // Examines
|
||||
if(user.client)
|
||||
user.examinate(src)
|
||||
return
|
||||
@@ -158,70 +156,82 @@
|
||||
/atom/proc/AIAltShiftClick()
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AIAltShiftClick() // Sets/Unsets Emergency Access Override
|
||||
if(density)
|
||||
Topic(src, list("src" = UID(), "command"="emergency", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="emergency", "activate" = "0"), 1)
|
||||
return
|
||||
|
||||
/atom/proc/AIShiftClick(var/mob/user)
|
||||
/atom/proc/AIShiftClick(mob/living/user) // borgs use this too
|
||||
if(user.client)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
|
||||
if(density)
|
||||
Topic(src, list("src" = UID(), "command"="open", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="open", "activate" = "0"), 1)
|
||||
/atom/proc/AICtrlClick(mob/living/silicon/ai/user)
|
||||
return
|
||||
|
||||
/atom/proc/AICtrlClick(var/mob/living/silicon/ai/user)
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
|
||||
if(locked)
|
||||
Topic(src, list("src" = UID(), "command"="bolts", "activate" = "0"), 1)// 1 meaning no window (consistency!)
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="bolts", "activate" = "1"), 1)
|
||||
|
||||
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
|
||||
Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
|
||||
|
||||
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
|
||||
Topic(src, list("src" = UID(), "command"="enable", "value"="[!enabled]"), 1) // 1 meaning no window (consistency!)
|
||||
|
||||
/atom/proc/AIAltClick(var/atom/A)
|
||||
/atom/proc/AIAltClick(atom/A)
|
||||
AltClick(A)
|
||||
|
||||
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
|
||||
if(!electrified_until)
|
||||
// permanent shock
|
||||
Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
else
|
||||
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
|
||||
Topic(src, list("src" = UID(), "command"="electrify_permanently", "activate" = "0"), 1)
|
||||
/atom/proc/AIMiddleClick(mob/living/user)
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/TurfAdjacent(turf/T)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
|
||||
|
||||
// APC
|
||||
|
||||
/obj/machinery/power/apc/AICtrlClick(mob/living/user) // turns off/on APCs.
|
||||
toggle_breaker(user)
|
||||
|
||||
|
||||
// TURRETCONTROL
|
||||
|
||||
/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets
|
||||
enabled = !enabled
|
||||
updateTurrets()
|
||||
|
||||
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
|
||||
Topic(src, list("src" = UID(), "command"="lethal", "value"="[!lethal]"), 1) // 1 meaning no window (consistency!)
|
||||
if(lethal_is_configurable)
|
||||
lethal = !lethal
|
||||
updateTurrets()
|
||||
|
||||
/atom/proc/AIMiddleClick()
|
||||
return
|
||||
// AIRLOCKS
|
||||
|
||||
/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
|
||||
if(!src.lights)
|
||||
Topic(src, list("src" = UID(), "command"="lights", "activate" = "1"), 1) // 1 meaning no window (consistency!)
|
||||
/obj/machinery/door/airlock/AIAltShiftClick(mob/user) // Sets/Unsets Emergency Access Override
|
||||
emergency = !emergency
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/AIShiftClick(mob/user) // Opens and closes doors!
|
||||
if(welded)
|
||||
to_chat(user, "<span class='warning'>The airlock has been welded shut!</span>")
|
||||
if(locked)
|
||||
locked = !locked
|
||||
if(density)
|
||||
open()
|
||||
else
|
||||
Topic(src, list("src" = UID(), "command"="lights", "activate" = "0"), 1)
|
||||
return
|
||||
close()
|
||||
|
||||
/obj/machinery/ai_slipper/AICtrlClick() //Turns liquid dispenser on or off
|
||||
ToggleOn()
|
||||
/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/ai/user) // Bolts doors
|
||||
locked = !locked
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/ai_slipper/AIAltClick() //Dispenses liquid if on
|
||||
Activate()
|
||||
/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Electrifies doors.
|
||||
if(wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(user, "<span class='warning'>The electrification wire is cut - Cannot electrify the door.</span>")
|
||||
if(isElectrified())
|
||||
electrify(0) // un-shock
|
||||
else
|
||||
electrify(-1) // permanent shock
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/AIMiddleClick(mob/living/user) // Toggles door bolt lights.
|
||||
if(wires.is_cut(WIRE_BOLT_LIGHT))
|
||||
to_chat(user, "<span class='warning'>The bolt lights wire has been cut - The door bolt lights are permanently disabled.</span>")
|
||||
else if(lights)
|
||||
lights = FALSE
|
||||
to_chat(user, "<span class='notice'>The door bolt lights have been disabled.</span>")
|
||||
else if(!lights)
|
||||
lights = TRUE
|
||||
to_chat(user, "<span class='notice'>The door bolt lights have been enabled.</span>")
|
||||
update_icon()
|
||||
|
||||
// FIRE ALARMS
|
||||
|
||||
/obj/machinery/firealarm/AICtrlClick()
|
||||
if(enabled)
|
||||
@@ -229,9 +239,10 @@
|
||||
else
|
||||
alarm()
|
||||
|
||||
//
|
||||
// Override AdjacentQuick for AltClicking
|
||||
//
|
||||
// AI-CONTROLLED SLIP GENERATOR IN AI CORE
|
||||
|
||||
/mob/living/silicon/ai/TurfAdjacent(var/turf/T)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
/obj/machinery/ai_slipper/AICtrlClick(mob/living/silicon/ai/user) //Turns liquid dispenser on or off
|
||||
ToggleOn()
|
||||
|
||||
/obj/machinery/ai_slipper/AIAltClick() //Dispenses liquid if on
|
||||
Activate()
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(instruments)
|
||||
name = "Instruments"
|
||||
init_order = INIT_ORDER_INSTRUMENTS
|
||||
wait = 1
|
||||
flags = SS_TICKER|SS_BACKGROUND|SS_KEEP_TIMING
|
||||
offline_implications = "Instruments will no longer play. No immediate action is needed."
|
||||
|
||||
/// List of all instrument data, associative id = datum
|
||||
var/list/datum/instrument/instrument_data
|
||||
/// List of all song datums.
|
||||
var/list/datum/song/songs
|
||||
/// Max lines in songs
|
||||
var/musician_maxlines = 600
|
||||
/// Max characters per line in songs
|
||||
var/musician_maxlinechars = 300
|
||||
/// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this.
|
||||
var/musician_hearcheck_mindelay = 5
|
||||
/// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels.
|
||||
var/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
|
||||
/// Current number of channels allocated for instruments
|
||||
var/current_instrument_channels = 0
|
||||
/// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
|
||||
var/list/synthesizer_instrument_ids
|
||||
|
||||
/datum/controller/subsystem/processing/instruments/Initialize()
|
||||
initialize_instrument_data()
|
||||
synthesizer_instrument_ids = get_allowed_instrument_ids()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Initializes all instrument datums
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/initialize_instrument_data()
|
||||
instrument_data = list()
|
||||
for(var/path in subtypesof(/datum/instrument))
|
||||
var/datum/instrument/I = path
|
||||
if(initial(I.abstract_type) == path)
|
||||
continue
|
||||
I = new path
|
||||
I.Initialize()
|
||||
if(!I.id)
|
||||
qdel(I)
|
||||
continue
|
||||
else
|
||||
instrument_data[I.id] = I
|
||||
CHECK_TICK
|
||||
|
||||
/**
|
||||
* Reserves a sound channel for a given instrument datum
|
||||
*
|
||||
* Arguments:
|
||||
* * I - The instrument datum
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/reserve_instrument_channel(datum/instrument/I)
|
||||
if(current_instrument_channels > max_instrument_channels)
|
||||
return
|
||||
. = SSsounds.reserve_sound_channel(I)
|
||||
if(!isnull(.))
|
||||
current_instrument_channels++
|
||||
|
||||
/**
|
||||
* Called when a datum/song is created
|
||||
*
|
||||
* Arguments:
|
||||
* * S - The created datum/song
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
|
||||
LAZYADD(songs, S)
|
||||
|
||||
/**
|
||||
* Called when a datum/song is deleted
|
||||
*
|
||||
* Arguments:
|
||||
* * S - The deleted datum/song
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/on_song_del(datum/song/S)
|
||||
LAZYREMOVE(songs, S)
|
||||
|
||||
/**
|
||||
* Returns the instrument datum at the given ID or path
|
||||
*
|
||||
* Arguments:
|
||||
* * id_or_path - The ID or path of the instrument
|
||||
*/
|
||||
/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
|
||||
return instrument_data["[id_or_path]"]
|
||||
@@ -0,0 +1,165 @@
|
||||
#define DATUMLESS "NO_DATUM"
|
||||
|
||||
SUBSYSTEM_DEF(sounds)
|
||||
name = "Sounds"
|
||||
init_order = INIT_ORDER_SOUNDS
|
||||
flags = SS_NO_FIRE
|
||||
offline_implications = "Sounds may not play correctly. Shuttle call recommended."
|
||||
|
||||
var/using_channels_max = CHANNEL_HIGHEST_AVAILABLE // BYOND max channels
|
||||
/// Amount of channels to reserve for random usage rather than reservations being allowed to reserve all channels. Also a nice safeguard for when someone screws up.
|
||||
var/random_channels_min = 50
|
||||
// Hey uh these two needs to be initialized fast because the whole "things get deleted before init" thing.
|
||||
/// Assoc list, "[channel]" = either the datum using it or TRUE for an unsafe-reserved (datumless reservation) channel
|
||||
var/list/using_channels
|
||||
/// Assoc list datum = list(channel1, channel2, ...) for what channels something reserved.
|
||||
var/list/using_channels_by_datum
|
||||
// Special datastructure for fast channel management
|
||||
/// List of all channels as numbers
|
||||
var/list/channel_list
|
||||
/// Associative list of all reserved channels associated to their position. "[channel_number]" = index as number
|
||||
var/list/reserved_channels
|
||||
/// lower iteration position - Incremented and looped to get "random" sound channels for normal sounds. The channel at this index is returned when asking for a random channel.
|
||||
var/channel_random_low
|
||||
/// higher reserve position - decremented and incremented to reserve sound channels, anything above this is reserved. The channel at this index is the highest unreserved channel.
|
||||
var/channel_reserve_high
|
||||
|
||||
/datum/controller/subsystem/sounds/Initialize()
|
||||
setup_available_channels()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Sets up all available sound channels
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/setup_available_channels()
|
||||
channel_list = list()
|
||||
reserved_channels = list()
|
||||
using_channels = list()
|
||||
using_channels_by_datum = list()
|
||||
for(var/i in 1 to using_channels_max)
|
||||
channel_list += i
|
||||
channel_random_low = 1
|
||||
channel_reserve_high = length(channel_list)
|
||||
|
||||
/**
|
||||
* Removes a channel from using list
|
||||
*
|
||||
* Arguments:
|
||||
* * channel - The channel number
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_sound_channel(channel)
|
||||
var/text_channel = num2text(channel)
|
||||
var/using = using_channels[text_channel]
|
||||
using_channels -= text_channel
|
||||
if(!using) // datum channel
|
||||
using_channels_by_datum[using] -= channel
|
||||
if(!length(using_channels_by_datum[using]))
|
||||
using_channels_by_datum -= using
|
||||
free_channel(channel)
|
||||
|
||||
/**
|
||||
* Frees all the channels a datum is using
|
||||
*
|
||||
* Arguments:
|
||||
* * D - The datum
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_datum_channels(datum/D)
|
||||
var/list/L = using_channels_by_datum[D]
|
||||
if(!L)
|
||||
return
|
||||
for(var/channel in L)
|
||||
using_channels -= num2text(channel)
|
||||
free_channel(channel)
|
||||
using_channels_by_datum -= D
|
||||
|
||||
/**
|
||||
* Frees all datumless channels
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_datumless_channels()
|
||||
free_datum_channels(DATUMLESS)
|
||||
|
||||
/**
|
||||
* NO AUTOMATIC CLEANUP - If you use this, you better manually free it later!
|
||||
*
|
||||
* Returns an integer for channel
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_sound_channel_datumless()
|
||||
. = reserve_channel()
|
||||
if(!.) // oh no..
|
||||
return FALSE
|
||||
var/text_channel = num2text(.)
|
||||
using_channels[text_channel] = DATUMLESS
|
||||
LAZYADD(using_channels_by_datum[DATUMLESS], .)
|
||||
|
||||
/**
|
||||
* Reserves a channel for a datum. Automatic cleanup only when the datum is deleted.
|
||||
*
|
||||
* Returns an integer for channel
|
||||
* Arguments:
|
||||
* * D - The datum
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_sound_channel(datum/D)
|
||||
if(!D) // i don't like typechecks but someone will fuck it up
|
||||
CRASH("Attempted to reserve sound channel without datum using the managed proc.")
|
||||
. = reserve_channel()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/text_channel = num2text(.)
|
||||
using_channels[text_channel] = D
|
||||
LAZYADD(using_channels_by_datum[D], .)
|
||||
|
||||
/**
|
||||
* Reserves a channel and updates the datastructure. Private proc.
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/reserve_channel()
|
||||
PRIVATE_PROC(TRUE)
|
||||
if(channel_reserve_high <= random_channels_min) // out of channels
|
||||
return
|
||||
var/channel = channel_list[channel_reserve_high]
|
||||
reserved_channels[num2text(channel)] = channel_reserve_high--
|
||||
return channel
|
||||
|
||||
/**
|
||||
* Frees a channel and updates the datastructure. Private proc.
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/free_channel(number)
|
||||
PRIVATE_PROC(TRUE)
|
||||
var/text_channel = num2text(number)
|
||||
var/index = reserved_channels[text_channel]
|
||||
if(!index)
|
||||
CRASH("Attempted to (internally) free a channel that wasn't reserved.")
|
||||
reserved_channels -= text_channel
|
||||
// push reserve index up, which makes it now on a channel that is reserved
|
||||
channel_reserve_high++
|
||||
// swap the reserved channel with the unreserved channel so the reserve index is now on an unoccupied channel and the freed channel is next to be used.
|
||||
channel_list.Swap(channel_reserve_high, index)
|
||||
// now, an existing reserved channel will likely (exception: unreserving last reserved channel) be at index
|
||||
// get it, and update position.
|
||||
var/text_reserved = num2text(channel_list[index])
|
||||
if(!reserved_channels[text_reserved]) // if it isn't already reserved make sure we don't accidently mistakenly put it on reserved list!
|
||||
return
|
||||
reserved_channels[text_reserved] = index
|
||||
|
||||
/**
|
||||
* Random available channel, returns text
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/random_available_channel_text()
|
||||
if(channel_random_low > channel_reserve_high)
|
||||
channel_random_low = 1
|
||||
. = "[channel_list[channel_random_low++]]"
|
||||
|
||||
/**
|
||||
* Random available channel, returns number
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/random_available_channel()
|
||||
if(channel_random_low > channel_reserve_high)
|
||||
channel_random_low = 1
|
||||
. = channel_list[channel_random_low++]
|
||||
|
||||
/**
|
||||
* How many channels we have left
|
||||
*/
|
||||
/datum/controller/subsystem/sounds/proc/available_channels_left()
|
||||
return length(channel_list) - random_channels_min
|
||||
|
||||
#undef DATUMLESS
|
||||
@@ -190,9 +190,6 @@
|
||||
/datum/action/item_action/toggle_mister
|
||||
name = "Toggle Mister"
|
||||
|
||||
/datum/action/item_action/toggle_headphones
|
||||
name = "Toggle Headphones"
|
||||
|
||||
/datum/action/item_action/toggle_helmet_light
|
||||
name = "Toggle Helmet Light"
|
||||
|
||||
@@ -232,19 +229,6 @@
|
||||
button.name = name
|
||||
..()
|
||||
|
||||
/datum/action/item_action/synthswitch
|
||||
name = "Change Synthesizer Instrument"
|
||||
desc = "Change the type of instrument your synthesizer is playing as."
|
||||
|
||||
/datum/action/item_action/synthswitch/Trigger()
|
||||
if(istype(target, /obj/item/instrument/piano_synth))
|
||||
var/obj/item/instrument/piano_synth/synth = target
|
||||
var/chosen = input("Choose the type of instrument you want to use", "Instrument Selection", "piano") as null|anything in synth.insTypes
|
||||
if(!synth.insTypes[chosen])
|
||||
return
|
||||
return synth.changeInstrument(chosen)
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/vortex_recall
|
||||
name = "Vortex Recall"
|
||||
desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.<br>If the beacon is still attached, will detach it."
|
||||
@@ -257,6 +241,9 @@
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/change_headphones_song
|
||||
name = "Change Headphones Song"
|
||||
|
||||
/datum/action/item_action/toggle
|
||||
|
||||
/datum/action/item_action/toggle/New(Target)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/datum/component/spooky
|
||||
var/too_spooky = TRUE //will it spawn a new instrument?
|
||||
|
||||
/datum/component/spooky/Initialize()
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/spectral_attack)
|
||||
|
||||
/datum/component/spooky/proc/spectral_attack(datum/source, mob/living/carbon/C, mob/user)
|
||||
if(ishuman(user)) //this weapon wasn't meant for mortals.
|
||||
var/mob/living/carbon/human/U = user
|
||||
if(!istype(U.dna.species, /datum/species/skeleton))
|
||||
U.adjustStaminaLoss(35) //Extra Damage
|
||||
U.Jitter(35)
|
||||
U.stuttering = 20
|
||||
if(U.getStaminaLoss() > 95)
|
||||
to_chat(U, "<font color='red' size='4'><b>Your ears weren't meant for this spectral sound.</b></font>")
|
||||
spectral_change(U)
|
||||
return
|
||||
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(istype(H.dna.species, /datum/species/skeleton))
|
||||
return //undeads are unaffected by the spook-pocalypse.
|
||||
C.Jitter(35)
|
||||
C.stuttering = 20
|
||||
if(!istype(H.dna.species, /datum/species/diona) && !istype(H.dna.species, /datum/species/machine) && !istype(H.dna.species, /datum/species/slime) && !istype(H.dna.species, /datum/species/golem) && !istype(H.dna.species, /datum/species/plasmaman))
|
||||
C.adjustStaminaLoss(25) //boneless humanoids don't lose the will to live
|
||||
to_chat(C, "<font color='red' size='4'><B>DOOT</B></font>")
|
||||
spectral_change(H)
|
||||
|
||||
else //the sound will spook monkeys.
|
||||
C.Jitter(15)
|
||||
C.stuttering = 20
|
||||
|
||||
/datum/component/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user)
|
||||
if((H.getStaminaLoss() > 95) && (!istype(H.dna.species, /datum/species/diona) && !istype(H.dna.species, /datum/species/machine) && !istype(H.dna.species, /datum/species/slime) && !istype(H.dna.species, /datum/species/golem) && !istype(H.dna.species, /datum/species/plasmaman) && !istype(H.dna.species, /datum/species/skeleton)))
|
||||
H.Stun(20)
|
||||
H.set_species(/datum/species/skeleton)
|
||||
H.visible_message("<span class='warning'>[H] has given up on life as a mortal.</span>")
|
||||
var/T = get_turf(H)
|
||||
if(too_spooky)
|
||||
if(prob(30))
|
||||
new/obj/item/instrument/saxophone/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/instrument/trumpet/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/instrument/trombone/spectral(T)
|
||||
else
|
||||
to_chat(H, "<span class='boldwarning'>The spooky gods forgot to ship your instrument. Better luck next unlife.</span>")
|
||||
to_chat(H, "<span class='boldnotice'>You are the spooky skeleton!</span>")
|
||||
to_chat(H, "<span class='boldnotice'>A new life and identity has begun. Help your fellow skeletons into bringing out the spooky-pocalypse. You haven't forgotten your past life, and are still beholden to past loyalties.</span>")
|
||||
change_name(H) //time for a new name!
|
||||
|
||||
/datum/component/spooky/proc/change_name(mob/living/carbon/human/H)
|
||||
var/t = stripped_input(H, "Enter your new skeleton name", H.real_name, null, MAX_NAME_LEN)
|
||||
if(!t)
|
||||
t = "spooky skeleton"
|
||||
H.real_name = t
|
||||
H.name = t
|
||||
@@ -71,7 +71,7 @@
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = open_sound_channel()
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
|
||||
@@ -736,6 +736,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
cost = 12 // normally 18
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/bulldog_XLmagsbag
|
||||
name = "Bulldog - 12g XL Magazine Duffel Bag"
|
||||
desc = "A duffel bag containing three 16 round drum magazines(Slug, Buckshot, Dragon's Breath)."
|
||||
reference = "12XLDB"
|
||||
item = /obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags
|
||||
cost = 12 // normally 18
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/smg
|
||||
name = "C-20r - .45 Magazine"
|
||||
desc = "An additional 20-round .45 magazine for use in the C-20r submachine gun. These bullets pack a lot of punch that can knock most targets down, but do limited overall damage."
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
. += "The door bolts [A.locked ? "have fallen!" : "look up."]"
|
||||
. += "The door bolt lights are [(A.lights && haspower) ? "on." : "off!"]"
|
||||
. += "The test light is [haspower ? "on." : "off!"]"
|
||||
. += "The 'AI control allowed' light is [(A.aiControlDisabled == 0 && !A.emagged && haspower) ? "on" : "off"]."
|
||||
. += "The 'AI control allowed' light is [(A.aiControlDisabled == AICONTROLDISABLED_OFF && !A.emagged && haspower) ? "on" : "off"]."
|
||||
. += "The 'Check Wiring' light is [(A.safe == 0 && haspower) ? "on" : "off"]."
|
||||
. += "The 'Check Timing Mechanism' light is [(A.normalspeed == 0 && haspower) ? "on" : "off"]."
|
||||
. += "The emergency lights are [(A.emergency && haspower) ? "on" : "off"]."
|
||||
@@ -74,16 +74,16 @@
|
||||
|
||||
if(!mend)
|
||||
//one wire for AI control. Cutting this prevents the AI from controlling the door unless it has hacked the door through the power connection (which takes about a minute). If both main and backup power are cut, as well as this wire, then the AI cannot operate or hack the door at all.
|
||||
//aiControlDisabled: If 1, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
|
||||
if(A.aiControlDisabled == 0)
|
||||
A.aiControlDisabled = 1
|
||||
else if(A.aiControlDisabled == -1)
|
||||
A.aiControlDisabled = 2
|
||||
//aiControlDisabled: see explanation in code\__DEFINES\construction.dm#32
|
||||
if(A.aiControlDisabled == AICONTROLDISABLED_OFF)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_ON
|
||||
else if(A.aiControlDisabled == AICONTROLDISABLED_PERMA)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_BYPASS
|
||||
else
|
||||
if(A.aiControlDisabled == 1)
|
||||
A.aiControlDisabled = 0
|
||||
else if(A.aiControlDisabled == 2)
|
||||
A.aiControlDisabled = -1
|
||||
if(A.aiControlDisabled == AICONTROLDISABLED_ON)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_OFF
|
||||
else if(A.aiControlDisabled == AICONTROLDISABLED_BYPASS)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_PERMA
|
||||
|
||||
if(WIRE_ELECTRIFY)
|
||||
if(!mend)
|
||||
@@ -136,10 +136,11 @@
|
||||
A.loseBackupPower()
|
||||
|
||||
if(WIRE_AI_CONTROL)
|
||||
if(A.aiControlDisabled == 0)
|
||||
A.aiControlDisabled = 1
|
||||
else if(A.aiControlDisabled == -1)
|
||||
A.aiControlDisabled = 2
|
||||
if(A.aiControlDisabled == AICONTROLDISABLED_OFF)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_ON
|
||||
else if(A.aiControlDisabled == AICONTROLDISABLED_PERMA)
|
||||
A.aiControlDisabled = AICONTROLDISABLED_BYPASS
|
||||
|
||||
addtimer(CALLBACK(A, /obj/machinery/door/airlock/.proc/ai_control_callback), 1 SECONDS)
|
||||
|
||||
if(WIRE_ELECTRIFY)
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
#define NEGATE_MUTATION_THRESHOLD 30 // Occupants with over ## percent radiation threshold will not gain mutations
|
||||
|
||||
#define PAGE_UI "ui"
|
||||
#define PAGE_SE "se"
|
||||
#define PAGE_BUFFER "buffer"
|
||||
#define PAGE_REJUVENATORS "rejuvenators"
|
||||
|
||||
//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
|
||||
/datum/dna2/record
|
||||
var/datum/dna/dna = null
|
||||
@@ -161,6 +166,7 @@
|
||||
occupant = usr
|
||||
icon_state = "scanner_occupied"
|
||||
add_fingerprint(usr)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/dna_scannernew/MouseDrop_T(atom/movable/O, mob/user)
|
||||
if(!istype(O))
|
||||
@@ -214,6 +220,7 @@
|
||||
return
|
||||
|
||||
beaker = I
|
||||
SStgui.update_uis(src)
|
||||
I.forceMove(src)
|
||||
user.visible_message("[user] adds \a [I] to \the [src]!", "You add \a [I] to \the [src]!")
|
||||
return
|
||||
@@ -260,6 +267,7 @@
|
||||
M.forceMove(src)
|
||||
occupant = M
|
||||
icon_state = "scanner_occupied"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
|
||||
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
|
||||
@@ -281,6 +289,7 @@
|
||||
occupant.forceMove(loc)
|
||||
occupant = null
|
||||
icon_state = "scanner_open"
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/dna_scannernew/force_eject_occupant()
|
||||
go_out(null, TRUE)
|
||||
@@ -296,6 +305,7 @@
|
||||
occupant = null
|
||||
updateUsrDialog()
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
// Checks if occupants can be irradiated/mutated - prevents exploits where wearing full rad protection would still let you gain mutations
|
||||
/obj/machinery/dna_scannernew/proc/radiation_check()
|
||||
@@ -333,12 +343,11 @@
|
||||
var/injector_ready = FALSE //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
|
||||
var/obj/machinery/dna_scannernew/connected = null
|
||||
var/obj/item/disk/data/disk = null
|
||||
var/selected_menu_key = null
|
||||
var/selected_menu_key = PAGE_UI
|
||||
anchored = TRUE
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 400
|
||||
var/waiting_for_user_input = 0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/disk/data)) //INSERT SOME diskS
|
||||
@@ -347,7 +356,7 @@
|
||||
I.forceMove(src)
|
||||
disk = I
|
||||
to_chat(user, "You insert [I].")
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src()
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
@@ -399,35 +408,18 @@
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/**
|
||||
* The ui_interact proc is used to open and update Nano UIs
|
||||
* If ui_interact is not used then the UI will not update correctly
|
||||
* ui_interact is currently defined for /atom/movable
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(user == connected.occupant)
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "DNAModifier", name, 660, 700, master_ui, state)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["selectedMenuKey"] = selected_menu_key
|
||||
data["locked"] = connected.locked
|
||||
@@ -501,9 +493,12 @@
|
||||
for(var/datum/reagent/R in connected.beaker.reagents.reagent_list)
|
||||
data["beakerVolume"] += R.volume
|
||||
|
||||
// Transfer modal information if there is one
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
|
||||
/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
|
||||
if(..())
|
||||
return FALSE // don't update uis
|
||||
if(!istype(usr.loc, /turf))
|
||||
@@ -512,405 +507,350 @@
|
||||
return FALSE // don't update uis
|
||||
if(irradiating) // Make sure that it isn't already irradiating someone...
|
||||
return FALSE // don't update uis
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["selectMenuKey"])
|
||||
selected_menu_key = href_list["selectMenuKey"]
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["toggleLock"])
|
||||
if((connected && connected.occupant))
|
||||
connected.locked = !(connected.locked)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseRadiation"])
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(!connected.occupant)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
if(prob(95))
|
||||
if(prob(75))
|
||||
randmutb(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
else
|
||||
if(prob(95))
|
||||
randmutg(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["radiationDuration"])
|
||||
if(text2num(href_list["radiationDuration"]) > 0)
|
||||
if(radiation_duration < 20)
|
||||
radiation_duration += 2
|
||||
else
|
||||
if(radiation_duration > 2)
|
||||
radiation_duration -= 2
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["radiationIntensity"])
|
||||
if(text2num(href_list["radiationIntensity"]) > 0)
|
||||
if(radiation_intensity < 10)
|
||||
radiation_intensity++
|
||||
else
|
||||
if(radiation_intensity > 1)
|
||||
radiation_intensity--
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) > 0)
|
||||
if(selected_ui_target < 15)
|
||||
selected_ui_target++
|
||||
selected_ui_target_hex = selected_ui_target
|
||||
switch(selected_ui_target)
|
||||
if(10)
|
||||
selected_ui_target_hex = "A"
|
||||
if(11)
|
||||
selected_ui_target_hex = "B"
|
||||
if(12)
|
||||
selected_ui_target_hex = "C"
|
||||
if(13)
|
||||
selected_ui_target_hex = "D"
|
||||
if(14)
|
||||
selected_ui_target_hex = "E"
|
||||
if(15)
|
||||
selected_ui_target_hex = "F"
|
||||
else
|
||||
selected_ui_target = 0
|
||||
selected_ui_target_hex = 0
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["changeUITarget"] && text2num(href_list["changeUITarget"]) < 1)
|
||||
if(selected_ui_target > 0)
|
||||
selected_ui_target--
|
||||
selected_ui_target_hex = selected_ui_target
|
||||
switch(selected_ui_target)
|
||||
if(10)
|
||||
selected_ui_target_hex = "A"
|
||||
if(11)
|
||||
selected_ui_target_hex = "B"
|
||||
if(12)
|
||||
selected_ui_target_hex = "C"
|
||||
if(13)
|
||||
selected_ui_target_hex = "D"
|
||||
if(14)
|
||||
selected_ui_target_hex = "E"
|
||||
else
|
||||
selected_ui_target = 15
|
||||
selected_ui_target_hex = "F"
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["selectUIBlock"] && href_list["selectUISubblock"]) // This chunk of code updates selected block / sub-block based on click
|
||||
var/select_block = text2num(href_list["selectUIBlock"])
|
||||
var/select_subblock = text2num(href_list["selectUISubblock"])
|
||||
if((select_block <= DNA_UI_LENGTH) && (select_block >= 1))
|
||||
selected_ui_block = select_block
|
||||
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
|
||||
selected_ui_subblock = select_subblock
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseUIRadiation"])
|
||||
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(!connected.occupant)
|
||||
return TRUE
|
||||
|
||||
if(prob((80 + (radiation_duration / 2))))
|
||||
var/radiation = (radiation_intensity + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation,IRRADIATE,0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
|
||||
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
|
||||
connected.occupant.UpdateAppearance()
|
||||
else
|
||||
var/radiation = ((radiation_intensity * 2) + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
|
||||
if(prob(20 + radiation_intensity))
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
connected.occupant.UpdateAppearance()
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["injectRejuvenators"])
|
||||
if(!connected.occupant)
|
||||
return FALSE
|
||||
var/inject_amount = round(text2num(href_list["injectRejuvenators"]), 5) // round to nearest 5
|
||||
if(inject_amount < 0) // Since the user can actually type the commands himself, some sanity checking
|
||||
inject_amount = 0
|
||||
if(inject_amount > 50)
|
||||
inject_amount = 50
|
||||
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
|
||||
connected.beaker.reagents.reaction(connected.occupant)
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
if(href_list["selectSEBlock"] && href_list["selectSESubblock"]) // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
|
||||
var/select_block = text2num(href_list["selectSEBlock"])
|
||||
var/select_subblock = text2num(href_list["selectSESubblock"])
|
||||
if((select_block <= DNA_SE_LENGTH) && (select_block >= 1))
|
||||
selected_se_block = select_block
|
||||
if((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
|
||||
selected_se_subblock = select_subblock
|
||||
//testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["pulseSERadiation"])
|
||||
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
|
||||
//var/original_block=block
|
||||
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(connected.occupant)
|
||||
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
|
||||
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
var/real_SE_block=selected_se_block
|
||||
block = miniscramble(block, radiation_intensity, radiation_duration)
|
||||
if(prob(20))
|
||||
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
|
||||
real_SE_block++
|
||||
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
|
||||
real_SE_block--
|
||||
|
||||
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
|
||||
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
if(prob(80 - radiation_duration))
|
||||
//testing("Random bad mut!")
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
//testing("Random identity mut!")
|
||||
connected.occupant.UpdateAppearance()
|
||||
return TRUE // return 1 forces an update to all Nano uis attached to src
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(connected.beaker)
|
||||
var/obj/item/reagent_containers/glass/B = connected.beaker
|
||||
B.forceMove(connected.loc)
|
||||
connected.beaker = null
|
||||
if(tgui_act_modal(action, params))
|
||||
return TRUE
|
||||
|
||||
if(href_list["ejectOccupant"])
|
||||
connected.eject_occupant(usr)
|
||||
return TRUE
|
||||
|
||||
// Transfer Buffer Management
|
||||
if(href_list["bufferOption"])
|
||||
var/bufferOption = href_list["bufferOption"]
|
||||
|
||||
// These bufferOptions do not require a bufferId
|
||||
if(bufferOption == "wipeDisk")
|
||||
if((isnull(disk)) || (disk.read_only))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
|
||||
disk.buf = null
|
||||
//temphtml = "Data saved."
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "ejectDisk")
|
||||
if(!disk)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("selectMenuKey")
|
||||
var/key = params["key"]
|
||||
if(!(key in list(PAGE_UI, PAGE_SE, PAGE_BUFFER, PAGE_REJUVENATORS)))
|
||||
return
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
return TRUE
|
||||
|
||||
// All bufferOptions from here on require a bufferId
|
||||
if(!href_list["bufferId"])
|
||||
return FALSE
|
||||
|
||||
var/bufferId = text2num(href_list["bufferId"])
|
||||
|
||||
if(bufferId < 1 || bufferId > 3)
|
||||
return FALSE // Not a valid buffer id
|
||||
|
||||
if(bufferOption == "saveUI")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.name
|
||||
databuf.name = "Unique Identifier"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "saveUIAndUE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.dna.real_name
|
||||
databuf.name = "Unique Identifier + Unique Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "saveSE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_SE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name = connected.occupant.dna.real_name
|
||||
databuf.name = "Structural Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "clear")
|
||||
buffers[bufferId] = new /datum/dna2/record()
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "changeLabel")
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
var/text = sanitize(input(usr, "New Label:", "Edit Label", buf.name) as text|null)
|
||||
buf.name = text
|
||||
buffers[bufferId] = buf
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "transfer")
|
||||
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
|
||||
return TRUE
|
||||
|
||||
irradiating = 2
|
||||
selected_menu_key = key
|
||||
if("toggleLock")
|
||||
if(connected && connected.occupant)
|
||||
connected.locked = !(connected.locked)
|
||||
if("pulseRadiation")
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
sleep(2 SECONDS)
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
var/radiation = (rand(20,50) / connected.damage_coeff)
|
||||
if(!connected.occupant)
|
||||
return
|
||||
|
||||
var/radiation = (((radiation_intensity * 3) + radiation_duration * 3) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return TRUE
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
|
||||
if((buf.types & DNA2_BUF_UI))
|
||||
if((buf.types & DNA2_BUF_UE))
|
||||
connected.occupant.real_name = buf.dna.real_name
|
||||
connected.occupant.name = buf.dna.real_name
|
||||
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
|
||||
else if(buf.types & DNA2_BUF_SE)
|
||||
connected.occupant.dna.SE = buf.dna.SE.Copy()
|
||||
connected.occupant.dna.UpdateSE()
|
||||
domutcheck(connected.occupant, connected)
|
||||
return TRUE
|
||||
|
||||
if(bufferOption == "createInjector")
|
||||
if(injector_ready && !waiting_for_user_input)
|
||||
|
||||
var/success = 1
|
||||
var/obj/item/dnainjector/I = new /obj/item/dnainjector
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
buf = buf.copy()
|
||||
if(href_list["createBlockInjector"])
|
||||
waiting_for_user_input=1
|
||||
var/list/selectedbuf
|
||||
if(buf.types & DNA2_BUF_SE)
|
||||
selectedbuf=buf.dna.SE
|
||||
else
|
||||
selectedbuf=buf.dna.UI
|
||||
var/blk = input(usr,"Select Block","Block") as null|anything in all_dna_blocks(selectedbuf)
|
||||
success = setInjectorBlock(I,blk,buf)
|
||||
if(prob(95))
|
||||
if(prob(75))
|
||||
randmutb(connected.occupant)
|
||||
else
|
||||
I.buf = buf
|
||||
waiting_for_user_input = 0
|
||||
if(success)
|
||||
I.forceMove(loc)
|
||||
I.name += " ([buf.name])"
|
||||
if(connected)
|
||||
I.damage_coeff = connected.damage_coeff
|
||||
injector_ready = FALSE
|
||||
spawn(300)
|
||||
injector_ready = TRUE
|
||||
return TRUE
|
||||
randmuti(connected.occupant)
|
||||
else
|
||||
if(prob(95))
|
||||
randmutg(connected.occupant)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
if("radiationDuration")
|
||||
radiation_duration = clamp(text2num(params["value"]), 1, 20)
|
||||
if("radiationIntensity")
|
||||
radiation_intensity = clamp(text2num(params["value"]), 1, 10)
|
||||
////////////////////////////////////////////////////////
|
||||
if("changeUITarget")
|
||||
selected_ui_target = clamp(text2num(params["value"]), 1, 15)
|
||||
selected_ui_target_hex = num2text(selected_ui_target, 1, 16)
|
||||
if("selectUIBlock") // This chunk of code updates selected block / sub-block based on click
|
||||
var/select_block = text2num(params["block"])
|
||||
var/select_subblock = text2num(params["subblock"])
|
||||
if(!select_block || !select_subblock)
|
||||
return
|
||||
|
||||
if(bufferOption == "loadDisk")
|
||||
if((isnull(disk)) || (!disk.buf))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
selected_ui_block = clamp(select_block, 1, DNA_UI_LENGTH)
|
||||
selected_ui_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
|
||||
if("pulseUIRadiation")
|
||||
var/block = connected.occupant.dna.GetUISubBlock(selected_ui_block, selected_ui_subblock)
|
||||
|
||||
buffers[bufferId] = disk.buf.copy()
|
||||
//temphtml = "Data loaded."
|
||||
return TRUE
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
if(bufferOption == "saveDisk")
|
||||
if((isnull(disk)) || (disk.read_only))
|
||||
//temphtml = "Invalid disk. Please try again."
|
||||
return FALSE
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
disk.buf = buf.copy()
|
||||
disk.name = "data disk - '[buf.dna.real_name]'"
|
||||
//temphtml = "Data saved."
|
||||
return TRUE
|
||||
if(!connected.occupant)
|
||||
return
|
||||
|
||||
if(prob((80 + (radiation_duration / 2))))
|
||||
var/radiation = (radiation_intensity + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation,IRRADIATE,0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
block = miniscrambletarget(num2text(selected_ui_target), radiation_intensity, radiation_duration)
|
||||
connected.occupant.dna.SetUISubBlock(selected_ui_block, selected_ui_subblock, block)
|
||||
connected.occupant.UpdateAppearance()
|
||||
else
|
||||
var/radiation = ((radiation_intensity * 2) + radiation_duration)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
if(prob(20 + radiation_intensity))
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
connected.occupant.UpdateAppearance()
|
||||
////////////////////////////////////////////////////////
|
||||
if("injectRejuvenators")
|
||||
if(!connected.occupant || !connected.beaker)
|
||||
return
|
||||
var/inject_amount = clamp(round(text2num(params["amount"]), 5), 0, 50) // round to nearest 5 and clamp to 0-50
|
||||
if(!inject_amount)
|
||||
return
|
||||
connected.beaker.reagents.trans_to(connected.occupant, inject_amount)
|
||||
connected.beaker.reagents.reaction(connected.occupant)
|
||||
////////////////////////////////////////////////////////
|
||||
if("selectSEBlock") // This chunk of code updates selected block / sub-block based on click (se stands for strutural enzymes)
|
||||
var/select_block = text2num(params["block"])
|
||||
var/select_subblock = text2num(params["subblock"])
|
||||
if(!select_block || !select_subblock)
|
||||
return
|
||||
|
||||
selected_se_block = clamp(select_block, 1, DNA_SE_LENGTH)
|
||||
selected_se_subblock = clamp(select_subblock, 1, DNA_BLOCK_SIZE)
|
||||
if("pulseSERadiation")
|
||||
var/block = connected.occupant.dna.GetSESubBlock(selected_se_block, selected_se_subblock)
|
||||
//var/original_block=block
|
||||
//testing("Irradiating SE block [selected_se_block]:[selected_se_subblock] ([block])...")
|
||||
|
||||
irradiating = radiation_duration
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
SStgui.update_uis(src)
|
||||
sleep(10 * radiation_duration) // sleep for radiation_duration seconds
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
if(connected.occupant)
|
||||
if(prob((80 + ((radiation_duration / 2) + (connected.precision_coeff ** 3)))))
|
||||
var/radiation = ((radiation_intensity + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return 1
|
||||
|
||||
var/real_SE_block=selected_se_block
|
||||
block = miniscramble(block, radiation_intensity, radiation_duration)
|
||||
if(prob(20))
|
||||
if(selected_se_block > 1 && selected_se_block < DNA_SE_LENGTH/2)
|
||||
real_SE_block++
|
||||
else if(selected_se_block > DNA_SE_LENGTH/2 && selected_se_block < DNA_SE_LENGTH)
|
||||
real_SE_block--
|
||||
|
||||
//testing("Irradiated SE block [real_SE_block]:[selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
|
||||
connected.occupant.dna.SetSESubBlock(real_SE_block, selected_se_subblock, block)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
var/radiation = (((radiation_intensity * 2) + radiation_duration) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
if(prob(80 - radiation_duration))
|
||||
//testing("Random bad mut!")
|
||||
randmutb(connected.occupant)
|
||||
domutcheck(connected.occupant, connected)
|
||||
else
|
||||
randmuti(connected.occupant)
|
||||
//testing("Random identity mut!")
|
||||
connected.occupant.UpdateAppearance()
|
||||
if("ejectBeaker")
|
||||
if(connected.beaker)
|
||||
var/obj/item/reagent_containers/glass/B = connected.beaker
|
||||
B.forceMove(connected.loc)
|
||||
connected.beaker = null
|
||||
if("ejectOccupant")
|
||||
connected.eject_occupant()
|
||||
// Transfer Buffer Management
|
||||
if("bufferOption")
|
||||
var/bufferOption = params["option"]
|
||||
var/bufferId = text2num(params["id"])
|
||||
if(bufferId < 1 || bufferId > 3) // Not a valid buffer id
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buffer = buffers[bufferId]
|
||||
switch(bufferOption)
|
||||
if("saveUI")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI // DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.name
|
||||
databuf.name = "Unique Identifier"
|
||||
buffers[bufferId] = databuf
|
||||
if("saveUIAndUE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name=connected.occupant.dna.real_name
|
||||
databuf.name = "Unique Identifier + Unique Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
if("saveSE")
|
||||
if(connected.occupant && connected.occupant.dna)
|
||||
var/datum/dna2/record/databuf = new
|
||||
databuf.types = DNA2_BUF_SE
|
||||
databuf.dna = connected.occupant.dna.Clone()
|
||||
if(ishuman(connected.occupant))
|
||||
databuf.dna.real_name = connected.occupant.dna.real_name
|
||||
databuf.name = "Structural Enzymes"
|
||||
buffers[bufferId] = databuf
|
||||
if("clear")
|
||||
buffers[bufferId] = new /datum/dna2/record()
|
||||
if("changeLabel")
|
||||
tgui_modal_input(src, "changeBufferLabel", "Please enter the new buffer label:", null, list("id" = bufferId), buffer.name, TGUI_MODAL_INPUT_MAX_LENGTH_NAME)
|
||||
if("transfer")
|
||||
if(!connected.occupant || (NOCLONE in connected.occupant.mutations && connected.scan_level < 3) || !connected.occupant.dna)
|
||||
return
|
||||
|
||||
irradiating = 2
|
||||
var/lock_state = connected.locked
|
||||
connected.locked = TRUE //lock it
|
||||
|
||||
SStgui.update_uis(src)
|
||||
sleep(2 SECONDS)
|
||||
|
||||
irradiating = 0
|
||||
connected.locked = lock_state
|
||||
|
||||
var/radiation = (rand(20,50) / connected.damage_coeff)
|
||||
connected.occupant.apply_effect(radiation, IRRADIATE, 0)
|
||||
|
||||
if(connected.radiation_check())
|
||||
return
|
||||
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
|
||||
if((buf.types & DNA2_BUF_UI))
|
||||
if((buf.types & DNA2_BUF_UE))
|
||||
connected.occupant.real_name = buf.dna.real_name
|
||||
connected.occupant.name = buf.dna.real_name
|
||||
connected.occupant.UpdateAppearance(buf.dna.UI.Copy())
|
||||
else if(buf.types & DNA2_BUF_SE)
|
||||
connected.occupant.dna.SE = buf.dna.SE.Copy()
|
||||
connected.occupant.dna.UpdateSE()
|
||||
domutcheck(connected.occupant, connected)
|
||||
if("createInjector")
|
||||
if(!injector_ready)
|
||||
return
|
||||
if(text2num(params["block"]) > 0)
|
||||
var/list/choices = all_dna_blocks((buffer.types & DNA2_BUF_SE) ? buffer.dna.SE : buffer.dna.UI)
|
||||
tgui_modal_choice(src, "createInjectorBlock", "Please select the block to create an injector from:", null, list("id" = bufferId), null, choices)
|
||||
else
|
||||
create_injector(bufferId, TRUE)
|
||||
if("loadDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
buffers[bufferId] = disk.buf.copy()
|
||||
if("saveDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[bufferId]
|
||||
disk.buf = buf.copy()
|
||||
disk.name = "data disk - '[buf.dna.real_name]'"
|
||||
if("wipeDisk")
|
||||
if(isnull(disk) || disk.read_only)
|
||||
return
|
||||
disk.buf = null
|
||||
if("ejectDisk")
|
||||
if(!disk)
|
||||
return
|
||||
disk.forceMove(get_turf(src))
|
||||
disk = null
|
||||
|
||||
/**
|
||||
* Creates a blank injector with the name of the buffer at the given buffer_id
|
||||
*
|
||||
* Arguments:
|
||||
* * buffer_id - The ID of the buffer
|
||||
* * copy_buffer - Whether the injector should copy the buffer contents
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/create_injector(buffer_id, copy_buffer = FALSE)
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
|
||||
// Cooldown
|
||||
injector_ready = FALSE
|
||||
addtimer(CALLBACK(src, .proc/injector_cooldown_finish), 30 SECONDS)
|
||||
|
||||
// Create it
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
var/obj/item/dnainjector/I = new()
|
||||
I.forceMove(loc)
|
||||
I.name += " ([buf.name])"
|
||||
if(copy_buffer)
|
||||
I.buf = buf.copy()
|
||||
if(connected)
|
||||
I.damage_coeff = connected.damage_coeff
|
||||
return I
|
||||
|
||||
/**
|
||||
* Called when the injector creation cooldown finishes
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/injector_cooldown_finish()
|
||||
injector_ready = TRUE
|
||||
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/computer/scan_consolenew/proc/tgui_act_modal(action, params)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("createInjectorBlock")
|
||||
var/buffer_id = text2num(arguments["id"])
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
var/obj/item/dnainjector/I = create_injector(buffer_id)
|
||||
setInjectorBlock(I, answer, buf.copy())
|
||||
if("changeBufferLabel")
|
||||
var/buffer_id = text2num(arguments["id"])
|
||||
if(buffer_id < 1 || buffer_id > length(buffers))
|
||||
return
|
||||
var/datum/dna2/record/buf = buffers[buffer_id]
|
||||
buf.name = answer
|
||||
buffers[buffer_id] = buf
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
|
||||
#undef PAGE_UI
|
||||
#undef PAGE_SE
|
||||
#undef PAGE_BUFFER
|
||||
#undef PAGE_REJUVENATORS
|
||||
|
||||
/////////////////////////// DNA MACHINES
|
||||
|
||||
@@ -510,3 +510,26 @@ proc/get_all_job_icons() //For all existing HUD icons
|
||||
return rankName
|
||||
|
||||
return "Unknown" //Return unknown if none of the above apply
|
||||
|
||||
proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND)
|
||||
var/list/retval
|
||||
for(var/i in num_min_region to num_max_region)
|
||||
var/list/accesses = list()
|
||||
var/list/available_accesses
|
||||
if(i == REGION_CENTCOMM) // Override necessary, because get_region_accesses(REGION_CENTCOM) returns BOTH CC and crew accesses.
|
||||
available_accesses = get_all_centcom_access()
|
||||
else
|
||||
available_accesses = get_region_accesses(i)
|
||||
for(var/access in available_accesses)
|
||||
var/access_desc = (i == REGION_CENTCOMM) ? get_centcom_access_desc(access) : get_access_desc(access)
|
||||
if (access_desc)
|
||||
accesses += list(list(
|
||||
"desc" = replacetext(access_desc, " ", " "),
|
||||
"ref" = access,
|
||||
))
|
||||
retval += list(list(
|
||||
"name" = get_region_accesses_name(i),
|
||||
"regid" = i,
|
||||
"accesses" = accesses
|
||||
))
|
||||
return retval
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/sleeper/attack_ghost(mob/user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/sleeper/attack_hand(mob/user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -135,17 +135,17 @@
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/sleeper/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "sleeper.tmpl", "Sleeper", 550, 770)
|
||||
ui = new(user, src, ui_key, "Sleeper", "Sleeper", 550, 775)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/sleeper/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/sleeper/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["amounts"] = amounts
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
var/occupantData[0]
|
||||
var/crisis = 0
|
||||
@@ -210,9 +210,13 @@
|
||||
if(beaker)
|
||||
data["isBeakerLoaded"] = 1
|
||||
if(beaker.reagents)
|
||||
data["beakerMaxSpace"] = beaker.reagents.maximum_volume
|
||||
data["beakerFreeSpace"] = round(beaker.reagents.maximum_volume - beaker.reagents.total_volume)
|
||||
else
|
||||
data["beakerMaxSpace"] = 0
|
||||
data["beakerFreeSpace"] = 0
|
||||
else
|
||||
data["isBeakerLoaded"] = FALSE
|
||||
|
||||
var/chemicals[0]
|
||||
for(var/re in possible_chems)
|
||||
@@ -234,51 +238,52 @@
|
||||
if(temp.id in occupant.reagents.overdose_list())
|
||||
overdosing = 1
|
||||
|
||||
// Because I don't know how to do this on the nano side
|
||||
pretty_amount = round(reagent_amount, 0.05)
|
||||
|
||||
chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("chemical" = temp.id), "occ_amount" = reagent_amount, "pretty_amount" = pretty_amount, "injectable" = injectable, "overdosing" = overdosing, "od_warning" = caution)))
|
||||
data["chemicals"] = chemicals
|
||||
return data
|
||||
|
||||
/obj/machinery/sleeper/Topic(href, href_list)
|
||||
if(!controls_inside && usr == occupant)
|
||||
return 0
|
||||
|
||||
/obj/machinery/sleeper/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
return
|
||||
if(!controls_inside && usr == occupant)
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(usr, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return 0
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon/ai)))
|
||||
if(href_list["chemical"])
|
||||
if(occupant)
|
||||
if(occupant.stat == DEAD)
|
||||
to_chat(usr, "<span class='danger'>This person has no life for to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
|
||||
else if(occupant.health > min_health || (href_list["chemical"] in emergency_chems))
|
||||
inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"]))
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
|
||||
|
||||
if(href_list["removebeaker"])
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("chemical")
|
||||
if(!occupant)
|
||||
return
|
||||
if(occupant.stat == DEAD)
|
||||
to_chat(usr, "<span class='danger'>This person has no life to preserve anymore. Take [occupant.p_them()] to a department capable of reanimating them.</span>")
|
||||
return
|
||||
var/chemical = params["chemid"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!length(chemical) || amount <= 0)
|
||||
return
|
||||
if(occupant.health > min_health || (chemical in emergency_chems))
|
||||
inject_chemical(usr, chemical, amount)
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!</span>")
|
||||
if("removebeaker")
|
||||
remove_beaker()
|
||||
|
||||
if(href_list["togglefilter"])
|
||||
if("togglefilter")
|
||||
toggle_filter()
|
||||
|
||||
if(href_list["ejectify"])
|
||||
if("ejectify")
|
||||
eject()
|
||||
|
||||
if(href_list["auto_eject_dead_on"])
|
||||
if("auto_eject_dead_on")
|
||||
auto_eject_dead = TRUE
|
||||
|
||||
if(href_list["auto_eject_dead_off"])
|
||||
if("auto_eject_dead_off")
|
||||
auto_eject_dead = FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1
|
||||
else
|
||||
return FALSE
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/reagent_containers/glass))
|
||||
@@ -290,6 +295,7 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
user.visible_message("[user] adds \a [I] to [src]!", "You add \a [I] to [src]!")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
else
|
||||
@@ -328,6 +334,7 @@
|
||||
to_chat(M, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
|
||||
add_fingerprint(user)
|
||||
qdel(G)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -374,9 +381,11 @@
|
||||
occupant = null
|
||||
updateUsrDialog()
|
||||
update_icon()
|
||||
SStgui.update_uis(src)
|
||||
if(A == beaker)
|
||||
beaker = null
|
||||
updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/sleeper/emp_act(severity)
|
||||
if(filtering)
|
||||
@@ -394,7 +403,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/sleeper/proc/toggle_filter()
|
||||
if(filtering)
|
||||
if(filtering || !beaker)
|
||||
filtering = 0
|
||||
else
|
||||
filtering = 1
|
||||
@@ -410,29 +419,28 @@
|
||||
// eject trash the occupant dropped
|
||||
for(var/atom/movable/A in contents - component_parts - list(beaker))
|
||||
A.forceMove(loc)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/sleeper/force_eject_occupant()
|
||||
go_out()
|
||||
|
||||
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user as mob, chemical, amount)
|
||||
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user, chemical, amount)
|
||||
if(!(chemical in possible_chems))
|
||||
to_chat(user, "<span class='notice'>The sleeper does not offer that chemical!</span>")
|
||||
return
|
||||
if(!(amount in amounts))
|
||||
return
|
||||
|
||||
if(occupant)
|
||||
if(occupant.reagents)
|
||||
if(occupant.reagents.get_reagent_amount(chemical) + amount <= max_chem)
|
||||
occupant.reagents.add_reagent(chemical, amount)
|
||||
return
|
||||
else
|
||||
to_chat(user, "You can not inject any more of this chemical.")
|
||||
return
|
||||
else
|
||||
to_chat(user, "The patient rejects the chemicals!")
|
||||
return
|
||||
else
|
||||
to_chat(user, "There's no occupant in the sleeper!")
|
||||
return
|
||||
|
||||
/obj/machinery/sleeper/verb/eject()
|
||||
set name = "Eject Sleeper"
|
||||
@@ -459,6 +467,7 @@
|
||||
filtering = 0
|
||||
beaker.forceMove(usr.loc)
|
||||
beaker = null
|
||||
SStgui.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
return
|
||||
|
||||
@@ -511,6 +520,7 @@
|
||||
add_fingerprint(user)
|
||||
if(user.pulling == L)
|
||||
user.stop_pulling()
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -547,6 +557,7 @@
|
||||
for(var/obj/O in src)
|
||||
qdel(O)
|
||||
add_fingerprint(usr)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
icon_state = "body_scanner_1"
|
||||
add_fingerprint(user)
|
||||
qdel(TYPECAST_YOUR_SHIT)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -127,12 +128,13 @@
|
||||
occupant = H
|
||||
icon_state = "bodyscanner"
|
||||
add_fingerprint(user)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_ai(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_ghost(user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_hand(user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -145,7 +147,7 @@
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/bodyscanner/relaymove(mob/user)
|
||||
if(user.incapacitated())
|
||||
@@ -171,6 +173,7 @@
|
||||
// eject trash the occupant dropped
|
||||
for(var/atom/movable/A in contents - component_parts)
|
||||
A.forceMove(loc)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/force_eject_occupant()
|
||||
go_out()
|
||||
@@ -192,17 +195,16 @@
|
||||
new /obj/effect/gibspawner/generic(get_turf(loc)) //I REPLACE YOUR TECHNOLOGY WITH FLESH!
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/bodyscanner/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 600)
|
||||
ui = new(user, src, ui_key, "BodyScanner", "Body Scanner", 690, 600)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/bodyscanner/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["occupied"] = occupant ? 1 : 0
|
||||
data["occupied"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -236,9 +238,9 @@
|
||||
occupantData["hasBorer"] = occupant.has_brain_worms()
|
||||
|
||||
var/bloodData[0]
|
||||
bloodData["hasBlood"] = 0
|
||||
bloodData["hasBlood"] = FALSE
|
||||
if(!(NO_BLOOD in occupant.dna.species.species_traits))
|
||||
bloodData["hasBlood"] = 1
|
||||
bloodData["hasBlood"] = TRUE
|
||||
bloodData["volume"] = occupant.blood_volume
|
||||
bloodData["percent"] = round(((occupant.blood_volume / BLOOD_VOLUME_NORMAL)*100))
|
||||
bloodData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
|
||||
@@ -282,19 +284,19 @@
|
||||
if(E.status & ORGAN_BROKEN)
|
||||
organStatus["broken"] = E.broken_description
|
||||
if(E.is_robotic())
|
||||
organStatus["robotic"] = 1
|
||||
organStatus["robotic"] = TRUE
|
||||
if(E.status & ORGAN_SPLINTED)
|
||||
organStatus["splinted"] = 1
|
||||
organStatus["splinted"] = TRUE
|
||||
if(E.status & ORGAN_DEAD)
|
||||
organStatus["dead"] = 1
|
||||
organStatus["dead"] = TRUE
|
||||
|
||||
organData["status"] = organStatus
|
||||
|
||||
if(istype(E, /obj/item/organ/external/chest) && occupant.is_lung_ruptured())
|
||||
organData["lungRuptured"] = 1
|
||||
organData["lungRuptured"] = TRUE
|
||||
|
||||
if(E.internal_bleeding)
|
||||
organData["internalBleeding"] = 1
|
||||
organData["internalBleeding"] = TRUE
|
||||
|
||||
extOrganData.Add(list(organData))
|
||||
|
||||
@@ -319,27 +321,33 @@
|
||||
|
||||
occupantData["blind"] = (BLINDNESS in occupant.mutations)
|
||||
occupantData["colourblind"] = (COLOURBLIND in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
|
||||
data["occupant"] = occupantData
|
||||
return data
|
||||
|
||||
/obj/machinery/bodyscanner/Topic(href, href_list)
|
||||
/obj/machinery/bodyscanner/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["ejectify"])
|
||||
eject()
|
||||
|
||||
if(href_list["print_p"])
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
P.info = "<CENTER><B>Body Scan - [href_list["name"]]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [href_list["name"]]"
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("ejectify")
|
||||
eject()
|
||||
if("print_p")
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
var/name = occupant ? occupant.name : "Unknown"
|
||||
P.info = "<CENTER><B>Body Scan - [name]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [name]"
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/bodyscanner/proc/generate_printing_text()
|
||||
var/dat = ""
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
list("name" = "\[SPECIAL\]", "icon" = "whiters")
|
||||
)
|
||||
possibleseccolor = list( // no point in having the N2O and "whiters" ones in these lists
|
||||
list("name" = "\[None\]", "icon" = "none"),
|
||||
list("name" = "\[N2\]", "icon" = "red-c"),
|
||||
list("name" = "\[O2\]", "icon" = "blue-c"),
|
||||
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c"),
|
||||
@@ -19,6 +20,7 @@
|
||||
list("name" = "\[CAUTION\]", "icon" = "yellow-c")
|
||||
)
|
||||
possibletertcolor = list(
|
||||
list("name" = "\[None\]", "icon" = "none"),
|
||||
list("name" = "\[N2\]", "icon" = "red-c-1"),
|
||||
list("name" = "\[O2\]", "icon" = "blue-c-1"),
|
||||
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-1"),
|
||||
@@ -27,6 +29,7 @@
|
||||
list("name" = "\[CAUTION\]", "icon" = "yellow-c-1")
|
||||
)
|
||||
possiblequartcolor = list(
|
||||
list("name" = "\[None\]", "icon" = "none"),
|
||||
list("name" = "\[N2\]", "icon" = "red-c-2"),
|
||||
list("name" = "\[O2\]", "icon" = "blue-c-2"),
|
||||
list("name" = "\[Toxin (Bio)\]", "icon" = "orange-c-2"),
|
||||
@@ -34,12 +37,6 @@
|
||||
list("name" = "\[Air\]", "icon" = "grey-c-2"),
|
||||
list("name" = "\[CAUTION\]", "icon" = "yellow-c-2")
|
||||
)
|
||||
|
||||
possibledecals = list( //var that stores all possible decals, used by ui
|
||||
list("name" = "Low temperature canister", "icon" = "cold"),
|
||||
list("name" = "High temperature canister", "icon" = "hot"),
|
||||
list("name" = "Plasma containing canister", "icon" = "plasma")
|
||||
)
|
||||
GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister
|
||||
@@ -52,22 +49,17 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
max_integrity = 250
|
||||
integrity_failure = 100
|
||||
|
||||
var/menu = 0
|
||||
//used by nanoui: 0 = main menu, 1 = relabel
|
||||
|
||||
var/valve_open = 0
|
||||
var/release_pressure = ONE_ATMOSPHERE
|
||||
|
||||
var/list/canister_color //variable that stores colours
|
||||
var/list/decals //list that stores the decals
|
||||
var/list/color_index // list which stores tgui color indexes for the recoloring options, to enable previously-set colors to show up right
|
||||
|
||||
//lists for check_change()
|
||||
var/list/oldcolor
|
||||
var/list/olddecals
|
||||
|
||||
//passed to the ui to render the color lists
|
||||
var/list/colorcontainer
|
||||
var/list/possibledecals
|
||||
|
||||
var/can_label = 1
|
||||
var/filled = 0.5
|
||||
@@ -82,18 +74,12 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
/obj/machinery/portable_atmospherics/canister/New()
|
||||
..()
|
||||
canister_color = list(
|
||||
"prim" = "yellow",
|
||||
"sec" = "none",
|
||||
"ter" = "none",
|
||||
"quart" = "none")
|
||||
"prim" = "yellow",
|
||||
"sec" = "none",
|
||||
"ter" = "none",
|
||||
"quart" = "none"
|
||||
)
|
||||
oldcolor = new /list()
|
||||
decals = list("cold" = 0, "hot" = 0, "plasma" = 0)
|
||||
colorcontainer = list()
|
||||
possibledecals = list()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/init_data_vars()
|
||||
//passed to the ui to render the color lists
|
||||
colorcontainer = list(
|
||||
"prim" = list(
|
||||
"options" = GLOB.canister_icon_container.possiblemaincolor,
|
||||
@@ -112,26 +98,8 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
"name" = "Quaternary color",
|
||||
)
|
||||
)
|
||||
|
||||
//var/anycolor used by the nanoUI, 0: no color applied. 1: color applied
|
||||
for(var/C in colorcontainer)
|
||||
if(C == "prim") continue
|
||||
var/list/L = colorcontainer[C]
|
||||
if(!(canister_color[C]) || (canister_color[C] == "none"))
|
||||
L.Add(list("anycolor" = 0))
|
||||
else
|
||||
L.Add(list("anycolor" = 1))
|
||||
colorcontainer[C] = L
|
||||
|
||||
possibledecals = list()
|
||||
|
||||
var/i
|
||||
var/list/L = GLOB.canister_icon_container.possibledecals
|
||||
for(i=1;i<=L.len;i++)
|
||||
var/list/LL = L[i]
|
||||
LL = LL.Copy() //make sure we don't edit the datum list
|
||||
LL.Add(list("active" = decals[LL["icon"]])) //"active" used by nanoUI
|
||||
possibledecals.Add(LL)
|
||||
color_index = list()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/check_change()
|
||||
var/old_flag = update_flag
|
||||
@@ -155,10 +123,6 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
update_flag |= 64
|
||||
oldcolor = canister_color.Copy()
|
||||
|
||||
if(list2params(olddecals) != list2params(decals))
|
||||
update_flag |= 128
|
||||
olddecals = decals.Copy()
|
||||
|
||||
if(update_flag == old_flag)
|
||||
return 1
|
||||
else
|
||||
@@ -174,17 +138,16 @@ update_flag
|
||||
16 = tank_pressure < 15*ONE_ATMOS
|
||||
32 = tank_pressure go boom.
|
||||
64 = colors
|
||||
128 = decals
|
||||
(note: colors and decals has to be applied every icon update)
|
||||
(note: colors has to be applied every icon update)
|
||||
*/
|
||||
|
||||
if(src.destroyed)
|
||||
src.overlays = 0
|
||||
src.icon_state = text("[]-1", src.canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
|
||||
if(destroyed)
|
||||
overlays = 0
|
||||
icon_state = text("[]-1", canister_color["prim"])//yes, I KNOW the colours don't reflect when the can's borked, whatever.
|
||||
return
|
||||
|
||||
if(icon_state != src.canister_color["prim"])
|
||||
icon_state = src.canister_color["prim"]
|
||||
if(icon_state != canister_color["prim"])
|
||||
icon_state = canister_color["prim"]
|
||||
|
||||
if(check_change()) //Returns 1 if no change needed to icons.
|
||||
return
|
||||
@@ -192,14 +155,12 @@ update_flag
|
||||
overlays.Cut()
|
||||
|
||||
for(var/C in canister_color)
|
||||
if(C == "prim") continue
|
||||
if(canister_color[C] == "none") continue
|
||||
if(C == "prim")
|
||||
continue
|
||||
if(canister_color[C] == "none")
|
||||
continue
|
||||
overlays.Add(canister_color[C])
|
||||
|
||||
for(var/D in decals)
|
||||
if(decals[D])
|
||||
overlays.Add("decal-" + D)
|
||||
|
||||
if(update_flag & 1)
|
||||
overlays += "can-open"
|
||||
if(update_flag & 2)
|
||||
@@ -213,35 +174,9 @@ update_flag
|
||||
else if(update_flag & 32)
|
||||
overlays += "can-o3"
|
||||
|
||||
update_flag &= ~196 //the flags 128 and 64 represent change, not states. As such, we have to reset them to be able to detect a change on the next go.
|
||||
update_flag &= ~68 //the flag 64 represents change, not states. As such, we have to reset them to be able to detect a change on the next go.
|
||||
return
|
||||
|
||||
//template modification exploit prevention, used in Topic()
|
||||
/obj/machinery/portable_atmospherics/canister/proc/is_a_color(var/inputVar, var/checkColor = "all")
|
||||
if(checkColor == "prim" || checkColor == "all")
|
||||
for(var/list/L in GLOB.canister_icon_container.possiblemaincolor)
|
||||
if(L["icon"] == inputVar)
|
||||
return 1
|
||||
if(checkColor == "sec" || checkColor == "all")
|
||||
for(var/list/L in GLOB.canister_icon_container.possibleseccolor)
|
||||
if(L["icon"] == inputVar)
|
||||
return 1
|
||||
if(checkColor == "ter" || checkColor == "all")
|
||||
for(var/list/L in GLOB.canister_icon_container.possibletertcolor)
|
||||
if(L["icon"] == inputVar)
|
||||
return 1
|
||||
if(checkColor == "quart" || checkColor == "all")
|
||||
for(var/list/L in GLOB.canister_icon_container.possiblequartcolor)
|
||||
if(L["icon"] == inputVar)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/is_a_decal(var/inputVar)
|
||||
for(var/list/L in GLOB.canister_icon_container.possibledecals)
|
||||
if(L["icon"] == inputVar)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature > temperature_resistance)
|
||||
@@ -271,7 +206,7 @@ update_flag
|
||||
|
||||
stat |= BROKEN
|
||||
density = FALSE
|
||||
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
|
||||
playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
|
||||
update_icon()
|
||||
|
||||
if(holding)
|
||||
@@ -297,7 +232,7 @@ update_flag
|
||||
|
||||
var/transfer_moles = 0
|
||||
if((air_contents.temperature > 0) && (pressure_delta > 0))
|
||||
transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
|
||||
transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
|
||||
@@ -307,7 +242,7 @@ update_flag
|
||||
else
|
||||
loc.assume_air(removed)
|
||||
air_update_turf()
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
|
||||
|
||||
if(air_contents.return_pressure() < 1)
|
||||
@@ -315,20 +250,20 @@ update_flag
|
||||
else
|
||||
can_label = 0
|
||||
|
||||
src.updateDialog()
|
||||
updateDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/return_air()
|
||||
return air_contents
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/return_temperature()
|
||||
var/datum/gas_mixture/GM = src.return_air()
|
||||
var/datum/gas_mixture/GM = return_air()
|
||||
if(GM && GM.volume>0)
|
||||
return GM.temperature
|
||||
return 0
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/proc/return_pressure()
|
||||
var/datum/gas_mixture/GM = src.return_air()
|
||||
var/datum/gas_mixture/GM = return_air()
|
||||
if(GM && GM.volume>0)
|
||||
return GM.return_pressure()
|
||||
return 0
|
||||
@@ -343,141 +278,113 @@ update_flag
|
||||
else if(valve_open && holding)
|
||||
investigate_log("[key_name(user)] started a transfer into [holding].<br>", "atmos")
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob)
|
||||
src.add_hiddenprint(user)
|
||||
return src.attack_hand(user)
|
||||
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user)
|
||||
add_hiddenprint(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/attack_ghost(var/mob/user as mob)
|
||||
return src.ui_interact(user)
|
||||
/obj/machinery/portable_atmospherics/canister/attack_ghost(var/mob/user)
|
||||
return tgui_interact(user)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob)
|
||||
return src.ui_interact(user)
|
||||
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user)
|
||||
return tgui_interact(user)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.physical_state)
|
||||
if(src.destroyed)
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/portable_atmospherics/canister/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_physical_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400, state = state)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "Canister", name, 600, 350, master_ui, state)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_data(mob/user, datum/topic_state/state)
|
||||
init_data_vars() //set up var/colorcontainer and var/possibledecals
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
var/data[0]
|
||||
data["name"] = name
|
||||
data["menu"] = menu ? 1 : 0
|
||||
data["canLabel"] = can_label ? 1 : 0
|
||||
data["canister_color"] = canister_color
|
||||
data["colorContainer"] = colorcontainer.Copy()
|
||||
colorcontainer.Cut()
|
||||
data["possibleDecals"] = possibledecals.Copy()
|
||||
possibledecals.Cut()
|
||||
/obj/machinery/portable_atmospherics/canister/tgui_data()
|
||||
var/data = list()
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
|
||||
data["minReleasePressure"] = round(ONE_ATMOSPHERE/10)
|
||||
data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE)
|
||||
data["defaultReleasePressure"] = ONE_ATMOSPHERE
|
||||
data["minReleasePressure"] = round(ONE_ATMOSPHERE / 10)
|
||||
data["maxReleasePressure"] = round(ONE_ATMOSPHERE * 10)
|
||||
data["valveOpen"] = valve_open ? 1 : 0
|
||||
|
||||
data["name"] = name
|
||||
data["canLabel"] = can_label ? 1 : 0
|
||||
data["colorContainer"] = colorcontainer.Copy()
|
||||
data["color_index"] = color_index
|
||||
data["hasHoldingTank"] = holding ? 1 : 0
|
||||
if(holding)
|
||||
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
|
||||
/obj/machinery/portable_atmospherics/canister/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["choice"] == "menu")
|
||||
menu = text2num(href_list["mode_target"])
|
||||
|
||||
if(href_list["toggle"])
|
||||
var/logmsg
|
||||
if(valve_open)
|
||||
if(holding)
|
||||
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding]<br>"
|
||||
else
|
||||
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the <font color='red'><b>air</b></font><br>"
|
||||
else
|
||||
if(holding)
|
||||
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting the transfer into the [holding]<br>"
|
||||
else
|
||||
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting the transfer into the <font color='red'><b>air</b></font><br>"
|
||||
if(air_contents.toxins > 0)
|
||||
message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
|
||||
if(air_contents.sleeping_agent > 0)
|
||||
message_admins("[key_name_admin(usr)] opened a canister that contains N2O in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
log_admin("[key_name(usr)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
|
||||
investigate_log(logmsg, "atmos")
|
||||
release_log += logmsg
|
||||
valve_open = !valve_open
|
||||
|
||||
if(href_list["remove_tank"])
|
||||
if(holding)
|
||||
if(valve_open)
|
||||
valve_open = 0
|
||||
release_log += "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding]<br>"
|
||||
holding.loc = loc
|
||||
holding = null
|
||||
|
||||
if(href_list["pressure_adj"])
|
||||
var/diff = text2num(href_list["pressure_adj"])
|
||||
if(diff > 0)
|
||||
release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff)
|
||||
else
|
||||
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
|
||||
|
||||
if(href_list["rename"])
|
||||
if(can_label)
|
||||
var/T = sanitize(copytext(input("Choose canister label", "Name", name) as text|null,1,MAX_NAME_LEN))
|
||||
if(can_label) //Exploit prevention
|
||||
if(T)
|
||||
name = T
|
||||
return
|
||||
var/can_min_release_pressure = round(ONE_ATMOSPHERE / 10)
|
||||
var/can_max_release_pressure = round(ONE_ATMOSPHERE * 10)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("relabel")
|
||||
if(can_label)
|
||||
var/T = sanitize(copytext(input("Choose canister label", "Name", name) as text|null, 1, MAX_NAME_LEN))
|
||||
if(can_label) //Exploit prevention
|
||||
if(T)
|
||||
name = T
|
||||
else
|
||||
name = "canister"
|
||||
else
|
||||
name = "canister"
|
||||
to_chat(usr, "<span class='warning'>As you attempted to rename it the pressure rose!</span>")
|
||||
. = FALSE
|
||||
if("pressure")
|
||||
var/pressure = params["pressure"]
|
||||
if(pressure == "reset")
|
||||
pressure = ONE_ATMOSPHERE
|
||||
else if(pressure == "min")
|
||||
pressure = can_min_release_pressure
|
||||
else if(pressure == "max")
|
||||
pressure = can_max_release_pressure
|
||||
else if(pressure == "input")
|
||||
pressure = input("New release pressure ([can_min_release_pressure]-[can_max_release_pressure] kPa):", name, release_pressure) as num|null
|
||||
if(isnull(pressure))
|
||||
. = FALSE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
if(.)
|
||||
release_pressure = clamp(round(pressure), can_min_release_pressure, can_max_release_pressure)
|
||||
investigate_log("was set to [release_pressure] kPa by [key_name(usr)].", "atmos")
|
||||
if("valve")
|
||||
var/logmsg
|
||||
valve_open = !valve_open
|
||||
if(valve_open)
|
||||
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting a transfer into the [holding || "air"].<br>"
|
||||
if(!holding)
|
||||
logmsg = "Valve was <b>opened</b> by [key_name(usr)], starting a transfer into the [holding || "air"].<br>"
|
||||
if(air_contents.toxins > 0)
|
||||
message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
|
||||
if(air_contents.sleeping_agent > 0)
|
||||
message_admins("[key_name_admin(usr)] opened a canister that contains N2O in [get_area(src)]! (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
log_admin("[key_name(usr)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>As you attempted to rename it the pressure rose!</span>")
|
||||
|
||||
if(href_list["choice"] == "Primary color")
|
||||
if(is_a_color(href_list["icon"],"prim"))
|
||||
canister_color["prim"] = href_list["icon"]
|
||||
if(href_list["choice"] == "Secondary color")
|
||||
if(href_list["icon"] == "none")
|
||||
canister_color["sec"] = "none"
|
||||
else if(is_a_color(href_list["icon"],"sec"))
|
||||
canister_color["sec"] = href_list["icon"]
|
||||
if(href_list["choice"] == "Tertiary color")
|
||||
if(href_list["icon"] == "none")
|
||||
canister_color["ter"] = "none"
|
||||
else if(is_a_color(href_list["icon"],"ter"))
|
||||
canister_color["ter"] = href_list["icon"]
|
||||
if(href_list["choice"] == "Quaternary color")
|
||||
if(href_list["icon"] == "none")
|
||||
canister_color["quart"] = "none"
|
||||
else if(is_a_color(href_list["icon"],"quart"))
|
||||
canister_color["quart"] = href_list["icon"]
|
||||
|
||||
if(href_list["choice"] == "decals")
|
||||
if(is_a_decal(href_list["icon"]))
|
||||
decals[href_list["icon"]] = (decals[href_list["icon"]] == 0)
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
logmsg = "Valve was <b>closed</b> by [key_name(usr)], stopping the transfer into the [holding || "air"].<br>"
|
||||
investigate_log(logmsg, "atmos")
|
||||
release_log += logmsg
|
||||
if("eject")
|
||||
if(holding)
|
||||
if(valve_open)
|
||||
release_log += "[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air<br>"
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the <span class='boldannounce'>air</span>.")
|
||||
investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the <span class='boldannounce'>air</span>.", "atmos")
|
||||
replace_tank(usr, FALSE)
|
||||
if("recolor")
|
||||
if(can_label)
|
||||
var/ctype = params["ctype"]
|
||||
var/cnum = text2num(params["nc"])
|
||||
if(isnull(colorcontainer[ctype]))
|
||||
message_admins("[key_name_admin(usr)] passed an invalid ctype var to a canister.")
|
||||
return
|
||||
var/newcolor = sanitize_integer(cnum, 0, length(colorcontainer[ctype]["options"]))
|
||||
color_index[ctype] = newcolor
|
||||
newcolor++ // javascript starts arrays at 0, byond (for some reason) starts them at 1, this converts JS values to byond values
|
||||
canister_color[ctype] = colorcontainer[ctype]["options"][newcolor]["icon"]
|
||||
add_fingerprint(usr)
|
||||
update_icon()
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/toxins
|
||||
name = "Canister \[Toxin (Plasma)\]"
|
||||
@@ -513,19 +420,18 @@ update_flag
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "orange"
|
||||
decals["plasma"] = 1
|
||||
src.air_contents.toxins = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
air_contents.toxins = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/oxygen/New()
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "blue"
|
||||
src.air_contents.oxygen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
air_contents.oxygen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/sleeping_agent/New()
|
||||
@@ -534,25 +440,25 @@ update_flag
|
||||
canister_color["prim"] = "redws"
|
||||
air_contents.sleeping_agent = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/nitrogen/New()
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "red"
|
||||
src.air_contents.nitrogen = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
air_contents.nitrogen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/carbon_dioxide/New()
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "black"
|
||||
src.air_contents.carbon_dioxide = (src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
air_contents.carbon_dioxide = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
|
||||
@@ -560,17 +466,17 @@ update_flag
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "grey"
|
||||
src.air_contents.oxygen = (O2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
src.air_contents.nitrogen = (N2STANDARD*src.maximum_pressure*filled)*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
|
||||
air_contents.oxygen = (O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
air_contents.nitrogen = (N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
|
||||
|
||||
src.update_icon()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/custom_mix/New()
|
||||
..()
|
||||
|
||||
canister_color["prim"] = "whiters"
|
||||
src.update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
|
||||
update_icon() // Otherwise new canisters do not have their icon updated with the pressure light, likely want to add this to the canister class constructor, avoiding at current time to refrain from screwing up code for other canisters. --DZD
|
||||
return 1
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/welder_act(mob/user, obj/item/I)
|
||||
|
||||
@@ -40,8 +40,7 @@
|
||||
add_fingerprint(user)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/operating/attack_hand(mob/user)
|
||||
if(..(user))
|
||||
@@ -52,16 +51,15 @@
|
||||
|
||||
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)//ui is mostly copy pasta from the sleeper ui
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/computer/operating/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "op_computer.tmpl", "Patient Monitor", 650, 455)
|
||||
ui = new(user, src, ui_key, "OperatingComputer", "Patient Monitor", 650, 455, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/computer/operating/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/operating/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
var/mob/living/carbon/human/occupant
|
||||
if(table)
|
||||
@@ -136,38 +134,43 @@
|
||||
return data
|
||||
|
||||
|
||||
/obj/machinery/computer/operating/Topic(href, href_list)
|
||||
/obj/machinery/computer/operating/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["verboseOn"])
|
||||
verbose=1
|
||||
if(href_list["verboseOff"])
|
||||
verbose=0
|
||||
if(href_list["healthOn"])
|
||||
healthAnnounce=1
|
||||
if(href_list["healthOff"])
|
||||
healthAnnounce=0
|
||||
if(href_list["critOn"])
|
||||
crit=1
|
||||
if(href_list["critOff"])
|
||||
crit=0
|
||||
if(href_list["oxyOn"])
|
||||
oxy=1
|
||||
if(href_list["oxyOff"])
|
||||
oxy=0
|
||||
if(href_list["oxy_adj"]!=0)
|
||||
oxyAlarm=oxyAlarm+text2num(href_list["oxy_adj"])
|
||||
if(href_list["choiceOn"])
|
||||
choice=1
|
||||
if(href_list["choiceOff"])
|
||||
choice=0
|
||||
if(href_list["health_adj"]!=0)
|
||||
healthAlarm=healthAlarm+text2num(href_list["health_adj"])
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("verboseOn")
|
||||
verbose = TRUE
|
||||
if("verboseOff")
|
||||
verbose = FALSE
|
||||
if("healthOn")
|
||||
healthAnnounce = TRUE
|
||||
if("healthOff")
|
||||
healthAnnounce = FALSE
|
||||
if("critOn")
|
||||
crit = TRUE
|
||||
if("critOff")
|
||||
crit = FALSE
|
||||
if("oxyOn")
|
||||
oxy = TRUE
|
||||
if("oxyOff")
|
||||
oxy = FALSE
|
||||
if("oxy_adj")
|
||||
oxyAlarm = clamp(text2num(params["new"]), -100, 100)
|
||||
if("choiceOn")
|
||||
choice = TRUE
|
||||
if("choiceOff")
|
||||
choice = FALSE
|
||||
if("health_adj")
|
||||
healthAlarm = clamp(text2num(params["new"]), -100, 100)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/operating/process()
|
||||
|
||||
@@ -178,6 +181,7 @@
|
||||
atom_say("New patient detected, loading stats")
|
||||
victim = table.victim
|
||||
atom_say("[victim.real_name], [victim.dna.blood_type] blood, [victim.stat ? "Non-Responsive" : "Awake"]")
|
||||
SStgui.update_uis(src)
|
||||
if(nextTick < world.time)
|
||||
nextTick=world.time + OP_COMPUTER_COOLDOWN
|
||||
if(crit && victim.health <= -50 )
|
||||
|
||||
@@ -233,7 +233,10 @@
|
||||
/obj/item/circuitboard/brigcells
|
||||
name = "Circuit board (Brig Cell Control)"
|
||||
build_path = /obj/machinery/computer/brigcells
|
||||
|
||||
/obj/item/circuitboard/sm_monitor
|
||||
name = "Circuit board (Supermatter Monitoring Console)"
|
||||
build_path = /obj/machinery/computer/sm_monitor
|
||||
origin_tech = "programming=2;powerstorage=2"
|
||||
|
||||
// RD console circuits, so that {de,re}constructing one of the special consoles doesn't ruin everything forever
|
||||
/obj/item/circuitboard/rdconsole
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define MENU_MAIN 1
|
||||
#define MENU_RECORDS 2
|
||||
|
||||
/obj/machinery/computer/cloning
|
||||
name = "cloning console"
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
@@ -6,11 +9,11 @@
|
||||
circuit = /obj/item/circuitboard/cloning
|
||||
req_access = list(ACCESS_HEADS) //Only used for record deletion right now.
|
||||
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
|
||||
var/list/pods = list() //Linked cloning pods.
|
||||
var/temp = ""
|
||||
var/scantemp = "Scanner ready."
|
||||
var/menu = 1 //Which menu screen to display
|
||||
var/list/records = list()
|
||||
var/list/pods = null //Linked cloning pods.
|
||||
var/list/temp = null
|
||||
var/list/scantemp = null
|
||||
var/menu = MENU_MAIN //Which menu screen to display
|
||||
var/list/records = null
|
||||
var/datum/dna2/record/active_record = null
|
||||
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
|
||||
var/loading = 0 // Nice loading text
|
||||
@@ -24,6 +27,9 @@
|
||||
|
||||
/obj/machinery/computer/cloning/Initialize()
|
||||
..()
|
||||
pods = list()
|
||||
records = list()
|
||||
set_scan_temp("Scanner ready.", "good")
|
||||
updatemodules()
|
||||
|
||||
/obj/machinery/computer/cloning/Destroy()
|
||||
@@ -91,7 +97,7 @@
|
||||
W.loc = src
|
||||
src.diskette = W
|
||||
to_chat(user, "You insert [W].")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
else if(istype(W, /obj/item/multitool))
|
||||
var/obj/item/multitool/M = W
|
||||
@@ -117,19 +123,21 @@
|
||||
return
|
||||
|
||||
updatemodules()
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/cloning/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
/obj/machinery/computer/cloning/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
// Set up the Nano UI
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
var/datum/asset/cloning/assets = get_asset_datum(/datum/asset/cloning)
|
||||
assets.send(user)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "cloning_console.tmpl", "Cloning Console UI", 640, 520)
|
||||
ui = new(user, src, ui_key, "CloningConsole", "Cloning Console", 640, 520)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/cloning/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/cloning/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["menu"] = src.menu
|
||||
data["scanner"] = sanitize("[src.scanner]")
|
||||
@@ -143,7 +151,18 @@
|
||||
if(pod.efficiency > 5)
|
||||
canpodautoprocess = 1
|
||||
|
||||
tempods.Add(list(list("pod" = "\ref[pod]", "name" = sanitize(capitalize(pod.name)), "biomass" = pod.biomass)))
|
||||
var/status = "idle"
|
||||
if(pod.mess)
|
||||
status = "mess"
|
||||
else if(pod.occupant && !(pod.stat & NOPOWER))
|
||||
status = "cloning"
|
||||
tempods.Add(list(list(
|
||||
"pod" = "\ref[pod]",
|
||||
"name" = sanitize(capitalize(pod.name)),
|
||||
"biomass" = pod.biomass,
|
||||
"status" = status,
|
||||
"progress" = (pod.occupant && pod.occupant.stat != DEAD) ? pod.get_completion() : 0
|
||||
)))
|
||||
data["pods"] = tempods
|
||||
|
||||
data["loading"] = loading
|
||||
@@ -168,188 +187,190 @@
|
||||
temprecords.Add(list(list("record" = "\ref[R]", "realname" = sanitize(tempRealName))))
|
||||
data["records"] = temprecords
|
||||
|
||||
if(src.menu == 3)
|
||||
if(src.active_record)
|
||||
data["activerecord"] = "\ref[src.active_record]"
|
||||
var/obj/item/implant/health/H = null
|
||||
if(src.active_record.implant)
|
||||
H = locate(src.active_record.implant)
|
||||
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
|
||||
data["podready"] = 1
|
||||
else
|
||||
data["podready"] = 0
|
||||
|
||||
if((H) && (istype(H)))
|
||||
data["health"] = H.sensehealth()
|
||||
data["realname"] = sanitize(src.active_record.dna.real_name)
|
||||
data["unidentity"] = src.active_record.dna.uni_identity
|
||||
data["strucenzymes"] = src.active_record.dna.struc_enzymes
|
||||
if(selected_pod && (selected_pod in pods) && selected_pod.biomass >= CLONE_BIOMASS)
|
||||
data["podready"] = 1
|
||||
else
|
||||
data["podready"] = 0
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/cloning/Topic(href, href_list)
|
||||
/obj/machinery/computer/cloning/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(loading)
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["scan"] && scanner && scanner.occupant)
|
||||
scantemp = "Scanner ready."
|
||||
|
||||
loading = 1
|
||||
|
||||
spawn(20)
|
||||
if(can_brainscan() && scan_mode)
|
||||
scan_mob(scanner.occupant, scan_brain = 1)
|
||||
else
|
||||
scan_mob(scanner.occupant)
|
||||
|
||||
loading = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
if(href_list["task"])
|
||||
switch(href_list["task"])
|
||||
if("autoprocess")
|
||||
autoprocess = 1
|
||||
SSnanoui.update_uis(src)
|
||||
if("stopautoprocess")
|
||||
autoprocess = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
//No locking an open scanner.
|
||||
else if((href_list["lock"]) && (!isnull(src.scanner)))
|
||||
if((!src.scanner.locked) && (src.scanner.occupant))
|
||||
src.scanner.locked = 1
|
||||
else
|
||||
src.scanner.locked = 0
|
||||
|
||||
else if(href_list["view_rec"])
|
||||
src.active_record = locate(href_list["view_rec"])
|
||||
if(istype(src.active_record,/datum/dna2/record))
|
||||
if((isnull(src.active_record.ckey)))
|
||||
qdel(src.active_record)
|
||||
src.temp = "<span class=\"bad\">Error: Record corrupt.</span>"
|
||||
else
|
||||
src.menu = 3
|
||||
else
|
||||
src.active_record = null
|
||||
src.temp = "<span class=\"bad\">Error: Record missing.</span>"
|
||||
|
||||
else if(href_list["del_rec"])
|
||||
if((!src.active_record) || (src.menu < 3))
|
||||
return
|
||||
if(src.menu == 3) //If we are viewing a record, confirm deletion
|
||||
src.temp = "Please confirm that you want to delete the record?"
|
||||
src.menu = 4
|
||||
|
||||
else if(src.menu == 4)
|
||||
var/obj/item/card/id/C = usr.get_active_hand()
|
||||
if(istype(C)||istype(C, /obj/item/pda))
|
||||
if(src.check_access(C))
|
||||
src.records.Remove(src.active_record)
|
||||
qdel(src.active_record)
|
||||
src.temp = "Record deleted."
|
||||
src.menu = 2
|
||||
. = TRUE
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
if(params["id"] == "del_rec" && active_record)
|
||||
var/obj/item/card/id/C = usr.get_active_hand()
|
||||
if(!istype(C) && !istype(C, /obj/item/pda))
|
||||
set_temp("ID not in hand.", "danger")
|
||||
return
|
||||
if(check_access(C))
|
||||
records.Remove(active_record)
|
||||
qdel(active_record)
|
||||
set_temp("Record deleted.", "success")
|
||||
menu = MENU_RECORDS
|
||||
else
|
||||
src.temp = "<span class=\"bad\">Error: Access denied.</span>"
|
||||
|
||||
else if(href_list["disk"]) //Load or eject.
|
||||
switch(href_list["disk"])
|
||||
if("load")
|
||||
if((isnull(src.diskette)) || isnull(src.diskette.buf))
|
||||
src.temp = "<span class=\"bad\">Error: The disk's data could not be read.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
if(isnull(src.active_record))
|
||||
src.temp = "<span class=\"bad\">Error: No active record was found.</span>"
|
||||
src.menu = 1
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
src.active_record = src.diskette.buf.copy()
|
||||
|
||||
src.temp = "Load successful."
|
||||
|
||||
if("eject")
|
||||
if(!isnull(src.diskette))
|
||||
src.diskette.loc = src.loc
|
||||
src.diskette = null
|
||||
|
||||
else if(href_list["save_disk"]) //Save to disk!
|
||||
if((isnull(src.diskette)) || (src.diskette.read_only) || (isnull(src.active_record)))
|
||||
src.temp = "<span class=\"bad\">Error: The data could not be saved.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_temp("Access denied.", "danger")
|
||||
return
|
||||
|
||||
// DNA2 makes things a little simpler.
|
||||
src.diskette.buf=src.active_record.copy()
|
||||
src.diskette.buf.types=0
|
||||
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
|
||||
if("ui")
|
||||
src.diskette.buf.types=DNA2_BUF_UI
|
||||
if("ue")
|
||||
src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE
|
||||
if("se")
|
||||
src.diskette.buf.types=DNA2_BUF_SE
|
||||
src.diskette.name = "data disk - '[src.active_record.dna.real_name]'"
|
||||
src.temp = "Save \[[href_list["save_disk"]]\] successful."
|
||||
switch(action)
|
||||
if("scan")
|
||||
if(!scanner || !scanner.occupant || loading)
|
||||
return
|
||||
set_scan_temp("Scanner ready.", "good")
|
||||
loading = TRUE
|
||||
|
||||
else if(href_list["refresh"])
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["selectpod"])
|
||||
var/obj/machinery/clonepod/selected = locate(href_list["selectpod"])
|
||||
if(istype(selected) && (selected in pods))
|
||||
selected_pod = selected
|
||||
|
||||
else if(href_list["clone"])
|
||||
var/datum/dna2/record/C = locate(href_list["clone"])
|
||||
//Look for that player! They better be dead!
|
||||
if(istype(C))
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!pods.len)
|
||||
temp = "<span class=\"bad\">Error: No cloning pod detected.</span>"
|
||||
else
|
||||
var/obj/machinery/clonepod/pod = selected_pod
|
||||
var/cloneresult
|
||||
if(!selected_pod)
|
||||
temp = "<span class=\"bad\">Error: No cloning pod selected.</span>"
|
||||
else if(pod.occupant)
|
||||
temp = "<span class=\"bad\">Error: The cloning pod is currently occupied.</span>"
|
||||
else if(pod.biomass < CLONE_BIOMASS)
|
||||
temp = "<span class=\"bad\">Error: Not enough biomass.</span>"
|
||||
else if(pod.mess)
|
||||
temp = "<span class=\"bad\">Error: The cloning pod is malfunctioning.</span>"
|
||||
else if(!config.revival_cloning)
|
||||
temp = "<span class=\"bad\">Error: Unable to initiate cloning cycle.</span>"
|
||||
spawn(20)
|
||||
if(can_brainscan() && scan_mode)
|
||||
scan_mob(scanner.occupant, scan_brain = TRUE)
|
||||
else
|
||||
cloneresult = pod.growclone(C)
|
||||
if(cloneresult)
|
||||
if(cloneresult > 0)
|
||||
temp = "Initiating cloning cycle..."
|
||||
records.Remove(C)
|
||||
qdel(C)
|
||||
menu = 1
|
||||
scan_mob(scanner.occupant)
|
||||
loading = FALSE
|
||||
SStgui.update_uis(src)
|
||||
if("autoprocess")
|
||||
autoprocess = text2num(params["on"]) > 0
|
||||
if("lock")
|
||||
if(isnull(scanner) || !scanner.occupant) //No locking an open scanner.
|
||||
return
|
||||
scanner.locked = !scanner.locked
|
||||
if("view_rec")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
active_record = locate(ref)
|
||||
if(istype(active_record))
|
||||
if(isnull(active_record.ckey))
|
||||
qdel(active_record)
|
||||
set_temp("Error: Record corrupt.", "danger")
|
||||
else
|
||||
var/obj/item/implant/health/H = null
|
||||
if(active_record.implant)
|
||||
H = locate(active_record.implant)
|
||||
var/list/payload = list(
|
||||
activerecord = "\ref[active_record]",
|
||||
health = (H && istype(H)) ? H.sensehealth() : "",
|
||||
realname = sanitize(active_record.dna.real_name),
|
||||
unidentity = active_record.dna.uni_identity,
|
||||
strucenzymes = active_record.dna.struc_enzymes,
|
||||
)
|
||||
tgui_modal_message(src, action, "", null, payload)
|
||||
else
|
||||
active_record = null
|
||||
set_temp("Error: Record missing.", "danger")
|
||||
if("del_rec")
|
||||
if(!active_record)
|
||||
return
|
||||
tgui_modal_boolean(src, action, "Please confirm that you want to delete the record by holding your ID and pressing Delete:", yes_text = "Delete", no_text = "Cancel")
|
||||
if("disk") // Disk management.
|
||||
if(!length(params["option"]))
|
||||
return
|
||||
switch(params["option"])
|
||||
if("load")
|
||||
if(isnull(diskette) || isnull(diskette.buf))
|
||||
set_temp("Error: The disk's data could not be read.", "danger")
|
||||
return
|
||||
else if(isnull(active_record))
|
||||
set_temp("Error: No active record was found.", "danger")
|
||||
menu = MENU_MAIN
|
||||
return
|
||||
|
||||
active_record = diskette.buf.copy()
|
||||
set_temp("Successfully loaded from disk.", "success")
|
||||
if("save")
|
||||
if(isnull(diskette) || diskette.read_only || isnull(active_record))
|
||||
set_temp("Error: The data could not be saved.", "danger")
|
||||
return
|
||||
|
||||
// DNA2 makes things a little simpler.
|
||||
var/types
|
||||
switch(params["savetype"]) // Save as Ui/Ui+Ue/Se
|
||||
if("ui")
|
||||
types = DNA2_BUF_UI
|
||||
if("ue")
|
||||
types = DNA2_BUF_UI|DNA2_BUF_UE
|
||||
if("se")
|
||||
types = DNA2_BUF_SE
|
||||
else
|
||||
set_temp("Error: Invalid save format.", "danger")
|
||||
return
|
||||
diskette.buf = active_record.copy()
|
||||
diskette.buf.types = types
|
||||
diskette.name = "data disk - '[active_record.dna.real_name]'"
|
||||
set_temp("Successfully saved to disk.", "success")
|
||||
if("eject")
|
||||
if(!isnull(diskette))
|
||||
diskette.loc = loc
|
||||
diskette = null
|
||||
if("refresh")
|
||||
SStgui.update_uis(src)
|
||||
if("selectpod")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/obj/machinery/clonepod/selected = locate(ref)
|
||||
if(istype(selected) && (selected in pods))
|
||||
selected_pod = selected
|
||||
if("clone")
|
||||
var/ref = params["ref"]
|
||||
if(!length(ref))
|
||||
return
|
||||
var/datum/dna2/record/C = locate(ref)
|
||||
//Look for that player! They better be dead!
|
||||
if(istype(C))
|
||||
tgui_modal_clear(src)
|
||||
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
|
||||
if(!length(pods))
|
||||
set_temp("Error: No cloning pod detected.", "danger")
|
||||
else
|
||||
var/obj/machinery/clonepod/pod = selected_pod
|
||||
var/cloneresult
|
||||
if(!selected_pod)
|
||||
set_temp("Error: No cloning pod selected.", "danger")
|
||||
else if(pod.occupant)
|
||||
set_temp("Error: The cloning pod is currently occupied.", "danger")
|
||||
else if(pod.biomass < CLONE_BIOMASS)
|
||||
set_temp("Error: Not enough biomass.", "danger")
|
||||
else if(pod.mess)
|
||||
set_temp("Error: The cloning pod is malfunctioning.", "danger")
|
||||
else if(!config.revival_cloning)
|
||||
set_temp("Error: Unable to initiate cloning cycle.", "danger")
|
||||
else
|
||||
temp = "[C.name] => <font class='bad'>Initialisation failure.</font>"
|
||||
|
||||
cloneresult = pod.growclone(C)
|
||||
if(cloneresult)
|
||||
set_temp("Initiating cloning cycle...", "success")
|
||||
records.Remove(C)
|
||||
qdel(C)
|
||||
menu = MENU_MAIN
|
||||
else
|
||||
set_temp("Error: Initialisation failure.", "danger")
|
||||
else
|
||||
set_temp("Error: Data corruption.", "danger")
|
||||
if("menu")
|
||||
menu = clamp(text2num(params["num"]), MENU_MAIN, MENU_RECORDS)
|
||||
if("toggle_mode")
|
||||
if(loading)
|
||||
return
|
||||
if(can_brainscan())
|
||||
scan_mode = !scan_mode
|
||||
else
|
||||
scan_mode = FALSE
|
||||
if("eject")
|
||||
if(usr.incapacitated() || !scanner || loading)
|
||||
return
|
||||
scanner.eject_occupant(usr)
|
||||
scanner.add_fingerprint(usr)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
else
|
||||
temp = "<span class=\"bad\">Error: Data corruption.</span>"
|
||||
|
||||
else if(href_list["menu"])
|
||||
src.menu = text2num(href_list["menu"])
|
||||
temp = ""
|
||||
scantemp = "Scanner ready."
|
||||
else if(href_list["toggle_mode"])
|
||||
if(can_brainscan())
|
||||
scan_mode = !scan_mode
|
||||
else
|
||||
scan_mode = 0
|
||||
return FALSE
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob, var/scan_brain = 0)
|
||||
if(stat & NOPOWER)
|
||||
@@ -360,46 +381,46 @@
|
||||
return
|
||||
if(isnull(subject) || (!(ishuman(subject))) || (!subject.dna))
|
||||
if(isalien(subject))
|
||||
scantemp = "<span class=\"bad\">Error: Xenomorphs are not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Xenomorphs are not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
// can add more conditions for specific non-human messages here
|
||||
else
|
||||
scantemp = "<span class=\"bad\">Error: Subject species is not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject species is not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(subject.get_int_organ(/obj/item/organ/internal/brain))
|
||||
var/obj/item/organ/internal/brain/Brn = subject.get_int_organ(/obj/item/organ/internal/brain)
|
||||
if(istype(Brn))
|
||||
if(NO_SCAN in Brn.dna.species.species_traits)
|
||||
scantemp = "<span class=\"bad\">Error: [Brn.dna.species.name_plural] are not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("[Brn.dna.species.name_plural] are not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(!subject.get_int_organ(/obj/item/organ/internal/brain))
|
||||
scantemp = "<span class=\"bad\">Error: No brain detected in subject.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("No brain detected in subject.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(subject.suiciding)
|
||||
scantemp = "<span class=\"bad\">Error: Subject has committed suicide and is not scannable.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject has committed suicide and is not scannable.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if((!subject.ckey) || (!subject.client))
|
||||
scantemp = "<span class=\"bad\">Error: Subject's brain is not responding. Further attempts after a short delay may succeed.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject's brain is not responding. Further attempts after a short delay may succeed.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if((NOCLONE in subject.mutations) && src.scanner.scan_level < 2)
|
||||
scantemp = "<span class=\"bad\">Error: Subject has incompatible genetic mutations.</span>"
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject has incompatible genetic mutations.", "bad")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
if(!isnull(find_record(subject.ckey)))
|
||||
scantemp = "Subject already in database."
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject already in database.")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
for(var/obj/machinery/clonepod/pod in pods)
|
||||
if(pod.occupant && pod.clonemind == subject.mind)
|
||||
scantemp = "Subject already getting cloned."
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject already getting cloned.")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
subject.dna.check_integrity()
|
||||
@@ -434,8 +455,8 @@
|
||||
R.mind = "\ref[subject.mind]"
|
||||
|
||||
src.records += R
|
||||
scantemp = "Subject successfully scanned. " + extra_info
|
||||
SSnanoui.update_uis(src)
|
||||
set_scan_temp("Subject successfully scanned. [extra_info]", "good")
|
||||
SStgui.update_uis(src)
|
||||
|
||||
//Find a specific record by key.
|
||||
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
|
||||
@@ -451,3 +472,30 @@
|
||||
|
||||
/obj/machinery/computer/cloning/proc/can_brainscan()
|
||||
return (scanner && scanner.scan_level > 3)
|
||||
|
||||
/**
|
||||
* Sets a temporary message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * style - The style of the message: (color name), info, success, warning, danger
|
||||
*/
|
||||
/obj/machinery/computer/cloning/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Sets a temporary scan message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * color - The color of the message: (color name)
|
||||
*/
|
||||
/obj/machinery/computer/cloning/proc/set_scan_temp(text = "", color = "", update_now = FALSE)
|
||||
scantemp = list(text = text, color = color)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
#undef MENU_MAIN
|
||||
#undef MENU_RECORDS
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#define MED_DATA_MAIN 1 // Main menu
|
||||
#define MED_DATA_R_LIST 2 // Record list
|
||||
#define MED_DATA_MAINT 3 // Records maintenance
|
||||
#define MED_DATA_RECORD 4 // Record
|
||||
#define MED_DATA_V_DATA 5 // Virus database
|
||||
#define MED_DATA_MEDBOT 6 // Medbot monitor
|
||||
|
||||
#define FIELD(N, V, E) list(field = N, value = V, edit = E)
|
||||
#define MED_FIELD(N, V, E, LB) list(field = N, value = V, edit = E, line_break = LB)
|
||||
|
||||
/obj/machinery/computer/med_data //TODO:SANITY
|
||||
name = "medical records console"
|
||||
desc = "This can be used to check medical records."
|
||||
@@ -18,11 +20,45 @@
|
||||
var/screen = null
|
||||
var/datum/data/record/active1 = null
|
||||
var/datum/data/record/active2 = null
|
||||
var/temp = null
|
||||
var/list/temp = null
|
||||
var/printing = null
|
||||
// The below are used to make modal generation more convenient
|
||||
var/static/list/field_edit_questions
|
||||
var/static/list/field_edit_choices
|
||||
|
||||
light_color = LIGHT_COLOR_DARKBLUE
|
||||
|
||||
/obj/machinery/computer/med_data/Initialize()
|
||||
..()
|
||||
field_edit_questions = list(
|
||||
// General
|
||||
"sex" = "Please select new sex:",
|
||||
"age" = "Please input new age:",
|
||||
"fingerprint" = "Please input new fingerprint hash:",
|
||||
"p_stat" = "Please select new physical status:",
|
||||
"m_stat" = "Please select new mental status:",
|
||||
// Medical
|
||||
"blood_type" = "Please select new blood type:",
|
||||
"b_dna" = "Please input new DNA:",
|
||||
"mi_dis" = "Please input new minor disabilities:",
|
||||
"mi_dis_d" = "Please summarize minor disabilities:",
|
||||
"ma_dis" = "Please input new major disabilities:",
|
||||
"ma_dis_d" = "Please summarize major disabilities:",
|
||||
"alg" = "Please input new allergies:",
|
||||
"alg_d" = "Please summarize allergies:",
|
||||
"cdi" = "Please input new current diseases:",
|
||||
"cdi_d" = "Please summarize current diseases:",
|
||||
"notes" = "Please input new important notes:",
|
||||
)
|
||||
field_edit_choices = list(
|
||||
// General
|
||||
"sex" = list("Male", "Female"),
|
||||
"p_stat" = list("*Deceased*", "*SSD*", "Active", "Physically Unfit", "Disabled"),
|
||||
"m_stat" = list("*Insane*", "*Unstable*", "*Watch*", "Stable"),
|
||||
// Medical
|
||||
"blood_type" = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"),
|
||||
)
|
||||
|
||||
/obj/machinery/computer/med_data/Destroy()
|
||||
active1 = null
|
||||
active2 = null
|
||||
@@ -33,7 +69,7 @@
|
||||
usr.drop_item()
|
||||
O.forceMove(src)
|
||||
scan = O
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -44,20 +80,25 @@
|
||||
to_chat(user, "<span class='danger'>Unable to establish a connection</span>: You're too far away from the station!")
|
||||
return
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/med_data/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/computer/med_data/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "med_data.tmpl", name, 800, 380)
|
||||
ui = new(user, src, ui_key, "MedicalRecords", "Medical Records", 800, 380, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE)
|
||||
|
||||
/obj/machinery/computer/med_data/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/computer/med_data/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["temp"] = temp
|
||||
data["scan"] = scan ? scan.name : null
|
||||
data["authenticated"] = authenticated
|
||||
data["rank"] = rank
|
||||
data["screen"] = screen
|
||||
data["printing"] = printing
|
||||
data["isAI"] = isAI(user)
|
||||
data["isRobot"] = isrobot(user)
|
||||
if(authenticated)
|
||||
switch(screen)
|
||||
if(MED_DATA_R_LIST)
|
||||
@@ -72,17 +113,17 @@
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
var/list/fields = list()
|
||||
general["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "edit" = null)
|
||||
fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "edit" = null)
|
||||
fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "edit" = "sex")
|
||||
fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "edit" = "age")
|
||||
fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "edit" = "fingerprint")
|
||||
fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"], "edit" = "p_stat")
|
||||
fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"], "edit" = "m_stat")
|
||||
fields[++fields.len] = FIELD("Name", active1.fields["name"], null)
|
||||
fields[++fields.len] = FIELD("ID", active1.fields["id"], null)
|
||||
fields[++fields.len] = FIELD("Sex", active1.fields["sex"], "sex")
|
||||
fields[++fields.len] = FIELD("Age", active1.fields["age"], "age")
|
||||
fields[++fields.len] = FIELD("Fingerprint", active1.fields["fingerprint"], "fingerprint")
|
||||
fields[++fields.len] = FIELD("Physical Status", active1.fields["p_stat"], "p_stat")
|
||||
fields[++fields.len] = FIELD("Mental Status", active1.fields["m_stat"], "m_stat")
|
||||
var/list/photos = list()
|
||||
general["photos"] = photos
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-south"])
|
||||
photos[++photos.len] = list("photo" = active1.fields["photo-west"])
|
||||
photos[++photos.len] = active1.fields["photo-south"]
|
||||
photos[++photos.len] = active1.fields["photo-west"]
|
||||
general["has_photos"] = (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0)
|
||||
general["empty"] = 0
|
||||
else
|
||||
@@ -93,17 +134,17 @@
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
var/list/fields = list()
|
||||
medical["fields"] = fields
|
||||
fields[++fields.len] = list("field" = "Blood Type:", "value" = active2.fields["blood_type"], "edit" = "blood_type", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "DNA:", "value" = active2.fields["b_dna"], "edit" = "b_dna", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Minor Disabilities:", "value" = active2.fields["mi_dis"], "edit" = "mi_dis", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["mi_dis_d"], "edit" = "mi_dis_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Major Disabilities:", "value" = active2.fields["ma_dis"], "edit" = "ma_dis", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["ma_dis_d"], "edit" = "ma_dis_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Allergies:", "value" = active2.fields["alg"], "edit" = "alg", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["alg_d"], "edit" = "alg_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Current Diseases:", "value" = active2.fields["cdi"], "edit" = "cdi", "line_break" = 0)
|
||||
fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["cdi_d"], "edit" = "cdi_d", "line_break" = 1)
|
||||
fields[++fields.len] = list("field" = "Important Notes:", "value" = active2.fields["notes"], "edit" = "notes", "line_break" = 0)
|
||||
fields[++fields.len] = MED_FIELD("Blood Type", active2.fields["blood_type"], "blood_type", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("DNA", active2.fields["b_dna"], "b_dna", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Minor Disabilities", active2.fields["mi_dis"], "mi_dis", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["mi_dis_d"], "mi_dis_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Major Disabilities", active2.fields["ma_dis"], "ma_dis", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["ma_dis_d"], "ma_dis_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Allergies", active2.fields["alg"], "alg", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["alg_d"], "alg_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Current Diseases", active2.fields["cdi"], "cdi", FALSE)
|
||||
fields[++fields.len] = MED_FIELD("Details", active2.fields["cdi_d"], "cdi_d", TRUE)
|
||||
fields[++fields.len] = MED_FIELD("Important Notes", active2.fields["notes"], "notes", TRUE)
|
||||
if(!active2.fields["comments"] || !islist(active2.fields["comments"]))
|
||||
active2.fields["comments"] = list()
|
||||
medical["comments"] = active2.fields["comments"]
|
||||
@@ -127,7 +168,9 @@
|
||||
var/turf/T = get_turf(M)
|
||||
if(T)
|
||||
var/medbot = list()
|
||||
var/area/A = get_area(T)
|
||||
medbot["name"] = M.name
|
||||
medbot["area"] = A.name
|
||||
medbot["x"] = T.x
|
||||
medbot["y"] = T.y
|
||||
medbot["on"] = M.on
|
||||
@@ -138,395 +181,290 @@
|
||||
else
|
||||
medbot["use_beaker"] = 0
|
||||
data["medbots"] += list(medbot)
|
||||
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/med_data/Topic(href, href_list)
|
||||
/obj/machinery/computer/med_data/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(!GLOB.data_core.general.Find(active1))
|
||||
active1 = null
|
||||
if(!GLOB.data_core.medical.Find(active2))
|
||||
active2 = null
|
||||
|
||||
if(href_list["temp"])
|
||||
temp = null
|
||||
. = TRUE
|
||||
if(tgui_act_modal(action, params))
|
||||
return
|
||||
|
||||
if(href_list["temp_action"])
|
||||
if(href_list["temp_action"])
|
||||
var/temp_href = splittext(href_list["temp_action"], "=")
|
||||
switch(temp_href[1])
|
||||
if("del_all2")
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
qdel(R)
|
||||
setTemp("<h3>All records deleted.</h3>")
|
||||
if("p_stat")
|
||||
if(active1)
|
||||
switch(temp_href[2])
|
||||
if("deceased")
|
||||
active1.fields["p_stat"] = "*Deceased*"
|
||||
if("ssd")
|
||||
active1.fields["p_stat"] = "*SSD*"
|
||||
if("active")
|
||||
active1.fields["p_stat"] = "Active"
|
||||
if("unfit")
|
||||
active1.fields["p_stat"] = "Physically Unfit"
|
||||
if("disabled")
|
||||
active1.fields["p_stat"] = "Disabled"
|
||||
if("m_stat")
|
||||
if(active1)
|
||||
switch(temp_href[2])
|
||||
if("insane")
|
||||
active1.fields["m_stat"] = "*Insane*"
|
||||
if("unstable")
|
||||
active1.fields["m_stat"] = "*Unstable*"
|
||||
if("watch")
|
||||
active1.fields["m_stat"] = "*Watch*"
|
||||
if("stable")
|
||||
active1.fields["m_stat"] = "Stable"
|
||||
if("blood_type")
|
||||
if(active2)
|
||||
switch(temp_href[2])
|
||||
if("an")
|
||||
active2.fields["blood_type"] = "A-"
|
||||
if("bn")
|
||||
active2.fields["blood_type"] = "B-"
|
||||
if("abn")
|
||||
active2.fields["blood_type"] = "AB-"
|
||||
if("on")
|
||||
active2.fields["blood_type"] = "O-"
|
||||
if("ap")
|
||||
active2.fields["blood_type"] = "A+"
|
||||
if("bp")
|
||||
active2.fields["blood_type"] = "B+"
|
||||
if("abp")
|
||||
active2.fields["blood_type"] = "AB+"
|
||||
if("op")
|
||||
active2.fields["blood_type"] = "O+"
|
||||
if("del_r2")
|
||||
QDEL_NULL(active2)
|
||||
|
||||
if(href_list["scan"])
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
switch(action)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
if("scan")
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
if("login")
|
||||
var/login_type = text2num(params["login_type"])
|
||||
if(login_type == LOGIN_TYPE_NORMAL && istype(scan))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
else if(login_type == LOGIN_TYPE_AI && isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_R_LIST
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/card/id))
|
||||
usr.drop_item()
|
||||
I.forceMove(src)
|
||||
scan = I
|
||||
. = FALSE
|
||||
|
||||
if(href_list["login"])
|
||||
if(isAI(usr))
|
||||
authenticated = usr.name
|
||||
rank = "AI"
|
||||
else if(isrobot(usr))
|
||||
authenticated = usr.name
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
rank = "[R.modtype] [R.braintype]"
|
||||
else if(istype(scan, /obj/item/card/id))
|
||||
if(check_access(scan))
|
||||
authenticated = scan.registered_name
|
||||
rank = scan.assignment
|
||||
|
||||
if(authenticated)
|
||||
active1 = null
|
||||
active2 = null
|
||||
screen = MED_DATA_MAIN
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(authenticated)
|
||||
if(href_list["logout"])
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("logout")
|
||||
if(scan)
|
||||
scan.forceMove(loc)
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(scan)
|
||||
scan = null
|
||||
authenticated = null
|
||||
screen = null
|
||||
active1 = null
|
||||
active2 = null
|
||||
if("screen")
|
||||
screen = clamp(text2num(params["screen"]) || 0, MED_DATA_R_LIST, MED_DATA_MEDBOT)
|
||||
active1 = null
|
||||
active2 = null
|
||||
if("vir")
|
||||
var/type = text2path(params["vir"] || "")
|
||||
if(!ispath(type, /datum/disease))
|
||||
return
|
||||
|
||||
if(href_list["screen"])
|
||||
screen = text2num(href_list["screen"])
|
||||
if(screen < 1)
|
||||
screen = MED_DATA_MAIN
|
||||
var/datum/disease/D = new type(0)
|
||||
var/list/payload = list(
|
||||
name = D.name,
|
||||
max_stages = D.max_stages,
|
||||
spread_text = D.spread_text,
|
||||
cure = D.cure_text || "None",
|
||||
desc = D.desc,
|
||||
severity = D.severity
|
||||
);
|
||||
tgui_modal_message(src, "virus", "", null, payload)
|
||||
qdel(D)
|
||||
if("del_all")
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
qdel(R)
|
||||
set_temp("All medical records deleted.")
|
||||
if("del_r")
|
||||
if(active2)
|
||||
set_temp("Medical record deleted.")
|
||||
qdel(active2)
|
||||
if("d_rec")
|
||||
var/datum/data/record/general_record = locate(params["d_rec"] || "")
|
||||
if(!GLOB.data_core.general.Find(general_record))
|
||||
set_temp("Record not found.", "danger")
|
||||
return
|
||||
|
||||
active1 = null
|
||||
active2 = null
|
||||
var/datum/data/record/medical_record
|
||||
for(var/datum/data/record/M in GLOB.data_core.medical)
|
||||
if(M.fields["name"] == general_record.fields["name"] && M.fields["id"] == general_record.fields["id"])
|
||||
medical_record = M
|
||||
break
|
||||
|
||||
if(href_list["vir"])
|
||||
var/type = href_list["vir"]
|
||||
var/datum/disease/D = new type(0)
|
||||
var/afs = ""
|
||||
for(var/mob/M in D.viable_mobtypes)
|
||||
afs += "[initial(M.name)];"
|
||||
var/severity = D.severity
|
||||
switch(severity)
|
||||
if("Harmful", "Minor")
|
||||
severity = "<span class='good'>[severity]</span>"
|
||||
if("Medium")
|
||||
severity = "<span class='average'>[severity]</span>"
|
||||
if("Dangerous!")
|
||||
severity = "<span class='bad'>[severity]</span>"
|
||||
if("BIOHAZARD THREAT!")
|
||||
severity = "<h4><span class='bad'>[severity]</span></h4>"
|
||||
setTemp({"<b>Name:</b> [D.name]
|
||||
<BR><b>Number of stages:</b> [D.max_stages]
|
||||
<BR><b>Spread:</b> [D.spread_text] Transmission
|
||||
<BR><b>Possible Cure:</b> [(D.cure_text||"none")]
|
||||
<BR><b>Affected Lifeforms:</b>[afs]<BR>
|
||||
<BR><b>Notes:</b> [D.desc]<BR>
|
||||
<BR><b>Severity:</b> [severity]"})
|
||||
qdel(D)
|
||||
|
||||
if(href_list["del_all"])
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_all2=1")
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete all records?</h3>", buttons)
|
||||
|
||||
if(href_list["field"])
|
||||
if(..())
|
||||
return 1
|
||||
var/a1 = active1
|
||||
var/a2 = active2
|
||||
switch(href_list["field"])
|
||||
if("fingerprint")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["fingerprint"] = t1
|
||||
if("sex")
|
||||
if(istype(active1, /datum/data/record))
|
||||
if(active1.fields["sex"] == "Male")
|
||||
active1.fields["sex"] = "Female"
|
||||
else
|
||||
active1.fields["sex"] = "Male"
|
||||
if("age")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
active1.fields["age"] = t1
|
||||
if("mi_dis")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_dis"] = t1
|
||||
if("mi_dis_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["mi_dis_d"] = t1
|
||||
if("ma_dis")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input major diabilities list:", "Med. records", active2.fields["ma_dis"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_dis"] = t1
|
||||
if("ma_dis_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["ma_dis_d"] = t1
|
||||
if("alg")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please state allergies:", "Med. records", active2.fields["alg"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["alg"] = t1
|
||||
if("alg_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["alg_d"] = t1
|
||||
if("cdi")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please state diseases:", "Med. records", active2.fields["cdi"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["cdi"] = t1
|
||||
if("cdi_d")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["cdi_d"] = t1
|
||||
if("notes")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Med. records", html_decode(active2.fields["notes"]), null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["notes"] = t1
|
||||
if("p_stat")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "*Deceased*", "icon" = "stethoscope", "href" = "p_stat=deceased", "status" = (active1.fields["p_stat"] == "*Deceased*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*SSD*", "icon" = "stethoscope", "href" = "p_stat=ssd", "status" = (active1.fields["p_stat"] == "*SSD*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Active", "icon" = "stethoscope", "href" = "p_stat=active", "status" = (active1.fields["p_stat"] == "Active" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Physically Unfit", "icon" = "stethoscope", "href" = "p_stat=unfit", "status" = (active1.fields["p_stat"] == "Physically Unfit" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Disabled", "icon" = "stethoscope", "href" = "p_stat=disabled", "status" = (active1.fields["p_stat"] == "Disabled" ? "selected" : null))
|
||||
setTemp("<h3>Physical Condition</h3>", buttons)
|
||||
if("m_stat")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "*Insane*", "icon" = "stethoscope", "href" = "m_stat=insane", "status" = (active1.fields["m_stat"] == "*Insane*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Unstable*", "icon" = "stethoscope", "href" = "m_stat=unstable", "status" = (active1.fields["m_stat"] == "*Unstable*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "*Watch*", "icon" = "stethoscope", "href" = "m_stat=watch", "status" = (active1.fields["m_stat"] == "*Watch*" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "Stable", "icon" = "stethoscope", "href" = "m_stat=stable", "status" = (active1.fields["m_stat"] == "Stable" ? "selected" : null))
|
||||
setTemp("<h3>Mental Condition</h3>", buttons)
|
||||
if("blood_type")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "A-", "icon" = "tint", "href" = "blood_type=an", "status" = (active2.fields["blood_type"] == "A-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "A+", "icon" = "tint", "href" = "blood_type=ap", "status" = (active2.fields["blood_type"] == "A+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "B-", "icon" = "tint", "href" = "blood_type=bn", "status" = (active2.fields["blood_type"] == "B-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "B+", "icon" = "tint", "href" = "blood_type=bp", "status" = (active2.fields["blood_type"] == "B+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "AB-", "icon" = "tint", "href" = "blood_type=abn", "status" = (active2.fields["blood_type"] == "AB-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "AB+", "icon" = "tint", "href" = "blood_type=abp", "status" = (active2.fields["blood_type"] == "AB+" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "O-", "icon" = "tint", "href" = "blood_type=on", "status" = (active2.fields["blood_type"] == "O-" ? "selected" : null))
|
||||
buttons[++buttons.len] = list("name" = "O+", "icon" = "tint", "href" = "blood_type=op", "status" = (active2.fields["blood_type"] == "O+" ? "selected" : null))
|
||||
setTemp("<h3>Blood Type</h3>", buttons)
|
||||
if("b_dna")
|
||||
if(istype(active2, /datum/data/record))
|
||||
var/t1 = copytext(trim(sanitize(input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["b_dna"] = t1
|
||||
if("vir_name")
|
||||
var/datum/data/record/v = locate(href_list["edit_vir"])
|
||||
if(v)
|
||||
var/t1 = copytext(trim(sanitize(input("Please input pathogen name:", "VirusDB", v.fields["name"], null) as text)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
v.fields["name"] = t1
|
||||
if("vir_desc")
|
||||
var/datum/data/record/v = locate(href_list["edit_vir"])
|
||||
if(v)
|
||||
var/t1 = copytext(trim(sanitize(input("Please input information about pathogen:", "VirusDB", v.fields["description"], null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active1 != a1)
|
||||
return 1
|
||||
v.fields["description"] = t1
|
||||
|
||||
if(href_list["del_r"])
|
||||
if(active2)
|
||||
var/list/buttons = list()
|
||||
buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_r2=1", "status" = null)
|
||||
buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null)
|
||||
setTemp("<h3>Are you sure you wish to delete the record (Medical Portion Only)?</h3>", buttons)
|
||||
|
||||
if(href_list["d_rec"])
|
||||
var/datum/data/record/R = locate(href_list["d_rec"])
|
||||
var/datum/data/record/M = locate(href_list["d_rec"])
|
||||
if(!GLOB.data_core.general.Find(R))
|
||||
setTemp("<h3 class='bad'>Record not found!</h3>")
|
||||
return 1
|
||||
for(var/datum/data/record/E in GLOB.data_core.medical)
|
||||
if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])
|
||||
M = E
|
||||
active1 = R
|
||||
active2 = M
|
||||
screen = MED_DATA_RECORD
|
||||
|
||||
if(href_list["new"])
|
||||
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
|
||||
var/datum/data/record/R = new /datum/data/record()
|
||||
R.fields["name"] = active1.fields["name"]
|
||||
R.fields["id"] = active1.fields["id"]
|
||||
R.name = "Medical Record #[R.fields["id"]]"
|
||||
R.fields["blood_type"] = "Unknown"
|
||||
R.fields["b_dna"] = "Unknown"
|
||||
R.fields["mi_dis"] = "None"
|
||||
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
||||
R.fields["ma_dis"] = "None"
|
||||
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
|
||||
R.fields["alg"] = "None"
|
||||
R.fields["alg_d"] = "No allergies have been detected in this patient."
|
||||
R.fields["cdi"] = "None"
|
||||
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
||||
R.fields["notes"] = "No notes."
|
||||
GLOB.data_core.medical += R
|
||||
active2 = R
|
||||
active1 = general_record
|
||||
active2 = medical_record
|
||||
screen = MED_DATA_RECORD
|
||||
|
||||
if(href_list["add_c"])
|
||||
if(!istype(active2, /datum/data/record))
|
||||
return 1
|
||||
var/a2 = active2
|
||||
var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)), 1, MAX_MESSAGE_LEN)
|
||||
if(!t1 || ..() || active2 != a2)
|
||||
return 1
|
||||
active2.fields["comments"] += "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]<BR>[t1]"
|
||||
|
||||
if(href_list["del_c"])
|
||||
var/index = min(max(text2num(href_list["del_c"]) + 1, 1), length(active2.fields["comments"]))
|
||||
if(istype(active2, /datum/data/record) && active2.fields["comments"][index])
|
||||
active2.fields["comments"] -= active2.fields["comments"][index]
|
||||
|
||||
if(href_list["search"])
|
||||
var/t1 = clean_input("Search String: (Name, DNA, or ID)", "Med. records", null, null)
|
||||
if(!t1 || ..())
|
||||
return 1
|
||||
active1 = null
|
||||
active2 = null
|
||||
t1 = lowertext(t1)
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
|
||||
if("new")
|
||||
if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record))
|
||||
var/datum/data/record/R = new /datum/data/record()
|
||||
R.fields["name"] = active1.fields["name"]
|
||||
R.fields["id"] = active1.fields["id"]
|
||||
R.name = "Medical Record #[R.fields["id"]]"
|
||||
R.fields["blood_type"] = "Unknown"
|
||||
R.fields["b_dna"] = "Unknown"
|
||||
R.fields["mi_dis"] = "None"
|
||||
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
|
||||
R.fields["ma_dis"] = "None"
|
||||
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
|
||||
R.fields["alg"] = "None"
|
||||
R.fields["alg_d"] = "No allergies have been detected in this patient."
|
||||
R.fields["cdi"] = "None"
|
||||
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
|
||||
R.fields["notes"] = "No notes."
|
||||
GLOB.data_core.medical += R
|
||||
active2 = R
|
||||
if(!active2)
|
||||
setTemp("<h3 class='bad'>Could not locate record [t1].</h3>")
|
||||
else
|
||||
screen = MED_DATA_RECORD
|
||||
set_temp("Medical record created.", "success")
|
||||
if("del_c")
|
||||
var/index = text2num(params["del_c"] || "")
|
||||
if(!index || !istype(active2, /datum/data/record))
|
||||
return
|
||||
|
||||
var/list/comments = active2.fields["comments"]
|
||||
index = clamp(index, 1, length(comments))
|
||||
if(comments[index])
|
||||
comments.Cut(index, index + 1)
|
||||
if("search")
|
||||
active1 = null
|
||||
active2 = null
|
||||
var/t1 = lowertext(params["t1"] || "")
|
||||
if(!length(t1))
|
||||
return
|
||||
|
||||
for(var/datum/data/record/R in GLOB.data_core.medical)
|
||||
if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
|
||||
active2 = R
|
||||
break
|
||||
if(!active2)
|
||||
set_temp("Medical record not found. You must enter the person's exact name, ID or DNA.", "danger")
|
||||
return
|
||||
for(var/datum/data/record/E in GLOB.data_core.general)
|
||||
if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"])
|
||||
active1 = E
|
||||
break
|
||||
screen = MED_DATA_RECORD
|
||||
if("print_p")
|
||||
if(!printing)
|
||||
printing = TRUE
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
SStgui.update_uis(src)
|
||||
addtimer(CALLBACK(src, .proc/print_finish), 5 SECONDS)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(href_list["print_p"])
|
||||
if(!printing)
|
||||
printing = 1
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
sleep(50)
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<CENTER><B>Medical Record</B></CENTER><BR>"
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
|
||||
<BR>\nSex: [active1.fields["sex"]]
|
||||
<BR>\nAge: [active1.fields["age"]]
|
||||
<BR>\nFingerprint: [active1.fields["fingerprint"]]
|
||||
<BR>\nPhysical Status: [active1.fields["p_stat"]]
|
||||
<BR>\nMental Status: [active1.fields["m_stat"]]<BR>"}
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/computer/med_data/proc/tgui_act_modal(action, params)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_OPEN)
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/question = field_edit_questions[field]
|
||||
var/choices = field_edit_choices[field]
|
||||
if(length(choices))
|
||||
tgui_modal_choice(src, id, question, arguments = arguments, value = arguments["value"], choices = choices)
|
||||
else
|
||||
tgui_modal_input(src, id, question, arguments = arguments, value = arguments["value"])
|
||||
if("add_c")
|
||||
tgui_modal_input(src, id, "Please enter your message:")
|
||||
else
|
||||
P.info += "<B>General Record Lost!</B><BR>"
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
P.info += {"<BR>\n<CENTER><B>Medical Data</B></CENTER>
|
||||
<BR>\nBlood Type: [active2.fields["blood_type"]]
|
||||
<BR>\nDNA: [active2.fields["b_dna"]]<BR>\n
|
||||
<BR>\nMinor Disabilities: [active2.fields["mi_dis"]]
|
||||
<BR>\nDetails: [active2.fields["mi_dis_d"]]<BR>\n
|
||||
<BR>\nMajor Disabilities: [active2.fields["ma_dis"]]
|
||||
<BR>\nDetails: [active2.fields["ma_dis_d"]]<BR>\n
|
||||
<BR>\nAllergies: [active2.fields["alg"]]
|
||||
<BR>\nDetails: [active2.fields["alg_d"]]<BR>\n
|
||||
<BR>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
|
||||
<BR>\nDetails: [active2.fields["cdi_d"]]<BR>\n
|
||||
<BR>\nImportant Notes:
|
||||
<BR>\n\t[active2.fields["notes"]]<BR>\n
|
||||
<BR>\n
|
||||
<CENTER><B>Comments/Log</B></CENTER><BR>"}
|
||||
for(var/c in active2.fields["comments"])
|
||||
P.info += "[c]<BR>"
|
||||
else
|
||||
P.info += "<B>Medical Record Lost!</B><BR>"
|
||||
P.info += "</TT>"
|
||||
P.name = "paper- 'Medical Record: [active1.fields["name"]]'"
|
||||
printing = 0
|
||||
return 1
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("edit")
|
||||
var/field = arguments["field"]
|
||||
if(!length(field) || !field_edit_questions[field])
|
||||
return
|
||||
var/list/choices = field_edit_choices[field]
|
||||
if(length(choices) && !(answer in choices))
|
||||
return
|
||||
|
||||
/obj/machinery/computer/med_data/proc/setTemp(text, list/buttons = list())
|
||||
temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0)
|
||||
if(field == "age")
|
||||
var/new_age = text2num(answer)
|
||||
if(new_age < AGE_MIN || new_age > AGE_MAX)
|
||||
set_temp("Invalid age. It must be between [AGE_MIN] and [AGE_MAX].", "danger")
|
||||
return
|
||||
answer = new_age
|
||||
|
||||
if(istype(active2) && (field in active2.fields))
|
||||
active2.fields[field] = answer
|
||||
else if(istype(active1) && (field in active1.fields))
|
||||
active1.fields[field] = answer
|
||||
if("add_c")
|
||||
if(!length(answer) || !istype(active2) || !length(authenticated))
|
||||
return
|
||||
active2.fields["comments"] += list(list(
|
||||
header = "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]",
|
||||
text = answer
|
||||
))
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Called when the print timer finishes
|
||||
*/
|
||||
/obj/machinery/computer/med_data/proc/print_finish()
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<center></b>Medical Record</b></center><br>"
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]]
|
||||
<br>\nSex: [active1.fields["sex"]]
|
||||
<br>\nAge: [active1.fields["age"]]
|
||||
<br>\nFingerprint: [active1.fields["fingerprint"]]
|
||||
<br>\nPhysical Status: [active1.fields["p_stat"]]
|
||||
<br>\nMental Status: [active1.fields["m_stat"]]<br>"}
|
||||
else
|
||||
P.info += "</b>General Record Lost!</b><br>"
|
||||
if(istype(active2, /datum/data/record) && GLOB.data_core.medical.Find(active2))
|
||||
P.info += {"<br>\n<center></b>Medical Data</b></center>
|
||||
<br>\nBlood Type: [active2.fields["blood_type"]]
|
||||
<br>\nDNA: [active2.fields["b_dna"]]<br>\n
|
||||
<br>\nMinor Disabilities: [active2.fields["mi_dis"]]
|
||||
<br>\nDetails: [active2.fields["mi_dis_d"]]<br>\n
|
||||
<br>\nMajor Disabilities: [active2.fields["ma_dis"]]
|
||||
<br>\nDetails: [active2.fields["ma_dis_d"]]<br>\n
|
||||
<br>\nAllergies: [active2.fields["alg"]]
|
||||
<br>\nDetails: [active2.fields["alg_d"]]<br>\n
|
||||
<br>\nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section)
|
||||
<br>\nDetails: [active2.fields["cdi_d"]]<br>\n
|
||||
<br>\nImportant Notes:
|
||||
<br>\n\t[active2.fields["notes"]]<br>\n
|
||||
<br>\n
|
||||
<center></b>Comments/Log</b></center><br>"}
|
||||
for(var/c in active2.fields["comments"])
|
||||
P.info += "[c]<br>"
|
||||
else
|
||||
P.info += "</b>Medical Record Lost!</b><br>"
|
||||
P.info += "</tt>"
|
||||
P.name = "paper - 'Medical Record: [active1.fields["name"]]'"
|
||||
printing = FALSE
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/**
|
||||
* Sets a temporary message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * style - The style of the message: (color name), info, success, warning, danger, virus
|
||||
*/
|
||||
/obj/machinery/computer/med_data/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/computer/med_data/emp_act(severity)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
@@ -564,9 +502,10 @@
|
||||
icon_screen = "medlaptop"
|
||||
density = 0
|
||||
|
||||
#undef MED_DATA_MAIN
|
||||
#undef MED_DATA_R_LIST
|
||||
#undef MED_DATA_MAINT
|
||||
#undef MED_DATA_RECORD
|
||||
#undef MED_DATA_V_DATA
|
||||
#undef MED_DATA_MEDBOT
|
||||
#undef FIELD
|
||||
#undef MED_FIELD
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/obj/machinery/computer/sm_monitor
|
||||
name = "supermatter monitoring console"
|
||||
desc = "Used to monitor supermatter shards."
|
||||
icon_keyboard = "power_key"
|
||||
icon_screen = "smmon_0"
|
||||
circuit = /obj/item/circuitboard/sm_monitor
|
||||
light_color = LIGHT_COLOR_YELLOW
|
||||
/// Cache-list of all supermatter shards
|
||||
var/list/supermatters
|
||||
/// Last status of the active supermatter for caching purposes
|
||||
var/last_status
|
||||
/// Reference to the active shard
|
||||
var/obj/machinery/power/supermatter_shard/active
|
||||
|
||||
/obj/machinery/computer/sm_monitor/Destroy()
|
||||
active = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/sm_monitor/attack_ai(mob/user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/sm_monitor/attack_hand(mob/user)
|
||||
add_fingerprint(user)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/sm_monitor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "SupermatterMonitor", name, 600, 325, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/sm_monitor/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
if(istype(active))
|
||||
var/turf/T = get_turf(active)
|
||||
// If we somehow delam during this proc, handle it somewhat
|
||||
if(!T)
|
||||
active = null
|
||||
refresh()
|
||||
return
|
||||
var/datum/gas_mixture/air = T.return_air()
|
||||
if(!air)
|
||||
active = null
|
||||
return
|
||||
|
||||
data["active"] = TRUE
|
||||
data["SM_integrity"] = active.get_integrity()
|
||||
data["SM_power"] = active.power
|
||||
data["SM_ambienttemp"] = air.temperature
|
||||
data["SM_ambientpressure"] = air.return_pressure()
|
||||
//data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01)
|
||||
var/other_moles = air.total_trace_moles()
|
||||
var/TM = air.total_moles()
|
||||
if(TM)
|
||||
data["SM_gas_O2"] = round(100*air.oxygen/TM, 0.01)
|
||||
data["SM_gas_CO2"] = round(100*air.carbon_dioxide/TM, 0.01)
|
||||
data["SM_gas_N2"] = round(100*air.nitrogen/TM, 0.01)
|
||||
data["SM_gas_PL"] = round(100*air.toxins/TM, 0.01)
|
||||
if(other_moles)
|
||||
data["SM_gas_OTHER"] = round(100 * other_moles / TM, 0.01)
|
||||
else
|
||||
data["SM_gas_OTHER"] = 0
|
||||
else
|
||||
data["SM_gas_O2"] = 0
|
||||
data["SM_gas_CO2"] = 0
|
||||
data["SM_gas_N2"] = 0
|
||||
data["SM_gas_PH"] = 0
|
||||
data["SM_gas_OTHER"] = 0
|
||||
else
|
||||
var/list/SMS = list()
|
||||
for(var/I in supermatters)
|
||||
var/obj/machinery/power/supermatter_shard/S = I
|
||||
var/area/A = get_area(S)
|
||||
if(!A)
|
||||
continue
|
||||
|
||||
SMS.Add(list(list(
|
||||
"area_name" = A.name,
|
||||
"integrity" = S.get_integrity(),
|
||||
"uid" = S.UID()
|
||||
)))
|
||||
|
||||
data["active"] = FALSE
|
||||
data["supermatters"] = SMS
|
||||
|
||||
return data
|
||||
|
||||
/**
|
||||
* Supermatter List Refresher
|
||||
*
|
||||
* This proc loops through the list of supermatters in the atmos SS and adds them to this console's cache list
|
||||
*/
|
||||
/obj/machinery/computer/sm_monitor/proc/refresh()
|
||||
supermatters = list()
|
||||
var/turf/T = get_turf(tgui_host()) // Get the TGUI host incase this ever turned into a supermatter monitoring module for AIs to use or something
|
||||
if(!T)
|
||||
return
|
||||
for(var/obj/machinery/power/supermatter_shard/S in SSair.atmos_machinery)
|
||||
// Delaminating, not within coverage, not on a tile.
|
||||
if(!(is_station_level(S.z) || is_mining_level(S.z) || atoms_share_level(S, T) || !istype(S.loc, /turf/simulated/)))
|
||||
continue
|
||||
supermatters.Add(S)
|
||||
|
||||
if(!(active in supermatters))
|
||||
active = null
|
||||
|
||||
/obj/machinery/computer/sm_monitor/process()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return FALSE
|
||||
|
||||
if(active)
|
||||
var/new_status = active.get_status()
|
||||
if(last_status != new_status)
|
||||
last_status = new_status
|
||||
if(last_status == SUPERMATTER_ERROR)
|
||||
last_status = SUPERMATTER_INACTIVE
|
||||
icon_screen = "smmon_[last_status]"
|
||||
update_icon()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/sm_monitor/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
|
||||
switch(action)
|
||||
if("refresh")
|
||||
refresh()
|
||||
|
||||
if("view")
|
||||
var/newuid = params["view"]
|
||||
for(var/obj/machinery/power/supermatter_shard/S in supermatters)
|
||||
if(S.UID() == newuid)
|
||||
active = S
|
||||
break
|
||||
|
||||
if("back")
|
||||
active = null
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O, mob/living/user)
|
||||
if(O.loc == user) //no you can't pull things out of your ass
|
||||
return
|
||||
if(user.incapacitated()) //are you cuffed, dying, lying, stunned or other
|
||||
@@ -140,6 +140,7 @@
|
||||
add_attack_logs(user, L, "put into a cryo cell at [COORD(src)].", ATKLOG_ALL)
|
||||
if(user.pulling == L)
|
||||
user.stop_pulling()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/process()
|
||||
..()
|
||||
@@ -177,14 +178,14 @@
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user)
|
||||
if(user.stat)
|
||||
return
|
||||
go_out()
|
||||
return
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attack_ghost(mob/user)
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attack_hand(mob/user)
|
||||
if(user == occupant)
|
||||
@@ -194,36 +195,18 @@
|
||||
to_chat(usr, "<span class='boldnotice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
|
||||
/**
|
||||
* The ui_interact proc is used to open and update Nano UIs
|
||||
* If ui_interact is not used then the UI will not update correctly
|
||||
* ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 480)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "Cryo", "Cryo Cell", 520, 490)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["isOperating"] = on
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
data["hasOccupant"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -246,7 +229,7 @@
|
||||
else if(air_contents.temperature > TCRYO)
|
||||
data["cellTemperatureStatus"] = "average"
|
||||
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
|
||||
data["beakerLabel"] = null
|
||||
data["beakerVolume"] = 0
|
||||
if(beaker)
|
||||
@@ -259,48 +242,44 @@
|
||||
data["auto_eject_dead"] = (auto_eject_prefs & AUTO_EJECT_DEAD) ? TRUE : FALSE
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
|
||||
if(usr == occupant)
|
||||
return 0 // don't update UIs attached to this object
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params)
|
||||
if(..() || usr == occupant)
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(..())
|
||||
return 0 // don't update UIs attached to this object
|
||||
|
||||
if(href_list["switchOn"])
|
||||
on = TRUE
|
||||
update_icon()
|
||||
|
||||
if(href_list["switchOff"])
|
||||
on = FALSE
|
||||
update_icon()
|
||||
|
||||
if(href_list["auto_eject_healthy_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_healthy_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_dead_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["auto_eject_dead_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(beaker)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("switchOn")
|
||||
on = TRUE
|
||||
update_icon()
|
||||
if("switchOff")
|
||||
on = FALSE
|
||||
update_icon()
|
||||
if("auto_eject_healthy_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_healthy_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_dead_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
if("auto_eject_dead_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
if("ejectBeaker")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(get_step(loc, SOUTH))
|
||||
beaker = null
|
||||
|
||||
if(href_list["ejectOccupant"])
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return 0 // don't update UIs attached to this object
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
if("ejectOccupant")
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
else
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1 // update UIs attached to this object
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G as obj, var/mob/user as mob, params)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G, var/mob/user, params)
|
||||
if(istype(G, /obj/item/reagent_containers/glass))
|
||||
var/obj/item/reagent_containers/B = G
|
||||
if(beaker)
|
||||
@@ -313,6 +292,7 @@
|
||||
beaker = B
|
||||
add_attack_logs(user, null, "Added [B] containing [B.reagents.log_list()] to a cryo cell at [COORD(src)]")
|
||||
user.visible_message("[user] adds \a [B] to [src]!", "You add \a [B] to [src]!")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(exchange_parts(user, G))
|
||||
@@ -357,7 +337,7 @@
|
||||
return
|
||||
|
||||
if(occupant)
|
||||
var/image/pickle = image(occupant.icon, occupant.icon_state)
|
||||
var/mutable_appearance/pickle = mutable_appearance(occupant.icon, occupant.icon_state)
|
||||
pickle.overlays = occupant.overlays
|
||||
pickle.pixel_y = 22
|
||||
|
||||
@@ -455,8 +435,9 @@
|
||||
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
if(AUTO_EJECT_DEAD)
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 40)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M)
|
||||
if(!istype(M))
|
||||
to_chat(usr, "<span class='danger'>The cryo cell cannot handle such a lifeform!</span>")
|
||||
return
|
||||
@@ -530,7 +511,7 @@
|
||||
/datum/data/function/proc/reset()
|
||||
return
|
||||
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user as mob)
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user)
|
||||
return
|
||||
|
||||
/datum/data/function/proc/display()
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
#define AIRLOCK_DAMAGE_DEFLECTION_N 21 // Normal airlock damage deflection
|
||||
#define AIRLOCK_DAMAGE_DEFLECTION_R 30 // Reinforced airlock damage deflection
|
||||
|
||||
#define TGUI_GREEN 2
|
||||
#define TGUI_ORANGE 1
|
||||
#define TGUI_RED 0
|
||||
|
||||
|
||||
GLOBAL_LIST_EMPTY(airlock_overlays)
|
||||
|
||||
/obj/machinery/door/airlock
|
||||
@@ -54,7 +59,7 @@ GLOBAL_LIST_EMPTY(airlock_overlays)
|
||||
normalspeed = 1
|
||||
siemens_strength = 1
|
||||
var/security_level = 0 //How much are wires secured
|
||||
var/aiControlDisabled = FALSE //If TRUE, AI control is disabled until the AI hacks back in and disables the lock. If 2, the AI has bypassed the lock. If -1, the control is enabled but the AI had bypassed it earlier, so if it is disabled again the AI would have no trouble getting back in.
|
||||
var/aiControlDisabled = AICONTROLDISABLED_OFF
|
||||
var/hackProof = FALSE // if TRUE, this door can't be hacked by the AI
|
||||
var/electrified_until = 0 // World time when the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
|
||||
var/main_power_lost_until = 0 //World time when main power is restored.
|
||||
@@ -65,7 +70,7 @@ GLOBAL_LIST_EMPTY(airlock_overlays)
|
||||
var/spawnPowerRestoreRunning = 0
|
||||
var/lights = TRUE // bolt lights show by default
|
||||
var/datum/wires/airlock/wires
|
||||
var/aiDisabledIdScanner = 0
|
||||
var/aiDisabledIdScanner = FALSE
|
||||
var/aiHacking = 0
|
||||
var/obj/machinery/door/airlock/closeOther
|
||||
var/closeOtherId
|
||||
@@ -96,7 +101,7 @@ GLOBAL_LIST_EMPTY(airlock_overlays)
|
||||
var/doorDeni = 'sound/machines/deniedbeep.ogg' // i'm thinkin' Deni's
|
||||
var/boltUp = 'sound/machines/boltsup.ogg'
|
||||
var/boltDown = 'sound/machines/boltsdown.ogg'
|
||||
var/is_special = 0
|
||||
var/is_special = FALSE
|
||||
|
||||
/obj/machinery/door/airlock/welded
|
||||
welded = TRUE
|
||||
@@ -174,7 +179,7 @@ About the new airlock wires panel:
|
||||
spawn (10)
|
||||
justzap = 0
|
||||
return
|
||||
else /*if(justzap)*/
|
||||
else
|
||||
return
|
||||
else if(user.hallucination > 50 && prob(10) && !operating)
|
||||
if(user.electrocute_act(50, src, 1, illusion = TRUE)) // We'll just go with a flat 50 damage, instead of doing powernet checks
|
||||
@@ -190,10 +195,10 @@ About the new airlock wires panel:
|
||||
return 0
|
||||
|
||||
/obj/machinery/door/airlock/proc/canAIControl()
|
||||
return ((aiControlDisabled!=1) && (!isAllPowerLoss()))
|
||||
return ((aiControlDisabled != AICONTROLDISABLED_ON) && (!isAllPowerLoss()))
|
||||
|
||||
/obj/machinery/door/airlock/proc/canAIHack()
|
||||
return ((aiControlDisabled==1) && (!hackProof) && (!isAllPowerLoss()))
|
||||
return ((aiControlDisabled == AICONTROLDISABLED_ON) && (!hackProof) && (!isAllPowerLoss()))
|
||||
|
||||
/obj/machinery/door/airlock/proc/arePowerSystemsOn()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
@@ -561,38 +566,58 @@ About the new airlock wires panel:
|
||||
/obj/machinery/door/airlock/attack_ghost(mob/user)
|
||||
if(panel_open)
|
||||
wires.Interact(user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/door/airlock/attack_ai(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/door/airlock/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375)
|
||||
ui = new(user, src, ui_key, "AiAirlock", name, 600, 400, master_ui, state)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/door/airlock/ui_data(mob/user, datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
|
||||
data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1)
|
||||
data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1)
|
||||
data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1)
|
||||
data["open"] = !density
|
||||
/obj/machinery/door/airlock/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/commands[0]
|
||||
commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner,"enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1)
|
||||
commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised", "disabled" = "Dropped", "danger" = 0, "act" = 0)
|
||||
commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1)
|
||||
commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0)
|
||||
commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0)
|
||||
commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0)
|
||||
commands[++commands.len] = list("name" = "Emergency Access","command"= "emergency", "active" = !emergency, "enabled" = "Disabled", "disabled" = "Enabled", "danger" = 0, "act" = 0)
|
||||
var/list/power = list()
|
||||
power["main"] = main_power_lost_until ? TGUI_RED : TGUI_GREEN
|
||||
power["main_timeleft"] = max(main_power_lost_until - world.time, 0) / 10
|
||||
power["backup"] = backup_power_lost_until ? TGUI_RED : TGUI_GREEN
|
||||
power["backup_timeleft"] = max(backup_power_lost_until - world.time, 0) / 10
|
||||
data["power"] = power
|
||||
if(electrified_until == -1)
|
||||
data["shock"] = TGUI_RED
|
||||
else if(electrified_until > 0)
|
||||
data["shock"] = TGUI_ORANGE
|
||||
else
|
||||
data["shock"] = TGUI_GREEN
|
||||
|
||||
data["commands"] = commands
|
||||
data["shock_timeleft"] = max(electrified_until - world.time, 0) / 10
|
||||
data["id_scanner"] = !aiDisabledIdScanner
|
||||
data["emergency"] = emergency // access
|
||||
data["locked"] = locked // bolted
|
||||
data["lights"] = lights // bolt lights
|
||||
data["safe"] = safe // safeties
|
||||
data["speed"] = normalspeed // safe speed
|
||||
data["welded"] = welded // welded
|
||||
data["opened"] = !density // opened
|
||||
|
||||
var/list/wire = list()
|
||||
wire["main_power"] = !wires.is_cut(WIRE_MAIN_POWER1)
|
||||
wire["backup_power"] = !wires.is_cut(WIRE_BACKUP_POWER1)
|
||||
wire["shock"] = !wires.is_cut(WIRE_ELECTRIFY)
|
||||
wire["id_scanner"] = !wires.is_cut(WIRE_IDSCAN)
|
||||
wire["bolts"] = !wires.is_cut(WIRE_DOOR_BOLTS)
|
||||
wire["lights"] = !wires.is_cut(WIRE_BOLT_LIGHT)
|
||||
wire["safe"] = !wires.is_cut(WIRE_SAFETY)
|
||||
wire["timing"] = !wires.is_cut(WIRE_SPEED)
|
||||
|
||||
data["wires"] = wire
|
||||
return data
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/proc/hack(mob/user)
|
||||
set waitfor = 0
|
||||
if(!aiHacking)
|
||||
@@ -632,7 +657,7 @@ About the new airlock wires panel:
|
||||
to_chat(user, "Transfer complete. Forcing airlock to execute program.")
|
||||
sleep(50)
|
||||
//disable blocked control
|
||||
aiControlDisabled = 2
|
||||
aiControlDisabled = AICONTROLDISABLED_BYPASS
|
||||
to_chat(user, "Receiving control information from airlock.")
|
||||
sleep(10)
|
||||
//bring up airlock dialog
|
||||
@@ -728,125 +753,125 @@ About the new airlock wires panel:
|
||||
else
|
||||
try_to_activate_door(user)
|
||||
|
||||
/obj/machinery/door/airlock/CanUseTopic(mob/user)
|
||||
if(!issilicon(user) && !isobserver(user))
|
||||
return STATUS_CLOSE
|
||||
|
||||
if(emagged)
|
||||
to_chat(user, "<span class='warning'>Unable to interface: Internal error.</span>")
|
||||
return STATUS_CLOSE
|
||||
if(!canAIControl() && !isobserver(user))
|
||||
if(canAIHack(user))
|
||||
hack(user)
|
||||
else
|
||||
if(isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it.
|
||||
to_chat(user, "<span class='warning'>Unable to interface: Connection timed out.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to interface: Connection refused.</span>")
|
||||
return STATUS_CLOSE
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/door/airlock/Topic(href, href_list, nowindow = 0)
|
||||
/obj/machinery/door/airlock/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/activate = text2num(href_list["activate"])
|
||||
switch(href_list["command"])
|
||||
if("idscan")
|
||||
if(wires.is_cut(WIRE_IDSCAN))
|
||||
to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.")
|
||||
else if(activate && aiDisabledIdScanner)
|
||||
aiDisabledIdScanner = 0
|
||||
to_chat(usr, "IdScan feature has been enabled.")
|
||||
else if(!activate && !aiDisabledIdScanner)
|
||||
aiDisabledIdScanner = 1
|
||||
to_chat(usr, "IdScan feature has been disabled.")
|
||||
if("main_power")
|
||||
return
|
||||
if(!issilicon(usr) && !usr.can_admin_interact())
|
||||
to_chat(usr, "<span class='warning'>Access denied. Only silicons may use this interface.</span>")
|
||||
return
|
||||
if(issilicon(usr) && emagged)
|
||||
to_chat(usr, "<span class='warning'>Unable to interface: Internal error.</span>")
|
||||
return
|
||||
if(!canAIControl() && !isobserver(usr))
|
||||
if(canAIHack(usr))
|
||||
hack(usr)
|
||||
else
|
||||
if(isAllPowerLoss())
|
||||
to_chat(usr, "<span class='warning'>Unable to interface: Connection timed out.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Unable to interface: Connection refused.</span>")
|
||||
return
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("disrupt-main")
|
||||
if(!main_power_lost_until)
|
||||
loseMainPower()
|
||||
update_icon()
|
||||
if("backup_power")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Main power is already offline.</span>")
|
||||
. = FALSE
|
||||
if("disrupt-backup")
|
||||
if(!backup_power_lost_until)
|
||||
loseBackupPower()
|
||||
update_icon()
|
||||
if("bolts")
|
||||
if(wires.is_cut(WIRE_DOOR_BOLTS))
|
||||
to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.")
|
||||
else if(activate && lock())
|
||||
to_chat(usr, "The door bolts have been dropped.")
|
||||
else if(!activate && unlock())
|
||||
to_chat(usr, "The door bolts have been raised.")
|
||||
if("electrify_temporary")
|
||||
if(activate && wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(usr, text("The electrification wire is cut - Door permanently electrified."))
|
||||
else if(!activate && electrified_until != 0)
|
||||
to_chat(usr, "The door is now un-electrified.")
|
||||
electrify(0)
|
||||
else if(activate) //electrify door for 30 seconds
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified", ATKLOG_ALL)
|
||||
to_chat(usr, "The door is now electrified for thirty seconds.")
|
||||
electrify(30)
|
||||
if("electrify_permanently")
|
||||
if(wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(usr, text("The electrification wire is cut - Cannot electrify the door."))
|
||||
else if(!activate && electrified_until != 0)
|
||||
to_chat(usr, "The door is now un-electrified.")
|
||||
electrify(0)
|
||||
else if(activate)
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified", ATKLOG_ALL)
|
||||
to_chat(usr, "The door is now electrified.")
|
||||
electrify(-1)
|
||||
if("open")
|
||||
if(welded)
|
||||
to_chat(usr, text("The airlock has been welded shut!"))
|
||||
else if(locked)
|
||||
to_chat(usr, text("The door bolts are down!"))
|
||||
else if(activate && density)
|
||||
open()
|
||||
else if(!activate && !density)
|
||||
close()
|
||||
if("safeties")
|
||||
// Safeties! We don't need no stinking safeties!
|
||||
if(wires.is_cut(WIRE_SAFETY))
|
||||
to_chat(usr, text("The safety wire is cut - Cannot secure the door."))
|
||||
else if(activate && safe)
|
||||
safe = 0
|
||||
else if(!activate && !safe)
|
||||
safe = 1
|
||||
if("timing")
|
||||
// Door speed control
|
||||
if(wires.is_cut(WIRE_SPEED))
|
||||
to_chat(usr, text("The timing wire is cut - Cannot alter timing."))
|
||||
else if(activate && normalspeed)
|
||||
normalspeed = 0
|
||||
else if(!activate && !normalspeed)
|
||||
normalspeed = 1
|
||||
if("lights")
|
||||
// Bolt lights
|
||||
if(wires.is_cut(WIRE_BOLT_LIGHT))
|
||||
to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.")
|
||||
else if(!activate && lights)
|
||||
lights = 0
|
||||
to_chat(usr, "The door bolt lights have been disabled.")
|
||||
else if(activate && !lights)
|
||||
lights = 1
|
||||
to_chat(usr, "The door bolt lights have been enabled.")
|
||||
update_icon()
|
||||
if("emergency")
|
||||
// Emergency access
|
||||
if(emergency)
|
||||
emergency = 0
|
||||
to_chat(usr, "Emergency access has been disabled.")
|
||||
else
|
||||
emergency = 1
|
||||
to_chat(usr, "Emergency access has been enabled.")
|
||||
to_chat(usr, "<span class='warning'>Backup power is already offline.</span>")
|
||||
if("shock-restore")
|
||||
to_chat(usr, "<span class='notice'>The door is now un-electrified.</span>")
|
||||
electrify(0)
|
||||
if("shock-temp")
|
||||
if(wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(usr, "<span class='warning'>The electrification wire is cut - Door permanently electrified.</span>")
|
||||
. = FALSE
|
||||
else
|
||||
//electrify door for 30 seconds
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified", ATKLOG_ALL)
|
||||
to_chat(usr, "<span class='notice'>The door is now electrified for thirty seconds.</span>")
|
||||
electrify(30)
|
||||
if("shock-perm")
|
||||
if(wires.is_cut(WIRE_ELECTRIFY))
|
||||
to_chat(usr, "<span class='warning'>The electrification wire is cut - Cannot electrify the door.</span>")
|
||||
. = FALSE
|
||||
else
|
||||
shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])")
|
||||
usr.create_attack_log("<font color='red'>Electrified the [name] at [x] [y] [z]</font>")
|
||||
add_attack_logs(usr, src, "Electrified", ATKLOG_ALL)
|
||||
to_chat(usr, "<span class='notice'>The door is now electrified.</span>")
|
||||
electrify(-1)
|
||||
if("idscan-toggle")
|
||||
if(wires.is_cut(WIRE_IDSCAN))
|
||||
to_chat(usr, "<span class='warning'>The IdScan wire has been cut - IdScan feature permanently disabled.</span>")
|
||||
. = FALSE
|
||||
else if(aiDisabledIdScanner)
|
||||
aiDisabledIdScanner = FALSE
|
||||
to_chat(usr, "<span class='notice'>IdScan feature has been enabled.</span>")
|
||||
else
|
||||
aiDisabledIdScanner = TRUE
|
||||
to_chat(usr, "<span class='notice'>IdScan feature has been disabled.</span>")
|
||||
if("emergency-toggle")
|
||||
emergency = !emergency
|
||||
if(emergency)
|
||||
to_chat(usr, "<span class='notice'>Emergency access has been enabled.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Emergency access has been disabled.</span>")
|
||||
update_icon()
|
||||
return 1
|
||||
if("bolt-toggle")
|
||||
if(wires.is_cut(WIRE_DOOR_BOLTS))
|
||||
to_chat(usr, "<span class='warning'>The door bolt control wire has been cut - Door bolts permanently dropped.</span>")
|
||||
else if(lock())
|
||||
to_chat(usr, "<span class='notice'>The door bolts have been dropped.</span>")
|
||||
else if(unlock())
|
||||
to_chat(usr, "<span class='notice'>The door bolts have been raised.</span>")
|
||||
if("light-toggle")
|
||||
if(wires.is_cut(WIRE_BOLT_LIGHT))
|
||||
to_chat(usr, "<span class='warning'>The bolt lights wire has been cut - The door bolt lights are permanently disabled.</span>")
|
||||
else if(lights)
|
||||
lights = FALSE
|
||||
to_chat(usr, "<span class='notice'>The door bolt lights have been disabled.</span>")
|
||||
else if(!lights)
|
||||
lights = TRUE
|
||||
to_chat(usr, "<span class='notice'>The door bolt lights have been enabled.</span>")
|
||||
update_icon()
|
||||
if("safe-toggle")
|
||||
if(wires.is_cut(WIRE_SAFETY))
|
||||
to_chat(usr, "<span class='warning'>The safety wire is cut - Cannot secure the door.</span>")
|
||||
else if(safe)
|
||||
safe = 0
|
||||
to_chat(usr, "<span class='notice'>The door safeties have been disabled.</span>")
|
||||
else
|
||||
safe = 1
|
||||
to_chat(usr, "<span class='notice'>The door safeties have been enabled.</span>")
|
||||
if("speed-toggle")
|
||||
if(wires.is_cut(WIRE_SPEED))
|
||||
to_chat(usr, "<span class='warning'>The timing wire is cut - Cannot alter timing.</span>")
|
||||
else if(normalspeed)
|
||||
normalspeed = 0
|
||||
else
|
||||
normalspeed = 1
|
||||
if("open-close")
|
||||
if(welded)
|
||||
to_chat(usr, "<span class='warning'>The airlock has been welded shut!</span>")
|
||||
else if(locked)
|
||||
to_chat(usr, "<span class='warning'>The door bolts are down!</span>")
|
||||
else if(density)
|
||||
open()
|
||||
else
|
||||
close()
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
/obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
@@ -1055,7 +1080,7 @@ About the new airlock wires panel:
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/door/airlock/try_to_crowbar(mob/living/user, obj/item/I) //*scream
|
||||
/obj/machinery/door/airlock/try_to_crowbar(mob/living/user, obj/item/I)
|
||||
if(operating)
|
||||
return
|
||||
if(istype(I, /obj/item/twohanded/fireaxe)) //let's make this more specific //FUCK YOU
|
||||
@@ -1399,10 +1424,10 @@ About the new airlock wires panel:
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/door/airlock/proc/ai_control_callback()
|
||||
if(aiControlDisabled == 1)
|
||||
aiControlDisabled = 0
|
||||
else if(aiControlDisabled == 2)
|
||||
aiControlDisabled = -1
|
||||
if(aiControlDisabled == AICONTROLDISABLED_ON)
|
||||
aiControlDisabled = AICONTROLDISABLED_OFF
|
||||
else if(aiControlDisabled == AICONTROLDISABLED_BYPASS)
|
||||
aiControlDisabled = AICONTROLDISABLED_PERMA
|
||||
|
||||
#undef AIRLOCK_CLOSED
|
||||
#undef AIRLOCK_CLOSING
|
||||
@@ -1423,3 +1448,7 @@ About the new airlock wires panel:
|
||||
#undef AIRLOCK_INTEGRITY_MULTIPLIER
|
||||
#undef AIRLOCK_DAMAGE_DEFLECTION_N
|
||||
#undef AIRLOCK_DAMAGE_DEFLECTION_R
|
||||
|
||||
#undef TGUI_GREEN
|
||||
#undef TGUI_ORANGE
|
||||
#undef TGUI_RED
|
||||
|
||||
@@ -365,14 +365,14 @@
|
||||
assemblytype = /obj/structure/door_assembly/door_assembly_vault
|
||||
security_level = 6
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = TRUE
|
||||
aiControlDisabled = AICONTROLDISABLED_ON
|
||||
|
||||
/obj/machinery/door/airlock/hatch/gamma
|
||||
name = "gamma level hatch"
|
||||
hackProof = 1
|
||||
aiControlDisabled = 1
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = AICONTROLDISABLED_ON
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
is_special = 1
|
||||
is_special = TRUE
|
||||
|
||||
/obj/machinery/door/airlock/hatch/gamma/attackby(obj/C, mob/user, params)
|
||||
if(!issilicon(user))
|
||||
@@ -432,8 +432,8 @@
|
||||
|
||||
/obj/machinery/door/airlock/highsecurity/red
|
||||
name = "secure armory airlock"
|
||||
hackProof = 1
|
||||
aiControlDisabled = 1
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = AICONTROLDISABLED_ON
|
||||
|
||||
/obj/machinery/door/airlock/highsecurity/red/attackby(obj/C, mob/user, params)
|
||||
if(!issilicon(user))
|
||||
@@ -487,7 +487,7 @@
|
||||
damage_deflection = 30
|
||||
explosion_block = 3
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = 1
|
||||
aiControlDisabled = AICONTROLDISABLED_ON
|
||||
normal_integrity = 700
|
||||
security_level = 1
|
||||
paintable = FALSE
|
||||
@@ -504,7 +504,7 @@
|
||||
assemblytype = /obj/structure/door_assembly/door_assembly_cult
|
||||
damage_deflection = 10
|
||||
hackProof = TRUE
|
||||
aiControlDisabled = TRUE
|
||||
aiControlDisabled = AICONTROLDISABLED_ON
|
||||
paintable = FALSE
|
||||
var/openingoverlaytype = /obj/effect/temp_visual/cult/door
|
||||
var/friendly = FALSE
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
// Reasonable defaults, in case someone manually spawns us
|
||||
var/lasercolor = "r" //Something to do with lasertag turrets, blame Sieve for not adding a comment.
|
||||
installation = /obj/item/gun/energy/laser/tag/red
|
||||
targetting_is_configurable = FALSE
|
||||
lethal_is_configurable = FALSE
|
||||
shot_delay = 30
|
||||
iconholder = 1
|
||||
has_cover = FALSE
|
||||
always_up = TRUE
|
||||
raised = TRUE
|
||||
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
|
||||
|
||||
/obj/machinery/porta_turret/tag/red
|
||||
|
||||
@@ -18,43 +26,15 @@
|
||||
icon_state = "[lasercolor]grey_target_prism"
|
||||
|
||||
/obj/machinery/porta_turret/tag/weapon_setup(var/obj/item/gun/energy/E)
|
||||
switch(E.type)
|
||||
if(/obj/item/gun/energy/laser/tag/blue)
|
||||
eprojectile = /obj/item/gun/energy/laser/tag/blue
|
||||
lasercolor = "b"
|
||||
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
|
||||
check_arrest = 0
|
||||
check_records = 0
|
||||
check_weapons = 1
|
||||
check_access = 0
|
||||
check_anomalies = 0
|
||||
shot_delay = 30
|
||||
return
|
||||
|
||||
if(/obj/item/gun/energy/laser/tag/red)
|
||||
eprojectile = /obj/item/gun/energy/laser/tag/red
|
||||
lasercolor = "r"
|
||||
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
|
||||
check_arrest = 0
|
||||
check_records = 0
|
||||
check_weapons = 1
|
||||
check_access = 0
|
||||
check_anomalies = 0
|
||||
shot_delay = 30
|
||||
iconholder = 1
|
||||
|
||||
/obj/machinery/porta_turret/tag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/porta_turret/tag/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["locked"] = locked
|
||||
data["enabled"] = enabled
|
||||
data["is_lethal"] = 0
|
||||
/obj/machinery/porta_turret/tag/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"locked" = isLocked(user), // does the current user have access?
|
||||
"on" = enabled, // is turret turned on?
|
||||
"lethal" = FALSE,
|
||||
"lethal_is_configurable" = lethal_is_configurable
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/porta_turret/tag/update_icon()
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
name = "turret"
|
||||
icon = 'icons/obj/turrets.dmi'
|
||||
icon_state = "turretCover"
|
||||
anchored = 1
|
||||
density = 0
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
use_power = IDLE_POWER_USE //this turret uses and requires power
|
||||
idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power
|
||||
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
|
||||
power_channel = EQUIP //drains power from the EQUIPMENT channel
|
||||
armor = list(melee = 50, bullet = 30, laser = 30, energy = 30, bomb = 30, bio = 0, rad = 0, fire = 90, acid = 90)
|
||||
var/raised = 0 //if the turret cover is "open" and the turret is raised
|
||||
var/raising= 0 //if the turret is currently opening or closing its cover
|
||||
var/raised = FALSE //if the turret cover is "open" and the turret is raised
|
||||
var/raising= FALSE //if the turret is currently opening or closing its cover
|
||||
var/health = 80 //the turret's health
|
||||
var/locked = 1 //if the turret's behaviour control access is locked
|
||||
var/controllock = 0 //if the turret responds to control panels
|
||||
var/locked = TRUE //if the turret's behaviour control access is locked
|
||||
var/controllock = FALSE //if the turret responds to control panels. TRUE = does NOT respond
|
||||
|
||||
var/installation = /obj/item/gun/energy/gun/turret //the type of weapon installed
|
||||
var/gun_charge = 0 //the charge of the gun inserted
|
||||
@@ -31,68 +31,49 @@
|
||||
var/last_fired = 0 //1: if the turret is cooling down from a shot, 0: turret is ready to fire
|
||||
var/shot_delay = 15 //1.5 seconds between each shot
|
||||
|
||||
var/check_arrest = 1 //checks if the perp is set to arrest
|
||||
var/check_records = 1 //checks if a security record exists at all
|
||||
var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
|
||||
var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
|
||||
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
|
||||
var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
|
||||
var/ailock = 0 // AI cannot use this
|
||||
var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
|
||||
var/check_arrest = TRUE //checks if the perp is set to arrest
|
||||
var/check_records = TRUE //checks if a security record exists at all
|
||||
var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
|
||||
var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
|
||||
var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
|
||||
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
|
||||
var/check_borgs = FALSE //if TRUE, target all cyborgs.
|
||||
var/ailock = FALSE // if TRUE, AI cannot use this
|
||||
|
||||
var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
|
||||
var/attacked = FALSE //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
|
||||
|
||||
var/enabled = 1 //determines if the turret is on
|
||||
var/lethal = 0 //whether in lethal or stun mode
|
||||
var/disabled = 0
|
||||
var/enabled = TRUE //determines if the turret is on
|
||||
var/lethal = FALSE //whether in lethal or stun mode
|
||||
var/lethal_is_configurable = TRUE // if false, its lethal setting cannot be changed
|
||||
var/disabled = FALSE
|
||||
|
||||
var/shot_sound //what sound should play when the turret fires
|
||||
var/eshot_sound //what sound should play when the emagged turret fires
|
||||
|
||||
var/datum/effect_system/spark_spread/spark_system //the spark system, used for generating... sparks?
|
||||
|
||||
var/wrenching = 0
|
||||
var/wrenching = FALSE
|
||||
var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range
|
||||
|
||||
var/screen = 0 // Screen 0: main control, screen 1: access levels
|
||||
var/one_access = 0 // Determines if access control is set to req_one_access or req_access
|
||||
var/one_access = FALSE // Determines if access control is set to req_one_access or req_access
|
||||
var/region_min = REGION_GENERAL
|
||||
var/region_max = REGION_COMMAND
|
||||
|
||||
var/syndicate = 0 //is the turret a syndicate turret?
|
||||
var/syndicate = FALSE //is the turret a syndicate turret?
|
||||
var/faction = ""
|
||||
var/emp_vulnerable = 1 // Can be empd
|
||||
var/emp_vulnerable = TRUE // Can be empd
|
||||
var/scan_range = 7
|
||||
var/always_up = 0 //Will stay active
|
||||
var/has_cover = 1 //Hides the cover
|
||||
var/always_up = FALSE //Will stay active
|
||||
var/has_cover = TRUE //Hides the cover
|
||||
|
||||
/obj/machinery/porta_turret/centcom
|
||||
name = "Centcom Turret"
|
||||
enabled = 0
|
||||
ailock = 1
|
||||
check_synth = 0
|
||||
check_access = 1
|
||||
check_arrest = 1
|
||||
check_records = 1
|
||||
check_weapons = 1
|
||||
check_anomalies = 1
|
||||
|
||||
/obj/machinery/porta_turret/centcom/pulse
|
||||
name = "Pulse Turret"
|
||||
health = 200
|
||||
enabled = 1
|
||||
lethal = 1
|
||||
req_access = list(ACCESS_CENT_COMMANDER)
|
||||
installation = /obj/item/gun/energy/pulse/turret
|
||||
|
||||
/obj/machinery/porta_turret/stationary
|
||||
ailock = 1
|
||||
lethal = 1
|
||||
installation = /obj/item/gun/energy/laser
|
||||
|
||||
/obj/machinery/porta_turret/Initialize(mapload)
|
||||
. = ..()
|
||||
if(req_access && req_access.len)
|
||||
req_access.Cut()
|
||||
req_one_access = list(ACCESS_SECURITY, ACCESS_HEADS)
|
||||
one_access = 1
|
||||
one_access = TRUE
|
||||
|
||||
//Sets up a spark system
|
||||
spark_system = new /datum/effect_system/spark_spread
|
||||
@@ -110,7 +91,7 @@
|
||||
if(req_one_access && req_one_access.len)
|
||||
req_one_access.Cut()
|
||||
req_access = list(ACCESS_CENT_SPECOPS)
|
||||
one_access = 0
|
||||
one_access = FALSE
|
||||
|
||||
/obj/machinery/porta_turret/proc/setup()
|
||||
var/obj/item/gun/energy/E = new installation //All energy-based weapons are applicable
|
||||
@@ -185,152 +166,151 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
else
|
||||
icon_state = "turretCover"
|
||||
|
||||
/obj/machinery/porta_turret/proc/isLocked(mob/user)
|
||||
if(ailock && (isrobot(user) || isAI(user)))
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return 1
|
||||
|
||||
if(locked && !(isrobot(user) || isAI(user) || isobserver(user)))
|
||||
to_chat(user, "<span class='notice'>Access denied.</span>")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/machinery/porta_turret/attack_ai(mob/user)
|
||||
if(isLocked(user))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/porta_turret/attack_ghost(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/porta_turret/attack_hand(mob/user)
|
||||
if(isLocked(user))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 320)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/porta_turret/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["screen"] = screen
|
||||
data["locked"] = locked
|
||||
data["enabled"] = enabled
|
||||
data["lethal_control"] = !syndicate ? 1 : 0
|
||||
data["lethal"] = lethal
|
||||
|
||||
if(data["access"] && !syndicate)
|
||||
var/settings[0]
|
||||
settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
|
||||
settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
|
||||
settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
|
||||
settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
|
||||
settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
|
||||
settings[++settings.len] = list("category" = "Check Misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
|
||||
data["settings"] = settings
|
||||
|
||||
if(!syndicate)
|
||||
data["one_access"] = one_access
|
||||
var/accesses[0]
|
||||
var/list/access_list = get_all_accesses()
|
||||
for(var/access in access_list)
|
||||
var/name = get_access_desc(access)
|
||||
var/active
|
||||
if(one_access)
|
||||
active = (access in req_one_access)
|
||||
else
|
||||
active = (access in req_access)
|
||||
accesses[++accesses.len] = list("name" = name, "active" = active, "number" = access)
|
||||
data["accesses"] = accesses
|
||||
return data
|
||||
|
||||
/obj/machinery/porta_turret/proc/HasController()
|
||||
var/area/A = get_area(src)
|
||||
return A && A.turret_controls.len > 0
|
||||
|
||||
/obj/machinery/porta_turret/CanUseTopic(var/mob/user)
|
||||
/obj/machinery/porta_turret/proc/access_is_configurable()
|
||||
return targetting_is_configurable && !HasController()
|
||||
|
||||
/obj/machinery/porta_turret/proc/isLocked(mob/user)
|
||||
if(HasController())
|
||||
to_chat(user, "<span class='notice'>Turrets can only be controlled using the assigned turret controller.</span>")
|
||||
return STATUS_CLOSE
|
||||
return TRUE
|
||||
if(isrobot(user) || isAI(user))
|
||||
if(ailock)
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
if(isobserver(user))
|
||||
if(user.can_admin_interact())
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
if(locked)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
if(isLocked(user))
|
||||
return STATUS_CLOSE
|
||||
/obj/machinery/porta_turret/attack_ai(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
if(!anchored)
|
||||
to_chat(usr, "<span class='notice'>\The [src] has to be secured first!</span>")
|
||||
return STATUS_CLOSE
|
||||
/obj/machinery/porta_turret/attack_ghost(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
return ..()
|
||||
/obj/machinery/porta_turret/attack_hand(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/porta_turret/Topic(href, href_list, var/nowindow = 0)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["command"] && href_list["value"])
|
||||
var/value = text2num(href_list["value"])
|
||||
if(href_list["command"] == "enable")
|
||||
enabled = value
|
||||
else if(syndicate)
|
||||
return 1
|
||||
else if(href_list["command"] == "screen")
|
||||
screen = value
|
||||
else if(href_list["command"] == "lethal")
|
||||
lethal = value
|
||||
else if(href_list["command"] == "check_synth")
|
||||
check_synth = value
|
||||
else if(href_list["command"] == "check_weapons")
|
||||
check_weapons = value
|
||||
else if(href_list["command"] == "check_records")
|
||||
check_records = value
|
||||
else if(href_list["command"] == "check_arrest")
|
||||
check_arrest = value
|
||||
else if(href_list["command"] == "check_access")
|
||||
check_access = value
|
||||
else if(href_list["command"] == "check_anomalies")
|
||||
check_anomalies = value
|
||||
|
||||
if(!syndicate)
|
||||
if(href_list["one_access"])
|
||||
toggle_one_access(href_list["one_access"])
|
||||
|
||||
if(href_list["access"])
|
||||
toggle_access(href_list["access"])
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/porta_turret/proc/toggle_one_access(var/access)
|
||||
one_access = text2num(access)
|
||||
|
||||
if(one_access == 1)
|
||||
req_one_access = req_access.Copy()
|
||||
req_access.Cut()
|
||||
else if(one_access == 0)
|
||||
req_access = req_one_access.Copy()
|
||||
req_one_access.Cut()
|
||||
|
||||
/obj/machinery/porta_turret/proc/toggle_access(var/access)
|
||||
var/required = text2num(access)
|
||||
if(!(required in get_all_accesses()))
|
||||
/obj/machinery/porta_turret/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(HasController())
|
||||
to_chat(user, "<span class='notice'>[src] can only be controlled using the assigned turret controller.</span>")
|
||||
return
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='notice'>[src] has to be secured first!</span>")
|
||||
return
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "PortableTurret", name, 500, access_is_configurable() ? 800 : 400)
|
||||
ui.open()
|
||||
|
||||
if(one_access)
|
||||
if((required in req_one_access))
|
||||
req_one_access -= required
|
||||
else
|
||||
req_one_access += required
|
||||
else
|
||||
if((required in req_access))
|
||||
req_access -= required
|
||||
else
|
||||
req_access += required
|
||||
/obj/machinery/porta_turret/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"locked" = isLocked(user), // does the current user have access?
|
||||
"on" = enabled,
|
||||
"targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up
|
||||
"lethal" = lethal,
|
||||
"lethal_is_configurable" = lethal_is_configurable,
|
||||
"check_weapons" = check_weapons,
|
||||
"neutralize_noaccess" = check_access,
|
||||
"one_access" = one_access,
|
||||
"selectedAccess" = one_access ? req_one_access : req_access,
|
||||
"access_is_configurable" = access_is_configurable(),
|
||||
"neutralize_norecord" = check_records,
|
||||
"neutralize_criminals" = check_arrest,
|
||||
"neutralize_all" = check_synth,
|
||||
"neutralize_unidentified" = check_anomalies,
|
||||
"neutralize_cyborgs" = check_borgs
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/porta_turret/tgui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["regions"] = get_accesslist_static_data(region_min, region_max)
|
||||
return data
|
||||
|
||||
/obj/machinery/porta_turret/tgui_act(action, params)
|
||||
if (..())
|
||||
return
|
||||
if(isLocked(usr))
|
||||
return
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("power")
|
||||
enabled = !enabled
|
||||
if("lethal")
|
||||
if(lethal_is_configurable)
|
||||
lethal = !lethal
|
||||
if(targetting_is_configurable)
|
||||
switch(action)
|
||||
if("authweapon")
|
||||
check_weapons = !check_weapons
|
||||
if("authaccess")
|
||||
check_access = !check_access
|
||||
if("authnorecord")
|
||||
check_records = !check_records
|
||||
if("autharrest")
|
||||
check_arrest = !check_arrest
|
||||
if("authxeno")
|
||||
check_anomalies = !check_anomalies
|
||||
if("authsynth")
|
||||
check_synth = !check_synth
|
||||
if("authborgs")
|
||||
check_borgs = !check_borgs
|
||||
if("set")
|
||||
var/access = text2num(params["access"])
|
||||
if(one_access)
|
||||
if(!(access in req_one_access))
|
||||
req_one_access += access
|
||||
else
|
||||
req_one_access -= access
|
||||
else
|
||||
if(!(access in req_access))
|
||||
req_access += access
|
||||
else
|
||||
req_access -= access
|
||||
if(access_is_configurable())
|
||||
switch(action)
|
||||
if("grant_region")
|
||||
var/region = text2num(params["region"])
|
||||
if(isnull(region))
|
||||
return
|
||||
if(one_access)
|
||||
req_one_access |= get_region_accesses(region)
|
||||
else
|
||||
req_access |= get_region_accesses(region)
|
||||
if("deny_region")
|
||||
var/region = text2num(params["region"])
|
||||
if(isnull(region))
|
||||
return
|
||||
if(one_access)
|
||||
req_one_access -= get_region_accesses(region)
|
||||
else
|
||||
req_access -= get_region_accesses(region)
|
||||
if("clear_all")
|
||||
if(one_access)
|
||||
req_one_access = list()
|
||||
else
|
||||
req_access = list()
|
||||
if("grant_all")
|
||||
if(one_access)
|
||||
req_one_access = get_all_accesses()
|
||||
else
|
||||
req_access = get_all_accesses()
|
||||
if("one_access")
|
||||
if(one_access)
|
||||
req_one_access = list()
|
||||
else
|
||||
req_access = list()
|
||||
one_access = !one_access
|
||||
|
||||
/obj/machinery/porta_turret/power_change()
|
||||
if(powered() || !use_power)
|
||||
@@ -379,23 +359,25 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
"<span class='notice'>You begin [anchored ? "un" : ""]securing the turret.</span>" \
|
||||
)
|
||||
|
||||
wrenching = 1
|
||||
wrenching = TRUE
|
||||
if(do_after(user, 50 * I.toolspeed, target = src))
|
||||
//This code handles moving the turret around. After all, it's a portable turret!
|
||||
if(!anchored)
|
||||
playsound(loc, I.usesound, 100, 1)
|
||||
anchored = 1
|
||||
anchored = TRUE
|
||||
update_icon()
|
||||
to_chat(user, "<span class='notice'>You secure the exterior bolts on the turret.</span>")
|
||||
else if(anchored)
|
||||
playsound(loc, I.usesound, 100, 1)
|
||||
anchored = 0
|
||||
anchored = FALSE
|
||||
to_chat(user, "<span class='notice'>You unsecure the exterior bolts on the turret.</span>")
|
||||
update_icon()
|
||||
wrenching = 0
|
||||
wrenching = FALSE
|
||||
|
||||
else if(istype(I, /obj/item/card/id) || istype(I, /obj/item/pda))
|
||||
if(allowed(user))
|
||||
if(HasController())
|
||||
to_chat(user, "<span class='notice'>Turrets regulated by a nearby turret controller are not unlockable.</span>")
|
||||
else if(allowed(user))
|
||||
locked = !locked
|
||||
to_chat(user, "<span class='notice'>Controls are now [locked ? "locked" : "unlocked"].</span>")
|
||||
updateUsrDialog()
|
||||
@@ -409,9 +391,9 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
playsound(src.loc, 'sound/weapons/smash.ogg', 60, 1)
|
||||
if(I.force * 0.5 > 1) //if the force of impact dealt at least 1 damage, the turret gets pissed off
|
||||
if(!attacked && !emagged)
|
||||
attacked = 1
|
||||
attacked = TRUE
|
||||
spawn(60)
|
||||
attacked = 0
|
||||
attacked = FALSE
|
||||
|
||||
..()
|
||||
|
||||
@@ -445,12 +427,12 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
if(user)
|
||||
to_chat(user, "<span class='warning'>You short out [src]'s threat assessment circuits.</span>")
|
||||
visible_message("[src] hums oddly...")
|
||||
emagged = 1
|
||||
emagged = TRUE
|
||||
iconholder = 1
|
||||
controllock = 1
|
||||
enabled = 0 //turns off the turret temporarily
|
||||
controllock = TRUE
|
||||
enabled = FALSE //turns off the turret temporarily
|
||||
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
|
||||
enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
|
||||
enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
|
||||
|
||||
/obj/machinery/porta_turret/take_damage(force)
|
||||
if(!raised && !raising)
|
||||
@@ -470,9 +452,9 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
|
||||
if(enabled)
|
||||
if(!attacked && !emagged)
|
||||
attacked = 1
|
||||
attacked = TRUE
|
||||
spawn(60)
|
||||
attacked = 0
|
||||
attacked = FALSE
|
||||
|
||||
..()
|
||||
|
||||
@@ -489,12 +471,12 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
check_access = prob(20) // check_access is a pretty big deal, so it's least likely to get turned on
|
||||
check_anomalies = prob(50)
|
||||
if(prob(5))
|
||||
emagged = 1
|
||||
emagged = TRUE
|
||||
|
||||
enabled=0
|
||||
spawn(rand(60,600))
|
||||
spawn(rand(60, 600))
|
||||
if(!enabled)
|
||||
enabled=1
|
||||
enabled = TRUE
|
||||
|
||||
..()
|
||||
|
||||
@@ -585,8 +567,8 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
if(get_turf(L) == get_turf(src))
|
||||
return TURRET_NOT_TARGET
|
||||
|
||||
if(!emagged && !syndicate && (issilicon(L) || isbot(L))) // Don't target silica
|
||||
return TURRET_NOT_TARGET
|
||||
if(!emagged && !syndicate && (issilicon(L) || isbot(L)))
|
||||
return (check_borgs && isrobot(L)) ? TURRET_PRIORITY_TARGET : TURRET_NOT_TARGET
|
||||
|
||||
if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really
|
||||
return TURRET_NOT_TARGET //move onto next potential victim!
|
||||
@@ -643,7 +625,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
return
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
set_raised_raising(raised, 1)
|
||||
set_raised_raising(raised, TRUE)
|
||||
playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1)
|
||||
update_icon()
|
||||
|
||||
@@ -653,7 +635,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
sleep(10)
|
||||
qdel(flick_holder)
|
||||
|
||||
set_raised_raising(1, 0)
|
||||
set_raised_raising(TRUE, FALSE)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/porta_turret/proc/popDown() //pops the turret down
|
||||
@@ -664,7 +646,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
return
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
set_raised_raising(raised, 1)
|
||||
set_raised_raising(raised, TRUE)
|
||||
playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1)
|
||||
update_icon()
|
||||
|
||||
@@ -674,7 +656,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
sleep(10)
|
||||
qdel(flick_holder)
|
||||
|
||||
set_raised_raising(0, 0)
|
||||
set_raised_raising(FALSE, FALSE)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/porta_turret/on_assess_perp(mob/living/carbon/human/perp)
|
||||
@@ -739,6 +721,27 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
A.throw_at(target, scan_range, 1)
|
||||
return A
|
||||
|
||||
/obj/machinery/porta_turret/centcom
|
||||
name = "Centcom Turret"
|
||||
enabled = FALSE
|
||||
ailock = TRUE
|
||||
check_synth = FALSE
|
||||
check_access = TRUE
|
||||
check_arrest = TRUE
|
||||
check_records = TRUE
|
||||
check_weapons = TRUE
|
||||
check_anomalies = TRUE
|
||||
region_max = REGION_CENTCOMM // Non-turretcontrolled turrets at CC can have their access customized to check for CC accesses.
|
||||
|
||||
/obj/machinery/porta_turret/centcom/pulse
|
||||
name = "Pulse Turret"
|
||||
health = 200
|
||||
enabled = TRUE
|
||||
lethal = TRUE
|
||||
lethal_is_configurable = FALSE
|
||||
req_access = list(ACCESS_CENT_COMMANDER)
|
||||
installation = /obj/item/gun/energy/pulse/turret
|
||||
|
||||
/datum/turret_checks
|
||||
var/enabled
|
||||
var/lethal
|
||||
@@ -748,6 +751,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
var/check_arrest
|
||||
var/check_weapons
|
||||
var/check_anomalies
|
||||
var/check_borgs
|
||||
var/ailock
|
||||
|
||||
/obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC)
|
||||
@@ -763,6 +767,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
check_arrest = TC.check_arrest
|
||||
check_weapons = TC.check_weapons
|
||||
check_anomalies = TC.check_anomalies
|
||||
check_borgs = TC.check_borgs
|
||||
ailock = TC.ailock
|
||||
|
||||
power_change()
|
||||
@@ -791,7 +796,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
if(istype(I, /obj/item/wrench) && !anchored)
|
||||
playsound(loc, I.usesound, 100, 1)
|
||||
to_chat(user, "<span class='notice'>You secure the external bolts.</span>")
|
||||
anchored = 1
|
||||
anchored = TRUE
|
||||
build_step = 1
|
||||
return
|
||||
|
||||
@@ -816,7 +821,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
else if(istype(I, /obj/item/wrench))
|
||||
playsound(loc, I.usesound, 75, 1)
|
||||
to_chat(user, "<span class='notice'>You unfasten the external bolts.</span>")
|
||||
anchored = 0
|
||||
anchored = FALSE
|
||||
build_step = 0
|
||||
return
|
||||
|
||||
@@ -841,8 +846,10 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
gun_charge = E.cell.charge //the gun's charge is stored in gun_charge
|
||||
to_chat(user, "<span class='notice'>You add [I] to the turret.</span>")
|
||||
|
||||
if(istype(installation, /obj/item/gun/energy/laser/tag/blue) || istype(installation, /obj/item/gun/energy/laser/tag/red))
|
||||
target_type = /obj/machinery/porta_turret/tag
|
||||
if(istype(E, /obj/item/gun/energy/laser/tag/blue))
|
||||
target_type = /obj/machinery/porta_turret/tag/blue
|
||||
else if(istype(E, /obj/item/gun/energy/laser/tag/red))
|
||||
target_type = /obj/machinery/porta_turret/tag/red
|
||||
else
|
||||
target_type = /obj/machinery/porta_turret
|
||||
|
||||
@@ -934,7 +941,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
Turret.name = finish_name
|
||||
Turret.installation = installation
|
||||
Turret.gun_charge = gun_charge
|
||||
Turret.enabled = 0
|
||||
Turret.enabled = FALSE
|
||||
Turret.setup()
|
||||
|
||||
qdel(src)
|
||||
@@ -981,25 +988,27 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
var/icon_state_active = "syndieturret1"
|
||||
var/icon_state_destroyed = "syndieturret2"
|
||||
|
||||
syndicate = 1
|
||||
syndicate = TRUE
|
||||
installation = null
|
||||
always_up = 1
|
||||
always_up = TRUE
|
||||
use_power = NO_POWER_USE
|
||||
has_cover = 0
|
||||
raised = 1
|
||||
has_cover = FALSE
|
||||
raised = TRUE
|
||||
scan_range = 9
|
||||
|
||||
faction = "syndicate"
|
||||
emp_vulnerable = 0
|
||||
emp_vulnerable = FALSE
|
||||
|
||||
lethal = 1
|
||||
check_arrest = 0
|
||||
check_records = 0
|
||||
check_weapons = 0
|
||||
check_access = 0
|
||||
check_anomalies = 1
|
||||
check_synth = 1
|
||||
ailock = 1
|
||||
lethal = TRUE
|
||||
lethal_is_configurable = FALSE
|
||||
targetting_is_configurable = FALSE
|
||||
check_arrest = FALSE
|
||||
check_records = FALSE
|
||||
check_weapons = FALSE
|
||||
check_access = FALSE
|
||||
check_anomalies = TRUE
|
||||
check_synth = TRUE
|
||||
ailock = TRUE
|
||||
var/area/syndicate_depot/core/depotarea
|
||||
|
||||
/obj/machinery/porta_turret/syndicate/die()
|
||||
@@ -1018,7 +1027,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
if(req_one_access && req_one_access.len)
|
||||
req_one_access.Cut()
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
one_access = 0
|
||||
one_access = FALSE
|
||||
|
||||
/obj/machinery/porta_turret/syndicate/update_icon()
|
||||
if(stat & BROKEN)
|
||||
|
||||
@@ -12,29 +12,26 @@
|
||||
var/resultlvl = null
|
||||
|
||||
/obj/machinery/slot_machine/attack_hand(mob/user as mob)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/slot_machine/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "SlotMachine", name, 350, 200, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/slot_machine/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
// Get account
|
||||
account = user.get_worn_id_account()
|
||||
if(!account)
|
||||
if(istype(user.get_active_hand(), /obj/item/card/id))
|
||||
account = get_card_account(user.get_active_hand())
|
||||
else
|
||||
account = null
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/slot_machine/wrench_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
default_unfasten_wrench(user, I)
|
||||
|
||||
/obj/machinery/slot_machine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "slotmachine.tmpl", name, 350, 200)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/slot_machine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
// Send data
|
||||
data["working"] = working
|
||||
data["money"] = account ? account.money : null
|
||||
data["plays"] = plays
|
||||
@@ -42,22 +39,23 @@
|
||||
data["resultlvl"] = resultlvl
|
||||
return data
|
||||
|
||||
/obj/machinery/slot_machine/Topic(href, href_list)
|
||||
/obj/machinery/slot_machine/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["ops"])
|
||||
if(text2num(href_list["ops"])) // Play
|
||||
if(working)
|
||||
return
|
||||
if(!account || account.money < 10)
|
||||
return
|
||||
if(!account.charge(10, null, "Bet", "Slot Machine", "Slot Machine"))
|
||||
return
|
||||
plays++
|
||||
working = 1
|
||||
icon_state = "slots-on"
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
addtimer(CALLBACK(src, .proc/spin_slots, usr.name), 25)
|
||||
if(action == "spin")
|
||||
if(working)
|
||||
return
|
||||
if(!account || account.money < 10)
|
||||
return
|
||||
if(!account.charge(10, null, "Bet", "Slot Machine", "Slot Machine"))
|
||||
return
|
||||
plays++
|
||||
working = TRUE
|
||||
icon_state = "slots-on"
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
addtimer(CALLBACK(src, .proc/spin_slots, usr.name), 25)
|
||||
|
||||
/obj/machinery/slot_machine/proc/spin_slots(userName)
|
||||
switch(rand(1,4050))
|
||||
@@ -65,44 +63,45 @@
|
||||
atom_say("JACKPOT! [userName] has won a MILLION CREDITS!")
|
||||
GLOB.event_announcement.Announce("Congratulations to [userName] on winning the Jackpot of ONE MILLION CREDITS!", "Jackpot Winner")
|
||||
result = "JACKPOT! You win one million credits!"
|
||||
resultlvl = "highlight"
|
||||
resultlvl = "teal"
|
||||
win_money(1000000, 'sound/goonstation/misc/airraid_loop.ogg')
|
||||
if(2 to 5) // .07%
|
||||
atom_say("Big Winner! [userName] has won a hundred thousand credits!")
|
||||
GLOB.event_announcement.Announce("Congratulations to [userName] on winning a hundred thousand credits!", "Big Winner")
|
||||
result = "Big Winner! You win a hundred thousand credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(100000, 'sound/goonstation/misc/klaxon.ogg')
|
||||
if(6 to 50) // 1.08%
|
||||
atom_say("Big Winner! [userName] has won ten thousand credits!")
|
||||
result = "You win ten thousand credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(10000, 'sound/goonstation/misc/klaxon.ogg')
|
||||
if(51 to 100) // 1.21%
|
||||
atom_say("Winner! [userName] has won a thousand credits!")
|
||||
result = "You win a thousand credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(1000, 'sound/goonstation/misc/bell.ogg')
|
||||
if(101 to 200) // 2.44%
|
||||
atom_say("Winner! [userName] has won a hundred credits!")
|
||||
result = "You win a hundred credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(100, 'sound/goonstation/misc/bell.ogg')
|
||||
if(201 to 300) // 2.44%
|
||||
atom_say("Winner! [userName] has won fifty credits!")
|
||||
result = "You win fifty credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(50)
|
||||
if(301 to 1000) // 17.26%
|
||||
atom_say("Winner! [userName] has won ten credits!")
|
||||
result = "You win ten credits!"
|
||||
resultlvl = "good"
|
||||
resultlvl = "green"
|
||||
win_money(10)
|
||||
else // 75.31%
|
||||
result = "<span class='warning'>No luck!</span>"
|
||||
resultlvl = "average"
|
||||
working = 0
|
||||
result = "No luck!"
|
||||
resultlvl = "orange"
|
||||
working = FALSE
|
||||
icon_state = "slots-off"
|
||||
SStgui.update_uis(src) // Push a UI update
|
||||
|
||||
/obj/machinery/slot_machine/proc/win_money(amt, sound='sound/machines/ping.ogg')
|
||||
if(sound)
|
||||
@@ -110,3 +109,9 @@
|
||||
if(!account)
|
||||
return
|
||||
account.credit(amt, "Slot Winnings", "Slot Machine", account.owner_name)
|
||||
|
||||
/obj/machinery/slot_machine/wrench_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
default_unfasten_wrench(user, I)
|
||||
|
||||
@@ -11,51 +11,56 @@
|
||||
desc = "Used to control a room's automated defenses."
|
||||
icon = 'icons/obj/machines/turret_control.dmi'
|
||||
icon_state = "control_standby"
|
||||
anchored = 1
|
||||
density = 0
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/enabled = 0
|
||||
var/lethal = 0
|
||||
var/locked = 1
|
||||
var/enabled = FALSE
|
||||
var/lethal = FALSE
|
||||
var/lethal_is_configurable = TRUE
|
||||
var/locked = TRUE
|
||||
var/area/control_area //can be area name, path or nothing.
|
||||
|
||||
var/check_arrest = 1 //checks if the perp is set to arrest
|
||||
var/check_records = 1 //checks if a security record exists at all
|
||||
var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
|
||||
var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
|
||||
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
|
||||
var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
|
||||
var/ailock = 0 //Silicons cannot use this
|
||||
var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
|
||||
var/check_arrest = TRUE //checks if the perp is set to arrest
|
||||
var/check_records = TRUE //checks if a security record exists at all
|
||||
var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
|
||||
var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
|
||||
var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
|
||||
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
|
||||
var/check_borgs = FALSE //if TRUE, target all cyborgs.
|
||||
var/ailock = FALSE //Silicons cannot use this
|
||||
|
||||
var/syndicate = 0
|
||||
var/syndicate = FALSE
|
||||
var/faction = "" // Turret controls can only access turrets that are in the same faction
|
||||
|
||||
req_access = list(ACCESS_AI_UPLOAD)
|
||||
|
||||
/obj/machinery/turretid/stun
|
||||
enabled = 1
|
||||
enabled = TRUE
|
||||
icon_state = "control_stun"
|
||||
|
||||
/obj/machinery/turretid/lethal
|
||||
enabled = 1
|
||||
lethal = 1
|
||||
enabled = TRUE
|
||||
lethal = TRUE
|
||||
icon_state = "control_kill"
|
||||
|
||||
/obj/machinery/turretid/syndicate
|
||||
enabled = 1
|
||||
lethal = 1
|
||||
enabled = TRUE
|
||||
lethal = TRUE
|
||||
lethal_is_configurable = FALSE
|
||||
targetting_is_configurable = FALSE
|
||||
icon_state = "control_kill"
|
||||
|
||||
lethal = 1
|
||||
check_arrest = 0
|
||||
check_records = 0
|
||||
check_weapons = 0
|
||||
check_access = 0
|
||||
check_anomalies = 1
|
||||
check_synth = 1
|
||||
ailock = 1
|
||||
check_arrest = FALSE
|
||||
check_records = FALSE
|
||||
check_weapons = FALSE
|
||||
check_access = FALSE
|
||||
check_anomalies = TRUE
|
||||
check_synth = TRUE
|
||||
check_borgs = FALSE
|
||||
ailock = TRUE
|
||||
|
||||
syndicate = 1
|
||||
syndicate = TRUE
|
||||
faction = "syndicate"
|
||||
req_access = list(ACCESS_SYNDICATE_LEADER)
|
||||
|
||||
@@ -87,21 +92,23 @@
|
||||
return
|
||||
|
||||
/obj/machinery/turretid/proc/isLocked(mob/user)
|
||||
if(ailock && (isrobot(user) || isAI(user)))
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return 1
|
||||
if(isrobot(user) || isAI(user))
|
||||
if(ailock)
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(locked && !(isrobot(user) || isAI(user) || isobserver(user)))
|
||||
to_chat(user, "<span class='notice'>Access denied.</span>")
|
||||
return 1
|
||||
if(isobserver(user))
|
||||
if(user.can_admin_interact())
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
return 0
|
||||
if(locked)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/turretid/CanUseTopic(mob/user)
|
||||
if(isLocked(user))
|
||||
return STATUS_CLOSE
|
||||
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/turretid/attackby(obj/item/W, mob/user)
|
||||
if(stat & BROKEN)
|
||||
@@ -120,89 +127,82 @@
|
||||
/obj/machinery/turretid/emag_act(user as mob)
|
||||
if(!emagged)
|
||||
to_chat(user, "<span class='danger'>You short out the turret controls' access analysis module.</span>")
|
||||
emagged = 1
|
||||
locked = 0
|
||||
ailock = 0
|
||||
emagged = TRUE
|
||||
locked = FALSE
|
||||
ailock = FALSE
|
||||
return
|
||||
|
||||
/obj/machinery/turretid/attack_ai(mob/user as mob)
|
||||
if(isLocked(user))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/turretid/attack_ghost(mob/user as mob)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/turretid/attack_hand(mob/user as mob)
|
||||
if(isLocked(user))
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/turretid/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/turretid/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 350)
|
||||
ui = new(user, src, ui_key, "PortableTurret", name, 500, 400)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/turretid/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
data["access"] = !isLocked(user)
|
||||
data["locked"] = locked
|
||||
data["enabled"] = enabled
|
||||
data["lethal_control"] = !syndicate ? 1 : 0
|
||||
data["lethal"] = lethal
|
||||
|
||||
if(data["access"] && !syndicate)
|
||||
var/settings[0]
|
||||
settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
|
||||
settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
|
||||
settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
|
||||
settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
|
||||
settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
|
||||
settings[++settings.len] = list("category" = "Check Misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
|
||||
data["settings"] = settings
|
||||
|
||||
/obj/machinery/turretid/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"locked" = isLocked(user), // does the current user have access?
|
||||
"on" = enabled,
|
||||
"targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up
|
||||
"lethal" = lethal,
|
||||
"lethal_is_configurable" = lethal_is_configurable,
|
||||
"check_weapons" = check_weapons,
|
||||
"neutralize_noaccess" = check_access,
|
||||
"one_access" = FALSE,
|
||||
"selectedAccess" = list(),
|
||||
"access_is_configurable" = FALSE,
|
||||
"neutralize_norecord" = check_records,
|
||||
"neutralize_criminals" = check_arrest,
|
||||
"neutralize_all" = check_synth,
|
||||
"neutralize_unidentified" = check_anomalies,
|
||||
"neutralize_cyborgs" = check_borgs
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/turretid/Topic(href, href_list, var/nowindow = 0)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
/obj/machinery/turretid/tgui_act(action, params)
|
||||
if (..())
|
||||
return
|
||||
if(isLocked(usr))
|
||||
return 1
|
||||
|
||||
if(href_list["command"] && href_list["value"])
|
||||
var/value = text2num(href_list["value"])
|
||||
if(href_list["command"] == "enable")
|
||||
enabled = value
|
||||
else if(syndicate)
|
||||
return 1
|
||||
else if(href_list["command"] == "lethal")
|
||||
lethal = value
|
||||
else if(href_list["command"] == "check_synth")
|
||||
check_synth = value
|
||||
else if(href_list["command"] == "check_weapons")
|
||||
check_weapons = value
|
||||
else if(href_list["command"] == "check_records")
|
||||
check_records = value
|
||||
else if(href_list["command"] == "check_arrest")
|
||||
check_arrest = value
|
||||
else if(href_list["command"] == "check_access")
|
||||
check_access = value
|
||||
else if(href_list["command"] == "check_anomalies")
|
||||
check_anomalies = value
|
||||
|
||||
updateTurrets()
|
||||
return 1
|
||||
return
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("power")
|
||||
enabled = !enabled
|
||||
if("lethal")
|
||||
if(lethal_is_configurable)
|
||||
lethal = !lethal
|
||||
if(targetting_is_configurable)
|
||||
switch(action)
|
||||
if("authweapon")
|
||||
check_weapons = !check_weapons
|
||||
if("authaccess")
|
||||
check_access = !check_access
|
||||
if("authnorecord")
|
||||
check_records = !check_records
|
||||
if("autharrest")
|
||||
check_arrest = !check_arrest
|
||||
if("authxeno")
|
||||
check_anomalies = !check_anomalies
|
||||
if("authsynth")
|
||||
check_synth = !check_synth
|
||||
if("authborgs")
|
||||
check_borgs = !check_borgs
|
||||
updateTurrets()
|
||||
|
||||
/obj/machinery/turretid/proc/updateTurrets()
|
||||
var/datum/turret_checks/TC = new
|
||||
TC.enabled = enabled
|
||||
TC.lethal = lethal
|
||||
TC.check_synth = check_synth
|
||||
TC.check_borgs = check_borgs
|
||||
TC.check_access = check_access
|
||||
TC.check_records = check_records
|
||||
TC.check_arrest = check_arrest
|
||||
|
||||
@@ -1372,7 +1372,6 @@
|
||||
/obj/item/clothing/glasses/gglasses = 1,
|
||||
/obj/item/clothing/shoes/jackboots = 1,
|
||||
/obj/item/clothing/under/schoolgirl = 1,
|
||||
/obj/item/clothing/head/kitty = 1,
|
||||
/obj/item/clothing/under/blackskirt = 1,
|
||||
/obj/item/clothing/suit/toggle/owlwings = 1,
|
||||
/obj/item/clothing/under/owl = 1,
|
||||
|
||||
@@ -372,6 +372,15 @@
|
||||
new /obj/item/ammo_box/magazine/m12g/buckshot(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/dragon(src)
|
||||
|
||||
/obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags
|
||||
desc = "A large duffelbag, containing three types of extended drum magazines."
|
||||
|
||||
/obj/item/storage/backpack/duffel/syndie/ammo/shotgunXLmags/New()
|
||||
..()
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg/buckshot(src)
|
||||
new /obj/item/ammo_box/magazine/m12g/XtrLrg/dragon(src)
|
||||
|
||||
/obj/item/storage/backpack/duffel/mining_conscript/
|
||||
name = "mining conscription kit"
|
||||
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
|
||||
|
||||
/datum/song
|
||||
var/name = "Untitled"
|
||||
var/list/lines = new()
|
||||
var/tempo = 5 // delay between notes
|
||||
|
||||
var/playing = 0 // if we're playing
|
||||
var/help = 0 // if help is open
|
||||
var/repeat = 0 // number of times remaining to repeat
|
||||
var/max_repeat = 10 // maximum times we can repeat
|
||||
|
||||
var/instrumentDir = "piano" // the folder with the sounds
|
||||
var/instrumentExt = "ogg" // the file extension
|
||||
var/obj/instrumentObj = null // the associated obj playing the sound
|
||||
|
||||
/datum/song/New(dir, obj, ext = "ogg")
|
||||
tempo = sanitize_tempo(tempo)
|
||||
instrumentDir = dir
|
||||
instrumentObj = obj
|
||||
instrumentExt = ext
|
||||
|
||||
/datum/song/Destroy()
|
||||
instrumentObj = null
|
||||
return ..()
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote(note, acc as text, oct)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
|
||||
soundfile = file(soundfile)
|
||||
// make sure the note exists
|
||||
if(!fexists(soundfile))
|
||||
return
|
||||
// and play
|
||||
var/turf/source = get_turf(instrumentObj)
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/A in hearers(15, source))
|
||||
var/mob/M = A
|
||||
if(!M.client || !(M.client.prefs.sound & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
|
||||
|
||||
/datum/song/proc/shouldStopPlaying(mob/user)
|
||||
if(instrumentObj)
|
||||
//if(!user.canUseTopic(instrumentObj))
|
||||
//return 1
|
||||
return !instrumentObj.anchored // add special cases to stop in subclasses
|
||||
else
|
||||
return 1
|
||||
|
||||
/datum/song/proc/playsong(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
if(!playing || shouldStopPlaying(user)) //If the instrument is playing, or special case
|
||||
playing = 0
|
||||
return
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
var/cur_note = text2ascii(note) - 96
|
||||
if(cur_note < 1 || cur_note > 7)
|
||||
continue
|
||||
for(var/i=2 to length(note))
|
||||
var/ni = copytext(note,i,i+1)
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(tempo)
|
||||
repeat--
|
||||
playing = 0
|
||||
repeat = 0
|
||||
|
||||
/datum/song/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!instrumentObj)
|
||||
return
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, instrumentObj, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, instrumentObj, ui_key, "song.tmpl", instrumentObj.name, 700, 500)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/song/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
|
||||
data["lines"] = lines
|
||||
data["tempo"] = tempo
|
||||
|
||||
data["playing"] = playing
|
||||
data["help"] = help
|
||||
data["repeat"] = repeat
|
||||
data["maxRepeat"] = max_repeat
|
||||
data["minTempo"] = world.tick_lag
|
||||
data["maxTempo"] = 600
|
||||
|
||||
return data
|
||||
|
||||
/datum/song/Topic(href, href_list)
|
||||
if(!in_range(instrumentObj, usr) || (issilicon(usr) && instrumentObj.loc != usr) || !isliving(usr) || usr.incapacitated())
|
||||
usr << browse(null, "window=instrument")
|
||||
usr.unset_machine()
|
||||
return 1
|
||||
|
||||
instrumentObj.add_fingerprint(usr)
|
||||
|
||||
if(href_list["newsong"])
|
||||
playing = 0
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["import"])
|
||||
playing = 0
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(instrumentObj, usr))
|
||||
return
|
||||
|
||||
if(length(t) >= 12000)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(length(t) > 12000)
|
||||
|
||||
//split into lines
|
||||
spawn()
|
||||
lines = splittext(t, "\n")
|
||||
if(lines.len == 0)
|
||||
return 1
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
|
||||
lines.Cut(1,2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(lines.len > 200)
|
||||
to_chat(usr, "Too many lines!")
|
||||
lines.Cut(201)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(length(l) > 200)
|
||||
to_chat(usr, "Line [linenum] too long!")
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["help"])
|
||||
help = !help
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat += round(text2num(href_list["repeat"]))
|
||||
if(repeat < 0)
|
||||
repeat = 0
|
||||
if(repeat > max_repeat)
|
||||
repeat = max_repeat
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["tempo"])
|
||||
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]) * world.tick_lag)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["play"])
|
||||
if(playing)
|
||||
return
|
||||
playing = 1
|
||||
spawn()
|
||||
playsong(usr)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["insertline"])
|
||||
var/num = round(text2num(href_list["insertline"]))
|
||||
if(num < 1 || num > lines.len + 1)
|
||||
return
|
||||
|
||||
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
|
||||
if(!newline || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lines.len > 200)
|
||||
return
|
||||
if(length(newline) > 200)
|
||||
newline = copytext(newline, 1, 200)
|
||||
|
||||
lines.Insert(num, newline)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines.Cut(num, num + 1)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]))
|
||||
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
|
||||
if(!content || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(length(content) > 200)
|
||||
content = copytext(content, 1, 200)
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = 0
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return max(round(new_tempo, world.tick_lag), world.tick_lag)
|
||||
|
||||
// subclass for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/shouldStopPlaying()
|
||||
if(instrumentObj)
|
||||
return !isliving(instrumentObj.loc)
|
||||
else
|
||||
return 1
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/obj/structure/piano
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/datum/song/song
|
||||
|
||||
|
||||
/obj/structure/piano/New()
|
||||
..()
|
||||
song = new("piano", src)
|
||||
|
||||
if(prob(50))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
|
||||
/obj/structure/piano/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/structure/piano/Initialize()
|
||||
if(song)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
..()
|
||||
|
||||
/obj/structure/piano/attack_hand(mob/user as mob)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/structure/piano/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!isliving(user) || user.incapacitated() || !anchored)
|
||||
return
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/structure/piano/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/structure/piano/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
/obj/structure/piano/wrench_act(mob/user, obj/item/I)
|
||||
. = TRUE
|
||||
if(!I.tool_use_check(user, 0))
|
||||
return
|
||||
if(!anchored && !isinspace())
|
||||
WRENCH_ANCHOR_MESSAGE
|
||||
if(!I.use_tool(src, user, 20, volume = I.tool_volume))
|
||||
return
|
||||
user.visible_message( \
|
||||
"[user] tightens [src]'s casters.", \
|
||||
"<span class='notice'> You have tightened [src]'s casters. Now it can be played again.</span>", \
|
||||
"You hear ratchet.")
|
||||
anchored = TRUE
|
||||
else if(anchored)
|
||||
to_chat(user, "<span class='notice'> You begin to loosen [src]'s casters...</span>")
|
||||
if(!I.use_tool(src, user, 40, volume = I.tool_volume))
|
||||
return
|
||||
user.visible_message( \
|
||||
"[user] loosens [src]'s casters.", \
|
||||
"<span class='notice'> You have loosened [src]. Now it can be pulled somewhere else.</span>", \
|
||||
"You hear ratchet.")
|
||||
anchored = FALSE
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] needs to be bolted to the floor!</span>")
|
||||
@@ -4,12 +4,13 @@
|
||||
return
|
||||
|
||||
var/turf/turf_source = get_turf(source)
|
||||
|
||||
if(!turf_source)
|
||||
return
|
||||
if(!SSsounds.channel_list) // Not ready yet
|
||||
return
|
||||
|
||||
//allocate a channel if necessary now so its the same for everyone
|
||||
channel = channel || open_sound_channel()
|
||||
channel = channel || SSsounds.random_available_channel()
|
||||
|
||||
// Looping through the player list has the added bonus of working for mobs inside containers
|
||||
var/sound/S = sound(get_sfx(soundin))
|
||||
@@ -33,7 +34,7 @@
|
||||
if(distance <= maxdistance)
|
||||
M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S)
|
||||
|
||||
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S)
|
||||
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, channel = 0, pressure_affected = TRUE, sound/S, distance_multiplier = 1)
|
||||
if(!client || !can_hear())
|
||||
return
|
||||
|
||||
@@ -41,7 +42,7 @@
|
||||
S = sound(get_sfx(soundin))
|
||||
|
||||
S.wait = 0 //No queue
|
||||
S.channel = channel || open_sound_channel()
|
||||
S.channel = channel || SSsounds.random_available_channel()
|
||||
S.volume = vol
|
||||
|
||||
if(vary)
|
||||
@@ -55,6 +56,7 @@
|
||||
|
||||
//sound volume falloff with distance
|
||||
var/distance = get_dist(T, turf_source)
|
||||
distance *= distance_multiplier
|
||||
|
||||
S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff.
|
||||
|
||||
@@ -81,9 +83,9 @@
|
||||
return //No sound
|
||||
|
||||
var/dx = turf_source.x - T.x // Hearing from the right/left
|
||||
S.x = dx
|
||||
S.x = dx * distance_multiplier
|
||||
var/dz = turf_source.y - T.y // Hearing from infront/behind
|
||||
S.z = dz
|
||||
S.z = dz * distance_multiplier
|
||||
// The y value is for above your head, but there is no ceiling in 2d spessmens.
|
||||
S.y = 1
|
||||
S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)
|
||||
@@ -98,15 +100,14 @@
|
||||
var/mob/M = m
|
||||
M.playsound_local(M, null, volume, vary, frequency, falloff, channel, pressure_affected, S)
|
||||
|
||||
/proc/open_sound_channel()
|
||||
var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used
|
||||
. = ++next_channel
|
||||
if(next_channel > CHANNEL_HIGHEST_AVAILABLE)
|
||||
next_channel = 1
|
||||
|
||||
/mob/proc/stop_sound_channel(chan)
|
||||
SEND_SOUND(src, sound(null, repeat = 0, wait = 0, channel = chan))
|
||||
|
||||
/mob/proc/set_sound_channel_volume(channel, volume)
|
||||
var/sound/S = sound(null, FALSE, FALSE, channel, volume)
|
||||
S.status = SOUND_UPDATE
|
||||
SEND_SOUND(src, S)
|
||||
|
||||
/client/proc/playtitlemusic()
|
||||
if(!SSticker || !SSticker.login_music || config.disable_lobby_music)
|
||||
return
|
||||
|
||||
@@ -309,6 +309,20 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
/datum/asset/chem_master/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
//Cloning pod sprites for UIs
|
||||
/datum/asset/cloning
|
||||
var/assets = list()
|
||||
var/verify = FALSE
|
||||
|
||||
/datum/asset/cloning/register()
|
||||
assets["pod_idle.gif"] = icon('icons/obj/cloning.dmi', "pod_idle")
|
||||
assets["pod_cloning.gif"] = icon('icons/obj/cloning.dmi', "pod_cloning")
|
||||
assets["pod_mess.gif"] = icon('icons/obj/cloning.dmi', "pod_mess")
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/cloning/send(client)
|
||||
send_asset_list(client, assets, verify)
|
||||
|
||||
//Pipe sprites for UIs
|
||||
/datum/asset/rpd
|
||||
|
||||
@@ -166,7 +166,3 @@
|
||||
/datum/gear/hat/flowerpin
|
||||
display_name = "hair flower"
|
||||
path = /obj/item/clothing/head/hairflower
|
||||
|
||||
/datum/gear/hat/kitty
|
||||
display_name = "kitty headband"
|
||||
path = /obj/item/clothing/head/kitty
|
||||
|
||||
@@ -8,21 +8,3 @@
|
||||
strip_delay = 15
|
||||
put_on_delay = 25
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/clothing/ears/headphones
|
||||
name = "headphones"
|
||||
desc = "Unce unce unce unce."
|
||||
var/on = 0
|
||||
icon_state = "headphones0"
|
||||
item_state = null
|
||||
actions_types = list(/datum/action/item_action/toggle_headphones)
|
||||
|
||||
/obj/item/clothing/ears/headphones/attack_self(mob/user)
|
||||
on = !on
|
||||
icon_state = "headphones[on]"
|
||||
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
user.update_inv_ears()
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Get all non admin_only instruments as a list of text ids.
|
||||
*/
|
||||
/proc/get_allowed_instrument_ids()
|
||||
. = list()
|
||||
for(var/id in SSinstruments.instrument_data)
|
||||
var/datum/instrument/I = SSinstruments.instrument_data[id]
|
||||
if(!I.admin_only)
|
||||
. += I.id
|
||||
|
||||
/**
|
||||
* # Instrument Datums
|
||||
*
|
||||
* Instrument datums hold the data for any given instrument, as well as data on how to play it and what bounds there are to playing it.
|
||||
*
|
||||
* The datums themselves are kept in SSinstruments in a list by their unique ID. The reason it uses ID instead of typepath is to support the runtime creation of instruments.
|
||||
* Since songs cache them while playing, there isn't realistic issues regarding performance from accessing.
|
||||
*/
|
||||
/datum/instrument
|
||||
/// Name of the instrument
|
||||
var/name = "Generic instrument"
|
||||
/// Uniquely identifies this instrument so runtime changes are possible as opposed to paths. If this is unset, things will use path instead.
|
||||
var/id
|
||||
/// Category
|
||||
var/category = "Unsorted"
|
||||
/// Used for categorization subtypes
|
||||
var/abstract_type = /datum/instrument
|
||||
/// Write here however many samples, follow this syntax: "%note num%"='%sample file%' eg. "27"='synthesizer/e2.ogg'. Key must never be lower than 0 and higher than 127
|
||||
var/list/real_samples
|
||||
/// assoc list key = /datum/instrument_key. do not fill this yourself!
|
||||
var/list/samples
|
||||
/// See __DEFINES/flags/instruments.dm
|
||||
var/instrument_flags = NONE
|
||||
/// For legacy instruments, the path to our notes
|
||||
var/legacy_instrument_path
|
||||
/// For legacy instruments, our file extension
|
||||
var/legacy_instrument_ext
|
||||
/// What songs are using us
|
||||
var/list/datum/song/songs_using = list()
|
||||
/// Don't touch this
|
||||
var/static/HIGHEST_KEY = 127
|
||||
/// Don't touch this x2
|
||||
var/static/LOWEST_KEY = 0
|
||||
/// Oh no - For truly troll instruments.
|
||||
var/admin_only = FALSE
|
||||
/// Volume multiplier. Synthesized instruments are quite loud and I don't like to cut off potential detail via editing. (someone correct me if this isn't a thing)
|
||||
var/volume_multiplier = 0.33
|
||||
|
||||
/datum/instrument/New()
|
||||
if(isnull(id))
|
||||
id = "[type]"
|
||||
|
||||
/datum/instrument/Destroy()
|
||||
SSinstruments.instrument_data -= id
|
||||
for(var/i in songs_using)
|
||||
var/datum/song/S = i
|
||||
S.set_instrument(null)
|
||||
real_samples = null
|
||||
samples = null
|
||||
songs_using = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Initializes the instrument, calculating its samples if necessary.
|
||||
*/
|
||||
/datum/instrument/proc/Initialize()
|
||||
if(instrument_flags & (INSTRUMENT_LEGACY | INSTRUMENT_DO_NOT_AUTOSAMPLE))
|
||||
return
|
||||
calculate_samples()
|
||||
|
||||
/**
|
||||
* Checks if this instrument is ready to play.
|
||||
*/
|
||||
/datum/instrument/proc/is_ready()
|
||||
if(instrument_flags & INSTRUMENT_LEGACY)
|
||||
return legacy_instrument_path && legacy_instrument_ext
|
||||
else if(instrument_flags & INSTRUMENT_DO_NOT_AUTOSAMPLE)
|
||||
return length(samples)
|
||||
return length(samples) >= 128
|
||||
|
||||
/**
|
||||
* For synthesized instruments, this is how the instrument generates the "keys" that a [/datum/song] uses to play notes.
|
||||
* Calculating them on the fly would be unperformant, so we do it during init and keep it all cached in a list.
|
||||
*/
|
||||
/datum/instrument/proc/calculate_samples()
|
||||
if(!length(real_samples))
|
||||
CRASH("No real samples defined for [id] [type] on calculate_samples() call.")
|
||||
var/list/real_keys = list()
|
||||
samples = list()
|
||||
for(var/key in real_samples)
|
||||
real_keys += text2num(key)
|
||||
sortTim(real_keys, /proc/cmp_numeric_asc, associative = FALSE)
|
||||
|
||||
for(var/i in 1 to (length(real_keys) - 1))
|
||||
var/from_key = real_keys[i]
|
||||
var/to_key = real_keys[i + 1]
|
||||
var/sample1 = real_samples[num2text(from_key)]
|
||||
var/sample2 = real_samples[num2text(to_key)]
|
||||
var/pivot = FLOOR((from_key + to_key) / 2, 1) //original code was a round but I replaced it because that's effectively a floor, thanks Baystation! who knows what was intended.
|
||||
for(var/key in from_key to pivot)
|
||||
samples[num2text(key)] = new /datum/instrument_key(sample1, key, key - from_key)
|
||||
for(var/key in (pivot + 1) to to_key)
|
||||
samples[num2text(key)] = new /datum/instrument_key(sample2, key, key - to_key)
|
||||
|
||||
// Fill in 0 to first key and last key to 127
|
||||
var/first_key = real_keys[1]
|
||||
var/last_key = real_keys[length(real_keys)]
|
||||
var/first_sample = real_samples[num2text(first_key)]
|
||||
var/last_sample = real_samples[num2text(last_key)]
|
||||
for(var/key in LOWEST_KEY to (first_key - 1))
|
||||
samples[num2text(key)] = new /datum/instrument_key(first_sample, key, key - first_key)
|
||||
for(var/key in last_key to HIGHEST_KEY)
|
||||
samples[num2text(key)] = new /datum/instrument_key(last_sample, key, key - last_key)
|
||||
@@ -0,0 +1,33 @@
|
||||
#define KEY_TWELTH (1/12)
|
||||
|
||||
/**
|
||||
* Instrument key datums contain everything needed to know how to play a specific
|
||||
* note of an instrument.*
|
||||
*/
|
||||
/datum/instrument_key
|
||||
/// The numerical key of what this is, from 1 to 127 on a standard piano keyboard.
|
||||
var/key
|
||||
/// The actual sample file that will be loaded when playing.
|
||||
var/sample
|
||||
/// The frequency to play the sample to get our desired note.
|
||||
var/frequency
|
||||
/// Deviation up/down from the pivot point that uses its sample. Used to calculate frequency.
|
||||
var/deviation
|
||||
|
||||
/datum/instrument_key/New(sample, key, deviation, frequency)
|
||||
src.sample = sample
|
||||
src.key = key
|
||||
src.deviation = deviation
|
||||
src.frequency = frequency
|
||||
if(!frequency && deviation)
|
||||
calculate()
|
||||
|
||||
/**
|
||||
* Calculates and stores our deviation.
|
||||
*/
|
||||
/datum/instrument_key/proc/calculate()
|
||||
if(!deviation)
|
||||
CRASH("Invalid calculate call: No deviation or sample in instrument_key")
|
||||
frequency = 2 ** (KEY_TWELTH * deviation)
|
||||
|
||||
#undef KEY_TWELTH
|
||||
@@ -0,0 +1,26 @@
|
||||
/datum/instrument/brass
|
||||
name = "Generic brass instrument"
|
||||
category = "Brass"
|
||||
abstract_type = /datum/instrument/brass
|
||||
|
||||
/datum/instrument/brass/crisis_section
|
||||
name = "Crisis Brass Section"
|
||||
id = "crbrass"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/brass/crisis_brass/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/brass/crisis_brass/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/brass/crisis_brass/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/brass/crisis_brass/c5.ogg')
|
||||
|
||||
/datum/instrument/brass/crisis_trombone
|
||||
name = "Crisis Trombone"
|
||||
id = "crtrombone"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/brass/crisis_trombone/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/brass/crisis_trombone/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/brass/crisis_trombone/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/brass/crisis_trombone/c5.ogg')
|
||||
|
||||
/datum/instrument/brass/crisis_trumpet
|
||||
name = "Crisis Trumpet"
|
||||
id = "crtrumpet"
|
||||
real_samples = list("60"='sound/instruments/synthesis_samples/brass/crisis_trumpet/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/brass/crisis_trumpet/c5.ogg')
|
||||
@@ -0,0 +1,31 @@
|
||||
/datum/instrument/chromatic
|
||||
name = "Generic chromatic percussion instrument"
|
||||
category = "Chromatic percussion"
|
||||
abstract_type = /datum/instrument/chromatic
|
||||
|
||||
/datum/instrument/chromatic/vibraphone1
|
||||
name = "Crisis Vibraphone"
|
||||
id = "crvibr"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/chromatic/vibraphone1/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/chromatic/vibraphone1/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/chromatic/vibraphone1/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/chromatic/vibraphone1/c5.ogg')
|
||||
|
||||
/datum/instrument/chromatic/musicbox1
|
||||
name = "SGM Music Box"
|
||||
id = "sgmmbox"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/chromatic/sgmbox/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/chromatic/sgmbox/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/chromatic/sgmbox/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/chromatic/sgmbox/c5.ogg')
|
||||
|
||||
/datum/instrument/chromatic/fluid_celeste
|
||||
name = "FluidR3 Celeste"
|
||||
id = "r3celeste"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c5.ogg',
|
||||
"84"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c6.ogg',
|
||||
"96"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c7.ogg',
|
||||
"108"='sound/instruments/synthesis_samples/chromatic/fluid_celeste/c8.ogg')
|
||||
@@ -0,0 +1,19 @@
|
||||
/datum/instrument/fun
|
||||
name = "Generic Fun Instrument"
|
||||
category = "Fun"
|
||||
abstract_type = /datum/instrument/fun
|
||||
|
||||
/datum/instrument/fun/honk
|
||||
name = "!!HONK!!"
|
||||
id = "honk"
|
||||
real_samples = list("74"='sound/items/bikehorn.ogg') // Cluwne Heaven
|
||||
|
||||
/datum/instrument/fun/signal
|
||||
name = "Ping"
|
||||
id = "ping"
|
||||
real_samples = list("79"='sound/machines/ping.ogg')
|
||||
|
||||
/datum/instrument/fun/chime
|
||||
name = "Chime"
|
||||
id = "chime"
|
||||
real_samples = list("79"='sound/machines/chime.ogg')
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/instrument/guitar
|
||||
name = "Generic guitar-like instrument"
|
||||
category = "Guitar"
|
||||
abstract_type = /datum/instrument/guitar
|
||||
|
||||
/datum/instrument/guitar/steel_crisis
|
||||
name = "Crisis Steel String Guitar"
|
||||
id = "csteelgt"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/guitar/crisis_steel/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/guitar/crisis_steel/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/guitar/crisis_steel/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/guitar/crisis_steel/c5.ogg')
|
||||
|
||||
/datum/instrument/guitar/nylon_crisis
|
||||
name = "Crisis Nylon String Guitar"
|
||||
id = "cnylongt"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/guitar/crisis_nylon/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/guitar/crisis_nylon/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/guitar/crisis_nylon/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/guitar/crisis_nylon/c5.ogg')
|
||||
|
||||
/datum/instrument/guitar/clean_crisis
|
||||
name = "Crisis Clean Guitar"
|
||||
id = "ccleangt"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/guitar/crisis_clean/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/guitar/crisis_clean/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/guitar/crisis_clean/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/guitar/crisis_clean/c5.ogg')
|
||||
|
||||
/datum/instrument/guitar/muted_crisis
|
||||
name = "Crisis Muted Guitar"
|
||||
id = "cmutedgt"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/guitar/crisis_muted/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/guitar/crisis_muted/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/guitar/crisis_muted/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/guitar/crisis_muted/c5.ogg')
|
||||
@@ -0,0 +1,86 @@
|
||||
//THESE ARE HARDCODED INSTRUMENT SAMPLES.
|
||||
//SONGS WILL BE AUTOMATICALLY SWITCHED TO LEGACY MODE IF THEY USE THIS KIND OF INSTRUMENT!
|
||||
//I'd prefer these stayed. They sound different from the mechanical synthesis of synthed instruments, and I quite like them that way. It's not legacy, it's hardcoded, old style. - kevinz000
|
||||
/datum/instrument/hardcoded
|
||||
abstract_type = /datum/instrument/hardcoded
|
||||
category = "Non-Synthesized"
|
||||
instrument_flags = INSTRUMENT_LEGACY
|
||||
volume_multiplier = 1 //not as loud as synth'd
|
||||
|
||||
/datum/instrument/hardcoded/accordion
|
||||
name = "Accordion"
|
||||
id = "accordion"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "accordion"
|
||||
|
||||
/datum/instrument/hardcoded/bikehorn
|
||||
name = "Bike Horn"
|
||||
id = "bikehorn"
|
||||
legacy_instrument_ext = "ogg"
|
||||
legacy_instrument_path = "bikehorn"
|
||||
|
||||
/datum/instrument/hardcoded/eguitar
|
||||
name = "Electric Guitar"
|
||||
id = "eguitar"
|
||||
legacy_instrument_ext = "ogg"
|
||||
legacy_instrument_path = "eguitar"
|
||||
|
||||
/datum/instrument/hardcoded/glockenspiel
|
||||
name = "Glockenspiel"
|
||||
id = "glockenspiel"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "glockenspiel"
|
||||
|
||||
/datum/instrument/hardcoded/guitar
|
||||
name = "Guitar"
|
||||
id = "guitar"
|
||||
legacy_instrument_ext = "ogg"
|
||||
legacy_instrument_path = "guitar"
|
||||
|
||||
/datum/instrument/hardcoded/harmonica
|
||||
name = "Harmonica"
|
||||
id = "harmonica"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "harmonica"
|
||||
|
||||
/datum/instrument/hardcoded/piano
|
||||
name = "Piano"
|
||||
id = "piano"
|
||||
legacy_instrument_ext = "ogg"
|
||||
legacy_instrument_path = "piano"
|
||||
|
||||
/datum/instrument/hardcoded/recorder
|
||||
name = "Recorder"
|
||||
id = "recorder"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "recorder"
|
||||
|
||||
/datum/instrument/hardcoded/saxophone
|
||||
name = "Saxophone"
|
||||
id = "saxophone"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "saxophone"
|
||||
|
||||
/datum/instrument/hardcoded/trombone
|
||||
name = "Trombone"
|
||||
id = "trombone"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "trombone"
|
||||
|
||||
/datum/instrument/hardcoded/violin
|
||||
name = "Violin"
|
||||
id = "violin"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "violin"
|
||||
|
||||
/datum/instrument/hardcoded/xylophone
|
||||
name = "Xylophone"
|
||||
id = "xylophone"
|
||||
legacy_instrument_ext = "mid"
|
||||
legacy_instrument_path = "xylophone"
|
||||
|
||||
/datum/instrument/hardcoded/banjo
|
||||
name = "Banjo"
|
||||
id = "banjo"
|
||||
legacy_instrument_ext = "ogg"
|
||||
legacy_instrument_path = "banjo"
|
||||
@@ -0,0 +1,53 @@
|
||||
//copy pasta of the space piano, don't hurt me -Pete
|
||||
/obj/item/instrument
|
||||
name = "generic instrument"
|
||||
force = 10
|
||||
max_integrity = 100
|
||||
resistance_flags = FLAMMABLE
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/equipment/instruments_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/instruments_righthand.dmi'
|
||||
/// Our song datum.
|
||||
var/datum/song/handheld/song
|
||||
/// Our allowed list of instrument ids. This is nulled on initialize.
|
||||
var/list/allowed_instrument_ids
|
||||
/// How far away our song datum can be heard.
|
||||
var/instrument_range = 15
|
||||
|
||||
/obj/item/instrument/Initialize(mapload)
|
||||
. = ..()
|
||||
song = new(src, allowed_instrument_ids, instrument_range)
|
||||
allowed_instrument_ids = null //We don't need this clogging memory after it's used.
|
||||
|
||||
/obj/item/instrument/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/item/instrument/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins to play 'Gloomy Sunday'! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/instrument/attack_self(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/item/instrument/tgui_data(mob/user)
|
||||
return song.tgui_data(user)
|
||||
|
||||
/obj/item/instrument/tgui_interact(mob/user)
|
||||
if(!isliving(user) || user.incapacitated())
|
||||
return
|
||||
song.tgui_interact(user)
|
||||
|
||||
/obj/item/instrument/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
return song.tgui_act(action, params)
|
||||
|
||||
/**
|
||||
* Whether the instrument should stop playing
|
||||
*
|
||||
* Arguments:
|
||||
* * user - The user
|
||||
*/
|
||||
/obj/item/instrument/proc/should_stop_playing(mob/user)
|
||||
return !(src in user) || !isliving(user) || user.incapacitated()
|
||||
@@ -0,0 +1,80 @@
|
||||
/obj/item/clothing/ears/headphones
|
||||
name = "headphones"
|
||||
desc = "Unce unce unce unce."
|
||||
icon_state = "headphones0"
|
||||
item_state = "headphones0"
|
||||
actions_types = list(/datum/action/item_action/change_headphones_song)
|
||||
var/datum/song/headphones/song
|
||||
|
||||
/obj/item/clothing/ears/headphones/Initialize(mapload)
|
||||
. = ..()
|
||||
song = new(src, "piano") // Piano is the default instrument but all instruments are allowed
|
||||
song.instrument_range = 0
|
||||
song.allowed_instrument_ids = SSinstruments.synthesizer_instrument_ids
|
||||
// To update the icon
|
||||
RegisterSignal(src, COMSIG_SONG_START, .proc/start_playing)
|
||||
RegisterSignal(src, COMSIG_SONG_END, .proc/stop_playing)
|
||||
|
||||
/obj/item/clothing/ears/headphones/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/ears/headphones/attack_self(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/item/clothing/ears/headphones/tgui_data(mob/user)
|
||||
return song.tgui_data(user)
|
||||
|
||||
/obj/item/clothing/ears/headphones/tgui_interact(mob/user)
|
||||
if(should_stop_playing(user) || user.incapacitated())
|
||||
return
|
||||
song.tgui_interact(user)
|
||||
|
||||
/obj/item/clothing/ears/headphones/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
return song.tgui_act(action, params)
|
||||
|
||||
/obj/item/clothing/ears/headphones/update_icon()
|
||||
var/mob/living/carbon/human/user = loc
|
||||
if(istype(user))
|
||||
user.update_action_buttons_icon()
|
||||
user.update_inv_ears()
|
||||
..()
|
||||
|
||||
/obj/item/clothing/ears/headphones/item_action_slot_check(slot)
|
||||
if(slot == slot_l_ear || slot == slot_r_ear)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called by a component signal when our song starts playing.
|
||||
*/
|
||||
/obj/item/clothing/ears/headphones/proc/start_playing()
|
||||
icon_state = item_state = "headphones1"
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* Called by a component signal when our song stops playing.
|
||||
*/
|
||||
/obj/item/clothing/ears/headphones/proc/stop_playing()
|
||||
icon_state = item_state = "headphones0"
|
||||
update_icon()
|
||||
|
||||
/**
|
||||
* Whether the headphone's song should stop playing
|
||||
*
|
||||
* Arguments:
|
||||
* * user - The user
|
||||
*/
|
||||
/obj/item/clothing/ears/headphones/proc/should_stop_playing(mob/living/carbon/human/user)
|
||||
return !(src in user) || !istype(user) || !((src == user.l_ear) || (src == user.r_ear))
|
||||
|
||||
// special subtype so it uses the correct item type
|
||||
/datum/song/headphones
|
||||
|
||||
/datum/song/headphones/should_stop_playing(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
var/obj/item/clothing/ears/headphones/I = parent
|
||||
return I.should_stop_playing(user)
|
||||
@@ -1,55 +1,10 @@
|
||||
//copy pasta of the space piano, don't hurt me -Pete
|
||||
/obj/item/instrument
|
||||
name = "generic instrument"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/equipment/instruments_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/instruments_righthand.dmi'
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 100
|
||||
var/datum/song/handheld/song
|
||||
var/instrumentId = "generic"
|
||||
var/instrumentExt = "mid"
|
||||
|
||||
/obj/item/instrument/New()
|
||||
song = new(instrumentId, src, instrumentExt)
|
||||
..()
|
||||
|
||||
/obj/item/instrument/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/item/instrument/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins to play 'Gloomy Sunday'! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/instrument/Initialize(mapload)
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
..()
|
||||
|
||||
/obj/item/instrument/attack_self(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/instrument/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
if(!isliving(user) || user.incapacitated())
|
||||
return
|
||||
|
||||
song.ui_interact(user, ui_key, ui, force_open)
|
||||
|
||||
/obj/item/instrument/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
return song.ui_data(user, ui_key, state)
|
||||
|
||||
/obj/item/instrument/Topic(href, href_list)
|
||||
song.Topic(href, href_list)
|
||||
|
||||
/obj/item/instrument/violin
|
||||
name = "space violin"
|
||||
desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
icon_state = "violin"
|
||||
item_state = "violin"
|
||||
instrumentExt = "ogg"
|
||||
force = 10
|
||||
hitsound = "swing_hit"
|
||||
instrumentId = "violin"
|
||||
allowed_instrument_ids = "violin"
|
||||
|
||||
/obj/item/instrument/violin/golden
|
||||
name = "golden violin"
|
||||
@@ -63,87 +18,146 @@
|
||||
desc = "An advanced electronic synthesizer that can be used as various instruments."
|
||||
icon_state = "synth"
|
||||
item_state = "synth"
|
||||
instrumentId = "piano"
|
||||
instrumentExt = "ogg"
|
||||
var/static/list/insTypes = list("accordion" = "mid", "glockenspiel" = "mid", "guitar" = "ogg", "eguitar" = "ogg", "harmonica" = "mid", "piano" = "ogg", "recorder" = "mid", "saxophone" = "mid", "trombone" = "mid", "violin" = "ogg", "xylophone" = "mid")
|
||||
actions_types = list(/datum/action/item_action/synthswitch)
|
||||
allowed_instrument_ids = "piano"
|
||||
|
||||
/obj/item/instrument/piano_synth/proc/changeInstrument(name = "piano")
|
||||
song.instrumentDir = name
|
||||
song.instrumentExt = insTypes[name]
|
||||
/obj/item/instrument/piano_synth/Initialize(mapload)
|
||||
. = ..()
|
||||
song.allowed_instrument_ids = SSinstruments.synthesizer_instrument_ids
|
||||
|
||||
/obj/item/instrument/banjo
|
||||
name = "banjo"
|
||||
desc = "A 'Mura' brand banjo. It's pretty much just a drum with a neck and strings."
|
||||
icon_state = "banjo"
|
||||
item_state = "banjo"
|
||||
attack_verb = list("scruggs-styled", "hum-diggitied", "shin-digged", "clawhammered")
|
||||
hitsound = 'sound/weapons/banjoslap.ogg'
|
||||
allowed_instrument_ids = "banjo"
|
||||
|
||||
/obj/item/instrument/guitar
|
||||
name = "guitar"
|
||||
desc = "It's made of wood and has bronze strings."
|
||||
icon_state = "guitar"
|
||||
item_state = "guitar"
|
||||
instrumentExt = "ogg"
|
||||
force = 10
|
||||
attack_verb = list("played metal on", "serenaded", "crashed", "smashed")
|
||||
hitsound = 'sound/effects/guitarsmash.ogg'
|
||||
instrumentId = "guitar"
|
||||
hitsound = 'sound/weapons/guitarslam.ogg'
|
||||
allowed_instrument_ids = "guitar"
|
||||
|
||||
/obj/item/instrument/eguitar
|
||||
name = "electric guitar"
|
||||
desc = "Makes all your shredding needs possible."
|
||||
icon_state = "eguitar"
|
||||
item_state = "eguitar"
|
||||
instrumentExt = "ogg"
|
||||
force = 12
|
||||
attack_verb = list("played metal on", "shredded", "crashed", "smashed")
|
||||
hitsound = 'sound/weapons/stringsmash.ogg'
|
||||
instrumentId = "eguitar"
|
||||
allowed_instrument_ids = "eguitar"
|
||||
|
||||
/obj/item/instrument/glockenspiel
|
||||
name = "glockenspiel"
|
||||
desc = "Smooth metal bars perfect for any marching band."
|
||||
icon_state = "glockenspiel"
|
||||
item_state = "glockenspiel"
|
||||
instrumentId = "glockenspiel"
|
||||
allowed_instrument_ids = "glockenspiel"
|
||||
|
||||
/obj/item/instrument/accordion
|
||||
name = "accordion"
|
||||
desc = "Pun-Pun not included."
|
||||
icon_state = "accordion"
|
||||
item_state = "accordion"
|
||||
instrumentId = "accordion"
|
||||
allowed_instrument_ids = "accordion"
|
||||
|
||||
/obj/item/instrument/trumpet
|
||||
name = "trumpet"
|
||||
desc = "To announce the arrival of the king!"
|
||||
icon_state = "trumpet"
|
||||
item_state = "trumpet"
|
||||
allowed_instrument_ids = "trombone"
|
||||
|
||||
/obj/item/instrument/trumpet/spectral
|
||||
name = "spectral trumpet"
|
||||
desc = "Things are about to get spooky!"
|
||||
icon_state = "spectral_trumpet"
|
||||
item_state = "spectral_trumpet"
|
||||
force = 0
|
||||
attack_verb = list("played", "jazzed", "trumpeted", "mourned", "dooted", "spooked")
|
||||
|
||||
/obj/item/instrument/trumpet/spectral/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/spooky)
|
||||
|
||||
/obj/item/instrument/trumpet/spectral/attack(mob/living/carbon/C, mob/user)
|
||||
playsound(src, 'sound/instruments/trombone/En4.mid', 100, 1, -1)
|
||||
..()
|
||||
|
||||
/obj/item/instrument/saxophone
|
||||
name = "saxophone"
|
||||
desc = "This soothing sound will be sure to leave your audience in tears."
|
||||
icon_state = "saxophone"
|
||||
item_state = "saxophone"
|
||||
instrumentId = "saxophone"
|
||||
allowed_instrument_ids = "saxophone"
|
||||
|
||||
/obj/item/instrument/saxophone/spectral
|
||||
name = "spectral saxophone"
|
||||
desc = "This spooky sound will be sure to leave mortals in bones."
|
||||
icon_state = "saxophone"
|
||||
item_state = "saxophone"
|
||||
force = 0
|
||||
attack_verb = list("played", "jazzed", "saxxed", "mourned", "dooted", "spooked")
|
||||
|
||||
/obj/item/instrument/saxophone/spectral/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/spooky)
|
||||
|
||||
/obj/item/instrument/saxophone/spectral/attack(mob/living/carbon/C, mob/user)
|
||||
playsound(src, 'sound/instruments/saxophone/En4.mid', 100,1,-1)
|
||||
..()
|
||||
|
||||
/obj/item/instrument/trombone
|
||||
name = "trombone"
|
||||
desc = "How can any pool table ever hope to compete?"
|
||||
icon_state = "trombone"
|
||||
allowed_instrument_ids = "trombone"
|
||||
item_state = "trombone"
|
||||
instrumentId = "trombone"
|
||||
|
||||
/obj/item/instrument/trombone/spectral
|
||||
name = "spectral trombone"
|
||||
desc = "A skeleton's favorite instrument. Apply directly on the mortals."
|
||||
icon_state = "trombone"
|
||||
item_state = "trombone"
|
||||
force = 0
|
||||
attack_verb = list("played", "jazzed", "tromboned", "mourned", "dooted", "spooked")
|
||||
|
||||
/obj/item/instrument/trombone/spectral/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/spooky)
|
||||
|
||||
/obj/item/instrument/trombone/spectral/attack(mob/living/carbon/C, mob/user)
|
||||
playsound (src, 'sound/instruments/trombone/Cn4.mid', 100,1,-1)
|
||||
..()
|
||||
|
||||
/obj/item/instrument/recorder
|
||||
name = "recorder"
|
||||
desc = "Just like in school, playing ability and all."
|
||||
force = 5
|
||||
icon_state = "recorder"
|
||||
item_state = "recorder"
|
||||
instrumentId = "recorder"
|
||||
allowed_instrument_ids = "recorder"
|
||||
|
||||
/obj/item/instrument/harmonica
|
||||
name = "harmonica"
|
||||
desc = "For when you get a bad case of the space blues."
|
||||
icon_state = "harmonica"
|
||||
item_state = "harmonica"
|
||||
instrumentId = "harmonica"
|
||||
force = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
allowed_instrument_ids = "harmonica"
|
||||
|
||||
/obj/item/instrument/xylophone
|
||||
name = "xylophone"
|
||||
desc = "a percussion instrument with a bright tone."
|
||||
desc = "A percussion instrument with a bright tone."
|
||||
icon_state = "xylophone"
|
||||
item_state = "xylophone"
|
||||
instrumentId = "xylophone"
|
||||
allowed_instrument_ids = "bikehorn"
|
||||
|
||||
/obj/item/instrument/bikehorn
|
||||
name = "gilded bike horn"
|
||||
@@ -153,14 +167,14 @@
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
attack_verb = list("beautifully honks")
|
||||
instrumentId = "bikehorn"
|
||||
instrumentExt = "ogg"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
force = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
hitsound = 'sound/items/bikehorn.ogg'
|
||||
allowed_instrument_ids = "bikehorn"
|
||||
|
||||
// Crafting recipes
|
||||
/datum/crafting_recipe/violin
|
||||
name = "Violin"
|
||||
result = /obj/item/instrument/violin
|
||||
@@ -168,7 +182,7 @@
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
time = 8 SECONDS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/guitar
|
||||
@@ -178,7 +192,7 @@
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
time = 8 SECONDS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/eguitar
|
||||
@@ -188,5 +202,15 @@
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 80
|
||||
time = 8 SECONDS
|
||||
category = CAT_MISC
|
||||
|
||||
/datum/crafting_recipe/banjo
|
||||
name = "Banjo"
|
||||
result = /obj/item/instrument/banjo
|
||||
reqs = list(/obj/item/stack/sheet/wood = 5,
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/tape_roll = 5)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 8 SECONDS
|
||||
category = CAT_MISC
|
||||
@@ -0,0 +1,47 @@
|
||||
/obj/structure/musician
|
||||
name = "Not A Piano"
|
||||
desc = "Something broke!"
|
||||
var/can_play_unanchored = FALSE
|
||||
var/list/allowed_instrument_ids
|
||||
var/datum/song/song
|
||||
|
||||
/obj/structure/musician/Initialize(mapload)
|
||||
. = ..()
|
||||
song = new(src, allowed_instrument_ids)
|
||||
allowed_instrument_ids = null
|
||||
|
||||
/obj/structure/musician/Destroy()
|
||||
QDEL_NULL(song)
|
||||
return ..()
|
||||
|
||||
/obj/structure/musician/attack_hand(mob/user)
|
||||
add_fingerprint(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/structure/musician/tgui_data(mob/user)
|
||||
return song.tgui_data(user)
|
||||
|
||||
/obj/structure/musician/tgui_interact(mob/user)
|
||||
song.tgui_interact(user)
|
||||
|
||||
/obj/structure/musician/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
return song.tgui_act(action, params)
|
||||
|
||||
/obj/structure/musician/wrench_act(mob/living/user, obj/item/I)
|
||||
default_unfasten_wrench(user, I, 40)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Whether the instrument should stop playing
|
||||
*
|
||||
* Arguments:
|
||||
* * user - The user
|
||||
*/
|
||||
/obj/structure/musician/proc/should_stop_playing(mob/user)
|
||||
if(!(anchored || can_play_unanchored))
|
||||
return TRUE
|
||||
if(!user)
|
||||
return FALSE
|
||||
return !CanUseTopic(user, GLOB.physical_state)
|
||||
@@ -0,0 +1,22 @@
|
||||
/obj/structure/piano
|
||||
parent_type = /obj/structure/musician // TODO: Can't edit maps right now due to a freeze, remove and update path when it's done
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
allowed_instrument_ids = "piano"
|
||||
|
||||
/obj/structure/piano/unanchored
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/piano/Initialize(mapload)
|
||||
. = ..()
|
||||
if(prob(50) && icon_state == initial(icon_state))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
@@ -0,0 +1,43 @@
|
||||
/datum/instrument/organ
|
||||
name = "Generic organ"
|
||||
category = "Organ"
|
||||
abstract_type = /datum/instrument/organ
|
||||
|
||||
/datum/instrument/organ/crisis_church
|
||||
name = "Crisis Church Organ"
|
||||
id = "crichugan"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_church/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/organ/crisis_church/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/organ/crisis_church/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/organ/crisis_church/c5.ogg')
|
||||
|
||||
/datum/instrument/organ/crisis_hammond
|
||||
name = "Crisis Hammond Organ"
|
||||
id = "crihamgan"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_hammond/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/organ/crisis_hammond/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/organ/crisis_hammond/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/organ/crisis_hammond/c5.ogg')
|
||||
|
||||
/datum/instrument/organ/crisis_accordian
|
||||
name = "Crisis Accordion"
|
||||
id = "crack"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_accordian/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/organ/crisis_accordian/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/organ/crisis_accordian/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/organ/crisis_accordian/c5.ogg')
|
||||
|
||||
/datum/instrument/organ/crisis_harmonica
|
||||
name = "Crisis Harmonica"
|
||||
id = "crharmony"
|
||||
real_samples = list("48"='sound/instruments/synthesis_samples/organ/crisis_harmonica/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/organ/crisis_harmonica/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/organ/crisis_harmonica/c5.ogg')
|
||||
|
||||
/datum/instrument/organ/crisis_tango_accordian
|
||||
name = "Crisis Tango Accordion"
|
||||
id = "crtango"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/organ/crisis_tangaccordian/c5.ogg')
|
||||
@@ -0,0 +1,56 @@
|
||||
/datum/instrument/piano
|
||||
name = "Generic piano"
|
||||
category = "Piano"
|
||||
abstract_type = /datum/instrument/piano
|
||||
|
||||
/datum/instrument/piano/fluid_piano
|
||||
name = "FluidR3 Grand Piano"
|
||||
id = "r3grand"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/piano/fluid_piano/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/piano/fluid_piano/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/piano/fluid_piano/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/piano/fluid_piano/c5.ogg',
|
||||
"84"='sound/instruments/synthesis_samples/piano/fluid_piano/c6.ogg',
|
||||
"96"='sound/instruments/synthesis_samples/piano/fluid_piano/c7.ogg',
|
||||
"108"='sound/instruments/synthesis_samples/piano/fluid_piano/c8.ogg')
|
||||
|
||||
/datum/instrument/piano/fluid_harpsichord
|
||||
name = "FluidR3 Harpsichord"
|
||||
id = "r3harpsi"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c5.ogg',
|
||||
"84"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c6.ogg',
|
||||
"96"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c7.ogg',
|
||||
"108"='sound/instruments/synthesis_samples/piano/fluid_harpsi/c8.ogg')
|
||||
|
||||
/datum/instrument/piano/crisis_harpsichord
|
||||
name = "Crisis Harpsichord"
|
||||
id = "crharpsi"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/piano/crisis_harpsichord/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/piano/crisis_harpsichord/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/piano/crisis_harpsichord/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/piano/crisis_harpsichord/c5.ogg')
|
||||
|
||||
/datum/instrument/piano/crisis_grandpiano_uni
|
||||
name = "Crisis Grand Piano One"
|
||||
id = "crgrand1"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c5.ogg',
|
||||
"84"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c6.ogg',
|
||||
"96"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c7.ogg',
|
||||
"108"='sound/instruments/synthesis_samples/piano/crisis_grand_piano/c8.ogg')
|
||||
|
||||
/datum/instrument/piano/crisis_brightpiano_uni
|
||||
name = "Crisis Bright Piano One"
|
||||
id = "crbright1"
|
||||
real_samples = list("36"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c2.ogg',
|
||||
"48"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c3.ogg',
|
||||
"60"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c4.ogg',
|
||||
"72"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c5.ogg',
|
||||
"84"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c6.ogg',
|
||||
"96"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c7.ogg',
|
||||
"108"='sound/instruments/synthesis_samples/piano/crisis_bright_piano/c8.ogg')
|
||||
@@ -0,0 +1,410 @@
|
||||
#define MUSICIAN_HEARCHECK_MINDELAY 4
|
||||
#define MUSIC_MAXLINES 1000
|
||||
#define MUSIC_MAXLINECHARS 300
|
||||
|
||||
/**
|
||||
* # Song datum
|
||||
*
|
||||
* These are the actual backend behind instruments.
|
||||
* They attach to an atom and provide the editor + playback functionality.
|
||||
*/
|
||||
/datum/song
|
||||
/// Name of the song
|
||||
var/name = "Untitled"
|
||||
|
||||
/// The atom we're attached to/playing from
|
||||
var/atom/parent
|
||||
|
||||
/// Our song lines
|
||||
var/list/lines
|
||||
|
||||
/// delay between notes in deciseconds
|
||||
var/tempo = 5
|
||||
|
||||
/// How far we can be heard
|
||||
var/instrument_range = 15
|
||||
|
||||
/// Are we currently playing?
|
||||
var/playing = FALSE
|
||||
|
||||
/// Are we currently editing?
|
||||
var/editing = TRUE
|
||||
/// Is the help screen open?
|
||||
var/help = FALSE
|
||||
|
||||
/// Repeats left
|
||||
var/repeat = 0
|
||||
/// Maximum times we can repeat
|
||||
var/max_repeats = 10
|
||||
|
||||
/// Our volume
|
||||
var/volume = 75
|
||||
/// Max volume
|
||||
var/max_volume = 75
|
||||
/// Min volume - This is so someone doesn't decide it's funny to set it to 0 and play invisible songs.
|
||||
var/min_volume = 1
|
||||
|
||||
/// What instruments our built in picker can use. The picker won't show unless this is longer than one.
|
||||
var/list/allowed_instrument_ids
|
||||
|
||||
//////////// Cached instrument variables /////////////
|
||||
/// Instrument we are currently using
|
||||
var/datum/instrument/using_instrument
|
||||
/// Cached legacy ext for legacy instruments
|
||||
var/cached_legacy_ext
|
||||
/// Cached legacy dir for legacy instruments
|
||||
var/cached_legacy_dir
|
||||
/// Cached list of samples, referenced directly from the instrument for synthesized instruments
|
||||
var/list/cached_samples
|
||||
/// Are we operating in legacy mode (so if the instrument is a legacy instrument)
|
||||
var/legacy = FALSE
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/////////////////// Playing variables ////////////////
|
||||
/**
|
||||
* Build by compile_chords()
|
||||
* Must be rebuilt on instrument switch.
|
||||
* Compilation happens when we start playing and is cleared after we finish playing.
|
||||
* Format: list of chord lists, with chordlists having (key1, key2, key3, tempodiv)
|
||||
*/
|
||||
var/list/compiled_chords
|
||||
/// Current section of a long chord we're on, so we don't need to make a billion chords, one for every unit ticklag.
|
||||
var/elapsed_delay
|
||||
/// Amount of delay to wait before playing the next chord
|
||||
var/delay_by
|
||||
/// Current chord we're on.
|
||||
var/current_chord
|
||||
/// Channel as text = current volume percentage but it's 0 to 100 instead of 0 to 1.
|
||||
var/list/channels_playing
|
||||
/// List of channels that aren't being used, as text. This is to prevent unnecessary freeing and reallocations from SSsounds/SSinstruments.
|
||||
var/list/channels_idle
|
||||
/// Person playing us
|
||||
var/mob/user_playing
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/// Last world.time we checked for who can hear us
|
||||
var/last_hearcheck = 0
|
||||
/// The list of mobs that can hear us
|
||||
var/list/hearing_mobs
|
||||
/// If this is enabled, some things won't be strictly cleared when they usually are (liked compiled_chords on play stop)
|
||||
var/debug_mode = FALSE
|
||||
/// Max sound channels to occupy
|
||||
var/max_sound_channels = CHANNELS_PER_INSTRUMENT
|
||||
/// Current channels, so we can save a length() call.
|
||||
var/using_sound_channels = 0
|
||||
/// Last channel to play. text.
|
||||
var/last_channel_played
|
||||
/// Should we not decay our last played note?
|
||||
var/full_sustain_held_note = TRUE
|
||||
|
||||
/////////////////////// DO NOT TOUCH THESE ///////////////////
|
||||
var/octave_min = INSTRUMENT_MIN_OCTAVE
|
||||
var/octave_max = INSTRUMENT_MAX_OCTAVE
|
||||
var/key_min = INSTRUMENT_MIN_KEY
|
||||
var/key_max = INSTRUMENT_MAX_KEY
|
||||
var/static/list/note_offset_lookup
|
||||
var/static/list/accent_lookup
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
///////////// !!FUN!! - Only works in synthesized mode! /////////////////
|
||||
/// Note numbers to shift.
|
||||
var/note_shift = 0
|
||||
var/note_shift_min = -100
|
||||
var/note_shift_max = 100
|
||||
var/can_noteshift = TRUE
|
||||
/// The kind of sustain we're using
|
||||
var/sustain_mode = SUSTAIN_LINEAR
|
||||
/// When a note is considered dead if it is below this in volume
|
||||
var/sustain_dropoff_volume = INSTRUMENT_MIN_SUSTAIN_DROPOFF
|
||||
/// Total duration of linear sustain for 100 volume note to get to SUSTAIN_DROPOFF
|
||||
var/sustain_linear_duration = 5
|
||||
/// Exponential sustain dropoff rate per decisecond
|
||||
var/sustain_exponential_dropoff = 1.4
|
||||
////////// DO NOT DIRECTLY SET THESE!
|
||||
/// Do not directly set, use update_sustain()
|
||||
var/cached_linear_dropoff = 10
|
||||
/// Do not directly set, use update_sustain()
|
||||
var/cached_exponential_dropoff = 1.045
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var/static/list/valid_files[0] // Cache to avoid running fexists() every time
|
||||
|
||||
/datum/song/New(atom/parent, list/instrument_ids, new_range)
|
||||
SSinstruments.on_song_new(src)
|
||||
lines = list()
|
||||
tempo = sanitize_tempo(tempo)
|
||||
src.parent = parent
|
||||
if(instrument_ids)
|
||||
allowed_instrument_ids = islist(instrument_ids) ? instrument_ids : list(instrument_ids)
|
||||
if(length(allowed_instrument_ids))
|
||||
set_instrument(allowed_instrument_ids[1])
|
||||
hearing_mobs = list()
|
||||
volume = clamp(volume, min_volume, max_volume)
|
||||
channels_playing = list()
|
||||
channels_idle = list()
|
||||
if(!note_offset_lookup)
|
||||
note_offset_lookup = list(9, 11, 0, 2, 4, 5, 7)
|
||||
accent_lookup = list("b" = -1, "s" = 1, "#" = 1, "n" = 0)
|
||||
update_sustain()
|
||||
if(new_range)
|
||||
instrument_range = new_range
|
||||
|
||||
/datum/song/Destroy()
|
||||
stop_playing()
|
||||
SSinstruments.on_song_del(src)
|
||||
lines = null
|
||||
using_instrument = null
|
||||
allowed_instrument_ids = null
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Checks and stores which mobs can hear us. Terminates sounds for mobs that leave our range.
|
||||
*/
|
||||
/datum/song/proc/do_hearcheck()
|
||||
last_hearcheck = world.time
|
||||
var/list/old = hearing_mobs.Copy()
|
||||
hearing_mobs.len = 0
|
||||
var/turf/source = get_turf(parent)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
var/dist = get_dist(M, source)
|
||||
if(dist > instrument_range) // Distance check
|
||||
continue
|
||||
if(!isInSight(M, source)) // Visibility check (direct line of sight)
|
||||
continue
|
||||
hearing_mobs[M] = dist
|
||||
var/list/exited = old - hearing_mobs
|
||||
for(var/i in exited)
|
||||
terminate_sound_mob(i)
|
||||
|
||||
/**
|
||||
* Sets our instrument, caching anything necessary for faster accessing. Accepts an ID, typepath, or instantiated instrument datum.
|
||||
*/
|
||||
/datum/song/proc/set_instrument(datum/instrument/I)
|
||||
terminate_all_sounds()
|
||||
var/old_legacy
|
||||
if(using_instrument)
|
||||
using_instrument.songs_using -= src
|
||||
old_legacy = (using_instrument.instrument_flags & INSTRUMENT_LEGACY)
|
||||
using_instrument = null
|
||||
cached_samples = null
|
||||
cached_legacy_ext = null
|
||||
cached_legacy_dir = null
|
||||
legacy = null
|
||||
if(istext(I) || ispath(I))
|
||||
I = SSinstruments.instrument_data[I]
|
||||
if(istype(I))
|
||||
using_instrument = I
|
||||
I.songs_using += src
|
||||
var/instrument_legacy = (I.instrument_flags & INSTRUMENT_LEGACY)
|
||||
if(instrument_legacy)
|
||||
cached_legacy_ext = I.legacy_instrument_ext
|
||||
cached_legacy_dir = I.legacy_instrument_path
|
||||
legacy = TRUE
|
||||
else
|
||||
cached_samples = I.samples
|
||||
legacy = FALSE
|
||||
if(isnull(old_legacy) || (old_legacy != instrument_legacy))
|
||||
if(playing)
|
||||
compile_chords()
|
||||
|
||||
/**
|
||||
* Attempts to start playing our song.
|
||||
*/
|
||||
/datum/song/proc/start_playing(mob/user)
|
||||
if(playing)
|
||||
return
|
||||
if(!using_instrument?.is_ready())
|
||||
to_chat(user, "<span class='warning'>An error has occured with [src]. Please reset the instrument.</span>")
|
||||
return
|
||||
compile_chords()
|
||||
if(!length(compiled_chords))
|
||||
to_chat(user, "<span class='warning'>Song is empty.</span>")
|
||||
return
|
||||
playing = TRUE
|
||||
SStgui.update_uis(parent)
|
||||
//we can not afford to runtime, since we are going to be doing sound channel reservations and if we runtime it means we have a channel allocation leak.
|
||||
//wrap the rest of the stuff to ensure stop_playing() is called.
|
||||
do_hearcheck()
|
||||
SEND_SIGNAL(parent, COMSIG_SONG_START)
|
||||
elapsed_delay = 0
|
||||
delay_by = 0
|
||||
current_chord = 1
|
||||
user_playing = user
|
||||
START_PROCESSING(SSinstruments, src)
|
||||
|
||||
/**
|
||||
* Stops playing, terminating all sounds if in synthesized mode. Clears hearing_mobs.
|
||||
*/
|
||||
/datum/song/proc/stop_playing()
|
||||
if(!playing)
|
||||
return
|
||||
playing = FALSE
|
||||
if(!debug_mode)
|
||||
compiled_chords = null
|
||||
STOP_PROCESSING(SSinstruments, src)
|
||||
SEND_SIGNAL(parent, COMSIG_SONG_END)
|
||||
terminate_all_sounds(TRUE)
|
||||
hearing_mobs.len = 0
|
||||
SStgui.update_uis(parent)
|
||||
user_playing = null
|
||||
|
||||
/**
|
||||
* Processes our song.
|
||||
*/
|
||||
/datum/song/proc/process_song(wait)
|
||||
if(!length(compiled_chords) || current_chord > length(compiled_chords) || should_stop_playing(user_playing))
|
||||
stop_playing()
|
||||
return
|
||||
var/list/chord = compiled_chords[current_chord]
|
||||
if(++elapsed_delay >= delay_by)
|
||||
play_chord(chord)
|
||||
elapsed_delay = 0
|
||||
delay_by = tempodiv_to_delay(chord[length(chord)])
|
||||
current_chord++
|
||||
if(current_chord > length(compiled_chords))
|
||||
if(repeat)
|
||||
repeat--
|
||||
current_chord = 1
|
||||
SStgui.update_uis(parent)
|
||||
return
|
||||
else
|
||||
stop_playing()
|
||||
return
|
||||
|
||||
/**
|
||||
* Converts a tempodiv to ticks to elapse before playing the next chord, taking into account our tempo.
|
||||
*/
|
||||
/datum/song/proc/tempodiv_to_delay(tempodiv)
|
||||
tempodiv = tempodiv || world.tick_lag // Default to world.tick_lag in case someone's trying to be smart
|
||||
return max(1, round((tempo / tempodiv) / world.tick_lag, 1))
|
||||
|
||||
/**
|
||||
* Compiles chords.
|
||||
*/
|
||||
/datum/song/proc/compile_chords()
|
||||
legacy ? compile_legacy() : compile_synthesized()
|
||||
|
||||
/**
|
||||
* Plays a chord.
|
||||
*/
|
||||
/datum/song/proc/play_chord(list/chord)
|
||||
// last value is timing information
|
||||
for(var/i in 1 to (length(chord) - 1))
|
||||
legacy? playkey_legacy(chord[i][1], chord[i][2], chord[i][3], user_playing) : playkey_synth(chord[i], user_playing)
|
||||
|
||||
/**
|
||||
* Checks if we should halt playback.
|
||||
*/
|
||||
/datum/song/proc/should_stop_playing(mob/user)
|
||||
return QDELETED(parent) || !using_instrument || !playing
|
||||
|
||||
/**
|
||||
* Sanitizes tempo to a value that makes sense and fits the current world.tick_lag.
|
||||
*/
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return clamp(round(new_tempo, world.tick_lag), world.tick_lag, 5 SECONDS)
|
||||
|
||||
/**
|
||||
* Gets our beats per minute based on our tempo.
|
||||
*/
|
||||
/datum/song/proc/get_bpm()
|
||||
return 600 / tempo
|
||||
|
||||
/**
|
||||
* Sets our tempo from a beats-per-minute, sanitizing it to a valid number first.
|
||||
*/
|
||||
/datum/song/proc/set_bpm(bpm)
|
||||
tempo = sanitize_tempo(600 / bpm)
|
||||
|
||||
/datum/song/process(wait)
|
||||
if(!playing)
|
||||
return PROCESS_KILL
|
||||
// it's expected this ticks at every world.tick_lag. if it lags, do not attempt to catch up.
|
||||
process_song(world.tick_lag)
|
||||
process_decay(world.tick_lag)
|
||||
|
||||
/**
|
||||
* Updates our cached linear/exponential falloff stuff, saving calculations down the line.
|
||||
*/
|
||||
/datum/song/proc/update_sustain()
|
||||
// Exponential is easy
|
||||
cached_exponential_dropoff = sustain_exponential_dropoff
|
||||
// Linear, not so much, since it's a target duration from 100 volume rather than an exponential rate.
|
||||
var/target_duration = sustain_linear_duration
|
||||
var/volume_diff = max(0, 100 - sustain_dropoff_volume)
|
||||
var/volume_decrease_per_decisecond = volume_diff / target_duration
|
||||
cached_linear_dropoff = volume_decrease_per_decisecond
|
||||
|
||||
/**
|
||||
* Setter for setting output volume.
|
||||
*/
|
||||
/datum/song/proc/set_volume(volume)
|
||||
src.volume = clamp(volume, max(0, min_volume), min(100, max_volume))
|
||||
update_sustain()
|
||||
// We don't want to send the whole payload (song included) just for volume
|
||||
var/datum/tgui/ui = SStgui.get_open_ui(usr, parent, "main")
|
||||
if(ui)
|
||||
ui.push_data(list("volume" = volume), force = TRUE)
|
||||
|
||||
/**
|
||||
* Setter for setting how low the volume has to get before a note is considered "dead" and dropped
|
||||
*/
|
||||
/datum/song/proc/set_dropoff_volume(volume, no_refresh = FALSE)
|
||||
sustain_dropoff_volume = clamp(volume, INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100)
|
||||
update_sustain()
|
||||
if(!no_refresh)
|
||||
SStgui.update_uis(parent)
|
||||
|
||||
/**
|
||||
* Setter for setting exponential falloff factor.
|
||||
*/
|
||||
/datum/song/proc/set_exponential_drop_rate(drop, no_refresh = FALSE)
|
||||
sustain_exponential_dropoff = clamp(drop, INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX)
|
||||
update_sustain()
|
||||
if(!no_refresh)
|
||||
SStgui.update_uis(parent)
|
||||
|
||||
/**
|
||||
* Setter for setting linear falloff duration.
|
||||
*/
|
||||
/datum/song/proc/set_linear_falloff_duration(duration, no_refresh = FALSE)
|
||||
sustain_linear_duration = clamp(duration, 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN)
|
||||
update_sustain()
|
||||
if(!no_refresh)
|
||||
SStgui.update_uis(parent)
|
||||
|
||||
/datum/song/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
if(.)
|
||||
switch(var_name)
|
||||
if(NAMEOF(src, volume))
|
||||
set_volume(var_value)
|
||||
if(NAMEOF(src, sustain_dropoff_volume))
|
||||
set_dropoff_volume(var_value)
|
||||
if(NAMEOF(src, sustain_exponential_dropoff))
|
||||
set_exponential_drop_rate(var_value)
|
||||
if(NAMEOF(src, sustain_linear_duration))
|
||||
set_linear_falloff_duration(var_value)
|
||||
|
||||
// subtype for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/should_stop_playing(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
var/obj/item/instrument/I = parent
|
||||
return I.should_stop_playing(user)
|
||||
|
||||
// subtype for stationary structures, like pianos
|
||||
/datum/song/stationary
|
||||
|
||||
/datum/song/stationary/should_stop_playing(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
var/obj/structure/musician/M = parent
|
||||
return M.should_stop_playing(user)
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/datum/song/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
// General
|
||||
data["playing"] = playing
|
||||
data["repeat"] = repeat
|
||||
data["maxRepeats"] = max_repeats
|
||||
data["editing"] = editing
|
||||
data["lines"] = lines
|
||||
data["tempo"] = tempo
|
||||
data["minTempo"] = world.tick_lag
|
||||
data["maxTempo"] = 5 SECONDS
|
||||
data["tickLag"] = world.tick_lag
|
||||
data["help"] = help
|
||||
|
||||
// Status
|
||||
var/list/allowed_instrument_names = list()
|
||||
for(var/i in allowed_instrument_ids)
|
||||
var/datum/instrument/I = SSinstruments.get_instrument(i)
|
||||
if(I)
|
||||
allowed_instrument_names += I.name
|
||||
data["allowedInstrumentNames"] = allowed_instrument_names
|
||||
data["instrumentLoaded"] = !isnull(using_instrument)
|
||||
if(using_instrument)
|
||||
data["instrument"] = using_instrument.name
|
||||
data["canNoteShift"] = can_noteshift
|
||||
if(can_noteshift)
|
||||
data["noteShift"] = note_shift
|
||||
data["noteShiftMin"] = note_shift_min
|
||||
data["noteShiftMax"] = note_shift_max
|
||||
data["sustainMode"] = sustain_mode
|
||||
switch(sustain_mode)
|
||||
if(SUSTAIN_LINEAR)
|
||||
data["sustainLinearDuration"] = sustain_linear_duration
|
||||
if(SUSTAIN_EXPONENTIAL)
|
||||
data["sustainExponentialDropoff"] = sustain_exponential_dropoff
|
||||
data["ready"] = using_instrument?.is_ready()
|
||||
data["legacy"] = legacy
|
||||
data["volume"] = volume
|
||||
data["minVolume"] = min_volume
|
||||
data["maxVolume"] = max_volume
|
||||
data["sustainDropoffVolume"] = sustain_dropoff_volume
|
||||
data["sustainHeldNote"] = full_sustain_held_note
|
||||
|
||||
return data
|
||||
|
||||
/datum/song/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, parent, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, parent, ui_key, "Instrument", parent?.name || "Instrument", 700, 500)
|
||||
ui.open()
|
||||
ui.set_autoupdate(FALSE) // NO!!! Don't auto-update this!!
|
||||
|
||||
/datum/song/tgui_act(action, params)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("newsong")
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
if("import")
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(parent, usr))
|
||||
return
|
||||
|
||||
if(length_char(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(length_char(t) > MUSIC_MAXLINES * MUSIC_MAXLINECHARS)
|
||||
parse_song(t)
|
||||
return FALSE
|
||||
if("help")
|
||||
help = !help
|
||||
if("edit")
|
||||
editing = !editing
|
||||
if("repeat") //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat = clamp(round(text2num(params["new"])), 0, max_repeats)
|
||||
if("tempo")
|
||||
tempo = sanitize_tempo(text2num(params["new"]))
|
||||
if("play")
|
||||
INVOKE_ASYNC(src, .proc/start_playing, usr)
|
||||
if("newline")
|
||||
var/newline = html_encode(input("Enter your line: ", parent.name) as text|null)
|
||||
if(!newline || !in_range(parent, usr))
|
||||
return
|
||||
if(length(lines) > MUSIC_MAXLINES)
|
||||
return
|
||||
if(length(newline) > MUSIC_MAXLINECHARS)
|
||||
newline = copytext(newline, 1, MUSIC_MAXLINECHARS)
|
||||
lines.Add(newline)
|
||||
if("deleteline")
|
||||
var/num = round(text2num(params["line"]))
|
||||
if(num > length(lines) || num < 1)
|
||||
return
|
||||
lines.Cut(num, num + 1)
|
||||
if("modifyline")
|
||||
var/num = round(text2num(params["line"]))
|
||||
var/content = stripped_input(usr, "Enter your line: ", parent.name, lines[num], MUSIC_MAXLINECHARS)
|
||||
if(!content || !in_range(parent, usr))
|
||||
return
|
||||
if(num > length(lines) || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
if("stop")
|
||||
stop_playing()
|
||||
if("setlinearfalloff")
|
||||
set_linear_falloff_duration(round(text2num(params["new"]) * 10, world.tick_lag), TRUE)
|
||||
if("setexpfalloff")
|
||||
set_exponential_drop_rate(round(text2num(params["new"]), 0.00001), TRUE)
|
||||
if("setvolume")
|
||||
set_volume(round(text2num(params["new"]), 1))
|
||||
if("setdropoffvolume")
|
||||
set_dropoff_volume(round(text2num(params["new"]), 0.01), TRUE)
|
||||
if("switchinstrument")
|
||||
if(!length(allowed_instrument_ids))
|
||||
return
|
||||
else if(length(allowed_instrument_ids) == 1)
|
||||
set_instrument(allowed_instrument_ids[1])
|
||||
return
|
||||
var/choice = params["name"]
|
||||
for(var/i in allowed_instrument_ids)
|
||||
var/datum/instrument/I = SSinstruments.get_instrument(i)
|
||||
if(I && I.name == choice)
|
||||
set_instrument(I)
|
||||
if("setnoteshift")
|
||||
note_shift = clamp(round(text2num(params["new"])), note_shift_min, note_shift_max)
|
||||
if("setsustainmode")
|
||||
var/static/list/sustain_modes
|
||||
if(!length(sustain_modes))
|
||||
sustain_modes = list("Linear" = SUSTAIN_LINEAR, "Exponential" = SUSTAIN_EXPONENTIAL)
|
||||
var/choice = params["new"]
|
||||
sustain_mode = sustain_modes[choice] || sustain_mode
|
||||
if("togglesustainhold")
|
||||
full_sustain_held_note = !full_sustain_held_note
|
||||
if("reset")
|
||||
var/default_instrument = allowed_instrument_ids[1]
|
||||
if(using_instrument != SSinstruments.instrument_data[default_instrument])
|
||||
set_instrument(default_instrument)
|
||||
note_shift = initial(note_shift)
|
||||
sustain_mode = initial(sustain_mode)
|
||||
set_linear_falloff_duration(initial(sustain_linear_duration), TRUE)
|
||||
set_exponential_drop_rate(initial(sustain_exponential_dropoff), TRUE)
|
||||
set_dropoff_volume(initial(sustain_dropoff_volume), TRUE)
|
||||
else
|
||||
return FALSE
|
||||
parent.add_fingerprint(usr)
|
||||
|
||||
/**
|
||||
* Parses a song the user has input into lines and stores them.
|
||||
*/
|
||||
/datum/song/proc/parse_song(text)
|
||||
set waitfor = FALSE
|
||||
//split into lines
|
||||
stop_playing()
|
||||
lines = splittext(text, "\n")
|
||||
if(length(lines))
|
||||
var/bpm_string = "BPM: "
|
||||
if(findtext(lines[1], bpm_string, 1, length(bpm_string) + 1))
|
||||
var/divisor = text2num(copytext(lines[1], length(bpm_string) + 1)) || 120 // default
|
||||
tempo = sanitize_tempo(600 / round(divisor, 1))
|
||||
lines.Cut(1, 2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(length(lines) > MUSIC_MAXLINES)
|
||||
to_chat(usr, "Too many lines!")
|
||||
lines.Cut(MUSIC_MAXLINES + 1)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(length_char(l) > MUSIC_MAXLINECHARS)
|
||||
to_chat(usr, "Line [linenum] too long!")
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
SStgui.update_uis(parent)
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Compiles our lines into "chords" with filenames for legacy playback. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag.
|
||||
*/
|
||||
/datum/song/proc/compile_legacy()
|
||||
if(!length(src.lines))
|
||||
return
|
||||
var/list/lines = src.lines //cache for hyepr speed!
|
||||
compiled_chords = list()
|
||||
var/list/octaves = list(3, 3, 3, 3, 3, 3, 3)
|
||||
var/list/accents = list("n", "n", "n", "n", "n", "n", "n")
|
||||
for(var/line in lines)
|
||||
var/list/chords = splittext(lowertext(line), ",")
|
||||
for(var/chord in chords)
|
||||
var/list/compiled_chord = list()
|
||||
var/tempodiv = 1
|
||||
var/list/notes_tempodiv = splittext(chord, "/")
|
||||
var/len = length(notes_tempodiv)
|
||||
if(len >= 2)
|
||||
tempodiv = text2num(notes_tempodiv[2])
|
||||
if(len) //some dunkass is going to do ,,,, to make 3 rests instead of ,/1 because there's no standardization so let's be prepared for that.
|
||||
var/list/notes = splittext(notes_tempodiv[1], "-")
|
||||
for(var/note in notes)
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
// 1-7, A-G
|
||||
var/key = text2ascii(note) - 96
|
||||
if((key < 1) || (key > 7))
|
||||
continue
|
||||
for(var/i in 2 to length(note))
|
||||
var/oct_acc = copytext(note, i, i + 1)
|
||||
var/num = text2num(oct_acc)
|
||||
if(!num) //it's an accidental
|
||||
accents[key] = oct_acc //if they misspelled it/fucked up that's on them lmao, no safety checks.
|
||||
else //octave
|
||||
octaves[key] = clamp(num, octave_min, octave_max)
|
||||
compiled_chord[++compiled_chord.len] = list(key, accents[key], octaves[key])
|
||||
compiled_chord += tempodiv //this goes last
|
||||
if(length(compiled_chord))
|
||||
compiled_chords[++compiled_chords.len] = compiled_chord
|
||||
|
||||
/**
|
||||
* Proc to play a legacy note. Just plays the sound to hearing mobs (and does hearcheck if necessary), no fancy channel/sustain/management.
|
||||
*
|
||||
* Arguments:
|
||||
* * note - number from 1-7 for A-G
|
||||
* * acc - either "b", "n", or "#"
|
||||
* * oct - 1-8 (or 9 for C)
|
||||
*/
|
||||
/datum/song/proc/playkey_legacy(note, acc as text, oct, mob/user)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/filename = "sound/instruments/[cached_legacy_dir]/[ascii2text(note + 64)][acc][oct].[cached_legacy_ext]"
|
||||
var/soundfile = file(filename)
|
||||
// make sure the note exists
|
||||
var/cached_fexists = valid_files[filename]
|
||||
if(!isnull(cached_fexists))
|
||||
if(!cached_fexists)
|
||||
return
|
||||
else if(!fexists(soundfile))
|
||||
valid_files[filename] = FALSE
|
||||
return
|
||||
else
|
||||
valid_files[filename] = TRUE
|
||||
// and play
|
||||
var/turf/source = get_turf(parent)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
do_hearcheck()
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
if(!(M.client?.prefs?.sound & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
M.playsound_local(source, null, volume * using_instrument.volume_multiplier, falloff = 5, S = music_played)
|
||||
// Could do environment and echo later but not for now
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Compiles our lines into "chords" with numbers. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag.
|
||||
*/
|
||||
/datum/song/proc/compile_synthesized()
|
||||
if(!length(src.lines))
|
||||
return
|
||||
var/list/lines = src.lines //cache for hyepr speed!
|
||||
compiled_chords = list()
|
||||
var/list/octaves = list(3, 3, 3, 3, 3, 3, 3)
|
||||
var/list/accents = list("n", "n", "n", "n", "n", "n", "n")
|
||||
for(var/line in lines)
|
||||
var/list/chords = splittext(lowertext(line), ",")
|
||||
for(var/chord in chords)
|
||||
var/list/compiled_chord = list()
|
||||
var/tempodiv = 1
|
||||
var/list/notes_tempodiv = splittext(chord, "/")
|
||||
var/len = length(notes_tempodiv)
|
||||
if(len >= 2)
|
||||
tempodiv = text2num(notes_tempodiv[2])
|
||||
if(len) //some dunkass is going to do ,,,, to make 3 rests instead of ,/1 because there's no standardization so let's be prepared for that.
|
||||
var/list/notes = splittext(notes_tempodiv[1], "-")
|
||||
for(var/note in notes)
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
// 1-7, A-G
|
||||
var/key = text2ascii(note) - 96
|
||||
if((key < 1) || (key > 7))
|
||||
continue
|
||||
for(var/i in 2 to length(note))
|
||||
var/oct_acc = copytext(note, i, i + 1)
|
||||
var/num = text2num(oct_acc)
|
||||
if(!num) //it's an accidental
|
||||
accents[key] = oct_acc //if they misspelled it/fucked up that's on them lmao, no safety checks.
|
||||
else //octave
|
||||
octaves[key] = clamp(num, octave_min, octave_max)
|
||||
compiled_chord += clamp((note_offset_lookup[key] + octaves[key] * 12 + accent_lookup[accents[key]]), key_min, key_max)
|
||||
compiled_chord += tempodiv //this goes last
|
||||
if(length(compiled_chord))
|
||||
compiled_chords[++compiled_chords.len] = compiled_chord
|
||||
|
||||
/**
|
||||
* Plays a specific numerical key from our instrument to anyone who can hear us.
|
||||
* Does a hearing check if enough time has passed.
|
||||
*/
|
||||
/datum/song/proc/playkey_synth(key, mob/user)
|
||||
if(can_noteshift)
|
||||
key = clamp(key + note_shift, key_min, key_max)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
do_hearcheck()
|
||||
var/datum/instrument_key/K = using_instrument.samples[num2text(key)] //See how fucking easy it is to make a number text? You don't need a complicated 9 line proc!
|
||||
//Should probably add channel limiters here at some point but I don't care right now.
|
||||
var/channel = pop_channel()
|
||||
if(isnull(channel))
|
||||
return FALSE
|
||||
. = TRUE
|
||||
var/sound/copy = sound(K.sample)
|
||||
var/volume = src.volume * using_instrument.volume_multiplier
|
||||
copy.frequency = K.frequency
|
||||
copy.volume = volume
|
||||
var/channel_text = num2text(channel)
|
||||
channels_playing[channel_text] = 100
|
||||
last_channel_played = channel_text
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
if(!(M.client?.prefs?.sound & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
M.playsound_local(get_turf(parent), null, volume, FALSE, K.frequency, INSTRUMENT_DISTANCE_NO_FALLOFF, channel, null, copy, distance_multiplier = INSTRUMENT_DISTANCE_FALLOFF_BUFF)
|
||||
// Could do environment and echo later but not for now
|
||||
|
||||
/**
|
||||
* Stops all sounds we are "responsible" for. Only works in synthesized mode.
|
||||
*/
|
||||
/datum/song/proc/terminate_all_sounds(clear_channels = TRUE)
|
||||
for(var/i in hearing_mobs)
|
||||
terminate_sound_mob(i)
|
||||
if(clear_channels && channels_playing)
|
||||
channels_playing.len = 0
|
||||
channels_idle.len = 0
|
||||
SSinstruments.current_instrument_channels -= using_sound_channels
|
||||
using_sound_channels = 0
|
||||
SSsounds.free_datum_channels(src)
|
||||
|
||||
/**
|
||||
* Stops all sounds we are responsible for in a given person. Only works in synthesized mode.
|
||||
*/
|
||||
/datum/song/proc/terminate_sound_mob(mob/M)
|
||||
for(var/channel in channels_playing)
|
||||
M.stop_sound_channel(text2num(channel))
|
||||
|
||||
/**
|
||||
* Pops a channel we have reserved so we don't have to release and re-request them from SSsounds every time we play a note. This is faster.
|
||||
*/
|
||||
/datum/song/proc/pop_channel()
|
||||
if(length(channels_idle)) //just pop one off of here if we have one available
|
||||
. = text2num(channels_idle[1])
|
||||
channels_idle.Cut(1, 2)
|
||||
return
|
||||
if(using_sound_channels >= max_sound_channels)
|
||||
return
|
||||
. = SSinstruments.reserve_instrument_channel(src)
|
||||
if(!isnull(.))
|
||||
using_sound_channels++
|
||||
|
||||
/**
|
||||
* Decays our channels and updates their volumes to mobs who can hear us.
|
||||
*
|
||||
* Arguments:
|
||||
* * wait_ds - the deciseconds we should decay by. This is to compensate for any lag, as otherwise songs would get pretty nasty during high time dilation.
|
||||
*/
|
||||
/datum/song/proc/process_decay(wait_ds)
|
||||
var/linear_dropoff = cached_linear_dropoff * wait_ds
|
||||
var/exponential_dropoff = cached_exponential_dropoff ** wait_ds
|
||||
for(var/channel in channels_playing)
|
||||
if(full_sustain_held_note && (channel == last_channel_played))
|
||||
continue
|
||||
var/current_volume = channels_playing[channel]
|
||||
switch(sustain_mode)
|
||||
if(SUSTAIN_LINEAR)
|
||||
current_volume -= linear_dropoff
|
||||
if(SUSTAIN_EXPONENTIAL)
|
||||
current_volume /= exponential_dropoff
|
||||
channels_playing[channel] = current_volume
|
||||
var/dead = current_volume <= sustain_dropoff_volume
|
||||
var/channelnumber = text2num(channel)
|
||||
if(dead)
|
||||
channels_playing -= channel
|
||||
channels_idle += channel
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
M.stop_sound_channel(channelnumber)
|
||||
else
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
M.set_sound_channel_volume(channelnumber, (current_volume * 0.01) * volume * using_instrument.volume_multiplier)
|
||||
@@ -0,0 +1,19 @@
|
||||
/datum/instrument/tones
|
||||
name = "Ideal tone"
|
||||
category = "Tones"
|
||||
abstract_type = /datum/instrument/tones
|
||||
|
||||
/datum/instrument/tones/square_wave
|
||||
name = "Ideal square wave"
|
||||
id = "square"
|
||||
real_samples = list("81"='sound/instruments/synthesis_samples/tones/Square.ogg')
|
||||
|
||||
/datum/instrument/tones/sine_wave
|
||||
name = "Ideal sine wave"
|
||||
id = "sine"
|
||||
real_samples = list("81"='sound/instruments/synthesis_samples/tones/Sine.ogg')
|
||||
|
||||
/datum/instrument/tones/saw_wave
|
||||
name = "Ideal sawtooth wave"
|
||||
id = "saw"
|
||||
real_samples = list("81"='sound/instruments/synthesis_samples/tones/Sawtooth.ogg')
|
||||
@@ -74,7 +74,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
var/viewalerts = 0
|
||||
var/modtype = "Default"
|
||||
var/lower_mod = 0
|
||||
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
|
||||
var/datum/effect_system/spark_spread/spark_system //So they can initialize sparks whenever/N
|
||||
var/jeton = 0
|
||||
var/low_power_mode = 0 //whether the robot has no charge left.
|
||||
var/weapon_lock = 0
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/purple/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.) // if mob is NOT dead
|
||||
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(!degenerate && spider_myqueen)
|
||||
if(dcheck_counter >= 10)
|
||||
dcheck_counter = 0
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(.) // if mob is NOT dead
|
||||
if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons.
|
||||
if(world.time > (spider_lastspawn + spider_spawnfrequency))
|
||||
if(eggslaid >= 20)
|
||||
|
||||
@@ -298,7 +298,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list)
|
||||
|
||||
/mob/living/simple_animal/hostile/poison/terror_spider/Life(seconds, times_fired)
|
||||
. = ..()
|
||||
if(!.) // if mob is dead
|
||||
if(stat == DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive.
|
||||
if(prob(2))
|
||||
// 2% chance every cycle to decompose
|
||||
visible_message("<span class='notice'>\The dead body of the [src] decomposes!</span>")
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
|
||||
#define APC_UPDATE_ICON_COOLDOWN 200 // 20 seconds
|
||||
|
||||
// main_status var
|
||||
#define APC_EXTERNAL_POWER_NOTCONNECTED 0
|
||||
#define APC_EXTERNAL_POWER_NOENERGY 1
|
||||
#define APC_EXTERNAL_POWER_GOOD 2
|
||||
|
||||
// APC malf status
|
||||
#define APC_MALF_NOT_HACKED 1
|
||||
#define APC_MALF_HACKED 2 // APC hacked by user, and user is in its core.
|
||||
@@ -75,7 +80,7 @@
|
||||
var/lastused_equip = 0
|
||||
var/lastused_environ = 0
|
||||
var/lastused_total = 0
|
||||
var/main_status = 0
|
||||
var/main_status = APC_EXTERNAL_POWER_NOTCONNECTED
|
||||
powernet = 0 // set so that APCs aren't found as powernet nodes //Hackish, Horrible, was like this before I changed it :(
|
||||
var/malfhack = 0 //New var for my changes to AI malf. --NeoFite
|
||||
var/mob/living/silicon/ai/malfai = null //See above --NeoFite
|
||||
@@ -213,7 +218,7 @@
|
||||
if(isarea(A))
|
||||
area = A
|
||||
// no-op, keep the name
|
||||
else if(isarea(A) && src.areastring == null)
|
||||
else if(isarea(A) && !areastring)
|
||||
area = A
|
||||
name = "\improper [area.name] APC"
|
||||
else
|
||||
@@ -429,8 +434,8 @@
|
||||
//attack with an item - open/close cover, insert cell, or (un)lock interface
|
||||
/obj/machinery/power/apc/attackby(obj/item/W, mob/living/user, params)
|
||||
|
||||
if(issilicon(user) && get_dist(src,user)>1)
|
||||
return src.attack_hand(user)
|
||||
if(issilicon(user) && get_dist(src, user) > 1)
|
||||
return attack_hand(user)
|
||||
|
||||
else if (istype(W, /obj/item/stock_parts/cell) && opened) // trying to put a cell inside
|
||||
if(cell)
|
||||
@@ -445,7 +450,7 @@
|
||||
W.forceMove(src)
|
||||
cell = W
|
||||
user.visible_message(\
|
||||
"[user.name] has inserted the power cell to [src.name]!",\
|
||||
"[user.name] has inserted the power cell to [name]!",\
|
||||
"<span class='notice'>You insert the power cell.</span>")
|
||||
chargecount = 0
|
||||
update_icon()
|
||||
@@ -474,7 +479,7 @@
|
||||
return
|
||||
user.visible_message("[user.name] adds cables to the APC frame.", \
|
||||
"<span class='notice'>You start adding cables to the APC frame...</span>")
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
if(do_after(user, 20, target = src))
|
||||
if(C.get_amount() < 10 || !C)
|
||||
return
|
||||
@@ -499,10 +504,10 @@
|
||||
|
||||
user.visible_message("[user.name] inserts the power control board into [src].", \
|
||||
"<span class='notice'>You start to insert the power control board into the frame...</span>")
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
if(do_after(user, 10, target = src))
|
||||
if(has_electronics==0)
|
||||
has_electronics = 1
|
||||
if(!has_electronics)
|
||||
has_electronics = TRUE
|
||||
locked = FALSE
|
||||
to_chat(user, "<span class='notice'>You place the power control board inside the frame.</span>")
|
||||
qdel(W)
|
||||
@@ -549,11 +554,11 @@
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You are trying to remove the power control board...</span>" )
|
||||
if(I.use_tool(src, user, 50, volume = I.tool_volume))
|
||||
if(has_electronics==1)
|
||||
has_electronics = 0
|
||||
if(has_electronics)
|
||||
has_electronics = FALSE
|
||||
if(stat & BROKEN)
|
||||
user.visible_message(\
|
||||
"[user.name] has broken the power control board inside [src.name]!",
|
||||
"[user.name] has broken the power control board inside [name]!",
|
||||
"<span class='notice'>You break the charred power control board and remove the remains.</span>",
|
||||
"<span class='italics'>You hear a crack.</span>")
|
||||
return
|
||||
@@ -561,19 +566,19 @@
|
||||
else if(emagged) // We emag board, not APC's frame
|
||||
emagged = FALSE
|
||||
user.visible_message(
|
||||
"[user.name] has discarded emaged power control board from [src.name]!",
|
||||
"<span class='notice'>You discarded shorten board.</span>")
|
||||
"[user.name] has discarded the shorted power control board from [name]!",
|
||||
"<span class='notice'>You discarded the shorted board.</span>")
|
||||
return
|
||||
else if(malfhack) // AI hacks board, not APC's frame
|
||||
user.visible_message(\
|
||||
"[user.name] has discarded strangely programmed power control board from [src.name]!",
|
||||
"<span class='notice'>You discarded strangely programmed board.</span>")
|
||||
"[user.name] has discarded strangely the programmed power control board from [name]!",
|
||||
"<span class='notice'>You discarded the strangely programmed board.</span>")
|
||||
malfai = null
|
||||
malfhack = 0
|
||||
return
|
||||
else
|
||||
user.visible_message(\
|
||||
"[user.name] has removed the power control board from [src.name]!",
|
||||
"[user.name] has removed the power control board from [name]!",
|
||||
"<span class='notice'>You remove the power control board.</span>")
|
||||
new /obj/item/apc_electronics(loc)
|
||||
return
|
||||
@@ -711,36 +716,29 @@
|
||||
|
||||
// attack with hand - remove cell (if cover open) or interact with the APC
|
||||
/obj/machinery/power/apc/attack_hand(mob/user)
|
||||
// if(!can_use(user)) This already gets called in interact() and in topic()
|
||||
// return
|
||||
if(!user)
|
||||
return
|
||||
src.add_fingerprint(user)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(usr == user && opened && (!issilicon(user)))
|
||||
if(usr == user && opened && !issilicon(user))
|
||||
if(cell)
|
||||
if(issilicon(user))
|
||||
cell.loc=src.loc // Drop it, whoops.
|
||||
else
|
||||
user.put_in_hands(cell)
|
||||
user.put_in_hands(cell)
|
||||
cell.add_fingerprint(user)
|
||||
cell.update_icon()
|
||||
|
||||
src.cell = null
|
||||
user.visible_message("<span class='warning'>[user.name] removes the power cell from [src.name]!", "You remove the power cell.</span>")
|
||||
// to_chat(user, "You remove the power cell.")
|
||||
charging = 0
|
||||
src.update_icon()
|
||||
cell = null
|
||||
user.visible_message("<span class='warning'>[user.name] removes [cell] from [src]!", "You remove the [cell].</span>")
|
||||
charging = FALSE
|
||||
update_icon()
|
||||
return
|
||||
if(stat & (BROKEN|MAINT))
|
||||
return
|
||||
|
||||
src.interact(user)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/apc/attack_ghost(mob/user)
|
||||
if(panel_open)
|
||||
wires.Interact(user)
|
||||
return ui_interact(user)
|
||||
return tgui_interact(user)
|
||||
|
||||
/obj/machinery/power/apc/interact(mob/user)
|
||||
if(!user)
|
||||
@@ -749,7 +747,7 @@
|
||||
if(panel_open)
|
||||
wires.Interact(user)
|
||||
|
||||
return ui_interact(user)
|
||||
return tgui_interact(user)
|
||||
|
||||
|
||||
/obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf)
|
||||
@@ -770,22 +768,16 @@
|
||||
else
|
||||
return APC_MALF_NOT_HACKED
|
||||
|
||||
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/power/apc/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new one
|
||||
ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, issilicon(user) ? 535 : 460)
|
||||
ui = new(user, src, ui_key, "APC", name, 510, 460, master_ui, state)
|
||||
ui.open()
|
||||
// Auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/power/apc/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
var/data[0]
|
||||
/obj/machinery/power/apc/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["locked"] = is_locked(user)
|
||||
data["normallyLocked"] = locked
|
||||
data["isOperating"] = operating
|
||||
data["externalPower"] = main_status
|
||||
data["powerCellStatus"] = cell ? cell.percent() : null
|
||||
@@ -862,7 +854,7 @@
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
var/mob/living/silicon/robot/robot = user
|
||||
if( \
|
||||
src.aidisabled || \
|
||||
aidisabled || \
|
||||
malfhack && istype(malfai) && \
|
||||
( \
|
||||
(istype(AI) && (malfai!=AI && malfai != AI.parent)) || \
|
||||
@@ -873,21 +865,21 @@
|
||||
to_chat(user, "<span class='danger'>\The [src] has AI control disabled!</span>")
|
||||
user << browse(null, "window=apc")
|
||||
user.unset_machine()
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
if((!in_range(src, user) || !istype(src.loc, /turf)))
|
||||
return 0
|
||||
if((!in_range(src, user) || !istype(loc, /turf)))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H))
|
||||
if(H.getBrainLoss() >= 60)
|
||||
for(var/mob/M in viewers(src, null))
|
||||
to_chat(M, "<span class='danger'>[H] stares cluelessly at [src] and drools.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
else if(prob(H.getBrainLoss()))
|
||||
to_chat(user, "<span class='danger'>You momentarily forget how to use [src].</span>")
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/power/apc/proc/is_authenticated(mob/user as mob)
|
||||
if(user.can_admin_interact())
|
||||
@@ -905,104 +897,59 @@
|
||||
else
|
||||
return locked
|
||||
|
||||
/obj/machinery/power/apc/Topic(href, href_list, var/usingUI = 1)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(!can_use(usr, 1))
|
||||
return 1
|
||||
|
||||
if(href_list["lock"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
coverlocked = !coverlocked
|
||||
|
||||
else if(href_list["breaker"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
toggle_breaker()
|
||||
|
||||
else if(href_list["toggle_nightshift"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
if(last_nightshift_switch > world.time + 100) // don't spam...
|
||||
to_chat(usr, "<span class='warning'>[src]'s night lighting circuit breaker is still cycling!</span>")
|
||||
return
|
||||
last_nightshift_switch = world.time
|
||||
set_nightshift(!nightshift_lights)
|
||||
|
||||
else if(href_list["cmode"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
chargemode = !chargemode
|
||||
if(!chargemode)
|
||||
charging = 0
|
||||
update_icon()
|
||||
|
||||
else if(href_list["eqp"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
var/val = text2num(href_list["eqp"])
|
||||
equipment = setsubsystem(val)
|
||||
update_icon()
|
||||
update()
|
||||
|
||||
else if(href_list["lgt"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
var/val = text2num(href_list["lgt"])
|
||||
lighting = setsubsystem(val)
|
||||
update_icon()
|
||||
update()
|
||||
|
||||
else if(href_list["env"])
|
||||
if(!is_authenticated(usr))
|
||||
return
|
||||
|
||||
var/val = text2num(href_list["env"])
|
||||
environ = setsubsystem(val)
|
||||
update_icon()
|
||||
update()
|
||||
else if( href_list["close"] )
|
||||
SSnanoui.close_user_uis(usr, src)
|
||||
|
||||
return 0
|
||||
else if(href_list["close2"])
|
||||
usr << browse(null, "window=apcwires")
|
||||
|
||||
return 0
|
||||
|
||||
else if(href_list["overload"])
|
||||
if(issilicon(usr) && !aidisabled)
|
||||
overload_lighting()
|
||||
|
||||
else if(href_list["malfhack"])
|
||||
if(get_malf_status(usr))
|
||||
malfhack(usr)
|
||||
|
||||
else if(href_list["occupyapc"])
|
||||
if(get_malf_status(usr))
|
||||
malfoccupy(usr)
|
||||
|
||||
else if(href_list["deoccupyapc"])
|
||||
if(get_malf_status(usr))
|
||||
malfvacate()
|
||||
|
||||
else if(href_list["toggleaccess"])
|
||||
if(istype(usr, /mob/living/silicon))
|
||||
if(emagged || aidisabled || (stat & (BROKEN|MAINT)))
|
||||
to_chat(usr, "The APC does not respond to the command.")
|
||||
/obj/machinery/power/apc/tgui_act(action, params)
|
||||
if(..() || !can_use(usr, TRUE) || (locked && !usr.has_unlimited_silicon_privilege && (action != "toggle_nightshift") && !usr.can_admin_interact()))
|
||||
return
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("lock")
|
||||
if(usr.has_unlimited_silicon_privilege)
|
||||
if(emagged || stat & BROKEN)
|
||||
to_chat(usr, "<span class='warning'>The APC does not respond to the command!</span>")
|
||||
return FALSE
|
||||
else
|
||||
locked = !locked
|
||||
update_icon()
|
||||
else
|
||||
locked = !locked
|
||||
to_chat(usr, "<span class='warning'>Access Denied!</span>")
|
||||
return FALSE
|
||||
if("cover")
|
||||
coverlocked = !coverlocked
|
||||
if("breaker")
|
||||
toggle_breaker(usr)
|
||||
if("toggle_nightshift")
|
||||
if(last_nightshift_switch > world.time + 100) // don't spam...
|
||||
to_chat(usr, "<span class='warning'>[src]'s night lighting circuit breaker is still cycling!</span>")
|
||||
return FALSE
|
||||
last_nightshift_switch = world.time
|
||||
set_nightshift(!nightshift_lights)
|
||||
if("charge")
|
||||
chargemode = !chargemode
|
||||
if("channel")
|
||||
if(params["eqp"])
|
||||
equipment = setsubsystem(text2num(params["eqp"]))
|
||||
update_icon()
|
||||
|
||||
return 0
|
||||
update()
|
||||
else if(params["lgt"])
|
||||
lighting = setsubsystem(text2num(params["lgt"]))
|
||||
update_icon()
|
||||
update()
|
||||
else if(params["env"])
|
||||
environ = setsubsystem(text2num(params["env"]))
|
||||
update_icon()
|
||||
update()
|
||||
if("overload")
|
||||
if(usr.has_unlimited_silicon_privilege)
|
||||
overload_lighting()
|
||||
if("hack")
|
||||
if(get_malf_status(usr))
|
||||
malfhack(usr)
|
||||
if("occupy")
|
||||
if(get_malf_status(usr))
|
||||
malfoccupy(usr)
|
||||
if("deoccupy")
|
||||
if(get_malf_status(usr))
|
||||
malfvacate()
|
||||
|
||||
/obj/machinery/power/apc/proc/toggle_breaker()
|
||||
operating = !operating
|
||||
@@ -1033,7 +980,7 @@
|
||||
if(!malf.can_shunt)
|
||||
to_chat(malf, "<span class='warning'>You cannot shunt!</span>")
|
||||
return
|
||||
if(!is_station_level(src.z))
|
||||
if(!is_station_level(z))
|
||||
return
|
||||
occupier = new /mob/living/silicon/ai(src,malf.laws,null,1)
|
||||
occupier.adjustOxyLoss(malf.getOxyLoss())
|
||||
@@ -1080,21 +1027,21 @@
|
||||
|
||||
/obj/machinery/power/apc/proc/ion_act()
|
||||
//intended to be exactly the same as an AI malf attack
|
||||
if(!src.malfhack && is_station_level(src.z))
|
||||
if(!malfhack && is_station_level(z))
|
||||
if(prob(3))
|
||||
src.locked = 1
|
||||
if(src.cell.charge > 0)
|
||||
src.cell.charge = 0
|
||||
locked = TRUE
|
||||
if(cell.charge > 0)
|
||||
cell.charge = 0
|
||||
cell.corrupt()
|
||||
src.malfhack = 1
|
||||
malfhack = TRUE
|
||||
update_icon()
|
||||
var/datum/effect_system/smoke_spread/smoke = new
|
||||
smoke.set_up(3, 0, src.loc)
|
||||
smoke.set_up(3, 0, loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
do_sparks(3, 1, src)
|
||||
for(var/mob/M in viewers(src))
|
||||
M.show_message("<span class='danger'>The [src.name] suddenly lets out a blast of smoke and some sparks!", 3, "<span class='danger'>You hear sizzling electronics.</span>", 2)
|
||||
M.show_message("<span class='danger'>The [name] suddenly lets out a blast of smoke and some sparks!", 3, "<span class='danger'>You hear sizzling electronics.</span>", 2)
|
||||
|
||||
|
||||
/obj/machinery/power/apc/surplus()
|
||||
@@ -1137,12 +1084,12 @@
|
||||
|
||||
var/excess = surplus()
|
||||
|
||||
if(!src.avail())
|
||||
main_status = 0
|
||||
if(!avail())
|
||||
main_status = APC_EXTERNAL_POWER_NOTCONNECTED
|
||||
else if(excess < 0)
|
||||
main_status = 1
|
||||
main_status = APC_EXTERNAL_POWER_NOENERGY
|
||||
else
|
||||
main_status = 2
|
||||
main_status = APC_EXTERNAL_POWER_GOOD
|
||||
|
||||
if(debug)
|
||||
log_debug("Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]")
|
||||
@@ -1257,7 +1204,7 @@
|
||||
if(shock_mobs.len)
|
||||
var/mob/living/L = pick(shock_mobs)
|
||||
L.electrocute_act(rand(5, 25), "electrical arc")
|
||||
playsound(get_turf(L), 'sound/effects/eleczap.ogg', 75, 1)
|
||||
playsound(get_turf(L), 'sound/effects/eleczap.ogg', 75, TRUE)
|
||||
Beam(L, icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = 5)
|
||||
|
||||
else // no cell, switch everything off
|
||||
@@ -1383,3 +1330,7 @@
|
||||
updateDialog()
|
||||
|
||||
#undef APC_UPDATE_ICON_COOLDOWN
|
||||
|
||||
#undef APC_EXTERNAL_POWER_NOTCONNECTED
|
||||
#undef APC_EXTERNAL_POWER_NOENERGY
|
||||
#undef APC_EXTERNAL_POWER_GOOD
|
||||
|
||||
@@ -310,16 +310,25 @@ field_generator power level display
|
||||
//This is here to help fight the "hurr durr, release singulo cos nobody will notice before the
|
||||
//singulo eats the evidence". It's not fool-proof but better than nothing.
|
||||
//I want to avoid using global variables.
|
||||
spawn(1)
|
||||
var/temp = 1 //stops spam
|
||||
for(var/thing in GLOB.singularities)
|
||||
var/obj/singularity/O = thing
|
||||
if(O.last_warning && temp)
|
||||
if((world.time - O.last_warning) > 50) //to stop message-spam
|
||||
temp = 0
|
||||
message_admins("A singulo exists and a containment field has failed. Location: [get_area(src)] (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</A>)",1)
|
||||
investigate_log("has <font color='red'>failed</font> whilst a singulo exists.","singulo")
|
||||
O.last_warning = world.time
|
||||
INVOKE_ASYNC(src, .proc/admin_alert)
|
||||
|
||||
/obj/machinery/field/generator/proc/admin_alert()
|
||||
var/temp = TRUE //stops spam
|
||||
for(var/thing in GLOB.singularities)
|
||||
var/obj/singularity/O = thing
|
||||
if(O.last_warning && temp && atoms_share_level(O, src))
|
||||
if((world.time - O.last_warning) > 50) //to stop message-spam
|
||||
temp = FALSE
|
||||
// To the person who asks "Hey affected, why are you using this massive operator when you can use AREACOORD?" Well, ill tell you
|
||||
// get_area_name is fucking broken and uses a for(x in world) search
|
||||
// It doesnt even work, is expensive, and returns 0
|
||||
// Im not refactoring one thing which could risk breaking all admin location logs
|
||||
// Fight me
|
||||
// [src ? "[get_location_name(src, TRUE)] [COORD(src)]" : "nonexistent location"] [ADMIN_JMP(src)] works much better and actually works at all
|
||||
// Oh and yes, this exact comment was pasted from the exact same thing I did to tcomms code. Dont at me.
|
||||
message_admins("A singularity exists and a containment field has failed on the same Z-Level. Singulo location: [O ? "[get_location_name(O, TRUE)] [COORD(O)]" : "nonexistent location"] [ADMIN_JMP(O)] | Field generator location: [src ? "[get_location_name(src, TRUE)] [COORD(src)]" : "nonexistent location"] [ADMIN_JMP(src)]")
|
||||
investigate_log("has <font color='red'>failed</font> whilst a singulo exists.","singulo")
|
||||
O.last_warning = world.time
|
||||
|
||||
/obj/machinery/field/generator/shock_field(mob/living/user)
|
||||
if(fields.len)
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
if(keep)
|
||||
stored_ammo.Insert(1,b)
|
||||
update_mat_value()
|
||||
update_icon()
|
||||
return b
|
||||
|
||||
/obj/item/ammo_box/proc/give_round(obj/item/ammo_casing/R, replace_spent = 0)
|
||||
|
||||
@@ -383,10 +383,7 @@
|
||||
origin_tech = "combat=3;syndicate=1"
|
||||
caliber = "shotgun"
|
||||
max_ammo = 8
|
||||
|
||||
/obj/item/ammo_box/magazine/m12g/update_icon()
|
||||
..()
|
||||
icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/8, 1)*8]"
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/m12g/buckshot
|
||||
name = "shotgun magazine (12g buckshot slugs)"
|
||||
@@ -414,6 +411,24 @@
|
||||
icon_state = "m12gbc"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/breaching
|
||||
|
||||
/obj/item/ammo_box/magazine/m12g/XtrLrg
|
||||
name = "\improper XL shotgun magazine (12g slugs)"
|
||||
desc = "An extra large drum magazine."
|
||||
icon_state = "m12gXlSl"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
ammo_type = /obj/item/ammo_casing/shotgun
|
||||
max_ammo = 16
|
||||
|
||||
/obj/item/ammo_box/magazine/m12g/XtrLrg/buckshot
|
||||
name = "\improper XL shotgun magazine (12g buckshot)"
|
||||
icon_state = "m12gXlBs"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
|
||||
|
||||
/obj/item/ammo_box/magazine/m12g/XtrLrg/dragon
|
||||
name = "\improper XL shotgun magazine (12g dragon's breath)"
|
||||
icon_state = "m12gXlDb"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath
|
||||
|
||||
/obj/item/ammo_box/magazine/toy
|
||||
name = "foam force META magazine"
|
||||
ammo_type = /obj/item/ammo_casing/caseless/foam_dart
|
||||
|
||||
@@ -275,13 +275,27 @@
|
||||
if(magazine)
|
||||
overlays.Cut()
|
||||
overlays += "[magazine.icon_state]"
|
||||
return
|
||||
if(istype(magazine, /obj/item/ammo_box/magazine/m12g/XtrLrg))
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
else
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
else
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/gun/projectile/automatic/shotgun/bulldog/update_icon()
|
||||
overlays.Cut()
|
||||
update_magazine()
|
||||
icon_state = "bulldog[chambered ? "" : "-e"]"
|
||||
|
||||
/obj/item/gun/projectile/automatic/shotgun/bulldog/attackby(var/obj/item/A as obj, mob/user as mob, params)
|
||||
if(istype(A, /obj/item/ammo_box/magazine/m12g/XtrLrg))
|
||||
if(istype(loc, /obj/item/storage)) // To prevent inventory exploits
|
||||
var/obj/item/storage/Strg = loc
|
||||
if(Strg.max_w_class < WEIGHT_CLASS_BULKY)
|
||||
to_chat(user, "<span class='warning'>You can't reload [src], with a XL mag, while it's in a normal bag.</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/projectile/automatic/shotgun/bulldog/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
|
||||
..()
|
||||
empty_alarm()
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
var/list/hacked_reagents = list("toxin")
|
||||
var/hack_message = "You disable the safety safeguards, enabling the \"Mad Scientist\" mode."
|
||||
var/unhack_message = "You re-enable the safety safeguards, enabling the \"NT Standard\" mode."
|
||||
var/is_drink = FALSE
|
||||
|
||||
/obj/machinery/chem_dispenser/get_cell()
|
||||
return cell
|
||||
@@ -120,7 +121,6 @@
|
||||
var/usedpower = cell.give(recharge_amount)
|
||||
if(usedpower)
|
||||
use_power(15 * recharge_amount)
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
recharge_counter = 0
|
||||
return
|
||||
recharge_counter++
|
||||
@@ -131,7 +131,6 @@
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
stat |= NOPOWER
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
|
||||
/obj/machinery/chem_dispenser/ex_act(severity)
|
||||
if(severity < 3)
|
||||
@@ -145,19 +144,17 @@
|
||||
beaker = null
|
||||
overlays.Cut()
|
||||
|
||||
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
/obj/machinery/chem_dispenser/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "chem_dispenser.tmpl", ui_title, 390, 655)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "ChemDispenser", ui_title, 390, 655)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_dispenser/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_dispenser/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["glass"] = is_drink
|
||||
data["amount"] = amount
|
||||
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
|
||||
data["maxEnergy"] = cell.maxcharge * powerefficiency
|
||||
@@ -187,63 +184,59 @@
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/chem_dispenser/Topic(href, href_list)
|
||||
/obj/machinery/chem_dispenser/tgui_act(actions, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["amount"])
|
||||
amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
|
||||
if(amount < 0) // Since the user can actually type the commands himself, some sanity checking
|
||||
amount = 0
|
||||
if(amount > 100)
|
||||
amount = 100
|
||||
|
||||
if(href_list["dispense"])
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
if(beaker && dispensable_reagents.Find(href_list["dispense"]))
|
||||
. = TRUE
|
||||
switch(actions)
|
||||
if("amount")
|
||||
amount = clamp(round(text2num(params["amount"]), 1), 0, 50) // round to nearest 1 and clamp to 0 - 50
|
||||
if("dispense")
|
||||
if(!is_operational() || QDELETED(cell))
|
||||
return
|
||||
if(!beaker || !dispensable_reagents.Find(params["reagent"]))
|
||||
return
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/free = R.maximum_volume - R.total_volume
|
||||
var/actual = min(amount, (cell.charge * powerefficiency) * 10, free)
|
||||
|
||||
if(!cell.use(actual / powerefficiency))
|
||||
atom_say("Not enough energy to complete operation!")
|
||||
return
|
||||
|
||||
R.add_reagent(href_list["dispense"], actual)
|
||||
R.add_reagent(params["reagent"], actual)
|
||||
overlays.Cut()
|
||||
if(!icon_beaker)
|
||||
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker.pixel_x = rand(-10, 5)
|
||||
overlays += icon_beaker
|
||||
|
||||
if(href_list["remove"])
|
||||
if(beaker)
|
||||
if(href_list["removeamount"])
|
||||
var/amount = text2num(href_list["removeamount"])
|
||||
if(isnum(amount) && (amount > 0))
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = href_list["remove"]
|
||||
R.remove_reagent(id, amount)
|
||||
else if(isnum(amount) && (amount == -1)) //Isolate instead
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = href_list["remove"]
|
||||
R.isolate_reagent(id)
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(beaker)
|
||||
if("remove")
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!beaker || !amount)
|
||||
return
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/id = params["reagent"]
|
||||
if(amount > 0)
|
||||
R.remove_reagent(id, amount)
|
||||
else if(amount == -1) //Isolate instead
|
||||
R.isolate_reagent(id)
|
||||
if("ejectBeaker")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(loc)
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
overlays.Cut()
|
||||
else
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(usr)
|
||||
return TRUE // update UIs attached to this object
|
||||
|
||||
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
|
||||
if(exchange_parts(user, I))
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(isrobot(user))
|
||||
@@ -263,9 +256,9 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You set [I] on the machine.</span>")
|
||||
SSnanoui.update_uis(src) // update all UIs attached to src
|
||||
SStgui.update_uis(src) // update all UIs attached to src
|
||||
if(!icon_beaker)
|
||||
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker = mutable_appearance('icons/obj/chemical.dmi', "disp_beaker") //randomize beaker overlay position.
|
||||
icon_beaker.pixel_x = rand(-10, 5)
|
||||
overlays += icon_beaker
|
||||
return
|
||||
@@ -299,8 +292,7 @@
|
||||
to_chat(user, unhack_message)
|
||||
dispensable_reagents -= hacked_reagents
|
||||
hackedcheck = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_dispenser/screwdriver_act(mob/user, obj/item/I)
|
||||
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", "[initial(icon_state)]", I))
|
||||
@@ -321,14 +313,14 @@
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/attack_hand(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/soda
|
||||
icon_state = "soda_dispenser"
|
||||
@@ -342,6 +334,7 @@
|
||||
hacked_reagents = list("thirteenloko")
|
||||
hack_message = "You change the mode from 'McNano' to 'Pizza King'."
|
||||
unhack_message = "You change the mode from 'Pizza King' to 'McNano'."
|
||||
is_drink = TRUE
|
||||
|
||||
/obj/machinery/chem_dispenser/soda/New()
|
||||
..()
|
||||
@@ -377,6 +370,7 @@
|
||||
hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
|
||||
hack_message = "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
|
||||
unhack_message = "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
|
||||
is_drink = TRUE
|
||||
|
||||
/obj/machinery/chem_dispenser/beer/New()
|
||||
..()
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/obj/machinery/chem_heater
|
||||
name = "chemical heater"
|
||||
density = 1
|
||||
anchored = 1
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "mixer0b"
|
||||
use_power = IDLE_POWER_USE
|
||||
idle_power_usage = 40
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
resistance_flags = FIRE_PROOF|ACID_PROOF
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
var/desired_temp = T0C
|
||||
var/on = FALSE
|
||||
/// Whether this should auto-eject the beaker once done heating/cooling.
|
||||
var/auto_eject = FALSE
|
||||
/// The higher this number, the faster reagents will heat/cool.
|
||||
var/speed_increase = 0
|
||||
|
||||
/obj/machinery/chem_heater/New()
|
||||
..()
|
||||
@@ -19,35 +23,36 @@
|
||||
component_parts += new /obj/item/stack/sheet/glass(null)
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/chem_heater/RefreshParts()
|
||||
speed_increase = initial(speed_increase)
|
||||
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
|
||||
speed_increase += 5 * (M.rating - 1)
|
||||
|
||||
/obj/machinery/chem_heater/process()
|
||||
..()
|
||||
if(stat & NOPOWER)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/state_change = FALSE
|
||||
if(on)
|
||||
if(beaker)
|
||||
if(!beaker.reagents.total_volume)
|
||||
on = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
return
|
||||
beaker.reagents.temperature_reagents(desired_temp)
|
||||
beaker.reagents.temperature_reagents(desired_temp)
|
||||
if(abs(beaker.reagents.chem_temp - desired_temp) <= 3)
|
||||
beaker.reagents.temperature_reagents(desired_temp, max(1, 35 - speed_increase))
|
||||
if(round(beaker.reagents.chem_temp) == round(desired_temp))
|
||||
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
on = FALSE
|
||||
state_change = TRUE
|
||||
|
||||
if(state_change)
|
||||
SSnanoui.update_uis(src)
|
||||
if(auto_eject)
|
||||
eject_beaker()
|
||||
|
||||
/obj/machinery/chem_heater/proc/eject_beaker(mob/user)
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(user) && !issilicon(user))
|
||||
if(user && Adjacent(user) && !issilicon(user))
|
||||
user.put_in_hands(beaker)
|
||||
beaker = null
|
||||
icon_state = "mixer0b"
|
||||
on = FALSE
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_heater/power_change()
|
||||
if(powered())
|
||||
@@ -55,7 +60,6 @@
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
stat |= NOPOWER
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/machinery/chem_heater/attackby(obj/item/I, mob/user)
|
||||
if(isrobot(user))
|
||||
@@ -71,7 +75,7 @@
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
|
||||
icon_state = "mixer1b"
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
@@ -95,62 +99,62 @@
|
||||
default_deconstruction_crowbar(user, I)
|
||||
|
||||
/obj/machinery/chem_heater/attack_hand(mob/user)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_heater/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_heater/attack_ai(mob/user)
|
||||
add_hiddenprint(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_heater/Topic(href, href_list)
|
||||
/obj/machinery/chem_heater/tgui_act(action, params)
|
||||
if(..())
|
||||
return FALSE
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(href_list["toggle_on"])
|
||||
if(!beaker.reagents.total_volume)
|
||||
return FALSE
|
||||
on = !on
|
||||
. = 1
|
||||
|
||||
if(href_list["adjust_temperature"])
|
||||
var/val = href_list["adjust_temperature"]
|
||||
if(isnum(val))
|
||||
desired_temp = clamp(desired_temp+val, 0, 1000)
|
||||
else if(val == "input")
|
||||
var/target = input("Please input the target temperature", name) as num
|
||||
desired_temp = clamp(target, 0, 1000)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("toggle_on")
|
||||
on = !on
|
||||
if("adjust_temperature")
|
||||
desired_temp = clamp(text2num(params["target"]), 0, 1000)
|
||||
if("eject_beaker")
|
||||
eject_beaker(usr)
|
||||
. = FALSE
|
||||
if("toggle_autoeject")
|
||||
auto_eject = !auto_eject
|
||||
else
|
||||
return FALSE
|
||||
. = 1
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["eject_beaker"])
|
||||
eject_beaker(usr)
|
||||
. = 0 //updated in eject_beaker() already
|
||||
|
||||
/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null)
|
||||
/obj/machinery/chem_heater/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
if(user.stat || user.restrained())
|
||||
return
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "chem_heater.tmpl", "ChemHeater", 350, 270)
|
||||
ui = new(user, src, ui_key, "ChemHeater", "Chemical Heater", 350, 270, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_heater/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
var/cur_temp = beaker ? beaker.reagents.chem_temp : null
|
||||
|
||||
data["targetTemp"] = desired_temp
|
||||
data["targetTempReached"] = FALSE
|
||||
data["autoEject"] = auto_eject
|
||||
data["isActive"] = on
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
|
||||
|
||||
data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
|
||||
data["currentTemp"] = cur_temp
|
||||
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
|
||||
data["beakerMaxVolume"] = beaker ? beaker.volume : null
|
||||
|
||||
if(cur_temp)
|
||||
data["targetTempReached"] = round(cur_temp) == round(desired_temp)
|
||||
|
||||
//copy-pasted from chem dispenser
|
||||
var/beakerContents[0]
|
||||
if(beaker)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
|
||||
#define MAX_MULTI_AMOUNT 20 // Max number of pills/patches that can be made at once
|
||||
#define MAX_UNITS_PER_PILL 100 // Max amount of units in a pill
|
||||
#define MAX_UNITS_PER_PATCH 30 // Max amount of units in a patch
|
||||
#define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever
|
||||
|
||||
/obj/machinery/chem_master
|
||||
name = "\improper ChemMaster 3000"
|
||||
density = TRUE
|
||||
@@ -14,10 +20,12 @@
|
||||
var/useramount = 30 // Last used amount
|
||||
var/pillamount = 10
|
||||
var/patchamount = 10
|
||||
var/bottlesprite = "bottle"
|
||||
var/pillsprite = "1"
|
||||
var/bottlesprite = 1
|
||||
var/pillsprite = 1
|
||||
var/client/has_sprites = list()
|
||||
var/printing = FALSE
|
||||
var/static/list/pill_bottle_wrappers
|
||||
var/static/list/bottle_styles
|
||||
|
||||
/obj/machinery/chem_master/New()
|
||||
..()
|
||||
@@ -94,7 +102,7 @@
|
||||
beaker = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine!</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
update_icon()
|
||||
|
||||
else if(istype(I, /obj/item/storage/pill_bottle))
|
||||
@@ -109,14 +117,10 @@
|
||||
loaded_pill_bottle = I
|
||||
I.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add [I] into the dispenser slot!</span>")
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/machinery/chem_master/crowbar_act(mob/user, obj/item/I)
|
||||
if(!panel_open)
|
||||
return
|
||||
@@ -142,319 +146,127 @@
|
||||
power_change()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/chem_master/Topic(href, href_list)
|
||||
/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(tgui_act_modal(action, params, ui, state))
|
||||
return TRUE
|
||||
|
||||
add_fingerprint(usr)
|
||||
usr.set_machine(src)
|
||||
|
||||
|
||||
if(href_list["ejectp"])
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(loc)
|
||||
loaded_pill_bottle = null
|
||||
else if(href_list["change_pillbottle"])
|
||||
if(loaded_pill_bottle)
|
||||
var/list/wrappers = list("Default wrapper", "Red wrapper", "Green wrapper", "Pale green wrapper", "Blue wrapper", "Light blue wrapper", "Teal wrapper", "Yellow wrapper", "Orange wrapper", "Pink wrapper", "Brown wrapper")
|
||||
var/chosen = input(usr, "Select a pillbottle wrapper", "Pillbottle wrapper", wrappers[1]) as null|anything in wrappers
|
||||
if(!chosen)
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("toggle")
|
||||
mode = !mode
|
||||
if("ejectp")
|
||||
if(loaded_pill_bottle)
|
||||
loaded_pill_bottle.forceMove(loc)
|
||||
loaded_pill_bottle = null
|
||||
if("print")
|
||||
if(printing || condi)
|
||||
return
|
||||
var/color
|
||||
switch(chosen)
|
||||
if("Default wrapper")
|
||||
loaded_pill_bottle.cut_overlays()
|
||||
return
|
||||
if("Red wrapper")
|
||||
color = COLOR_RED
|
||||
if("Green wrapper")
|
||||
color = COLOR_GREEN
|
||||
if("Pink wrapper")
|
||||
color = COLOR_PINK
|
||||
if("Teal wrapper")
|
||||
color = COLOR_TEAL
|
||||
if("Blue wrapper")
|
||||
color = COLOR_BLUE
|
||||
if("Brown wrapper")
|
||||
color = COLOR_MAROON
|
||||
if("Light blue wrapper")
|
||||
color = COLOR_CYAN_BLUE
|
||||
if("Yellow wrapper")
|
||||
color = COLOR_YELLOW
|
||||
if("Pale green wrapper")
|
||||
color = COLOR_PALE_BTL_GREEN
|
||||
if("Orange wrapper")
|
||||
color = COLOR_ORANGE
|
||||
loaded_pill_bottle.wrapper_color = color
|
||||
loaded_pill_bottle.apply_wrap()
|
||||
else if(href_list["close"])
|
||||
usr << browse(null, "window=chem_master")
|
||||
onclose(usr, "chem_master")
|
||||
usr.unset_machine()
|
||||
return
|
||||
|
||||
if(href_list["print_p"])
|
||||
if(!printing)
|
||||
var/idx = text2num(params["idx"]) || 0
|
||||
var/from_beaker = text2num(params["beaker"]) || FALSE
|
||||
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
|
||||
if(idx < 1 || idx > length(reagent_list))
|
||||
return
|
||||
|
||||
var/datum/reagent/R = reagent_list[idx]
|
||||
|
||||
printing = TRUE
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
P.info = "<CENTER><B>Chemical Analysis</B></CENTER><BR>"
|
||||
P.info = "<center><b>Chemical Analysis</b></center><br>"
|
||||
P.info += "<b>Time of analysis:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "<b>Chemical name:</b> [href_list["name"]]<br>"
|
||||
if(href_list["name"] == "Blood")
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/datum/reagent/blood/G
|
||||
for(var/datum/reagent/F in R.reagent_list)
|
||||
if(F.name == href_list["name"])
|
||||
G = F
|
||||
break
|
||||
var/B = G.data["blood_type"]
|
||||
var/C = G.data["blood_DNA"]
|
||||
P.info += "<b>Description:</b><br>Blood Type: [B]<br>DNA: [C]"
|
||||
P.info += "<b>Chemical name:</b> [R.name]<br>"
|
||||
if(istype(R, /datum/reagent/blood))
|
||||
var/datum/reagent/blood/B = R
|
||||
P.info += "<b>Description:</b> N/A<br><b>Blood Type:</b> [B.data["blood_type"]]<br><b>DNA:</b> [B.data["blood_DNA"]]"
|
||||
else
|
||||
P.info += "<b>Description:</b> [href_list["desc"]]"
|
||||
P.info += "<b>Description:</b> [R.description]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Chemical Analysis - [href_list["name"]]"
|
||||
printing = FALSE
|
||||
P.name = "Chemical Analysis - [R.name]"
|
||||
spawn(50)
|
||||
printing = FALSE
|
||||
else
|
||||
. = FALSE
|
||||
|
||||
if(beaker)
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
if(href_list["analyze"])
|
||||
var/dat = ""
|
||||
if(!condi)
|
||||
if(href_list["name"] == "Blood")
|
||||
var/datum/reagent/blood/G
|
||||
for(var/datum/reagent/F in R.reagent_list)
|
||||
if(F.name == href_list["name"])
|
||||
G = F
|
||||
break
|
||||
var/A = G.name
|
||||
var/B = G.data["blood_type"]
|
||||
var/C = G.data["blood_DNA"]
|
||||
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[A]<BR><BR>Description:<BR>Blood Type: [B]<br>DNA: [C]"
|
||||
else
|
||||
dat += "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]"
|
||||
dat += "<BR><BR><A href='?src=[UID()];print_p=1;desc=[href_list["desc"]];name=[href_list["name"]]'>(Print Analysis)</A><BR>"
|
||||
dat += "<A href='?src=[UID()];main=1'>(Back)</A>"
|
||||
if(. || !beaker)
|
||||
return
|
||||
|
||||
. = TRUE
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
switch(action)
|
||||
if("add")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
R.trans_id_to(src, id, amount)
|
||||
if("remove")
|
||||
var/id = params["id"]
|
||||
var/amount = text2num(params["amount"])
|
||||
if(!id || !amount)
|
||||
return
|
||||
if(mode)
|
||||
reagents.trans_id_to(beaker, id, amount)
|
||||
else
|
||||
dat += "<TITLE>Condimaster 3000</TITLE>Condiment infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]<BR><BR><BR><A href='?src=[UID()];main=1'>(Back)</A>"
|
||||
usr << browse(dat, "window=chem_master;size=575x500")
|
||||
return
|
||||
|
||||
else if(href_list["add"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["add"]
|
||||
var/amount = text2num(href_list["amount"])
|
||||
R.trans_id_to(src, id, amount)
|
||||
|
||||
else if(href_list["addcustom"])
|
||||
|
||||
var/id = href_list["addcustom"]
|
||||
useramount = input("Select the amount to transfer.", 30, useramount) as num
|
||||
useramount = isgoodnumber(useramount)
|
||||
Topic(null, list("amount" = "[useramount]", "add" = "[id]"))
|
||||
|
||||
else if(href_list["remove"])
|
||||
|
||||
if(href_list["amount"])
|
||||
var/id = href_list["remove"]
|
||||
var/amount = text2num(href_list["amount"])
|
||||
if(mode)
|
||||
reagents.trans_id_to(beaker, id, amount)
|
||||
else
|
||||
reagents.remove_reagent(id, amount)
|
||||
|
||||
|
||||
else if(href_list["removecustom"])
|
||||
|
||||
var/id = href_list["removecustom"]
|
||||
useramount = input("Select the amount to transfer.", 30, useramount) as num
|
||||
useramount = isgoodnumber(useramount)
|
||||
Topic(null, list("amount" = "[useramount]", "remove" = "[id]"))
|
||||
|
||||
else if(href_list["toggle"])
|
||||
mode = !mode
|
||||
|
||||
else if(href_list["main"])
|
||||
attack_hand(usr)
|
||||
return
|
||||
else if(href_list["eject"])
|
||||
if(beaker)
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
update_icon()
|
||||
else if(href_list["createpill"] || href_list["createpill_multiple"])
|
||||
if(!condi)
|
||||
var/count = 1
|
||||
if(href_list["createpill_multiple"])
|
||||
count = input("Select the number of pills to make.", 10, pillamount) as num|null
|
||||
if(count == null)
|
||||
return
|
||||
count = isgoodnumber(count)
|
||||
if(count > 20)
|
||||
count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
|
||||
if(count <= 0)
|
||||
return
|
||||
var/amount_per_pill = reagents.total_volume / count
|
||||
if(amount_per_pill > 100)
|
||||
amount_per_pill = 100
|
||||
var/name = clean_input("Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)")
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
|
||||
return
|
||||
var/obj/item/reagent_containers/food/pill/P = new/obj/item/reagent_containers/food/pill(loc)
|
||||
if(!name)
|
||||
name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] pill"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = "pill"+pillsprite
|
||||
reagents.trans_to(P, amount_per_pill)
|
||||
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
updateUsrDialog()
|
||||
else
|
||||
var/name = clean_input("Name:", "Name your bag!", reagents.get_master_reagent_name())
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(loc)
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.originalname = name
|
||||
P.name = "[name] pack"
|
||||
P.desc = "A small condiment pack. The label says it contains [name]."
|
||||
reagents.trans_to(P, 10)
|
||||
else if(href_list["createpatch"] || href_list["createpatch_multiple"])
|
||||
if(!condi)
|
||||
var/count = 1
|
||||
if(href_list["createpatch_multiple"])
|
||||
count = input("Select the number of patches to make.", 10, patchamount) as num|null
|
||||
if(count == null)
|
||||
return
|
||||
count = isgoodnumber(count)
|
||||
if(!count || count <= 0)
|
||||
return
|
||||
if(count > 20)
|
||||
count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
|
||||
var/amount_per_patch = reagents.total_volume/count
|
||||
if(amount_per_patch > 30)
|
||||
amount_per_patch = 30
|
||||
var/name = clean_input("Name:", "Name your patch!", "[reagents.get_master_reagent_name()] ([amount_per_patch]u)")
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/is_medical_patch = chemical_safety_check(reagents)
|
||||
while(count--)
|
||||
var/obj/item/reagent_containers/food/pill/patch/P = new/obj/item/reagent_containers/food/pill/patch(loc)
|
||||
if(!name) name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] patch"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
reagents.trans_to(P,amount_per_patch)
|
||||
if(is_medical_patch)
|
||||
P.instant_application = TRUE
|
||||
P.icon_state = "bandaid_med"
|
||||
if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle/patch_pack)
|
||||
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["createbottle"])
|
||||
if(!condi)
|
||||
var/name = clean_input("Name:", "Name your bottle!", reagents.get_master_reagent_name())
|
||||
if(!name)
|
||||
return
|
||||
name = reject_bad_text(name)
|
||||
var/obj/item/reagent_containers/glass/bottle/reagent/P = new/obj/item/reagent_containers/glass/bottle/reagent(loc)
|
||||
if(!name)
|
||||
name = reagents.get_master_reagent_name()
|
||||
P.name = "[name] bottle"
|
||||
P.pixel_x = rand(-7, 7) //random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = bottlesprite
|
||||
reagents.trans_to(P, 50)
|
||||
else
|
||||
var/obj/item/reagent_containers/food/condiment/P = new/obj/item/reagent_containers/food/condiment(loc)
|
||||
reagents.trans_to(P, 50)
|
||||
else if(href_list["change_pill"])
|
||||
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
|
||||
var/dat = "<table>"
|
||||
var/j = 0
|
||||
for(var/i = 1 to MAX_PILL_SPRITE)
|
||||
j++
|
||||
if(j == 1)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href=\"?src=[UID()]&pill_sprite=[i]\"><img src=\"pill[i].png\" /></a></td>"
|
||||
if(j == 5)
|
||||
dat += "</tr>"
|
||||
j = 0
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
|
||||
return
|
||||
else if(href_list["change_bottle"])
|
||||
var/dat = "<table>"
|
||||
var/j = 0
|
||||
for(var/i in list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle"))
|
||||
j++
|
||||
if(j == 1)
|
||||
dat += "<tr>"
|
||||
dat += "<td><a href=\"?src=[UID()]&bottle_sprite=[i]\"><img src=\"[i].png\" /></a></td>"
|
||||
if(j == 5)
|
||||
dat += "</tr>"
|
||||
j = 0
|
||||
dat += "</table>"
|
||||
usr << browse(dat, "window=chem_master_iconsel;size=225x193")
|
||||
return
|
||||
else if(href_list["pill_sprite"])
|
||||
pillsprite = href_list["pill_sprite"]
|
||||
usr << browse(null, "window=chem_master_iconsel")
|
||||
else if(href_list["bottle_sprite"])
|
||||
bottlesprite = href_list["bottle_sprite"]
|
||||
usr << browse(null, "window=chem_master_iconsel")
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
reagents.remove_reagent(id, amount)
|
||||
if("eject")
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.forceMove(get_turf(src))
|
||||
if(Adjacent(usr) && !issilicon(usr))
|
||||
usr.put_in_hands(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
update_icon()
|
||||
if("create_condi_bottle")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
var/obj/item/reagent_containers/food/condiment/P = new(loc)
|
||||
reagents.trans_to(P, 50)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/chem_master/attack_ghost(mob/user)
|
||||
if(user.can_admin_interact())
|
||||
return attack_hand(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_master/attack_hand(mob/user)
|
||||
if(..())
|
||||
return TRUE
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
|
||||
/obj/machinery/chem_master/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
var/datum/asset/chem_master/assets = get_asset_datum(/datum/asset/chem_master)
|
||||
assets.send(user)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "chem_master.tmpl", name, 575, 500)
|
||||
ui = new(user, src, ui_key, "ChemMaster", name, 575, 500)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/chem_master/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/chem_master/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["condi"] = condi
|
||||
data["loaded_pill_bottle"] = (loaded_pill_bottle ? 1 : 0)
|
||||
data["loaded_pill_bottle"] = loaded_pill_bottle ? TRUE : FALSE
|
||||
if(loaded_pill_bottle)
|
||||
data["loaded_pill_bottle_name"] = loaded_pill_bottle.name
|
||||
data["loaded_pill_bottle_contents_len"] = loaded_pill_bottle.contents.len
|
||||
data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.storage_slots
|
||||
|
||||
data["beaker"] = (beaker ? 1 : 0)
|
||||
data["beaker"] = beaker ? TRUE : FALSE
|
||||
if(beaker)
|
||||
var/list/beaker_reagents_list = list()
|
||||
data["beaker_reagents"] = beaker_reagents_list
|
||||
@@ -464,13 +276,255 @@
|
||||
data["buffer_reagents"] = buffer_reagents_list
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
buffer_reagents_list[++buffer_reagents_list.len] = list("name" = R.name, "volume" = R.volume, "id" = R.id, "description" = R.description)
|
||||
else
|
||||
data["beaker_reagents"] = list()
|
||||
data["buffer_reagents"] = list()
|
||||
|
||||
data["pillsprite"] = pillsprite
|
||||
data["bottlesprite"] = bottlesprite
|
||||
data["mode"] = mode
|
||||
data["printing"] = printing
|
||||
|
||||
// Transfer modal information if there is one
|
||||
data["modal"] = tgui_modal_data(src)
|
||||
|
||||
return data
|
||||
|
||||
/**
|
||||
* Called in tgui_act() to process modal actions
|
||||
*
|
||||
* Arguments:
|
||||
* * action - The action passed by tgui
|
||||
* * params - The params passed by tgui
|
||||
*/
|
||||
/obj/machinery/chem_master/proc/tgui_act_modal(action, params, datum/tgui/ui, datum/tgui_state/state)
|
||||
. = TRUE
|
||||
var/id = params["id"] // The modal's ID
|
||||
var/list/arguments = istext(params["arguments"]) ? json_decode(params["arguments"]) : params["arguments"]
|
||||
switch(tgui_modal_act(src, action, params))
|
||||
if(TGUI_MODAL_OPEN)
|
||||
switch(id)
|
||||
if("analyze")
|
||||
var/idx = text2num(arguments["idx"]) || 0
|
||||
var/from_beaker = text2num(arguments["beaker"]) || FALSE
|
||||
var/reagent_list = from_beaker ? beaker.reagents.reagent_list : reagents.reagent_list
|
||||
if(idx < 1 || idx > length(reagent_list))
|
||||
return
|
||||
|
||||
var/datum/reagent/R = reagent_list[idx]
|
||||
var/list/result = list("idx" = idx, "name" = R.name, "desc" = R.description)
|
||||
if(!condi && istype(R, /datum/reagent/blood))
|
||||
var/datum/reagent/blood/B = R
|
||||
result["blood_type"] = B.data["blood_type"]
|
||||
result["blood_dna"] = B.data["blood_DNA"]
|
||||
|
||||
arguments["analysis"] = result
|
||||
tgui_modal_message(src, id, "", null, arguments)
|
||||
if("change_pill_bottle_style")
|
||||
if(!loaded_pill_bottle)
|
||||
return
|
||||
if(!pill_bottle_wrappers)
|
||||
pill_bottle_wrappers = list(
|
||||
"CLEAR" = "Default",
|
||||
COLOR_RED = "Red",
|
||||
COLOR_GREEN = "Green",
|
||||
COLOR_PALE_BTL_GREEN = "Pale green",
|
||||
COLOR_BLUE = "Blue",
|
||||
COLOR_CYAN_BLUE = "Light blue",
|
||||
COLOR_TEAL = "Teal",
|
||||
COLOR_YELLOW = "Yellow",
|
||||
COLOR_ORANGE = "Orange",
|
||||
COLOR_PINK = "Pink",
|
||||
COLOR_MAROON = "Brown"
|
||||
)
|
||||
var/current = pill_bottle_wrappers[loaded_pill_bottle.wrapper_color] || "Default"
|
||||
tgui_modal_choice(src, id, "Please select a pill bottle wrapper:", null, arguments, current, pill_bottle_wrappers)
|
||||
if("addcustom")
|
||||
if(!beaker || !beaker.reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount to transfer to buffer:", null, arguments, useramount)
|
||||
if("removecustom")
|
||||
if(!reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount)
|
||||
if("create_condi_pack")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
|
||||
if("create_pill")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/num = round(text2num(arguments["num"] || 1))
|
||||
if(!num)
|
||||
return
|
||||
arguments["num"] = num
|
||||
var/amount_per_pill = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PILL)
|
||||
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)"
|
||||
var/pills_text = num == 1 ? "new pill" : "[num] new pills"
|
||||
tgui_modal_input(src, id, "Please name your [pills_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
|
||||
if("create_pill_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount of pills to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
|
||||
if("change_pill_style")
|
||||
var/list/choices = list()
|
||||
for(var/i = 1 to MAX_PILL_SPRITE)
|
||||
choices += "pill[i].png"
|
||||
tgui_modal_bento(src, id, "Please select the new style for pills:", null, arguments, pillsprite, choices)
|
||||
if("create_patch")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/num = round(text2num(arguments["num"] || 1))
|
||||
if(!num)
|
||||
return
|
||||
arguments["num"] = num
|
||||
var/amount_per_patch = clamp(reagents.total_volume / num, 0, MAX_UNITS_PER_PATCH)
|
||||
var/default_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)"
|
||||
var/patches_text = num == 1 ? "new patch" : "[num] new patches"
|
||||
tgui_modal_input(src, id, "Please name your [patches_text]:", null, arguments, default_name, MAX_CUSTOM_NAME_LEN)
|
||||
if("create_patch_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please enter the amount of patches to make (max [MAX_MULTI_AMOUNT] at a time):", null, arguments, pillamount, 5)
|
||||
if("create_bottle")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_modal_input(src, id, "Please name your bottle:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN)
|
||||
if("change_bottle_style")
|
||||
if(!bottle_styles)
|
||||
bottle_styles = list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle")
|
||||
var/list/bottle_styles_png = list()
|
||||
for(var/style in bottle_styles)
|
||||
bottle_styles_png += "[style].png"
|
||||
tgui_modal_bento(src, id, "Please select the new style for bottles:", null, arguments, bottlesprite, bottle_styles_png)
|
||||
else
|
||||
return FALSE
|
||||
if(TGUI_MODAL_ANSWER)
|
||||
var/answer = params["answer"]
|
||||
switch(id)
|
||||
if("change_pill_bottle_style")
|
||||
if(!pill_bottle_wrappers || !loaded_pill_bottle) // wat?
|
||||
return
|
||||
var/color = "CLEAR"
|
||||
for(var/col in pill_bottle_wrappers)
|
||||
var/col_name = pill_bottle_wrappers[col]
|
||||
if(col_name == answer)
|
||||
color = col
|
||||
break
|
||||
if(length(color) && color != "CLEAR")
|
||||
loaded_pill_bottle.wrapper_color = color
|
||||
loaded_pill_bottle.apply_wrap()
|
||||
else
|
||||
loaded_pill_bottle.wrapper_color = null
|
||||
loaded_pill_bottle.cut_overlays()
|
||||
if("addcustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("add", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("removecustom")
|
||||
var/amount = isgoodnumber(text2num(answer))
|
||||
if(!amount || !arguments["id"])
|
||||
return
|
||||
tgui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state)
|
||||
if("create_condi_pack")
|
||||
if(!condi || !reagents.total_volume)
|
||||
return
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/obj/item/reagent_containers/food/condiment/pack/P = new(loc)
|
||||
P.originalname = answer
|
||||
P.name = "[answer] pack"
|
||||
P.desc = "A small condiment pack. The label says it contains [answer]."
|
||||
reagents.trans_to(P, 10)
|
||||
if("create_pill")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
|
||||
if(!count)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/amount_per_pill = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these pills!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/food/pill/P = new(loc)
|
||||
P.name = "[answer] pill"
|
||||
P.pixel_x = rand(-7, 7) // Random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = "pill[pillsprite]"
|
||||
reagents.trans_to(P, amount_per_pill)
|
||||
// Load the pills in the bottle if there's one loaded
|
||||
if(istype(loaded_pill_bottle) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
if("create_pill_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_act("modal_open", list("id" = "create_pill", "arguments" = list("num" = answer)), ui, state)
|
||||
if("change_pill_style")
|
||||
var/new_style = clamp(text2num(answer) || 0, 0, MAX_PILL_SPRITE)
|
||||
if(!new_style)
|
||||
return
|
||||
pillsprite = new_style
|
||||
if("create_patch")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
var/count = clamp(round(text2num(arguments["num"]) || 0), 0, MAX_MULTI_AMOUNT)
|
||||
if(!count)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/amount_per_patch = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH)
|
||||
var/is_medical_patch = chemical_safety_check(reagents)
|
||||
while(count--)
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(usr, "<span class='notice'>Not enough reagents to create these patches!</span>")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/food/pill/patch/P = new(loc)
|
||||
P.name = "[answer] patch"
|
||||
P.pixel_x = rand(-7, 7) // random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
reagents.trans_to(P, amount_per_patch)
|
||||
if(is_medical_patch)
|
||||
P.instant_application = TRUE
|
||||
P.icon_state = "bandaid_med"
|
||||
// Load the patches in the bottle if there's one loaded
|
||||
if(istype(loaded_pill_bottle, /obj/item/storage/pill_bottle/patch_pack) && length(loaded_pill_bottle.contents) < loaded_pill_bottle.storage_slots)
|
||||
P.forceMove(loaded_pill_bottle)
|
||||
if("create_patch_multiple")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
tgui_act("modal_open", list("id" = "create_patch", "arguments" = list("num" = answer)), ui, state)
|
||||
if("create_bottle")
|
||||
if(condi || !reagents.total_volume)
|
||||
return
|
||||
|
||||
if(!length(answer))
|
||||
answer = reagents.get_master_reagent_name()
|
||||
var/obj/item/reagent_containers/glass/bottle/reagent/P = new(loc)
|
||||
P.name = "[answer] bottle"
|
||||
P.pixel_x = rand(-7, 7) // random position
|
||||
P.pixel_y = rand(-7, 7)
|
||||
P.icon_state = length(bottle_styles) && bottle_styles[bottlesprite] || "bottle"
|
||||
reagents.trans_to(P, 50)
|
||||
if("change_bottle_style")
|
||||
if(!bottle_styles)
|
||||
return
|
||||
var/new_sprite = text2num(answer) || 1
|
||||
if(new_sprite < 1 || new_sprite > length(bottle_styles))
|
||||
return
|
||||
bottlesprite = new_sprite
|
||||
else
|
||||
return FALSE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/proc/isgoodnumber(num)
|
||||
if(isnum(num))
|
||||
if(num > 200)
|
||||
@@ -481,7 +535,7 @@
|
||||
num = round(num)
|
||||
return num
|
||||
else
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
|
||||
var/all_safe = TRUE
|
||||
@@ -503,3 +557,9 @@
|
||||
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
|
||||
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
|
||||
RefreshParts()
|
||||
|
||||
#undef MAX_PILL_SPRITE
|
||||
#undef MAX_MULTI_AMOUNT
|
||||
#undef MAX_UNITS_PER_PILL
|
||||
#undef MAX_UNITS_PER_PATCH
|
||||
#undef MAX_CUSTOM_NAME_LEN
|
||||
|
||||
@@ -272,6 +272,16 @@
|
||||
build_path = /obj/item/circuitboard/solar_control
|
||||
category = list("Computer Boards")
|
||||
|
||||
/datum/design/sm_monitor
|
||||
name = "Console Board (Supermatter Monitoring)"
|
||||
desc = "Allows for the construction of circuit boards used to build a supermatter monitoring console"
|
||||
id = "sm_monitor"
|
||||
req_tech = list("programming" = 2, "powerstorage" = 2)
|
||||
build_type = IMPRINTER
|
||||
materials = list(MAT_GLASS = 1000)
|
||||
build_path = /obj/item/circuitboard/sm_monitor
|
||||
category = list("Computer Boards")
|
||||
|
||||
/datum/design/spacepodlocator
|
||||
name = "Console Board (Spacepod Locator)"
|
||||
desc = "Allows for the construction of circuit boards used to build a space-pod locating console"
|
||||
|
||||
@@ -296,7 +296,7 @@
|
||||
return
|
||||
var/sound/S = sound(mysound)
|
||||
S.wait = 0 //No queue
|
||||
S.channel = open_sound_channel()
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = 50
|
||||
for(var/mob/M in passengers | pilot)
|
||||
M << S
|
||||
|
||||
@@ -111,6 +111,12 @@
|
||||
typepath = /obj/item/instrument/eguitar
|
||||
cost = 500
|
||||
|
||||
/datum/storeitem/banjo
|
||||
name = "Banjo"
|
||||
desc = "It's pretty much just a drum with a neck and strings."
|
||||
typepath = /obj/item/instrument/banjo
|
||||
cost = 500
|
||||
|
||||
/datum/storeitem/piano_synth
|
||||
name = "Piano Synthesizer"
|
||||
desc = "An advanced electronic synthesizer that can emulate various instruments."
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* tgui modals
|
||||
*
|
||||
* Allows creation of modals within tgui.
|
||||
*/
|
||||
|
||||
GLOBAL_LIST(tgui_modals)
|
||||
|
||||
/**
|
||||
* Call this from a proc that is called in tgui_act() to process modal actions
|
||||
*
|
||||
* Example: /obj/machinery/chem_master/proc/tgui_act_modal
|
||||
* You can then switch based on the return value and show different
|
||||
* modals depending on the answer.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * action - The called action
|
||||
* * params - The params to the action
|
||||
*/
|
||||
/datum/proc/tgui_modal_act(datum/source = src, action = "", params)
|
||||
ASSERT(istype(source))
|
||||
|
||||
. = null
|
||||
switch(action)
|
||||
if("modal_open") // Params: id, arguments
|
||||
return TGUI_MODAL_OPEN
|
||||
if("modal_answer") // Params: id, answer, arguments
|
||||
params["answer"] = tgui_modal_preprocess_answer(source, params["answer"])
|
||||
if(tgui_modal_answer(source, params["id"], params["answer"])) // If there's a current modal with a delegate that returned TRUE, no need to continue
|
||||
. = TGUI_MODAL_DELEGATE
|
||||
else
|
||||
. = TGUI_MODAL_ANSWER
|
||||
tgui_modal_clear(source)
|
||||
if("modal_close") // Params: id
|
||||
tgui_modal_clear(source)
|
||||
return TGUI_MODAL_CLOSE
|
||||
|
||||
/**
|
||||
* Call this from tgui_data() to return modal information if needed
|
||||
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_data(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return null
|
||||
|
||||
return current.to_data()
|
||||
|
||||
/**
|
||||
* Clears the current modal for a given datum
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
*/
|
||||
/datum/proc/tgui_modal_clear(datum/source = src)
|
||||
ASSERT(istype(source))
|
||||
|
||||
LAZYINITLIST(GLOB.tgui_modals)
|
||||
var/datum/tgui_modal/previous = GLOB.tgui_modals[source.UID()]
|
||||
if(!previous)
|
||||
return FALSE
|
||||
|
||||
for(var/i in 1 to length(GLOB.tgui_modals))
|
||||
var/key = GLOB.tgui_modals[i]
|
||||
if(previous == GLOB.tgui_modals[key])
|
||||
GLOB.tgui_modals.Cut(i, i + 1)
|
||||
break
|
||||
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Opens a message TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when closed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
*/
|
||||
/datum/proc/tgui_modal_message(datum/source = src, id, text = "Default modal message", delegate, arguments)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/modal = new(id, text, delegate, arguments)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a text input TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the input
|
||||
* * max_length - The maximum char length of the input
|
||||
*/
|
||||
/datum/proc/tgui_modal_input(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", max_length = TGUI_MODAL_INPUT_MAX_LENGTH)
|
||||
ASSERT(length(id))
|
||||
ASSERT(max_length > 0)
|
||||
|
||||
var/datum/tgui_modal/input/modal = new(id, text, delegate, arguments, value, max_length)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a dropdown input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the dropdown
|
||||
* * choices - The list of available choices in the dropdown
|
||||
*/
|
||||
/datum/proc/tgui_modal_choice(datum/source = src, id, text = "Default modal message", delegate, arguments, value = "", choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/choice/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a bento input TGUI modal
|
||||
*
|
||||
* Internally checks if the answer is in the list of choices.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when submitted
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * value - The default value of the bento
|
||||
* * choices - The list of available choices in the bento
|
||||
*/
|
||||
/datum/proc/tgui_modal_bento(datum/source = src, id, text = "Default modal message", delegate, arguments, value, choices)
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/input/bento/modal = new(id, text, delegate, arguments, value, choices)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Opens a yes/no TGUI modal
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * text - The text to display above the answers
|
||||
* * delegate - The proc to call when "Yes" is pressed
|
||||
* * delegate_no - The proc to call when "No" is pressed
|
||||
* * arguments - List of arguments passed to and from JS (mostly useful for chaining modals)
|
||||
* * yes_text - The text to show in the "Yes" button
|
||||
* * no_text - The text to show in the "No" button
|
||||
*/
|
||||
/datum/proc/tgui_modal_boolean(datum/source = src, id, text = "Default modal message", delegate, delegate_no, arguments, yes_text = "Yes", no_text = "No")
|
||||
ASSERT(length(id))
|
||||
|
||||
var/datum/tgui_modal/boolean/modal = new(id, text, delegate, delegate_no, arguments, yes_text, no_text)
|
||||
return tgui_modal_new(source, modal)
|
||||
|
||||
/**
|
||||
* Registers a given modal to a source. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * modal - The datum/tgui_modal to register
|
||||
* * replace_previous - Whether any modal currently assigned to source should be replaced
|
||||
* * instant_update - Whether the changes should reflect immediately
|
||||
*/
|
||||
/datum/proc/tgui_modal_new(datum/source = src, datum/tgui_modal/modal = null, replace_previous = TRUE, instant_update = TRUE)
|
||||
ASSERT(istype(source))
|
||||
ASSERT(istype(modal))
|
||||
|
||||
var/datum/tgui_modal/previous = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(previous && !replace_previous)
|
||||
return FALSE
|
||||
|
||||
modal.owning_source = source
|
||||
|
||||
// Previous one should get GC'd
|
||||
LAZYSET(GLOB.tgui_modals, source.UID(), modal)
|
||||
if(instant_update)
|
||||
SStgui.update_uis(source)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Calls the source's currently assigned modal's (if there is one) on_answer() proc. Private.
|
||||
*
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * id - The ID of the modal
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_answer(datum/source = src, id, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return FALSE
|
||||
|
||||
return current.on_answer(answer)
|
||||
|
||||
/**
|
||||
* Passes an answer from JS through the modal's proc.
|
||||
*
|
||||
* Used namely for cutting the text short if it's longer
|
||||
* than an input modal's max_length.
|
||||
* Arguments:
|
||||
* * source - The source datum
|
||||
* * answer - The provided answer
|
||||
*/
|
||||
/datum/proc/tgui_modal_preprocess_answer(datum/source = src, answer = "")
|
||||
ASSERT(istype(source))
|
||||
|
||||
var/datum/tgui_modal/current = LAZYACCESS(GLOB.tgui_modals, source.UID())
|
||||
if(!current)
|
||||
return answer
|
||||
|
||||
return current.preprocess_answer(answer)
|
||||
|
||||
/**
|
||||
* Modal datum (contains base information for a modal)
|
||||
*/
|
||||
/datum/tgui_modal
|
||||
var/datum/owning_source
|
||||
var/id
|
||||
var/text
|
||||
var/delegate
|
||||
var/list/arguments
|
||||
var/modal_type = "message"
|
||||
|
||||
/datum/tgui_modal/New(id, text, delegate, list/arguments)
|
||||
src.id = id
|
||||
src.text = text
|
||||
src.delegate = delegate
|
||||
src.arguments = arguments
|
||||
|
||||
/**
|
||||
* Called when it's time to pre-process the answer before using it
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/preprocess_answer(answer)
|
||||
return reject_bad_text(answer, TGUI_MODAL_INPUT_MAX_LENGTH) // bleh
|
||||
|
||||
/**
|
||||
* Called when a modal receives an answer
|
||||
*
|
||||
* Arguments:
|
||||
* * answer - The answer, a nullable text
|
||||
*/
|
||||
/datum/tgui_modal/proc/on_answer(answer)
|
||||
if(delegate)
|
||||
return call(owning_source, delegate)(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Creates a list that describes a modal visually to be passed to JS
|
||||
*/
|
||||
/datum/tgui_modal/proc/to_data()
|
||||
. = list()
|
||||
.["id"] = id
|
||||
.["text"] = text
|
||||
.["args"] = arguments || list()
|
||||
.["type"] = modal_type
|
||||
|
||||
/**
|
||||
* Input modal - has a text entry that can be used to enter an answer
|
||||
*/
|
||||
/datum/tgui_modal/input
|
||||
modal_type = "input"
|
||||
var/value
|
||||
var/max_length
|
||||
|
||||
/datum/tgui_modal/input/New(id, text, delegate, list/arguments, value, max_length)
|
||||
..(id, text, delegate, arguments)
|
||||
src.value = value
|
||||
src.max_length = max_length
|
||||
|
||||
/datum/tgui_modal/input/preprocess_answer(answer)
|
||||
. = ..(answer)
|
||||
if(length(answer) > max_length)
|
||||
. = copytext(., 1, max_length + 1)
|
||||
|
||||
/datum/tgui_modal/input/to_data()
|
||||
. = ..()
|
||||
.["value"] = value
|
||||
|
||||
/**
|
||||
* Choice modal - has a dropdown menu that can be used to select an answer
|
||||
*/
|
||||
/datum/tgui_modal/input/choice
|
||||
modal_type = "choice"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/choice/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, value, TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in dropdowns, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/choice/on_answer(answer)
|
||||
if(answer in choices) // Make sure the answer is actually in our choices!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/choice/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Bento modal - Similar to choice, it displays the choices in a grid of images
|
||||
*
|
||||
* The returned answer is the index of the choice.
|
||||
*/
|
||||
/datum/tgui_modal/input/bento
|
||||
modal_type = "bento"
|
||||
var/choices
|
||||
|
||||
/datum/tgui_modal/input/bento/New(id, text, delegate, list/arguments, value, choices)
|
||||
..(id, text, delegate, arguments, text2num(value), TGUI_MODAL_INPUT_MAX_LENGTH) // Max length doesn't really matter in here, but whatever
|
||||
src.choices = choices
|
||||
|
||||
/datum/tgui_modal/input/bento/preprocess_answer(answer)
|
||||
return text2num(answer) || 0
|
||||
|
||||
/datum/tgui_modal/input/bento/on_answer(answer)
|
||||
if(answer >= 1 && answer <= length(choices)) // Make sure the answer index is actually in our indexes!
|
||||
return ..(answer, arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/input/bento/to_data()
|
||||
. = ..()
|
||||
.["choices"] = choices
|
||||
|
||||
/**
|
||||
* Boolean modal - has yes/no buttons that do different actions depending on which is pressed
|
||||
*/
|
||||
/datum/tgui_modal/boolean
|
||||
modal_type = "boolean"
|
||||
var/delegate_no
|
||||
var/yes_text
|
||||
var/no_text
|
||||
|
||||
/datum/tgui_modal/boolean/New(id, text, delegate, delegate_no, list/arguments, yes_text, no_text)
|
||||
..(id, text, delegate, arguments)
|
||||
src.delegate_no = delegate_no
|
||||
src.yes_text = yes_text
|
||||
src.no_text = no_text
|
||||
|
||||
/datum/tgui_modal/boolean/preprocess_answer(answer)
|
||||
return text2num(answer) || FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/on_answer(answer)
|
||||
if(answer)
|
||||
return ..(answer, arguments)
|
||||
else if(delegate_no)
|
||||
return call(owning_source, delegate_no)(arguments)
|
||||
return FALSE
|
||||
|
||||
/datum/tgui_modal/boolean/to_data()
|
||||
. = ..()
|
||||
.["yes_text"] = yes_text
|
||||
.["no_text"] = no_text
|
||||
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 23 KiB |
@@ -1,231 +0,0 @@
|
||||
<!--
|
||||
Title: Body Scanner UI
|
||||
Used In File(s): \code\game\machinery\adv_med.dm
|
||||
-->
|
||||
|
||||
{{if !data.occupied}}
|
||||
<h3>No occupant detected.</h3>
|
||||
{{else}}
|
||||
<h4><b>Occupant Data:</b></h4>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Name:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:data.occupant.name}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Health:
|
||||
</div>
|
||||
{{:helper.displayBar(data.occupant.health, -100, 100, (data.occupant.health >= 50) ? 'good' : (data.occupant.health >= 0) ? 'average' : 'bad')}}
|
||||
<div class="itemContent" style="width: 60px">
|
||||
{{:helper.smoothRound(data.occupant.health)}}%
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.occupant.stat==0}}
|
||||
<span class="good"> Alive </span>
|
||||
{{else data.occupant.stat==1}}
|
||||
<span class="average"> Critical </span>
|
||||
{{else}}
|
||||
<span class="bad"> Dead </span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Temperature:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.smoothRound(data.occupant.bodyTempC)}}°C, {{:helper.smoothRound(data.occupant.bodyTempF)}}°F
|
||||
</div>
|
||||
</div>
|
||||
{{if data.occupant.hasBorer}}
|
||||
<span class="bad">
|
||||
Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended. </span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.blind}}
|
||||
<span class="average">Cataracts detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.colourblind}}
|
||||
<span class="average">Photoreceptor abnormalities detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.nearsighted}}
|
||||
<span class="average">Retinal misalignment detected.</span> <br>
|
||||
{{/if}}
|
||||
|
||||
<br>
|
||||
{{:helper.link('Print', 'print', {'print_p' : 1, 'name' : data.occupant.name})}}
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectify' : 1}, data.occupied ? null : 'disabled')}}
|
||||
<br> <br>
|
||||
|
||||
<b>Damage: </b>
|
||||
<table> <tbody>
|
||||
<tr>
|
||||
<td> Brute Damage: </td>
|
||||
<td> Brain Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth+100, (data.occupant.bruteLoss < 15) ? 'notgood' : (data.occupant.bruteLoss < 40) ? 'average' : 'bad', data.occupant.bruteLoss) }} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.brainLoss, 0, data.occupant.maxHealth+100, (data.occupant.brainLoss < 15) ? 'notgood' : (data.occupant.brainLoss < 40) ? 'average' : 'bad', data.occupant.brainLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Resp. Damage: </td>
|
||||
<td> Radiation Level: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth+100, (data.occupant.oxyLoss < 15) ? 'notgood' : (data.occupant.oxyLoss < 40) ? 'average' : 'bad', data.occupant.oxyLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.radLoss, 0, data.occupant.maxHealth+100, (data.occupant.radLoss < 15) ? 'notgood' : (data.occupant.radLoss < 40) ? 'average' : 'bad', data.occupant.radLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Toxin Damage: </td>
|
||||
<td> Genetic Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth+100, (data.occupant.toxLoss < 15) ? 'notgood' : (data.occupant.toxLoss < 40) ? 'average' : 'bad', data.occupant.toxLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.cloneLoss, 0, data.occupant.maxHealth+100, (data.occupant.cloneLoss < 15) ? 'notgood' : (data.occupant.cloneLoss < 40) ? 'average' : 'bad', data.occupant.cloneLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Burn Severity: </td>
|
||||
<td> Paralysis %: ({{:helper.smoothRound(data.occupant.paralysisSeconds)}} seconds left) </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth+100, (data.occupant.fireLoss < 15) ? 'notgood' : (data.occupant.fireLoss < 40) ? 'average' : 'bad', data.occupant.fireLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.paralysis, 0, 100, (data.occupant.paralysis < 25) ? 'notgood' : (data.occupant.paralysis < 50) ? 'average' : 'bad', data.occupant.paralysis)}} </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{if data.occupant.blood.hasBlood}}
|
||||
<br>
|
||||
<b>Blood:</b>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.blood.pulse}} bpm</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{:helper.displayBar(data.occupant.blood.bloodLevel, 0, data.occupant.blood.bloodMax, (data.occupant.blood.percent <= 60) ? 'bad' : (data.occupant.blood.percent <= 90) ? 'average' : 'good' )}}
|
||||
<div class="statusValue"> {{:helper.smoothRound(data.occupant.blood.percent)}}%, {{:helper.smoothRound(data.occupant.blood.bloodLevel)}}cl </div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<br>
|
||||
{{if data.occupant.hasVirus}}
|
||||
<span class="bad">
|
||||
Viral pathogen detected in blood stream.
|
||||
</span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.implant_len}}
|
||||
<br>
|
||||
<b>Implants</b>
|
||||
<table style="width: 30%">
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.implant}}
|
||||
<tr><td>{{:value.name}}</td></tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{{/if}}
|
||||
<b>External Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th style="width: 25%"> Name </th>
|
||||
<th style='width: 15%'> Total damage </th>
|
||||
<th style="width: 15%"> Brute damage </th>
|
||||
<th style="width: 15%"> Burn damage </th>
|
||||
<th style="width: 30%"> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.extOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} </td>
|
||||
<td> {{:helper.displayBar(value.totalLoss, 0, value.maxHealth, (value.totalLoss < value.bruised) ? 'notgood' : (value.totalLoss < value.broken) ? 'average' : 'bad', value.totalLoss) }} </td>
|
||||
<td> {{if value.bruteLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.bruteLoss)}} </span> </td>
|
||||
<td> {{if value.fireLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.fireLoss)}} </span> </td>
|
||||
<td>
|
||||
<span class='average'>
|
||||
{{if value.internalBleeding}} internal bleeding <br> {{/if}}
|
||||
{{if value.lungRuptured}} lung ruptured <br> {{/if}}
|
||||
{{if value.status.broken}} {{:value.status.broken}} <br> {{/if}}
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if value.open}} open incision <br> {{/if}}
|
||||
</span>
|
||||
{{if value.status.splinted}} splinted <br> {{/if}}
|
||||
{{if value.status.robotic}} robotic <br> {{/if}}
|
||||
{{if value.status.dead}} <span class='bad'>DEAD</span> <br {{/if}}
|
||||
{{if value.shrapnel_len}}
|
||||
{{for value.shrapnel : shrapValue:shrapindex}}
|
||||
{{:shrapValue.known ? shrapValue.name : "unknown object"}} <br>
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<b>Internal Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th width=25%> Name </th>
|
||||
<th width=35%> Brute damage </th>
|
||||
<th widht=40%> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.intOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} <br> </td>
|
||||
<td> {{:helper.displayBar(value.damage, 0, value.maxHealth, (value.damage < value.bruised) ? 'notgood' : (value.damage < value.broken) ? 'average' : 'bad', value.damage) }} </td>
|
||||
<td>
|
||||
<span class="average">
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute Infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute Infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute Infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{if value.robotic == 1}} robotic <br> {{/if}}
|
||||
{{if value.robotic == 2}} assisted <br> {{/if}}
|
||||
{{if value.dead}} <span class='bad'>DEAD</span> <br> {{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
@@ -1,197 +0,0 @@
|
||||
<div class='notice'>
|
||||
{{if data.siliconUser}}
|
||||
<div class="itemContentSmall">
|
||||
Interface Lock:
|
||||
</div>
|
||||
<div class="itemContentFull">
|
||||
{{:helper.link('Engaged', 'lock', {'toggleaccess' : 1}, data.siliconLock ? 'selected' : null)}}{{:helper.link('Disengaged', 'unlock', {'toggleaccess' : 1}, data.malfStatus >= 2 ? 'linkOff' : (data.siliconLock ? null : 'selected'))}}
|
||||
</div>
|
||||
<div class="clearBoth"></div>
|
||||
{{else}}
|
||||
{{if data.locked}}
|
||||
Swipe an ID card to unlock this interface
|
||||
{{else}}
|
||||
Swipe an ID card to lock this interface
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div style="min-width: 480px">
|
||||
|
||||
<h3>Power Status</h3>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Main Breaker:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.locked && !data.siliconUser}}
|
||||
{{if data.isOperating}}
|
||||
<span class='good'>On</span>
|
||||
{{else}}
|
||||
<span class='bad'>Off</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{:helper.link('On', 'power-off', {'breaker' : 1}, data.isOperating ? 'selected' : null)}}{{:helper.link('Off', 'close', {'breaker' : 1}, data.isOperating ? null : 'selected')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
External Power:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.externalPower == 2}}
|
||||
<span class='good'>Good</span>
|
||||
{{else data.externalPower == 1}}
|
||||
<span class='average'>Low</span>
|
||||
{{else}}
|
||||
<span class='bad'>None</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Power Cell:
|
||||
</div>
|
||||
{{if data.powerCellStatus == null}}
|
||||
<div class="itemContent bad">
|
||||
Power cell removed.
|
||||
</div>
|
||||
{{else}}
|
||||
|
||||
{{:helper.displayBar(data.powerCellStatus, 0, 100, (data.powerCellStatus >= 50) ? 'good' : (data.powerCellStatus >= 25) ? 'average' : 'bad')}}
|
||||
<div class="itemContent" style="width: 60px">
|
||||
{{:helper.smoothRound(data.powerCellStatus, 1)}}%
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if data.powerCellStatus != null}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Charge Mode:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.locked && !data.siliconUser}}
|
||||
{{if data.chargeMode}}
|
||||
<span class='good'>Auto</span>
|
||||
{{else}}
|
||||
<span class='bad'>Off</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{:helper.link('Auto', 'refresh', {'cmode' : 1}, data.chargeMode ? 'selected' : null)}}{{:helper.link('Off', 'close', {'cmode' : 1}, data.chargeMode ? null : 'selected')}}
|
||||
{{/if}}
|
||||
|
||||
{{if data.chargingStatus > 1}}
|
||||
[<span class='good'>Fully Charged</span>]
|
||||
{{else data.chargingStatus == 1}}
|
||||
[<span class='average'>Charging</span>]
|
||||
{{else}}
|
||||
[<span class='bad'>Not Charging</span>]
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
<h3>Power Channels</h3>
|
||||
|
||||
{{for data.powerChannels}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
{{:value.title}}:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 70px; text-align: right">
|
||||
{{:helper.smoothRound(value.powerLoad)}} W
|
||||
</div>
|
||||
<div class="itemContent" style="width: 105px">
|
||||
|
||||
{{if value.status <= 1}}
|
||||
<span class='bad'>Off</span>
|
||||
{{else value.status >= 2}}
|
||||
<span class='good'>On</span>
|
||||
{{/if}}
|
||||
{{if data.locked}}
|
||||
{{if value.status == 1 || value.status == 3}}
|
||||
Auto
|
||||
{{else}}
|
||||
Manual
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if !data.locked || data.siliconUser}}
|
||||
<div class="itemContentFull">
|
||||
{{:helper.link('Auto', 'refresh', value.topicParams.auto, (value.status == 1 || value.status == 3) ? 'selected' : null)}}
|
||||
{{:helper.link('On', 'power-off', value.topicParams.on, (value.status == 2) ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', value.topicParams.off, (value.status == 0) ? 'selected' : null)}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
|
||||
<div class="item" style="font-weight: bold">
|
||||
<div class="itemLabel">
|
||||
Total Load:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 70px; text-align: right">
|
||||
{{:helper.smoothRound(data.totalLoad)}} W
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Cover Lock:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.locked && !data.siliconUser}}
|
||||
{{if data.coverLocked}}
|
||||
<span class='good'>Engaged</span>
|
||||
{{else}}
|
||||
<span class='bad'>Disengaged</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{:helper.link('Engaged', 'lock', {'lock' : 1}, data.coverLocked ? 'selected' : null)}}{{:helper.link('Disengaged', 'unlock', {'lock' : 1}, data.coverLocked ? null : 'selected')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if data.siliconUser}}
|
||||
<h3>System Overrides</h3>
|
||||
|
||||
<div class="item">
|
||||
{{:helper.link('Overload Lighting Circuit', 'lightbulb-o', {'overload' : 1})}}
|
||||
{{if data.malfStatus == 1}}
|
||||
{{:helper.link('Override Programming', 'file-text', {'malfhack' : 1})}}
|
||||
{{else data.malfStatus == 2}}
|
||||
{{:helper.link('Shunt Core Processes', 'arrow-down', {'occupyapc' : 1})}}
|
||||
{{else data.malfStatus == 3}}
|
||||
{{:helper.link('Return to Main Core', 'arrow-left', {'deoccupyapc' : 1})}}
|
||||
{{else data.malfStatus == 4}}
|
||||
{{:helper.link('Shunt Core Processes', 'arrow-down', {'occupyapc' : 1}, 'linkOff')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Night Shift Lighting:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.locked}}
|
||||
{{if data.nightshiftLights}}
|
||||
<span class='good'>On</span>
|
||||
{{else}}
|
||||
<span class='bad'>Off</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{:helper.link('Enabled', 'lightbulb-o', {'toggle_nightshift' : 1}, data.nightshiftLights ? 'selected' : null)}}{{:helper.link('Disabled', 'lightbulb-o', {'toggle_nightshift' : 1}, data.nightshiftLights ? null : 'selected')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,158 +0,0 @@
|
||||
{{if data.menu == 0}}
|
||||
<h3>Tank Status</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Tank Label:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
<div style="float: left; width: 180px;">{{:data.name}}</div> {{:helper.link('Relabel', 'pencil', {'choice' : 'menu', 'mode_target' : 1}, data.canLabel ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Tank Pressure:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.smoothRound(data.tankPressure)}} kPa
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Port Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:data.portConnected ? '<span class="good">Connected</span>' : '<span class="average">Disconnected</span>'}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Holding Tank Status</h3>
|
||||
{{if data.hasHoldingTank}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Tank Label:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
<div style="float: left; width: 180px;">{{:data.holdingTank.name}}</div> {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Tank Pressure:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.smoothRound(data.holdingTank.tankPressure)}} kPa
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item"><span class="average"><i>No holding tank inserted.</i></span></div>
|
||||
<div class="item"> </div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
<h3>Release Valve Status</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Release Pressure:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure)}}
|
||||
<div style="clear: both; padding-top: 4px;">
|
||||
{{:helper.link('-', null, {'pressure_adj' : -1000}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'pressure_adj' : -100}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'pressure_adj' : -10}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'pressure_adj' : -1}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
|
||||
<div style="float: left; width: 80px; text-align: center;"> {{:data.releasePressure}} kPa </div>
|
||||
{{:helper.link('+', null, {'pressure_adj' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'pressure_adj' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'pressure_adj' : 100}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'pressure_adj' : 1000}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Release Valve:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('Open', 'unlock', {'toggle' : 1}, data.valveOpen ? 'selected' : null)}}{{:helper.link('Close', 'lock', {'toggle' : 1}, data.valveOpen ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{:helper.link('Go back', 'home', {'choice' : 'menu', 'mode_target' : 0}, null)}}
|
||||
<h3>Relabel</h3>
|
||||
<div class="itemLabel">
|
||||
Name:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
<div style="float: left; width: 180px;">{{:data.name}}</div> {{:helper.link('Rename', 'pencil', {'rename' : 1}, data.canLabel ? null : 'disabled')}}
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Colors</h3>
|
||||
<div class="item" style='width: 100%'>
|
||||
<div style='float: left; width: 175px; min-height: 210px'>
|
||||
<div class='average'><b>{{:data.colorContainer.prim.name}}</b></div>
|
||||
{{for data.colorContainer.prim.options}}
|
||||
<div class='itemContentWide'>
|
||||
{{if value.icon == data.canister_color.prim}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.prim.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
|
||||
{{else}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.prim.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div style='float: left; width: 175px; min-height: 210px'>
|
||||
<div class='average'><b>{{:data.colorContainer.sec.name}}</b></div>
|
||||
{{:helper.link("None", '', {'choice' : data.colorContainer.sec.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.sec.anycolor ? null : 'selected')}}
|
||||
{{for data.colorContainer.sec.options}}
|
||||
<div class='itemContentWide'>
|
||||
{{if value.icon == data.canister_color.sec}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.sec.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
|
||||
{{else}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.sec.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div style='float: left; width: 175px; min-height: 210px'>
|
||||
<div class='average'><b>{{:data.colorContainer.ter.name}}</b></div>
|
||||
{{:helper.link("None", '', {'choice' : data.colorContainer.ter.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.ter.anycolor ? null : 'selected')}}
|
||||
{{for data.colorContainer.ter.options}}
|
||||
<div class='itemContentWide'>
|
||||
{{if value.icon == data.canister_color.ter}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.ter.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
|
||||
{{else}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.ter.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div style='float: left; width: 175px; min-height: 210px'>
|
||||
<div class='average'><b>{{:data.colorContainer.quart.name}}</b></div>
|
||||
{{:helper.link("None", '', {'choice' : data.colorContainer.quart.name, 'icon' : "none"}, data.canLabel ? null : 'disabled', data.colorContainer.quart.anycolor ? null : 'selected')}}
|
||||
{{for data.colorContainer.quart.options}}
|
||||
<div class='itemContentWide'>
|
||||
{{if value.icon == data.canister_color.quart}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.quart.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', 'selected')}}
|
||||
{{else}}
|
||||
{{:helper.link(value.name, '', {'choice' : data.colorContainer.quart.name, 'icon' : value.icon}, data.canLabel ? null : 'disabled', null)}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
<h3>Decals</h3>
|
||||
<div style='float: left; width: 175px; min-height: 110px'>
|
||||
<div class='average'><b>Pick and choose:</b></div>
|
||||
<div class='itemContentWide'>
|
||||
{{for data.possibleDecals}}
|
||||
{{:helper.link(value.name, '', {'choice' : 'decals', 'icon' : value.icon}, data.canLabel ? null : 'disabled', value.active ? 'selected' : null)}}
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,93 +0,0 @@
|
||||
<!--
|
||||
Title: Chem Dispenser 5000 UI
|
||||
Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
|
||||
-->
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Energy:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.energy, 0, data.maxEnergy, 'good', data.energy + ' Units')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Dispense:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('1', 'gear', {'amount' : 1}, (data.amount == 1) ? 'selected' : null)}}
|
||||
{{:helper.link('5', 'gear', {'amount' : 5}, (data.amount == 5) ? 'selected' : null)}}
|
||||
{{:helper.link('10', 'gear', {'amount' : 10}, (data.amount == 10) ? 'selected' : null)}}
|
||||
{{:helper.link('20', 'gear', {'amount' : 20}, (data.amount == 20) ? 'selected' : null)}}
|
||||
{{:helper.link('30', 'gear', {'amount' : 30}, (data.amount == 30) ? 'selected' : null)}}
|
||||
{{:helper.link('50', 'gear', {'amount' : 50}, (data.amount == 50) ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 100%;">
|
||||
{{if data.glass}}
|
||||
Drink Dispenser
|
||||
{{else}}
|
||||
Chemical Dispenser
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide" style="width: 100%;">
|
||||
{{for data.chemicals}}
|
||||
{{:helper.link(value.title, 'arrow-circle-down', value.commands, null, data.glass ? 'fixedLeftWide' : 'fixedLeft')}}
|
||||
{{/for}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
{{if data.glass}}
|
||||
Glass
|
||||
{{else}}
|
||||
Beaker
|
||||
{{/if}} Contents
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.glass ? 'Eject Glass' : 'Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled', 'floatRight')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="statusDisplay" style="min-height: 180px;">
|
||||
<div class="item">
|
||||
<div class="itemContent" style="width: 100%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{if data.beakerCurrentVolume}}
|
||||
<span class="floatRight" style="width: 115px;"><b>Dispose:</b></span>
|
||||
{{/if}}
|
||||
<b>Volume: {{:data.beakerCurrentVolume}} / {{:data.beakerMaxVolume}}</b><br>
|
||||
{{for data.beakerContents}}
|
||||
<div style="min-height: 22px;">
|
||||
<div class="floatLeft">
|
||||
<span class="highlight">
|
||||
{{:value.volume}} units of {{:value.name}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="floatRight">
|
||||
{{:helper.link('Isolate', null, {'remove' : value.id, 'removeamount' : -1})}}
|
||||
{{:helper.link('1', null, {'remove' : value.id, 'removeamount' : 1})}}
|
||||
{{:helper.link('5', null, {'remove' : value.id, 'removeamount' : 5})}}
|
||||
{{:helper.link('10', null, {'remove' : value.id, 'removeamount' : 10})}}
|
||||
{{:helper.link('ALL', null, {'remove' : value.id, 'removeamount' : value.volume})}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:2px"></div> <!-- This is necessary to prevent the link margins from hitting each other and causing weird things to happen. It's essentialy a smaller <br> tag. -->
|
||||
{{empty}}
|
||||
<span class="bad">{{if data.glass}}Glass{{else}}Beaker{{/if}} is empty
|
||||
</span>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<span class="average"><i>
|
||||
No {{if data.glass}}Glass{{else}}Beaker{{/if}} loaded
|
||||
</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,47 +0,0 @@
|
||||
<!--
|
||||
Title: ChemHeater UI
|
||||
Used In File(s): \code\modules\reagents\newchem\chem_heater.dm
|
||||
-->
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.isActive ? 'On' : 'Off', 'power-off', {'toggle_on' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Target:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.targetTemp + 'K', 'gear', {'adjust_temperature' : 'input'}, null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Beaker
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('Eject', 'eject', {'eject_beaker' : 1}, data.isBeakerLoaded ? null : 'disabled', 'floatRight')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="statusDisplay">
|
||||
<div style="height: 110px; overflow: auto;">
|
||||
<div class="item">
|
||||
<div class="itemContent">
|
||||
<div style="width: 100%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
<b>Volume: {{:helper.smoothRound(data.beakerCurrentVolume)}} / {{:data.beakerMaxVolume}}</b><br>
|
||||
<b>Temperature: {{:helper.smoothRound(data.currentTemp)}} Kelvin</b><br>
|
||||
{{for data.beakerContents}}
|
||||
<span class="highlight">{{:value.volume}} units of {{:value.name}}</span><br>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,106 +0,0 @@
|
||||
{{if data.beaker}}
|
||||
<div class='item'>{{:helper.link('Eject Beaker and Clear Buffer', 'eject', {'eject': 1})}}</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>Add to buffer:</h3>
|
||||
{{for data.beaker_reagents}}
|
||||
<div class='line'>
|
||||
<div class='itemLabel'>{{:value.name}}, {{:value.volume}} units</div>
|
||||
{{:helper.link('Analyze', 'search', {'analyze': 1, 'desc': value.description, 'name': value.name})}}
|
||||
{{:helper.link('1', 'plus', {'add': value.id, 'amount': 1})}}
|
||||
{{:helper.link('5', 'plus', {'add': value.id, 'amount': 5})}}
|
||||
{{:helper.link('10', 'plus', {'add': value.id, 'amount': 10})}}
|
||||
{{:helper.link('All', 'plus', {'add': value.id, 'amount': value.volume})}}
|
||||
{{:helper.link('Custom', 'plus', {'addcustom': value.id})}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>
|
||||
<div class='item'>
|
||||
Transfer to {{:helper.link(data.mode ? 'beaker' : 'disposal', 'arrows-h', {'toggle': 1})}}
|
||||
</div>
|
||||
</h3>
|
||||
{{for data.buffer_reagents}}
|
||||
<div class='line'>
|
||||
<div class='itemLabel'>{{:value.name}}, {{:value.volume}} units</div>
|
||||
{{:helper.link('Analyze', 'search', {'analyze': 1, 'desc': value.description, 'name': value.name})}}
|
||||
{{:helper.link('1', 'plus', {'remove': value.id, 'amount': 1})}}
|
||||
{{:helper.link('5', 'plus', {'remove': value.id, 'amount': 5})}}
|
||||
{{:helper.link('10', 'plus', {'remove': value.id, 'amount': 10})}}
|
||||
{{:helper.link('All', 'plus', {'remove': value.id, 'amount': value.volume})}}
|
||||
{{:helper.link('Custom', 'plus', {'removecustom': value.id})}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div class='statusDisplay'>
|
||||
<h3>Containers:</h3>
|
||||
<div class='item'>
|
||||
{{if data.condi}}
|
||||
{{:helper.link('Create pack (10u max)', 'arrow-right', {'createpill': 1})}}
|
||||
{{:helper.link('Create bottle (50u max)', 'arrow-right', {'createbottle': 1})}}
|
||||
{{else}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create pill (100u max)', 'arrow-right', {'createpill': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Multiple', 'arrow-right', {'createpill_multiple': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Style', 'pencil', {'change_pill': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
<img src='pill{{:data.pillsprite}}.png'>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create patch (30u max)', 'arrow-right', {'createpatch': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Multiple', 'arrow-right', {'createpatch_multiple': 1})}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Create bottle (50u max)', 'arrow-right', {'createbottle': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Style', 'pencil', {'change_bottle': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
<img src='{{:data.bottlesprite}}.png'>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<span class='item'>No beaker loaded</span><br>
|
||||
{{/if}}
|
||||
<div class='statusDisplay'>
|
||||
<span class='item'>
|
||||
{{if data.loaded_pill_bottle}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('Pill Bottle (' + data.loaded_pill_bottle_contents_len + '/' + data.loaded_pill_bottle_storage_slots + ')', 'eject', {'ejectp': 1})}}
|
||||
</td>
|
||||
<td>
|
||||
{{:helper.link('Change Wrapper', 'pencil', {'change_pillbottle': 1})}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{else}}
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{:helper.link('No Pill Bottle', 'eject', {}, 'disabled')}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{/if}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -1,148 +0,0 @@
|
||||
<!--
|
||||
Title: Cloning Console UI
|
||||
Used In File(s): \code\game\machinery\computer\cloning.dm
|
||||
-->
|
||||
<div class="block">
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Menu</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Main', 'home', {'menu' : 1}, data.menu == 1 ? 'selected' : '')}}{{:helper.link('Records', 'folder-open', {'menu' : 2}, data.menu == 2 ? 'selected' : '')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Refresh</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Refresh', 'refresh', {'refresh' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Autoprocessing</div>
|
||||
<div class="itemContentWide">
|
||||
{{if data.autoallowed}}
|
||||
{{:helper.link('Enabled', 'check', {'task' : 'autoprocess'}, data.autoprocess ? 'selected' : '')}}{{:helper.link('Disabled', 'close', {'task' : 'stopautoprocess'}, !data.autoprocess ? 'selected' : '')}}
|
||||
{{else}}
|
||||
{{:helper.link('Enabled', 'check', null, 'disabled')}}{{:helper.link('Disabled', 'close', null, 'selected')}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.disk}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Disk</div>
|
||||
<div class="itemContentWide">{{:helper.link('Eject', 'eject', {'disk' : 'eject'})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if data.menu == 1}}
|
||||
<h2>Modules</h2>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scanner</div>
|
||||
<div class="itemContentWide{{if data.scanner}} good{{else}} bad{{/if}}">
|
||||
{{if data.scanner}} Found!{{else}} Error: Not detected!{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Pods</div>
|
||||
<div class="itemContentWide{{if data.numberofpods}} good{{else}} bad{{/if}}">
|
||||
{{if data.numberofpods}} Found {{:data.numberofpods}}!{{else}} Error: None detected!{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.scanner}}
|
||||
<h2>Scanner Functions</h2>
|
||||
{{if data.loading}}
|
||||
<b>Scanning...</b>
|
||||
{{else}}
|
||||
<b>{{:data.scantemp}}</b>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scan Occupant</div>
|
||||
<div class="itemContentWide">{{:helper.link('Scan', 'search', {'scan' : 1}, !data.occupant ? 'disabled' : '')}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scanner Lock</div>
|
||||
<div class="itemContentWide">{{if data.occupant}}{{:helper.link('Engaged', 'lock', {'lock' : 1}, data.locked ? 'selected' : '')}}{{else}} {{:helper.link('Engaged', 'lock', null, 'disabled')}}{{/if}}{{:helper.link('Disengaged', 'unlock', {'lock' : 1}, !data.locked ? 'selected' : '')}}</div>
|
||||
</div>
|
||||
{{if data.can_brainscan}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Scan Mode</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Brain', null, {'toggle_mode' : 1}, !data.scan_mode ? '' : 'selected')}}{{:helper.link('Body', null, {'toggle_mode' : 1}, data.scan_mode ? '' : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.numberofpods}}
|
||||
<h2>Pods</h2>
|
||||
{{for data.pods}}
|
||||
<b>{{:value.name}}</b></br>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Biomass</div>
|
||||
<div class="itemContentWide{{if value.biomass > 0}} good{{else}} bad{{/if}}">
|
||||
{{:value.biomass}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Select</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Select', 'check', {'selectpod' : value.pod}, value.pod == data.selected_pod ? 'selected' : '')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.menu == 2}}
|
||||
<h2>Current Records</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{for data.records}}
|
||||
<div>{{:helper.link(value.realname, 'arrow-circle-down', {'view_rec' : value.record})}}</div>
|
||||
{{empty}}
|
||||
No records found!
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
{{if data.menu == 3}}
|
||||
<h2>Selected Record</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if !data.activerecord}}
|
||||
<div class="bad">Error: Record not found!</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<b>Real Name:</b> {{:data.realname}}<br />
|
||||
<b>Health:</b> {{:data.health}} (<span class="oxyloss_light">OXY</span> - <span class="burn">BURN</span> - <span class="toxin_light">TOX</span> - <span class="brute">BRUTE</span>)
|
||||
</div>
|
||||
<div class="item">
|
||||
<b>UI:</b> {{:data.unidentity}}<br />
|
||||
<b>SE:</b> <div style="word-wrap: break-word;">{{:data.strucenzymes}}</div>
|
||||
</div>
|
||||
{{if data.disk}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Disk</div>
|
||||
<div class="itemContentWide">{{:helper.link('Load from Disk', 'floppy-o', {'disk' : 'load'})}}{{:helper.link('Save UI + UE', 'arrow-circle-up', {'save_disk' : 'ue'})}}{{:helper.link('Save UI', 'arrow-circle-up', {'save_disk' : 'ui'})}}{{:helper.link('Save SE', 'arrow-circle-up', {'save_disk' : 'se'})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">Actions</div>
|
||||
<div class="itemContentWide">{{:helper.link('Clone', 'arrow-right', {'clone' : data.activerecord}, !data.podready ? 'disabled' : '')}}{{:helper.link('Delete', 'trash', {'del_rec' : 1})}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if data.menu == 4}}
|
||||
<h2>Confirm Record Deletion</h2>
|
||||
{{if data.temp}}
|
||||
<div class="item">
|
||||
{{:data.temp}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
{{:helper.link('Scan Card and Confirm', 'trash', {'del_rec' : 1})}}{{:helper.link('Cancel', 'close', {'menu' : 3})}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<!--
|
||||
Title: Cryo Cell Status UI
|
||||
Used In File(s): \code\game\machinery\cryo.dm
|
||||
-->
|
||||
<h3>Cryo Cell Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Cell Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} <i class="fa fa-arrow-right"></i>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if data.occupant.stat < 2}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<br>
|
||||
<hr>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Cell Temperature:</div><div class="statusValue">
|
||||
<span class="{{:data.cellTemperatureStatus}}">{{:helper.smoothRound(data.cellTemperature)}} K</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Cryo Cell Operation</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Cryo Cell Status:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{:helper.link('On', 'power-off', {'switchOn' : 1}, data.isOperating ? 'selected' : null)}}{{:helper.link('Off', 'close', {'switchOff' : 1}, data.isOperating ? null : 'selected')}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectOccupant' : 1}, data.hasOccupant ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Beaker:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{:data.beakerLabel ? data.beakerLabel : '<span class="average">No label</span>'}}<br>
|
||||
{{if data.beakerVolume}}
|
||||
<span class="highlight">{{:helper.smoothRound(data.beakerVolume)}} units remaining</span><br>
|
||||
{{else}}
|
||||
<span class="bad">Beaker is empty</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject healthy patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_healthy_on' : 1}, data.auto_eject_healthy ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_healthy_off' : 0}, data.auto_eject_healthy ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject dead patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_dead_on' : 1}, data.auto_eject_dead ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_dead_off' : 0}, data.auto_eject_dead ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,313 +0,0 @@
|
||||
<!--
|
||||
Title: DNA Modifier UI
|
||||
Used In File(s): D:\Development\SS13-BS12\code\game\dna\dna_modifier.dm
|
||||
-->
|
||||
<h3>Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Cell Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if !data.occupant.isViableSubject || !data.occupant.uniqueIdentity || !data.occupant.structuralEnzymes}}
|
||||
<div class="notice">
|
||||
The occupant's DNA structure is ruined beyond recognition, please insert a subject with an intact DNA structure.
|
||||
</div>
|
||||
{{else data.occupant.stat < 2}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Radiation:</div>
|
||||
{{:helper.displayBar(data.occupant.radiationLevel, 0, 100, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.radiationLevel)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Unique Enzymes:</div>
|
||||
<div class="statusValue">{{:data.occupant.uniqueEnzymes ? data.occupant.uniqueEnzymes : '<span class="bad">Unknown</span>'}}</div>
|
||||
</div>
|
||||
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="clearBoth"></div>
|
||||
</div>
|
||||
|
||||
<h3>Operations</h3>
|
||||
{{if !data.occupant.isViableSubject || !data.occupant.uniqueIdentity || !data.occupant.structuralEnzymes}}
|
||||
<div class="notice">
|
||||
No operation possible on this subject
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
{{:helper.link('Modify U.I.', 'link', {'selectMenuKey' : 'ui'}, data.selectedMenuKey == 'ui' ? 'selected' : null)}}
|
||||
{{:helper.link('Modify S.E.', 'link', {'selectMenuKey' : 'se'}, data.selectedMenuKey == 'se' ? 'selected' : null)}}
|
||||
{{:helper.link('Transfer Buffers', 'floppy-o', {'selectMenuKey' : 'buffer'}, data.selectedMenuKey == 'buffer' ? 'selected' : null)}}
|
||||
{{:helper.link('Rejuvenators', 'plus', {'selectMenuKey' : 'rejuvenators'}, data.selectedMenuKey == 'rejuvenators' ? 'selected' : null)}}
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
|
||||
{{if !data.selectedMenuKey || data.selectedMenuKey == 'ui'}}
|
||||
<h3>Modify Unique Identifier</h3>
|
||||
{{:helper.displayDNABlocks(data.occupant.uniqueIdentity, data.selectedUIBlock, data.selectedUISubBlock, data.dnaBlockSize, 'UI')}}
|
||||
<div class="clearBoth"></div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Target:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'changeUITarget' : 0}, (data.selectedUITarget > 0) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.selectedUITargetHex}} </div>
|
||||
{{:helper.link('+', null, {'changeUITarget' : 1}, (data.selectedUITarget < 15) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Irradiate Block', 'exclamation-circle', {'pulseUIRadiation' : 1}, !data.occupant.isViableSubject ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'se'}}
|
||||
<h3>Modify Structural Enzymes</h3>
|
||||
{{:helper.displayDNABlocks(data.occupant.structuralEnzymes, data.selectedSEBlock, data.selectedSESubBlock, data.dnaBlockSize, 'SE')}}
|
||||
<div class="clearBoth"></div>
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Irradiate Block', 'exclamation-circle', {'pulseSERadiation' : 1}, !data.occupant.isViableSubject ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'buffer'}}
|
||||
<h3>Transfer Buffers</h3>
|
||||
{{for data.buffers}}
|
||||
<h4>Buffer {{:(index + 1)}}</h4>
|
||||
<div class="itemGroup">
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Load Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Subject U.I.', 'link', {'bufferOption' : 'saveUI', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Subject U.I. + U.E.', 'link', {'bufferOption' : 'saveUIAndUE', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Subject S.E.', 'link', {'bufferOption' : 'saveSE', 'bufferId' : (index + 1)}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('From Disk', 'floppy-o', {'bufferOption' : 'loadDisk', 'bufferId' : (index + 1)}, (!data.hasDisk || !data.disk.data) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{if value.data}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Label:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link(value.label, 'file', {'bufferOption' : 'changeLabel', 'bufferId' : (index + 1)})}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Subject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:value.owner ? value.owner : '<span class="average">Unknown</span>'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Stored Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:value.data == 'ui' ? 'Unique Identifiers' : 'Structural Enzymes'}}
|
||||
{{:value.ue ? ' + Unique Enzymes' : ''}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="highlight">This buffer is empty.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Options:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Clear', 'trash', {'bufferOption' : 'clear', 'bufferId' : (index + 1)}, !value.data ? 'disabled' : null)}}
|
||||
{{:helper.link('Injector', data.isInjectorReady ? 'pencil' : 'clock-o', {'bufferOption' : 'createInjector', 'bufferId' : (index + 1)}, (!data.isInjectorReady || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Block Injector', data.isInjectorReady ? 'pencil' : 'clock-o', {'bufferOption' : 'createInjector', 'bufferId' : (index + 1), 'createBlockInjector' : 1}, (!data.isInjectorReady || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Transfer', 'exclamation-circle', {'bufferOption' : 'transfer', 'bufferId' : (index + 1)}, (!data.hasOccupant || !value.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Save To Disk', 'floppy-o', {'bufferOption' : 'saveDisk', 'bufferId' : (index + 1)}, (!value.data || !data.hasDisk) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
|
||||
<h4>Data Disk</h4>
|
||||
<div class="itemGroup">
|
||||
{{if data.hasDisk}}
|
||||
{{if data.disk.data}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Label:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.label ? data.disk.label : 'No Label'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Subject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.owner ? data.disk.owner : '<span class="average">Unknown</span>'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Stored Data:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:data.disk.data == 'ui' ? 'Unique Identifiers' : 'Structural Enzymes'}}
|
||||
{{:data.disk.ue ? ' + Unique Enzymes' : ''}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="average">Disk is blank.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemContentWide">
|
||||
<span class="highlight">No disk inserted.</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Options:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Wipe Disk', 'trash', {'bufferOption' : 'wipeDisk'}, (!data.hasDisk || !data.disk.data) ? 'disabled' : null)}}
|
||||
{{:helper.link('Eject Disk', 'eject', {'bufferOption' : 'ejectDisk'}, !data.hasDisk ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else data.selectedMenuKey == 'rejuvenators'}}
|
||||
<h3>Rejuvenators</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Inject:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('5', 'pencil', {'injectRejuvenators' : 5}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('10', 'pencil', {'injectRejuvenators' : 10}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('20', 'pencil', {'injectRejuvenators' : 20}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('30', 'pencil', {'injectRejuvenators' : 30}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
{{:helper.link('50', 'pencil', {'injectRejuvenators' : 50}, (!data.hasOccupant || !data.beakerVolume) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Beaker:
|
||||
</div>
|
||||
<div class="itemContentWide" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{:data.beakerLabel ? data.beakerLabel : '<span class="average">No label</span>'}}<br>
|
||||
{{if data.beakerVolume}}
|
||||
<span class="highlight">{{:data.beakerVolume}} units remaining</span><br>
|
||||
{{else}}
|
||||
<span class="bad">Beaker is empty</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContentWide" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="item"> </div>
|
||||
|
||||
{{if !data.selectedMenuKey || data.selectedMenuKey == 'ui' || data.selectedMenuKey == 'se'}}
|
||||
<h3>Radiation Emitter Settings</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Intensity:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'radiationIntensity' : 0}, (data.radiationIntensity > 1) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.radiationIntensity}} </div>
|
||||
{{:helper.link('+', null, {'radiationIntensity' : 1}, (data.radiationIntensity < 10) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Duration:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('-', null, {'radiationDuration' : 0}, (data.radiationDuration > 2) ? null : 'disabled')}}
|
||||
<div class="statusValue"> {{:data.radiationDuration}} </div>
|
||||
{{:helper.link('+', null, {'radiationDuration' : 1}, (data.radiationDuration < 20) ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Pulse Radiation', 'exclamation-circle', {'pulseRadiation' : 1}, !data.hasOccupant ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<div class="item"> </div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Occupant:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Eject Occupant', 'eject', {'ejectOccupant' : 1}, data.locked || !data.hasOccupant || data.irradiating ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Door Lock:
|
||||
</div>
|
||||
<div class="itemContentWide">
|
||||
{{:helper.link('Engaged', 'lock', {'toggleLock' : 1}, data.locked ? 'selected' : !data.hasOccupant ? 'disabled' : null)}}
|
||||
{{:helper.link('Disengaged', 'unlock', {'toggleLock' : 1}, !data.locked ? 'selected' : data.irradiating ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if data.irradiating}}
|
||||
<div class="mask">
|
||||
<div class="maskContent">
|
||||
<h1>Irradiating Subject</h1>
|
||||
<h3>For {{:data.irradiating}} seconds.</h3>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,69 +0,0 @@
|
||||
<style type="text/css">
|
||||
.fixedCell {
|
||||
width: 78px;
|
||||
}
|
||||
|
||||
.fixedCellWide {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
|
||||
min-width: 70px;
|
||||
margin: 0px 2px 0px 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelWider">
|
||||
Main power is
|
||||
{{if data.main_power_loss == 0}}
|
||||
online
|
||||
{{else data.main_power_loss == -1}}
|
||||
offline
|
||||
{{else}}
|
||||
offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}}
|
||||
{{/if}}.
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelWider">
|
||||
Backup power is
|
||||
{{if data.backup_power_loss == 0}}
|
||||
online
|
||||
{{else data.backup_power_loss == -1}}
|
||||
offline
|
||||
{{else}}
|
||||
offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}}
|
||||
{{/if}}.
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelWidest">
|
||||
Electrified Status:
|
||||
</div>
|
||||
<div class="itemContentWidest">
|
||||
{{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, data.electrified == 0 ? 'selected' : null)}}
|
||||
{{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, null, data.electrified > 0 ? 'redButton' : null)}}
|
||||
{{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, data.electrified == -1 ? 'redButton' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<table>
|
||||
{{for data.commands}}
|
||||
<tr>
|
||||
<td class='itemLabel fixedCellWide'>{{:value.name}}:</td>
|
||||
<td class='fixedCell'>{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, value.active ? 'selected' : null)}}</td>
|
||||
<td class='fixedCell'>{{:helper.link(value.disabled, null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, !value.active ? (value.danger ? 'redButton' : 'selected') : null)}}</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</table>
|
||||
@@ -1,171 +0,0 @@
|
||||
<!--
|
||||
Title: Medical Records UI
|
||||
Used In File(s): \code\game\machinery\computer\medical.dm
|
||||
-->
|
||||
|
||||
<!--
|
||||
#define MED_DATA_MAIN 1 // Main menu
|
||||
#define MED_DATA_R_LIST 2 // Record list
|
||||
#define MED_DATA_MAINT 3 // Records maintenance
|
||||
#define MED_DATA_RECORD 4 // Record
|
||||
#define MED_DATA_V_DATA 5 // Virus database
|
||||
#define MED_DATA_MEDBOT 6 // Medbot monitor
|
||||
-->
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
<b>Confirm Identity:</b>
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{if data.authenticated}}
|
||||
{{if data.screen == 1}} <!-- MED_DATA_MAIN -->
|
||||
<h3>Menu</h3>
|
||||
<div class="item">
|
||||
<div class="line">{{:helper.link('Search Records', 'search', {'search' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('List Records', 'list', {'screen' : 2})}}</div>
|
||||
<div class="line">{{:helper.link('Virus Database', 'database', {'screen' : 5})}}</div>
|
||||
<div class="line">{{:helper.link('Medbot Tracking', 'plus-square', {'screen' : 6})}}</div>
|
||||
<div class="line">{{:helper.link('Record Maintenance', 'wrench', {'screen' : 3})}}</div>
|
||||
<div class="line">{{:helper.link('Logout', 'lock', {'logout' : 1})}}</div>
|
||||
</div>
|
||||
{{else data.screen == 2}} <!-- MED_DATA_R_LIST -->
|
||||
<h3><center>Record List</center></h3>
|
||||
{{for data.records}}
|
||||
<div class="line">{{:helper.link(value.id + ': ' + value.name, 'user', {'d_rec' : value.ref})}}</div>
|
||||
{{/for}}
|
||||
<br><hr>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{else data.screen == 3}} <!-- MED_DATA_MAINT -->
|
||||
<h3>Records Maintenance</h3>
|
||||
<div class="line">{{:helper.link('Backup To Disk', 'download', {'back' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Upload From disk', 'upload', {'u_load' : 1}, 'disabled')}}</div>
|
||||
<div class="line">{{:helper.link('Delete All Records', 'trash', {'del_all' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{else data.screen == 4}} <!-- MED_DATA_RECORD -->
|
||||
<h3><center>Medical Record</center></h3>
|
||||
<h4><center>General Data</center></h4>
|
||||
{{if data.general.empty}}
|
||||
<span class="bad"><center>General Record Lost!</center></span>
|
||||
{{else}}
|
||||
<div class="statusDisplayRecords">
|
||||
<table style='width:100%'><tr>
|
||||
<td valign='top' style='margin-right: 300px;'>
|
||||
{{for data.general.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">{{:value.field}}</div>
|
||||
<div class="itemContent">{{:helper.link(value.value, value.edit ? 'pencil' : 'user-times', {'field' : value.edit}, value.edit ? null : 'disabled')}}</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
</td>
|
||||
<td valign='middle' align='center' style='width: 300px;'>
|
||||
{{if data.general.has_photos}}
|
||||
{{for data.general.photos}}
|
||||
{{if value.photo}}
|
||||
<img src={{:value.photo}} height=96 width=96 border=5>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<h4><center>Medical Data</center></h4>
|
||||
{{if data.medical.empty}}
|
||||
<span class="bad"><center>Medical Record Lost!</center></span>
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('New Record', 'plus', {'new' : 1})}}</div>
|
||||
</div>
|
||||
<h3><center>Menu</center></h3>
|
||||
{{else}}
|
||||
{{for data.medical.fields}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">{{:value.field}}</div>
|
||||
<div class="itemContent">{{:helper.link(value.value, 'pencil', {'field' : value.edit})}}</div>
|
||||
</div>
|
||||
{{if value.line_break}}
|
||||
<br>
|
||||
{{/if}}
|
||||
{{/for}}
|
||||
|
||||
<h4><center>Comments/Log</center></h4>
|
||||
{{for data.medical.comments}}
|
||||
<div class="line">{{:value}}</div>
|
||||
<div class="line">{{:helper.link('Remove entry', 'trash', {'del_c' : index})}}</div>
|
||||
<br><hr>
|
||||
{{/for}}
|
||||
|
||||
<div style="text-align: center;">
|
||||
<div style="display: inline-block;">{{:helper.link('Add Entry', 'plus', {'add_c' : 1})}}</div>
|
||||
</div>
|
||||
|
||||
<h3><center>Menu</center></h3>
|
||||
<div class="line">{{:helper.link('Delete Record (Medical Only)', 'trash', {'del_r' : 1})}}</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="line">{{:helper.link('Print Record', 'print', {'print_p' : 1})}}</div>
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 2})}}</div>
|
||||
{{else data.screen == 5}} <!-- MED_DATA_V_DATA -->
|
||||
<h3><center>Virus Database</center></h3>
|
||||
{{for data.virus}}
|
||||
<div class="line">{{:helper.link(value.name, 'arrow-right', {'vir' : value.D})}}</div>
|
||||
{{/for}}
|
||||
<br><hr>
|
||||
{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
|
||||
{{else data.screen == 6}} <!-- MED_DATA_MEDBOT -->
|
||||
<h3><center>Medical Robot Monitor</center></h3>
|
||||
{{for data.medbots}}
|
||||
<h4>{{:value.name}}</h4>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Location:</div>
|
||||
<div class="itemContent">{{:value.x}}, {{:value.y}}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Status:</div>
|
||||
<div class="itemContent">
|
||||
{{:value.on ? "<span class='good'>Online</span>" : "<span class='average'>Offline</span>"}}. {{if value.use_beaker}}Reservoir: [{{:value.total_volume}}/{{:value.maximum_volume}}]{{else}}Using internal synthesizer.{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
{{empty}}
|
||||
<h4 class="bad"><center>None detected!</center></h4>
|
||||
{{/for}}
|
||||
<div class="line">{{:helper.link('Back', 'arrow-left', {'screen' : 1})}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<h3>Menu</h3>
|
||||
{{:helper.link('Login', 'unlock', {'login' : 1})}}
|
||||
{{/if}}
|
||||
|
||||
{{if data.temp}}
|
||||
<div class="mask" style="display: table;">
|
||||
<div class="maskContent" style="margin: 0px; vertical-align: middle; align:center; display: table-cell;">
|
||||
{{if data.temp.notice}}
|
||||
<div class="notice"><center>{{:data.temp.text}}</center></div>
|
||||
{{else}}
|
||||
<center>{{:data.temp.text}}</center>
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{if data.temp.has_buttons}}
|
||||
<div class="line">
|
||||
<div style="display: inline-block;">
|
||||
<div style="width: 500px; display: flex; display: -webkit-flex; flex-wrap: wrap; -webkit-flex-wrap: wrap; justify-content: center; -webkit-justify-content: center;">
|
||||
{{for data.temp.buttons}}
|
||||
{{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.href}, value.status)}}
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div style="display: inline-block;">
|
||||
<div class="item">{{:helper.link('Clear screen', 'home', {'temp' : 1})}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,215 +0,0 @@
|
||||
<!--
|
||||
Title: Operating Computer UI
|
||||
Used In File(s): \code\game\machinery\computer\Operating.dm
|
||||
-->
|
||||
<h3>Patient Monitor</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if data.choice==0}}
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">No Patient Detected</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= data.occupant.maxHealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else data.occupant.health > 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'average')}}
|
||||
{{else data.occupant.health >= data.minhealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{if data.occupant.hasBlood}}
|
||||
<br>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{if data.occupant.bloodPercent <= 60}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'bad')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else data.occupant.bloodPercent <= 90}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'average')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'good')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Type:</div> <div class="statusValue">{{:data.occupant.bloodType}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.pulse}} bpm</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if data.occupant.inSurgery}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Initiated Surgery Procedure:</div> <div class="statusValue">{{:data.occupant.surgeryName}}</div>
|
||||
<br>
|
||||
<div class="statusLabel">Next Step:</div> <div class="statusValue">{{:data.occupant.stepName}}</div>
|
||||
|
||||
</div>
|
||||
{{/if}}
|
||||
<br>
|
||||
<br>
|
||||
{{/if}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
{{:helper.link('Options', 'gear', {'choiceOn' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Loudspeaker:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'verboseOn' : 1}, data.verbose ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'verboseOff' : 1}, data.verbose ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Health Announcer:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'healthOn' : 1}, data.health ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'healthOff' : 1}, data.health ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health Announcer Threshold:</div>
|
||||
{{:helper.link('-', null, {'health_adj' : -100}, (data.healthAlarm >= 0) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'health_adj' : -10}, (data.healthAlarm >= -90) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'health_adj' : -1}, (data.healthAlarm > -100) ? null : 'disabled')}}
|
||||
|
||||
{{if data.healthAlarm >= 100}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, 100, 'good')}}
|
||||
{{else data.healthAlarm > 0}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, 100, 'average')}}
|
||||
{{else data.healthAlarm >= -100}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, -100, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.healthAlarm, 0, -100, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
|
||||
{{:helper.link('+', null, {'health_adj' : 1}, (data.healthAlarm < 100) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'health_adj' : 10}, (data.healthAlarm <= 90) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'health_adj' : 100}, (data.healthAlarm <= 0) ? null : 'disabled')}}
|
||||
<div style="float: left; width: 80px; text-align: center;"> {{: data.healthAlarm }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Oxygen Alarm:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'oxyOn' : 1}, data.oxy ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'oxyOff' : 1}, data.oxy ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="line">
|
||||
<div class="statusLabel">Oxygen Alert Threshold:</div>
|
||||
{{:helper.link('-', null, {'oxy_adj' : -100}, (data.oxyAlarm >= 100) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'oxy_adj' : -10}, (data.oxyAlarm >= 10) ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'oxy_adj' : -1}, (data.oxyAlarm >= 0) ? null : 'disabled')}}
|
||||
{{:helper.displayBar( data.oxyAlarm, 0, 200, 'good')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 1}, (data.oxyAlarm < 200) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 10}, (data.oxyAlarm <= 190) ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'oxy_adj' : 100}, (data.oxyAlarm <= 100) ? null : 'disabled')}}
|
||||
<div style="float: left; width: 80px; text-align: center;"> {{: data.oxyAlarm }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Critical Alert:
|
||||
</div>
|
||||
<div class="itemContentNarrow" style="float: left">
|
||||
{{:helper.link('On', 'power-off', {'critOn' : 1}, data.crit ? 'selected' : null)}}
|
||||
{{:helper.link('Off', 'close', {'critOff' : 1}, data.crit ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
{{:helper.link('Return', 'arrow-left', {'choiceOff' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -1,211 +0,0 @@
|
||||
<!--
|
||||
Title: Sleeper Status UI
|
||||
Used In File(s): \code\game\machinery\Sleeper.dm
|
||||
-->
|
||||
<h3>Sleeper Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Sleeper Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} =>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= data.occupant.maxHealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else data.occupant.health > 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'average')}}
|
||||
{{else data.occupant.health >= data.minhealth}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'bad alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel">=> Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="line">
|
||||
<!--
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold3')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold2')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'cold1')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot1')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot2')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'hot3')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
If you can get the changing temperature bars to work right, congratulations
|
||||
-->
|
||||
<div class="statusLabel">Patient Temperature:</div>
|
||||
{{if data.occupant.temperatureSuitability == -3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == -1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 0}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'good')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 1}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 2}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'average')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{else data.occupant.temperatureSuitability == 3}}
|
||||
{{:helper.displayBar(data.occupant.bodyTemperature, 0, data.occupant.maxTemp, 'bad')}}
|
||||
<div class="statusValue bad">{{:helper.smoothRound(data.occupant.btCelsius)}}°C, {{:helper.smoothRound(data.occupant.btFaren)}}°F</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
||||
{{if data.occupant.hasBlood}}
|
||||
|
||||
<br>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.pulse}} bpm</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{if data.occupant.bloodPercent <= 60}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'bad')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else data.occupant.bloodPercent <= 90}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'average')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.bloodLevel, 0, data.occupant.bloodMax, 'good')}}
|
||||
<div class="statusValue">
|
||||
{{:helper.smoothRound(data.occupant.bloodPercent)}}%, {{:helper.smoothRound(data.occupant.bloodLevel)}}cl
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<h3>Sleeper Operation</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Sleeper Status:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectify' : 1}, data.hasOccupant ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Dialysis Beaker:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
<span class="highlight">{{:helper.smoothRound(data.beakerFreeSpace)}} units of space remaining</span><br>
|
||||
{{else}}
|
||||
<span class="average"><i>No Dialysis Output Beaker Loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'removebeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
{{if data.isBeakerLoaded}}
|
||||
<div class="line">
|
||||
<div class="itemContent">
|
||||
{{:helper.link('On', 'power-off', {'togglefilter' : 1}, data.occupant.hasBlood ? (data.dialysis ? 'selected' : null) : 'disabled')}}{{:helper.link('Off', 'close', {'togglefilter' : 1}, data.dialysis ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Chemicals:
|
||||
</div>
|
||||
|
||||
{{for data.chemicals}}
|
||||
<div class="line"><b>{{:value.title}}</b></div>
|
||||
<div class="line">
|
||||
{{if value.overdosing}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'bad')}}
|
||||
{{else value.od_warning}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'average')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(value.occ_amount, 0, data.maxchem, 'good')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(value.pretty_amount)}}/{{:data.maxchem}}</div>
|
||||
<br>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="itemContent">
|
||||
{{:helper.link('5', 'gear', {'chemical' : value.id, 'amount' : 5}, (!value.injectable || ((value.occ_amount + 5) > data.maxchem)) ? 'disabled' : null)}}
|
||||
{{:helper.link('10', 'gear', {'chemical' : value.id, 'amount' : 10}, (!value.injectable || ((value.occ_amount + 10) > data.maxchem)) ? 'disabled' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 35%">
|
||||
Auto-eject dead patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_dead_on' : 1}, data.auto_eject_dead ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_dead_off' : 0}, data.auto_eject_dead ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<!--
|
||||
Title: Slot Machine UI
|
||||
Used In File(s): /code/game/machinery/slotmachine.dm
|
||||
-->
|
||||
{{if data.money != null}}
|
||||
<div class="line">
|
||||
{{:data.plays}} players have tried their luck today!
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Credits Remaining:</div>
|
||||
{{:helper.string("<div class='statusValue {0}'>{1}</div>", data.money >= 10 ? "" : "bad", helper.smoothRound(data.money))}}
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="statusLabel">
|
||||
Ten credits to play!
|
||||
</div>
|
||||
<div class="statusValue">
|
||||
{{:helper.link('SPIN!', 'refresh', {'ops' : 1}, data.money >= 10 && !data.working ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.result}}
|
||||
<div class="line {{:data.resultlvl}}">
|
||||
{{:data.result}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if data.working}}
|
||||
<div class="notice">Spinning!</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="notice">
|
||||
Could not scan your card or could not find account!<br>
|
||||
Please wear or hold your ID and try again.
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -1,89 +0,0 @@
|
||||
<!--
|
||||
Title: Instrument UI
|
||||
Used In File(s): \code\game\objects\structures\musician.dm
|
||||
-->
|
||||
|
||||
<div class="block">
|
||||
<div class="item">
|
||||
<div class="itemLabel"><b>Playback</b></div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('New', 'file', {'newsong': 1})}}
|
||||
{{:helper.link('Import', 'folder-open', {'import': 1})}}
|
||||
{{:helper.link('Play', 'play', {'play': 1}, data.lines.length > 0 ? (data.playing ? 'selected' : null) : 'disabled')}}
|
||||
{{:helper.link('Stop', 'stop', {'stop': 1}, !data.playing ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Repeat Song:</div>
|
||||
{{:helper.link('-', null, {'repeat' : -10}, data.repeat > 0 && !data.playing ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'repeat' : -1}, data.repeat > 0 && !data.playing ? null : 'disabled')}}
|
||||
<span style="float: left; width: 80px; text-align: center;">{{:data.repeat}}</span>
|
||||
{{:helper.link('+', null, {'repeat' : 1}, data.repeat < data.maxRepeat && !data.playing ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'repeat' : 10}, data.repeat < data.maxRepeat && !data.playing ? null : 'disabled')}}
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Tempo:</div>
|
||||
{{:helper.link('-', null, {'tempo' : 10}, data.tempo < data.maxTempo ? null : 'disabled')}}
|
||||
{{:helper.link('-', null, {'tempo' : 1}, data.tempo < data.maxTempo ? null : 'disabled')}}
|
||||
<span style="float: left; width: 80px; text-align: center;">{{:helper.round(600 / data.tempo)}} BPM</span>
|
||||
{{:helper.link('+', null, {'tempo' : -1}, data.tempo > data.minTempo ? null : 'disabled')}}
|
||||
{{:helper.link('+', null, {'tempo' : -10}, data.tempo > data.minTempo ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Editor</h3>
|
||||
<div class="striped">
|
||||
{{for data.lines}}
|
||||
<div class="line" style="padding:4px">
|
||||
<div class="floatLeft highlight">{{:index + 1}}: </div>
|
||||
<div class="floatRight">
|
||||
{{:helper.link('Edit', 'pencil', {'modifyline': index+1}, data.playing ? 'disabled' : null)}}
|
||||
{{:helper.link('Insert', 'arrow-up', {'insertline': index+1}, data.playing ? 'disabled' : null)}}
|
||||
{{:helper.link('Delete', 'trash', {'deleteline': index+1}, data.playing ? 'disabled' : null)}}
|
||||
</div>
|
||||
<div>{{:value}}</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
<div class="floatRight">
|
||||
{{:helper.link('Add Line', 'arrow-down', {'insertline': data.lines.length + 1}, data.playing ? 'disabled' : null)}}
|
||||
</div>
|
||||
<div class="clearBoth"></div>
|
||||
<hr>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
{{:helper.link('Help', data.help ? 'close' : 'question', {'help': 1})}}
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.help}}
|
||||
<p>
|
||||
Lines are a series of chords, separated by commas <span class="highlight">(,)</span>, each with notes seperated by hyphens <span class="highlight">(-)</span>.
|
||||
<br>
|
||||
Every note in a chord will play together, with the chord timed by the <span class="highlight">tempo</span> as defined above.
|
||||
</p>
|
||||
<p>
|
||||
Notes are played by the <span class="good">names of the note</span>, and optionally, the <span class="average">accidental</span>, and/or the <span class="bad">octave number</span>.
|
||||
<br>
|
||||
By default, every note is <span class="average">natural</span> and in <span class="bad">octave 3</span>. Defining a different state for either is remembered for each <span class="good">note</span>.
|
||||
<ul>
|
||||
<li><span class="highlight">Example:</span> <i>C,D,E,F,G,A,B</i> will play a <span class="good">C</span> <span class="average">major</span> scale.</li>
|
||||
<li>After a note has an <span class="average">accidental</span> or <span class="bad">octave</span> placed, it will be remembered: <i>C,C4,C#,C3</i> is <i>C3,C4,C4#,C3#</i></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
<span class="highlight">Chords</span> can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i>.<br>
|
||||
A <span class="highlight">pause</span> may be denoted by an empty chord: <i>C,E,,C,G</i>.
|
||||
<br>
|
||||
To make a chord be a different time, end it with /x, where the chord length will be length defined by <span class="highlight">tempo / x</span>, <span class="highlight">eg:</span> <i>C,G/2,E/4</i>.
|
||||
</p>
|
||||
<p>
|
||||
Combined, an example line is: <i>E-E4/4,F#/2,G#/8,B/8,E3-E4/4</i>.
|
||||
<ul>
|
||||
<li>Lines may be up to 50 characters.</li>
|
||||
<li>A song may only contain up to 50 lines.</li>
|
||||
</ul>
|
||||
</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,72 +0,0 @@
|
||||
<div class="item">
|
||||
Behaviour controls are {{:data.locked ? "locked" : "unlocked"}}.
|
||||
</div>
|
||||
<br>
|
||||
{{if data.access}}
|
||||
{{if !data.screen}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
Turret Status:
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('Enabled', null, {'command' : 'enable', 'value' : 1}, data.enabled ?'redButton' : null)}}
|
||||
{{:helper.link('Disabled',null, {'command' : 'enable', 'value' : 0}, !data.enabled ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{if data.accesses}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
Required Access:
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('Modify', null, {'command' : 'screen', 'value' : 1})}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{if data.lethal_control}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
Lethal Mode:
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('On', null, {'command' : 'lethal', 'value' : 1}, data.lethal ?'redButton' : null)}}
|
||||
{{:helper.link('Off',null, {'command' : 'lethal', 'value' : 0}, !data.lethal ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{for data.settings}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
{{:value.category}}
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('On', null, {'command' : value.setting, 'value' : 1}, value.value ? 'selected' : null)}}
|
||||
{{:helper.link('Off',null, {'command' : value.setting, 'value' : 0}, !value.value ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
{{/for}}
|
||||
{{else}}
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
Turret Settings:
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('Modify', null, {'command' : 'screen', 'value' : 0})}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelWide">
|
||||
Access Type:
|
||||
</div>
|
||||
<div class="itemContentNarrow">
|
||||
{{:helper.link('All', null, {'one_access' : 0}, !data.one_access ? 'selected' : null)}}
|
||||
{{:helper.link('One', null, {'one_access' : 1}, data.one_access ? 'selected' : null)}}
|
||||
</div>
|
||||
</div>
|
||||
<h3>Select Access</h3>
|
||||
{{for data.accesses}}
|
||||
{{:helper.link(value.name, null, {'access' : value.number}, null, value.active ? 'selected' : null)}}
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "code\__DEFINES\genetics.dm"
|
||||
#include "code\__DEFINES\hud.dm"
|
||||
#include "code\__DEFINES\hydroponics.dm"
|
||||
#include "code\__DEFINES\instruments.dm"
|
||||
#include "code\__DEFINES\inventory.dm"
|
||||
#include "code\__DEFINES\is_helpers.dm"
|
||||
#include "code\__DEFINES\job.dm"
|
||||
@@ -71,6 +72,7 @@
|
||||
#include "code\__DEFINES\station_goals.dm"
|
||||
#include "code\__DEFINES\status_effects.dm"
|
||||
#include "code\__DEFINES\subsystems.dm"
|
||||
#include "code\__DEFINES\tgui.dm"
|
||||
#include "code\__DEFINES\tools.dm"
|
||||
#include "code\__DEFINES\typeids.dm"
|
||||
#include "code\__DEFINES\vv.dm"
|
||||
@@ -239,6 +241,7 @@
|
||||
#include "code\controllers\subsystem\parallax.dm"
|
||||
#include "code\controllers\subsystem\radio.dm"
|
||||
#include "code\controllers\subsystem\shuttles.dm"
|
||||
#include "code\controllers\subsystem\sounds.dm"
|
||||
#include "code\controllers\subsystem\spacedrift.dm"
|
||||
#include "code\controllers\subsystem\statistics.dm"
|
||||
#include "code\controllers\subsystem\sun.dm"
|
||||
@@ -251,6 +254,7 @@
|
||||
#include "code\controllers\subsystem\weather.dm"
|
||||
#include "code\controllers\subsystem\processing\dcs.dm"
|
||||
#include "code\controllers\subsystem\processing\fastprocess.dm"
|
||||
#include "code\controllers\subsystem\processing\instruments.dm"
|
||||
#include "code\controllers\subsystem\processing\obj.dm"
|
||||
#include "code\controllers\subsystem\processing\processing.dm"
|
||||
#include "code\controllers\subsystem\tickets\mentor_tickets.dm"
|
||||
@@ -305,6 +309,7 @@
|
||||
#include "code\datums\components\paintable.dm"
|
||||
#include "code\datums\components\slippery.dm"
|
||||
#include "code\datums\components\spawner.dm"
|
||||
#include "code\datums\components\spooky.dm"
|
||||
#include "code\datums\components\squeak.dm"
|
||||
#include "code\datums\components\swarming.dm"
|
||||
#include "code\datums\diseases\_disease.dm"
|
||||
@@ -729,6 +734,7 @@
|
||||
#include "code\game\machinery\computer\salvage_ship.dm"
|
||||
#include "code\game\machinery\computer\security.dm"
|
||||
#include "code\game\machinery\computer\skills.dm"
|
||||
#include "code\game\machinery\computer\sm_monitor.dm"
|
||||
#include "code\game\machinery\computer\specops_shuttle.dm"
|
||||
#include "code\game\machinery\computer\station_alert.dm"
|
||||
#include "code\game\machinery\computer\store.dm"
|
||||
@@ -878,7 +884,6 @@
|
||||
#include "code\game\objects\items\devices\flashlight.dm"
|
||||
#include "code\game\objects\items\devices\floor_painter.dm"
|
||||
#include "code\game\objects\items\devices\handheld_defib.dm"
|
||||
#include "code\game\objects\items\devices\instruments.dm"
|
||||
#include "code\game\objects\items\devices\laserpointer.dm"
|
||||
#include "code\game\objects\items\devices\lightreplacer.dm"
|
||||
#include "code\game\objects\items\devices\machineprototype.dm"
|
||||
@@ -1083,7 +1088,6 @@
|
||||
#include "code\game\objects\structures\misc.dm"
|
||||
#include "code\game\objects\structures\mop_bucket.dm"
|
||||
#include "code\game\objects\structures\morgue.dm"
|
||||
#include "code\game\objects\structures\musician.dm"
|
||||
#include "code\game\objects\structures\noticeboard.dm"
|
||||
#include "code\game\objects\structures\plasticflaps.dm"
|
||||
#include "code\game\objects\structures\reflector.dm"
|
||||
@@ -1603,6 +1607,25 @@
|
||||
#include "code\modules\hydroponics\grown\tobacco.dm"
|
||||
#include "code\modules\hydroponics\grown\tomato.dm"
|
||||
#include "code\modules\hydroponics\grown\towercap.dm"
|
||||
#include "code\modules\instruments\_instrument_data.dm"
|
||||
#include "code\modules\instruments\_instrument_key.dm"
|
||||
#include "code\modules\instruments\brass.dm"
|
||||
#include "code\modules\instruments\chromatic_percussion.dm"
|
||||
#include "code\modules\instruments\fun.dm"
|
||||
#include "code\modules\instruments\guitar.dm"
|
||||
#include "code\modules\instruments\hardcoded.dm"
|
||||
#include "code\modules\instruments\organ.dm"
|
||||
#include "code\modules\instruments\piano.dm"
|
||||
#include "code\modules\instruments\synth_tones.dm"
|
||||
#include "code\modules\instruments\objs\items\_instrument.dm"
|
||||
#include "code\modules\instruments\objs\items\headphones.dm"
|
||||
#include "code\modules\instruments\objs\items\instruments.dm"
|
||||
#include "code\modules\instruments\objs\structures\_musician.dm"
|
||||
#include "code\modules\instruments\objs\structures\piano.dm"
|
||||
#include "code\modules\instruments\songs\_song.dm"
|
||||
#include "code\modules\instruments\songs\_song_ui.dm"
|
||||
#include "code\modules\instruments\songs\play_legacy.dm"
|
||||
#include "code\modules\instruments\songs\play_synthesized.dm"
|
||||
#include "code\modules\karma\karma.dm"
|
||||
#include "code\modules\keybindings\bindings_admin.dm"
|
||||
#include "code\modules\keybindings\bindings_ai.dm"
|
||||
@@ -2433,6 +2456,7 @@
|
||||
#include "code\modules\telesci\telepad.dm"
|
||||
#include "code\modules\telesci\telesci_computer.dm"
|
||||
#include "code\modules\tgui\external.dm"
|
||||
#include "code\modules\tgui\modal.dm"
|
||||
#include "code\modules\tgui\states.dm"
|
||||
#include "code\modules\tgui\tgui.dm"
|
||||
#include "code\modules\tgui\modules\_base.dm"
|
||||
|
||||