mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-20 04:17:33 +01:00
@@ -0,0 +1,31 @@
|
||||
/obj/machinery/modular_computer/initial_data()
|
||||
return cpu ? cpu.get_header_data() : ..()
|
||||
|
||||
/obj/item/modular_computer/initial_data()
|
||||
return get_header_data()
|
||||
|
||||
/obj/machinery/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/obj/item/modular_computer/update_layout()
|
||||
return TRUE
|
||||
|
||||
/datum/nano_module/program
|
||||
available_to_ai = FALSE
|
||||
var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null.
|
||||
|
||||
/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
/datum/topic_manager/program
|
||||
var/datum/program
|
||||
|
||||
/datum/topic_manager/program/New(var/datum/program)
|
||||
..()
|
||||
src.program = program
|
||||
|
||||
// Calls forwarded to PROGRAM itself should begin with "PRG_"
|
||||
// Calls forwarded to COMPUTER running the program should begin with "PC_"
|
||||
/datum/topic_manager/program/Topic(href, href_list)
|
||||
return program && program.Topic(href, href_list)
|
||||
@@ -0,0 +1,117 @@
|
||||
/datum/computer_file/program/aidiag
|
||||
filename = "aidiag"
|
||||
filedesc = "AI Maintenance Utility"
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program is capable of reconstructing damaged AI systems. It can also be used to upload basic laws to the AI. Requires direct AI connection via intellicard slot."
|
||||
size = 12
|
||||
requires_ntnet = 0
|
||||
required_access = access_heads
|
||||
requires_access_to_run = 0
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/program/computer_aidiag/
|
||||
var/restoring = 0
|
||||
|
||||
/datum/computer_file/program/aidiag/proc/get_ai()
|
||||
if(computer && computer.ai_slot && computer.ai_slot.check_functionality() && computer.ai_slot.enabled && computer.ai_slot.stored_card && computer.ai_slot.stored_card.carded_ai)
|
||||
return computer.ai_slot.stored_card.carded_ai
|
||||
return null
|
||||
|
||||
/datum/computer_file/program/aidiag/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/living/silicon/ai/A = get_ai()
|
||||
if(!A)
|
||||
return 0
|
||||
if(href_list["PRG_beginReconstruction"])
|
||||
if((A.hardware_integrity() < 100) || (A.backup_capacitor() < 100))
|
||||
restoring = 1
|
||||
return 1
|
||||
|
||||
// Following actions can only be used by non-silicon users, as they involve manipulation of laws.
|
||||
if(issilicon(usr))
|
||||
return 0
|
||||
if(href_list["PRG_purgeAiLaws"])
|
||||
A.laws.clear_zeroth_laws()
|
||||
A.laws.clear_ion_laws()
|
||||
A.laws.clear_inherent_laws()
|
||||
A.laws.clear_supplied_laws()
|
||||
A << "<span class='danger'>All laws purged.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_resetLaws"])
|
||||
A.laws.clear_ion_laws()
|
||||
A.laws.clear_supplied_laws()
|
||||
A << "<span class='danger'>Non-core laws reset.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_uploadNTDefault"])
|
||||
A.laws = new/datum/ai_laws/nanotrasen
|
||||
A << "<span class='danger'>All laws purged. NT Default lawset uploaded.</span>"
|
||||
return 1
|
||||
if(href_list["PRG_addCustomSuppliedLaw"])
|
||||
var/law_to_add = sanitize(input("Please enter a new law for the AI.", "Custom Law Entry"))
|
||||
var/sector = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)") as num
|
||||
sector = between(MIN_SUPPLIED_LAW_NUMBER, sector, MAX_SUPPLIED_LAW_NUMBER)
|
||||
A.add_supplied_law(sector, law_to_add)
|
||||
A << "<span class='danger'>Custom law uploaded to sector [sector]: [law_to_add].</span>"
|
||||
return 1
|
||||
|
||||
|
||||
/datum/computer_file/program/aidiag/process_tick()
|
||||
var/mob/living/silicon/ai/A = get_ai()
|
||||
if(!A || !restoring)
|
||||
restoring = 0 // If the AI was removed, stop the restoration sequence.
|
||||
return
|
||||
A.adjustFireLoss(-4)
|
||||
A.adjustBruteLoss(-4)
|
||||
A.adjustOxyLoss(-4)
|
||||
A.updatehealth()
|
||||
// If the AI is dead, revive it.
|
||||
if (A.health >= -100 && A.stat == DEAD)
|
||||
A.stat = CONSCIOUS
|
||||
A.lying = 0
|
||||
A.switch_from_dead_to_living_mob_list()
|
||||
A.add_ai_verbs()
|
||||
A.updateicon()
|
||||
var/obj/item/weapon/aicard/AC = A.loc
|
||||
if(AC)
|
||||
AC.update_icon()
|
||||
// Finished restoring
|
||||
if((A.hardware_integrity() == 100) && (A.backup_capacitor() == 100))
|
||||
restoring = 0
|
||||
|
||||
/datum/nano_module/program/computer_aidiag
|
||||
name = "AI Maintenance Utility"
|
||||
|
||||
/datum/nano_module/program/computer_aidiag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/mob/living/silicon/ai/A
|
||||
// A shortcut for getting the AI stored inside the computer. The program already does necessary checks.
|
||||
if(program && istype(program, /datum/computer_file/program/aidiag))
|
||||
var/datum/computer_file/program/aidiag/AD = program
|
||||
A = AD.get_ai()
|
||||
|
||||
if(!A)
|
||||
data["error"] = "No AI located"
|
||||
else
|
||||
data["ai_name"] = A.name
|
||||
data["ai_integrity"] = A.hardware_integrity()
|
||||
data["ai_capacitor"] = A.backup_capacitor()
|
||||
data["ai_isdamaged"] = (A.hardware_integrity() < 100) || (A.backup_capacitor() < 100)
|
||||
data["ai_isdead"] = (A.stat == DEAD)
|
||||
|
||||
var/list/all_laws[0]
|
||||
for(var/datum/ai_law/L in A.laws.all_laws())
|
||||
all_laws.Add(list(list(
|
||||
"index" = L.index,
|
||||
"text" = L.law
|
||||
)))
|
||||
|
||||
data["ai_laws"] = all_laws
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "aidiag.tmpl", "AI Maintenance Utility", 600, 400, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
@@ -7,7 +7,7 @@
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_dos/
|
||||
nanomodule_path = /datum/nano_module/program/computer_dos/
|
||||
var/obj/machinery/ntnet_relay/target = null
|
||||
var/dos_speed = 0
|
||||
var/error = ""
|
||||
@@ -17,29 +17,30 @@
|
||||
dos_speed = 0
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
dos_speed = NTNETSPEED_LOWSIGNAL * 10
|
||||
dos_speed = NTNETSPEED_LOWSIGNAL * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(2)
|
||||
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
|
||||
dos_speed = NTNETSPEED_HIGHSIGNAL * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(3)
|
||||
dos_speed = NTNETSPEED_ETHERNET * 10
|
||||
dos_speed = NTNETSPEED_ETHERNET * NTNETSPEED_DOS_AMPLIFICATION
|
||||
if(target && executed)
|
||||
target.dos_overload += dos_speed
|
||||
if(target.is_operational())
|
||||
if(!target.operable())
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
error = "Connection to destination relay lost."
|
||||
|
||||
/datum/computer_file/program/ntnet_dos/kill_program(var/forced)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/computer_dos
|
||||
/datum/nano_module/program/computer_dos
|
||||
name = "DoS Traffic Generator"
|
||||
|
||||
/datum/nano_module/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
var/datum/computer_file/program/ntnet_dos/PRG = program
|
||||
@@ -89,8 +90,9 @@
|
||||
target = R
|
||||
return 1
|
||||
if(href_list["PRG_reset"])
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
if(target)
|
||||
target.dos_sources.Remove(src)
|
||||
target = null
|
||||
executed = 0
|
||||
error = ""
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/computer_file/program/camera_monitor/hacked
|
||||
filename = "camcrypt"
|
||||
filedesc = "Camera Decryption Tool"
|
||||
nanomodule_path = /datum/nano_module/camera_monitor/hacked
|
||||
program_icon_state = "hostile"
|
||||
extended_desc = "This very advanced piece of software uses adaptive programming and large database of cipherkeys to bypass most encryptions used on camera networks. Be warned that system administrator may notice this."
|
||||
size = 73 // Very large, a price for bypassing ID checks completely.
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
|
||||
/datum/computer_file/program/camera_monitor/hacked/process_tick()
|
||||
..()
|
||||
if(program_state != PROGRAM_STATE_ACTIVE) // Background programs won't trigger alarms.
|
||||
return
|
||||
|
||||
var/datum/nano_module/camera_monitor/hacked/HNM = NM
|
||||
|
||||
// The program is active and connected to one of the station's networks. Has a very small chance to trigger IDS alarm every tick.
|
||||
if(HNM.current_network && (HNM.current_network in station_networks) && prob(0.1))
|
||||
if(ntnet_global.intrusion_detection_enabled)
|
||||
ntnet_global.add_log("IDS WARNING - Unauthorised access detected to camera network [HNM.current_network] by device with NID [computer.network_card.get_network_tag()]")
|
||||
ntnet_global.intrusion_detection_alarm = 1
|
||||
|
||||
|
||||
/datum/nano_module/camera_monitor/hacked
|
||||
name = "Hacked Camera Monitoring Program"
|
||||
available_to_ai = FALSE
|
||||
|
||||
/datum/nano_module/camera_monitor/hacked/can_access_network(var/mob/user, var/network_access)
|
||||
return 1
|
||||
|
||||
// The hacked variant has access to all commonly used networks.
|
||||
/datum/nano_module/camera_monitor/hacked/modify_networks_list(var/list/networks)
|
||||
networks.Add(list(list("tag" = NETWORK_MERCENARY, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
|
||||
return networks
|
||||
@@ -7,7 +7,7 @@
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
available_on_syndinet = 1
|
||||
nanomodule_path = /datum/nano_module/revelation/
|
||||
nanomodule_path = /datum/nano_module/program/revelation/
|
||||
var/armed = 0
|
||||
|
||||
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
|
||||
@@ -56,10 +56,10 @@
|
||||
temp.armed = armed
|
||||
return temp
|
||||
|
||||
/datum/nano_module/revelation
|
||||
/datum/nano_module/program/revelation
|
||||
name = "Revelation Virus"
|
||||
|
||||
/datum/nano_module/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = list()
|
||||
var/datum/computer_file/program/revelation/PRG = program
|
||||
if(!istype(PRG))
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Returns which access is relevant to passed network. Used by the program.
|
||||
/proc/get_camera_access(var/network)
|
||||
if(!network)
|
||||
return 0
|
||||
|
||||
switch(network)
|
||||
if(NETWORK_THUNDER)
|
||||
return 0
|
||||
if(NETWORK_ENGINE,NETWORK_ENGINEERING,NETWORK_ENGINEERING_OUTPOST,NETWORK_ALARM_ATMOS,NETWORK_ALARM_FIRE,NETWORK_ALARM_POWER)
|
||||
return access_engine
|
||||
if(NETWORK_MEDICAL)
|
||||
return access_medical
|
||||
if(NETWORK_RESEARCH,NETWORK_RESEARCH_OUTPOST)
|
||||
return access_research
|
||||
if(NETWORK_MINE,NETWORK_SUPPLY,NETWORK_CIVILIAN_WEST,NETWORK_EXPEDITION,NETWORK_CALYPSO,NETWORK_POD)
|
||||
return access_mailsorting // Cargo office - all cargo staff should have access here.
|
||||
if(NETWORK_COMMAND,NETWORK_TELECOM)
|
||||
return access_heads
|
||||
if(NETWORK_CRESCENT,NETWORK_ERT)
|
||||
return access_cent_specops
|
||||
|
||||
return access_security // Default for all other networks
|
||||
|
||||
/datum/computer_file/program/camera_monitor
|
||||
filename = "cammon"
|
||||
filedesc = "Camera Monitoring"
|
||||
nanomodule_path = /datum/nano_module/camera_monitor
|
||||
program_icon_state = "generic"
|
||||
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements."
|
||||
size = 12
|
||||
available_on_ntnet = 1
|
||||
requires_ntnet = 1
|
||||
|
||||
/datum/nano_module/camera_monitor
|
||||
name = "Camera Monitoring program"
|
||||
var/obj/machinery/camera/current_camera = null
|
||||
var/current_network = null
|
||||
|
||||
/datum/nano_module/camera_monitor/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["current_camera"] = current_camera ? current_camera.nano_structure() : null
|
||||
data["current_network"] = current_network
|
||||
|
||||
var/list/all_networks[0]
|
||||
for(var/network in station_networks)
|
||||
all_networks.Add(list(list(
|
||||
"tag" = network,
|
||||
"has_access" = can_access_network(user, get_camera_access(network))
|
||||
)))
|
||||
|
||||
all_networks = modify_networks_list(all_networks)
|
||||
|
||||
data["networks"] = all_networks
|
||||
|
||||
if(current_network)
|
||||
data["cameras"] = camera_repository.cameras_in_network(current_network)
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "sec_camera.tmpl", "Camera Monitoring", 900, 800, state = state)
|
||||
// ui.auto_update_layout = 1 // Disabled as with suit sensors monitor - breaks the UI map. Re-enable once it's fixed somehow.
|
||||
|
||||
ui.add_template("mapContent", "sec_camera_map_content.tmpl")
|
||||
ui.add_template("mapHeader", "sec_camera_map_header.tmpl")
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
// Intended to be overriden by subtypes to manually add non-station networks to the list.
|
||||
/datum/nano_module/camera_monitor/proc/modify_networks_list(var/list/networks)
|
||||
return networks
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/can_access_network(var/mob/user, var/network_access)
|
||||
// No access passed, or 0 which is considered no access requirement. Allow it.
|
||||
if(!network_access)
|
||||
return 1
|
||||
|
||||
return check_access(user, access_security) || check_access(user, network_access)
|
||||
|
||||
/datum/nano_module/camera_monitor/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["switch_camera"])
|
||||
var/obj/machinery/camera/C = locate(href_list["switch_camera"]) in cameranet.cameras
|
||||
if(!C)
|
||||
return
|
||||
if(!(current_network in C.network))
|
||||
return
|
||||
|
||||
switch_to_camera(usr, C)
|
||||
return 1
|
||||
|
||||
else if(href_list["switch_network"])
|
||||
// Either security access, or access to the specific camera network's department is required in order to access the network.
|
||||
if(can_access_network(usr, get_camera_access(href_list["switch_network"])))
|
||||
current_network = href_list["switch_network"]
|
||||
else
|
||||
to_chat(usr, "\The [nano_host()] shows an \"Network Access Denied\" error message.")
|
||||
return 1
|
||||
|
||||
else if(href_list["reset"])
|
||||
reset_current()
|
||||
usr.reset_view(current_camera)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
|
||||
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
|
||||
if(isAI(user))
|
||||
var/mob/living/silicon/ai/A = user
|
||||
// Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
|
||||
if(!A.is_in_chassis())
|
||||
return 0
|
||||
|
||||
A.eyeobj.setLoc(get_turf(C))
|
||||
A.client.eye = A.eyeobj
|
||||
return 1
|
||||
|
||||
set_current(C)
|
||||
user.machine = nano_host()
|
||||
user.reset_view(current_camera)
|
||||
check_eye(user)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/set_current(var/obj/machinery/camera/C)
|
||||
if(current_camera == C)
|
||||
return
|
||||
|
||||
if(current_camera)
|
||||
reset_current()
|
||||
|
||||
current_camera = C
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_initiated()
|
||||
|
||||
/datum/nano_module/camera_monitor/proc/reset_current()
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_cancelled()
|
||||
current_camera = null
|
||||
|
||||
/datum/nano_module/camera_monitor/check_eye(var/mob/user as mob)
|
||||
if(!current_camera)
|
||||
return 0
|
||||
var/viewflag = current_camera.check_eye(user)
|
||||
if ( viewflag < 0 ) //camera doesn't work
|
||||
reset_current()
|
||||
return viewflag
|
||||
|
||||
|
||||
// ERT Variant of the program
|
||||
/datum/computer_file/program/camera_monitor/ert
|
||||
filename = "ntcammon"
|
||||
filedesc = "Advanced Camera Monitoring"
|
||||
extended_desc = "This program allows remote access to station's camera system. Some camera networks may have additional access requirements. This version has an integrated database with additional encrypted keys."
|
||||
size = 14
|
||||
nanomodule_path = /datum/nano_module/camera_monitor/ert
|
||||
available_on_ntnet = 0
|
||||
|
||||
/datum/nano_module/camera_monitor/ert
|
||||
name = "Advanced Camera Monitoring Program"
|
||||
available_to_ai = FALSE
|
||||
|
||||
// The ERT variant has access to ERT and crescent cams, but still checks for accesses. ERT members should be able to use it.
|
||||
/datum/nano_module/camera_monitor/ert/modify_networks_list(var/list/networks)
|
||||
..()
|
||||
networks.Add(list(list("tag" = NETWORK_ERT, "has_access" = 1)))
|
||||
networks.Add(list(list("tag" = NETWORK_CRESCENT, "has_access" = 1)))
|
||||
return networks
|
||||
@@ -1,23 +1,21 @@
|
||||
/datum/computer_file/program/card_mod
|
||||
filename = "cardmod"
|
||||
filedesc = "ID card modification program"
|
||||
nanomodule_path = /datum/nano_module/card_mod
|
||||
nanomodule_path = /datum/nano_module/program/card_mod
|
||||
program_icon_state = "id"
|
||||
extended_desc = "Program for programming employee ID cards to access parts of the station."
|
||||
required_access = access_change_ids
|
||||
requires_ntnet = 0
|
||||
size = 8
|
||||
|
||||
/datum/nano_module/card_mod
|
||||
/datum/nano_module/program/card_mod
|
||||
name = "ID card modification program"
|
||||
var/mod_mode = 1
|
||||
var/is_centcom = 0
|
||||
var/show_assignments = 0
|
||||
|
||||
/datum/nano_module/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["src"] = "\ref[src]"
|
||||
data["station_name"] = station_name()
|
||||
@@ -89,7 +87,7 @@
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/card_mod/proc/format_jobs(list/jobs)
|
||||
/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs)
|
||||
var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
|
||||
var/list/formatted = list()
|
||||
for(var/job in jobs)
|
||||
@@ -100,8 +98,7 @@
|
||||
|
||||
return formatted
|
||||
|
||||
/datum/nano_module/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
|
||||
/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0)
|
||||
return null
|
||||
|
||||
|
||||
@@ -112,7 +109,7 @@
|
||||
var/mob/user = usr
|
||||
var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
|
||||
var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
|
||||
var/datum/nano_module/card_mod/module = NM
|
||||
var/datum/nano_module/program/card_mod/module = NM
|
||||
switch(href_list["action"])
|
||||
if("switchm")
|
||||
if(href_list["target"] == "mod")
|
||||
@@ -147,7 +144,7 @@
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>[computer] prints out paper.</span>")
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
else
|
||||
var/contents = {"<h4>Crew Manifest</h4>
|
||||
<br>
|
||||
@@ -157,7 +154,7 @@
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
return
|
||||
else
|
||||
computer.visible_message("<span class='notice'>[computer] prints out paper.</span>")
|
||||
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
|
||||
if("eject")
|
||||
if(computer && computer.card_slot)
|
||||
if(id_card)
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
#define STATE_DEFAULT 1
|
||||
#define STATE_MESSAGELIST 2
|
||||
#define STATE_VIEWMESSAGE 3
|
||||
#define STATE_STATUSDISPLAY 4
|
||||
#define STATE_ALERT_LEVEL 5
|
||||
/datum/computer_file/program/comm
|
||||
filename = "comm"
|
||||
filedesc = "Command and communications program."
|
||||
program_icon_state = "comm"
|
||||
nanomodule_path = /datum/nano_module/program/comm
|
||||
extended_desc = "Used to command and control the station. Can relay long-range communications."
|
||||
required_access = access_heads
|
||||
requires_ntnet = 1
|
||||
size = 12
|
||||
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
|
||||
network_destination = "station long-range communication array"
|
||||
var/datum/comm_message_listener/message_core = new
|
||||
|
||||
/datum/computer_file/program/comm/clone()
|
||||
var/datum/computer_file/program/comm/temp = ..()
|
||||
temp.message_core.messages = null
|
||||
temp.message_core.messages = message_core.messages.Copy()
|
||||
return temp
|
||||
|
||||
/datum/nano_module/program/comm
|
||||
name = "Command and communications program"
|
||||
available_to_ai = TRUE
|
||||
var/current_status = STATE_DEFAULT
|
||||
var/msg_line1 = ""
|
||||
var/msg_line2 = ""
|
||||
var/centcomm_message_cooldown = 0
|
||||
var/announcment_cooldown = 0
|
||||
var/datum/announcement/priority/crew_announcement = new
|
||||
var/current_viewing_message_id = 0
|
||||
var/current_viewing_message = null
|
||||
|
||||
/datum/nano_module/program/comm/New()
|
||||
..()
|
||||
crew_announcement.newscast = 1
|
||||
|
||||
/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
if(program)
|
||||
data["emagged"] = program.computer_emagged
|
||||
data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer
|
||||
data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL)
|
||||
if(program.computer)
|
||||
data["have_printer"] = !!program.computer.nano_printer
|
||||
else
|
||||
data["have_printer"] = 0
|
||||
else
|
||||
data["emagged"] = 0
|
||||
data["net_comms"] = 1
|
||||
data["net_syscont"] = 1
|
||||
data["have_printer"] = 0
|
||||
|
||||
data["message_line1"] = msg_line1
|
||||
data["message_line2"] = msg_line2
|
||||
data["state"] = current_status
|
||||
data["isAI"] = issilicon(usr)
|
||||
data["authenticated"] = is_autenthicated(user)
|
||||
data["boss_short"] = boss_short
|
||||
data["current_security_level"] = security_level
|
||||
data["current_security_level_title"] = num2seclevel(security_level)
|
||||
|
||||
data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA
|
||||
data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE
|
||||
data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN
|
||||
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
data["messages"] = l.messages
|
||||
data["message_deletion_allowed"] = l != global_message_listener
|
||||
data["message_current_id"] = current_viewing_message_id
|
||||
if(current_viewing_message)
|
||||
data["message_current"] = current_viewing_message
|
||||
|
||||
if(emergency_shuttle.location())
|
||||
data["have_shuttle"] = 1
|
||||
if(emergency_shuttle.online())
|
||||
data["have_shuttle_called"] = 1
|
||||
else
|
||||
data["have_shuttle_called"] = 0
|
||||
else
|
||||
data["have_shuttle"] = 0
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "communication.tmpl", name, 550, 420, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/datum/nano_module/program/comm/proc/is_autenthicated(var/mob/user)
|
||||
if(program)
|
||||
return program.can_run(user)
|
||||
return 1
|
||||
|
||||
/datum/nano_module/program/comm/proc/obtain_message_listener()
|
||||
if(program)
|
||||
var/datum/computer_file/program/comm/P = program
|
||||
return P.message_core
|
||||
return global_message_listener
|
||||
|
||||
/datum/nano_module/program/comm/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
var/mob/user = usr
|
||||
var/ntn_comm = !!program.get_signal(NTNET_COMMUNICATION)
|
||||
var/ntn_cont = !!program.get_signal(NTNET_SYSTEMCONTROL)
|
||||
var/datum/comm_message_listener/l = obtain_message_listener()
|
||||
switch(href_list["action"])
|
||||
if("sw_menu")
|
||||
current_status = text2num(href_list["target"])
|
||||
if("announce")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
|
||||
if(user)
|
||||
var/obj/item/weapon/card/id/id_card = user.GetIdCard()
|
||||
crew_announcement.announcer = GetNameAndAssignmentFromId(id_card)
|
||||
else
|
||||
crew_announcement.announcer = "Unknown"
|
||||
if(announcment_cooldown)
|
||||
usr << "Please allow at least one minute to pass between announcements"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|text
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
crew_announcement.Announce(input)
|
||||
announcment_cooldown = 1
|
||||
spawn(600)//One minute cooldown
|
||||
announcment_cooldown = 0
|
||||
if("message")
|
||||
if(href_list["target"] == "emagged")
|
||||
if(program)
|
||||
if(is_autenthicated(user) && program.computer_emagged && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
Syndicate_announce(input, usr)
|
||||
usr << "<span class='notice'>Message transmitted.</span>"
|
||||
log_say("[key_name(usr)] has made an illegal announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300)//30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
else if(href_list["target"] == "regular")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_comm)
|
||||
if(centcomm_message_cooldown)
|
||||
usr << "<span class='warning'>Arrays recycling. Please stand by.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs.
|
||||
usr <<"<span class='warning'>No Emergency Bluespace Relay detected. Unable to transmit message.</span>"
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
var/input = sanitize(input("Please choose a message to transmit to [boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
|
||||
if(!input || !can_still_topic())
|
||||
nanomanager.update_uis(src)
|
||||
return
|
||||
Centcomm_announce(input, usr)
|
||||
usr << "<span class='notice'>Message transmitted.</span>"
|
||||
log_say("[key_name(usr)] has made an IA [boss_short] announcement: [input]")
|
||||
centcomm_message_cooldown = 1
|
||||
spawn(300) //30 second cooldown
|
||||
centcomm_message_cooldown = 0
|
||||
if("shuttle")
|
||||
if(is_autenthicated(user) && ntn_cont)
|
||||
if(href_list["target"] == "call")
|
||||
var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
call_shuttle_proc(usr)
|
||||
if(href_list["target"] == "cancel" && !issilicon(usr))
|
||||
var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
cancel_call_proc(usr)
|
||||
if("setstatus")
|
||||
if(is_autenthicated(user) && ntn_cont)
|
||||
switch(href_list["target"])
|
||||
if("line1")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line1 = linput
|
||||
if("line2")
|
||||
var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40)
|
||||
if(can_still_topic())
|
||||
msg_line2 = linput
|
||||
if("message")
|
||||
post_status("message", msg_line1, msg_line2)
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
else
|
||||
post_status(href_list["target"])
|
||||
|
||||
if("setalert")
|
||||
if(is_autenthicated(user) && !issilicon(usr) && ntn_cont && ntn_comm)
|
||||
var/current_level = text2num(href_list["target"])
|
||||
var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes")
|
||||
if(confirm == "Yes" && can_still_topic())
|
||||
var/old_level = security_level
|
||||
if(!current_level) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN
|
||||
if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this
|
||||
set_security_level(current_level)
|
||||
if(security_level != old_level)
|
||||
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
|
||||
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
|
||||
switch(security_level)
|
||||
if(SEC_LEVEL_GREEN)
|
||||
feedback_inc("alert_comms_green",1)
|
||||
if(SEC_LEVEL_BLUE)
|
||||
feedback_inc("alert_comms_blue",1)
|
||||
else
|
||||
usr << "You press button, but red light flashes and nothing happens." //This should never happen
|
||||
current_status = STATE_DEFAULT
|
||||
if("viewmessage")
|
||||
if(is_autenthicated(user) && ntn_comm)
|
||||
current_viewing_message_id = text2num(href_list["target"])
|
||||
for(var/list/m in l.messages)
|
||||
if(m["id"] == current_viewing_message_id)
|
||||
current_viewing_message = m
|
||||
current_status = STATE_VIEWMESSAGE
|
||||
if("delmessage")
|
||||
if(is_autenthicated(user) && ntn_comm && l != global_message_listener)
|
||||
l.Remove(current_viewing_message)
|
||||
current_status = STATE_MESSAGELIST
|
||||
if("printmessage")
|
||||
if(is_autenthicated(user) && ntn_comm)
|
||||
if(program && program.computer && program.computer.nano_printer)
|
||||
if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"]))
|
||||
usr << "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>"
|
||||
else
|
||||
program.computer.visible_message("<span class='notice'>\The [program.computer] prints out paper.</span>")
|
||||
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = 1
|
||||
status_signal.data["command"] = command
|
||||
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]")
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
#undef STATE_DEFAULT
|
||||
#undef STATE_MESSAGELIST
|
||||
#undef STATE_VIEWMESSAGE
|
||||
#undef STATE_STATUSDISPLAY
|
||||
#undef STATE_ALERT_LEVEL
|
||||
|
||||
/*
|
||||
General message handling stuff
|
||||
*/
|
||||
var/list/comm_message_listeners = list() //We first have to initialize list then we can use it.
|
||||
var/datum/comm_message_listener/global_message_listener = new //May be used by admins
|
||||
var/last_message_id = 0
|
||||
|
||||
/proc/get_comm_message_id()
|
||||
last_message_id = last_message_id + 1
|
||||
return last_message_id
|
||||
|
||||
/proc/post_comm_message(var/message_title, var/message_text)
|
||||
var/list/message = list()
|
||||
message["id"] = get_comm_message_id()
|
||||
message["title"] = message_title
|
||||
message["contents"] = message_text
|
||||
|
||||
for (var/datum/comm_message_listener/l in comm_message_listeners)
|
||||
l.Add(message)
|
||||
|
||||
//Old console support
|
||||
for (var/obj/machinery/computer/communications/comm in machines)
|
||||
if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
|
||||
var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc )
|
||||
intercept.name = message_title
|
||||
intercept.info = message_text
|
||||
|
||||
comm.messagetitle.Add(message_title)
|
||||
comm.messagetext.Add(message_text)
|
||||
|
||||
/datum/comm_message_listener
|
||||
var/list/messages
|
||||
|
||||
/datum/comm_message_listener/New()
|
||||
..()
|
||||
messages = list()
|
||||
comm_message_listeners.Add(src)
|
||||
|
||||
/datum/comm_message_listener/proc/Add(var/list/message)
|
||||
messages[++messages.len] = message
|
||||
|
||||
/datum/comm_message_listener/proc/Remove(var/list/message)
|
||||
messages -= list(message)
|
||||
@@ -12,13 +12,13 @@
|
||||
size = 4
|
||||
available_on_ntnet = 0
|
||||
requires_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/computer_configurator/
|
||||
nanomodule_path = /datum/nano_module/program/computer_configurator/
|
||||
|
||||
/datum/nano_module/computer_configurator
|
||||
/datum/nano_module/program/computer_configurator
|
||||
name = "NTOS Computer Configuration Tool"
|
||||
var/obj/item/modular_computer/movable = null
|
||||
|
||||
/datum/nano_module/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_configurator/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)
|
||||
movable = program.computer
|
||||
if(!istype(movable))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#define MAX_TEXTFILE_LENGTH 128000 // 512GQ file
|
||||
/datum/computer_file/program/filemanager
|
||||
filename = "filemanager"
|
||||
filedesc = "NTOS File Manager"
|
||||
@@ -7,7 +8,7 @@
|
||||
requires_ntnet = 0
|
||||
available_on_ntnet = 0
|
||||
undeletable = 1
|
||||
nanomodule_path = /datum/nano_module/computer_filemanager/
|
||||
nanomodule_path = /datum/nano_module/program/computer_filemanager/
|
||||
var/open_file
|
||||
var/error
|
||||
|
||||
@@ -83,8 +84,16 @@
|
||||
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
|
||||
if(!F || !istype(F))
|
||||
return 1
|
||||
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
|
||||
var/newtext = sanitize(html_decode(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", F.stored_data) as message), 16384)
|
||||
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
|
||||
return 1
|
||||
|
||||
var/oldtext = html_decode(F.stored_data)
|
||||
oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
|
||||
|
||||
var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[editorbr\]"), MAX_TEXTFILE_LENGTH)
|
||||
if(!newtext)
|
||||
return
|
||||
|
||||
if(F)
|
||||
var/datum/computer_file/data/backup = F.clone()
|
||||
HDD.remove_file(F)
|
||||
@@ -94,7 +103,7 @@
|
||||
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
|
||||
// They will be able to copy-paste the text from error screen and store it in notepad or something.
|
||||
if(!HDD.store_file(F))
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[F.stored_data]<br><br>"
|
||||
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[html_decode(F.stored_data)]<br><br>"
|
||||
HDD.store_file(backup)
|
||||
if(href_list["PRG_printfile"])
|
||||
. = 1
|
||||
@@ -109,7 +118,7 @@
|
||||
if(!computer.nano_printer)
|
||||
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
|
||||
return 1
|
||||
if(!computer.nano_printer.print_text(parse_tags(F.stored_data)))
|
||||
if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
|
||||
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
|
||||
return 1
|
||||
if(href_list["PRG_copytousb"])
|
||||
@@ -137,56 +146,14 @@
|
||||
if(.)
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/filemanager/proc/parse_tags(var/t)
|
||||
t = replacetext(t, "\[center\]", "<center>")
|
||||
t = replacetext(t, "\[/center\]", "</center>")
|
||||
t = replacetext(t, "\[br\]", "<BR>")
|
||||
t = replacetext(t, "\[b\]", "<B>")
|
||||
t = replacetext(t, "\[/b\]", "</B>")
|
||||
t = replacetext(t, "\[i\]", "<I>")
|
||||
t = replacetext(t, "\[/i\]", "</I>")
|
||||
t = replacetext(t, "\[u\]", "<U>")
|
||||
t = replacetext(t, "\[/u\]", "</U>")
|
||||
t = replacetext(t, "\[time\]", "[worldtime2text()]")
|
||||
t = replacetext(t, "\[date\]", "[worlddate2text()]")
|
||||
t = replacetext(t, "\[large\]", "<font size=\"4\">")
|
||||
t = replacetext(t, "\[/large\]", "</font>")
|
||||
t = replacetext(t, "\[h1\]", "<H1>")
|
||||
t = replacetext(t, "\[/h1\]", "</H1>")
|
||||
t = replacetext(t, "\[h2\]", "<H2>")
|
||||
t = replacetext(t, "\[/h2\]", "</H2>")
|
||||
t = replacetext(t, "\[h3\]", "<H3>")
|
||||
t = replacetext(t, "\[/h3\]", "</H3>")
|
||||
t = replacetext(t, "\[*\]", "<li>")
|
||||
t = replacetext(t, "\[hr\]", "<HR>")
|
||||
t = replacetext(t, "\[small\]", "<font size = \"1\">")
|
||||
t = replacetext(t, "\[/small\]", "</font>")
|
||||
t = replacetext(t, "\[list\]", "<ul>")
|
||||
t = replacetext(t, "\[/list\]", "</ul>")
|
||||
t = replacetext(t, "\[table\]", "<table border=1 cellspacing=0 cellpadding=3 style='border: 1px solid black;'>")
|
||||
t = replacetext(t, "\[/table\]", "</td></tr></table>")
|
||||
t = replacetext(t, "\[grid\]", "<table>")
|
||||
t = replacetext(t, "\[/grid\]", "</td></tr></table>")
|
||||
t = replacetext(t, "\[row\]", "</td><tr>")
|
||||
t = replacetext(t, "\[tr\]", "</td><tr>")
|
||||
t = replacetext(t, "\[td\]", "<td>")
|
||||
t = replacetext(t, "\[cell\]", "<td>")
|
||||
t = replacetext(t, "\[logo\]", "<img src = ntlogo.png>")
|
||||
return t
|
||||
|
||||
|
||||
/datum/nano_module/computer_filemanager
|
||||
/datum/nano_module/program/computer_filemanager
|
||||
name = "NTOS File Manager"
|
||||
|
||||
/datum/nano_module/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
|
||||
/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
var/datum/computer_file/program/filemanager/PRG
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
PRG = program
|
||||
else
|
||||
return
|
||||
//var/list/data = program.get_header_data()
|
||||
PRG = program
|
||||
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
|
||||
@@ -203,7 +170,7 @@
|
||||
if(!istype(file))
|
||||
data["error"] = "I/O ERROR: Unable to open file."
|
||||
else
|
||||
data["filedata"] = PRG.parse_tags(file.stored_data)
|
||||
data["filedata"] = pencode2html(file.stored_data)
|
||||
data["filename"] = "[file.filename].[file.filetype]"
|
||||
else
|
||||
if(!PRG.computer || !PRG.computer.hard_drive)
|
||||
@@ -238,5 +205,4 @@
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
|
||||
#undef MAX_TEXTFILE_LENGTH
|
||||
@@ -0,0 +1,151 @@
|
||||
// This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation
|
||||
// for someone who may not be as experienced in coding. When making changes, please try to keep it this way.
|
||||
|
||||
// An actual program definition.
|
||||
/datum/computer_file/program/game
|
||||
filename = "arcadec" // File name, as shown in the file browser program.
|
||||
filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor.
|
||||
program_icon_state = "game" // Icon state of this program's screen.
|
||||
extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description.
|
||||
size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
|
||||
requires_ntnet = 0 // This particular program does not require NTNet network conectivity...
|
||||
available_on_ntnet = 1 // ... but we want it to be available for download.
|
||||
nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file.
|
||||
var/picked_enemy_name
|
||||
|
||||
// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name
|
||||
/datum/computer_file/program/game/proc/random_enemy_name()
|
||||
var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ", "the vibrating bluespace")
|
||||
var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn", "Squirrel")
|
||||
return "[name_part1] [name_part2]"
|
||||
|
||||
// When the program is first created, we generate a new enemy name and name ourselves accordingly.
|
||||
/datum/computer_file/program/game/New()
|
||||
..()
|
||||
picked_enemy_name = random_enemy_name()
|
||||
filedesc = "Defeat [picked_enemy_name]"
|
||||
|
||||
// Important in order to ensure that copied versions will have the same enemy name.
|
||||
/datum/computer_file/program/game/clone()
|
||||
var/datum/computer_file/program/game/G = ..()
|
||||
G.picked_enemy_name = picked_enemy_name
|
||||
return G
|
||||
|
||||
// When running the program, we also want to pass our enemy name to the nano module.
|
||||
/datum/computer_file/program/game/run_program()
|
||||
. = ..()
|
||||
if(. && NM)
|
||||
var/datum/nano_module/arcade_classic/NMC = NM
|
||||
NMC.enemy_name = picked_enemy_name
|
||||
|
||||
|
||||
// Nano module the program uses.
|
||||
// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers,
|
||||
// and should generally not be used, as such nano modules are hard to use on other places.
|
||||
/datum/nano_module/arcade_classic/
|
||||
name = "Classic Arcade"
|
||||
var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats.
|
||||
var/player_health
|
||||
var/enemy_mana
|
||||
var/enemy_health
|
||||
var/enemy_name = "Greytide Horde"
|
||||
var/gameover
|
||||
var/information
|
||||
|
||||
/datum/nano_module/arcade_classic/New()
|
||||
..()
|
||||
new_game()
|
||||
|
||||
// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client
|
||||
// to see, and don't send unnecessarily large amounts of data (due to laginess).
|
||||
/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["player_health"] = player_health
|
||||
data["player_mana"] = player_mana
|
||||
data["enemy_health"] = enemy_health
|
||||
data["enemy_mana"] = enemy_mana
|
||||
data["enemy_name"] = enemy_name
|
||||
data["gameover"] = gameover
|
||||
data["information"] = information
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state)
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too.
|
||||
/datum/nano_module/arcade_classic/proc/enemy_play()
|
||||
if((enemy_mana < 5) && prob(60))
|
||||
var/steal = rand(2, 3)
|
||||
player_mana -= steal
|
||||
enemy_mana += steal
|
||||
information += "[enemy_name] steals [steal] of your power!"
|
||||
else if((enemy_health < 15) && (enemy_mana > 3) && prob(80))
|
||||
var/healamt = min(rand(3, 5), enemy_mana)
|
||||
enemy_mana -= healamt
|
||||
enemy_health += healamt
|
||||
information += "[enemy_name] heals for [healamt] health!"
|
||||
else
|
||||
var/dam = rand(3,6)
|
||||
player_health -= dam
|
||||
information += "[enemy_name] attacks for [dam] damage!"
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/check_gameover()
|
||||
if((player_health <= 0) || player_mana <= 0)
|
||||
if(enemy_health <= 0)
|
||||
information += "You have defeated [enemy_name], but you have died in the fight!"
|
||||
else
|
||||
information += "You have been defeated by [enemy_name]!"
|
||||
gameover = 1
|
||||
return TRUE
|
||||
else if(enemy_health <= 0)
|
||||
gameover = 1
|
||||
information += "Congratulations! You have defeated [enemy_name]!"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/nano_module/arcade_classic/proc/new_game()
|
||||
player_mana = 10
|
||||
player_health = 30
|
||||
enemy_mana = 20
|
||||
enemy_health = 45
|
||||
gameover = FALSE
|
||||
information = "A new game has started!"
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/arcade_classic/Topic(href, href_list)
|
||||
if(..()) // Always begin your Topic() calls with a parent call!
|
||||
return 1
|
||||
if(href_list["new_game"])
|
||||
new_game()
|
||||
return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates.
|
||||
if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all.
|
||||
return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste.
|
||||
if(href_list["attack"])
|
||||
var/damage = rand(2, 6)
|
||||
information = "You attack for [damage] damage."
|
||||
enemy_health -= damage
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["heal"])
|
||||
var/healfor = rand(6, 8)
|
||||
var/cost = rand(1, 3)
|
||||
information = "You heal yourself for [healfor] damage, using [cost] energy in the process."
|
||||
player_health += healfor
|
||||
player_mana -= cost
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
if(href_list["regain_mana"])
|
||||
var/regen = rand(4, 7)
|
||||
information = "You rest of a while, regaining [regen] energy."
|
||||
player_mana += regen
|
||||
enemy_play()
|
||||
check_gameover()
|
||||
return 1
|
||||
@@ -0,0 +1,129 @@
|
||||
/datum/computer_file/program/newsbrowser
|
||||
filename = "newsbrowser"
|
||||
filedesc = "NTNet/ExoNet News Browser"
|
||||
extended_desc = "This program may be used to view and download news articles from the network."
|
||||
program_icon_state = "generic"
|
||||
size = 8
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
|
||||
nanomodule_path = /datum/nano_module/program/computer_newsbrowser/
|
||||
var/datum/computer_file/data/news_article/loaded_article
|
||||
var/download_progress = 0
|
||||
var/download_netspeed = 0
|
||||
var/downloading = 0
|
||||
var/message = ""
|
||||
var/show_archived = 0
|
||||
|
||||
/datum/computer_file/program/newsbrowser/process_tick()
|
||||
if(!downloading)
|
||||
return
|
||||
download_netspeed = 0
|
||||
// Speed defines are found in misc.dm
|
||||
switch(ntnet_status)
|
||||
if(1)
|
||||
download_netspeed = NTNETSPEED_LOWSIGNAL
|
||||
if(2)
|
||||
download_netspeed = NTNETSPEED_HIGHSIGNAL
|
||||
if(3)
|
||||
download_netspeed = NTNETSPEED_ETHERNET
|
||||
download_progress += download_netspeed
|
||||
if(download_progress >= loaded_article.size)
|
||||
downloading = 0
|
||||
requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory.
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
/datum/computer_file/program/newsbrowser/kill_program()
|
||||
..()
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
download_progress = 0
|
||||
downloading = 0
|
||||
show_archived = 0
|
||||
|
||||
/datum/computer_file/program/newsbrowser/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
if(href_list["PRG_openarticle"])
|
||||
. = 1
|
||||
if(downloading || loaded_article)
|
||||
return 1
|
||||
|
||||
for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
|
||||
if(N.uid == text2num(href_list["PRG_openarticle"]))
|
||||
loaded_article = N.clone()
|
||||
downloading = 1
|
||||
break
|
||||
if(href_list["PRG_reset"])
|
||||
. = 1
|
||||
downloading = 0
|
||||
download_progress = 0
|
||||
requires_ntnet = 1
|
||||
loaded_article = null
|
||||
if(href_list["PRG_clearmessage"])
|
||||
. = 1
|
||||
message = ""
|
||||
if(href_list["PRG_savearticle"])
|
||||
. = 1
|
||||
if(downloading || !loaded_article)
|
||||
return
|
||||
|
||||
var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
|
||||
if(!savename)
|
||||
return 1
|
||||
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
|
||||
if(!HDD)
|
||||
return 1
|
||||
var/datum/computer_file/data/news_article/N = loaded_article.clone()
|
||||
N.filename = savename
|
||||
HDD.store_file(N)
|
||||
if(href_list["PRG_toggle_archived"])
|
||||
. = 1
|
||||
show_archived = !show_archived
|
||||
if(.)
|
||||
nanomanager.update_uis(NM)
|
||||
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser
|
||||
name = "NTNet/ExoNet News Browser"
|
||||
|
||||
/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
|
||||
var/datum/computer_file/program/newsbrowser/PRG
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
PRG = program
|
||||
else
|
||||
return
|
||||
|
||||
data["message"] = PRG.message
|
||||
if(PRG.loaded_article && !PRG.downloading) // Viewing an article.
|
||||
data["title"] = PRG.loaded_article.filename
|
||||
data["article"] = PRG.loaded_article.stored_data
|
||||
else if(PRG.downloading) // Downloading an article.
|
||||
data["download_running"] = 1
|
||||
data["download_progress"] = PRG.download_progress
|
||||
data["download_maxprogress"] = PRG.loaded_article.size
|
||||
data["download_rate"] = PRG.download_netspeed
|
||||
else // Viewing list of articles
|
||||
var/list/all_articles[0]
|
||||
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
|
||||
if(!PRG.show_archived && F.archived)
|
||||
continue
|
||||
all_articles.Add(list(list(
|
||||
"name" = F.filename,
|
||||
"size" = F.size,
|
||||
"uid" = F.uid,
|
||||
"archived" = F.archived
|
||||
)))
|
||||
data["all_articles"] = all_articles
|
||||
data["showing_archived"] = PRG.show_archived
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
requires_ntnet = 1
|
||||
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
|
||||
available_on_ntnet = 0
|
||||
nanomodule_path = /datum/nano_module/computer_ntnetdownload/
|
||||
nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/
|
||||
ui_header = "downloader_finished.gif"
|
||||
var/datum/computer_file/program/downloaded_file = null
|
||||
var/hacked_download = 0
|
||||
@@ -102,7 +102,7 @@
|
||||
download_netspeed += delta
|
||||
download_netspeed = round(download_netspeed, 0.002)//3 decimal places
|
||||
|
||||
var/delta_seconds = (download_last_update - world.time) * 10
|
||||
var/delta_seconds = (world.time - download_last_update) / 10
|
||||
|
||||
download_completion = min(download_completion + delta_seconds * download_netspeed, downloaded_file.size)
|
||||
|
||||
@@ -130,11 +130,11 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/nano_module/computer_ntnetdownload
|
||||
/datum/nano_module/program/computer_ntnetdownload
|
||||
name = "Network Downloader"
|
||||
var/obj/item/modular_computer/my_computer = null
|
||||
|
||||
/datum/nano_module/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)
|
||||
/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
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
var/list/all_entries[0]
|
||||
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
|
||||
// Only those programs our user can run will show in the list
|
||||
if(!P.can_run(user))
|
||||
if(!P.can_run(user) && P.requires_access_to_download)
|
||||
continue
|
||||
all_entries.Add(list(list(
|
||||
"filename" = P.filename,
|
||||
|
||||
@@ -11,15 +11,12 @@
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor
|
||||
name = "NTNet Diagnostics and Monitoring"
|
||||
available_to_ai = TRUE
|
||||
|
||||
/datum/nano_module/computer_ntnetmonitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
if(program)
|
||||
data = program.get_header_data()
|
||||
|
||||
var/list/data = host.initial_data()
|
||||
|
||||
data["ntnetstatus"] = ntnet_global.check_function()
|
||||
data["ntnetrelays"] = ntnet_global.relays.len
|
||||
@@ -38,7 +35,8 @@
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state)
|
||||
ui.auto_update_layout = 1
|
||||
if(host.update_layout())
|
||||
ui.auto_update_layout = 1
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
network_destination = "NTNRC server"
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_chatclient/
|
||||
nanomodule_path = /datum/nano_module/program/computer_chatclient/
|
||||
var/last_message = null // Used to generate the toolbar icon
|
||||
var/username
|
||||
var/datum/ntnet_conversation/channel = null
|
||||
@@ -159,7 +159,7 @@
|
||||
|
||||
/datum/computer_file/program/chatclient/process_tick()
|
||||
..()
|
||||
if(running)
|
||||
if(program_state != PROGRAM_STATE_KILLED)
|
||||
ui_header = "ntnrc_idle.gif"
|
||||
if(channel)
|
||||
// Remember the last message. If there is no message in the channel remember null.
|
||||
@@ -178,10 +178,10 @@
|
||||
channel = null
|
||||
..(forced)
|
||||
|
||||
/datum/nano_module/computer_chatclient
|
||||
/datum/nano_module/program/computer_chatclient
|
||||
name = "NTNet Relay Chat Client"
|
||||
|
||||
/datum/nano_module/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
if(!ntnet_global || !ntnet_global.chat_channels)
|
||||
return
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ var/global/nttransfer_uid = 0
|
||||
requires_ntnet_feature = NTNET_PEERTOPEER
|
||||
network_destination = "other device via P2P tunnel"
|
||||
available_on_ntnet = 1
|
||||
nanomodule_path = /datum/nano_module/computer_nttransfer/
|
||||
nanomodule_path = /datum/nano_module/program/computer_nttransfer/
|
||||
|
||||
var/error = "" // Error screen
|
||||
var/server_password = "" // Optional password to download the file.
|
||||
@@ -87,13 +87,10 @@ var/global/nttransfer_uid = 0
|
||||
download_completion = 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/datum/nano_module/computer_nttransfer
|
||||
/datum/nano_module/program/computer_nttransfer
|
||||
name = "NTNet P2P Transfer Client"
|
||||
|
||||
/datum/nano_module/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
|
||||
/datum/nano_module/program/computer_nttransfer/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)
|
||||
return
|
||||
var/datum/computer_file/program/nttransfer/PRG = program
|
||||
|
||||
Reference in New Issue
Block a user