Modular Cmp Updates

This commit is contained in:
Letter N
2021-02-12 18:29:00 +08:00
parent 5db87b9065
commit 5b0a1077f4
46 changed files with 1311 additions and 318 deletions
@@ -33,6 +33,14 @@
var/tgui_id
/// 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 /icons/program_icons. Be careful not to use too large images!
var/ui_header = null
/// Font Awesome icon to use as this program's icon in the modular computer main menu. Defaults to a basic program maximize window icon if not overridden.
var/program_icon = "window-maximize-o"
/// Whether this program can send alerts while minimized or closed. Used to show a mute button per program in the file manager
var/alert_able = FALSE
/// Whether the user has muted this program's ability to send alerts.
var/alert_silenced = FALSE
/// Whether to highlight our program in the main screen. Intended for alerts, but loosely available for any need to notify of changed conditions. Think Windows task bar highlighting. Available even if alerts are muted.
var/alert_pending = FALSE
/datum/computer_file/program/New(obj/item/modular_computer/comp = null)
..()
@@ -68,8 +76,8 @@
if(!(hardware_flag & usage_flags))
if(loud && computer && user)
to_chat(user, "<span class='danger'>\The [computer] flashes a \"Hardware Error - Incompatible software\" warning.</span>")
return 0
return 1
return FALSE
return TRUE
/datum/computer_file/program/proc/get_signal(specific_action = 0)
if(computer)
@@ -77,21 +85,21 @@
return 0
// Called by Process() on device that runs us, once every tick.
/datum/computer_file/program/proc/process_tick()
return 1
/datum/computer_file/program/proc/process_tick(delta_time)
return TRUE
/**
*Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
*ID must be inserted into a card slot to be read. If the program is not currently installed (as is the case when
*NT Software Hub is checking available software), a list can be given to be used instead.
*Arguments:
*user is a ref of the mob using the device.
*loud is a bool deciding if this proc should use to_chats
*access_to_check is an access level that will be checked against the ID
*transfer, if TRUE and access_to_check is null, will tell this proc to use the program's transfer_access in place of access_to_check
*access can contain a list of access numbers to check against. If access is not empty, it will be used istead of checking any inserted ID.
*Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
*ID must be inserted into a card slot to be read. If the program is not currently installed (as is the case when
*NT Software Hub is checking available software), a list can be given to be used instead.
*Arguments:
*user is a ref of the mob using the device.
*loud is a bool deciding if this proc should use to_chats
*access_to_check is an access level that will be checked against the ID
*transfer, if TRUE and access_to_check is null, will tell this proc to use the program's transfer_access in place of access_to_check
*access can contain a list of access numbers to check against. If access is not empty, it will be used istead of checking any inserted ID.
*/
/datum/computer_file/program/proc/can_run(mob/user, loud = FALSE, access_to_check, transfer = FALSE, var/list/access)
/datum/computer_file/program/proc/can_run(mob/user, loud = FALSE, access_to_check, transfer = FALSE, list/access)
// Defaults to required_access
if(!access_to_check)
if(transfer && transfer_access)
@@ -147,19 +155,19 @@
ID = card_holder.GetID()
generate_network_log("Connection opened -- Program ID: [filename] User:[ID?"[ID.registered_name]":"None"]")
program_state = PROGRAM_STATE_ACTIVE
return 1
return 0
return TRUE
return FALSE
/**
*
*Called by the device when it is emagged.
*
*Emagging the device allows certain programs to unlock new functions. However, the program will
*need to be downloaded first, and then handle the unlock on their own in their run_emag() proc.
*The device will allow an emag to be run multiple times, so the user can re-emag to run the
*override again, should they download something new. The run_emag() proc should return TRUE if
*the emagging affected anything, and FALSE if no change was made (already emagged, or has no
*emag functions).
*
*Called by the device when it is emagged.
*
*Emagging the device allows certain programs to unlock new functions. However, the program will
*need to be downloaded first, and then handle the unlock on their own in their run_emag() proc.
*The device will allow an emag to be run multiple times, so the user can re-emag to run the
*override again, should they download something new. The run_emag() proc should return TRUE if
*the emagging affected anything, and FALSE if no change was made (already emagged, or has no
*emag functions).
**/
/datum/computer_file/program/proc/run_emag()
return FALSE
@@ -179,8 +187,8 @@
ui = SStgui.try_update_ui(user, src, ui)
if(!ui && tgui_id)
ui = new(user, src, tgui_id, filedesc)
ui.open()
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
if(ui.open())
ui.send_asset(get_asset_datum(/datum/asset/simple/headers))
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
// Topic calls are automagically forwarded from NanoModule this program contains.
@@ -188,18 +196,20 @@
// 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/ui_act(action,list/params,datum/tgui/ui)
if(..())
return 1
. = ..()
if(.)
return
if(computer)
switch(action)
if("PC_exit")
computer.kill_program()
ui.close()
return 1
return TRUE
if("PC_shutdown")
computer.shutdown_computer()
ui.close()
return 1
return TRUE
if("PC_minimize")
var/mob/user = usr
if(!computer.active_program || !computer.all_components[MC_CPU])
@@ -9,6 +9,7 @@
transfer_access = ACCESS_HEADS
available_on_ntnet = TRUE
tgui_id = "NtosAiRestorer"
program_icon = "laptop-code"
/// Variable dictating if we are in the process of restoring the AI in the inserted intellicard
var/restoring = FALSE
@@ -19,7 +20,7 @@
if(computer)
ai_slot = computer.all_components[MC_AI]
if(computer && ai_slot && ai_slot.check_functionality())
if(computer && ai_slot?.check_functionality())
if(cardcheck == 1)
return ai_slot
if(ai_slot.enabled && ai_slot.stored_card)
@@ -31,7 +32,8 @@
return
/datum/computer_file/program/aidiag/ui_act(action, params)
if(..())
. = ..()
if(.)
return
var/mob/living/silicon/ai/A = get_ai()
@@ -47,7 +49,7 @@
if("PRG_eject")
if(computer.all_components[MC_AI])
var/obj/item/computer_hardware/ai_slot/ai_slot = computer.all_components[MC_AI]
if(ai_slot && ai_slot.stored_card)
if(ai_slot?.stored_card)
ai_slot.try_eject(usr)
return TRUE
@@ -72,10 +74,10 @@
restoring = FALSE
return
ai_slot.locked = TRUE
A.adjustOxyLoss(-5, 0)//, FALSE)
A.adjustFireLoss(-5, 0)//, FALSE)
A.adjustToxLoss(-5, 0)
A.adjustBruteLoss(-5, 0)
A.adjustOxyLoss(-5, FALSE)
A.adjustFireLoss(-5, FALSE)
A.adjustToxLoss(-5, FALSE)
A.adjustBruteLoss(-5, FALSE)
// Please don't forget to update health, otherwise the below if statements will probably always fail.
A.updatehealth()
@@ -7,6 +7,7 @@
requires_ntnet = 1
size = 5
tgui_id = "NtosStationAlertConsole"
program_icon = "bell"
var/has_alert = 0
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
@@ -9,6 +9,7 @@
unsendable = 1
undeletable = 1
tgui_id = "SyndContractor"
program_icon = "tasks"
var/error = ""
var/info_screen = TRUE
var/assigned = FALSE
@@ -18,8 +19,9 @@
. = ..(user)
/datum/computer_file/program/contract_uplink/ui_act(action, params)
if(..())
return TRUE
. = ..()
if(.)
return
var/mob/living/user = usr
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
@@ -8,6 +8,7 @@
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosNetDos"
program_icon = "satellite-dish"
var/obj/machinery/ntnet_relay/target = null
var/dos_speed = 0
@@ -39,7 +40,8 @@
..()
/datum/computer_file/program/ntnet_dos/ui_act(action, params)
if(..())
. = ..()
if(.)
return
switch(action)
if("PRG_target_relay")
@@ -8,6 +8,7 @@
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosRevelation"
program_icon = "magnet"
var/armed = 0
/datum/computer_file/program/revelation/run_program(mob/living/user)
@@ -17,6 +18,12 @@
/datum/computer_file/program/revelation/proc/activate()
if(computer)
if(istype(computer, /obj/item/modular_computer/tablet/integrated)) //If this is a borg's integrated tablet
var/obj/item/modular_computer/tablet/integrated/modularInterface = computer
to_chat(modularInterface.borgo,"<span class='userdanger'>SYSTEM PURGE DETECTED/</span>")
addtimer(CALLBACK(modularInterface.borgo, /mob/living/silicon/robot/.proc/death), 2 SECONDS, TIMER_UNIQUE)
return
computer.visible_message("<span class='notice'>\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.</span>")
computer.enabled = FALSE
computer.update_icon()
@@ -39,7 +46,8 @@
/datum/computer_file/program/revelation/ui_act(action, params)
if(..())
. = ..()
if(.)
return
switch(action)
if("PRG_arm")
@@ -6,6 +6,7 @@
requires_ntnet = FALSE
size = 6
tgui_id = "NtosArcade"
program_icon = "gamepad"
///Returns TRUE if the game is being played.
var/game_active = TRUE
@@ -27,7 +28,7 @@
// user?.mind?.adjust_experience(/datum/skill/gaming, 1)
if(boss_hp <= 0)
heads_up = "You have crushed [boss_name]! Rejoice!"
playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/win.ogg', 50)
game_active = FALSE
program_icon_state = "arcade_off"
if(istype(computer))
@@ -37,7 +38,7 @@
sleep(10)
else if(player_hp <= 0 || player_mp <= 0)
heads_up = "You have been defeated... how will the station survive?"
playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/lose.ogg', 50)
game_active = FALSE
program_icon_state = "arcade_off"
if(istype(computer))
@@ -57,17 +58,17 @@
return
if (boss_mp <= 5)
heads_up = "[boss_mpamt] magic power has been stolen from you!"
playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE)
player_mp -= boss_mpamt
boss_mp += boss_mpamt
else if(boss_mp > 5 && boss_hp <12)
heads_up = "[boss_name] heals for [bossheal] health!"
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE)
boss_hp += bossheal
boss_mp -= boss_mpamt
else
heads_up = "[boss_name] attacks you for [boss_attackamt] damage!"
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE)
player_hp -= boss_attackamt
pause_state = FALSE
@@ -91,22 +92,27 @@
return data
/datum/computer_file/program/arcade/ui_act(action, list/params)
if(..())
return TRUE
. = ..()
if(.)
return
var/obj/item/computer_hardware/printer/printer
if(computer)
printer = computer.all_components[MC_PRINT]
// var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming)
// var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
// var/gamerSkillLevel = 0
var/gamerSkill = 0
// if(usr?.mind)
// gamerSkillLevel = usr.mind.get_skill_level(/datum/skill/gaming)
// gamerSkill = usr.mind.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
switch(action)
if("Attack")
var/attackamt = 0 //Spam prevention.
if(pause_state == FALSE)
attackamt = rand(2,6)// + rand(0, gamerSkill)
attackamt = rand(2,6) + rand(0, gamerSkill)
pause_state = TRUE
heads_up = "You attack for [attackamt] damage."
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE)
boss_hp -= attackamt
sleep(10)
game_check()
@@ -116,14 +122,14 @@
var/healamt = 0 //More Spam Prevention.
var/healcost = 0
if(pause_state == FALSE)
healamt = rand(6,8)// + rand(0, gamerSkill)
healamt = rand(6,8) + rand(0, gamerSkill)
var/maxPointCost = 3
// if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN)
// maxPointCost = 2
healcost = rand(1, maxPointCost)
pause_state = TRUE
heads_up = "You heal for [healamt] damage."
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE)
player_hp += healamt
player_mp -= healcost
sleep(10)
@@ -133,10 +139,10 @@
if("Recharge_Power")
var/rechargeamt = 0 //As above.
if(pause_state == FALSE)
rechargeamt = rand(4,7)// + rand(0, gamerSkill)
rechargeamt = rand(4,7) + rand(0, gamerSkill)
pause_state = TRUE
heads_up = "You regain [rechargeamt] magic power."
playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3)
playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE)
player_mp += rechargeamt
sleep(10)
game_check()
@@ -153,7 +159,7 @@
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
if(ticket_count >= 1)
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
to_chat(usr, "<span class='notice'>[computer] dispenses a ticket!</span>")
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
ticket_count -= 1
printer.stored_paper -= 1
else
@@ -5,6 +5,7 @@
extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device."
size = 4
tgui_id = "NtosAtmos"
program_icon = "thermometer-half"
/datum/computer_file/program/atmosscan/run_program(mob/living/user)
. = ..()
@@ -39,5 +40,6 @@
return data
/datum/computer_file/program/atmosscan/ui_act(action, list/params)
if(..())
return TRUE
. = ..()
if(.)
return
@@ -8,6 +8,7 @@
transfer_access = ACCESS_ROBOTICS
size = 5
tgui_id = "NtosCyborgRemoteMonitor"
program_icon = "project-diagram"
/datum/computer_file/program/borg_monitor/ui_data(mob/user)
var/list/data = get_header_data()
@@ -43,7 +44,8 @@
return data
/datum/computer_file/program/borg_monitor/ui_act(action, params)
if(..())
. = ..()
if(.)
return
switch(action)
@@ -54,10 +56,14 @@
var/ID = checkID()
if(!ID)
return
if(R.stat == DEAD) //Dead borgs will listen to you no longer
to_chat(usr, "<span class='warn'>Error -- Could not open a connection to unit:[R]</span>")
var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message")
if(!message)
return
to_chat(R, "<br><br><span class='notice'>Message from [ID] -- \"[message]\"</span><br>")
to_chat(usr, "Message sent to [R]: [message]")
R.logevent("Message from [ID] -- \"[message]\"")
SEND_SOUND(R, 'sound/machines/twobeep_high.ogg')
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='notice'>Message from [ID] to [R] -- \"[message]\"</span><br>")
@@ -44,7 +44,8 @@
return data
/datum/computer_file/program/bounty_board/ui_act(action, list/params)
if(..())
. = ..()
if(.)
return
var/current_ref_num = params["request"]
var/current_app_num = params["applicant"]
@@ -0,0 +1,280 @@
/datum/computer_file/program/budgetorders
filename = "orderapp"
filedesc = "Nanotrasen Internal Requisition Network (NIRN)"
program_icon_state = "request"
extended_desc = "A request network that utilizes the Nanotrasen Ordering network to purchase supplies using a department budget account."
requires_ntnet = TRUE
transfer_access = ACCESS_HEADS
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET
size = 20
tgui_id = "NtosCargo"
///Are you actually placing orders with it?
var/requestonly = TRUE
///Can the tablet see or buy illegal stuff?
var/contraband = FALSE
///Is it being bought from a personal account, or is it being done via a budget/cargo?
var/self_paid = FALSE
///Can this console approve purchase requests?
var/can_approve_requests = FALSE
///What do we say when the shuttle moves with living beings on it.
var/safety_warning = "For safety reasons, the automated supply shuttle \
cannot transport live organisms, human remains, classified nuclear weaponry, \
homing beacons or machinery housing any form of artificial intelligence."
///If you're being raided by pirates, what do you tell the crew?
var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
/datum/computer_file/program/budgetorders/proc/get_export_categories()
. = EXPORT_CARGO
/datum/computer_file/program/budgetorders/proc/is_visible_pack(mob/user, paccess_to_check, list/access, contraband)
if(issilicon(user)) //Borgs can't buy things.
return FALSE
if(computer.obj_flags & EMAGGED)
return TRUE
else if(contraband) //Hide contrband when non-emagged.
return FALSE
if(!paccess_to_check) // No required_access, allow it.
return TRUE
if(isAdminGhostAI(user))
return TRUE
//Aquire access from the inserted ID card.
if(!length(access))
var/obj/item/card/id/D
var/obj/item/computer_hardware/card_slot/card_slot
if(computer)
card_slot = computer.all_components[MC_CARD]
D = card_slot?.GetID()
if(!D)
return FALSE
access = D.GetAccess()
if(paccess_to_check in access)
return TRUE
return FALSE
/datum/computer_file/program/budgetorders/ui_data()
. = ..()
var/list/data = get_header_data()
data["location"] = SSshuttle.supply.getStatusText()
var/datum/bank_account/buyer = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/card/id/id_card = card_slot?.GetID()
if(id_card?.registered_account)
if(ACCESS_HEADS in id_card.access)
requestonly = FALSE
buyer = SSeconomy.get_dep_account(id_card.registered_account.account_job.paycheck_department)
can_approve_requests = TRUE
else
requestonly = TRUE
can_approve_requests = FALSE
else
requestonly = TRUE
if(buyer)
data["points"] = buyer.account_balance
//Otherwise static data, that is being applied in ui_data as the crates visible and buyable are not static, and are determined by inserted ID.
data["requestonly"] = requestonly
data["supplies"] = list()
for(var/pack in SSshuttle.supply_packs)
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
if(!is_visible_pack(usr, P.access_view , null, P.contraband) || P.hidden)
continue
if(!data["supplies"][P.group])
data["supplies"][P.group] = list(
"name" = P.group,
"packs" = list()
)
if((P.hidden && (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.DropPodOnly))
continue
data["supplies"][P.group]["packs"] += list(list(
"name" = P.name,
"cost" = P.cost,
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
"goody" = P.goody,
"access" = P.access
))
//Data regarding the User's capability to buy things.
data["has_id"] = id_card
data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
data["self_paid"] = self_paid
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
data["loan"] = !!SSshuttle.shuttle_loan
data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
data["can_send"] = FALSE //There is no situation where I want the app to be able to send the shuttle AWAY from the station, but conversely is fine.
data["can_approve_requests"] = can_approve_requests
data["app_cost"] = TRUE
var/message = "Remember to stamp and send back the supply manifests."
if(SSshuttle.centcom_message)
message = SSshuttle.centcom_message
if(SSshuttle.supplyBlocked)
message = blockade_warning
data["message"] = message
data["cart"] = list()
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
data["cart"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"id" = SO.id,
"orderer" = SO.orderer,
"paid" = !isnull(SO.paying_account) //paid by requester
))
data["requests"] = list()
for(var/datum/supply_order/SO in SSshuttle.requestlist)
data["requests"] += list(list(
"object" = SO.pack.name,
"cost" = SO.pack.cost,
"orderer" = SO.orderer,
"reason" = SO.reason,
"id" = SO.id
))
return data
/datum/computer_file/program/budgetorders/ui_act(action, params, datum/tgui/ui)
if(..())
return
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
switch(action)
if("send")
if(!SSshuttle.supply.canMove())
computer.say(safety_warning)
return
if(SSshuttle.supplyBlocked)
computer.say(blockade_warning)
return
if(SSshuttle.supply.getDockedId() == "supply_home")
SSshuttle.supply.export_categories = get_export_categories()
SSshuttle.moveShuttle("supply", "supply_away", TRUE)
computer.say("The supply shuttle is departing.")
computer.investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO)
else
computer.investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO)
computer.say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.")
SSshuttle.moveShuttle("supply", "supply_home", TRUE)
. = TRUE
if("loan")
if(!SSshuttle.shuttle_loan)
return
if(SSshuttle.supplyBlocked)
computer.say(blockade_warning)
return
else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
return
else if(SSshuttle.supply.getDockedId() != "supply_away")
return
else
SSshuttle.shuttle_loan.loan_shuttle()
computer.say("The supply shuttle has been loaned to CentCom.")
computer.investigate_log("[key_name(usr)] accepted a shuttle loan event.", INVESTIGATE_CARGO)
log_game("[key_name(usr)] accepted a shuttle loan event.")
. = TRUE
if("add")
var/id = text2path(params["id"])
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
if(!istype(pack))
return
if((pack.hidden && (pack.contraband && !contraband) || pack.DropPodOnly))
return
var/name = "*None Provided*"
var/rank = "*None Provided*"
var/ckey = usr.ckey
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
name = H.get_authentification_name()
rank = H.get_assignment(hand_first = TRUE)
else if(issilicon(usr))
name = usr.real_name
rank = "Silicon"
var/datum/bank_account/account
if(self_paid)
var/mob/living/carbon/human/H = usr
var/obj/item/card/id/id_card = H.get_idcard(TRUE)
if(!istype(id_card))
computer.say("No ID card detected.")
return
if(istype(id_card, /obj/item/card/id/departmental_budget))
computer.say("The [src] rejects [id_card].")
return
account = id_card.registered_account
if(!istype(account))
computer.say("Invalid bank account.")
return
var/reason = ""
if((requestonly && !self_paid) || !(card_slot?.GetID()))
reason = stripped_input("Reason:", name, "")
if(isnull(reason) || ..())
return
if(pack.goody && !self_paid)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
computer.say("ERROR: Small crates may only be purchased by private accounts.")
return
if(!self_paid && ishuman(usr) && !account)
var/obj/item/card/id/id_card = card_slot?.GetID()
account = SSeconomy.get_dep_account(id_card?.registered_account?.account_job.paycheck_department)
var/turf/T = get_turf(src)
var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account)
SO.generateRequisition(T)
if((requestonly && !self_paid) || !(card_slot?.GetID()))
SSshuttle.requestlist += SO
else
SSshuttle.shoppinglist += SO
if(self_paid)
computer.say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.")
. = TRUE
if("remove")
var/id = text2num(params["id"])
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
if(SO.id == id)
SSshuttle.shoppinglist -= SO
. = TRUE
break
if("clear")
SSshuttle.shoppinglist.Cut()
. = TRUE
if("approve")
var/id = text2num(params["id"])
for(var/datum/supply_order/SO in SSshuttle.requestlist)
if(SO.id == id)
var/obj/item/card/id/id_card = card_slot?.GetID()
if(id_card && id_card?.registered_account)
SO.paying_account = SSeconomy.get_dep_account(id_card?.registered_account?.account_job.paycheck_department)
SSshuttle.requestlist -= SO
SSshuttle.shoppinglist += SO
. = TRUE
break
if("deny")
var/id = text2num(params["id"])
for(var/datum/supply_order/SO in SSshuttle.requestlist)
if(SO.id == id)
SSshuttle.requestlist -= SO
. = TRUE
break
if("denyall")
SSshuttle.requestlist.Cut()
. = TRUE
if("toggleprivate")
self_paid = !self_paid
. = TRUE
if(.)
post_signal("supply")
/datum/computer_file/program/budgetorders/proc/post_signal(command)
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
if(!frequency)
return
var/datum/signal/status_signal = new(list("command" = command))
frequency.post_signal(src, status_signal)
@@ -15,6 +15,7 @@
requires_ntnet = 0
size = 8
tgui_id = "NtosCard"
program_icon = "id-card"
var/is_centcom = FALSE
var/minor = FALSE
@@ -94,8 +95,9 @@
return FALSE
/datum/computer_file/program/card_mod/ui_act(action, params)
if(..())
return TRUE
. = ..()
if(.)
return
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/card_slot/card_slot2
@@ -130,7 +132,7 @@
if(!authenticated)
return
var/contents = {"<h4>Access Report</h4>
<u>Prepared By:</u> [user_id_card && user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
<u>Prepared By:</u> [user_id_card?.registered_name ? user_id_card.registered_name : "Unknown"]<br>
<u>For:</u> [target_id_card.registered_name ? target_id_card.registered_name : "Unregistered"]<br>
<hr>
<u>Assignment:</u> [target_id_card.assignment]<br>
@@ -175,7 +177,7 @@
if("PRG_edit")
if(!computer || !authenticated || !target_id_card)
return
var/new_name = reject_bad_name(params["name"])
var/new_name = params["name"]
if(!new_name)
return
target_id_card.registered_name = new_name
@@ -190,7 +192,7 @@
return
if(target == "Custom")
var/custom_name = reject_bad_name(params["custom_name"])
var/custom_name = params["custom_name"]
if(custom_name)
target_id_card.assignment = custom_name
target_id_card.update_label()
@@ -320,32 +322,31 @@
/datum/computer_file/program/card_mod/ui_data(mob/user)
var/list/data = get_header_data()
data["station_name"] = station_name()
var/obj/item/computer_hardware/card_slot/card_slot2
var/obj/item/computer_hardware/printer/printer
if(computer)
card_slot2 = computer.all_components[MC_CARD2]
printer = computer.all_components[MC_PRINT]
data["station_name"] = station_name()
if(computer)
data["have_id_slot"] = !!(card_slot2)
data["have_printer"] = !!printer
data["have_printer"] = !!(printer)
else
data["have_id_slot"] = FALSE
data["have_printer"] = FALSE
data["authenticated"] = authenticated
if(!card_slot2)
return data //We're just gonna error out on the js side at this point anyway
if(computer)
var/obj/item/card/id/id_card = card_slot2.stored_card
data["has_id"] = !!id_card
data["id_name"] = id_card ? id_card.name : "-----"
if(id_card)
data["id_rank"] = id_card.assignment ? id_card.assignment : "Unassigned"
data["id_owner"] = id_card.registered_name ? id_card.registered_name : "-----"
data["access_on_card"] = id_card.access
var/obj/item/card/id/id_card = card_slot2.stored_card
data["has_id"] = !!id_card
data["id_name"] = id_card ? id_card.name : "-----"
if(id_card)
data["id_rank"] = id_card.assignment ? id_card.assignment : "Unassigned"
data["id_owner"] = id_card.registered_name ? id_card.registered_name : "-----"
data["access_on_card"] = id_card.access
return data
@@ -5,6 +5,7 @@
extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping."
size = 6
tgui_id = "NtosShipping"
program_icon = "tags"
///Account used for creating barcodes.
var/datum/bank_account/payments_acc
///The amount which the tagger will receive for the sale.
@@ -19,14 +20,15 @@
data["has_id_slot"] = !!card_slot
data["has_printer"] = !!printer
data["paperamt"] = printer ? "[printer.stored_paper] / [printer.max_paper]" : null
data["card_owner"] = card_slot && card_slot.stored_card ? id_card.registered_name : "No Card Inserted."
data["card_owner"] = card_slot?.stored_card ? id_card.registered_name : "No Card Inserted."
data["current_user"] = payments_acc ? payments_acc.account_holder : null
data["barcode_split"] = percent_cut
return data
/datum/computer_file/program/shipping/ui_act(action, list/params)
if(..())
return TRUE
. = ..()
if(.)
return
if(!computer)
return
@@ -40,7 +42,7 @@
switch(action)
if("ejectid")
if(id_card)
card_slot.try_eject(TRUE, usr)
card_slot.try_eject(usr, TRUE)
if("selectid")
if(!id_card)
return
@@ -13,6 +13,7 @@
available_on_ntnet = 0
requires_ntnet = 0
tgui_id = "NtosConfiguration"
program_icon = "cog"
var/obj/item/modular_computer/movable = null
@@ -34,11 +35,11 @@
data["disk_used"] = hard_drive.used_capacity
data["power_usage"] = movable.last_power_usage
data["battery_exists"] = battery_module ? 1 : 0
if(battery_module && battery_module.battery)
if(battery_module?.battery)
data["battery_rating"] = battery_module.battery.maxcharge
data["battery_percent"] = round(battery_module.battery.percent())
if(battery_module && battery_module.battery)
if(battery_module?.battery)
data["battery"] = list("max" = battery_module.battery.maxcharge, "charge" = round(battery_module.battery.charge))
var/list/all_entries[0]
@@ -57,7 +58,8 @@
/datum/computer_file/program/computerconfig/ui_act(action,params)
if(..())
. = ..()
if(.)
return
switch(action)
if("PC_toggle_component")
@@ -7,6 +7,7 @@
requires_ntnet = TRUE
size = 4
tgui_id = "NtosCrewManifest"
program_icon = "clipboard-list"
/datum/computer_file/program/crew_manifest/ui_static_data(mob/user)
var/list/data = list()
@@ -27,7 +28,8 @@
return data
/datum/computer_file/program/crew_manifest/ui_act(action, params, datum/tgui/ui)
if(..())
. = ..()
if(.)
return
var/obj/item/computer_hardware/printer/printer
@@ -8,12 +8,14 @@
available_on_ntnet = FALSE
undeletable = TRUE
tgui_id = "NtosFileManager"
program_icon = "folder"
var/open_file
var/error
/datum/computer_file/program/filemanager/ui_act(action, params)
if(..())
. = ..()
if(.)
return
var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
@@ -65,6 +67,13 @@
var/datum/computer_file/C = F.clone(FALSE)
HDD.store_file(C)
return TRUE
if("PRG_togglesilence")
if(!HDD)
return
var/datum/computer_file/program/binary = HDD.find_file_by_name(params["name"])
if(!binary || !istype(binary))
return
binary.alert_silenced = !binary.alert_silenced
/datum/computer_file/program/filemanager/ui_data(mob/user)
var/list/data = get_header_data()
@@ -78,11 +87,19 @@
else
var/list/files = list()
for(var/datum/computer_file/F in HDD.stored_files)
var/noisy = FALSE
var/silenced = FALSE
var/datum/computer_file/program/binary = F
if(istype(binary))
noisy = binary.alert_able
silenced = binary.alert_silenced
files += list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
"undeletable" = F.undeletable,
"alert_able" = noisy,
"alert_silenced" = silenced
))
data["files"] = files
if(RHDD)
@@ -7,6 +7,7 @@
requires_ntnet = TRUE
size = 4
tgui_id = "NtosJobManager"
program_icon = "address-book"
var/change_position_cooldown = 30
//Jobs you cannot open new positions for
@@ -49,17 +50,14 @@
return FALSE
/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui)
if(..())
. = ..()
if(.)
return
var/authed = FALSE
var/mob/user = usr
var/obj/item/card/id/user_id = user.get_idcard()
if(user_id)
if(ACCESS_CHANGE_IDS in user_id.access)
authed = TRUE
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/card/id/user_id = card_slot?.stored_card
if(!authed)
if(!user_id || !(ACCESS_CHANGE_IDS in user_id.access))
return
switch(action)
@@ -107,10 +105,10 @@
var/list/data = get_header_data()
var/authed = FALSE
var/obj/item/card/id/user_id = user.get_idcard(FALSE)
if(user_id)
if(ACCESS_CHANGE_IDS in user_id.access)
authed = TRUE
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/card/id/user_id = card_slot?.stored_card
if(user_id && (ACCESS_CHANGE_IDS in user_id.access))
authed = TRUE
data["authed"] = authed
@@ -11,10 +11,11 @@
available_on_ntnet = FALSE
ui_header = "downloader_finished.gif"
tgui_id = "NtosNetDownloader"
program_icon = "download"
var/datum/computer_file/program/downloaded_file = null
var/hacked_download = 0
var/download_completion = 0 //GQ of downloaded data.
var/hacked_download = FALSE
var/download_completion = FALSE //GQ of downloaded data.
var/download_netspeed = 0
var/downloaderror = ""
var/obj/item/modular_computer/my_computer = null
@@ -36,33 +37,33 @@
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
if(downloaded_file)
return 0
return FALSE
var/datum/computer_file/program/PRG = SSnetworks.station_network.find_ntnet_file_by_name(filename)
if(!PRG || !istype(PRG))
return 0
return FALSE
// Attempting to download antag only program, but without having emagged/syndicate computer. No.
if(PRG.available_on_syndinet && !emagged)
return 0
return FALSE
var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
if(!computer || !hard_drive || !hard_drive.can_store_file(PRG))
return 0
return FALSE
ui_header = "downloader_running.gif"
if(PRG in main_repo)
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
hacked_download = 0
hacked_download = FALSE
else if(PRG in antag_repo)
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
hacked_download = 1
hacked_download = TRUE
else
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.")
hacked_download = 0
hacked_download = FALSE
downloaded_file = PRG.clone()
@@ -71,7 +72,7 @@
return
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
downloaded_file = null
download_completion = 0
download_completion = FALSE
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
@@ -83,7 +84,7 @@
// 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."
downloaded_file = null
download_completion = 0
download_completion = FALSE
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/process_tick()
@@ -104,21 +105,22 @@
download_completion += download_netspeed
/datum/computer_file/program/ntnetdownload/ui_act(action, params)
if(..())
return 1
. = ..()
if(.)
return
switch(action)
if("PRG_downloadfile")
if(!downloaded_file)
begin_file_download(params["filename"])
return 1
return TRUE
if("PRG_reseterror")
if(downloaderror)
download_completion = 0
download_netspeed = 0
download_completion = FALSE
download_netspeed = FALSE
downloaded_file = null
downloaderror = ""
return 1
return 0
return TRUE
return FALSE
/datum/computer_file/program/ntnetdownload/ui_data(mob/user)
my_computer = computer
@@ -148,7 +150,7 @@
for(var/A in main_repo)
var/datum/computer_file/program/P = A
// Only those programs our user can run will show in the list
if(!P.can_run(user,transfer = 1, access = access) || hard_drive.find_file_by_name(P.filename))
if(hard_drive.find_file_by_name(P.filename))
continue
all_entries.Add(list(list(
"filename" = P.filename,
@@ -156,6 +158,7 @@
"fileinfo" = P.extended_desc,
"compatibility" = check_compatibility(P),
"size" = P.size,
"access" = P.can_run(user,transfer = 1, access = access)
)))
data["hackedavailable"] = FALSE
if(emagged) // If we are running on emagged computer we have access to some "bonus" software
@@ -169,7 +172,9 @@
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"compatibility" = check_compatibility(P),
"size" = P.size,
"access" = TRUE,
)))
data["hacked_programs"] = hacked_programs
@@ -180,13 +185,13 @@
/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P)
var/hardflag = computer.hardware_flag
if(P && P.is_supported_by_hardware(hardflag,0))
if(P?.is_supported_by_hardware(hardflag,0))
return "Compatible"
return "Incompatible!"
/datum/computer_file/program/ntnetdownload/kill_program(forced)
abort_file_download()
return ..(forced)
return ..()
////////////////////////
//Syndicate Downloader//
@@ -199,7 +204,7 @@
filedesc = "Software Download Tool"
program_icon_state = "generic"
extended_desc = "This program allows downloads of software from shared Syndicate repositories"
requires_ntnet = 0
requires_ntnet = FALSE
ui_header = "downloader_finished.gif"
tgui_id = "NtosNetDownloader"
emagged = TRUE
@@ -1,6 +1,6 @@
/datum/computer_file/program/ntnetmonitor
filename = "wirecarp"
filedesc = "WireCarp" //wireshark.
filedesc = "WireCarp"
program_icon_state = "comm_monitor"
extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes"
size = 12
@@ -8,9 +8,11 @@
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
available_on_ntnet = TRUE
tgui_id = "NtosNetMonitor"
program_icon = "network-wired"
/datum/computer_file/program/ntnetmonitor/ui_act(action, params)
if(..())
. = ..()
if(.)
return
switch(action)
if("resetIDS")
@@ -9,6 +9,7 @@
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
tgui_id = "NtosNetChat"
program_icon = "comment-alt"
var/last_message // Used to generate the toolbar icon
var/username
var/active_channel
@@ -20,7 +21,8 @@
username = "DefaultUser[rand(100, 999)]"
/datum/computer_file/program/chatclient/ui_act(action, params)
if(..())
. = ..()
if(.)
return
var/datum/ntnet_conversation/channel = SSnetworks.station_network.get_chat_channel_by_id(active_channel)
@@ -182,7 +184,7 @@
var/list/all_channels = list()
for(var/C in SSnetworks.station_network.chat_channels)
var/datum/ntnet_conversation/conv = C
if(conv && conv.title)
if(conv?.title)
all_channels.Add(list(list(
"chan" = conv.title,
"id" = conv.id
@@ -11,6 +11,7 @@
requires_ntnet = 0
size = 9
tgui_id = "NtosPowerMonitor"
program_icon = "plug"
var/has_alert = 0
var/obj/structure/cable/attached_wire
@@ -49,7 +50,7 @@
local_apc = null
/datum/computer_file/program/power_monitor/proc/get_powernet() //keep in sync with /obj/machinery/computer/monitor's version
if(attached_wire || (local_apc && local_apc.terminal))
if(attached_wire || (local_apc?.terminal))
return attached_wire ? attached_wire.powernet : local_apc.terminal.powernet
return FALSE
@@ -63,7 +63,8 @@
return data
/datum/computer_file/program/radar/ui_act(action, params)
if(..())
. = ..()
if(.)
return
switch(action)
@@ -73,13 +74,13 @@
scan()
/**
*Updates tracking information of the selected target.
*
*The track() proc updates the entire set of information about the location
*of the target, including whether the Ntos window should use a pinpointer
*crosshair over the up/down arrows, or none in favor of a rotating arrow
*for far away targets. This information is returned in the form of a list.
*
*Updates tracking information of the selected target.
*
*The track() proc updates the entire set of information about the location
*of the target, including whether the Ntos window should use a pinpointer
*crosshair over the up/down arrows, or none in favor of a rotating arrow
*for far away targets. This information is returned in the form of a list.
*
*/
/datum/computer_file/program/radar/proc/track()
var/atom/movable/signal = find_atom()
@@ -115,13 +116,13 @@
return trackinfo
/**
*
*Checks the trackability of the selected target.
*
*If the target is on the computer's Z level, or both are on station Z
*levels, and the target isn't untrackable, return TRUE.
*Arguments:
**arg1 is the atom being evaluated.
*
*Checks the trackability of the selected target.
*
*If the target is on the computer's Z level, or both are on station Z
*levels, and the target isn't untrackable, return TRUE.
*Arguments:
**arg1 is the atom being evaluated.
*/
/datum/computer_file/program/radar/proc/trackable(atom/movable/signal)
if(!signal || !computer)
@@ -133,30 +134,30 @@
return (there.z == here.z) || (is_station_level(here.z) && is_station_level(there.z))
/**
*
*Runs a scan of all the trackable atoms.
*
*Checks each entry in the GLOB of the specific trackable atoms against
*the track() proc, and fill the objects list with lists containing the
*atoms' names and REFs. The objects list is handed to the tgui screen
*for displaying to, and being selected by, the user. A two second
*sleep is used to delay the scan, both for thematical reasons as well
*as to limit the load players may place on the server using these
*somewhat costly loops.
*
*Runs a scan of all the trackable atoms.
*
*Checks each entry in the GLOB of the specific trackable atoms against
*the track() proc, and fill the objects list with lists containing the
*atoms' names and REFs. The objects list is handed to the tgui screen
*for displaying to, and being selected by, the user. A two second
*sleep is used to delay the scan, both for thematical reasons as well
*as to limit the load players may place on the server using these
*somewhat costly loops.
*/
/datum/computer_file/program/radar/proc/scan()
return
/**
*
*Finds the atom in the appropriate list that the `selected` var indicates
*
*The `selected` var holds a REF, which is a string. A mob REF may be
*something like "mob_209". In order to find the actual atom, we need
*to search the appropriate list for the REF string. This is dependant
*on the program (Lifeline uses GLOB.human_list, while Fission360 uses
*GLOB.poi_list), but the result will be the same; evaluate the string and
*return an atom reference.
*
*Finds the atom in the appropriate list that the `selected` var indicates
*
*The `selected` var holds a REF, which is a string. A mob REF may be
*something like "mob_209". In order to find the actual atom, we need
*to search the appropriate list for the REF string. This is dependant
*on the program (Lifeline uses GLOB.human_list, while Fission360 uses
*GLOB.poi_list), but the result will be the same; evaluate the string and
*return an atom reference.
*/
/datum/computer_file/program/radar/proc/find_atom()
return
@@ -212,6 +213,7 @@
requires_ntnet = TRUE
transfer_access = ACCESS_MEDICAL
available_on_ntnet = TRUE
program_icon = "heartbeat"
/datum/computer_file/program/radar/lifeline/find_atom()
return locate(selected) in GLOB.human_list
@@ -228,7 +230,7 @@
var/crewmember_name = "Unknown"
if(humanoid.wear_id)
var/obj/item/card/id/ID = humanoid.wear_id.GetID()
if(ID && ID.registered_name)
if(ID?.registered_name)
crewmember_name = ID.registered_name
var/list/crewinfo = list(
ref = REF(humanoid),
@@ -262,6 +264,7 @@
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosRadarSyndicate"
program_icon = "bomb"
arrowstyle = "ntosradarpointerS.png"
pointercolor = "red"
@@ -1,13 +1,14 @@
/datum/computer_file/program/robocontrol
filename = "botkeeper"
filedesc = "Botkeeper"
filedesc = "BotKeeper"
program_icon_state = "robot"
extended_desc = "A remote controller used for giving basic commands to non-sentient robots."
transfer_access = ACCESS_ROBOTICS
transfer_access = null
requires_ntnet = TRUE
size = 12
tgui_id = "NtosRoboControl"
program_icon = "robot"
///Number of simple robots on-station.
var/botcount = 0
///Used to find the location of the user for the purposes of summoning robots.
@@ -36,7 +37,13 @@
for(var/B in GLOB.bots_list)
var/mob/living/simple_animal/bot/Bot = B
if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
continue //Also, the PDA must have access to the bot type.
continue
else if(computer) //Also, the inserted ID must have access to the bot type
var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null
if(!id_card && !Bot.bot_core.allowed(current_user))
continue
else if(id_card && !Bot.bot_core.check_access(id_card))
continue
var/list/newbot = list("name" = Bot.name, "mode" = Bot.get_mode_ui(), "model" = Bot.model, "locat" = get_area(Bot), "bot_ref" = REF(Bot), "mule_check" = FALSE)
if(Bot.bot_type == MULE_BOT)
var/mob/living/simple_animal/bot/mulebot/MULE = Bot
@@ -53,8 +60,9 @@
return data
/datum/computer_file/program/robocontrol/ui_act(action, list/params)
if(..())
return TRUE
. = ..()
if(.)
return
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/card/id/id_card
if(computer)
@@ -0,0 +1,147 @@
/datum/computer_file/program/robotact
filename = "robotact"
filedesc = "RoboTact"
extended_desc = "A built-in app for cyborg self-management and diagnostics."
ui_header = "robotact.gif" //DEBUG -- new icon before PR
program_icon_state = "command"
requires_ntnet = FALSE
transfer_access = null
available_on_ntnet = FALSE
unsendable = TRUE
undeletable = TRUE
usage_flags = PROGRAM_TABLET
size = 5
tgui_id = "NtosRobotact"
program_icon = "terminal"
///A typed reference to the computer, specifying the borg tablet type
var/obj/item/modular_computer/tablet/integrated/tablet
/datum/computer_file/program/robotact/Destroy()
tablet = null
return ..()
/datum/computer_file/program/robotact/run_program(mob/living/user)
if(!istype(computer, /obj/item/modular_computer/tablet/integrated))
to_chat(user, "<span class='warning'>A warning flashes across \the [computer]: Device Incompatible.</span>")
return FALSE
. = ..()
if(.)
tablet = computer
if(tablet.device_theme == "syndicate")
program_icon_state = "command-syndicate"
return TRUE
return FALSE
/datum/computer_file/program/robotact/ui_data(mob/user)
var/list/data = get_header_data()
if(!iscyborg(user))
return data
var/mob/living/silicon/robot/borgo = tablet.borgo
data["name"] = borgo.name
data["designation"] = borgo.designation //Borgo module type
data["masterAI"] = borgo.connected_ai //Master AI
var/charge = 0
var/maxcharge = 1
if(borgo.cell)
charge = borgo.cell.charge
maxcharge = borgo.cell.maxcharge
data["charge"] = charge //Current cell charge
data["maxcharge"] = maxcharge //Cell max charge
data["integrity"] = ((borgo.health + 100) / 2) //Borgo health, as percentage
data["lampIntensity"] = borgo.lamp_intensity //Borgo lamp power setting
data["sensors"] = "[borgo.sensors_on?"ACTIVE":"DISABLED"]"
data["printerPictures"] = borgo.connected_ai? borgo.connected_ai.aicamera.stored.len : borgo.aicamera.stored.len //Number of pictures taken, synced to AI if available
data["printerToner"] = borgo.toner //amount of toner
data["printerTonerMax"] = borgo.tonermax //It's a variable, might as well use it
data["thrustersInstalled"] = borgo.ionpulse //If we have a thruster uprade
data["thrustersStatus"] = "[borgo.ionpulse_on?"ACTIVE":"DISABLED"]" //Feedback for thruster status
//DEBUG -- Cover, TRUE for locked
data["cover"] = "[borgo.locked? "LOCKED":"UNLOCKED"]"
//Ability to move. FAULT if lockdown wire is cut, DISABLED if borg locked, ENABLED otherwise
data["locomotion"] = "[borgo.wires.is_cut(WIRE_LOCKDOWN)?"FAULT":"[borgo.lockcharge?"DISABLED":"ENABLED"]"]"
//Module wire. FAULT if cut, NOMINAL otherwise
data["wireModule"] = "[borgo.wires.is_cut(WIRE_RESET_MODULE)?"FAULT":"NOMINAL"]"
//DEBUG -- Camera(net) wire. FAULT if cut (or no cameranet camera), DISABLED if pulse-disabled, NOMINAL otherwise
data["wireCamera"] = "[!borgo.builtInCamera || borgo.wires.is_cut(WIRE_CAMERA)?"FAULT":"[borgo.builtInCamera.can_use()?"NOMINAL":"DISABLED"]"]"
//AI wire. FAULT if wire is cut, CONNECTED if connected to AI, READY otherwise
data["wireAI"] = "[borgo.wires.is_cut(WIRE_AI)?"FAULT":"[borgo.connected_ai?"CONNECTED":"READY"]"]"
//Law sync wire. FAULT if cut, NOMINAL otherwise
data["wireLaw"] = "[borgo.wires.is_cut(WIRE_LAWSYNC)?"FAULT":"NOMINAL"]"
return data
/datum/computer_file/program/robotact/ui_static_data(mob/user)
var/list/data = list()
if(!iscyborg(user))
return data
var/mob/living/silicon/robot/borgo = user
data["Laws"] = borgo.laws.get_law_list(TRUE, TRUE, FALSE)
data["borgLog"] = tablet.borglog
data["borgUpgrades"] = borgo.upgrades
return data
/datum/computer_file/program/robotact/ui_act(action, params)
. = ..()
if(.)
return
var/mob/living/silicon/robot/borgo = tablet.borgo
switch(action)
if("coverunlock")
if(borgo.locked)
borgo.locked = FALSE
borgo.update_icons()
if(borgo.emagged)
borgo.logevent("ChÃ¥vÃis cover lock has been [borgo.locked ? "engaged" : "released"]") //"The cover interface glitches out for a split second"
else
borgo.logevent("Chassis cover lock has been [borgo.locked ? "engaged" : "released"]")
if("lawchannel")
borgo.set_autosay()
if("lawstate")
borgo.checklaws()
if("alertPower")
if(borgo.stat == CONSCIOUS)
if(!borgo.cell || !borgo.cell.charge)
borgo.visible_message("<span class='notice'>The power warning light on <span class='name'>[borgo]</span> flashes urgently.</span>", \
"You announce you are operating in low power mode.")
playsound(borgo, 'sound/machines/buzz-two.ogg', 50, FALSE)
if("toggleSensors")
borgo.toggle_sensors()
if("viewImage")
if(borgo.connected_ai)
borgo.connected_ai.aicamera?.viewpictures(usr)
else
borgo.aicamera?.viewpictures(usr)
if("printImage")
var/obj/item/camera/siliconcam/robot_camera/borgcam = borgo.aicamera
borgcam?.borgprint(usr)
if("toggleThrusters")
borgo.toggle_ionpulse()
if("lampIntensity")
borgo.lamp_intensity = params["ref"]
borgo.toggle_headlamp(FALSE, TRUE)
/**
* Forces a full update of the UI, if currently open.
*
* Forces an update that includes refreshing ui_static_data. Called by
* law changes and borg log additions.
*/
/datum/computer_file/program/robotact/proc/force_full_update()
if(tablet)
var/datum/tgui/active_ui = SStgui.get_open_ui(tablet.borgo, src)
if(active_ui)
active_ui.send_full_update()
@@ -0,0 +1,195 @@
#define DEFAULT_MAP_SIZE 15
/datum/computer_file/program/secureye
filename = "secureye"
filedesc = "SecurEye"
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows access to standard security camera networks."
requires_ntnet = TRUE
transfer_access = ACCESS_SECURITY
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
size = 5
tgui_id = "NtosSecurEye"
program_icon = "eye"
var/list/network = list("ss13")
var/obj/machinery/camera/active_camera
/// The turf where the camera was last updated.
var/turf/last_camera_turf
var/list/concurrent_users = list()
// Stuff needed to render the map
var/map_name
var/atom/movable/screen/map_view/cam_screen
/// All the plane masters that need to be applied.
var/list/cam_plane_masters
var/atom/movable/screen/background/cam_background
/datum/computer_file/program/secureye/New()
. = ..()
// Map name has to start and end with an A-Z character,
// and definitely NOT with a square bracket or even a number.
map_name = "camera_console_[REF(src)]_map"
// Convert networks to lowercase
for(var/i in network)
network -= i
network += lowertext(i)
// Initialize map objects
cam_screen = new
cam_screen.name = "screen"
cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = FALSE
cam_screen.screen_loc = "[map_name]:1,1"
cam_plane_masters = list()
for(var/plane in subtypesof(/atom/movable/screen/plane_master))
var/atom/movable/screen/instance = new plane()
instance.assigned_map = map_name
instance.del_on_map_removal = FALSE
instance.screen_loc = "[map_name]:CENTER"
cam_plane_masters += instance
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
/datum/computer_file/program/secureye/Destroy()
qdel(cam_screen)
QDEL_LIST(cam_plane_masters)
qdel(cam_background)
return ..()
/datum/computer_file/program/secureye/ui_interact(mob/user, datum/tgui/ui)
// Update UI
ui = SStgui.try_update_ui(user, src, ui)
// Update the camera, showing static if necessary and updating data if the location has moved.
update_active_camera_screen()
if(!ui)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Ghosts shouldn't count towards concurrent users, which produces
// an audible terminal_on click.
if(is_living)
concurrent_users += user_ref
// Register map objects
user.client.register_map_obj(cam_screen)
for(var/plane in cam_plane_masters)
user.client.register_map_obj(plane)
user.client.register_map_obj(cam_background)
return ..()
/datum/computer_file/program/secureye/ui_data()
var/list/data = get_header_data()
data["network"] = network
data["activeCamera"] = null
if(active_camera)
data["activeCamera"] = list(
name = active_camera.c_tag,
status = active_camera.status,
)
return data
/datum/computer_file/program/secureye/ui_static_data()
var/list/data = list()
data["mapRef"] = map_name
var/list/cameras = get_available_cameras()
data["cameras"] = list()
for(var/i in cameras)
var/obj/machinery/camera/C = cameras[i]
data["cameras"] += list(list(
name = C.c_tag,
))
return data
/datum/computer_file/program/secureye/ui_act(action, params)
. = ..()
if(.)
return
if(action == "switch_camera")
var/c_tag = params["name"]
var/list/cameras = get_available_cameras()
var/obj/machinery/camera/selected_camera = cameras[c_tag]
active_camera = selected_camera
playsound(src, get_sfx("terminal_type"), 25, FALSE)
if(!selected_camera)
return TRUE
update_active_camera_screen()
return TRUE
/datum/computer_file/program/secureye/ui_close(mob/user)
. = ..()
var/user_ref = REF(user)
var/is_living = isliving(user)
// Living creature or not, we remove you anyway.
concurrent_users -= user_ref
// Unregister map objects
user.client.clear_map(map_name)
// Turn off the console
if(length(concurrent_users) == 0 && is_living)
active_camera = null
playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
/datum/computer_file/program/secureye/proc/update_active_camera_screen()
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
return
var/list/visible_turfs = list()
// Is this camera located in or attached to a living thing? If so, assume the camera's loc is the living thing.
var/cam_location = isliving(active_camera.loc) ? active_camera.loc : active_camera
// If we're not forcing an update for some reason and the cameras are in the same location,
// we don't need to update anything.
// Most security cameras will end here as they're not moving.
var/newturf = get_turf(cam_location)
if(last_camera_turf == newturf)
return
// Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
last_camera_turf = get_turf(cam_location)
var/list/visible_things = active_camera.isXRay() ? range(active_camera.view_range, cam_location) : view(active_camera.view_range, cam_location)
for(var/turf/visible_turf in visible_things)
visible_turfs += visible_turf
var/list/bbox = get_bbox_of_atoms(visible_turfs)
var/size_x = bbox[3] - bbox[1] + 1
var/size_y = bbox[4] - bbox[2] + 1
cam_screen.vis_contents = visible_turfs
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, size_x, size_y)
/datum/computer_file/program/secureye/proc/show_camera_static()
cam_screen.vis_contents.Cut()
cam_background.icon_state = "scanline2"
cam_background.fill_rect(1, 1, DEFAULT_MAP_SIZE, DEFAULT_MAP_SIZE)
// Returns the list of cameras accessible from this computer
/datum/computer_file/program/secureye/proc/get_available_cameras()
var/list/L = list()
for (var/obj/machinery/camera/cam in GLOB.cameranet.cameras)
if(!is_station_level(cam.z))//Only show station cameras.
continue
L.Add(cam)
var/list/camlist = list()
for(var/obj/machinery/camera/cam in L)
if(!cam.network)
stack_trace("Camera in a cameranet has no camera network")
continue
if(!(islist(cam.network)))
stack_trace("Camera in a cameranet has a non-list camera network")
continue
var/list/tempnetwork = cam.network & network
if(tempnetwork.len)
camlist["[cam.c_tag]"] = cam
return camlist
@@ -8,10 +8,16 @@
transfer_access = ACCESS_CONSTRUCTION
size = 5
tgui_id = "NtosSupermatterMonitor"
program_icon = "radiation"
alert_able = TRUE
var/last_status = SUPERMATTER_INACTIVE
var/list/supermatters
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
/datum/computer_file/program/supermatter_monitor/Destroy()
clear_signals()
active = null
return ..()
/datum/computer_file/program/supermatter_monitor/process_tick()
..()
@@ -25,10 +31,11 @@
/datum/computer_file/program/supermatter_monitor/run_program(mob/living/user)
. = ..(user)
if(!(active in GLOB.machines))
active = null
refresh()
/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
active = null
supermatters = null
..()
@@ -52,6 +59,58 @@
for(var/obj/machinery/power/supermatter_crystal/S in supermatters)
. = max(., S.get_status())
/**
* Sets up the signal listener for Supermatter delaminations.
*
* Unregisters any old listners for SM delams, and then registers one for the SM refered
* to in the `active` variable. This proc is also used with no active SM to simply clear
* the signal and exit.
*/
/datum/computer_file/program/supermatter_monitor/proc/set_signals()
// if(active)
// RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM, .proc/send_alert, override = TRUE)
// RegisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM, .proc/send_start_alert, override = TRUE)
/**
* Removes the signal listener for Supermatter delaminations from the selected supermatter.
*
* Pretty much does what it says.
*/
/datum/computer_file/program/supermatter_monitor/proc/clear_signals()
// if(active)
// UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM)
// UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM)
/**
* Sends an SM delam alert to the computer.
*
* Triggered by a signal from the selected supermatter, this proc sends a notification
* to the computer if the program is either closed or minimized. We do not send these
* notifications to the comptuer if we're the active program, because engineers fixing
* the supermatter probably don't need constant beeping to distract them.
*/
/datum/computer_file/program/supermatter_monitor/proc/send_alert()
if(!computer.get_ntnet_status())
return
if(computer.active_program != src)
computer.alert_call(src, "Crystal delamination in progress!")
alert_pending = TRUE
/**
* Sends an SM delam start alert to the computer.
*
* Triggered by a signal from the selected supermatter at the start of a delamination,
* this proc sends a notification to the computer if this program is the active one.
* We do this so that people carrying a tablet with NT CIMS open but with the NTOS window
* closed will still get one audio alert. This is not sent to computers with the program
* minimized or closed to avoid double-notifications.
*/
/datum/computer_file/program/supermatter_monitor/proc/send_start_alert()
if(!computer.get_ntnet_status())
return
if(computer.active_program == src)
computer.alert_call(src, "Crystal delamination in progress!")
/datum/computer_file/program/supermatter_monitor/ui_data()
var/list/data = get_header_data()
@@ -107,11 +166,13 @@
return data
/datum/computer_file/program/supermatter_monitor/ui_act(action, params)
if(..())
return TRUE
. = ..()
if(.)
return
switch(action)
if("PRG_clear")
clear_signals()
active = null
return TRUE
if("PRG_refresh")
@@ -122,4 +183,5 @@
for(var/obj/machinery/power/supermatter_crystal/S in supermatters)
if(S.uid == newuid)
active = S
set_signals()
return TRUE