mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-26 10:02:28 +00:00
pAIs, Computers and ntIRC (#8757)
#8005 just revived. Tasks to acomplish while here: Fix merge conflicts Add ntIRC direct messaging Things I migth consider adding in future PR: Porting IRC to VueUI Porting File Manager to VueUI.
This commit is contained in:
@@ -182,10 +182,14 @@
|
||||
#define PROGRAM_LAPTOP 2
|
||||
#define PROGRAM_TABLET 4
|
||||
#define PROGRAM_TELESCREEN 8
|
||||
#define PROGRAM_SILICON 16
|
||||
#define PROGRAM_SILICON_AI 16
|
||||
#define PROGRAM_WRISTBOUND 32
|
||||
#define PROGRAM_SILICON_ROBOT 64
|
||||
#define PROGRAM_SILICON_PAI 128
|
||||
|
||||
#define PROGRAM_ALL (PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_TABLET | PROGRAM_WRISTBOUND | PROGRAM_TELESCREEN | PROGRAM_SILICON)
|
||||
#define PROGRAM_ALL (PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_TABLET | PROGRAM_WRISTBOUND | PROGRAM_TELESCREEN | PROGRAM_SILICON_AI | PROGRAM_SILICON_ROBOT | PROGRAM_SILICON_PAI)
|
||||
#define PROGRAM_SILICON (PROGRAM_SILICON_AI | PROGRAM_SILICON_ROBOT | PROGRAM_SILICON_PAI)
|
||||
#define PROGRAM_STATIONBOUND (PROGRAM_SILICON_AI | PROGRAM_SILICON_ROBOT)
|
||||
#define PROGRAM_ALL_REGULAR (PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_TABLET | PROGRAM_WRISTBOUND | PROGRAM_TELESCREEN)
|
||||
|
||||
#define PROGRAM_STATE_KILLED 0
|
||||
@@ -200,6 +204,10 @@
|
||||
#define PROGRAM_ACCESS_LIST_ONE 2
|
||||
#define PROGRAM_ACCESS_LIST_ALL 3
|
||||
|
||||
#define PROGRAM_NORMAL 1
|
||||
#define PROGRAM_SERVICE 2
|
||||
#define PROGRAM_TYPE_ALL (PROGRAM_NORMAL | PROGRAM_SERVICE)
|
||||
|
||||
// Special return values from bullet_act(). Positive return values are already used to indicate the blocked level of the projectile.
|
||||
#define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act()
|
||||
#define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs.
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
/datum/controller/subsystem/ghostroles/proc/vui_interact(mob/user,var/spawnpoint=null)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user,src)
|
||||
if(!ui)
|
||||
ui = new(user,src,"misc-ghostspawner",950,700,"Ghost Role Spawner", nstate = interactive_state)
|
||||
ui = new(user,src,"misc-ghostspawner",950,700,"Ghost Role Spawner", state = interactive_state)
|
||||
ui.data = vueui_data_change(list("spawnpoint"=spawnpoint,"current_tag"="All"),user,ui)
|
||||
ui.open()
|
||||
|
||||
|
||||
@@ -20,18 +20,6 @@
|
||||
LAZYINITLIST(pai_software_by_key)
|
||||
LAZYINITLIST(default_pai_software)
|
||||
|
||||
/datum/controller/subsystem/pai/Initialize()
|
||||
// Initialize the pAI software list.
|
||||
for(var/type in subtypesof(/datum/pai_software))
|
||||
var/datum/pai_software/P = new type()
|
||||
if(pai_software_by_key[P.id])
|
||||
var/datum/pai_software/O = pai_software_by_key[P.id]
|
||||
to_world("<span class='warning'>pAI software module [P.name] has the same key as [O.name]!</span>")
|
||||
continue
|
||||
pai_software_by_key[P.id] = P
|
||||
if(P.default)
|
||||
default_pai_software[P.id] = P
|
||||
|
||||
/datum/controller/subsystem/pai/Recover()
|
||||
pai_software_by_key = SSpai.pai_software_by_key
|
||||
default_pai_software = SSpai.default_pai_software
|
||||
@@ -141,7 +129,7 @@
|
||||
"description" = candidate.description,
|
||||
"role" = candidate.role,
|
||||
"comments" = candidate.comments),
|
||||
nstate = interactive_state)
|
||||
state = interactive_state)
|
||||
ui.metadata = list("candidate" = candidate)
|
||||
ui.header = "minimal"
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@ Byond Vue UI framework's management subsystem
|
||||
LAZYINITLIST(open_uis[new_object_key])
|
||||
|
||||
for(var/datum/vueui/ui in open_uis[old_object_key])
|
||||
ui.object.vueui_on_transfer(ui)
|
||||
ui.object = new_object
|
||||
if(new_activeui) {ui.activeui = new_activeui}
|
||||
if(new_title) {ui.title = new_title}
|
||||
|
||||
@@ -216,9 +216,9 @@
|
||||
dat = replacetext(dat, "\t", "")
|
||||
return dat
|
||||
|
||||
/datum/controller/subsystem/records/proc/get_manifest_json()
|
||||
/datum/controller/subsystem/records/proc/get_manifest_list()
|
||||
if(manifest.len)
|
||||
return manifest_json
|
||||
return manifest
|
||||
manifest = list(
|
||||
"heads" = list(),
|
||||
"sec" = list(),
|
||||
@@ -256,6 +256,7 @@
|
||||
department = 1
|
||||
if ((depthead || rank == "Captain") && manifest[positionType].len != 1)
|
||||
manifest[positionType].Swap(1, manifest[positionType].len)
|
||||
manifest[positionType][1]["head"] = TRUE
|
||||
if(positionType == "head")
|
||||
depthead = 1
|
||||
|
||||
@@ -278,6 +279,13 @@
|
||||
manifest["bot"].Swap(1, manifest["bot"].len)
|
||||
|
||||
manifest_json = json_encode(manifest)
|
||||
return manifest
|
||||
|
||||
/datum/controller/subsystem/records/proc/get_manifest_json()
|
||||
if(manifest.len)
|
||||
return manifest_json
|
||||
|
||||
get_manifest_list()
|
||||
return manifest_json
|
||||
|
||||
/datum/controller/subsystem/records/proc/onDelete(var/datum/record/r)
|
||||
|
||||
@@ -398,7 +398,7 @@ var/datum/controller/subsystem/vote/SSvote
|
||||
/datum/controller/subsystem/vote/proc/OpenVotingUI(var/mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new(user, SSvote, "misc-voting", 400, 500, "Voting panel", nstate = interactive_state)
|
||||
ui = new(user, SSvote, "misc-voting", 400, 500, "Voting panel", state = interactive_state)
|
||||
ui.header = "minimal"
|
||||
ui.open()
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
weakref = null
|
||||
destroyed_event.raise_event(src)
|
||||
SSnanoui.close_uis(src)
|
||||
SSvueui.close_uis(src)
|
||||
tag = null
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
|
||||
@@ -38,7 +38,7 @@ var/datum/vueui_module/player_panel/global_player_panel
|
||||
return
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if(!ui)
|
||||
ui = new(user, src, "admin-player-panel", 800, 600, "Modern player panel", nstate = interactive_state)
|
||||
ui = new(user, src, "admin-player-panel", 800, 600, "Modern player panel", state = interactive_state)
|
||||
ui.header = "minimal"
|
||||
ui.auto_update_content = TRUE
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/proc/init_subsystems()
|
||||
computer = new/obj/item/modular_computer/silicon/preset(src)
|
||||
alarm_monitor = new(src)
|
||||
law_manager = new(src)
|
||||
rcon = new(src)
|
||||
@@ -33,8 +32,17 @@
|
||||
|
||||
/mob/living/silicon/ai/init_subsystems()
|
||||
..()
|
||||
computer = new/obj/item/modular_computer/silicon/ai(src)
|
||||
ntnet_monitor = new(src)
|
||||
|
||||
/mob/living/silicon/pai/init_subsystems()
|
||||
..()
|
||||
computer = new/obj/item/modular_computer/silicon/pai(src)
|
||||
|
||||
/mob/living/silicon/robot/init_subsystems()
|
||||
..()
|
||||
computer = new/obj/item/modular_computer/silicon/robot(src)
|
||||
|
||||
/****************
|
||||
* Computer *
|
||||
*****************/
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
mob_size = 1//As a holographic projection, a pAI is massless except for its card device
|
||||
can_pull_size = 2 //max size for an object the pAI can pull
|
||||
|
||||
|
||||
var/network = "SS13"
|
||||
var/obj/machinery/camera/current = null
|
||||
var/ram = 100 // Used as currency to purchase different abilities
|
||||
@@ -46,6 +47,24 @@
|
||||
"Rodent" = list("squeaks","squeals","squeeks")
|
||||
)
|
||||
|
||||
var/list/pai_emotions = list(
|
||||
"Happy" = 1,
|
||||
"Cat" = 2,
|
||||
"Extremely Happy" = 3,
|
||||
"Face" = 4,
|
||||
"Laugh" = 5,
|
||||
"Off" = 6,
|
||||
"Sad" = 7,
|
||||
"Angry" = 8,
|
||||
"What" = 9,
|
||||
"Neutral" = 10,
|
||||
"Silly" = 11,
|
||||
"Nose" = 12,
|
||||
"Smirk" = 13,
|
||||
"Exclamation Points" = 14,
|
||||
"Question Mark" = 15
|
||||
)
|
||||
|
||||
var/obj/item/pai_cable/cable // The cable we produce and use when door or camera jacking
|
||||
id_card_type = /obj/item/card/id //Internal ID used to store copied owner access, and to check access for airlocks
|
||||
|
||||
@@ -68,11 +87,6 @@
|
||||
var/secHUD = 0 // Toggles whether the Security HUD is active or not
|
||||
var/medHUD = 0 // Toggles whether the Medical HUD is active or not
|
||||
|
||||
var/medical_cannotfind = 0
|
||||
var/datum/record/general/active // Datacore record declarations for record software
|
||||
|
||||
var/security_cannotfind = 0
|
||||
|
||||
var/obj/machinery/door/airlock/hackdoor // The airlock being hacked
|
||||
var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check
|
||||
var/hack_aborted = 0
|
||||
@@ -136,10 +150,12 @@
|
||||
add_language(LANGUAGE_TRADEBAND, 1)
|
||||
add_language(LANGUAGE_GUTTER, 1)
|
||||
add_language(LANGUAGE_EAL, 1)
|
||||
add_language(LANGUAGE_SIGN, 0)
|
||||
set_custom_sprite()
|
||||
|
||||
verbs += /mob/living/silicon/pai/proc/choose_chassis
|
||||
verbs += /mob/living/silicon/pai/proc/choose_verbs
|
||||
verbs += /mob/living/silicon/proc/computer_interact
|
||||
|
||||
//PDA
|
||||
pda = new(src)
|
||||
@@ -245,16 +261,6 @@
|
||||
src.reset_view(C)
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/pai/verb/reset_record_view()
|
||||
set category = "pAI Commands"
|
||||
set name = "Reset Records Software"
|
||||
|
||||
active = null
|
||||
security_cannotfind = 0
|
||||
medical_cannotfind = 0
|
||||
SSnanoui.update_uis(src)
|
||||
to_chat(usr, "<span class='notice'>You reset your record-viewing software.</span>")
|
||||
|
||||
/mob/living/silicon/pai/cancel_camera()
|
||||
set category = "pAI Commands"
|
||||
set name = "Cancel Camera View"
|
||||
@@ -509,3 +515,14 @@
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You are too small to pull that.</span>")
|
||||
return
|
||||
|
||||
|
||||
/mob/living/silicon/pai/verb/select_card_icon()
|
||||
set category = "pAI Commands"
|
||||
set name = "Select card icon"
|
||||
|
||||
if(stat || sleeping || paralysis || weakened)
|
||||
return
|
||||
|
||||
var/selection = input(src, "Choose an icon for you card.") in pai_emotions
|
||||
card.setEmotion(pai_emotions[selection])
|
||||
@@ -1,116 +0,0 @@
|
||||
var/list/pai_emotions = list(
|
||||
"Happy" = 1,
|
||||
"Cat" = 2,
|
||||
"Extremely Happy" = 3,
|
||||
"Face" = 4,
|
||||
"Laugh" = 5,
|
||||
"Off" = 6,
|
||||
"Sad" = 7,
|
||||
"Angry" = 8,
|
||||
"What" = 9,
|
||||
"Neutral" = 10,
|
||||
"Silly" = 11,
|
||||
"Nose" = 12,
|
||||
"Smirk" = 13,
|
||||
"Exclamation Points" = 14,
|
||||
"Question Mark" = 15
|
||||
)
|
||||
|
||||
/mob/living/silicon/pai/Initialize()
|
||||
..()
|
||||
software = SSpai.default_pai_software.Copy()
|
||||
|
||||
/mob/living/silicon/pai/verb/paiInterface()
|
||||
set category = "pAI Commands"
|
||||
set name = "Software Interface"
|
||||
|
||||
ui_interact(src)
|
||||
|
||||
/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
if(user != src)
|
||||
if(ui) ui.set_status(STATUS_CLOSE, 0)
|
||||
return
|
||||
|
||||
if(ui_key != "main")
|
||||
var/datum/pai_software/S = software[ui_key]
|
||||
if(S && !S.toggle)
|
||||
S.on_ui_interact(src, ui, force_open)
|
||||
else
|
||||
if(ui) ui.set_status(STATUS_CLOSE, 0)
|
||||
return
|
||||
|
||||
var/data[0]
|
||||
|
||||
// Software we have bought
|
||||
var/bought_software[0]
|
||||
// Software we have not bought
|
||||
var/not_bought_software[0]
|
||||
|
||||
var/list/pai_software_by_key = SSpai.pai_software_by_key
|
||||
|
||||
for(var/key in pai_software_by_key)
|
||||
var/datum/pai_software/S = pai_software_by_key[key]
|
||||
var/software_data[0]
|
||||
software_data["name"] = S.name
|
||||
software_data["id"] = S.id
|
||||
if(key in software)
|
||||
software_data["on"] = S.is_active(src)
|
||||
bought_software[++bought_software.len] = software_data
|
||||
else
|
||||
software_data["ram"] = S.ram_cost
|
||||
not_bought_software[++not_bought_software.len] = software_data
|
||||
|
||||
data["bought"] = bought_software
|
||||
data["not_bought"] = not_bought_software
|
||||
data["available_ram"] = ram
|
||||
|
||||
// Emotions
|
||||
var/emotions[0]
|
||||
for(var/name in pai_emotions)
|
||||
var/emote[0]
|
||||
emote["name"] = name
|
||||
emote["id"] = pai_emotions[name]
|
||||
emotions[++emotions.len] = emote
|
||||
|
||||
data["emotions"] = emotions
|
||||
data["current_emotion"] = card.current_emotion
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/mob/living/silicon/pai/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(.) return
|
||||
|
||||
if(href_list["software"])
|
||||
var/soft = href_list["software"]
|
||||
var/datum/pai_software/S = software[soft]
|
||||
if(S.toggle)
|
||||
S.toggle(src)
|
||||
else
|
||||
ui_interact(src, ui_key = soft)
|
||||
return 1
|
||||
|
||||
else if(href_list["stopic"])
|
||||
var/soft = href_list["stopic"]
|
||||
var/datum/pai_software/S = software[soft]
|
||||
if(S)
|
||||
return S.Topic(href, href_list)
|
||||
|
||||
else if(href_list["purchase"])
|
||||
var/soft = href_list["purchase"]
|
||||
var/datum/pai_software/S = SSpai.pai_software_by_key[soft]
|
||||
if(S && (ram >= S.ram_cost))
|
||||
ram -= S.ram_cost
|
||||
software[S.id] = S
|
||||
return 1
|
||||
|
||||
else if(href_list["image"])
|
||||
var/img = text2num(href_list["image"])
|
||||
if(1 <= img && img <= 15)
|
||||
card.setEmotion(img)
|
||||
return 1
|
||||
@@ -1,509 +0,0 @@
|
||||
/datum/pai_software
|
||||
// Name for the software. This is used as the button text when buying or opening/toggling the software
|
||||
var/name = "pAI software module"
|
||||
// RAM cost; pAIs start with 100 RAM, spending it on programs
|
||||
var/ram_cost = 0
|
||||
// ID for the software. This must be unique
|
||||
var/id = ""
|
||||
// Whether this software is a toggle or not
|
||||
// Toggled software should override toggle() and is_active()
|
||||
// Non-toggled software should override on_ui_interact() and Topic()
|
||||
var/toggle = 1
|
||||
// Whether pAIs should automatically receive this module at no cost
|
||||
var/default = 0
|
||||
|
||||
proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
return
|
||||
|
||||
proc/toggle(mob/living/silicon/pai/user)
|
||||
return
|
||||
|
||||
proc/is_active(mob/living/silicon/pai/user)
|
||||
return 0
|
||||
|
||||
/datum/pai_software/directives
|
||||
name = "Directives"
|
||||
ram_cost = 0
|
||||
id = "directives"
|
||||
toggle = 0
|
||||
default = 1
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
data["master"] = user.master
|
||||
data["dna"] = user.master_dna
|
||||
data["prime"] = user.pai_law0
|
||||
data["supplemental"] = user.pai_laws
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(href_list["getdna"])
|
||||
var/mob/living/M = P.loc
|
||||
var/count = 0
|
||||
|
||||
// Find the carrier
|
||||
while(!istype(M, /mob/living))
|
||||
if(!M || !M.loc || count > 6)
|
||||
//For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
|
||||
to_chat(src, "You are not being carried by anyone!")
|
||||
return 0
|
||||
M = M.loc
|
||||
count++
|
||||
|
||||
// Check the carrier
|
||||
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
|
||||
if(answer == "Yes")
|
||||
var/turf/T = get_turf_or_move(P.loc)
|
||||
for (var/mob/v in viewers(T))
|
||||
v.show_message("<span class='notice'>[M] presses \his thumb against [P].</span>", 3, "<span class='notice'>[P] makes a sharp clicking sound as it extracts DNA material from [M].</span>", 2)
|
||||
var/datum/dna/dna = M.dna
|
||||
to_chat(P, "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>")
|
||||
if(dna.unique_enzymes == P.master_dna)
|
||||
to_chat(P, "<b>DNA is a match to stored Master DNA.</b>")
|
||||
else
|
||||
to_chat(P, "<b>DNA does not match stored Master DNA.</b>")
|
||||
else
|
||||
to_chat(P, "[M] does not seem like \he [gender_datums[M.gender].is] going to provide a DNA sample willingly.")
|
||||
return 1
|
||||
|
||||
/datum/pai_software/radio_config
|
||||
name = "Radio Configuration"
|
||||
ram_cost = 0
|
||||
id = "radio"
|
||||
toggle = 0
|
||||
default = 1
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1)
|
||||
var/data[0]
|
||||
|
||||
data["listening"] = user.radio.broadcasting
|
||||
data["frequency"] = format_frequency(user.radio.frequency)
|
||||
|
||||
var/channels[0]
|
||||
for(var/ch_name in user.radio.channels)
|
||||
var/ch_stat = user.radio.channels[ch_name]
|
||||
var/ch_dat[0]
|
||||
ch_dat["name"] = ch_name
|
||||
// FREQ_LISTENING is const in /obj/item/device/radio
|
||||
ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING)
|
||||
channels[++channels.len] = ch_dat
|
||||
|
||||
data["channels"] = channels
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
P.radio.Topic(href, href_list)
|
||||
return 1
|
||||
|
||||
/datum/pai_software/crew_manifest
|
||||
name = "Crew Manifest"
|
||||
ram_cost = 5
|
||||
id = "manifest"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
// This is dumb, but NanoUI breaks if it has no data to send
|
||||
data["manifest"] = list("__json_cache" = SSrecords.get_manifest_json())
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/datum/pai_software/messenger
|
||||
name = "Digital Messenger"
|
||||
ram_cost = 5
|
||||
id = "messenger"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
data["receiver_off"] = user.pda.toff
|
||||
data["ringer_off"] = user.pda.message_silent
|
||||
data["current_ref"] = null
|
||||
data["current_name"] = user.current_pda_messaging
|
||||
|
||||
var/pdas[0]
|
||||
if(!user.pda.toff)
|
||||
for(var/obj/item/device/pda/P in sortAtom(PDAs))
|
||||
if(!P.owner || P.toff || P == user.pda || P.hidden) continue
|
||||
var/pda[0]
|
||||
pda["name"] = "[P]"
|
||||
pda["owner"] = "[P.owner]"
|
||||
pda["ref"] = "\ref[P]"
|
||||
if(P.owner == user.current_pda_messaging)
|
||||
data["current_ref"] = "\ref[P]"
|
||||
pdas[++pdas.len] = pda
|
||||
|
||||
data["pdas"] = pdas
|
||||
|
||||
var/messages[0]
|
||||
if(user.current_pda_messaging)
|
||||
for(var/index in user.pda.tnote)
|
||||
if(index["owner"] != user.current_pda_messaging)
|
||||
continue
|
||||
var/msg[0]
|
||||
var/sent = index["sent"]
|
||||
msg["sent"] = sent ? 1 : 0
|
||||
msg["target"] = index["owner"]
|
||||
msg["message"] = index["message"]
|
||||
messages[++messages.len] = msg
|
||||
|
||||
data["messages"] = messages
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(!isnull(P.pda))
|
||||
if(href_list["toggler"])
|
||||
P.pda.toff = href_list["toggler"] != "1"
|
||||
return 1
|
||||
else if(href_list["ringer"])
|
||||
P.pda.message_silent = href_list["ringer"] != "1"
|
||||
return 1
|
||||
else if(href_list["select"])
|
||||
var/s = href_list["select"]
|
||||
if(s == "*NONE*")
|
||||
P.current_pda_messaging = null
|
||||
else
|
||||
P.current_pda_messaging = s
|
||||
return 1
|
||||
else if(href_list["target"])
|
||||
if(P.silence_time)
|
||||
return alert("Communications circuits remain uninitialized.")
|
||||
|
||||
var/target = locate(href_list["target"])
|
||||
P.pda.create_message(P, target, 0)
|
||||
return 1
|
||||
|
||||
/datum/pai_software/med_records
|
||||
name = "Medical Records"
|
||||
ram_cost = 15
|
||||
id = "med_records"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
var/records[0]
|
||||
for(var/datum/record/general/R in sortRecord(SSrecords.records))
|
||||
var/record[0]
|
||||
record["name"] = R.name
|
||||
record["ref"] = "\ref[R]"
|
||||
records[++records.len] = record
|
||||
|
||||
data["records"] = records
|
||||
|
||||
var/datum/record/general/R = user.active
|
||||
data["general"] = R ? R.Listify(0) : null
|
||||
data["medical"] = R ? R.medical.Listify(0) : null
|
||||
data["could_not_find"] = user.medical_cannotfind
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(href_list["select"])
|
||||
var/datum/record/general/record = locate(href_list["select"])
|
||||
if(istype(record))
|
||||
if(!(record in SSrecords.records))
|
||||
P.active = null
|
||||
P.medical_cannotfind = 1
|
||||
else
|
||||
P.medical_cannotfind = 0
|
||||
P.active = record
|
||||
else
|
||||
P.medical_cannotfind = 1
|
||||
return 1
|
||||
|
||||
/datum/pai_software/sec_records
|
||||
name = "Security Records"
|
||||
ram_cost = 15
|
||||
id = "sec_records"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
var/records[0]
|
||||
for(var/datum/record/general/R in sortRecord(SSrecords.records))
|
||||
var/record[0]
|
||||
record["name"] = R.name
|
||||
record["ref"] = "\ref[R]"
|
||||
records[++records.len] = record
|
||||
|
||||
data["records"] = records
|
||||
|
||||
var/datum/record/general/R = user.active
|
||||
data["general"] = R ? R.Listify(0) : null
|
||||
data["security"] = R ? R.security.Listify() : null
|
||||
data["could_not_find"] = user.security_cannotfind
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(href_list["select"])
|
||||
var/datum/record/general/record = locate(href_list["select"])
|
||||
if(istype(record))
|
||||
if(!(record in SSrecords.records))
|
||||
P.active = null
|
||||
P.security_cannotfind = 1
|
||||
else
|
||||
P.security_cannotfind = 0
|
||||
P.active = record
|
||||
else
|
||||
P.active = null
|
||||
P.security_cannotfind = 1
|
||||
return 1
|
||||
|
||||
/datum/pai_software/door_jack
|
||||
name = "Door Jack"
|
||||
ram_cost = 30
|
||||
id = "door_jack"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
data["cable"] = user.cable != null
|
||||
data["machine"] = user.cable && (user.cable.machine != null)
|
||||
data["inprogress"] = user.hackdoor != null
|
||||
data["progress_a"] = round(user.hackprogress / 10)
|
||||
data["progress_b"] = user.hackprogress % 10
|
||||
data["aborted"] = user.hack_aborted
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(href_list["jack"])
|
||||
if(P.cable && P.cable.machine)
|
||||
P.hackdoor = P.cable.machine
|
||||
P.hackloop()
|
||||
return 1
|
||||
else if(href_list["cancel"])
|
||||
P.hackdoor = null
|
||||
return 1
|
||||
else if(href_list["cable"])
|
||||
var/turf/T = get_turf_or_move(P.loc)
|
||||
P.hack_aborted = 0
|
||||
P.cable = new /obj/item/pai_cable(T)
|
||||
for(var/mob/M in viewers(T))
|
||||
M.show_message("<span class='warning'>A port on [P] opens to reveal [P.cable], which promptly falls to the floor.</span>", 3,
|
||||
"<span class='warning'>You hear the soft click of something light and hard falling to the ground.</span>", 2)
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/pai/proc/hackloop()
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for(var/mob/living/silicon/ai/AI in player_list)
|
||||
if(T.loc)
|
||||
to_chat(AI, "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>")
|
||||
else
|
||||
to_chat(AI, "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>")
|
||||
var/obj/machinery/door/airlock/D = cable.machine
|
||||
if(!istype(D))
|
||||
hack_aborted = 1
|
||||
hackprogress = 0
|
||||
cable.machine = null
|
||||
hackdoor = null
|
||||
return
|
||||
while(hackprogress < 1000)
|
||||
if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
|
||||
hackprogress = min(hackprogress+rand(1, 20), 1000)
|
||||
else
|
||||
hack_aborted = 1
|
||||
hackprogress = 0
|
||||
hackdoor = null
|
||||
return
|
||||
if(hackprogress >= 1000)
|
||||
hackprogress = 0
|
||||
D.unlock() //unbolts door as long as bolt wires aren't cut
|
||||
D.open()
|
||||
cable.machine = null
|
||||
return
|
||||
sleep(10) // Update every second
|
||||
|
||||
/datum/pai_software/atmosphere_sensor
|
||||
name = "Atmosphere Sensor"
|
||||
ram_cost = 5
|
||||
id = "atmos_sense"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
var/turf/T = get_turf_or_move(user.loc)
|
||||
if(!T)
|
||||
data["reading"] = 0
|
||||
data["pressure"] = 0
|
||||
data["temperature"] = 0
|
||||
data["temperatureC"] = 0
|
||||
data["gas"] = list()
|
||||
else
|
||||
var/datum/gas_mixture/env = T.return_air()
|
||||
data["reading"] = 1
|
||||
var/pres = env.return_pressure() * 10
|
||||
data["pressure"] = "[round(pres/10)].[pres%10]"
|
||||
data["temperature"] = round(env.temperature)
|
||||
data["temperatureC"] = round(env.temperature-T0C)
|
||||
|
||||
var/t_moles = env.total_moles
|
||||
var/gases[0]
|
||||
for(var/g in env.gas)
|
||||
var/gas[0]
|
||||
gas["name"] = gas_data.name[g]
|
||||
gas["percent"] = round((env.gas[g] / t_moles) * 100)
|
||||
gases[++gases.len] = gas
|
||||
data["gas"] = gases
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/pai_software/sec_hud
|
||||
name = "Security HUD"
|
||||
ram_cost = 20
|
||||
id = "sec_hud"
|
||||
|
||||
toggle(mob/living/silicon/pai/user)
|
||||
user.secHUD = !user.secHUD
|
||||
|
||||
is_active(mob/living/silicon/pai/user)
|
||||
return user.secHUD
|
||||
|
||||
/datum/pai_software/med_hud
|
||||
name = "Medical HUD"
|
||||
ram_cost = 20
|
||||
id = "med_hud"
|
||||
|
||||
toggle(mob/living/silicon/pai/user)
|
||||
user.medHUD = !user.medHUD
|
||||
|
||||
is_active(mob/living/silicon/pai/user)
|
||||
return user.medHUD
|
||||
|
||||
/datum/pai_software/translator
|
||||
name = "Universal Translator"
|
||||
ram_cost = 35
|
||||
id = "translator"
|
||||
|
||||
toggle(mob/living/silicon/pai/user)
|
||||
// Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages
|
||||
user.translator_on = !user.translator_on
|
||||
if(user.translator_on)
|
||||
user.add_language(LANGUAGE_UNATHI)
|
||||
user.add_language(LANGUAGE_SIIK_MAAS)
|
||||
user.add_language(LANGUAGE_SKRELLIAN)
|
||||
user.add_language(LANGUAGE_ROOTSONG)
|
||||
else
|
||||
user.remove_language(LANGUAGE_UNATHI)
|
||||
user.remove_language(LANGUAGE_SIIK_MAAS)
|
||||
user.remove_language(LANGUAGE_SKRELLIAN)
|
||||
user.add_language(LANGUAGE_ROOTSONG)
|
||||
|
||||
is_active(mob/living/silicon/pai/user)
|
||||
return user.translator_on
|
||||
|
||||
/datum/pai_software/signaller
|
||||
name = "Remote Signaller"
|
||||
ram_cost = 5
|
||||
id = "signaller"
|
||||
toggle = 0
|
||||
|
||||
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
|
||||
var/data[0]
|
||||
|
||||
data["frequency"] = format_frequency(user.sradio.frequency)
|
||||
data["code"] = user.sradio.code
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
|
||||
if(!ui)
|
||||
// Don't copy-paste this unless you're making a pAI software module!
|
||||
ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
Topic(href, href_list)
|
||||
var/mob/living/silicon/pai/P = usr
|
||||
if(!istype(P)) return
|
||||
|
||||
if(href_list["send"])
|
||||
P.sradio.send_signal("ACTIVATE")
|
||||
for(var/mob/O in hearers(1, P.loc))
|
||||
O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2)
|
||||
return 1
|
||||
|
||||
else if(href_list["freq"])
|
||||
var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"]))
|
||||
if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)
|
||||
new_frequency = sanitize_frequency(new_frequency)
|
||||
P.sradio.set_frequency(new_frequency)
|
||||
return 1
|
||||
|
||||
else if(href_list["code"])
|
||||
P.sradio.code += text2num(href_list["code"])
|
||||
P.sradio.code = round(P.sradio.code)
|
||||
P.sradio.code = min(100, P.sradio.code)
|
||||
P.sradio.code = max(1, P.sradio.code)
|
||||
return 1
|
||||
@@ -5,6 +5,7 @@ var/global/ntnrc_uid = 0
|
||||
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
|
||||
var/list/messages = list()
|
||||
var/list/clients = list()
|
||||
var/direct = FALSE
|
||||
var/password
|
||||
|
||||
/datum/ntnet_conversation/New(var/name, var/no_operator)
|
||||
@@ -22,10 +23,8 @@ var/global/ntnrc_uid = 0
|
||||
log_ntirc("[user.client.ckey]/([username]) : [message]", ckey=key_name(user), conversation=title)
|
||||
|
||||
for(var/datum/computer_file/program/chatclient/C in clients)
|
||||
if(C.username == username || !C.computer.screen_on)
|
||||
continue
|
||||
if(C.computer.active_program == C || (C in C.computer.idle_threads))
|
||||
C.computer.output_message(FONT_SMALL("<b>([title]) [username]:</b> [message]"), 0)
|
||||
if(C.program_state > PROGRAM_STATE_KILLED && C.username != username)
|
||||
C.computer.output_message(FONT_SMALL("<b>[get_title(C)]) <i>[username]</i>:</b> [message]"), 0)
|
||||
|
||||
message = "[worldtime2text()] [username]: [message]"
|
||||
messages.Add(message)
|
||||
@@ -46,16 +45,27 @@ var/global/ntnrc_uid = 0
|
||||
/datum/ntnet_conversation/proc/add_client(var/datum/computer_file/program/chatclient/C)
|
||||
if(!istype(C))
|
||||
return
|
||||
if (C in clients)
|
||||
return
|
||||
clients.Add(C)
|
||||
// No operator, so we assume the channel was empty. Assign this user as operator.
|
||||
if(!operator)
|
||||
changeop(C)
|
||||
|
||||
for(var/datum/computer_file/program/chatclient/CC in clients)
|
||||
if(CC == C || !CC.computer.screen_on)
|
||||
continue
|
||||
if(CC.computer.active_program == CC || (CC in CC.computer.idle_threads))
|
||||
CC.computer.output_message(FONT_SMALL("<b>([title]) A new client ([C.username]) has entered the chat.</b>"), 0)
|
||||
if(CC.program_state > PROGRAM_STATE_KILLED && CC != C)
|
||||
if(!direct)
|
||||
CC.computer.output_message(FONT_SMALL("<b>([get_title(CC)]) <i>[C.username]</i> has entered the chat.</b>"), 0)
|
||||
|
||||
/datum/ntnet_conversation/proc/begin_direct(var/datum/computer_file/program/chatclient/CA, var/datum/computer_file/program/chatclient/CB)
|
||||
if(!istype(CA) || !istype(CB))
|
||||
return
|
||||
direct = TRUE
|
||||
clients.Add(CA)
|
||||
clients.Add(CB)
|
||||
|
||||
add_status_message("[CA.username] has opened direct conversation.")
|
||||
if(CB.program_state > PROGRAM_STATE_KILLED)
|
||||
CB.computer.output_message(FONT_SMALL("<b>([get_title(CB)]) <i>[CA.username]</i> has opened direct conversation with you.</b>"), 0)
|
||||
|
||||
/datum/ntnet_conversation/proc/remove_client(var/datum/computer_file/program/chatclient/C)
|
||||
if(!istype(C) || !(C in clients))
|
||||
@@ -70,10 +80,8 @@ var/global/ntnrc_uid = 0
|
||||
changeop(newop)
|
||||
|
||||
for(var/datum/computer_file/program/chatclient/CC in clients)
|
||||
if(CC == C || !CC.computer.screen_on)
|
||||
continue
|
||||
if(CC.computer.active_program == CC || (CC in CC.computer.idle_threads))
|
||||
CC.computer.output_message(FONT_SMALL("<b>([title]) A client ([C.username]) has left the chat.</b>"), 0)
|
||||
if(CC.program_state > PROGRAM_STATE_KILLED && CC != C)
|
||||
CC.computer.output_message(FONT_SMALL("<b>([get_title(CC)]) <i>[C.username]</i> has left the chat.</b>"), 0)
|
||||
|
||||
|
||||
/datum/ntnet_conversation/proc/changeop(var/datum/computer_file/program/chatclient/newop)
|
||||
@@ -85,11 +93,29 @@ var/global/ntnrc_uid = 0
|
||||
if(operator != client)
|
||||
return 0 // Not Authorised
|
||||
|
||||
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
|
||||
add_status_message("[client.username] has changed channel title from [get_title(client)] to [newtitle]")
|
||||
|
||||
for(var/datum/computer_file/program/chatclient/C in clients)
|
||||
if(C.program_state > PROGRAM_STATE_KILLED && C != client)
|
||||
C.computer.output_message(FONT_SMALL("([get_title(C)]) <i>[client.username]</i> has changed the channel title to <b>[newtitle]</b>."), 0)
|
||||
title = newtitle
|
||||
|
||||
for(var/datum/computer_file/program/chatclient/C in clients)
|
||||
if(C == client || !C.computer.screen_on)
|
||||
continue
|
||||
if(C.computer.active_program == src || (C in C.computer.idle_threads))
|
||||
C.computer.output_message(FONT_SMALL("([title]) A new client ([C.username]) has entered the chat."), 0)
|
||||
/datum/ntnet_conversation/proc/get_title(var/datum/computer_file/program/chatclient/cl = null)
|
||||
if(direct)
|
||||
var/names = list()
|
||||
for(var/datum/computer_file/program/chatclient/C in clients)
|
||||
names += C.username
|
||||
if(cl)
|
||||
names -= cl.username
|
||||
return "\[DM] [english_list(names)]"
|
||||
else
|
||||
return title
|
||||
|
||||
/datum/ntnet_conversation/proc/can_see(var/datum/computer_file/program/chatclient/cl)
|
||||
if(cl in clients)
|
||||
return TRUE
|
||||
if(cl.netadmin_mode)
|
||||
return TRUE
|
||||
if(!direct)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -11,6 +11,7 @@ var/global/datum/ntnet/ntnet_global = new()
|
||||
var/list/available_software_presets = list()
|
||||
var/list/available_news = list()
|
||||
var/list/chat_channels = list()
|
||||
var/list/chat_clients = list()
|
||||
var/list/fileservers = list()
|
||||
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
|
||||
// High values make displaying logs much laggier.
|
||||
|
||||
@@ -33,6 +33,15 @@
|
||||
else
|
||||
idle_threads.Remove(P)
|
||||
|
||||
for(var/s in enabled_services)
|
||||
var/datum/computer_file/program/service = s
|
||||
if(service.program_type & PROGRAM_SERVICE) // Safety checks
|
||||
if(service.service_state == PROGRAM_STATE_ACTIVE)
|
||||
if(active_program != service && !(service in idle_threads))
|
||||
service.process_tick()
|
||||
else
|
||||
enabled_services -= service
|
||||
|
||||
working = hard_drive && processor_unit && damage < broken_damage && computer_use_power()
|
||||
check_update_ui_need()
|
||||
|
||||
@@ -169,6 +178,13 @@
|
||||
for(var/datum/computer_file/program/P in idle_threads)
|
||||
P.kill_program(TRUE)
|
||||
idle_threads.Remove(P)
|
||||
|
||||
for(var/s in enabled_services)
|
||||
var/datum/computer_file/program/service = s
|
||||
if(service.program_type & PROGRAM_SERVICE) // Safety checks
|
||||
service.service_deactivate()
|
||||
service.service_state = PROGRAM_STATE_KILLED
|
||||
|
||||
if(loud)
|
||||
visible_message(SPAN_NOTICE("\The [src] shuts down."))
|
||||
SSvueui.close_uis(src)
|
||||
@@ -182,7 +198,13 @@
|
||||
// Autorun feature
|
||||
var/datum/computer_file/data/autorun = hard_drive ? hard_drive.find_file_by_name("autorun") : null
|
||||
if(istype(autorun))
|
||||
run_program(autorun.stored_data)
|
||||
run_program(autorun.stored_data, user)
|
||||
|
||||
for(var/s in enabled_services)
|
||||
var/datum/computer_file/program/service = s
|
||||
if(service.program_type & PROGRAM_SERVICE) // Safety checks
|
||||
service.service_activate()
|
||||
service.service_state = PROGRAM_STATE_ACTIVE
|
||||
|
||||
if(user)
|
||||
ui_interact(user)
|
||||
@@ -201,9 +223,10 @@
|
||||
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
|
||||
|
||||
|
||||
/obj/item/modular_computer/proc/run_program(prog)
|
||||
/obj/item/modular_computer/proc/run_program(prog, mob/user)
|
||||
var/datum/computer_file/program/P = null
|
||||
var/mob/user = usr
|
||||
if(!istype(user))
|
||||
user = usr
|
||||
if(hard_drive)
|
||||
P = hard_drive.find_file_by_name(prog)
|
||||
|
||||
@@ -294,6 +317,58 @@
|
||||
/obj/item/modular_computer/get_cell()
|
||||
return battery_module ? battery_module.get_cell() : DEVICE_NO_CELL
|
||||
|
||||
/obj/item/modular_computer/proc/toggle_service(service, mob/user, var/datum/computer_file/program/S = null)
|
||||
if(!S)
|
||||
S = hard_drive?.find_file_by_name(service)
|
||||
|
||||
if(!istype(S)) // Program not found or it's not executable program.
|
||||
to_chat(user, SPAN_WARNING("\The [src] displays, \"I/O ERROR - Unable to locate [service]\""))
|
||||
return
|
||||
|
||||
if(S.service_state == PROGRAM_STATE_ACTIVE)
|
||||
disable_service(null, user, S)
|
||||
else
|
||||
enable_service(null, user, S)
|
||||
|
||||
|
||||
/obj/item/modular_computer/proc/enable_service(service, mob/user, var/datum/computer_file/program/S = null)
|
||||
if(!S)
|
||||
S = hard_drive?.find_file_by_name(service)
|
||||
|
||||
if(!istype(S)) // Program not found or it's not executable program.
|
||||
to_chat(user, SPAN_WARNING("\The [src] displays, \"I/O ERROR - Unable to enable [service]\""))
|
||||
return
|
||||
|
||||
S.computer = src
|
||||
|
||||
if(!S.is_supported_by_hardware(hardware_flag, 1, user))
|
||||
return
|
||||
|
||||
if(S in enabled_services)
|
||||
return
|
||||
|
||||
enabled_services += S
|
||||
|
||||
// Start service
|
||||
S.service_activate()
|
||||
S.service_state = PROGRAM_STATE_ACTIVE
|
||||
|
||||
|
||||
/obj/item/modular_computer/proc/disable_service(service, mob/user, var/datum/computer_file/program/S = null)
|
||||
if(!S)
|
||||
S = hard_drive?.find_file_by_name(service)
|
||||
|
||||
if(!istype(S)) // Program not found or it's not executable program.
|
||||
return
|
||||
|
||||
if(!(S in enabled_services))
|
||||
return
|
||||
enabled_services -= S
|
||||
|
||||
// Stop service
|
||||
S.service_deactivate()
|
||||
S.service_state = PROGRAM_STATE_KILLED
|
||||
|
||||
/obj/item/modular_computer/proc/output_message(var/message, var/message_range)
|
||||
message_range += message_output_range
|
||||
if(message_range == 0)
|
||||
@@ -301,4 +376,4 @@
|
||||
if(istype(user))
|
||||
to_chat(user, message)
|
||||
return
|
||||
visible_message(message, range = message_range)
|
||||
visible_message(message, range = message_range)
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["desc"], P.filedesc, ., data)
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["autorun"], (istype(autorun) && (autorun.stored_data == P.filename)), ., data)
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["running"], (P in idle_threads), ., data)
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["type"], P.program_type, ., data)
|
||||
VUEUI_SET_CHECK_IFNOTSET(data["programs"][P.filename]["service"], list(), ., data)
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["service"]["enabled"], (P in enabled_services), ., data)
|
||||
VUEUI_SET_CHECK(data["programs"][P.filename]["service"]["online"], (P.service_state == PROGRAM_STATE_ACTIVE), ., data)
|
||||
|
||||
// Handles user's GUI input
|
||||
/obj/item/modular_computer/Topic(href, href_list)
|
||||
@@ -90,8 +94,8 @@
|
||||
update_uis()
|
||||
to_chat(user, SPAN_NOTICE("Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed."))
|
||||
|
||||
if(href_list["PC_runprogram"])
|
||||
. = run_program(href_list["PC_runprogram"])
|
||||
if(href_list["PC_runprogram"] )
|
||||
. = run_program(href_list["PC_runprogram"], usr)
|
||||
ui_interact(usr)
|
||||
|
||||
if(href_list["PC_setautorun"])
|
||||
@@ -106,6 +110,10 @@
|
||||
autorun.stored_data = null
|
||||
else
|
||||
autorun.stored_data = href_list["PC_setautorun"]
|
||||
|
||||
if( href_list["PC_toggleservice"] )
|
||||
toggle_service(href_list["PC_toggleservice"], usr)
|
||||
return 1
|
||||
|
||||
if(.)
|
||||
update_uis()
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
|
||||
var/light_strength = 0 // Intensity of light this computer emits. Comparable to numbers light fixtures use.
|
||||
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
|
||||
var/list/enabled_services = list() // Enabled services that run in background and handle things pasively. Supported on all CPUs.
|
||||
var/power_has_failed = FALSE
|
||||
var/is_holographic = FALSE
|
||||
|
||||
|
||||
@@ -10,8 +10,13 @@
|
||||
base_active_power_usage = 25
|
||||
max_hardware_size = 3
|
||||
max_damage = 50
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
enrolled = 2
|
||||
var/mob/living/silicon/computer_host // Thing that contains this computer. Used for silicon computers
|
||||
|
||||
/obj/item/modular_computer/silicon/ui_host()
|
||||
. = computer_host
|
||||
|
||||
/obj/item/modular_computer/silicon/Initialize(mapload)
|
||||
. = ..()
|
||||
if(istype(loc, /mob/living/silicon))
|
||||
@@ -30,10 +35,10 @@
|
||||
if(istype(computer_host, /mob/living/silicon/robot))
|
||||
var/mob/living/silicon/robot/R = computer_host
|
||||
return R.cell_use_power(power_usage)
|
||||
// If we are in AI or pAI we just don't botherwith power use.
|
||||
// If we are in AI or pAI we just don't bother with power use.
|
||||
return TRUE
|
||||
else
|
||||
// If we don't have host, then we let regular computer code handle power - like batteries and tesla coils
|
||||
// If we don't have host, then we let regular computer code handle power - like batteries and tesla coils.
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/silicon/Destroy()
|
||||
@@ -42,3 +47,14 @@
|
||||
|
||||
/obj/item/modular_computer/silicon/Click(location, control, params)
|
||||
return attack_self(usr)
|
||||
|
||||
/obj/item/modular_computer/silicon/install_default_hardware()
|
||||
. = ..()
|
||||
processor_unit = new /obj/item/computer_hardware/processor_unit(src)
|
||||
hard_drive = new /obj/item/computer_hardware/hard_drive(src)
|
||||
network_card = new /obj/item/computer_hardware/network_card/advanced(src)
|
||||
|
||||
/obj/item/modular_computer/silicon/install_default_programs()
|
||||
hard_drive.store_file(new /datum/computer_file/program/filemanager())
|
||||
hard_drive.store_file(new /datum/computer_file/program/ntnetdownload())
|
||||
hard_drive.remove_file(hard_drive.find_file_by_name("clientmanager"))
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/obj/item/modular_computer/silicon/ai
|
||||
hardware_flag = PROGRAM_SILICON_AI
|
||||
|
||||
/obj/item/modular_computer/silicon/ai/install_default_hardware()
|
||||
. = ..()
|
||||
network_card = new /obj/item/computer_hardware/network_card/wired(src)
|
||||
|
||||
/obj/item/modular_computer/silicon/ai/install_default_programs()
|
||||
. = ..()
|
||||
hard_drive.store_file(new /datum/computer_file/program/records())
|
||||
hard_drive.store_file(new /datum/computer_file/program/rcon_console())
|
||||
hard_drive.store_file(new /datum/computer_file/program/suit_sensors())
|
||||
hard_drive.store_file(new /datum/computer_file/program/power_monitor())
|
||||
|
||||
/obj/item/modular_computer/silicon/robot
|
||||
hardware_flag = PROGRAM_SILICON_ROBOT
|
||||
|
||||
/obj/item/modular_computer/silicon/pai
|
||||
hardware_flag = PROGRAM_SILICON_PAI
|
||||
|
||||
/obj/item/modular_computer/silicon/ai/install_default_hardware()
|
||||
. = ..()
|
||||
hard_drive = new /obj/item/computer_hardware/hard_drive/small(src)
|
||||
|
||||
/obj/item/modular_computer/silicon/pai/install_default_programs()
|
||||
. = ..()
|
||||
hard_drive.store_file(new /datum/computer_file/program/pai_directives())
|
||||
hard_drive.store_file(new /datum/computer_file/program/pai_radio())
|
||||
@@ -1,13 +0,0 @@
|
||||
/obj/item/modular_computer/silicon/preset
|
||||
enrolled = 2
|
||||
|
||||
/obj/item/modular_computer/silicon/preset/install_default_hardware()
|
||||
. = ..()
|
||||
processor_unit = new /obj/item/computer_hardware/processor_unit(src)
|
||||
hard_drive = new /obj/item/computer_hardware/hard_drive(src)
|
||||
network_card = new /obj/item/computer_hardware/network_card/advanced(src)
|
||||
|
||||
/obj/item/modular_computer/silicon/preset/install_default_programs()
|
||||
hard_drive.store_file(new /datum/computer_file/program/filemanager())
|
||||
hard_drive.store_file(new /datum/computer_file/program/ntnetdownload())
|
||||
hard_drive.remove_file(hard_drive.find_file_by_name("clientmanager"))
|
||||
@@ -2,6 +2,7 @@
|
||||
/datum/computer_file/program
|
||||
filetype = "PRG"
|
||||
filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET!
|
||||
var/program_type = PROGRAM_NORMAL // Program type, used to determine if program runs in background or not.
|
||||
var/required_access_run // List of required accesses to run the program.
|
||||
var/required_access_download // List of required accesses to download the program.
|
||||
var/requires_access_to_run = PROGRAM_ACCESS_ONE // Whether the program checks for required_access when run. (1 = requires single access, 2 = requires single access from list, 3 = requires all access from list)
|
||||
@@ -22,7 +23,8 @@
|
||||
var/available_on_syndinet = FALSE // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
|
||||
var/computer_emagged = FALSE // Set to TRUE if computer that's running us was emagged. Computer updates this every Process() tick
|
||||
var/ui_header // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
|
||||
var/color = "#FFFFFF" // The color of light the computer should emit when this program is open.
|
||||
var/color = "#FFFFFF" // The color of light the computer should emit when this program is open.
|
||||
var/service_state = PROGRAM_STATE_KILLED // PROGRAM_STATE_KILLED or PROGRAM_STATE_ACTIVE - specifies whether this program's service is running.
|
||||
|
||||
/datum/computer_file/program/New(var/obj/item/modular_computer/comp)
|
||||
..()
|
||||
@@ -30,6 +32,8 @@
|
||||
computer = comp
|
||||
|
||||
/datum/computer_file/program/Destroy()
|
||||
computer.idle_threads -= src
|
||||
computer.enabled_services -= src
|
||||
computer = null
|
||||
. = ..()
|
||||
|
||||
@@ -135,6 +139,10 @@
|
||||
if(!check_type)
|
||||
check_type = requires_access_to_download
|
||||
|
||||
if(istype(computer, /obj/item/modular_computer/silicon/pai))
|
||||
check_type = requires_access_to_run
|
||||
access_to_check = required_access_run
|
||||
|
||||
// No required_access, allow it.
|
||||
if(!access_to_check || !requires_access_to_download)
|
||||
return TRUE
|
||||
@@ -213,7 +221,6 @@
|
||||
|
||||
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
|
||||
// Topic calls are automagically forwarded from NanoModule this program contains.
|
||||
// Calls beginning with "PRG_" are reserved for programs handling.
|
||||
// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program)
|
||||
// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE.
|
||||
/datum/computer_file/program/Topic(href, href_list)
|
||||
@@ -228,3 +235,12 @@
|
||||
return NM.check_eye(user)
|
||||
else
|
||||
return -1
|
||||
|
||||
// Is called when program service is being activated
|
||||
// Returns 1 if service startup was sucessfull
|
||||
/datum/computer_file/program/proc/service_activate()
|
||||
return 0
|
||||
|
||||
// Is called when program service is being deactivated
|
||||
/datum/computer_file/program/proc/service_deactivate()
|
||||
return
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/obj/item/modular_computer/initial_data()
|
||||
return list("_PC" = get_header_data())
|
||||
|
||||
/datum/computer_file/program/initial_data()
|
||||
return list("_PC" = get_header_data())
|
||||
|
||||
/obj/item/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
return
|
||||
|
||||
computer.visible_message(SPAN_NOTICE("\The [computer]'s screen brightly flashes and emits a loud electrical buzzing."))
|
||||
computer.enabled = FALSE
|
||||
computer.update_icon()
|
||||
computer.shutdown_computer(0)
|
||||
spark(get_turf(src), 10, alldirs)
|
||||
|
||||
if(computer.hard_drive)
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
requires_ntnet = TRUE
|
||||
network_destination = "atmospheric control system"
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_SILICON
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP | PROGRAM_STATIONBOUND
|
||||
size = 17
|
||||
color = LIGHT_COLOR_CYAN
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
requires_ntnet = TRUE
|
||||
network_destination = "RCON remote control system"
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_SILICON
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_STATIONBOUND
|
||||
size = 19
|
||||
color = LIGHT_COLOR_GREEN
|
||||
|
||||
@@ -103,6 +103,6 @@
|
||||
requires_ntnet = TRUE
|
||||
network_destination = "APC Coordinator"
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_SILICON
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_STATIONBOUND
|
||||
size = 9
|
||||
color = LIGHT_COLOR_GREEN
|
||||
@@ -0,0 +1,44 @@
|
||||
/datum/computer_file/program/manifest
|
||||
filename = "manifest"
|
||||
filedesc = "Crew Manifest"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is used for viewing the crew manifest."
|
||||
size = 3
|
||||
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
|
||||
|
||||
/datum/computer_file/program/manifest/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "manifest", 450, 600, "Crew Manifest")
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/manifest/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "manifest", 450, 600, "Crew Manifest")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/manifest/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
VUEUI_SET_CHECK(data["manifest"], SSrecords.get_manifest_list(), ., data)
|
||||
|
||||
/datum/computer_file/program/manifest/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
host.radio.Topic(href, href_list)
|
||||
@@ -15,6 +15,7 @@
|
||||
var/datum/ntnet_conversation/channel
|
||||
var/operator_mode = FALSE // Channel operator mode
|
||||
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
|
||||
var/list/directmessagechannels = list()
|
||||
color = LIGHT_COLOR_GREEN
|
||||
|
||||
/datum/computer_file/program/chatclient/New()
|
||||
@@ -60,9 +61,12 @@
|
||||
channel = C
|
||||
if(href_list["PRG_leavechannel"])
|
||||
. = TRUE
|
||||
if(channel)
|
||||
if(channel && !channel.direct)
|
||||
channel.remove_client(src)
|
||||
channel = null
|
||||
if(href_list["PRG_backtomain"])
|
||||
. = TRUE
|
||||
channel = null
|
||||
if(href_list["PRG_newchannel"])
|
||||
. = TRUE
|
||||
var/mob/living/user = usr
|
||||
@@ -98,10 +102,16 @@
|
||||
var/new_name = sanitize(input(user, "Enter new nickname or leave blank to cancel:"))
|
||||
if(!new_name)
|
||||
return TRUE
|
||||
if(channel)
|
||||
channel.add_status_message("[username] is now known as [new_name].")
|
||||
var/comp_name = ckey(new_name)
|
||||
for(var/cl in ntnet_global.chat_clients)
|
||||
var/datum/computer_file/program/chatclient/C = cl
|
||||
if(ckey(C.username) == comp_name || comp_name == "cancel")
|
||||
alert(user, "This nickname is already taken.")
|
||||
return TRUE
|
||||
for(var/datum/ntnet_conversation/channel in ntnet_global.chat_channels)
|
||||
if(src in channel.clients)
|
||||
channel.add_status_message("[username] is now known as [new_name].")
|
||||
username = new_name
|
||||
|
||||
if(href_list["PRG_savelog"])
|
||||
. = TRUE
|
||||
if(!channel)
|
||||
@@ -156,6 +166,30 @@
|
||||
channel.password = ""
|
||||
else
|
||||
channel.password = newpassword
|
||||
if(href_list["PRG_directmessage"])
|
||||
. = TRUE
|
||||
var/clients = list()
|
||||
var/names = list()
|
||||
for(var/cl in ntnet_global.chat_clients)
|
||||
var/datum/computer_file/program/chatclient/C = cl
|
||||
clients[C.username] = C
|
||||
names += C.username
|
||||
names -= username // Remove ourselves
|
||||
names += "== Cancel =="
|
||||
var/picked = input(usr, "Select with whom you would like to start a conversation.") in names
|
||||
if(picked == "== Cancel ==")
|
||||
return
|
||||
var/datum/computer_file/program/chatclient/otherClient = clients[picked]
|
||||
if(picked)
|
||||
if(directmessagechannels[otherClient])
|
||||
channel = directmessagechannels[otherClient]
|
||||
return
|
||||
var/datum/ntnet_conversation/C = new /datum/ntnet_conversation("", TRUE)
|
||||
C.begin_direct(src, otherClient)
|
||||
channel = C
|
||||
directmessagechannels[otherClient] = C
|
||||
otherClient.directmessagechannels[src] = C
|
||||
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
..()
|
||||
@@ -176,11 +210,14 @@
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
|
||||
/datum/computer_file/program/chatclient/kill_program(var/forced = FALSE)
|
||||
if(channel)
|
||||
channel.remove_client(src)
|
||||
channel = null
|
||||
channel = null
|
||||
ntnet_global.chat_clients -= src
|
||||
..(forced)
|
||||
|
||||
/datum/computer_file/program/chatclient/run_program(var/mob/user)
|
||||
ntnet_global.chat_clients += src
|
||||
return ..(user)
|
||||
|
||||
/datum/nano_module/program/computer_chatclient
|
||||
name = "NTNet Relay Chat Client"
|
||||
|
||||
@@ -198,7 +235,7 @@
|
||||
|
||||
data["adminmode"] = C.netadmin_mode
|
||||
if(C.channel)
|
||||
data["title"] = C.channel.title
|
||||
data["title"] = C.channel.get_title(C)
|
||||
var/list/messages[0]
|
||||
for(var/M in C.channel.messages)
|
||||
messages.Add(list(list(
|
||||
@@ -208,19 +245,21 @@
|
||||
var/list/clients[0]
|
||||
for(var/datum/computer_file/program/chatclient/cl in C.channel.clients)
|
||||
clients.Add(list(list(
|
||||
"name" = cl.username
|
||||
"name" = cl.username,
|
||||
"active" = cl.program_state > PROGRAM_STATE_KILLED
|
||||
)))
|
||||
data["clients"] = clients
|
||||
C.operator_mode = (C.channel.operator == C) ? 1 : 0
|
||||
data["is_operator"] = C.operator_mode || C.netadmin_mode
|
||||
|
||||
data["is_direct"] = C.channel.direct
|
||||
else // Channel selection screen
|
||||
var/list/all_channels[0]
|
||||
for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels)
|
||||
if(conv && conv.title)
|
||||
if(conv && conv.title && conv.can_see(program))
|
||||
all_channels.Add(list(list(
|
||||
"chan" = conv.title,
|
||||
"id" = conv.id
|
||||
"chan" = conv.get_title(C),
|
||||
"id" = conv.id,
|
||||
"con" = (program in conv.clients)
|
||||
)))
|
||||
data["all_channels"] = all_channels
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
requires_ntnet = TRUE
|
||||
requires_ntnet_feature = NTNET_SYSTEMCONTROL
|
||||
requires_access_to_run = PROGRAM_ACCESS_LIST_ONE
|
||||
usage_flags = PROGRAM_ALL_REGULAR | PROGRAM_STATIONBOUND
|
||||
|
||||
var/records_type = RECORD_GENERAL | RECORD_MEDICAL | RECORD_SECURITY | RECORD_VIRUS | RECORD_WARRANT | RECORD_LOCKED
|
||||
var/edit_type = RECORD_GENERAL | RECORD_MEDICAL | RECORD_SECURITY | RECORD_VIRUS | RECORD_WARRANT | RECORD_LOCKED
|
||||
@@ -77,6 +78,12 @@
|
||||
program_icon_state = "employment_record"
|
||||
color = LIGHT_COLOR_BLUE
|
||||
|
||||
/datum/computer_file/program/records/pai
|
||||
available_on_ntnet = 1
|
||||
extended_desc = "This program is used to view crew records."
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
edit_type = 0
|
||||
|
||||
/datum/computer_file/program/records/New()
|
||||
. = ..()
|
||||
listener = new(src)
|
||||
@@ -339,4 +346,4 @@
|
||||
var/datum/computer_file/program/records/t = target
|
||||
if(istype(t) && !t.isEditing)
|
||||
if(t.active == r || t.active_virus == r)
|
||||
SSvueui.check_uis_for_change(t)
|
||||
SSvueui.check_uis_for_change(t)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
requires_ntnet = TRUE
|
||||
network_destination = "crew lifesigns monitoring system"
|
||||
size = 11
|
||||
usage_flags = PROGRAM_ALL_REGULAR
|
||||
usage_flags = PROGRAM_ALL_REGULAR | PROGRAM_STATIONBOUND
|
||||
color = LIGHT_COLOR_CYAN
|
||||
|
||||
/datum/computer_file/program/suit_sensors/ui_interact(mob/user)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/datum/computer_file/program/pai_atmos
|
||||
filename = "pai_atmos"
|
||||
filedesc = "Atmosphere Sensor"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is for viewing local atmospheric data."
|
||||
size = 0
|
||||
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_atmos/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-pai-atmosphere", 400, 200, "pAI Atmosphere Sensor")
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/pai_atmos/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "mcomputer-pai-atmosphere", 400, 200, "pAI Atmosphere Sensor")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/pai_atmos/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
var/turf/T = get_turf_or_move(host.loc)
|
||||
|
||||
|
||||
if(T)
|
||||
var/datum/gas_mixture/env = T.return_air()
|
||||
VUEUI_SET_CHECK(data["read"], TRUE, ., data)
|
||||
VUEUI_SET_CHECK(data["press"], env.return_pressure(), ., data)
|
||||
VUEUI_SET_CHECK(data["temp"], env.temperature, ., data)
|
||||
VUEUI_SET_CHECK(data["tempC"], env.temperature-T0C, ., data)
|
||||
VUEUI_SET_CHECK_IFNOTSET(data["gas"], list("_" = "_"), ., data)
|
||||
for(var/g in gas_data.gases)
|
||||
if(!(g in env.gas))
|
||||
VUEUI_SET_CHECK(data["gas"][g], null, ., data)
|
||||
else
|
||||
VUEUI_SET_CHECK(data["gas"][g], env.gas[g], ., data)
|
||||
else
|
||||
VUEUI_SET_CHECK(data["read"], FALSE, ., data)
|
||||
VUEUI_SET_CHECK(data["press"], 0, ., data)
|
||||
VUEUI_SET_CHECK(data["temp"], T0C, ., data)
|
||||
VUEUI_SET_CHECK(data["tempC"], 0, ., data)
|
||||
VUEUI_SET_CHECK_IFNOTSET(data["gas"], list("_" = "_"), ., data)
|
||||
for(var/g in gas_data.gases)
|
||||
VUEUI_SET_CHECK(data["gas"][g], null, ., data)
|
||||
@@ -0,0 +1,79 @@
|
||||
/datum/computer_file/program/pai_directives
|
||||
filename = "pai_directives"
|
||||
filedesc = "pAI Directives"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is for viewing currently assigned directives."
|
||||
size = 0
|
||||
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_directives/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-pai-directives", 450, 500, "pAI directives")
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/pai_directives/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "mcomputer-pai-directives", 450, 500, "pAI directives")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/pai_directives/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
VUEUI_SET_CHECK(data["master"], host.master, ., data)
|
||||
VUEUI_SET_CHECK(data["dna"], host.master_dna, ., data)
|
||||
VUEUI_SET_CHECK(data["prime"], host.pai_law0, ., data)
|
||||
VUEUI_SET_CHECK(data["supplemental"], host.pai_laws, ., data)
|
||||
|
||||
/datum/computer_file/program/pai_directives/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
if(href_list["getdna"])
|
||||
var/mob/living/M = host.loc
|
||||
var/count = 0
|
||||
|
||||
// Find the carrier
|
||||
while(!istype(M, /mob/living))
|
||||
if(!M || !M.loc || count > 6)
|
||||
//For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
|
||||
to_chat(src, SPAN_WARNING("You are not being carried by anyone!"))
|
||||
return 0
|
||||
M = M.loc
|
||||
count++
|
||||
|
||||
// Check the carrier
|
||||
var/answer = input(M, "[host] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[host] Check DNA", "No") in list("Yes", "No")
|
||||
if(answer == "Yes")
|
||||
var/turf/T = get_turf_or_move(host.loc)
|
||||
for (var/mob/v in viewers(T))
|
||||
v.show_message(SPAN_NOTICE("[M] presses \his thumb against [host]."), 3, SPAN_NOTICE("[host] makes a sharp clicking sound as it extracts DNA material from [M]."), 2)
|
||||
var/datum/dna/dna = M.dna
|
||||
to_chat(host, "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>")
|
||||
if(dna.unique_enzymes == host.master_dna)
|
||||
to_chat(host, SPAN_NOTICE("<b>Provided DNA is a match to stored Master DNA.</b>"))
|
||||
else
|
||||
to_chat(host, SPAN_WARNING("<b>Provided DNA does not match stored Master DNA.</b>"))
|
||||
else
|
||||
to_chat(host, SPAN_WARNING("[M] does not seem like \he [gender_datums[M.gender].is] going to provide a DNA sample willingly."))
|
||||
return 1
|
||||
@@ -0,0 +1,106 @@
|
||||
/datum/computer_file/program/pai_doorjack
|
||||
filename = "doorjack"
|
||||
filedesc = "Door Jack"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is used to access standard-issue pAI door jack systems."
|
||||
size = 12
|
||||
|
||||
available_on_ntnet = 1
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_doorjack/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-pai-doorjack", 400, 150, "Door Jack")
|
||||
ui.auto_update_content = TRUE
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/pai_doorjack/vueui_transfer(oldobj)
|
||||
var/uis = SSvueui.transfer_uis(oldobj, src, "mcomputer-pai-doorjack", 400, 150, "Door Jack")
|
||||
for(var/i in uis)
|
||||
var/datum/vueui/ui = i
|
||||
ui.auto_update_content = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/pai_doorjack/vueui_on_transfer(datum/vueui/ui)
|
||||
. = ..()
|
||||
ui.auto_update_content = FALSE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/pai_doorjack/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
VUEUI_SET_CHECK(data["extended"], !!host.cable, ., data)
|
||||
VUEUI_SET_CHECK(data["connected"], !!host.cable?.machine , ., data)
|
||||
VUEUI_SET_CHECK(data["ishacking"], !!host.hackdoor, ., data)
|
||||
VUEUI_SET_CHECK(data["progress"], host.hackprogress, ., data)
|
||||
VUEUI_SET_CHECK(data["aborted"], host.hack_aborted, ., data)
|
||||
|
||||
/datum/computer_file/program/pai_doorjack/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
if(href_list["hack"])
|
||||
if(host.cable && host.cable.machine)
|
||||
host.hackdoor = host.cable.machine
|
||||
host.hackloop()
|
||||
return 1
|
||||
if(href_list["cancel"])
|
||||
host.hackdoor = null
|
||||
return 1
|
||||
if(href_list["extend"])
|
||||
var/turf/T = get_turf_or_move(host.loc)
|
||||
host.hack_aborted = 0
|
||||
host.cable = new /obj/item/pai_cable(T)
|
||||
T.visible_message(SPAN_WARNING("A port on [host] opens to reveal [host.cable], which promptly falls to the floor."),
|
||||
SPAN_WARNING("You hear the soft click of something light and hard falling to the ground."))
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/pai/proc/hackloop()
|
||||
var/turf/T = get_turf_or_move(src.loc)
|
||||
for(var/mob/living/silicon/ai/AI in player_list)
|
||||
if(T.loc)
|
||||
to_chat(AI, "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>")
|
||||
else
|
||||
to_chat(AI, "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>")
|
||||
var/obj/machinery/door/airlock/D = cable.machine
|
||||
if(!istype(D))
|
||||
hack_aborted = 1
|
||||
hackprogress = 0
|
||||
cable.machine = null
|
||||
hackdoor = null
|
||||
return
|
||||
while(hackprogress < 1000)
|
||||
if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
|
||||
hackprogress = min(hackprogress+rand(1, 20), 1000)
|
||||
else
|
||||
hack_aborted = 1
|
||||
hackprogress = 0
|
||||
hackdoor = null
|
||||
return
|
||||
if(hackprogress >= 1000)
|
||||
hackprogress = 0
|
||||
D.unlock() //unbolts door as long as bolt wires aren't cut
|
||||
D.open()
|
||||
cable.machine = null
|
||||
return
|
||||
sleep(10) // Update every second
|
||||
@@ -0,0 +1,57 @@
|
||||
/datum/computer_file/program/pai_sechud
|
||||
filename = "sechud"
|
||||
filedesc = "pAI Security HUD"
|
||||
extended_desc = "This service enables the integrated security HUD."
|
||||
size = 10
|
||||
program_type = PROGRAM_SERVICE
|
||||
available_on_ntnet = 1
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_sechud/service_activate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
host.secHUD = TRUE
|
||||
|
||||
/datum/computer_file/program/pai_sechud/service_deactivate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
host.secHUD = FALSE
|
||||
|
||||
/datum/computer_file/program/pai_medhud
|
||||
filename = "medhud"
|
||||
filedesc = "pAI Medical HUD"
|
||||
extended_desc = "This service enables the integrated medical HUD."
|
||||
size = 10
|
||||
program_type = PROGRAM_SERVICE
|
||||
available_on_ntnet = 1
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_medhud/service_activate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
host.medHUD = TRUE
|
||||
|
||||
/datum/computer_file/program/pai_medhud/service_deactivate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
host.medHUD = FALSE
|
||||
@@ -0,0 +1,56 @@
|
||||
/datum/computer_file/program/pai_radio
|
||||
filename = "pai_radio"
|
||||
filedesc = "Radio Configuration"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is used to configure the integrated pAI radio."
|
||||
size = 0
|
||||
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_radio/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-pai-radio", 400, 150, "pAI Radio Configuration")
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/pai_radio/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "mcomputer-pai-radio", 400, 150, "pAI Radio Configuration")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/pai_radio/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
VUEUI_SET_CHECK(data["listening"], host.radio.broadcasting, ., data)
|
||||
VUEUI_SET_CHECK(data["frequency"], format_frequency(host.radio.frequency), ., data)
|
||||
|
||||
LAZYINITLIST(data["channels"])
|
||||
for(var/ch_name in host.radio.channels)
|
||||
var/ch_stat = host.radio.channels[ch_name]
|
||||
VUEUI_SET_CHECK(data["channels"][ch_name], !!(ch_stat & host.radio.FREQ_LISTENING), ., data)
|
||||
|
||||
/datum/computer_file/program/pai_radio/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
host.radio.Topic(href, href_list)
|
||||
SSvueui.check_uis_for_change(src)
|
||||
@@ -0,0 +1,69 @@
|
||||
/datum/computer_file/program/pai_signaler
|
||||
filename = "signaler"
|
||||
filedesc = "Remote Signaller"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program can be used to send wide-range signals of various frequencies."
|
||||
size = 3
|
||||
available_on_ntnet = 1
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_signaler/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-pai-signaler", 400, 150, "pAI Signaller")
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/pai_signaler/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "mcomputer-pai-signaler", 400, 150, "pAI Signaller")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/pai_signaler/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
VUEUI_SET_CHECK(data["code"], host.sradio.code, ., data)
|
||||
VUEUI_SET_CHECK(data["frequency"], format_frequency(host.sradio.frequency), ., data)
|
||||
|
||||
|
||||
/datum/computer_file/program/pai_signaler/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
if(href_list["send"])
|
||||
host.sradio.send_signal("ACTIVATE")
|
||||
for(var/mob/O in hearers(1, host.loc))
|
||||
O.show_message(text("\icon[] *beep* *beep*", host), 3, "*beep* *beep*", 2)
|
||||
return 1
|
||||
|
||||
else if(href_list["freq"])
|
||||
var/new_frequency = (host.sradio.frequency + href_list["freq"])
|
||||
if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)
|
||||
new_frequency = sanitize_frequency(new_frequency)
|
||||
host.sradio.set_frequency(new_frequency)
|
||||
return 1
|
||||
|
||||
else if(href_list["code"])
|
||||
host.sradio.code += href_list["code"]
|
||||
host.sradio.code = round(host.sradio.code)
|
||||
host.sradio.code = min(100, host.sradio.code)
|
||||
host.sradio.code = max(1, host.sradio.code)
|
||||
return 1
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/computer_file/program/pai_translator
|
||||
filename = "translator"
|
||||
filedesc = "pAI Universal Translator"
|
||||
extended_desc = "This service enables the integrated universal translation systems."
|
||||
size = 12
|
||||
program_type = PROGRAM_SERVICE
|
||||
available_on_ntnet = 1
|
||||
usage_flags = PROGRAM_SILICON_PAI
|
||||
|
||||
/datum/computer_file/program/pai_translator/service_activate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
if(!host.translator_on)
|
||||
host.add_language(LANGUAGE_UNATHI)
|
||||
host.add_language(LANGUAGE_SIIK_MAAS)
|
||||
host.add_language(LANGUAGE_SKRELLIAN)
|
||||
host.add_language(LANGUAGE_ROOTSONG)
|
||||
host.translator_on = TRUE
|
||||
|
||||
/datum/computer_file/program/pai_translator/service_deactivate()
|
||||
. = ..()
|
||||
if(!istype(computer, /obj/item/modular_computer/silicon))
|
||||
return
|
||||
var/obj/item/modular_computer/silicon/true_computer = computer
|
||||
if(!istype(true_computer.computer_host, /mob/living/silicon/pai))
|
||||
return
|
||||
var/mob/living/silicon/pai/host = true_computer.computer_host
|
||||
|
||||
if(host.translator_on)
|
||||
host.remove_language(LANGUAGE_UNATHI)
|
||||
host.remove_language(LANGUAGE_SIIK_MAAS)
|
||||
host.remove_language(LANGUAGE_SKRELLIAN)
|
||||
host.remove_language(LANGUAGE_ROOTSONG)
|
||||
host.translator_on = FALSE
|
||||
@@ -7,7 +7,7 @@
|
||||
requires_ntnet = TRUE
|
||||
required_access_run = access_network
|
||||
required_access_download = access_heads
|
||||
usage_flags = PROGRAM_CONSOLE
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_SILICON_AI
|
||||
color = LIGHT_COLOR_GREEN
|
||||
|
||||
available_on_ntnet = TRUE
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
required_access_download = access_hos
|
||||
required_access_run = access_security
|
||||
nanomodule_path = /datum/nano_module/program/digitalwarrant
|
||||
usage_flags = PROGRAM_ALL_REGULAR | PROGRAM_STATIONBOUND
|
||||
|
||||
/datum/nano_module/program/digitalwarrant
|
||||
name = "Warrant Assistant"
|
||||
|
||||
@@ -9,231 +9,224 @@
|
||||
size = 4
|
||||
requires_ntnet = TRUE
|
||||
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
|
||||
available_on_ntnet = FALSE
|
||||
nanomodule_path = /datum/nano_module/program/computer_ntnetdownload
|
||||
available_on_ntnet = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
var/datum/computer_file/program/downloaded_file
|
||||
var/hacked_download = FALSE
|
||||
var/download_completion = 0 //GQ of downloaded data.
|
||||
var/download_netspeed = 0
|
||||
var/download_last_update = 0 // For tracking download rates and completion.
|
||||
var/downloaderror = ""
|
||||
var/downstream_variance = 0.1
|
||||
var/list/download_queue = list()
|
||||
var/list/download_files = list()
|
||||
var/queue_size = 0
|
||||
var/active_download = null
|
||||
var/last_update = 0
|
||||
var/speed = 0
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename, var/user)
|
||||
if(downloaded_file)
|
||||
return FALSE
|
||||
|
||||
var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename)
|
||||
/datum/computer_file/program/ntnetdownload/ui_interact(mob/user, var/datum/topic_state/state = default_state)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-system-downloader", 575, 700, "NTNet Download Program", state = state)
|
||||
ui.open()
|
||||
|
||||
if(!PRG || !istype(PRG))
|
||||
return FALSE
|
||||
/datum/computer_file/program/ntnetdownload/vueui_transfer(oldobj)
|
||||
SSvueui.transfer_uis(oldobj, src, "mcomputer-system-downloader", 575, 700, "NTNet Download Program")
|
||||
return TRUE
|
||||
|
||||
// Gaters data for ui
|
||||
/datum/computer_file/program/ntnetdownload/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list("queue" = download_queue)
|
||||
|
||||
if(!istype(computer))
|
||||
return
|
||||
|
||||
// Gather data for computer header
|
||||
var/headerdata = get_header_data(data["_PC"])
|
||||
if(headerdata)
|
||||
data["_PC"] = headerdata
|
||||
. = data
|
||||
|
||||
// Let's send all installed programs
|
||||
LAZYINITLIST(data["installed"])
|
||||
for(var/datum/computer_file/program/I in hard_drive.stored_files)
|
||||
LAZYINITLIST(data["installed"][I.filename])
|
||||
VUEUI_SET_CHECK(data["installed"][I.filename]["name"], I.filedesc, ., data)
|
||||
VUEUI_SET_CHECK(data["installed"][I.filename]["size"], I.size, ., data)
|
||||
|
||||
// Now lets send all avaivable programs with there status.
|
||||
// Statuses (rest): 0 - ALL OK, 1 - can't download due to access, 2 - unsuported hardware, 3 - sindies only
|
||||
LAZYINITLIST(data["avaivable"])
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_software)
|
||||
LAZYINITLIST(data["avaivable"][P.filename])
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["name"], P.filedesc, ., data)
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["desc"], P.extended_desc, ., data)
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["size"], P.size, ., data)
|
||||
if(computer_emagged)
|
||||
if(!P.is_supported_by_hardware(computer.hardware_flag))
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 2, ., data)
|
||||
else
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 0, ., data)
|
||||
else
|
||||
if(!P.available_on_ntnet)
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 3, ., data)
|
||||
else if(!P.can_download(user) && P.requires_access_to_download)
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 1, ., data)
|
||||
else if(!P.is_supported_by_hardware(computer.hardware_flag))
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 2, ., data)
|
||||
else
|
||||
VUEUI_SET_CHECK(data["avaivable"][P.filename]["rest"], 0, ., data)
|
||||
|
||||
VUEUI_SET_CHECK(data["disk_size"], hard_drive.max_capacity, ., data)
|
||||
VUEUI_SET_CHECK(data["disk_used"], hard_drive.used_capacity, ., data)
|
||||
VUEUI_SET_CHECK(data["queue_size"], queue_size, ., data)
|
||||
VUEUI_SET_CHECK(data["speed"], speed, ., data)
|
||||
|
||||
for(var/name in download_queue)
|
||||
VUEUI_SET_CHECK(data["queue"][name], download_queue[name], ., data)
|
||||
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
var/datum/vueui/ui = href_list["vueui"]
|
||||
if(!istype(ui))
|
||||
return
|
||||
|
||||
if(href_list["download"])
|
||||
var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(href_list["download"])
|
||||
|
||||
if(!istype(PRG))
|
||||
return 1
|
||||
return add_to_queue(PRG, ui.user)
|
||||
|
||||
if(href_list["cancel"])
|
||||
return cancel_from_queue(href_list["cancel"])
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/add_to_queue(var/datum/computer_file/program/PRG, var/mob/user)
|
||||
// Attempting to download antag only program, but without having emagged computer. No.
|
||||
if(PRG.available_on_syndinet && !computer_emagged)
|
||||
return FALSE
|
||||
|
||||
if(!hard_drive.can_store_file(queue_size + PRG.size))
|
||||
to_chat(user, SPAN_WARNING("You can't download this program as queued items exceed hard drive capacity."))
|
||||
return TRUE
|
||||
|
||||
if(!computer?.hard_drive?.try_store_file(PRG))
|
||||
return FALSE
|
||||
|
||||
if(computer.enrolled == TRUE && !computer_emagged)
|
||||
if(!computer_emagged && !PRG.can_download(user) && PRG.requires_access_to_download)
|
||||
return TRUE
|
||||
|
||||
if(!PRG.is_supported_by_hardware(computer.hardware_flag))
|
||||
return FALSE
|
||||
|
||||
ui_header = "downloader_running.gif"
|
||||
|
||||
if(PRG in ntnet_global.available_station_software)
|
||||
if(PRG.available_on_ntnet)
|
||||
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
|
||||
hacked_download = FALSE
|
||||
else if(PRG in ntnet_global.available_antag_software)
|
||||
else if (PRG.available_on_syndinet)
|
||||
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
|
||||
hacked_download = TRUE
|
||||
else
|
||||
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.")
|
||||
hacked_download = FALSE
|
||||
|
||||
downloaded_file = PRG.clone()
|
||||
if(user)
|
||||
spawn()
|
||||
ui_interact(user)
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/abort_file_download()
|
||||
if(!downloaded_file)
|
||||
download_files[PRG.filename] = PRG.clone()
|
||||
queue_size += PRG.size
|
||||
download_queue[PRG.filename] = 0
|
||||
for(var/i in SSvueui.get_open_uis(src))
|
||||
var/datum/vueui/ui = i
|
||||
ui.data["queue"][PRG.filename] = 0
|
||||
ui.push_change()
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/cancel_from_queue(var/name)
|
||||
if(!download_files[name])
|
||||
return
|
||||
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
download_last_update = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
var/datum/computer_file/program/PRG = download_files[name]
|
||||
var/hacked_download = PRG.available_on_syndinet && !PRG.available_on_ntnet
|
||||
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : PRG.filename].[PRG.filetype].")
|
||||
download_queue -= name
|
||||
download_files -= name
|
||||
queue_size -= PRG.size
|
||||
for(var/i in SSvueui.get_open_uis(src))
|
||||
var/datum/vueui/ui = i
|
||||
ui.data["queue"] -= name
|
||||
ui.push_change()
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
|
||||
if(!downloaded_file)
|
||||
/datum/computer_file/program/ntnetdownload/proc/finish_from_queue(var/name)
|
||||
if(!download_files[name])
|
||||
return
|
||||
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : downloaded_file.filename].[downloaded_file.filetype].")
|
||||
if(!computer?.hard_drive?.store_file(downloaded_file))
|
||||
// The download failed
|
||||
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
|
||||
else
|
||||
playsound(get_turf(computer), 'sound/machines/ping.ogg', 40, 0)
|
||||
computer.output_message("\icon[computer] <b>[capitalize_first_letters(computer)]</b> pings, \"Software download completed successfully!\"", 1)
|
||||
downloaded_file = null
|
||||
download_completion = 0
|
||||
download_last_update = 0
|
||||
ui_header = "downloader_finished.gif"
|
||||
|
||||
var/datum/computer_file/program/PRG = download_files[name]
|
||||
var/hacked_download = PRG.available_on_syndinet && !PRG.available_on_ntnet
|
||||
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : PRG.filename].[PRG.filetype].")
|
||||
if(!computer?.hard_drive?.store_file(PRG))
|
||||
download_queue[name] = -1
|
||||
for(var/i in SSvueui.get_open_uis(src))
|
||||
var/datum/vueui/ui = i
|
||||
ui.data["queue"] = -1
|
||||
ui.push_change()
|
||||
return
|
||||
|
||||
download_queue -= name
|
||||
download_files -= name
|
||||
queue_size -= PRG.size
|
||||
for(var/i in SSvueui.get_open_uis(src))
|
||||
var/datum/vueui/ui = i
|
||||
ui.data["queue"] -= name
|
||||
ui.push_change()
|
||||
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/process_tick()
|
||||
if(!downloaded_file)
|
||||
if(!queue_size)
|
||||
ui_header = "downloader_finished.gif"
|
||||
return
|
||||
if(download_completion >= downloaded_file.size)
|
||||
complete_file_download()
|
||||
return
|
||||
// Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity
|
||||
download_netspeed = 0
|
||||
// Speed defines are found in misc.dm
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
downstream_variance = 0.3
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
downstream_variance = 0.2
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
ui_header = "downloader_running.gif"
|
||||
|
||||
// We recovered connection or started a new download.
|
||||
// So we don't have any bytes yet. We'll get them next time!
|
||||
if (!download_last_update)
|
||||
download_last_update = world.time
|
||||
return
|
||||
|
||||
var/delta = ((rand() - 0.5) * 2) * downstream_variance * download_netspeed
|
||||
//Download speed varies +/- 10% each proc. Adds a more realistic feel
|
||||
|
||||
download_netspeed += delta
|
||||
download_netspeed = round(download_netspeed, 0.002)//3 decimal places
|
||||
|
||||
var/delta_seconds = (world.time - download_last_update) / 10
|
||||
|
||||
download_completion = min(download_completion + delta_seconds * download_netspeed, downloaded_file.size)
|
||||
|
||||
// No connection, so cancel the download.
|
||||
// This is done at the end because of logic reasons.
|
||||
// Trust me, it's fine. - Skull132
|
||||
if (!download_netspeed)
|
||||
download_last_update = 0
|
||||
else
|
||||
download_last_update = world.time
|
||||
|
||||
/datum/computer_file/program/ntnetdownload/Topic(href, href_list)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(href_list["PRG_downloadfile"])
|
||||
if(!downloaded_file)
|
||||
begin_file_download(href_list["PRG_downloadfile"], usr)
|
||||
return TRUE
|
||||
if(href_list["PRG_reseterror"])
|
||||
if(downloaderror)
|
||||
download_completion = 0
|
||||
download_netspeed = 0
|
||||
downloaded_file = null
|
||||
downloaderror = ""
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nano_module/program/computer_ntnetdownload
|
||||
name = "Network Downloader"
|
||||
var/obj/item/modular_computer/my_computer
|
||||
|
||||
/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(program)
|
||||
my_computer = program.computer
|
||||
|
||||
if(!istype(my_computer))
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
var/datum/computer_file/program/ntnetdownload/prog = program
|
||||
// For now limited to execution by the downloader program
|
||||
if(!prog || !istype(prog))
|
||||
return
|
||||
if(program)
|
||||
data = list("_PC" = program.get_header_data())
|
||||
|
||||
// This IF cuts on data transferred to client, so i guess it's worth it.
|
||||
if(prog.downloaderror) // Download errored. Wait until user resets the program.
|
||||
data["error"] = prog.downloaderror
|
||||
else if(prog.downloaded_file) // Download running. Wait please..
|
||||
if (ui)
|
||||
ui.set_auto_update(TRUE)
|
||||
data["downloadname"] = prog.downloaded_file.filename
|
||||
data["downloaddesc"] = prog.downloaded_file.filedesc
|
||||
data["downloadsize"] = prog.downloaded_file.size
|
||||
data["downloadspeed"] = prog.download_netspeed //Even if it does update every 2 seconds, this is bad coding on everyone's count. :ree:
|
||||
data["downloadcompletion"] = round(prog.download_completion, 0.01)
|
||||
else // No download running, pick file.
|
||||
if (ui)
|
||||
ui.set_auto_update(FALSE)//No need for auto updating on the software menu
|
||||
data["disk_size"] = my_computer.hard_drive.max_capacity
|
||||
data["disk_used"] = my_computer.hard_drive.used_capacity
|
||||
if(my_computer.enrolled == 2) //To lock installation of software on work computers until the IT Department is properly implemented - Then check for access on enrolled computers
|
||||
data += get_programlist(user)
|
||||
else
|
||||
data["downloadable_programs"] = list()
|
||||
data["locked"] = TRUE
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state)
|
||||
ui.auto_update_layout = TRUE
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(TRUE)
|
||||
|
||||
|
||||
/datum/nano_module/program/computer_ntnetdownload/proc/get_programlist(var/mob/user)
|
||||
var/list/all_entries[0]
|
||||
var/datum/computer_file/program/ntnetdownload/prog = program
|
||||
var/list/data = list()
|
||||
data["hackedavailable"] = FALSE
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
|
||||
var/installed = FALSE
|
||||
for(var/datum/computer_file/program/Q in program.hard_drive.stored_files)
|
||||
if(istype(P, Q.type))
|
||||
installed = TRUE
|
||||
if(download_queue[active_download] == null)
|
||||
for(var/name in download_queue)
|
||||
if(download_queue[name] >= 0)
|
||||
active_download = name
|
||||
break
|
||||
if(download_queue[active_download] == null)
|
||||
return
|
||||
|
||||
if(!installed)
|
||||
// Only those programs our user can run will show in the list
|
||||
if(!P.can_download(user) && P.requires_access_to_download)
|
||||
continue
|
||||
var/datum/computer_file/active_download_file = download_files[active_download]
|
||||
if(download_queue[active_download] >= 0)
|
||||
if (!last_update)
|
||||
last_update = world.time
|
||||
return
|
||||
speed = 0
|
||||
var/variance = 0.1
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
speed = NTNETSPEED_LOWSIGNAL
|
||||
variance = 0.3
|
||||
if(2)
|
||||
speed = NTNETSPEED_HIGHSIGNAL
|
||||
variance = 0.2
|
||||
if(3)
|
||||
speed = NTNETSPEED_ETHERNET
|
||||
|
||||
if(!P.is_supported_by_hardware(program.computer.hardware_flag))
|
||||
continue
|
||||
var/delta = ((rand() - 0.5) * 2) * variance * speed
|
||||
//Download speed varies +/- 10% each proc. Adds a more realistic feels
|
||||
speed += delta
|
||||
speed = round(speed, 0.002)//3 decimal places
|
||||
|
||||
all_entries.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"size" = P.size
|
||||
)))
|
||||
var/delta_seconds = (world.time - last_update) / 10
|
||||
|
||||
if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
|
||||
var/list/hacked_programs[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_antag_software)
|
||||
var/installed = FALSE
|
||||
for(var/datum/computer_file/program/Q in program.hard_drive.stored_files)
|
||||
if(istype(P, Q.type))
|
||||
installed = TRUE
|
||||
break
|
||||
download_queue[active_download] = min(download_queue[active_download] + delta_seconds * speed, active_download_file.size)
|
||||
|
||||
if(!installed)
|
||||
data["hackedavailable"] = TRUE
|
||||
hacked_programs.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
"filedesc" = P.filedesc,
|
||||
"fileinfo" = P.extended_desc,
|
||||
"size" = P.size
|
||||
)))
|
||||
data["hacked_programs"] = hacked_programs
|
||||
// No connection, so cancel the download.
|
||||
// This is done at the end because of logic reasons.
|
||||
// Trust me, it's fine. - Skull132
|
||||
if (!speed)
|
||||
last_update = 0
|
||||
else
|
||||
last_update = world.time
|
||||
|
||||
|
||||
data["downloadable_programs"] = all_entries
|
||||
return data
|
||||
if(download_queue[active_download] >= active_download_file.size)
|
||||
finish_from_queue(active_download)
|
||||
active_download = null
|
||||
playsound(get_turf(computer), 'sound/machines/ping.ogg', 40, 0)
|
||||
computer.output_message("\icon[computer] <b>[capitalize_first_letters(computer)]</b> pings, \"Software download completed successfully!\"", 1)
|
||||
|
||||
SSvueui.check_uis_for_change(src)
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
/datum/nano_module/New(var/datum/host, var/topic_manager)
|
||||
..()
|
||||
src.host = host.ui_host()
|
||||
src.host = host
|
||||
src.topic_manager = topic_manager
|
||||
|
||||
/datum/nano_module/ui_host()
|
||||
return host ? host : src
|
||||
return host ? host.ui_host() : src
|
||||
|
||||
/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = default_state)
|
||||
return CanUseTopic(usr, state) == STATUS_INTERACTIVE
|
||||
|
||||
@@ -36,4 +36,20 @@
|
||||
/datum/proc/vueui_transfer(var/srcObject)
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Callback to object when UI is being transfered away from it
|
||||
*
|
||||
* @param ui - that is being transfered
|
||||
*/
|
||||
/datum/proc/vueui_on_transfer(var/datum/vueui/ui)
|
||||
return
|
||||
|
||||
/**
|
||||
* Callback to object when UI is closed
|
||||
*
|
||||
* @param ui - that is being closed
|
||||
*/
|
||||
/datum/proc/vueui_on_close(var/datum/vueui/ui)
|
||||
return
|
||||
|
||||
/mob/var/list/open_vueui_uis
|
||||
|
||||
@@ -46,11 +46,11 @@ main ui datum.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/datum/vueui/New(var/nuser, var/nobject, var/nactiveui = 0, var/nwidth = 0, var/nheight = 0, var/ntitle, var/list/ndata, var/datum/topic_state/nstate = default_state)
|
||||
/datum/vueui/New(var/nuser, var/nobject, var/nactiveui = 0, var/nwidth = 0, var/nheight = 0, var/ntitle, var/list/ndata, var/datum/topic_state/state = default_state)
|
||||
user = nuser
|
||||
object = nobject
|
||||
data = ndata
|
||||
state = nstate
|
||||
src.state = state
|
||||
LAZYINITLIST(assets)
|
||||
|
||||
if (nactiveui)
|
||||
@@ -100,6 +100,7 @@ main ui datum.
|
||||
* @return nothing
|
||||
*/
|
||||
/datum/vueui/proc/close()
|
||||
object.vueui_on_close(src)
|
||||
SSvueui.ui_closed(src)
|
||||
user << browse(null, "window=[windowid]")
|
||||
status = null
|
||||
|
||||
Reference in New Issue
Block a user