This commit is contained in:
LetterN
2021-10-28 17:34:52 +08:00
parent 49940c373e
commit f7b898a2a9
346 changed files with 13714 additions and 8493 deletions

View File

@@ -5,7 +5,14 @@
var/title = "Untitled Conversation"
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
var/list/messages = list()
var/list/clients = list()
///chat clients who are active or minimized
var/list/active_clients = list()
///chat clients who have exited out of the program.
var/list/offline_clients = list()
///clients muted by operator
var/list/muted_clients = list()
//if a channel is strong, it cannot be renamed or deleted.
var/strong = FALSE
var/password
var/static/ntnrc_uid = 0
@@ -22,6 +29,8 @@
/datum/ntnet_conversation/Destroy()
if(SSnetworks.station_network)
SSnetworks.station_network.chat_channels.Remove(src)
for(var/datum/computer_file/program/chatclient/chatterbox in (active_clients | offline_clients | muted_clients))
purge_client(chatterbox)
return ..()
/datum/ntnet_conversation/proc/add_message(message, username)
@@ -38,39 +47,70 @@
return
messages = messages.Copy(messages.len-50 ,0)
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C)
if(!istype(C))
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/new_user, silent = FALSE)
if(!istype(new_user))
return
clients.Add(C)
add_status_message("[C.username] has joined the channel.")
new_user.conversations |= src
active_clients.Add(new_user)
if(!silent)
add_status_message("[new_user.username] has joined the channel.")
// No operator, so we assume the channel was empty. Assign this user as operator.
if(!operator)
changeop(C)
changeop(new_user)
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C)
if(!istype(C) || !(C in clients))
//Clear all of our references to a client, used for client deletion
/datum/ntnet_conversation/proc/purge_client(datum/computer_file/program/chatclient/forget)
remove_client(forget)
muted_clients -= forget
offline_clients -= forget
forget.conversations -= src
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/leaving)
if(!istype(leaving))
return
clients.Remove(C)
add_status_message("[C.username] has left the channel.")
if(leaving in active_clients)
active_clients.Remove(leaving)
add_status_message("[leaving.username] has left the channel.")
// Channel operator left, pick new operator
if(C == operator)
if(leaving == operator)
operator = null
if(clients.len)
var/datum/computer_file/program/chatclient/newop = pick(clients)
if(active_clients.len)
var/datum/computer_file/program/chatclient/newop = pick(active_clients)
changeop(newop)
/datum/ntnet_conversation/proc/go_offline(datum/computer_file/program/chatclient/offline)
if(!istype(offline) || !(offline in active_clients))
return
active_clients.Remove(offline)
offline_clients.Add(offline)
/datum/ntnet_conversation/proc/mute_user(datum/computer_file/program/chatclient/op, datum/computer_file/program/chatclient/muted)
if(operator != op) //sanity even if the person shouldn't be able to see the mute button
return
if(muted in muted_clients)
muted_clients.Remove(muted)
muted.computer.alert_call(muted, "You have been unmuted from [title]!", 'sound/machines/ping.ogg')
else
muted_clients.Add(muted)
muted.computer.alert_call(muted, "You have been muted from [title]!")
/datum/ntnet_conversation/proc/ping_user(datum/computer_file/program/chatclient/pinger, datum/computer_file/program/chatclient/pinged)
if(pinger in muted_clients) //oh my god fuck off
return
add_status_message("[pinger.username] pinged [pinged.username].")
pinged.computer.alert_call(pinged, "You have been pinged in [title] by [pinger.username]!", 'sound/machines/ping.ogg')
/datum/ntnet_conversation/proc/changeop(datum/computer_file/program/chatclient/newop)
if(istype(newop))
operator = newop
add_status_message("Channel operator status transferred to [newop.username].")
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/client)
if(operator != client)
return FALSE // Not Authorised
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/renamer)
if(operator != renamer || strong)
return FALSE // Not Authorised or channel cannot be editted
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
add_status_message("[renamer.username] has changed channel title from [title] to [newtitle]")
title = newtitle
#undef MAX_CHANNELS

View File

@@ -39,7 +39,7 @@
. += "It has a slot installed for an intelliCard which contains: [ai_slot.stored_card.name]"
else
. += "It has a slot installed for an intelliCard, which appears to be occupied."
. += "<span class='info'>Alt-click to eject the intelliCard.</span>"
. += span_info("Alt-click to eject the intelliCard.")
else
. += "It has a slot installed for an intelliCard."
@@ -55,7 +55,7 @@
. += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed[multiple_cards ? " which contain [first_ID] and [second_ID]" : ", one of which contains [first_ID ? first_ID : second_ID]"]."
else
. += "It has [multiple_slots ? "two slots" : "a slot"] for identification cards installed, [multiple_cards ? "both of which appear" : "and one of them appears"] to be occupied."
. += "<span class='info'>Alt-click [src] to eject the identification card[multiple_cards ? "s":""].</span>"
. += span_info("Alt-click [src] to eject the identification card[multiple_cards ? "s":""].")
else
. += "It has [multiple_slots ? "two slots" : "a slot"] installed for identification cards."
@@ -63,4 +63,4 @@
if(printer_slot)
. += "It has a printer installed."
if(user_is_adjacent)
. += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].</span>"
. += "The printer's paper levels are at: [printer_slot.stored_paper]/[printer_slot.max_paper].</span>]"

View File

@@ -3,19 +3,19 @@
return FALSE
if(H.w_class > max_hardware_size)
to_chat(user, "<span class='warning'>This component is too large for \the [src]!</span>")
to_chat(user, span_warning("This component is too large for \the [src]!"))
return FALSE
if(H.expansion_hw)
if(LAZYLEN(expansion_bays) >= max_bays)
to_chat(user, "<span class='warning'>All of the computer's expansion bays are filled.</span>")
to_chat(user, span_warning("All of the computer's expansion bays are filled."))
return FALSE
if(LAZYACCESS(expansion_bays, H.device_type))
to_chat(user, "<span class='warning'>The computer immediately ejects /the [H] and flashes an error: \"Hardware Address Conflict\".</span>")
to_chat(user, span_warning("The computer immediately ejects /the [H] and flashes an error: \"Hardware Address Conflict\"."))
return FALSE
if(all_components[H.device_type])
to_chat(user, "<span class='warning'>This computer's hardware slot is already occupied by \the [all_components[H.device_type]].</span>")
to_chat(user, span_warning("This computer's hardware slot is already occupied by \the [all_components[H.device_type]]."))
return FALSE
return TRUE
@@ -32,7 +32,7 @@
LAZYSET(expansion_bays, H.device_type, H)
all_components[H.device_type] = H
to_chat(user, "<span class='notice'>You install \the [H] into \the [src].</span>")
to_chat(user, span_notice("You install \the [H] into \the [src]."))
H.holder = src
H.forceMove(src)
H.on_install(src, user)
@@ -47,14 +47,14 @@
LAZYREMOVE(expansion_bays, H.device_type)
all_components.Remove(H.device_type)
to_chat(user, "<span class='notice'>You remove \the [H] from \the [src].</span>")
to_chat(user, span_notice("You remove \the [H] from \the [src]."))
H.forceMove(get_turf(src))
H.holder = null
H.on_remove(src, user)
if(enabled && !use_power())
shutdown_computer()
update_icon()
update_appearance()
return TRUE

View File

@@ -18,7 +18,7 @@
/obj/item/modular_computer/proc/break_apart()
if(!(flags_1 & NODECONSTRUCT_1))
physical.visible_message("<span class='notice'>\The [src] breaks apart!</span>")
physical.visible_message(span_notice("\The [src] breaks apart!"))
var/turf/newloc = get_turf(src)
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
for(var/C in all_components)

View File

@@ -16,7 +16,7 @@
if(cell.use(amount * GLOB.CELLRATE))
return TRUE
else // Discharge the cell anyway.
cell.use(min(amount*GLOB.CELLRATE, cell.charge))
cell.use(min(amount * GLOB.CELLRATE, cell.charge))
return FALSE
return FALSE

View File

@@ -13,6 +13,10 @@
ui.close()
return
// if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS))
// to_chat(user, span_warning("Your fingers are too big to use this right now!"))
// return
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
if(!screen_on && !issilicon(user))
if(ui)
@@ -30,7 +34,7 @@
// This screen simply lists available programs and user may select them.
var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
to_chat(user, "<span class='danger'>\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning.</span>")
to_chat(user, span_danger("\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning."))
return // No HDD, No HDD files list or no stored files. Something is very broken.
ui = SStgui.try_update_ui(user, src, ui)
@@ -111,7 +115,7 @@
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
active_program = null
update_icon()
update_appearance()
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
if("eject_pen")
@@ -132,7 +136,7 @@
return
P.kill_program(forced = TRUE)
to_chat(user, "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>")
to_chat(user, span_notice("Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed."))
if("PC_runprogram")
var/prog = params["name"]
@@ -142,7 +146,7 @@
P = hard_drive.find_file_by_name(prog)
if(!P || !istype(P)) // Program not found or it's not executable program.
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>")
to_chat(user, span_danger("\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning."))
return
P.computer = src
@@ -156,22 +160,22 @@
active_program = P
P.alert_pending = FALSE
idle_threads.Remove(P)
update_icon()
update_appearance()
return
var/obj/item/computer_hardware/processor_unit/PU = all_components[MC_CPU]
if(idle_threads.len > PU.max_idle_programs)
to_chat(user, "<span class='danger'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error.</span>")
to_chat(user, span_danger("\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error."))
return
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet.
to_chat(user, "<span class='danger'>\The [src]'s screen shows \"Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>")
to_chat(user, span_danger("\The [src]'s screen shows \"Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning."))
return
if(P.run_program(user))
active_program = P
P.alert_pending = FALSE
update_icon()
update_appearance()
return 1
if("PC_toggle_light")
@@ -185,7 +189,7 @@
if(!new_color)
return
if(color_hex2num(new_color) < 200) //Colors too dark are rejected
to_chat(user, "<span class='warning'>That color is too dark! Choose a lighter one.</span>")
to_chat(user, span_warning("That color is too dark! Choose a lighter one."))
new_color = null
return set_flashlight_color(new_color)

View File

@@ -17,8 +17,8 @@
// No running around with open laptops in hands.
item_flags = SLOWS_WHILE_IN_HAND
screen_on = FALSE // Starts closed
var/start_open = TRUE // unless this var is set to 1
screen_on = FALSE // Starts closed
var/start_open = TRUE // unless this var is set to 1
var/icon_state_closed = "laptop-closed"
var/w_class_open = WEIGHT_CLASS_BULKY
var/slowdown_open = TRUE
@@ -44,15 +44,14 @@
/obj/item/modular_computer/laptop/update_icon_state()
if(!screen_on)
icon_state = icon_state_closed
else
. = ..()
return
return ..()
/obj/item/modular_computer/laptop/update_overlays()
if(screen_on)
return ..()
else
if(!screen_on)
cut_overlays()
icon_state = icon_state_closed
return
return ..()
/obj/item/modular_computer/laptop/attack_self(mob/user)
if(!screen_on)
@@ -68,7 +67,8 @@
try_toggle_open(usr)
/obj/item/modular_computer/laptop/MouseDrop(obj/over_object, src_location, over_location)
if(istype(over_object, /atom/movable/screen/inventory/hand) || over_object == usr)
. = ..()
if(istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
var/mob/M = usr
@@ -103,17 +103,17 @@
/obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null)
if(screen_on)
to_chat(user, "<span class='notice'>You close \the [src].</span>")
to_chat(user, span_notice("You close \the [src]."))
slowdown = initial(slowdown)
w_class = initial(w_class)
else
to_chat(user, "<span class='notice'>You open \the [src].</span>")
to_chat(user, span_notice("You open \the [src]."))
slowdown = slowdown_open
w_class = w_class_open
screen_on = !screen_on
display_overlays = screen_on
update_icon()
update_appearance()

View File

@@ -38,7 +38,7 @@
integrity_failure = machinery_computer.integrity_failure
base_active_power_usage = machinery_computer.base_active_power_usage
base_idle_power_usage = machinery_computer.base_idle_power_usage
machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /atom/proc/update_icon) //when we update_icon, also update the computer
machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /obj/machinery/modular_computer/proc/relay_icon_update) //when we update_icon, also update the computer
/obj/item/modular_computer/processor/relay_qdel()
qdel(machinery_computer)
@@ -47,7 +47,7 @@
if(!machinery_computer)
return
..()
machinery_computer.update_icon()
machinery_computer.update_appearance()
return
/obj/item/modular_computer/processor/attack_ghost(mob/user)
@@ -57,4 +57,4 @@
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext)
return
playsound(src, 'sound/machines/twobeep_high.ogg', 50, TRUE)
machinery_computer.visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
machinery_computer.visible_message(span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))

View File

@@ -2,9 +2,10 @@
name = "tablet computer"
icon = 'icons/obj/modular_tablet.dmi'
icon_state = "tablet-red"
icon_state_unpowered = "tablet"
icon_state_powered = "tablet"
icon_state_unpowered = "tablet-red"
icon_state_powered = "tablet-red"
icon_state_menu = "menu"
base_icon_state = "tablet"
// worn_icon_state = "tablet"
hardware_flag = PROGRAM_TABLET
max_hardware_size = 1
@@ -80,12 +81,12 @@
/obj/item/modular_computer/tablet/ui_data(mob/user)
. = ..()
.["PC_showpeneject"] = inserted_item ? 1 : 0
/obj/item/modular_computer/tablet/update_icon_state()
if(has_variants)
if(!finish_color)
finish_color = pick("red","blue","brown","green","black")
icon_state = icon_state_powered = icon_state_unpowered = "tablet-[finish_color]"
finish_color = pick("red", "blue", "brown", "green", "black")
icon_state = icon_state_powered = icon_state_unpowered = "[base_icon_state]-[finish_color]"
return ..()
/obj/item/modular_computer/tablet/syndicate_contract_uplink
name = "contractor tablet"
@@ -102,6 +103,8 @@
/// Given to Nuke Ops members.
/obj/item/modular_computer/tablet/nukeops
icon_state = "tablet-syndicate"
icon_state_powered = "tablet-syndicate"
icon_state_unpowered = "tablet-syndicate"
comp_light_luminosity = 6.3
has_variants = FALSE
device_theme = "syndicate"
@@ -109,15 +112,18 @@
/obj/item/modular_computer/tablet/nukeops/emag_act(mob/user)
if(!enabled)
to_chat(user, "<span class='warning'>You'd need to turn the [src] on first.</span>")
to_chat(user, span_warning("You'd need to turn the [src] on first."))
return FALSE
to_chat(user, "<span class='notice'>You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\".</span>")
to_chat(user, span_notice("You swipe \the [src]. It's screen briefly shows a message reading \"MEMORY CODE INJECTION DETECTED AND SUCCESSFULLY QUARANTINED\"."))
return FALSE
/// Borg Built-in tablet interface
/obj/item/modular_computer/tablet/integrated
name = "modular interface"
icon_state = "tablet-silicon"
icon_state_powered = "tablet-silicon"
icon_state_unpowered = "tablet-silicon"
base_icon_state = "tablet-silicon"
has_light = FALSE //tablet light button actually enables/disables the borg lamp
comp_light_luminosity = 0
has_variants = FALSE
@@ -198,11 +204,13 @@
if(!caller || !caller.alert_able || caller.alert_silenced || !alerttext) //Yeah, we're checking alert_able. No, you don't get to make alerts that the user can't silence.
return
borgo.playsound_local(src, sound, 50, TRUE)
to_chat(borgo, "<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
to_chat(borgo, span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))
/obj/item/modular_computer/tablet/integrated/syndicate
icon_state = "tablet-silicon-syndicate"
icon_state_powered = "tablet-silicon-syndicate"
icon_state_unpowered = "tablet-silicon-syndicate"
device_theme = "syndicate"

View File

@@ -20,6 +20,17 @@
install_component(new /obj/item/computer_hardware/card_slot)
install_component(new /obj/item/computer_hardware/printer/mini)
/obj/item/modular_computer/tablet/preset/science/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/hard_drive = new
install_component(new /obj/item/computer_hardware/processor_unit/small)
install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer))
install_component(hard_drive)
install_component(new /obj/item/computer_hardware/card_slot)
install_component(new /obj/item/computer_hardware/network_card)
install_component(new /obj/item/computer_hardware/radio_card)
hard_drive.store_file(new /datum/computer_file/program/signaler)
/obj/item/modular_computer/tablet/preset/cargo/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/hard_drive = new
@@ -30,17 +41,38 @@
install_component(new /obj/item/computer_hardware/network_card)
install_component(new /obj/item/computer_hardware/printer/mini)
// hard_drive.store_file(new /datum/computer_file/program/shipping)
var/datum/computer_file/program/chatclient/chatprogram
chatprogram = new
hard_drive.store_file(chatprogram)
chatprogram.username = get_cargochat_username()
/obj/item/modular_computer/tablet/preset/cargo/proc/get_cargochat_username()
return "cargonian_[rand(1,999)]"
/obj/item/modular_computer/tablet/preset/cargo/quartermaster/get_cargochat_username()
return "quartermaster"
/obj/item/modular_computer/tablet/preset/advanced/atmos/Initialize() //This will be defunct and will be replaced when NtOS PDAs are done
. = ..()
install_component(new /obj/item/computer_hardware/sensorpackage)
/obj/item/modular_computer/tablet/preset/advanced/engineering/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
hard_drive.store_file(new /datum/computer_file/program/supermatter_monitor)
/obj/item/modular_computer/tablet/preset/advanced/command/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
install_component(new /obj/item/computer_hardware/sensorpackage)
install_component(new /obj/item/computer_hardware/card_slot/secondary)
hard_drive.store_file(new /datum/computer_file/program/budgetorders)
// hard_drive.store_file(new /datum/computer_file/program/science)
/obj/item/modular_computer/tablet/preset/advanced/command/engineering/Initialize()
. = ..()
var/obj/item/computer_hardware/hard_drive/small/hard_drive = find_hardware_by_name("solid state drive")
hard_drive.store_file(new /datum/computer_file/program/supermatter_monitor)
/// Given by the syndicate as part of the contract uplink bundle - loads in the Contractor Uplink.
/obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink/Initialize()

View File

@@ -26,8 +26,6 @@
/obj/machinery/modular_computer/console/preset/proc/install_programs()
return
// ===== ENGINEERING CONSOLE =====
/obj/machinery/modular_computer/console/preset/engineering
console_department = "Engineering"
@@ -45,6 +43,7 @@
console_department = "Research"
name = "research director's console"
desc = "A stationary computer. This one comes preloaded with research programs."
_has_second_id_slot = TRUE
_has_ai = TRUE
/obj/machinery/modular_computer/console/preset/research/install_programs()
@@ -84,6 +83,18 @@
hard_drive.store_file(new/datum/computer_file/program/job_management())
hard_drive.store_file(new/datum/computer_file/program/crew_manifest())
/obj/machinery/modular_computer/console/preset/id/centcom
desc = "A stationary computer. This one comes preloaded with CentCom identification modification programs."
/obj/machinery/modular_computer/console/preset/id/centcom/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
var/datum/computer_file/program/card_mod/card_mod_centcom = new /datum/computer_file/program/card_mod()
card_mod_centcom.is_centcom = TRUE
hard_drive.store_file(new /datum/computer_file/program/chatclient())
hard_drive.store_file(card_mod_centcom)
hard_drive.store_file(new /datum/computer_file/program/job_management())
hard_drive.store_file(new /datum/computer_file/program/crew_manifest())
// ===== CIVILIAN CONSOLE =====
/obj/machinery/modular_computer/console/preset/civilian
console_department = "Civilian"
@@ -94,3 +105,79 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
hard_drive.store_file(new/datum/computer_file/program/arcade())
// curator
/obj/machinery/modular_computer/console/preset/curator
console_department = "Civilian"
name = "curator console"
desc = "A stationary computer. This one comes preloaded with art programs."
_has_printer = TRUE
/obj/machinery/modular_computer/console/preset/curator/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/portrait_printer())
// ===== CARGO CHAT CONSOLES =====
/obj/machinery/modular_computer/console/preset/cargochat
name = "cargo chatroom console"
desc = "A stationary computer. This one comes preloaded with a chatroom for your cargo requests."
///chat client installed on this computer, just helpful for linking all the computers
var/datum/computer_file/program/chatclient/chatprogram
/obj/machinery/modular_computer/console/preset/cargochat/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
chatprogram = new
chatprogram.computer = cpu
hard_drive.store_file(chatprogram)
chatprogram.username = "[lowertext(console_department)]_department"
chatprogram.program_state = PROGRAM_STATE_ACTIVE
cpu.active_program = chatprogram
//ONE PER MAP PLEASE, IT MAKES A CARGOBUS FOR EACH ONE OF THESE
/obj/machinery/modular_computer/console/preset/cargochat/cargo
console_department = "Cargo"
name = "department chatroom console"
desc = "A stationary computer. This one comes preloaded with a chatroom for incoming cargo requests. You may moderate it from this computer."
/obj/machinery/modular_computer/console/preset/cargochat/cargo/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
//adding chat, setting it as the active window immediately
chatprogram = new
chatprogram.computer = cpu
hard_drive.store_file(chatprogram)
chatprogram.program_state = PROGRAM_STATE_ACTIVE
cpu.active_program = chatprogram
//setting up chat
chatprogram.username = "cargo_requests_operator"
var/datum/ntnet_conversation/cargochat = new
cargochat.operator = chatprogram //adding operator before joining the chat prevents an unnecessary message about switching op from showing
cargochat.add_client(chatprogram)
cargochat.title = "#cargobus"
cargochat.strong = TRUE
chatprogram.active_channel = cargochat.id
/obj/machinery/modular_computer/console/preset/cargochat/cargo/LateInitialize()
. = ..()
var/datum/ntnet_conversation/cargochat = SSnetworks.station_network.get_chat_channel_by_id(chatprogram.active_channel)
for(var/obj/machinery/modular_computer/console/preset/cargochat/cargochat_console in GLOB.machines)
if(cargochat_console == src)
continue
cargochat_console.chatprogram.active_channel = chatprogram.active_channel
cargochat.add_client(cargochat_console.chatprogram, silent = TRUE)
/obj/machinery/modular_computer/console/preset/cargochat/service
console_department = "Service"
/obj/machinery/modular_computer/console/preset/cargochat/engineering
console_department = "Engineering"
/obj/machinery/modular_computer/console/preset/cargochat/science
console_department = "Science"
/obj/machinery/modular_computer/console/preset/cargochat/security
console_department = "Security"
/obj/machinery/modular_computer/console/preset/cargochat/medical
console_department = "Medical"

View File

@@ -4,28 +4,41 @@
name = "modular computer"
desc = "An advanced computer."
use_power = IDLE_POWER_USE
idle_power_usage = 5
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0 // Power usage during last tick
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = null
icon_state = null
var/icon_state_unpowered = null // Icon state when the computer is turned off.
var/icon_state_powered = null // Icon state when the computer is turned on.
var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'.
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
var/light_strength = 0 // Light luminosity when turned on
var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
var/obj/item/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things.
use_power = IDLE_POWER_USE
idle_power_usage = 5
///A flag that describes this device type
var/hardware_flag = 0
///Power usage during last tick
var/last_power_usage = 0
///Icon state when the computer is turned off.
var/icon_state_unpowered = null
///Icon state when the computer is turned on.
var/icon_state_powered = null
///Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/screen_icon_state_menu = "menu"
///Icon state overlay when the computer is powered, but not 'switched on'.
var/screen_icon_screensaver = "standby"
///Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
var/max_hardware_size = 0
///Amount of steel sheets refunded when disassembling an empty frame of this computer.
var/steel_sheet_cost = 10
///Light luminosity when turned on
var/light_strength = 0
///Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
var/base_active_power_usage = 100
///Power usage when the computer is idle and screen is off (currently only applies to laptops)
var/base_idle_power_usage = 10
///CPU that handles most logic while this type only handles power and other specific things.
var/obj/item/modular_computer/processor/cpu = null
/obj/machinery/modular_computer/Initialize()
. = ..()
@@ -48,32 +61,35 @@
cpu.attack_ghost(user)
/obj/machinery/modular_computer/emag_act(mob/user)
. = ..()
if(!cpu)
to_chat(user, "<span class='warning'>You'd need to turn the [src] on first.</span>")
to_chat(user, span_warning("You'd need to turn the [src] on first."))
return FALSE
return (cpu.emag_act(user))
/obj/machinery/modular_computer/update_icon()
cut_overlays()
icon_state = icon_state_powered
/obj/machinery/modular_computer/update_appearance(updates)
. = ..()
set_light(cpu?.enabled ? light_strength : 0)
if(!cpu || !cpu.enabled)
/obj/machinery/modular_computer/update_icon_state()
icon_state = (cpu?.enabled || (!(stat & NOPOWER) && cpu?.use_power())) ? icon_state_powered : icon_state_unpowered
return ..()
/obj/machinery/modular_computer/update_overlays()
. = ..()
if(!cpu?.enabled)
if (!(stat & NOPOWER) && (cpu?.use_power()))
add_overlay(screen_icon_screensaver)
else
icon_state = icon_state_unpowered
set_light(0)
. += screen_icon_screensaver
else
set_light(light_strength)
if(cpu.active_program)
add_overlay(cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu)
else
add_overlay(screen_icon_state_menu)
. += cpu.active_program?.program_icon_state || screen_icon_state_menu
if(cpu && cpu.obj_integrity <= cpu.integrity_failure * cpu.max_integrity)
add_overlay("bsod")
add_overlay("broken")
. += "bsod"
. += "broken"
/// Eats the "source" arg because update_icon actually expects args now.
/obj/machinery/modular_computer/proc/relay_icon_update(datum/source, updates, updated)
SIGNAL_HANDLER
return update_icon(updates)
/obj/machinery/modular_computer/AltClick(mob/user)
if(cpu)
@@ -98,17 +114,17 @@
/obj/machinery/modular_computer/proc/power_failure(malfunction = 0)
var/obj/item/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL]
if(cpu?.enabled) // Shut down the computer
visible_message("<span class='danger'>\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.</span>")
visible_message(span_danger("\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly."))
if(cpu)
cpu.shutdown_computer(0)
stat |= NOPOWER
update_icon()
set_machine_stat(stat | NOPOWER)
update_appearance()
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
/obj/machinery/modular_computer/power_change()
if(cpu?.use_power()) // If MC_CPU still has a power source, PC wouldn't go offline.
stat &= ~NOPOWER
update_icon()
set_machine_stat(stat & ~NOPOWER)
update_appearance()
return
. = ..()
@@ -116,7 +132,7 @@
if(cpu)
return cpu.screwdriver_act(user, tool)
/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/user)
/obj/machinery/modular_computer/attackby(obj/item/W as obj, mob/living/user)
if (user.a_intent == INTENT_HELP && cpu && !(flags_1 & NODECONSTRUCT_1))
return cpu.attackby(W, user)
return ..()
@@ -126,15 +142,16 @@
// Minor explosions are mostly mitigitated by casing.
/obj/machinery/modular_computer/ex_act(severity)
if(cpu)
cpu.ex_act(severity)
// switch(severity)
// if(EXPLODE_DEVASTATE)
// SSexplosions.high_mov_atom += cpu
// if(EXPLODE_HEAVY)
// SSexplosions.med_mov_atom += cpu
// if(EXPLODE_LIGHT)
// SSexplosions.low_mov_atom += cpu
..()
return cpu.ex_act(severity)
// switch(severity)
// if(EXPLODE_DEVASTATE)
// SSexplosions.high_mov_atom += cpu
// if(EXPLODE_HEAVY)
// SSexplosions.med_mov_atom += cpu
// if(EXPLODE_LIGHT)
// SSexplosions.low_mov_atom += cpu
return ..()
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
/obj/machinery/modular_computer/emp_act(severity)

View File

@@ -16,7 +16,8 @@
light_strength = 2
max_integrity = 300
integrity_failure = 0.5
var/console_department = "" // Used in New() to set network tag according to our area.
///Used in New() to set network tag according to our area.
var/console_department = ""
/obj/machinery/modular_computer/console/buildable/Initialize()
. = ..()
@@ -52,4 +53,4 @@
network_card.identification_string = "Unknown Console"
if(cpu)
cpu.screen_on = 1
update_icon()
update_appearance()

View File

@@ -1,11 +1,11 @@
/datum/computer_file
var/filename = "NewFile" // Placeholder. No spacebars
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
var/size = 1 // File size in GQ. Integers only!
var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file.
var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means.
var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc.
var/uid // UID of this file
var/filename = "NewFile" // Placeholder. No spacebars
var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case
var/size = 1 // File size in GQ. Integers only!
var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file.
var/unsendable = FALSE // Whether the file may be sent to someone via NTNet transfer or other means.
var/undeletable = FALSE // Whether the file may be deleted. Setting to TRUE prevents deletion/renaming/etc.
var/uid // UID of this file
var/static/file_uid = 0
/datum/computer_file/New()

View File

@@ -1,10 +1,10 @@
// /data/ files store data in string format.
// They don't contain other logic for now.
/datum/computer_file/data
var/stored_data = "" // Stored data in string format.
var/stored_data = "" // Stored data in string format.
filetype = "DAT"
var/block_size = 250
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited.
/datum/computer_file/data/clone()
var/datum/computer_file/data/temp = ..()

View File

@@ -15,6 +15,8 @@
var/filedesc = "Unknown Program"
/// Short description of this program's function.
var/extended_desc = "N/A"
/// Category in the NTDownloader.
var/category = PROGRAM_CATEGORY_MISC
/// Program-specific screen icon state
var/program_icon_state = null
/// Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
@@ -25,10 +27,10 @@
var/ntnet_status = 1
/// Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
var/usage_flags = PROGRAM_ALL
/// Whether the program can be downloaded from NTNet. Set to 0 to disable.
var/available_on_ntnet = 1
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
var/available_on_syndinet = 0
/// Whether the program can be downloaded from NTNet. Set to FALSE to disable.
var/available_on_ntnet = TRUE
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to TRUE to enable.
var/available_on_syndinet = FALSE
/// Name of the tgui interface
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!
@@ -64,7 +66,7 @@
// Relays icon update to the computer.
/datum/computer_file/program/proc/update_computer_icon()
if(computer)
computer.update_icon()
computer.update_appearance()
// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail.
/datum/computer_file/program/proc/generate_network_log(text)
@@ -72,10 +74,25 @@
return computer.add_log(text)
return 0
/**
*Runs when the device is used to attack an atom in non-combat mode.
*
*Simulates using the device to read or scan something. Tap is called by the computer during pre_attack
*and sends us all of the related info. If we return TRUE, the computer will stop the attack process
*there. What we do with the info is up to us, but we should only return TRUE if we actually perform
*an action of some sort.
*Arguments:
*A is the atom being tapped
*user is the person making the attack action
*params is anything the pre_attack() proc had in the same-named variable.
*/
/datum/computer_file/program/proc/tap(atom/A, mob/living/user, params)
return FALSE
/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null)
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>")
to_chat(user, span_danger("\The [computer] flashes a \"Hardware Error - Incompatible software\" warning."))
return FALSE
return TRUE
@@ -109,7 +126,7 @@
if(!access_to_check) // No required_access, allow it.
return TRUE
if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
if(!transfer && computer && (computer.obj_flags & EMAGGED)) //emags can bypass the execution locks but not the download ones.
return TRUE
if(IsAdminGhost(user))
@@ -127,14 +144,14 @@
if(!D)
if(loud)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>")
to_chat(user, span_danger("\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning."))
return FALSE
access = D.GetAccess()
if(access_to_check in access)
return TRUE
if(loud)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Access Denied\" warning.</span>")
to_chat(user, span_danger("\The [computer] flashes an \"Access Denied\" warning."))
return FALSE
// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones
@@ -219,7 +236,7 @@
program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
computer.active_program = null
computer.update_icon()
computer.update_appearance()
ui.close()
if(user && istype(user))

View File

@@ -13,6 +13,6 @@
/datum/computer_file/program/proc/event_networkfailure(background)
kill_program(forced = TRUE)
if(background)
computer.visible_message("<span class='danger'>\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error</span>")
computer.visible_message(span_danger("\The [computer]'s screen displays a \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error"))
else
computer.visible_message("<span class='danger'>\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.</span>")
computer.visible_message(span_danger("\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error."))

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/aidiag
filename = "aidiag"
filedesc = "NT FRK"
category = PROGRAM_CATEGORY_ROBO
program_icon_state = "generic"
extended_desc = "Firmware Restoration Kit, capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot."
size = 12
@@ -55,7 +56,7 @@
/datum/computer_file/program/aidiag/process_tick()
. = ..()
if(!restoring) //Put the check here so we don't check for an ai all the time
if(!restoring) //Put the check here so we don't check for an ai all the time
return
var/obj/item/aicard/cardhold = get_ai(2)
@@ -64,7 +65,7 @@
var/mob/living/silicon/ai/A = get_ai()
if(!A || !cardhold)
restoring = FALSE // If the AI was removed, stop the restoration sequence.
restoring = FALSE // If the AI was removed, stop the restoration sequence.
if(ai_slot)
ai_slot.locked = FALSE
return
@@ -84,7 +85,7 @@
if(A.health >= 0 && A.stat == DEAD)
A.revive(full_heal = FALSE, admin_revive = FALSE)
cardhold.update_icon()
cardhold.update_appearance()
// Finished restoring
if(A.health >= 100)

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/contract_uplink
filename = "contractor uplink"
filedesc = "Syndicate Contractor Uplink"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "assign"
extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field."
size = 10
@@ -91,9 +92,9 @@
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.put_in_hands(crystals))
to_chat(H, "<span class='notice'>Your payment materializes into your hands!</span>")
to_chat(H, span_notice("Your payment materializes into your hands!"))
else
to_chat(user, "<span class='notice'>Your payment materializes onto the floor.</span>")
to_chat(user, span_notice("Your payment materializes onto the floor."))
hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0
@@ -164,6 +165,11 @@
))
for (var/datum/syndicate_contract/contract in traitor_data.contractor_hub.assigned_contracts)
if(!contract.contract)
stack_trace("Syndiate contract with null contract objective found in [traitor_data.owner]'s contractor hub!")
contract.status = CONTRACT_STATUS_ABORTED
continue
data["contracts"] += list(list(
"target" = contract.contract.target,
"target_rank" = contract.target_rank,

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/ntnet_dos
filename = "ntn_dos"
filedesc = "DoS Traffic Generator"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "hostile"
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
size = 20

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/revelation
filename = "revelation"
filedesc = "Revelation"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "hostile"
extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution."
size = 13
@@ -20,13 +21,13 @@
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>")
to_chat(modularInterface.borgo,span_userdanger("SYSTEM PURGE DETECTED/"))
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.visible_message(span_notice("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard."))
computer.enabled = FALSE
computer.update_icon()
computer.update_appearance()
var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL]
var/obj/item/computer_hardware/recharger/recharger = computer.all_components[MC_CHARGE]
@@ -34,13 +35,13 @@
computer.take_damage(25, BRUTE, 0, 0)
if(battery_module && prob(25))
qdel(battery_module)
computer.visible_message("<span class='notice'>\The [computer]'s battery explodes in rain of sparks.</span>")
computer.visible_message(span_notice("\The [computer]'s battery explodes in rain of sparks."))
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
if(recharger && prob(50))
qdel(recharger)
computer.visible_message("<span class='notice'>\The [computer]'s recharger explodes in rain of sparks.</span>")
computer.visible_message(span_notice("\The [computer]'s recharger explodes in rain of sparks."))
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()

View File

@@ -32,7 +32,7 @@
game_active = FALSE
program_icon_state = "arcade_off"
if(istype(computer))
computer.update_icon()
computer.update_appearance()
ticket_count += 1
// user?.mind?.adjust_experience(/datum/skill/gaming, 50)
sleep(10)
@@ -42,7 +42,7 @@
game_active = FALSE
program_icon_state = "arcade_off"
if(istype(computer))
computer.update_icon()
computer.update_appearance()
// user?.mind?.adjust_experience(/datum/skill/gaming, 10)
sleep(10)
@@ -150,20 +150,20 @@
return TRUE
if("Dispense_Tickets")
if(!printer)
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to redeem tickets.</span>")
to_chat(usr, span_notice("Hardware error: A printer is required to redeem tickets."))
return
if(printer.stored_paper <= 0)
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
to_chat(usr, span_notice("Hardware error: Printer is out of paper."))
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
computer.visible_message(span_notice("\The [computer] prints out paper."))
if(ticket_count >= 1)
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
to_chat(usr, span_notice("[computer] dispenses a ticket!"))
ticket_count -= 1
printer.stored_paper -= 1
else
to_chat(usr, "<span class='notice'>You don't have any stored tickets!</span>")
to_chat(usr, span_notice("You don't have any stored tickets!"))
return TRUE
if("Start_Game")
game_active = TRUE
@@ -175,4 +175,4 @@
boss_id = rand(1,6)
pause_state = FALSE
if(istype(computer))
computer.update_icon()
computer.update_appearance()

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/atmosscan
filename = "atmosscan"
filedesc = "AtmoZphere"
category = PROGRAM_CATEGORY_ENGI
program_icon_state = "air"
extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device."
size = 4
@@ -12,7 +13,7 @@
if (!.)
return
if(!computer?.get_modular_computer_part(MC_SENSORS)) //Giving a clue to users why the program is spitting out zeros.
to_chat(user, "<span class='warning'>\The [computer] flashes an error: \"hardware\\sensorpackage\\startup.bin -- file not found\".</span>")
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\sensorpackage\\startup.bin -- file not found\"."))
/datum/computer_file/program/atmosscan/ui_data(mob/user)

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/borg_monitor
filename = "siliconnect"
filedesc = "SiliConnect"
category = PROGRAM_CATEGORY_ROBO
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows for remote monitoring of station cyborgs."
@@ -9,6 +10,70 @@
size = 5
tgui_id = "NtosCyborgRemoteMonitor"
program_icon = "project-diagram"
var/emagged = FALSE ///Bool of if this app has already been emagged
var/list/loglist = list() ///A list to copy a borg's IC log list into
var/mob/living/silicon/robot/DL_source ///reference of a borg if we're downloading a log, or null if not.
var/DL_progress = -1 ///Progress of current download, 0 to 100, -1 for no current download
/datum/computer_file/program/borg_monitor/Destroy()
loglist = null
DL_source = null
return ..()
/datum/computer_file/program/borg_monitor/kill_program(forced = FALSE)
loglist = null //Not everything is saved if you close an app
DL_source = null
DL_progress = 0
return ..()
/datum/computer_file/program/borg_monitor/run_emag()
if(emagged)
return FALSE
emagged = TRUE
return TRUE
/datum/computer_file/program/borg_monitor/tap(atom/A, mob/living/user, params)
var/mob/living/silicon/robot/borgo = A
if(!istype(borgo) || !borgo.modularInterface)
return FALSE
DL_source = borgo
DL_progress = 0
var/username = "unknown user"
var/obj/item/card/id/stored_card = computer.GetID()
if(istype(stored_card) && stored_card.registered_name)
username = "user [stored_card.registered_name]"
to_chat(borgo, span_userdanger("Request received from [username] for the system log file. Upload in progress."))//Damning evidence may be contained, so warn the borg
borgo.logevent("File request by [username]: /var/logs/syslog")
return TRUE
/datum/computer_file/program/borg_monitor/process_tick()
if(!DL_source)
DL_progress = -1
return
var/turf/here = get_turf(computer)
var/turf/there = get_turf(DL_source)
if(!here.Adjacent(there))//If someone walked away, cancel the download
to_chat(DL_source, span_danger("Log upload failed: general connection error."))//Let the borg know the upload stopped
DL_source = null
DL_progress = -1
return
if(DL_progress == 100)
if(!DL_source || !DL_source.modularInterface) //sanity check, in case the borg or their modular tablet poofs somehow
loglist = list("System log of unit [DL_source.name]")
loglist += "Error -- Download corrupted."
else
loglist = DL_source.modularInterface.borglog.Copy()
loglist.Insert(1,"System log of unit [DL_source.name]")
DL_progress = -1
DL_source = null
for(var/datum/tgui/window in SStgui.open_uis_by_src[REF(src)])
window.send_full_update()
return
DL_progress += 25
/datum/computer_file/program/borg_monitor/ui_data(mob/user)
var/list/data = get_header_data()
@@ -32,15 +97,22 @@
var/list/cyborg_data = list(
name = R.name,
integ = round((R.health + 100) / 2), //mob heath is -100 to 100, we want to scale that to 0 - 100
locked_down = R.locked_down,
status = R.stat,
shell_discon = shell,
charge = R.cell ? round(R.cell.percent()) : null,
module = R.module ? "[R.module.name] Module" : "No Module Detected",
module = R.module ? "[R.module.name] Model" : "No Model Detected",
upgrades = upgrade,
ref = REF(R)
)
data["cyborgs"] += list(cyborg_data)
data["DL_progress"] = DL_progress
return data
/datum/computer_file/program/borg_monitor/ui_static_data(mob/user)
var/list/data = list()
data["borglog"] = loglist
return data
/datum/computer_file/program/borg_monitor/ui_act(action, params)
@@ -57,16 +129,16 @@
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>")
to_chat(usr, span_warning("Error -- Could not open a connection to unit:[R]"))
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(R, "<br><br>[span_notice("Message from [ID] -- \"[message]\"")]<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>")
to_chat(R.connected_ai, "<br><br>[span_notice("Message from [ID] to [R] -- \"[message]\"")]<br>")
SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg')
usr.log_talk(message, LOG_PDA, tag="Cyborg Monitor Program: ID name \"[ID]\" to [R]")
@@ -82,12 +154,15 @@
/datum/computer_file/program/borg_monitor/proc/checkID()
var/obj/item/card/id/ID = computer.GetID()
if(!ID)
if(emagged)
return "STDERR:UNDF"
return FALSE
return ID.registered_name
/datum/computer_file/program/borg_monitor/syndicate
filename = "roboverlord"
filedesc = "Roboverlord"
category = PROGRAM_CATEGORY_ROBO
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
@@ -97,6 +172,9 @@
transfer_access = null
tgui_id = "NtosCyborgRemoteMonitorSyndicate"
/datum/computer_file/program/borg_monitor/syndicate/run_emag()
return FALSE
/datum/computer_file/program/borg_monitor/syndicate/evaluate_borg(mob/living/silicon/robot/R)
if((get_turf(computer)).z != (get_turf(R)).z)
return FALSE

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/bounty_board
filename = "bountyboard"
filedesc = "Bounty Board Request Network"
category = PROGRAM_CATEGORY_SUPL
program_icon_state = "bountyboard"
extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.."
requires_ntnet = TRUE

View File

@@ -1,41 +1,50 @@
/datum/computer_file/program/budgetorders
filename = "orderapp"
filedesc = "NT IRN"
// category = PROGRAM_CATEGORY_SUPL
category = PROGRAM_CATEGORY_SUPL
program_icon_state = "request"
extended_desc = "Nanotrasen Internal Requisition Network interface for supply purchasing 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_view = FALSE
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."
var/safety_warning = "For safety and ethical reasons, the automated supply shuttle \
cannot transport live organisms, human remains, classified nuclear weaponry, mail, \
homing beacons, unstable eigenstates 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."
///The name of the shuttle template being used as the cargo shuttle. 'supply' is default and contains critical code. Don't change this unless you know what you're doing.
var/cargo_shuttle = "supply"
///The docking port called when returning to the station.
var/docking_home = "supply_home"
///The docking port called when leaving the station.
var/docking_away = "supply_away"
///If this console can loan the cargo shuttle. Set to false to disable.
var/stationcargo = TRUE
///The account this console processes and displays. Independent from the account the shuttle processes.
var/cargo_account = ACCOUNT_CAR
/datum/computer_file/program/budgetorders/proc/get_export_categories()
. = EXPORT_CARGO
/datum/computer_file/program/budgetorders/run_emag()
if(!contraband_view)
contraband_view = TRUE
if(!contraband)
contraband = TRUE
return TRUE
/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) || contraband_view)
if(computer.obj_flags & EMAGGED)
return TRUE
else if(contraband) //Hide contrband when non-emagged.
return FALSE
@@ -64,11 +73,11 @@
. = ..()
var/list/data = get_header_data()
data["location"] = SSshuttle.supply.getStatusText()
var/datum/bank_account/buyer = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/datum/bank_account/buyer = SSeconomy.get_dep_account(cargo_account)
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)
if((ACCESS_HEADS in id_card.access) || (ACCESS_QM in id_card.access))
requestonly = FALSE
buyer = SSeconomy.get_dep_account(id_card.registered_account.account_job.paycheck_department)
can_approve_requests = TRUE
@@ -85,14 +94,14 @@
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 , null, P.contraband))
if(!is_visible_pack(usr, P.access , 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_view) || (P.special && !P.special_enabled) || P.DropPodOnly)
if((P.hidden && (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.DropPodOnly))
continue
data["supplies"][P.group]["packs"] += list(list(
"name" = P.name,
@@ -105,7 +114,7 @@
//Data regarding the User's capability to buy things.
data["has_id"] = id_card
data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
data["away"] = SSshuttle.supply.getDockedId() == docking_away
data["self_paid"] = self_paid
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
data["loan"] = !!SSshuttle.shuttle_loan
@@ -153,15 +162,15 @@
if(SSshuttle.supplyBlocked)
computer.say(blockade_warning)
return
if(SSshuttle.supply.getDockedId() == "supply_home")
if(SSshuttle.supply.getDockedId() == docking_home)
SSshuttle.supply.export_categories = get_export_categories()
SSshuttle.moveShuttle("supply", "supply_away", TRUE)
SSshuttle.moveShuttle(cargo_shuttle, docking_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)
SSshuttle.moveShuttle(cargo_shuttle, docking_home, TRUE)
. = TRUE
if("loan")
if(!SSshuttle.shuttle_loan)
@@ -171,7 +180,9 @@
return
else if(SSshuttle.supply.mode != SHUTTLE_IDLE)
return
else if(SSshuttle.supply.getDockedId() != "supply_away")
else if(SSshuttle.supply.getDockedId() != docking_away)
return
else if(stationcargo != TRUE)
return
else
SSshuttle.shuttle_loan.loan_shuttle()
@@ -184,7 +195,7 @@
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
if(!istype(pack))
return
if(((pack.hidden || pack.contraband) && !contraband_view) || pack.DropPodOnly)
if((pack.hidden && (pack.contraband && !contraband) || pack.DropPodOnly))
return
var/name = "*None Provided*"
@@ -273,7 +284,7 @@
self_paid = !self_paid
. = TRUE
if(.)
post_signal("supply")
post_signal(cargo_shuttle)
/datum/computer_file/program/budgetorders/proc/post_signal(command)

View File

@@ -9,6 +9,7 @@
/datum/computer_file/program/card_mod
filename = "plexagonidwriter"
filedesc = "Plexagon Access Management"
category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for programming employee ID cards to access parts of the station."
transfer_access = ACCESS_HEADS

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/shipping
filename = "shipping"
filedesc = "GrandArk Exporter"
category = PROGRAM_CATEGORY_SUPL
program_icon_state = "shipping"
extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping."
size = 6
@@ -8,8 +9,12 @@
program_icon = "tags"
///Account used for creating barcodes.
var/datum/bank_account/payments_acc
///The amount which the tagger will receive for the sale.
var/percent_cut = 20
///The person who tagged this will receive the sale value multiplied by this number.
var/cut_multiplier = 0.5
///Maximum value for cut_multiplier.
var/cut_max = 0.5
///Minimum value for cut_multiplier.
var/cut_min = 0.01
/datum/computer_file/program/shipping/ui_data(mob/user)
var/list/data = get_header_data()
@@ -22,7 +27,7 @@
data["paperamt"] = printer ? "[printer.stored_paper] / [printer.max_paper]" : null
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
data["barcode_split"] = cut_multiplier * 100
return data
/datum/computer_file/program/shipping/ui_act(action, list/params)
@@ -54,20 +59,20 @@
if("resetid")
payments_acc = null
if("setsplit")
var/potential_cut = tgui_input_num(usr, "How much would you like to payout to the registered card?","Percentage Profit")
percent_cut = potential_cut ? clamp(round(potential_cut, 1), 1, 50) : 20
var/potential_cut = input("How much would you like to pay out to the registered card?","Percentage Profit ([round(cut_min*100)]% - [round(cut_max*100)]%)") as num|null
cut_multiplier = potential_cut ? clamp(round(potential_cut/100, cut_min), cut_min, cut_max) : initial(cut_multiplier)
if("print")
if(!printer)
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to print barcodes.</span>")
to_chat(usr, span_notice("Hardware error: A printer is required to print barcodes."))
return
if(printer.stored_paper <= 0)
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
to_chat(usr, span_notice("Hardware error: Printer is out of paper."))
return
if(!payments_acc)
to_chat(usr, "<span class='notice'>Software error: Please set a current user first.</span>")
to_chat(usr, span_notice("Software error: Please set a current user first."))
return
var/obj/item/barcode/barcode = new /obj/item/barcode(get_turf(ui_host()))
barcode.payments_acc = payments_acc
barcode.percent_cut = percent_cut
barcode.cut_multiplier = cut_multiplier
printer.stored_paper--
to_chat(usr, "<span class='notice'>The computer prints out a barcode.</span>")
to_chat(usr, span_notice("The computer prints out a barcode."))

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/crew_manifest
filename = "plexagoncrew"
filedesc = "Plexagon Crew List"
category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for viewing and printing the current crew manifest"
transfer_access = ACCESS_HEADS
@@ -11,7 +12,7 @@
/datum/computer_file/program/crew_manifest/ui_static_data(mob/user)
var/list/data = list()
data["manifest"] = GLOB.data_core.get_manifest_tg()
data["manifest"] = GLOB.data_core.get_manifest()
return data
/datum/computer_file/program/crew_manifest/ui_data(mob/user)
@@ -44,7 +45,7 @@
[GLOB.data_core ? GLOB.data_core.get_manifest() : ""]
"}
if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time))))
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
to_chat(usr, span_notice("Hardware error: Printer was unable to print the file. It may be out of paper."))
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out a paper.</span>")
computer.visible_message(span_notice("\The [computer] prints out a paper."))

View File

@@ -38,14 +38,27 @@
return
RHDD.remove_file(file)
return TRUE
if("PRG_rename")
if("PRG_renamefile")
if(!HDD)
return
var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
if(!file)
return
var/newname = params["new_name"]
if(!newname)
var/newname = reject_bad_name(params["new_name"])
if(!newname || newname != params["new_name"])
playsound(computer, 'sound/machines/terminal_error.ogg', 25, FALSE)
return
file.filename = newname
return TRUE
if("PRG_usbrenamefile")
if(!RHDD)
return
var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
if(!file)
return
var/newname = reject_bad_name(params["new_name"])
if(!newname || newname != params["new_name"])
playsound(computer, 'sound/machines/terminal_error.ogg', 25, FALSE)
return
file.filename = newname
return TRUE

View File

@@ -1,6 +1,10 @@
/// The time since the last job opening was created
// GLOBAL_VAR_INIT(time_last_changed_position, 0)
/datum/computer_file/program/job_management
filename = "plexagoncore"
filedesc = "Plexagon HR Core"
category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for viewing and changing job slot avalibility."
transfer_access = ACCESS_HEADS
@@ -35,21 +39,25 @@
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
/datum/computer_file/program/job_management/proc/can_open_job(datum/job/job)
if(!(job?.title in blacklisted))
if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100)))
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
return TRUE
if(job?.title in blacklisted)
return FALSE
if((job.total_positions <= length(GLOB.player_list) * (max_relative_positions / 100)))
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
return TRUE
return FALSE
/datum/computer_file/program/job_management/proc/can_close_job(datum/job/job)
if(!(job?.title in blacklisted))
if(job.total_positions > job.current_positions)
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
return TRUE
if(job?.title in blacklisted)
return FALSE
if(job.total_positions > job.current_positions)
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
return TRUE
return FALSE
/datum/computer_file/program/job_management/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
@@ -68,9 +76,10 @@
if(!j || !can_open_job(j))
return
if(opened_positions[edit_job_target] >= 0)
GLOB.time_last_changed_position = world.time / 10 // global cd
GLOB.time_last_changed_position = world.time / 10
j.total_positions++
opened_positions[edit_job_target]++
log_game("[key_name(usr)] opened a [j.title] job position, for a total of [j.total_positions] open job slots.")
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
if("PRG_close_job")
@@ -83,21 +92,23 @@
GLOB.time_last_changed_position = world.time / 10
j.total_positions--
opened_positions[edit_job_target]--
log_game("[key_name(usr)] closed a [j.title] job position, leaving [j.total_positions] open job slots.")
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
if("PRG_priority")
if(length(SSjob.prioritized_jobs) >= 5)
return
var/priority_target = params["target"]
var/datum/job/j = SSjob.GetJob(priority_target)
if(!j)
if(!j || (job?.title in blacklisted))
return
if(j.total_positions <= j.current_positions)
return
if(j in SSjob.prioritized_jobs)
SSjob.prioritized_jobs -= j
else
SSjob.prioritized_jobs += j
if(length(SSjob.prioritized_jobs) < 5)
SSjob.prioritized_jobs += j
else
computer.say("Error: CentCom employment protocols restrict prioritising more than 5 jobs.")
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE

View File

@@ -22,6 +22,13 @@
var/emagged = FALSE
var/list/main_repo
var/list/antag_repo
var/list/show_categories = list(
PROGRAM_CATEGORY_CREW,
PROGRAM_CATEGORY_ENGI,
PROGRAM_CATEGORY_ROBO,
PROGRAM_CATEGORY_SUPL,
PROGRAM_CATEGORY_MISC,
)
/datum/computer_file/program/ntnetdownload/run_program()
. = ..()
@@ -146,39 +153,29 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD]
data["disk_size"] = hard_drive.max_capacity
data["disk_used"] = hard_drive.used_capacity
var/list/all_entries[0]
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(hard_drive.find_file_by_name(P.filename))
continue
all_entries.Add(list(list(
data["emagged"] = emagged
var/list/repo = antag_repo | main_repo
var/list/program_categories = list()
for(var/I in repo)
var/datum/computer_file/program/P = I
if(!(P.category in program_categories))
program_categories.Add(P.category)
data["programs"] += list(list(
"icon" = P.program_icon,
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"compatibility" = check_compatibility(P),
"category" = P.category,
"installed" = !!hard_drive.find_file_by_name(P.filename),
"compatible" = 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
var/list/hacked_programs[0]
for(var/S in antag_repo)
var/datum/computer_file/program/P = S
if(hard_drive.find_file_by_name(P.filename))
continue
data["hackedavailable"] = TRUE
hacked_programs.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"compatibility" = check_compatibility(P),
"size" = P.size,
"access" = TRUE,
)))
data["hacked_programs"] = hacked_programs
"access" = emagged && P.available_on_syndinet ? TRUE : P.can_run(user,transfer = 1, access = access),
"verifiedsource" = P.available_on_ntnet,
))
data["downloadable_programs"] = all_entries
data["categories"] = show_categories & program_categories
return data
@@ -186,8 +183,8 @@
var/hardflag = computer.hardware_flag
if(P?.is_supported_by_hardware(hardflag,0))
return "Compatible"
return "Incompatible!"
return TRUE
return FALSE
/datum/computer_file/program/ntnetdownload/kill_program(forced)
abort_file_download()

View File

@@ -1,11 +1,12 @@
/datum/computer_file/program/ntnetmonitor
filename = "wirecarp"
filedesc = "WireCarp"
category = PROGRAM_CATEGORY_MISC
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
requires_ntnet = TRUE
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
required_access = ACCESS_NETWORK //NETWORK CONTROL IS A MORE SECURE PROGRAM.
available_on_ntnet = TRUE
tgui_id = "NtosNetMonitor"
program_icon = "network-wired"

View File

@@ -1,25 +1,36 @@
/datum/computer_file/program/chatclient
filename = "ntnrc_client"
filedesc = "Chat Client"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "command"
extended_desc = "This program allows communication over NTNRC network"
size = 8
requires_ntnet = 1
requires_ntnet = TRUE
requires_ntnet_feature = NTNET_COMMUNICATION
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
available_on_ntnet = TRUE
tgui_id = "NtosNetChat"
program_icon = "comment-alt"
var/last_message // Used to generate the toolbar icon
alert_able = TRUE
var/last_message // Used to generate the toolbar icon
var/username
var/active_channel
var/list/channel_history = list()
var/operator_mode = FALSE // Channel operator mode
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
var/operator_mode = FALSE // Channel operator mode
var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
//A list of all the converstations we're a part of
var/list/datum/ntnet_conversation/conversations = list()
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
/datum/computer_file/program/chatclient/Destroy()
for(var/datum/ntnet_conversation/discussion as anything in conversations)
discussion.purge_client(src)
conversations.Cut()
return ..()
/datum/computer_file/program/chatclient/ui_act(action, params)
. = ..()
if(.)
@@ -36,7 +47,7 @@
var/message = reject_bad_text(params["message"])
if(!message)
return
if(channel.password && !(src in channel.clients))
if(channel.password && (!(src in channel.active_clients) && !(src in channel.offline_clients)))
if(channel.password == message)
channel.add_client(src)
return TRUE
@@ -56,7 +67,7 @@
active_channel = new_target
channel = SSnetworks.station_network.get_chat_channel_by_id(new_target)
if(!(src in channel.clients) && !channel.password)
if((!(src in channel.active_clients) && !(src in channel.offline_clients)) && !channel.password)
channel.add_client(src)
return TRUE
if("PRG_leavechannel")
@@ -89,12 +100,12 @@
return TRUE
if("PRG_changename")
var/newname = sanitize(params["new_name"])
if(!newname)
newname = replacetext(newname, " ", "_")
if(!newname || newname == username)
return
for(var/C in SSnetworks.station_network.chat_channels)
var/datum/ntnet_conversation/chan = C
if(src in chan.clients)
chan.add_status_message("[username] is now known as [newname].")
for(var/datum/ntnet_conversation/anychannel as anything in SSnetworks.station_network.chat_channels)
if(src in anychannel.active_clients)
anychannel.add_status_message("[username] is now known as [newname].")
username = newname
return TRUE
if("PRG_savelog")
@@ -117,9 +128,9 @@
// This program shouldn't even be runnable without computer.
CRASH("Var computer is null!")
if(!hard_drive)
computer.visible_message("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.</span>")
else // In 99.9% cases this will mean our HDD is full
computer.visible_message("<span class='warning'>\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.</span>")
computer.visible_message(span_warning("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning."))
else // In 99.9% cases this will mean our HDD is full
computer.visible_message(span_warning("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning."))
return TRUE
if("PRG_renamechannel")
if(!authed)
@@ -145,6 +156,18 @@
channel.password = new_password
return TRUE
if("PRG_mute_user")
if(!authed)
return
var/datum/computer_file/program/chatclient/muted = locate(params["ref"]) in channel.active_clients + channel.offline_clients
channel.mute_user(src, muted)
return TRUE
if("PRG_ping_user")
if(!authed)
return
var/datum/computer_file/program/chatclient/pinged = locate(params["ref"]) in channel.active_clients + channel.offline_clients
channel.ping_user(src, pinged)
return TRUE
/datum/computer_file/program/chatclient/process_tick()
. = ..()
@@ -162,10 +185,19 @@
else
ui_header = "ntnrc_idle.gif"
/datum/computer_file/program/chatclient/run_program(mob/living/user)
. = ..()
if(!.)
return
for(var/datum/ntnet_conversation/channel as anything in SSnetworks.station_network.chat_channels)
if(src in channel.offline_clients)
channel.offline_clients.Remove(src)
channel.active_clients.Add(src)
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
for(var/C in SSnetworks.station_network.chat_channels)
var/datum/ntnet_conversation/channel = C
channel.remove_client(src)
for(var/datum/ntnet_conversation/channel as anything in SSnetworks.station_network.chat_channels)
channel.go_offline(src)
active_channel = null
..()
/datum/computer_file/program/chatclient/ui_static_data(mob/user)
@@ -192,6 +224,7 @@
data["all_channels"] = all_channels
data["active_channel"] = active_channel
data["selfref"] = REF(src) //used to verify who is you, as usernames can be copied.
data["username"] = username
data["adminmode"] = netadmin_mode
var/datum/ntnet_conversation/channel = SSnetworks.station_network.get_chat_channel_by_id(active_channel)
@@ -203,21 +236,25 @@
if(netadmin_mode)
authed = TRUE
var/list/clients = list()
for(var/C in channel.clients)
if(C == src)
for(var/datum/computer_file/program/chatclient/channel_client as anything in channel.active_clients + channel.offline_clients)
if(channel_client == src)
authed = TRUE
var/datum/computer_file/program/chatclient/cl = C
clients.Add(list(list(
"name" = cl.username
"name" = channel_client.username,
"status" = channel_client.program_state,
"muted" = (channel_client in channel.muted_clients),
"operator" = channel.operator == channel_client,
"ref" = REF(channel_client)
)))
data["authed"] = authed
//no fishing for ui data allowed
if(authed)
data["strong"] = channel.strong
data["clients"] = clients
var/list/messages = list()
for(var/M in channel.messages)
for(var/message in channel.messages)
messages.Add(list(list(
"msg" = M
"msg" = message
)))
data["messages"] = messages
data["is_operator"] = (channel.operator == src) || netadmin_mode

View File

@@ -0,0 +1,83 @@
///how much paper it takes from the printer to create a canvas.
#define CANVAS_PAPER_COST 10
/**
* ## portrait printer!
*
* Program that lets the curator browse all of the portraits in the database
* They are free to print them out as they please.
*/
/datum/computer_file/program/portrait_printer
filename = "PortraitPrinter"
filedesc = "Marlowe Treeby's Art Galaxy"
category = PROGRAM_CATEGORY_CREW
program_icon_state = "dummy"
extended_desc = "This program connects to a Spinward Sector community art site for viewing and printing art."
transfer_access = ACCESS_LIBRARY
usage_flags = PROGRAM_CONSOLE
requires_ntnet = TRUE
size = 9
tgui_id = "NtosPortraitPrinter"
program_icon = "paint-brush"
/datum/computer_file/program/portrait_printer/ui_data(mob/user)
var/list/data = list()
data["library"] = SSpersistence.paintings["library"] ? SSpersistence.paintings["library"] : 0
data["library_secure"] = SSpersistence.paintings["library_secure"] ? SSpersistence.paintings["library_secure"] : 0
data["library_private"] = SSpersistence.paintings["library_private"] ? SSpersistence.paintings["library_private"] : 0 //i'm gonna regret this, won't i?
return data
/datum/computer_file/program/portrait_printer/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/portraits/library),
get_asset_datum(/datum/asset/simple/portraits/library_secure),
get_asset_datum(/datum/asset/simple/portraits/library_private)
)
/datum/computer_file/program/portrait_printer/ui_act(action, params)
. = ..()
if(.)
return
//printer check!
var/obj/item/computer_hardware/printer/printer
if(computer)
printer = computer.all_components[MC_PRINT]
if(!printer)
to_chat(usr, span_notice("Hardware error: A printer is required to print a canvas."))
return
if(printer.stored_paper < CANVAS_PAPER_COST)
to_chat(usr, span_notice("Printing error: Your printer needs at least [CANVAS_PAPER_COST] paper to print a canvas."))
return
printer.stored_paper -= CANVAS_PAPER_COST
//canvas printing!
var/list/tab2key = list(TAB_LIBRARY = "library", TAB_SECURE = "library_secure", TAB_PRIVATE = "library_private")
var/folder = tab2key[params["tab"]]
var/list/current_list = SSpersistence.paintings[folder]
var/list/chosen_portrait = current_list[params["selected"]]
var/author = chosen_portrait["author"]
var/title = chosen_portrait["title"]
var/png = "data/paintings/[folder]/[chosen_portrait["md5"]].png"
var/icon/art_icon = new(png)
var/obj/item/canvas/printed_canvas
var/art_width = art_icon.Width()
var/art_height = art_icon.Height()
for(var/canvas_type in typesof(/obj/item/canvas))
printed_canvas = canvas_type
if(initial(printed_canvas.width) == art_width && initial(printed_canvas.height) == art_height)
printed_canvas = new canvas_type(get_turf(computer.physical))
break
printed_canvas.fill_grid_from_icon(art_icon)
printed_canvas.generated_icon = art_icon
printed_canvas.icon_generated = TRUE
printed_canvas.finalized = TRUE
printed_canvas.painting_name = title
printed_canvas.author_ckey = author
printed_canvas.name = "painting - [title]"
///this is a copy of something that is already in the database- it should not be able to be saved.
printed_canvas.no_save = TRUE
printed_canvas.update_icon()
to_chat(usr, span_notice("You have printed [title] onto a new canvas."))
playsound(computer.physical, 'sound/items/poster_being_created.ogg', 100, TRUE)

View File

@@ -3,6 +3,7 @@
/datum/computer_file/program/power_monitor
filename = "ampcheck"
filedesc = "AmpCheck"
category = PROGRAM_CATEGORY_ENGI
program_icon_state = "power_monitor"
extended_desc = "This program connects to sensors around the station to provide information about electrical systems"
ui_header = "power_norm.gif"

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/radar //generic parent that handles most of the process
filename = "genericfinder"
filedesc = "debug_finder"
category = PROGRAM_CATEGORY_CREW
ui_header = "borg_mon.gif" //DEBUG -- new icon before PR
program_icon_state = "radarntos"
requires_ntnet = TRUE
@@ -15,7 +16,7 @@
var/atom/selected
///Used to store when the next scan is available. Updated by the scan() proc.
var/next_scan = 0
///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_icon() calls
///Used to keep track of the last value program_icon_state was set to, to prevent constant unnecessary update_appearance() calls
var/last_icon_state = ""
///Used by the tgui interface, themed NT or Syndicate.
var/arrowstyle = "ntosradarpointer.png"
@@ -174,7 +175,7 @@
if(!trackable(signal))
program_icon_state = "[initial(program_icon_state)]lost"
if(last_icon_state != program_icon_state)
computer.update_icon()
computer.update_appearance()
last_icon_state = program_icon_state
return
@@ -192,7 +193,7 @@
program_icon_state = "[initial(program_icon_state)]far"
if(last_icon_state != program_icon_state)
computer.update_icon()
computer.update_appearance()
last_icon_state = program_icon_state
computer.setDir(get_dir(here_turf, target_turf))
@@ -241,13 +242,12 @@
/datum/computer_file/program/radar/lifeline/trackable(mob/living/carbon/human/humanoid)
if(!humanoid || !istype(humanoid))
return FALSE
if(..() && istype(humanoid.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/uniform = humanoid.w_uniform
if(!uniform.has_sensor || (uniform.sensor_mode < SENSOR_COORDS)) // Suit sensors must be on maximum.
return FALSE
return TRUE
if(..())
if (istype(humanoid.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/uniform = humanoid.w_uniform
if(uniform.has_sensor && uniform.sensor_mode >= SENSOR_COORDS) // Suit sensors must be on maximum
return TRUE
return FALSE
////////////////////////
//Nuke Disk Finder App//
@@ -257,6 +257,7 @@
/datum/computer_file/program/radar/fission360
filename = "fission360"
filedesc = "Fission360"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "radarsyndicate"
extended_desc = "This program allows for tracking of nuclear authorization disks and warheads."
requires_ntnet = FALSE

View File

@@ -2,6 +2,7 @@
/datum/computer_file/program/robocontrol
filename = "botkeeper"
filedesc = "BotKeeper"
category = PROGRAM_CATEGORY_ROBO
program_icon_state = "robot"
extended_desc = "A remote controller used for giving basic commands to non-sentient robots."
transfer_access = null

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/robotact
filename = "robotact"
filedesc = "RoboTact"
category = PROGRAM_CATEGORY_ROBO
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"
@@ -22,7 +23,7 @@
/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>")
to_chat(user, span_warning("A warning flashes across \the [computer]: Device Incompatible."))
return FALSE
. = ..()
if(.)
@@ -39,7 +40,7 @@
var/mob/living/silicon/robot/borgo = tablet.borgo
data["name"] = borgo.name
data["designation"] = borgo.designation //Borgo module type
data["designation"] = borgo.designation //Borgo model type
data["masterAI"] = borgo.connected_ai //Master AI
var/charge = 0
@@ -62,7 +63,7 @@
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.locked_down?"DISABLED":"ENABLED"]"]"
//Module wire. FAULT if cut, NOMINAL otherwise
//Model 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"]"]"
@@ -110,7 +111,7 @@
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>", \
borgo.visible_message(span_notice("The power warning light on [span_name("[borgo]")] flashes urgently."), \
"You announce you are operating in low power mode.")
playsound(borgo, 'sound/machines/buzz-two.ogg', 50, FALSE)

View File

@@ -3,6 +3,7 @@
/datum/computer_file/program/secureye
filename = "secureye"
filedesc = "SecurEye"
category = PROGRAM_CATEGORY_MISC
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows access to standard security camera networks."

View File

@@ -0,0 +1,83 @@
/datum/computer_file/program/signaler
filename = "signaler"
filedesc = "SignalCommander"
category = PROGRAM_CATEGORY_MISC
program_icon_state = "signal"
extended_desc = "A small built-in frequency app that sends out signaller signals with the appropriate hardware."
size = 2
tgui_id = "NtosSignaler"
program_icon = "satellite-dish"
usage_flags = PROGRAM_TABLET | PROGRAM_LAPTOP
///What is the saved signal frequency?
var/signal_frequency = FREQ_SIGNALER
/// What is the saved signal code?
var/signal_code = DEFAULT_SIGNALER_CODE
/// Radio connection datum used by signalers.
var/datum/radio_frequency/radio_connection
/datum/computer_file/program/signaler/run_program(mob/living/user)
. = ..()
if (!.)
return
if(!computer?.get_modular_computer_part(MC_SIGNALER)) //Giving a clue to users why the program is spitting out zeros.
to_chat(user, span_warning("\The [computer] flashes an error: \"hardware\\signal_hardware\\startup.bin -- file not found\"."))
/datum/computer_file/program/signaler/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(sensor?.check_functionality())
data["frequency"] = signal_frequency
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
return data
/datum/computer_file/program/signaler/ui_act(action, list/params)
. = ..()
if(.)
return
var/obj/item/computer_hardware/radio_card/sensor = computer?.get_modular_computer_part(MC_SIGNALER)
if(!(sensor?.check_functionality()))
playsound(src, 'sound/machines/scanbuzz.ogg', 100, FALSE)
return
switch(action)
if("signal")
INVOKE_ASYNC(src, .proc/signal)
. = TRUE
if("freq")
signal_frequency = unformat_frequency(params["freq"])
signal_frequency = sanitize_frequency(signal_frequency, TRUE)
set_frequency(signal_frequency)
. = TRUE
if("code")
signal_code = text2num(params["code"])
signal_code = round(signal_code)
. = TRUE
if("reset")
if(params["reset"] == "freq")
signal_frequency = initial(signal_frequency)
else
signal_code = initial(signal_code)
. = TRUE
/datum/computer_file/program/signaler/proc/signal()
if(!radio_connection)
return
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(src)
var/logging_data
if(usr)
logging_data = "[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(signal_frequency)]/[signal_code]"
GLOB.lastsignalers.Add(logging_data)
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
radio_connection.post_signal(src, signal)
/datum/computer_file/program/signaler/proc/set_frequency(new_frequency)
SSradio.remove_object(src, signal_frequency)
signal_frequency = new_frequency
radio_connection = SSradio.add_object(src, signal_frequency, RADIO_SIGNALER)
return

View File

@@ -1,6 +1,7 @@
/datum/computer_file/program/supermatter_monitor
filename = "ntcims"
filedesc = "NT CIMS"
category = PROGRAM_CATEGORY_ENGI
ui_header = "smmon_0.gif"
program_icon_state = "smmon_0"
extended_desc = "Crystal Integrity Monitoring System, connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines."
@@ -12,7 +13,7 @@
alert_able = TRUE
var/last_status = SUPERMATTER_INACTIVE
var/list/supermatters
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
var/obj/machinery/power/supermatter_crystal/active // Currently selected supermatter crystal.
/datum/computer_file/program/supermatter_monitor/Destroy()
clear_signals()
@@ -27,7 +28,7 @@
ui_header = "smmon_[last_status].gif"
program_icon_state = "smmon_[last_status]"
if(istype(computer))
computer.update_icon()
computer.update_appearance()
/datum/computer_file/program/supermatter_monitor/run_program(mob/living/user)
. = ..(user)
@@ -36,11 +37,15 @@
refresh()
/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE)
for(var/supermatter in supermatters)
clear_supermatter(supermatter)
supermatters = null
..()
// Refreshes list of active supermatter crystals
/datum/computer_file/program/supermatter_monitor/proc/refresh()
for(var/supermatter in supermatters)
clear_supermatter(supermatter)
supermatters = list()
var/turf/T = get_turf(ui_host())
if(!T)
@@ -50,9 +55,7 @@
if (!isturf(S.loc) || !(is_station_level(S.z) || is_mining_level(S.z) || S.z == T.z))
continue
supermatters.Add(S)
if(!(active in supermatters))
active = null
RegisterSignal(S, COMSIG_PARENT_QDELETING, .proc/react_to_del)
/datum/computer_file/program/supermatter_monitor/proc/get_status()
. = SUPERMATTER_INACTIVE
@@ -67,9 +70,9 @@
* 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)
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.
@@ -77,9 +80,9 @@
* 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)
if(active)
UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_ALARM)
UnregisterSignal(active, COMSIG_SUPERMATTER_DELAM_START_ALARM)
/**
* Sends an SM delam alert to the computer.
@@ -90,6 +93,7 @@
* the supermatter probably don't need constant beeping to distract them.
*/
/datum/computer_file/program/supermatter_monitor/proc/send_alert()
SIGNAL_HANDLER
if(!computer.get_ntnet_status())
return
if(computer.active_program != src)
@@ -106,12 +110,13 @@
* minimized or closed to avoid double-notifications.
*/
/datum/computer_file/program/supermatter_monitor/proc/send_start_alert()
SIGNAL_HANDLER
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()
/datum/computer_file/program/supermatter_monitor/ui_data(mob/user)
var/list/data = get_header_data()
if(istype(active))
@@ -125,30 +130,9 @@
active = null
return
data["active"] = TRUE
data["SM_integrity"] = active.get_integrity()
data["SM_power"] = active.power
data["SM_ambienttemp"] = air.return_temperature()
data["SM_ambientpressure"] = air.return_pressure()
//data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01)
var/list/gasdata = list()
data += active.ui_data()
data["singlecrystal"] = FALSE
if(air.total_moles())
for(var/gasid in air.get_gases())
var/amount = air.get_moles(gasid)
if(amount)
gasdata.Add(list(list(
"name"= GLOB.gas_data.names[gasid],
"amount" = round(100*amount/air.total_moles(),0.01))))
else
for(var/gasid in air.get_gases())
gasdata.Add(list(list(
"name"= GLOB.gas_data.names[gasid],
"amount" = 0)))
data["gases"] = gasdata
else
var/list/SMS = list()
for(var/obj/machinery/power/supermatter_crystal/S in supermatters)
@@ -185,3 +169,13 @@
active = S
set_signals()
return TRUE
/datum/computer_file/program/supermatter_monitor/proc/react_to_del(datum/source)
SIGNAL_HANDLER
clear_supermatter(source)
/datum/computer_file/program/supermatter_monitor/proc/clear_supermatter(matter)
supermatters -= matter
if(matter == active)
active = null
UnregisterSignal(matter, COMSIG_PARENT_QDELETING)

View File

@@ -4,22 +4,34 @@
icon = 'icons/obj/module.dmi'
icon_state = "std_mod"
w_class = WEIGHT_CLASS_TINY // w_class limits which devices can contain this component.
w_class = WEIGHT_CLASS_TINY // w_class limits which devices can contain this component.
// 1: PDAs/Tablets, 2: Laptops, 3-4: Consoles only
var/obj/item/modular_computer/holder = null
// Computer that holds this hardware, if any.
var/power_usage = 0 // If the hardware uses extra power, change this.
var/enabled = TRUE // If the hardware is turned off set this to 0.
var/critical = FALSE // Prevent disabling for important component, like the CPU.
var/can_install = TRUE // Prevents direct installation of removable media.
var/expansion_hw = FALSE // Hardware that fits into expansion bays.
var/removable = TRUE // Whether the hardware is removable or not.
var/damage = 0 // Current damage level
var/max_damage = 100 // Maximal damage level.
var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
var/malfunction_probability = 10// Chance of malfunction when the component is damaged
// If the hardware uses extra power, change this.
var/power_usage = 0
// If the hardware is turned off set this to 0.
var/enabled = TRUE
// Prevent disabling for important component, like the CPU.
var/critical = FALSE
// Prevents direct installation of removable media.
var/can_install = TRUE
// Hardware that fits into expansion bays.
var/expansion_hw = FALSE
// Whether the hardware is removable or not.
var/removable = TRUE
// Current damage level
var/damage = 0
// Maximal damage level.
var/max_damage = 100
// "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
var/damage_malfunction = 20
// "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
var/damage_failure = 50
// Chance of malfunction when the component is damaged
var/malfunction_probability = 10
// What define is used to qualify this piece of hardware? Important for upgraded versions of the same hardware.
var/device_type
/obj/item/computer_hardware/New(obj/L)
@@ -38,10 +50,10 @@
if(istype(I, /obj/item/stack/cable_coil))
var/obj/item/stack/S = I
if(obj_integrity == max_integrity)
to_chat(user, "<span class='warning'>\The [src] doesn't seem to require repairs.</span>")
to_chat(user, span_warning("\The [src] doesn't seem to require repairs."))
return 1
if(S.use(1))
to_chat(user, "<span class='notice'>You patch up \the [src] with a bit of \the [I].</span>")
to_chat(user, span_notice("You patch up \the [src] with a bit of \the [I]."))
obj_integrity = min(obj_integrity + 10, max_integrity)
return 1
@@ -78,11 +90,11 @@
/obj/item/computer_hardware/examine(mob/user)
. = ..()
if(damage > damage_failure)
. += "<span class='danger'>It seems to be severely damaged!</span>"
. += span_danger("It seems to be severely damaged!")
else if(damage > damage_malfunction)
. += "<span class='warning'>It seems to be damaged!</span>"
. += span_warning("It seems to be damaged!")
else if(damage)
. += "<span class='notice'>It seems to be slightly damaged.</span>"
. += span_notice("It seems to be slightly damaged.")
// Component-side compatibility check.
/obj/item/computer_hardware/proc/can_install(obj/item/modular_computer/M, mob/living/user = null)
@@ -93,8 +105,9 @@
return
// Called when component is removed from PC.
/obj/item/computer_hardware/proc/on_remove(obj/item/modular_computer/M, mob/living/user = null)
try_eject(forced = TRUE)
/obj/item/computer_hardware/proc/on_remove(obj/item/modular_computer/M, mob/living/user)
if(M.physical || !QDELETED(M))
try_eject(forced = TRUE)
// Called when someone tries to insert something in it - paper in printer, card in card reader, etc.
/obj/item/computer_hardware/proc/try_insert(obj/item/I, mob/living/user = null)

View File

@@ -7,13 +7,14 @@
device_type = MC_AI
expansion_hw = TRUE
var/obj/item/aicard/stored_card = null
var/obj/item/aicard/stored_card
var/locked = FALSE
/obj/item/computer_hardware/ai_slot/handle_atom_del(atom/A)
if(A == stored_card)
try_eject(forced = TRUE)
. = ..()
///What happens when the intellicard is removed (or deleted) from the module, through try_eject() or not.
/obj/item/computer_hardware/ai_slot/Exited(atom/movable/gone, direction)
if(stored_card == gone)
stored_card = null
return ..()
/obj/item/computer_hardware/ai_slot/examine(mob/user)
. = ..()
@@ -28,34 +29,33 @@
return FALSE
if(stored_card)
to_chat(user, "<span class='warning'>You try to insert \the [I] into \the [src], but the slot is occupied.</span>")
to_chat(user, span_warning("You try to insert \the [I] into \the [src], but the slot is occupied."))
return FALSE
if(user && !user.transferItemToLoc(I, src))
return FALSE
stored_card = I
to_chat(user, "<span class='notice'>You insert \the [I] into \the [src].</span>")
to_chat(user, span_notice("You insert \the [I] into \the [src]."))
return TRUE
/obj/item/computer_hardware/ai_slot/try_eject(mob/living/user = null, forced = FALSE)
if(!stored_card)
to_chat(user, "<span class='warning'>There is no card in \the [src].</span>")
to_chat(user, span_warning("There is no card in \the [src]."))
return FALSE
if(locked && !forced)
to_chat(user, "<span class='warning'>Safeties prevent you from removing the card until reconstruction is complete...</span>")
to_chat(user, span_warning("Safeties prevent you from removing the card until reconstruction is complete..."))
return FALSE
if(stored_card)
to_chat(user, "<span class='notice'>You remove [stored_card] from [src].</span>")
to_chat(user, span_notice("You remove [stored_card] from [src]."))
locked = FALSE
if(user)
if(Adjacent(user))
user.put_in_hands(stored_card)
else
stored_card.forceMove(drop_location())
stored_card = null
return TRUE
return FALSE
@@ -64,6 +64,6 @@
if(..())
return
if(I.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, "<span class='notice'>You press down on the manual eject button with \the [I].</span>")
to_chat(user, span_notice("You press down on the manual eject button with \the [I]."))
try_eject(user, TRUE)
return

View File

@@ -4,25 +4,28 @@
icon_state = "cell_con"
critical = 1
malfunction_probability = 1
var/obj/item/stock_parts/cell/battery = null
var/obj/item/stock_parts/cell/battery
device_type = MC_CELL
/obj/item/computer_hardware/battery/get_cell()
return battery
/obj/item/computer_hardware/battery/New(loc, battery_type = null)
/obj/item/computer_hardware/battery/Initialize(mapload, battery_type)
. = ..()
if(battery_type)
battery = new battery_type(src)
..()
/obj/item/computer_hardware/battery/Destroy()
. = ..()
QDEL_NULL(battery)
battery = null
return ..()
/obj/item/computer_hardware/battery/handle_atom_del(atom/A)
if(A == battery)
try_eject(forced = TRUE)
. = ..()
///What happens when the battery is removed (or deleted) from the module, through try_eject() or not.
/obj/item/computer_hardware/battery/Exited(atom/movable/gone, direction)
if(battery == gone)
battery = null
if(holder?.enabled && !holder.use_power())
holder.shutdown_computer()
return ..()
/obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null)
if(!holder)
@@ -32,46 +35,33 @@
return FALSE
if(battery)
to_chat(user, "<span class='warning'>You try to connect \the [I] to \the [src], but its connectors are occupied.</span>")
to_chat(user, span_warning("You try to connect \the [I] to \the [src], but its connectors are occupied."))
return FALSE
if(I.w_class > holder.max_hardware_size)
to_chat(user, "<span class='warning'>This power cell is too large for \the [holder]!</span>")
to_chat(user, span_warning("This power cell is too large for \the [holder]!"))
return FALSE
if(user && !user.transferItemToLoc(I, src))
return FALSE
battery = I
to_chat(user, "<span class='notice'>You connect \the [I] to \the [src].</span>")
to_chat(user, span_notice("You connect \the [I] to \the [src]."))
return TRUE
/obj/item/computer_hardware/battery/try_eject(mob/living/user = null, forced = FALSE)
/obj/item/computer_hardware/battery/try_eject(mob/living/user, forced = FALSE)
if(!battery)
to_chat(user, "<span class='warning'>There is no power cell connected to \the [src].</span>")
to_chat(user, span_warning("There is no power cell connected to \the [src]."))
return FALSE
else
if(user)
user.put_in_hands(battery)
to_chat(user, span_notice("You detach \the [battery] from \the [src]."))
else
battery.forceMove(drop_location())
to_chat(user, "<span class='notice'>You detach \the [battery] from \the [src].</span>")
battery = null
if(holder)
if(holder.enabled && !holder.use_power())
holder.shutdown_computer()
return TRUE
/obj/item/stock_parts/cell/computer
name = "standard battery"
desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops."
@@ -80,7 +70,6 @@
w_class = WEIGHT_CLASS_TINY
maxcharge = 750
/obj/item/stock_parts/cell/computer/advanced
name = "advanced battery"
desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices."

View File

@@ -1,17 +1,31 @@
/obj/item/computer_hardware/card_slot
name = "primary RFID card module" // \improper breaks the find_hardware_by_name proc
name = "primary RFID card module" // \improper breaks the find_hardware_by_name proc
desc = "A module allowing this computer to read or write data on ID cards. Necessary for some programs to run properly."
power_usage = 10 //W
icon_state = "card_mini"
w_class = WEIGHT_CLASS_TINY
device_type = MC_CARD
var/obj/item/card/id/stored_card = null
var/obj/item/card/id/stored_card
/obj/item/computer_hardware/card_slot/handle_atom_del(atom/A)
if(A == stored_card)
try_eject(null, TRUE)
. = ..()
///What happens when the ID card is removed (or deleted) from the module, through try_eject() or not.
/obj/item/computer_hardware/card_slot/Exited(atom/movable/gone, direction)
if(stored_card == gone)
stored_card = null
if(holder)
if(holder.active_program)
holder.active_program.event_idremoved(0)
for(var/p in holder.idle_threads)
var/datum/computer_file/program/computer_program = p
computer_program.event_idremoved(1)
holder.update_slot_icon()
if(ishuman(holder.loc))
var/mob/living/carbon/human/human_wearer = holder.loc
if(human_wearer.wear_id == holder)
human_wearer.sec_hud_set_ID()
return ..()
/obj/item/computer_hardware/card_slot/Destroy()
try_eject(forced = TRUE)
@@ -47,6 +61,11 @@
if(stored_card)
return FALSE
// item instead of player is checked so telekinesis will still work if the item itself is close
if(!in_range(src, I))
return FALSE
if(user)
if(!user.transferItemToLoc(I, src))
return FALSE
@@ -54,38 +73,32 @@
I.forceMove(src)
stored_card = I
to_chat(user, "<span class='notice'>You insert \the [I] into \the [expansion_hw ? "secondary":"primary"] [src].</span>")
to_chat(user, span_notice("You insert \the [I] into \the [expansion_hw ? "secondary":"primary"] [src]."))
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.sec_hud_set_ID()
var/holder_loc = holder.loc
if(ishuman(holder_loc))
var/mob/living/carbon/human/human_wearer = holder_loc
if(human_wearer.wear_id == holder)
human_wearer.sec_hud_set_ID()
holder.update_slot_icon()
return TRUE
/obj/item/computer_hardware/card_slot/try_eject(mob/living/user = null, forced = FALSE)
if(!stored_card)
to_chat(user, "<span class='warning'>There are no cards in \the [src].</span>")
to_chat(user, span_warning("There are no cards in \the [src]."))
return FALSE
if(user)
if(user && !issilicon(user) && in_range(src, user))
user.put_in_hands(stored_card)
else
stored_card.forceMove(drop_location())
stored_card = null
if(holder)
if(holder.active_program)
holder.active_program.event_idremoved(0)
for(var/p in holder.idle_threads)
var/datum/computer_file/program/computer_program = p
computer_program.event_idremoved(1)
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
human_user.sec_hud_set_ID()
to_chat(user, "<span class='notice'>You remove the card from \the [src].</span>")
to_chat(user, span_notice("You remove the card from \the [src]."))
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
return TRUE
/obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user)
@@ -93,11 +106,11 @@
return
if(I.tool_behaviour == TOOL_SCREWDRIVER)
if(stored_card)
to_chat(user, "<span class='notice'>You press down on the manual eject button with \the [I].</span>")
to_chat(user, span_notice("You press down on the manual eject button with \the [I]."))
try_eject(user)
return
swap_slot()
to_chat(user, "<span class='notice'>You adjust the connecter to fit into [expansion_hw ? "an expansion bay" : "the primary ID bay"].</span>")
to_chat(user, span_notice("You adjust the connecter to fit into [expansion_hw ? "an expansion bay" : "the primary ID bay"]."))
/**
*Swaps the card_slot hardware between using the dedicated card slot bay on a computer, and using an expansion bay.

View File

@@ -8,19 +8,19 @@
device_type = MC_HDD
var/max_capacity = 128
var/used_capacity = 0
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
/obj/item/computer_hardware/hard_drive/on_remove(obj/item/modular_computer/MC, mob/user)
MC.shutdown_computer()
/obj/item/computer_hardware/hard_drive/proc/install_default_programs()
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
/obj/item/computer_hardware/hard_drive/examine(user)
. = ..()
. += "<span class='notice'>It has [max_capacity] GQ of storage capacity.</span>"
. += span_notice("It has [max_capacity] GQ of storage capacity.")
/obj/item/computer_hardware/hard_drive/diagnostics(mob/user)
..()
@@ -117,7 +117,7 @@
return null
/obj/item/computer_hardware/hard_drive/Destroy()
stored_files = null
QDEL_LIST(stored_files)
return ..()
/obj/item/computer_hardware/hard_drive/Initialize()
@@ -129,7 +129,7 @@
name = "advanced hard disk drive"
desc = "A hybrid HDD, for use in higher grade computers where balance between power efficiency and capacity is desired."
max_capacity = 256
power_usage = 50 // Hybrid, medium capacity and medium power storage
power_usage = 50 // Hybrid, medium capacity and medium power storage
icon_state = "harddisk_mini"
w_class = WEIGHT_CLASS_SMALL
@@ -137,7 +137,7 @@
name = "super hard disk drive"
desc = "A high capacity HDD, for use in cluster storage solutions where capacity is more important than power efficiency."
max_capacity = 512
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link.
icon_state = "harddisk_mini"
w_class = WEIGHT_CLASS_SMALL
@@ -161,8 +161,8 @@
// For borg integrated tablets. No downloader.
/obj/item/computer_hardware/hard_drive/small/integrated/install_default_programs()
store_file(new /datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new /datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
store_file(new /datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new /datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation.
store_file(new /datum/computer_file/program/robotact(src))

View File

@@ -3,8 +3,9 @@
desc = "A basic wireless network card for usage with standard NTNet frequencies."
power_usage = 50
icon_state = "radio_mini"
var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
// network_id = NETWORK_CARDS // Network we are on
var/hardware_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
var/long_range = 0
var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks.
malfunction_probability = 1
@@ -13,7 +14,7 @@
/obj/item/computer_hardware/network_card/diagnostics(mob/user)
..()
to_chat(user, "NIX Unique ID: [identification_id]")
to_chat(user, "NIX Unique ID: [hardware_id]")
to_chat(user, "NIX User Tag: [identification_string]")
to_chat(user, "Supported protocols:")
to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread")
@@ -24,11 +25,11 @@
/obj/item/computer_hardware/network_card/New(l)
..()
identification_id = ntnet_card_uid++
hardware_id = ntnet_card_uid++
// Returns a string identifier of this network card
/obj/item/computer_hardware/network_card/proc/get_network_tag()
return "[identification_string] (NID [identification_id])"
return "[identification_string] (NID [hardware_id])"
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
/obj/item/computer_hardware/network_card/proc/get_signal(specific_action = 0)

View File

@@ -11,11 +11,11 @@
/obj/item/computer_hardware/printer/diagnostics(mob/living/user)
..()
to_chat(user, "<span class='notice'>Paper level: [stored_paper]/[max_paper].</span>")
to_chat(user, span_notice("Paper level: [stored_paper]/[max_paper]."))
/obj/item/computer_hardware/printer/examine(mob/user)
. = ..()
. += "<span class='notice'>Paper level: [stored_paper]/[max_paper].</span>"
. += span_notice("Paper level: [stored_paper]/[max_paper].")
/obj/item/computer_hardware/printer/proc/print_text(text_to_print, paper_title = "")
@@ -33,7 +33,7 @@
P.info = text_to_print
if(paper_title)
P.name = paper_title
P.update_icon()
P.update_appearance()
stored_paper--
P = null
return TRUE
@@ -41,12 +41,12 @@
/obj/item/computer_hardware/printer/try_insert(obj/item/I, mob/living/user = null)
if(istype(I, /obj/item/paper))
if(stored_paper >= max_paper)
to_chat(user, "<span class='warning'>You try to add \the [I] into [src], but its paper bin is full!</span>")
to_chat(user, span_warning("You try to add \the [I] into [src], but its paper bin is full!"))
return FALSE
if(user && !user.temporarilyRemoveItemFromInventory(I))
return FALSE
to_chat(user, "<span class='notice'>You insert \the [I] into [src]'s paper recycler.</span>")
to_chat(user, span_notice("You insert \the [I] into [src]'s paper recycler."))
qdel(I)
stored_paper++
return TRUE

View File

@@ -55,7 +55,7 @@
/obj/item/computer_hardware/recharger/wired/can_install(obj/item/modular_computer/M, mob/living/user = null)
if(ismachinery(M.physical) && M.physical.anchored)
return ..()
to_chat(user, "<span class='warning'>\The [src] is incompatible with portable computers!</span>")
to_chat(user, span_warning("\The [src] is incompatible with portable computers!"))
return FALSE
/obj/item/computer_hardware/recharger/wired/use_power(amount, charging=0)
@@ -96,3 +96,4 @@
/obj/item/computer_hardware/recharger/lambda/use_power(amount, charging=0)
return 1

View File

@@ -6,3 +6,12 @@
w_class = WEIGHT_CLASS_TINY
device_type = MC_SENSORS
expansion_hw = TRUE
/obj/item/computer_hardware/radio_card
name = "integrated radio card"
desc = "An integrated signaling assembly for computers to send an outgoing frequency signal. Required by certain programs."
icon_state = "signal_card"
w_class = WEIGHT_CLASS_TINY
device_type = MC_SIGNALER
expansion_hw = TRUE
power_usage = 10

View File

@@ -13,19 +13,19 @@
var/obj/item/modular_computer/tablet/fabricated_tablet = null
// Utility vars
var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen
var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet
var/total_price = 0 // Price of currently vended device.
var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen
var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet
var/total_price = 0 // Price of currently vended device.
var/credits = 0
// Device loadout
var/dev_cpu = 1 // 1: Default, 2: Upgraded
var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced
var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced
var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range
var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY)
var/dev_printer = 0 // 0: None, 1: Standard
var/dev_card = 0 // 0: None, 1: Standard
var/dev_cpu = 1 // 1: Default, 2: Upgraded
var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced
var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced
var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range
var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY)
var/dev_printer = 0 // 0: None, 1: Standard
var/dev_card = 0 // 0: None, 1: Standard
// Removes all traces of old order and allows you to begin configuration from scratch.
/obj/machinery/lapvend/proc/reset_order()
@@ -48,7 +48,7 @@
// Recalculates the price and optionally even fabricates the device.
/obj/machinery/lapvend/proc/fabricate_and_recalc_price(fabricate = FALSE)
total_price = 0
if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles
if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles
var/obj/item/computer_hardware/battery/battery_module = null
if(fabricate)
fabricated_laptop = new /obj/item/modular_computer/laptop/buildable(src)
@@ -111,7 +111,7 @@
fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot/secondary)
return total_price
else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this.
else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this.
var/obj/item/computer_hardware/battery/battery_module = null
if(fabricate)
fabricated_tablet = new(src)
@@ -241,13 +241,13 @@
if(!user.temporarilyRemoveItemFromInventory(c))
return
credits += c.value
visible_message("<span class='info'><span class='name'>[user]</span> inserts [c.value] cr into [src].</span>")
visible_message(span_info("[span_name("[user]")] inserts [c.value] cr into [src]."))
qdel(c)
return
else if(istype(I, /obj/item/holochip))
var/obj/item/holochip/HC = I
credits += HC.credits
visible_message("<span class='info'>[user] inserts a [HC.credits] cr holocredit chip into [src].</span>")
visible_message(span_info("[user] inserts a [HC.credits] cr holocredit chip into [src]."))
qdel(HC)
return
else if(istype(I, /obj/item/card/id))

View File

@@ -1,127 +1,201 @@
/**
* Clipboard
*/
/obj/item/clipboard
name = "clipboard"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "clipboard"
item_state = "clipboard"
// inhand_icon_state = "clipboard"
// worn_icon_state = "clipboard"
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 7
var/obj/item/pen/haspen //The stored pen.
var/obj/item/paper/toppaper //The topmost piece of paper.
slot_flags = ITEM_SLOT_BELT
resistance_flags = FLAMMABLE
/// The stored pen
var/obj/item/pen/pen
/// Is the pen integrated?
var/integrated_pen = FALSE
/**
* Weakref of the topmost piece of paper
*
* This is used for the paper displayed on the clipboard's icon
* and it is the one attacked, when attacking the clipboard.
* (As you can't organise contents directly in BYOND)
*/
var/datum/weakref/toppaper_ref
/obj/item/clipboard/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return BRUTELOSS//the clipboard's clip is very strong. industrial duty. can kill a man easily.
user.visible_message(span_suicide("[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS //The clipboard's clip is very strong. Industrial duty. Can kill a man easily.
/obj/item/clipboard/Initialize()
update_icon()
update_appearance()
. = ..()
/obj/item/clipboard/Destroy()
QDEL_NULL(haspen)
QDEL_NULL(toppaper) //let movable/Destroy handle the rest
QDEL_NULL(pen)
return ..()
/obj/item/clipboard/examine()
. = ..()
if(!integrated_pen && pen)
. += span_notice("Alt-click to remove [pen].")
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(toppaper)
. += span_notice("Right-click to remove [toppaper].")
/// Take out the topmost paper
/obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user)
if(!istype(paper))
return
paper.forceMove(user.loc)
user.put_in_hands(paper)
to_chat(user, span_notice("You remove [paper] from [src]."))
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(paper == toppaper)
UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
toppaper_ref = null
var/obj/item/paper/newtop = locate(/obj/item/paper) in src
if(newtop && (newtop != paper))
toppaper_ref = WEAKREF(newtop)
else
toppaper_ref = null
update_icon()
/obj/item/clipboard/proc/remove_pen(mob/user)
pen.forceMove(user.loc)
user.put_in_hands(pen)
to_chat(user, span_notice("You remove [pen] from [src]."))
pen = null
update_icon()
/obj/item/clipboard/AltClick(mob/user)
..()
if(pen)
if(integrated_pen)
to_chat(user, span_warning("You can't seem to find a way to remove [src]'s [pen]."))
else
remove_pen(user)
/obj/item/clipboard/update_overlays()
. = ..()
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(toppaper)
. += toppaper.icon_state
. += toppaper.overlays
if(haspen)
if(pen)
. += "clipboard_pen"
. += "clipboard_over"
/obj/item/clipboard/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/paper))
if(!user.transferItemToLoc(W, src))
/obj/item/clipboard/attack_hand(mob/user, act_intent)
if(act_intent != INTENT_HELP)
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
remove_paper(toppaper, user)
return TRUE
. = ..()
/obj/item/clipboard/attackby(obj/item/weapon, mob/user, params)
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(istype(weapon, /obj/item/paper))
//Add paper into the clipboard
if(!user.transferItemToLoc(weapon, src))
return
toppaper = W
to_chat(user, "<span class='notice'>You clip the paper onto \the [src].</span>")
update_icon()
if(toppaper)
UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
RegisterSignal(weapon, COMSIG_ATOM_UPDATED_ICON, .proc/on_top_paper_change)
toppaper_ref = WEAKREF(weapon)
to_chat(user, span_notice("You clip [weapon] onto [src]."))
else if(istype(weapon, /obj/item/pen) && !pen)
//Add a pen into the clipboard, attack (write) if there is already one
if(!usr.transferItemToLoc(weapon, src))
return
pen = weapon
to_chat(usr, span_notice("You slot [weapon] into [src]."))
else if(toppaper)
toppaper.attackby(user.get_active_held_item(), user)
update_icon()
update_appearance()
/obj/item/clipboard/attack_self(mob/user)
var/dat = "<title>Clipboard</title>"
if(haspen)
dat += "<A href='?src=[REF(src)];pen=1'>Remove Pen</A><BR><HR>"
else
dat += "<A href='?src=[REF(src)];addpen=1'>Add Pen</A><BR><HR>"
//The topmost paper. You can't organise contents directly in byond, so this is what we're stuck with. -Pete
if(toppaper)
var/obj/item/paper/P = toppaper
dat += "<A href='?src=[REF(src)];write=[REF(P)]'>Write</A> <A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A> - <A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A><BR><HR>"
for(P in src)
if(P == toppaper)
continue
dat += "<A href='?src=[REF(src)];write=[REF(P)]'>Write</A> <A href='?src=[REF(src)];remove=[REF(P)]'>Remove</A> <A href='?src=[REF(src)];top=[REF(P)]'>Move to top</A> - <A href='?src=[REF(src)];read=[REF(P)]'>[P.name]</A><BR>"
user << browse(dat, "window=clipboard")
onclose(user, "clipboard")
add_fingerprint(usr)
ui_interact(user)
return
/obj/item/clipboard/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Clipboard")
ui.open()
/obj/item/clipboard/Topic(href, href_list)
..()
if(usr.stat != CONSCIOUS || usr.restrained()) //HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED))
/obj/item/clipboard/ui_data(mob/user)
// prepare data for TGUI
var/list/data = list()
data["pen"] = "[pen]"
data["integrated_pen"] = integrated_pen
var/obj/item/paper/toppaper = toppaper_ref?.resolve()
data["top_paper"] = "[toppaper]"
data["top_paper_ref"] = "[REF(toppaper)]"
data["paper"] = list()
data["paper_ref"] = list()
for(var/obj/item/paper/paper in src)
if(paper == toppaper)
continue
data["paper"] += "[paper]"
data["paper_ref"] += "[REF(paper)]"
return data
/obj/item/clipboard/ui_act(action, params)
. = ..()
if(.)
return
if(usr.contents.Find(src))
if(usr.stat != CONSCIOUS || usr.restrained())
return
if(href_list["pen"])
if(haspen)
haspen.forceMove(usr.loc)
usr.put_in_hands(haspen)
haspen = null
switch(action)
// Take the pen out
if("remove_pen")
if(pen)
if(!integrated_pen)
remove_pen(usr)
else
to_chat(usr, span_warning("You can't seem to find a way to remove [src]'s [pen]."))
. = TRUE
// Take paper out
if("remove_paper")
var/obj/item/paper/paper = locate(params["ref"]) in src
if(istype(paper))
remove_paper(paper, usr)
. = TRUE
// Look at (or edit) the paper
if("edit_paper")
var/obj/item/paper/paper = locate(params["ref"]) in src
if(istype(paper))
paper.ui_interact(usr)
update_icon()
. = TRUE
// Move paper to the top
if("move_top_paper")
var/obj/item/paper/paper = locate(params["ref"]) in src
if(istype(paper))
toppaper_ref = WEAKREF(paper)
to_chat(usr, span_notice("You move [paper] to the top."))
update_icon()
. = TRUE
// Rename the paper (it's a verb)
if("rename_paper")
var/obj/item/paper/paper = locate(params["ref"]) in src
if(istype(paper))
paper.rename()
update_icon()
. = TRUE
if(href_list["addpen"])
if(!haspen)
var/obj/item/held = usr.get_active_held_item()
if(istype(held, /obj/item/pen))
var/obj/item/pen/W = held
if(!usr.transferItemToLoc(W, src))
return
haspen = W
to_chat(usr, "<span class='notice'>You slot [W] into [src].</span>")
if(href_list["write"])
var/obj/item/P = locate(href_list["write"]) in src
if(istype(P))
if(usr.get_active_held_item())
P.attackby(usr.get_active_held_item(), usr)
if(href_list["remove"])
var/obj/item/P = locate(href_list["remove"]) in src
if(istype(P))
P.forceMove(usr.loc)
usr.put_in_hands(P)
if(P == toppaper)
toppaper = null
var/obj/item/paper/newtop = locate(/obj/item/paper) in src
if(newtop && (newtop != P))
toppaper = newtop
else
toppaper = null
if(href_list["read"])
var/obj/item/paper/P = locate(href_list["read"]) in src
if(istype(P))
usr.examinate(P)
if(href_list["top"])
var/obj/item/P = locate(href_list["top"]) in src
if(istype(P))
toppaper = P
to_chat(usr, "<span class='notice'>You move [P.name] to the top.</span>")
//Update everything
attack_self(usr)
update_icon()
/**
* This is a simple proc to handle calling update_icon() upon receiving the top paper's `COMSIG_ATOM_UPDATE_APPEARANCE`.
*/
/obj/item/clipboard/proc/on_top_paper_change()
SIGNAL_HANDLER
update_appearance()

View File

@@ -628,6 +628,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
//Tells the engi team to get their butt in gear
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
if(damage_archived < warning_point) //If damage_archive is under the warning point, this is the very first cycle that we've reached said point.
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_START_ALARM)
if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY)
alarm()
@@ -635,6 +637,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(damage > emergency_point)
// it's bad, LETS YELL
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel, list(SPAN_YELL))
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
lastwarning = REALTIMEOFDAY
if(!has_reached_emergency)
investigate_log("has reached the emergency point for the first time.", INVESTIGATE_SUPERMATTER)
@@ -642,6 +645,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
has_reached_emergency = TRUE
else if(damage >= damage_archived) // The damage is still going up
radio.talk_into(src, "[warning_alert] Integrity: [get_integrity()]%", engineering_channel)
SEND_SIGNAL(src, COMSIG_SUPERMATTER_DELAM_ALARM)
lastwarning = REALTIMEOFDAY - (WARNING_DELAY * 5)
else // Phew, we're safe

View File

@@ -372,11 +372,11 @@
/obj/machinery/bci_implanter/update_overlays()
var/list/overlays = ..()
if ((machine_stat & MAINT) || panel_open)
if ((stat & MAINT) || panel_open)
overlays += "maint"
return overlays
if (machine_stat & (NOPOWER|BROKEN))
if (stat & (NOPOWER|BROKEN))
return overlays
if (busy || locked)
@@ -448,9 +448,9 @@
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/machinery/bci_implanter/proc/start_process()
if (machine_stat & (NOPOWER|BROKEN))
if (stat & (NOPOWER|BROKEN))
return
if ((machine_stat & MAINT) || panel_open)
if ((stat & MAINT) || panel_open)
return
if (!occupant || busy)
return