mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-25 13:09:11 +01:00
TGUI Engineering: Squashed Edition (Commits Below)
TGUI APCs TGUI vending machines Fix AI default_tgui_interaction TGUI Airlocks Station & Atmospheric Alert TGUI + Misc NTOS-TGUI Fixes TGUI Air Alarms & Central Atmospheric Control Airlock TGUI TG... got rid of UI for fire alarm. í´· TGUI Gas Heating/Cooling System TGUI Gas Pump & Passive Gate + Fixes TGUI Omni Atmospherics TGUI Pipe Dispensers & RPD TGUI IntelliCore & Vending Fix TGUI Handheld Tanks TGUI Portable Pump & Scrubber TGUI Tank Dispenser & Canisters TGUI Radios TGUI SMES & Air Alarm adjustment Tweak vending machine interfaces a tad TGUI Algae Farm TGUI general_air_control - Distro & Waste Console - Riot Control Console - Atmos Intake Console - Engine Cooling Console TGUI Heavy Scrubber Control (and body scanner fix) TGUI trinary devices & shutoff monitor TGUI Telecomms Log Browser TGUI Telecomms Machine Browser TGUI Spaceheater Internal Panel TGUI Gravity Generator TGUI Id Cards & Fix ID Card Images TGUI Id Card Redesign TGUI Turbolift TGUI Suit Cycler & Suit Storage Unit & Vending Fixes TGUI Power Monitor TGUI Signalers TGUI Employment Records TGUI Drone Console TGUI RIGSuits TGUI PA & PACMAN, and Margin Fix TGUI Solar Panels & Fix Power Monitor Adjust TGUI modules & their interaction with NTOS TGUI RCON TGUI Message Monitor Bump TGUI line limit to 120 (ParadiseSS13/Paradise#14002) TGUI Exonet & NTNet Relay TGUI Telecomms Multitool Menu TGUI Shield Capacitor & Shield Generator TGUI Supermatter-everything & Refactors
This commit is contained in:
@@ -22,15 +22,26 @@
|
||||
to_chat(user, "<b>ERROR ERROR ERROR</b>")
|
||||
|
||||
/obj/item/device/aicard/attack_self(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
ui_interact(user)
|
||||
/obj/item/device/aicard/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui_state/custom_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "AICard", "[name]") // 600, 394
|
||||
ui.open()
|
||||
if(custom_state)
|
||||
ui.set_state(custom_state)
|
||||
|
||||
/obj/item/device/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state)
|
||||
/obj/item/device/aicard/tgui_state(mob/user)
|
||||
return GLOB.tgui_inventory_state
|
||||
|
||||
/obj/item/device/aicard/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["has_ai"] = carded_ai != null
|
||||
if(carded_ai)
|
||||
data["name"] = carded_ai.name
|
||||
data["hardware_integrity"] = carded_ai.hardware_integrity()
|
||||
data["integrity"] = carded_ai.hardware_integrity()
|
||||
data["backup_capacitor"] = carded_ai.backup_capacitor()
|
||||
data["radio"] = !carded_ai.aiRadio.disabledAi
|
||||
data["wireless"] = !carded_ai.control_disabled
|
||||
@@ -38,52 +49,42 @@
|
||||
data["flushing"] = flush
|
||||
|
||||
var/laws[0]
|
||||
for(var/datum/ai_law/AL in carded_ai.laws.all_laws())
|
||||
laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law))
|
||||
for(var/datum/ai_law/law in carded_ai.laws.all_laws())
|
||||
if(law in carded_ai.laws.ion_laws) // If we're an ion law, give it an ion index code
|
||||
laws.Add(ionnum() + ". " + law.law)
|
||||
else
|
||||
laws.Add(num2text(law.get_index()) + ". " + law.law)
|
||||
data["laws"] = laws
|
||||
data["has_laws"] = laws.len
|
||||
data["has_laws"] = length(carded_ai.laws.all_laws())
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
return data
|
||||
|
||||
/obj/item/device/aicard/Topic(href, href_list, state)
|
||||
/obj/item/device/aicard/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(!carded_ai)
|
||||
return 1
|
||||
return
|
||||
|
||||
var/user = usr
|
||||
if (href_list["wipe"])
|
||||
var/confirm = alert("Are you sure you want to disable this core's power? This cannot be undone once started.", "Confirm Shutdown", "No", "Yes")
|
||||
if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE))
|
||||
switch(action)
|
||||
if("wipe")
|
||||
msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].")
|
||||
add_attack_logs(user,carded_ai,"Purged from AI Card")
|
||||
flush = 1
|
||||
carded_ai.suiciding = 1
|
||||
to_chat(carded_ai, "Your power has been disabled!")
|
||||
while (carded_ai && carded_ai.stat != DEAD)
|
||||
if(carded_ai.deployed_shell && prob(carded_ai.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely.
|
||||
carded_ai.disconnect_shell("Disconnecting from remote shell due to insufficent power.")
|
||||
carded_ai.adjustOxyLoss(2)
|
||||
carded_ai.updatehealth()
|
||||
sleep(10)
|
||||
flush = 0
|
||||
if (href_list["radio"])
|
||||
carded_ai.aiRadio.disabledAi = text2num(href_list["radio"])
|
||||
to_chat(carded_ai, "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
|
||||
to_chat(user, "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
|
||||
if (href_list["wireless"])
|
||||
carded_ai.control_disabled = text2num(href_list["wireless"])
|
||||
to_chat(carded_ai, "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>")
|
||||
to_chat(user, "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
|
||||
if(carded_ai.control_disabled && carded_ai.deployed_shell)
|
||||
carded_ai.disconnect_shell("Disconnecting from remote shell due to [src] wireless access interface being disabled.")
|
||||
update_icon()
|
||||
return 1
|
||||
INVOKE_ASYNC(src, .proc/wipe_ai)
|
||||
if("radio")
|
||||
carded_ai.aiRadio.disabledAi = !carded_ai.aiRadio.disabledAi
|
||||
to_chat(carded_ai, "<span class='warning'>Your Subspace Transceiver has been [carded_ai.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
|
||||
to_chat(user, "<span class='notice'>You [carded_ai.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
|
||||
if("wireless")
|
||||
carded_ai.control_disabled = !carded_ai.control_disabled
|
||||
to_chat(carded_ai, "<span class='warning'>Your wireless interface has been [carded_ai.control_disabled ? "disabled" : "enabled"]!</span>")
|
||||
to_chat(user, "<span class='notice'>You [carded_ai.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
|
||||
if(carded_ai.control_disabled && carded_ai.deployed_shell)
|
||||
carded_ai.disconnect_shell("Disconnecting from remote shell due to [src] wireless access interface being disabled.")
|
||||
update_icon()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/device/aicard/update_icon()
|
||||
overlays.Cut()
|
||||
@@ -168,3 +169,17 @@
|
||||
var/obj/item/weapon/rig/rig = src.get_rig()
|
||||
if(istype(rig))
|
||||
rig.forced_move(direction, user)
|
||||
|
||||
/obj/item/device/aicard/proc/wipe_ai()
|
||||
var/mob/living/silicon/ai/AI = carded_ai
|
||||
flush = TRUE
|
||||
AI.suiciding = TRUE
|
||||
to_chat(AI, "Your power has been disabled!")
|
||||
while(AI && AI.stat != DEAD)
|
||||
// This is absolutely evil and I love it.
|
||||
if(AI.deployed_shell && prob(AI.oxyloss)) //You feel it creeping? Eventually will reach 100, resulting in the second half of the AI's remaining life being lonely.
|
||||
AI.disconnect_shell("Disconnecting from remote shell due to insufficent power.")
|
||||
AI.adjustOxyLoss(2)
|
||||
AI.updatehealth()
|
||||
sleep(10)
|
||||
flush = FALSE
|
||||
@@ -382,7 +382,7 @@
|
||||
return
|
||||
|
||||
|
||||
/obj/item/device/radio/headset/proc/recalculateChannels(var/setDescription = 0)
|
||||
/obj/item/device/radio/headset/recalculateChannels(var/setDescription = 0)
|
||||
src.channels = list()
|
||||
src.translate_binary = 0
|
||||
src.translate_hive = 0
|
||||
|
||||
@@ -37,12 +37,14 @@ var/global/list/default_medbay_channels = list(
|
||||
var/frequency = PUB_FREQ //common chat
|
||||
var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies
|
||||
var/canhear_range = 3 // the range which mobs can hear this radio from
|
||||
var/loudspeaker = TRUE // Allows borgs to disable canhear_range.
|
||||
var/datum/wires/radio/wires = null
|
||||
var/b_stat = 0
|
||||
var/broadcasting = 0
|
||||
var/listening = 1
|
||||
var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h
|
||||
var/subspace_transmission = 0
|
||||
var/subspace_switchable = FALSE
|
||||
var/adhoc_fallback = FALSE //Falls back to 'radio' mode if subspace not available
|
||||
var/syndie = 0//Holder to see if it's a syndicate encrypted radio
|
||||
var/centComm = 0//Holder to see if it's a CentCom encrypted radio
|
||||
@@ -133,6 +135,8 @@ var/global/list/default_medbay_channels = list(
|
||||
if(!found)
|
||||
testing("A radio [src] at [x],[y],[z] specified bluespace prelink IDs, but the machines with corresponding IDs ([bs_tx_preload_id], [bs_rx_preload_id]) couldn't be found.")
|
||||
|
||||
/obj/item/device/radio/proc/recalculateChannels()
|
||||
return
|
||||
|
||||
/obj/item/device/radio/attack_self(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
@@ -145,15 +149,31 @@ var/global/list/default_medbay_channels = list(
|
||||
if(b_stat)
|
||||
wires.Interact(user)
|
||||
|
||||
return ui_interact(user)
|
||||
return tgui_interact(user)
|
||||
|
||||
/obj/item/device/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
/obj/item/device/radio/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nano_ui/master_ui, datum/topic_state/state)
|
||||
log_runtime(EXCEPTION("Warning: [user] attempted to call ui_interact on radio [src] [type]. This is deprecated. Please update the caller to tgui_interact."))
|
||||
|
||||
/obj/item/device/radio/Topic(href, href_list)
|
||||
if(href_list["track"])
|
||||
log_runtime(EXCEPTION("Warning: Topic() was improperly called on radio [src] [type], with the track href and \[[href] [json_encode(href_list)]]. Please update the caller to use tgui_act."))
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Radio", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/radio/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
data["listening"] = listening
|
||||
data["broadcasting"] = broadcasting
|
||||
data["subspace"] = subspace_transmission
|
||||
data["subspaceSwitchable"] = subspace_switchable
|
||||
data["loudspeaker"] = loudspeaker
|
||||
|
||||
data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL))
|
||||
@@ -161,21 +181,16 @@ var/global/list/default_medbay_channels = list(
|
||||
var/list/chanlist = list_channels(user)
|
||||
if(islist(chanlist) && chanlist.len)
|
||||
data["chan_list"] = chanlist
|
||||
data["chan_list_len"] = chanlist.len
|
||||
else
|
||||
data["chan_list"] = null
|
||||
|
||||
if(syndie)
|
||||
data["useSyndMode"] = 1
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
data["minFrequency"] = PUBLIC_LOW_FREQ
|
||||
data["maxFrequency"] = PUBLIC_HIGH_FREQ
|
||||
|
||||
/obj/item/device/radio/CouldUseTopic(var/mob/user)
|
||||
..()
|
||||
if(iscarbon(user))
|
||||
playsound(src, "button", 10)
|
||||
return data
|
||||
|
||||
/obj/item/device/radio/proc/list_channels(var/mob/user)
|
||||
return list_internal_channels(user)
|
||||
@@ -187,7 +202,7 @@ var/global/list/default_medbay_channels = list(
|
||||
var/chan_stat = channels[ch_name]
|
||||
var/listening = !!(chan_stat & FREQ_LISTENING) != 0
|
||||
|
||||
dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name]))))
|
||||
dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "freq" = radiochannels[ch_name])))
|
||||
|
||||
return dat
|
||||
|
||||
@@ -195,7 +210,7 @@ var/global/list/default_medbay_channels = list(
|
||||
var/dat[0]
|
||||
for(var/internal_chan in internal_channels)
|
||||
if(has_channel_access(user, internal_chan))
|
||||
dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan)))))
|
||||
dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "freq" = text2num(internal_chan))))
|
||||
|
||||
return dat
|
||||
|
||||
@@ -233,50 +248,61 @@ var/global/list/default_medbay_channels = list(
|
||||
return STATUS_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/Topic(href, href_list)
|
||||
/obj/item/device/radio/tgui_act(action, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
usr.set_machine(src)
|
||||
if (href_list["track"])
|
||||
var/mob/target = locate(href_list["track"])
|
||||
var/mob/living/silicon/ai/A = locate(href_list["track2"])
|
||||
if(A && target)
|
||||
A.ai_actual_track(target)
|
||||
. = 1
|
||||
|
||||
else if (href_list["freq"])
|
||||
var/new_frequency = (frequency + text2num(href_list["freq"]))
|
||||
if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ))
|
||||
new_frequency = sanitize_frequency(new_frequency)
|
||||
set_frequency(new_frequency)
|
||||
if(hidden_uplink)
|
||||
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
|
||||
usr << browse(null, "window=radio")
|
||||
. = 1
|
||||
else if (href_list["talk"])
|
||||
ToggleBroadcast()
|
||||
. = 1
|
||||
else if (href_list["listen"])
|
||||
var/chan_name = href_list["ch_name"]
|
||||
if (!chan_name)
|
||||
switch(action)
|
||||
if("setFrequency")
|
||||
var/new_frequency = (text2num(params["freq"]))
|
||||
if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ))
|
||||
new_frequency = sanitize_frequency(new_frequency)
|
||||
set_frequency(new_frequency)
|
||||
if(hidden_uplink)
|
||||
if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency))
|
||||
usr << browse(null, "window=radio")
|
||||
. = TRUE
|
||||
if("broadcast")
|
||||
ToggleBroadcast()
|
||||
. = TRUE
|
||||
if("listen")
|
||||
ToggleReception()
|
||||
else
|
||||
if (channels[chan_name] & FREQ_LISTENING)
|
||||
. = TRUE
|
||||
if("channel")
|
||||
var/chan_name = params["channel"]
|
||||
if(channels[chan_name] & FREQ_LISTENING)
|
||||
channels[chan_name] &= ~FREQ_LISTENING
|
||||
else
|
||||
channels[chan_name] |= FREQ_LISTENING
|
||||
. = 1
|
||||
else if(href_list["spec_freq"])
|
||||
var freq = href_list["spec_freq"]
|
||||
if(has_channel_access(usr, freq))
|
||||
set_frequency(text2num(freq))
|
||||
. = 1
|
||||
if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk
|
||||
return TRUE
|
||||
. = TRUE
|
||||
if("specFreq")
|
||||
var/freq = params["channel"]
|
||||
if(has_channel_access(usr, freq))
|
||||
set_frequency(text2num(freq))
|
||||
. = TRUE
|
||||
if("subspace")
|
||||
if(subspace_switchable)
|
||||
subspace_transmission = !subspace_transmission
|
||||
if(!subspace_transmission)
|
||||
channels = list()
|
||||
to_chat(usr, "<span class='notice'>Subspace Transmission is disabled</span>")
|
||||
else
|
||||
recalculateChannels()
|
||||
to_chat(usr, "<span class='notice'>Subspace Transmission is enabled</span>")
|
||||
. = TRUE
|
||||
if("toggleLoudspeaker")
|
||||
if(!subspace_switchable)
|
||||
return
|
||||
loudspeaker = !loudspeaker
|
||||
|
||||
if(.)
|
||||
SSnanoui.update_uis(src)
|
||||
if(loudspeaker)
|
||||
to_chat(usr, "<span class='notice'>Loadspeaker enabled.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Loadspeaker disabled.</span>")
|
||||
. = TRUE
|
||||
|
||||
if(. && iscarbon(usr))
|
||||
playsound(src, "button", 10)
|
||||
|
||||
GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
|
||||
/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels) //BS12 EDIT
|
||||
@@ -569,10 +595,9 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
|
||||
return canhear_range
|
||||
|
||||
/obj/item/device/radio/proc/send_hear(freq, level)
|
||||
|
||||
var/range = receive_range(freq, level)
|
||||
if(range > -1)
|
||||
return get_mobs_or_objects_in_view(canhear_range, src)
|
||||
if(range > -1 && loudspeaker)
|
||||
return get_mobs_or_objects_in_view(range, src)
|
||||
|
||||
|
||||
/obj/item/device/radio/examine(mob/user)
|
||||
@@ -616,11 +641,11 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
|
||||
/obj/item/device/radio/borg
|
||||
var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks
|
||||
var/obj/item/device/encryptionkey/keyslot = null//Borg radios can handle a single encryption key
|
||||
var/shut_up = 1
|
||||
icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component.
|
||||
icon_state = "radio"
|
||||
canhear_range = 0
|
||||
subspace_transmission = 1
|
||||
subspace_transmission = TRUE
|
||||
subspace_switchable = TRUE
|
||||
|
||||
/obj/item/device/radio/borg/Destroy()
|
||||
myborg = null
|
||||
@@ -678,7 +703,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/device/radio/borg/proc/recalculateChannels()
|
||||
/obj/item/device/radio/borg/recalculateChannels()
|
||||
src.channels = list()
|
||||
src.syndie = 0
|
||||
|
||||
@@ -710,71 +735,6 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/device/radio/borg/Topic(href, href_list)
|
||||
if(..())
|
||||
return TRUE
|
||||
if (href_list["mode"])
|
||||
var/enable_subspace_transmission = text2num(href_list["mode"])
|
||||
if(enable_subspace_transmission != subspace_transmission)
|
||||
subspace_transmission = !subspace_transmission
|
||||
if(subspace_transmission)
|
||||
to_chat(usr, "<span class='notice'>Subspace Transmission is enabled</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Subspace Transmission is disabled</span>")
|
||||
|
||||
if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled
|
||||
channels = list()
|
||||
else
|
||||
recalculateChannels()
|
||||
. = 1
|
||||
if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio.
|
||||
var/do_shut_up = text2num(href_list["shutup"])
|
||||
if(do_shut_up != shut_up)
|
||||
shut_up = !shut_up
|
||||
if(shut_up)
|
||||
canhear_range = 0
|
||||
to_chat(usr, "<span class='notice'>Loadspeaker disabled.</span>")
|
||||
else
|
||||
canhear_range = 3
|
||||
to_chat(usr, "<span class='notice'>Loadspeaker enabled.</span>")
|
||||
. = 1
|
||||
|
||||
if(.)
|
||||
SSnanoui.update_uis(src)
|
||||
|
||||
/obj/item/device/radio/borg/interact(mob/user as mob)
|
||||
if(!on)
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/device/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
|
||||
data["mic_status"] = broadcasting
|
||||
data["speaker"] = listening
|
||||
data["freq"] = format_frequency(frequency)
|
||||
data["rawfreq"] = num2text(frequency)
|
||||
|
||||
var/list/chanlist = list_channels(user)
|
||||
if(islist(chanlist) && chanlist.len)
|
||||
data["chan_list"] = chanlist
|
||||
data["chan_list_len"] = chanlist.len
|
||||
|
||||
if(syndie)
|
||||
data["useSyndMode"] = 1
|
||||
|
||||
data["has_loudspeaker"] = 1
|
||||
data["loudspeaker"] = !shut_up
|
||||
data["has_subspace"] = 1
|
||||
data["subspace"] = subspace_transmission
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/radio/proc/config(op)
|
||||
if(radio_controller)
|
||||
for (var/ch_name in channels)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#define PAINT_MODE -2
|
||||
#define EATING_MODE -1
|
||||
#define ATMOS_MODE 0
|
||||
#define DISPOSALS_MODE 1
|
||||
#define TRANSIT_MODE 2
|
||||
#define ATMOS_CATEGORY 0
|
||||
#define DISPOSALS_CATEGORY 1
|
||||
#define TRANSIT_CATEGORY 2
|
||||
|
||||
#define BUILD_MODE (1<<0)
|
||||
#define WRENCH_MODE (1<<1)
|
||||
#define DESTROY_MODE (1<<2)
|
||||
#define PAINT_MODE (1<<3)
|
||||
|
||||
/obj/item/weapon/pipe_dispenser
|
||||
name = "Rapid Piping Device (RPD)"
|
||||
@@ -22,18 +25,16 @@
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
matter = list(MAT_STEEL = 50000, MAT_GLASS = 25000)
|
||||
var/datum/effect/effect/system/spark_spread/spark_system
|
||||
var/mode = ATMOS_MODE
|
||||
var/p_dir = NORTH // Next pipe will be built with this dir
|
||||
var/p_flipped = FALSE // If the next pipe should be built flipped
|
||||
var/paint_color = "grey" // Pipe color index for next pipe painted/built.
|
||||
var/screen = ATMOS_MODE // Starts on the atmos tab.
|
||||
var/category = ATMOS_CATEGORY
|
||||
var/piping_layer = PIPING_LAYER_DEFAULT
|
||||
var/wrench_mode = FALSE
|
||||
var/obj/item/weapon/tool/wrench/tool
|
||||
var/datum/pipe_recipe/recipe // pipe recipie selected for display/construction
|
||||
var/static/datum/pipe_recipe/first_atmos
|
||||
var/static/datum/pipe_recipe/first_disposal
|
||||
var/static/datum/asset/spritesheet/pipes/icon_assets
|
||||
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE
|
||||
var/static/list/pipe_layers = list(
|
||||
"Regular" = PIPING_LAYER_REGULAR,
|
||||
"Supply" = PIPING_LAYER_SUPPLY,
|
||||
@@ -51,10 +52,10 @@
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/proc/SetupPipes()
|
||||
if(!first_atmos)
|
||||
first_atmos = atmos_pipe_recipes[atmos_pipe_recipes[1]][1]
|
||||
first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
|
||||
recipe = first_atmos
|
||||
if(!first_disposal)
|
||||
first_disposal = disposal_pipe_recipes[disposal_pipe_recipes[1]][1]
|
||||
first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1]
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/Destroy()
|
||||
qdel_null(spark_system)
|
||||
@@ -69,170 +70,97 @@
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/attack_self(mob/user)
|
||||
src.interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
// TODO - Wouldn't it be nice to have nanoui?
|
||||
/obj/item/weapon/pipe_dispenser/interact(mob/user)
|
||||
/obj/item/weapon/pipe_dispenser/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/pipes),
|
||||
)
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/tgui_interact(mob/user, datum/tgui/ui)
|
||||
SetupPipes()
|
||||
if(!icon_assets)
|
||||
icon_assets = get_asset_datum(/datum/asset/spritesheet/pipes)
|
||||
icon_assets.send(user)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "RapidPipeDispenser", name)
|
||||
ui.open()
|
||||
|
||||
var/list/lines = list()
|
||||
if(mode >= ATMOS_MODE)
|
||||
lines += "<div class=\"block\"><h3>Direction:</h3><div class=\"item\">"
|
||||
switch(recipe.dirtype)
|
||||
/obj/item/weapon/pipe_dispenser/tgui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"category" = category,
|
||||
"piping_layer" = piping_layer,
|
||||
"pipe_layers" = pipe_layers,
|
||||
"preview_rows" = recipe.get_preview(p_dir),
|
||||
"categories" = list(),
|
||||
"selected_color" = paint_color,
|
||||
"paint_colors" = pipe_colors,
|
||||
"mode" = mode
|
||||
)
|
||||
|
||||
if(PIPE_STRAIGHT) // Straight, N-S, W-E
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTH,"Vertical","↕")
|
||||
lines += render_dir_img(recipe.icon_state,user,EAST,"Horizontal","↔")
|
||||
var/list/recipes
|
||||
switch(category)
|
||||
if(ATMOS_CATEGORY)
|
||||
recipes = GLOB.atmos_pipe_recipes
|
||||
if(DISPOSALS_CATEGORY)
|
||||
recipes = GLOB.disposal_pipe_recipes
|
||||
// if(TRANSIT_CATEGORY)
|
||||
// recipes = transit_tube_recipes
|
||||
for(var/c in recipes)
|
||||
var/list/cat = recipes[c]
|
||||
var/list/r = list()
|
||||
for(var/i in 1 to cat.len)
|
||||
var/datum/pipe_recipe/info = cat[i]
|
||||
r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe)))
|
||||
data["categories"] += list(list("cat_name" = c, "recipes" = r))
|
||||
|
||||
if(PIPE_BENDABLE) // Bent, N-W, N-E etc
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTH,"Vertical","↕")
|
||||
lines += render_dir_img(recipe.icon_state,user,EAST,"Horizontal","↔")
|
||||
lines += "<br />"
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTHWEST,"West to North","╝")
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTHEAST,"North to East","╚")
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTHWEST,"South to West","╗")
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTHEAST,"East to South","╔")
|
||||
return data
|
||||
|
||||
if(PIPE_TRINARY) // Manifold
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTH,"West South East","╦")
|
||||
lines += render_dir_img(recipe.icon_state,user,EAST,"North West South","╣")
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTH,"East North West","╩")
|
||||
lines += render_dir_img(recipe.icon_state,user,WEST,"South East North","╠")
|
||||
|
||||
if(PIPE_TRIN_M) // Mirrored ones
|
||||
//each mirror icon is 45 anticlockwise from it's real direction
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTH,"West South East","╦")
|
||||
lines += render_dir_img(recipe.icon_state,user,EAST,"North West South","╣")
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTH,"East North West","╩")
|
||||
lines += render_dir_img(recipe.icon_state,user,WEST,"South East North","╠")
|
||||
lines += "<br />"
|
||||
lines += render_dir_img(recipe.icon_state_m,user,SOUTH,"West South East","╦", 1)
|
||||
lines += render_dir_img(recipe.icon_state_m,user,WEST,"South East North","╠", 1)
|
||||
lines += render_dir_img(recipe.icon_state_m,user,NORTH,"East North West","╩", 1)
|
||||
lines += render_dir_img(recipe.icon_state_m,user,EAST,"North West South","╣", 1)
|
||||
|
||||
if(PIPE_DIRECTIONAL) // Stuff with four directions - includes pumps etc.
|
||||
lines += render_dir_img(recipe.icon_state,user,NORTH,"North","↑")
|
||||
lines += render_dir_img(recipe.icon_state,user,EAST,"East","→")
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTH,"South","↓")
|
||||
lines += render_dir_img(recipe.icon_state,user,WEST,"West","←")
|
||||
|
||||
if(PIPE_ONEDIR) // Single icon_state (eg 4-way manifolds)
|
||||
lines += render_dir_img(recipe.icon_state,user,SOUTH,"Pipe","↕")
|
||||
lines += "</div></div>"
|
||||
|
||||
if(mode == ATMOS_MODE || mode == PAINT_MODE)
|
||||
lines += "<div class=\"block\"><h3>Color:</h3>"
|
||||
var/i = 0
|
||||
for(var/c in pipe_colors)
|
||||
++i
|
||||
lines += "<a class='[paint_color == c ? "linkOn" : ""]' href='?src=\ref[src];paint_color=[c]'>[c]</a>"
|
||||
if(i == 4)
|
||||
lines += "<br>"
|
||||
i = 0
|
||||
lines += "</div>"
|
||||
|
||||
lines += "<div class=\"block\"><h3>Mode:</h3>"
|
||||
lines += "<a class='[mode >= ATMOS_MODE ? "linkOn" : ""]' href='?src=\ref[src];mode=[screen]'>Lay Pipes</a>"
|
||||
lines += "<a class='[mode == EATING_MODE ? "linkOn" : ""]' href='?src=\ref[src];mode=[EATING_MODE]'>Eat Pipes</a>"
|
||||
lines += "<a class='[mode == PAINT_MODE ? "linkOn" : ""]' href='?src=\ref[src];mode=[PAINT_MODE]'>Paint Pipes</a>"
|
||||
lines += "</div>"
|
||||
|
||||
lines += "<div class=\"block\"><h3>Category:</h3>"
|
||||
lines += "<a class='[screen == ATMOS_MODE ? "linkOn" : ""]' href='?src=\ref[src];screen=[ATMOS_MODE]'>Atmospherics</a>"
|
||||
lines += "<a class='[screen == DISPOSALS_MODE ? "linkOn" : ""]' href='?src=\ref[src];screen=[DISPOSALS_MODE]'>Disposals</a>"
|
||||
//lines += "<a class='[screen == TRANSIT_MODE ? "linkOn" : ""]' href='?src=\ref[src];screen=[TRANSIT_MODE]'>Transit Tube</a>"
|
||||
lines += "<br><a class='[wrench_mode ? "linkOn" : ""]' href='?src=\ref[src];switch_wrench=1;wrench_mode=[!wrench_mode]'>Wrench Mode</a>"
|
||||
lines += "</div>"
|
||||
|
||||
if(screen == ATMOS_MODE)
|
||||
for(var/category in atmos_pipe_recipes)
|
||||
lines += "<div class=\"block\"><h3>[category]:</h3>"
|
||||
|
||||
if(category == "Pipes")
|
||||
lines += "<div class=\"item\">"
|
||||
for(var/pipename in pipe_layers)
|
||||
var/pipelayer = pipe_layers[pipename]
|
||||
lines += "<a class='[piping_layer == pipelayer ? "linkOn" : "linkOff"]' href='?src=\ref[src];piping_layer=[pipelayer]'>[pipename]</a> "
|
||||
lines += "</div>"
|
||||
lines += "<hr>"
|
||||
for(var/i in 1 to atmos_pipe_recipes[category].len)
|
||||
var/datum/pipe_recipe/PI = atmos_pipe_recipes[category][i]
|
||||
lines += "<div class=\"item\">"
|
||||
lines += "<a class='[recipe == PI ? "linkOn" : ""]' href='?src=\ref[src]&category=[category]&pipe_type=[i]'>[PI.name]</a>"
|
||||
lines += "</div>"
|
||||
lines += "</div>"
|
||||
else if(screen == DISPOSALS_MODE)
|
||||
for(var/category in disposal_pipe_recipes)
|
||||
lines += "<div class=\"block\"><h3>[category]:</h3>"
|
||||
for(var/i in 1 to disposal_pipe_recipes[category].len)
|
||||
var/datum/pipe_recipe/PI = disposal_pipe_recipes[category][i]
|
||||
lines += "<div class=\"item\">"
|
||||
lines += "<a class='[recipe == PI ? "linkOn" : ""]' href='?src=\ref[src]&category=[category]&pipe_type=[i]'>[PI.name]</a>"
|
||||
lines += "</div>"
|
||||
lines += "</div>"
|
||||
|
||||
var/dat = lines.Join()
|
||||
var/datum/browser/popup = new(user, "rpd", name, 300, 800, src)
|
||||
popup.set_content("<TT>[dat]</TT>")
|
||||
popup.add_head_content(icon_assets.css_tag())
|
||||
popup.open()
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/Topic(href, href_list, state = global.inventory_state)
|
||||
/obj/item/weapon/pipe_dispenser/tgui_act(action, params)
|
||||
SetupPipes()
|
||||
if(..())
|
||||
return 1
|
||||
return TRUE
|
||||
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
|
||||
return 1
|
||||
var/playeffect = TRUE // Do we spark the device
|
||||
var/anyclicked = FALSE // Tells us if we need to refresh the window.
|
||||
if(href_list["paint_color"])
|
||||
paint_color = href_list["paint_color"]
|
||||
playeffect = FALSE
|
||||
anyclicked = TRUE
|
||||
if(href_list["mode"])
|
||||
mode = text2num(href_list["mode"])
|
||||
anyclicked = TRUE
|
||||
if(href_list["screen"])
|
||||
if(mode == screen)
|
||||
mode = text2num(href_list["screen"])
|
||||
screen = text2num(href_list["screen"])
|
||||
switch(screen)
|
||||
if(DISPOSALS_MODE)
|
||||
recipe = first_disposal
|
||||
if(ATMOS_MODE)
|
||||
recipe = first_atmos
|
||||
p_dir = NORTH
|
||||
playeffect = FALSE
|
||||
anyclicked = TRUE
|
||||
if(href_list["piping_layer"])
|
||||
piping_layer = text2num(href_list["piping_layer"])
|
||||
playeffect = FALSE
|
||||
anyclicked = TRUE
|
||||
if(href_list["pipe_type"])
|
||||
recipe = all_pipe_recipes[href_list["category"]][text2num(href_list["pipe_type"])]
|
||||
if(recipe.dirtype == PIPE_ONEDIR) // One hell of a hack for the fact that the image previews for the onedir types only show on the south, but the default pipe type is north.
|
||||
p_dir = SOUTH // Did I fuck this up? Maybe. Or maybe it's just the icon files not being ready for an RPD.
|
||||
else // If going to try and fix this hack, be aware the pipe dispensers might rely on pipes defaulting south instead of north.
|
||||
return TRUE
|
||||
var/playeffect = TRUE
|
||||
switch(action)
|
||||
if("color")
|
||||
paint_color = params["paint_color"]
|
||||
if("category")
|
||||
category = text2num(params["category"])
|
||||
switch(category)
|
||||
if(DISPOSALS_CATEGORY)
|
||||
recipe = first_disposal
|
||||
if(ATMOS_CATEGORY)
|
||||
recipe = first_atmos
|
||||
// if(TRANSIT_CATEGORY)
|
||||
// recipe = first_transit
|
||||
p_dir = NORTH
|
||||
p_flipped = FALSE
|
||||
anyclicked = TRUE
|
||||
if(href_list["dir"])
|
||||
p_dir = text2dir(href_list["dir"])
|
||||
p_flipped = text2num(href_list["flipped"])
|
||||
playeffect = FALSE
|
||||
anyclicked = TRUE
|
||||
if(href_list["switch_wrench"])
|
||||
wrench_mode = text2num(href_list["wrench_mode"])
|
||||
anyclicked = TRUE
|
||||
if(anyclicked)
|
||||
if(playeffect)
|
||||
spark_system.start()
|
||||
playsound(src, 'sound/effects/pop.ogg', 50, 0)
|
||||
src.interact(usr)
|
||||
playeffect = FALSE
|
||||
if("piping_layer")
|
||||
piping_layer = text2num(params["piping_layer"])
|
||||
playeffect = FALSE
|
||||
// if("ducting_layer")
|
||||
// ducting_layer = text2num(params["ducting_layer"])
|
||||
// playeffect = FALSE
|
||||
if("pipe_type")
|
||||
var/static/list/recipes
|
||||
if(!recipes)
|
||||
recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes
|
||||
recipe = recipes[params["category"]][text2num(params["pipe_type"])]
|
||||
p_dir = NORTH
|
||||
if("setdir")
|
||||
p_dir = text2dir(params["dir"])
|
||||
p_flipped = text2num(params["flipped"])
|
||||
playeffect = FALSE
|
||||
if("mode")
|
||||
var/n = text2num(params["mode"])
|
||||
if(mode & n)
|
||||
mode &= ~n
|
||||
else
|
||||
mode |= n
|
||||
if(playeffect)
|
||||
spark_system.start()
|
||||
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/afterattack(atom/A, mob/user as mob, proximity)
|
||||
if(!user.IsAdvancedToolUser() || istype(A, /turf/space/transit) || !proximity)
|
||||
@@ -249,88 +177,89 @@
|
||||
make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe))
|
||||
var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist))
|
||||
|
||||
. = FALSE
|
||||
switch(mode) //if we've gotten this var, the target is valid
|
||||
if(PAINT_MODE) //Paint pipes
|
||||
if(!istype(A, /obj/machinery/atmospherics/pipe))
|
||||
return ..()
|
||||
var/can_destroy_pipe = istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct)
|
||||
|
||||
. = TRUE
|
||||
if((mode & DESTROY_MODE) && can_destroy_pipe)
|
||||
to_chat(user, "<span class='notice'>You start destroying a pipe...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
animate_deletion(A)
|
||||
return
|
||||
|
||||
if((mode & PAINT_MODE)) //Paint pipes
|
||||
if(istype(A, /obj/machinery/atmospherics/pipe))
|
||||
var/obj/machinery/atmospherics/pipe/P = A
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
P.change_color(pipe_colors[paint_color])
|
||||
user.visible_message("<span class='notice'>[user] paints \the [P] [paint_color].</span>", "<span class='notice'>You paint \the [P] [paint_color].</span>")
|
||||
return
|
||||
|
||||
if(EATING_MODE) //Eating pipes
|
||||
if(!(istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct)))
|
||||
return ..()
|
||||
to_chat(user, "<span class='notice'>You start destroying a pipe...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
animate_deletion(A)
|
||||
if(mode & BUILD_MODE) //Making pipes
|
||||
switch(category)
|
||||
if(ATMOS_CATEGORY)
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if(istype(recipe, /datum/pipe_recipe/meter))
|
||||
to_chat(user, "<span class='notice'>You start building a meter...</span>")
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A))
|
||||
PM.setAttachLayer(queued_piping_layer)
|
||||
if(mode & WRENCH_MODE)
|
||||
do_wrench(PM, user)
|
||||
else if(istype(recipe, /datum/pipe_recipe/pipe))
|
||||
var/datum/pipe_recipe/pipe/R = recipe
|
||||
to_chat(user, "<span class='notice'>You start building a pipe...</span>")
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
var/obj/machinery/atmospherics/path = R.pipe_type
|
||||
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
|
||||
var/obj/item/pipe/P = new pipe_item_type(get_turf(A), path, queued_p_dir)
|
||||
|
||||
if(ATMOS_MODE) //Making pipes
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if (istype(recipe, /datum/pipe_recipe/meter))
|
||||
to_chat(user, "<span class='notice'>You start building a meter...</span>")
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A))
|
||||
PM.setAttachLayer(queued_piping_layer)
|
||||
if(wrench_mode)
|
||||
do_wrench(PM, user)
|
||||
else if(istype(recipe, /datum/pipe_recipe/pipe))
|
||||
var/datum/pipe_recipe/pipe/R = recipe
|
||||
to_chat(user, "<span class='notice'>You start building a pipe...</span>")
|
||||
if(do_after(user, 2, target = A))
|
||||
activate()
|
||||
var/obj/machinery/atmospherics/path = R.pipe_type
|
||||
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
|
||||
var/obj/item/pipe/P = new pipe_item_type(get_turf(A), path, queued_p_dir)
|
||||
P.update()
|
||||
P.add_fingerprint(usr)
|
||||
if(R.paintable)
|
||||
P.color = pipe_colors[paint_color]
|
||||
P.setPipingLayer(queued_piping_layer)
|
||||
if(queued_p_flipped)
|
||||
P.do_a_flip()
|
||||
if(mode & WRENCH_MODE)
|
||||
do_wrench(P, user)
|
||||
else
|
||||
build_effect(P)
|
||||
|
||||
P.update()
|
||||
P.add_fingerprint(usr)
|
||||
if (R.paintable)
|
||||
P.color = pipe_colors[paint_color]
|
||||
P.setPipingLayer(queued_piping_layer)
|
||||
if(queued_p_flipped)
|
||||
P.do_a_flip()
|
||||
if(wrench_mode)
|
||||
do_wrench(P, user)
|
||||
else
|
||||
build_effect(P)
|
||||
|
||||
if(DISPOSALS_MODE) //Making disposals pipes
|
||||
var/datum/pipe_recipe/disposal/R = recipe
|
||||
if(!istype(R) || !can_make_pipe)
|
||||
return ..()
|
||||
A = get_turf(A)
|
||||
if(istype(A, /turf/unsimulated))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start building a disposals pipe...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, 4, target = A))
|
||||
var/obj/structure/disposalconstruct/C = new(A, R.pipe_type, queued_p_dir, queued_p_flipped, R.subtype)
|
||||
|
||||
if(!C.can_place())
|
||||
to_chat(user, "<span class='warning'>There's not enough room to build that here!</span>")
|
||||
qdel(C)
|
||||
if(DISPOSALS_CATEGORY) //Making disposals pipes
|
||||
var/datum/pipe_recipe/disposal/R = recipe
|
||||
if(!istype(R) || !can_make_pipe)
|
||||
return ..()
|
||||
A = get_turf(A)
|
||||
if(istype(A, /turf/unsimulated))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start building a disposals pipe...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, 4, target = A))
|
||||
var/obj/structure/disposalconstruct/C = new(A, R.pipe_type, queued_p_dir, queued_p_flipped, R.subtype)
|
||||
|
||||
activate()
|
||||
if(!C.can_place())
|
||||
to_chat(user, "<span class='warning'>There's not enough room to build that here!</span>")
|
||||
qdel(C)
|
||||
return
|
||||
|
||||
C.add_fingerprint(usr)
|
||||
C.update_icon()
|
||||
if(wrench_mode)
|
||||
do_wrench(C, user)
|
||||
else
|
||||
build_effect(C)
|
||||
activate()
|
||||
|
||||
else
|
||||
return ..()
|
||||
C.add_fingerprint(usr)
|
||||
C.update_icon()
|
||||
if(mode & WRENCH_MODE)
|
||||
do_wrench(C, user)
|
||||
else
|
||||
build_effect(C)
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/proc/build_effect(var/obj/P, var/time = 1.5)
|
||||
set waitfor = FALSE
|
||||
@@ -359,19 +288,11 @@
|
||||
if(!resolved && tool && target)
|
||||
tool.afterattack(target,user,1)
|
||||
|
||||
/obj/item/weapon/pipe_dispenser/proc/render_dir_img(icon_state, user, _dir, title, noimg, flipped = FALSE)
|
||||
var/dirtext = dir2text(_dir)
|
||||
var/attrs = " style=\"height:34px;width:34px;display:inline-block\""
|
||||
if(_dir == p_dir && flipped == p_flipped)
|
||||
attrs += " class=\"linkOn\""
|
||||
if(icon_state)
|
||||
var/img_tag = icon_assets.icon_tag("[dirtext]-[icon_state]")
|
||||
return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[img_tag]</a>"
|
||||
else
|
||||
return "<a href=\"?src=\ref[src];dir=[dirtext];flipped=[flipped]\" title=\"[title]\"[attrs]>[noimg]</a>"
|
||||
#undef ATMOS_CATEGORY
|
||||
#undef DISPOSALS_CATEGORY
|
||||
#undef TRANSIT_CATEGORY
|
||||
|
||||
|
||||
#undef PAINT_MODE
|
||||
#undef EATING_MODE
|
||||
#undef ATMOS_MODE
|
||||
#undef DISPOSALS_MODE
|
||||
#undef BUILD_MODE
|
||||
#undef WRENCH_MODE
|
||||
#undef DESTROY_MODE
|
||||
#undef PAINT_MODE
|
||||
@@ -17,8 +17,7 @@
|
||||
var/dna_hash = "\[UNSET\]"
|
||||
var/fingerprint_hash = "\[UNSET\]"
|
||||
var/sex = "\[UNSET\]"
|
||||
var/icon/front
|
||||
var/icon/side
|
||||
var/front
|
||||
|
||||
var/primary_color = rgb(0,0,0) // Obtained by eyedroppering the stripe in the middle of the card
|
||||
var/secondary_color = rgb(0,0,0) // Likewise for the oval in the top-left corner
|
||||
@@ -34,30 +33,27 @@
|
||||
/obj/item/weapon/card/id/examine(mob/user)
|
||||
. = ..()
|
||||
if(in_range(user, src))
|
||||
show(user) //Not chat related
|
||||
tgui_interact(user) //Not chat related
|
||||
else
|
||||
. += "<span class='warning'>It is too far away to read.</span>"
|
||||
|
||||
/obj/item/weapon/card/id/proc/prevent_tracking()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/card/id/proc/show(mob/user as mob)
|
||||
if(front && side)
|
||||
user << browse_rsc(front, "front.png")
|
||||
user << browse_rsc(side, "side.png")
|
||||
var/datum/browser/popup = new(user, "idcard", name, 600, 250)
|
||||
popup.set_content(dat())
|
||||
popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
return
|
||||
/obj/item/weapon/card/id/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "IDCard", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/weapon/card/id/proc/update_name()
|
||||
name = "[src.registered_name]'s ID Card ([src.assignment])"
|
||||
|
||||
/obj/item/weapon/card/id/proc/set_id_photo(var/mob/M)
|
||||
var/icon/charicon = cached_character_icon(M)
|
||||
front = icon(charicon,dir = SOUTH)
|
||||
side = icon(charicon,dir = WEST)
|
||||
COMPILE_OVERLAYS(M)
|
||||
SSoverlays.queue -= M
|
||||
var/icon/F = getFlatIcon(M, defdir = SOUTH, no_anim = TRUE)
|
||||
front = "'data:image/png;base64,[icon2base64(F)]'"
|
||||
|
||||
/mob/proc/set_id_info(var/obj/item/weapon/card/id/id_card)
|
||||
id_card.age = 0
|
||||
@@ -75,19 +71,19 @@
|
||||
..()
|
||||
id_card.age = age
|
||||
|
||||
/obj/item/weapon/card/id/proc/dat()
|
||||
var/dat = ("<table><tr><td>")
|
||||
dat += text("Name: []</A><BR>", registered_name)
|
||||
dat += text("Sex: []</A><BR>\n", sex)
|
||||
dat += text("Age: []</A><BR>\n", age)
|
||||
dat += text("Rank: []</A><BR>\n", assignment)
|
||||
dat += text("Fingerprint: []</A><BR>\n", fingerprint_hash)
|
||||
dat += text("Blood Type: []<BR>\n", blood_type)
|
||||
dat += text("DNA Hash: []<BR><BR>\n", dna_hash)
|
||||
if(front && side)
|
||||
dat +="<td align = center valign = top>Photo:<br><img src=front.png height=80 width=80 border=4><img src=side.png height=80 width=80 border=4></td>"
|
||||
dat += "</tr></table>"
|
||||
return dat
|
||||
/obj/item/weapon/card/id/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["registered_name"] = registered_name
|
||||
data["sex"] = sex
|
||||
data["age"] = age
|
||||
data["assignment"] = assignment
|
||||
data["fingerprint_hash"] = fingerprint_hash
|
||||
data["blood_type"] = blood_type
|
||||
data["dna_hash"] = dna_hash
|
||||
data["photo_front"] = front
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/weapon/card/id/attack_self(mob/user as mob)
|
||||
user.visible_message("\The [user] shows you: [bicon(src)] [src.name]. The assignment on the card: [src.assignment]",\
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define TANK_MAX_RELEASE_PRESSURE (3*ONE_ATMOSPHERE)
|
||||
#define TANK_DEFAULT_RELEASE_PRESSURE 24
|
||||
#define TANK_DEFAULT_RELEASE_PRESSURE 21
|
||||
#define TANK_IDEAL_PRESSURE 1015 //Arbitrary.
|
||||
|
||||
var/list/global/tank_gauge_cache = list()
|
||||
@@ -217,90 +217,73 @@ var/list/global/tank_gauge_cache = list()
|
||||
add_fingerprint(user)
|
||||
if (!(src.air_contents))
|
||||
return
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
// There's GOT to be a better way to do this
|
||||
if (src.proxyassembly.assembly)
|
||||
src.proxyassembly.assembly.attack_self(user)
|
||||
|
||||
|
||||
/obj/item/weapon/tank/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/mob/living/carbon/location = null
|
||||
/obj/item/weapon/tank/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Tank", name)
|
||||
ui.open()
|
||||
|
||||
if(istype(loc, /obj/item/weapon/rig)) // check for tanks in rigs
|
||||
if(istype(loc.loc, /mob/living/carbon))
|
||||
location = loc.loc
|
||||
else if(istype(loc, /mob/living/carbon))
|
||||
location = loc
|
||||
|
||||
var/using_internal
|
||||
if(istype(location))
|
||||
if(location.internal==src)
|
||||
using_internal = 1
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
var/data[0]
|
||||
/obj/item/weapon/tank/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0)
|
||||
data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE)
|
||||
data["minReleasePressure"] = 0
|
||||
data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
|
||||
data["valveOpen"] = using_internal ? 1 : 0
|
||||
data["maskConnected"] = 0
|
||||
|
||||
if(istype(location))
|
||||
var/mask_check = 0
|
||||
var/mob/living/carbon/C = user
|
||||
if(!istype(C))
|
||||
C = loc.loc
|
||||
if(!istype(C))
|
||||
return data
|
||||
|
||||
if(location.internal == src) // if tank is current internal
|
||||
mask_check = 1
|
||||
else if(src in location) // or if tank is in the mobs possession
|
||||
if(!location.internal) // and they do not have any active internals
|
||||
mask_check = 1
|
||||
else if(istype(src.loc, /obj/item/weapon/rig) && src.loc in location) // or the rig is in the mobs possession
|
||||
if(!location.internal) // and they do not have any active internals
|
||||
mask_check = 1
|
||||
if(C.internal == src)
|
||||
data["connected"] = TRUE
|
||||
else
|
||||
data["connected"] = FALSE
|
||||
|
||||
if(mask_check)
|
||||
if(location.wear_mask && (location.wear_mask.item_flags & AIRTIGHT))
|
||||
data["maskConnected"] = 1
|
||||
else if(istype(location, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = location
|
||||
if(H.head && (H.head.item_flags & AIRTIGHT))
|
||||
data["maskConnected"] = 1
|
||||
data["maskConnected"] = FALSE
|
||||
if(C.wear_mask && (C.wear_mask.item_flags & AIRTIGHT))
|
||||
data["maskConnected"] = TRUE
|
||||
else if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.head && (H.head.item_flags & AIRTIGHT))
|
||||
data["maskConnected"] = TRUE
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "tanks.tmpl", "Tank", 500, 300)
|
||||
// when the ui is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
return data
|
||||
|
||||
/obj/item/weapon/tank/Topic(href, href_list)
|
||||
..()
|
||||
if (usr.stat|| usr.restrained())
|
||||
return 0
|
||||
if (src.loc != usr)
|
||||
return 0
|
||||
/obj/item/weapon/tank/tgui_act(action, params)
|
||||
if(..())
|
||||
return TRUE
|
||||
switch(action)
|
||||
if("pressure")
|
||||
var/pressure = params["pressure"]
|
||||
if(pressure == "reset")
|
||||
pressure = TANK_DEFAULT_RELEASE_PRESSURE
|
||||
. = TRUE
|
||||
else if(pressure == "min")
|
||||
pressure = 0
|
||||
. = TRUE
|
||||
else if(pressure == "max")
|
||||
pressure = TANK_MAX_RELEASE_PRESSURE
|
||||
. = TRUE
|
||||
else if(text2num(pressure) != null)
|
||||
pressure = text2num(pressure)
|
||||
. = TRUE
|
||||
if(.)
|
||||
distribute_pressure = clamp(round(pressure), 0, TANK_MAX_RELEASE_PRESSURE)
|
||||
if("toggle")
|
||||
toggle_valve(usr)
|
||||
. = TRUE
|
||||
|
||||
if (href_list["dist_p"])
|
||||
if (href_list["dist_p"] == "reset")
|
||||
src.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
|
||||
else if (href_list["dist_p"] == "max")
|
||||
src.distribute_pressure = TANK_MAX_RELEASE_PRESSURE
|
||||
else
|
||||
var/cp = text2num(href_list["dist_p"])
|
||||
src.distribute_pressure += cp
|
||||
src.distribute_pressure = min(max(round(src.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE)
|
||||
if (href_list["stat"])
|
||||
toggle_valve(usr)
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
return 1
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/item/weapon/tank/proc/toggle_valve(var/mob/user)
|
||||
if(istype(loc,/mob/living/carbon))
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define TANK_DISPENSER_CAPACITY 10
|
||||
|
||||
/obj/structure/dispenser
|
||||
name = "tank storage unit"
|
||||
desc = "A simple yet bulky storage device for gas tanks. Has room for up to ten oxygen tanks, and ten phoron tanks."
|
||||
@@ -6,10 +8,8 @@
|
||||
density = 1
|
||||
anchored = 1.0
|
||||
w_class = ITEMSIZE_HUGE
|
||||
var/oxygentanks = 10
|
||||
var/phorontanks = 10
|
||||
var/list/oxytanks = list() //sorry for the similar var names
|
||||
var/list/platanks = list()
|
||||
var/oxygentanks = TANK_DISPENSER_CAPACITY
|
||||
var/phorontanks = TANK_DISPENSER_CAPACITY
|
||||
|
||||
|
||||
/obj/structure/dispenser/oxygen
|
||||
@@ -19,10 +19,14 @@
|
||||
oxygentanks = 0
|
||||
|
||||
|
||||
/obj/structure/dispenser/New()
|
||||
/obj/structure/dispenser/Initialize()
|
||||
. = ..()
|
||||
for(var/i in 1 to oxygentanks)
|
||||
new /obj/item/weapon/tank/oxygen(src)
|
||||
for(var/i in 1 to phorontanks)
|
||||
new /obj/item/weapon/tank/phoron(src)
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/structure/dispenser/update_icon()
|
||||
overlays.Cut()
|
||||
switch(oxygentanks)
|
||||
@@ -32,49 +36,44 @@
|
||||
if(1 to 4) overlays += "phoron-[phorontanks]"
|
||||
if(5 to INFINITY) overlays += "phoron-5"
|
||||
|
||||
/obj/structure/dispenser/attack_ai(mob/user as mob)
|
||||
/obj/structure/dispenser/attack_ai(mob/user)
|
||||
// This looks silly, but robots also call attack_ai, and they're allowed physical state stuff.
|
||||
if(user.Adjacent(src))
|
||||
return attack_hand(user)
|
||||
..()
|
||||
|
||||
/obj/structure/dispenser/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
var/dat = "[src]<br><br>"
|
||||
dat += "Oxygen tanks: [oxygentanks] - [oxygentanks ? "<A href='?src=\ref[src];oxygen=1'>Dispense</A>" : "empty"]<br>"
|
||||
dat += "Phoron tanks: [phorontanks] - [phorontanks ? "<A href='?src=\ref[src];phoron=1'>Dispense</A>" : "empty"]"
|
||||
user << browse(dat, "window=dispenser")
|
||||
onclose(user, "dispenser")
|
||||
return
|
||||
/obj/structure/dispenser/attack_hand(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/structure/dispenser/tgui_state(mob/user)
|
||||
return GLOB.tgui_physical_state
|
||||
|
||||
/obj/structure/dispenser/attackby(obj/item/I as obj, mob/user as mob)
|
||||
/obj/structure/dispenser/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TankDispenser", name)
|
||||
ui.open()
|
||||
|
||||
/obj/structure/dispenser/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["oxygen"] = oxygentanks
|
||||
data["plasma"] = phorontanks
|
||||
|
||||
return data
|
||||
|
||||
/obj/structure/dispenser/attackby(obj/item/I, mob/user)
|
||||
var/full
|
||||
if(istype(I, /obj/item/weapon/tank/oxygen) || istype(I, /obj/item/weapon/tank/air) || istype(I, /obj/item/weapon/tank/anesthetic))
|
||||
if(oxygentanks < 10)
|
||||
user.drop_item()
|
||||
I.loc = src
|
||||
oxytanks.Add(I)
|
||||
if(oxygentanks < TANK_DISPENSER_CAPACITY)
|
||||
oxygentanks++
|
||||
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
|
||||
if(oxygentanks < 5)
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] is full.</span>")
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(istype(I, /obj/item/weapon/tank/phoron))
|
||||
if(phorontanks < 10)
|
||||
user.drop_item()
|
||||
I.loc = src
|
||||
platanks.Add(I)
|
||||
full = TRUE
|
||||
else if(istype(I, /obj/item/weapon/tank/phoron))
|
||||
if(phorontanks < TANK_DISPENSER_CAPACITY)
|
||||
phorontanks++
|
||||
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
|
||||
if(oxygentanks < 6)
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] is full.</span>")
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(I.is_wrench())
|
||||
full = TRUE
|
||||
else if(I.is_wrench())
|
||||
if(anchored)
|
||||
to_chat(user, "<span class='notice'>You lean down and unwrench [src].</span>")
|
||||
anchored = 0
|
||||
@@ -82,39 +81,42 @@
|
||||
to_chat(user, "<span class='notice'>You wrench [src] into place.</span>")
|
||||
anchored = 1
|
||||
return
|
||||
|
||||
/obj/structure/dispenser/Topic(href, href_list)
|
||||
if(usr.stat || usr.restrained())
|
||||
else if(user.a_intent != I_HURT)
|
||||
to_chat(user, "<span class='notice'>[I] does not fit into [src].</span>")
|
||||
return
|
||||
if(Adjacent(usr))
|
||||
usr.set_machine(src)
|
||||
if(href_list["oxygen"])
|
||||
if(oxygentanks > 0)
|
||||
var/obj/item/weapon/tank/oxygen/O
|
||||
if(oxytanks.len == oxygentanks)
|
||||
O = oxytanks[1]
|
||||
oxytanks.Remove(O)
|
||||
else
|
||||
O = new /obj/item/weapon/tank/oxygen(loc)
|
||||
O.loc = loc
|
||||
to_chat(usr, "<span class='notice'>You take [O] out of [src].</span>")
|
||||
oxygentanks--
|
||||
update_icon()
|
||||
if(href_list["phoron"])
|
||||
if(phorontanks > 0)
|
||||
var/obj/item/weapon/tank/phoron/P
|
||||
if(platanks.len == phorontanks)
|
||||
P = platanks[1]
|
||||
platanks.Remove(P)
|
||||
else
|
||||
P = new /obj/item/weapon/tank/phoron(loc)
|
||||
P.loc = loc
|
||||
to_chat(usr, "<span class='notice'>You take [P] out of [src].</span>")
|
||||
phorontanks--
|
||||
update_icon()
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
else
|
||||
usr << browse(null, "window=dispenser")
|
||||
return ..()
|
||||
|
||||
if(full)
|
||||
to_chat(user, "<span class='notice'>[src] can't hold any more of [I].</span>")
|
||||
return
|
||||
return
|
||||
|
||||
if(!user.unEquip(I, target = src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You put [I] in [src].</span>")
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/structure/dispenser/tgui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("plasma")
|
||||
var/obj/item/weapon/tank/phoron/tank = locate() in src
|
||||
if(tank && Adjacent(usr))
|
||||
usr.put_in_hands(tank)
|
||||
phorontanks--
|
||||
. = TRUE
|
||||
playsound(src, 'sound/machines/vending/vending_drop.ogg', 100, 1, 1)
|
||||
if("oxygen")
|
||||
var/obj/item/weapon/tank/tank = null
|
||||
for(var/obj/item/weapon/tank/T in src)
|
||||
if(istype(T, /obj/item/weapon/tank/oxygen) || istype(T, /obj/item/weapon/tank/air) || istype(T, /obj/item/weapon/tank/anesthetic))
|
||||
tank = T
|
||||
break
|
||||
if(tank && Adjacent(usr))
|
||||
usr.put_in_hands(tank)
|
||||
oxygentanks--
|
||||
. = TRUE
|
||||
playsound(src, 'sound/machines/vending/vending_drop.ogg', 100, 1, 1)
|
||||
update_icon()
|
||||
Reference in New Issue
Block a user