i think it works

MAJOR antag backend update
- you cannot bruteforce the pen anymore
- uplink now uses bitflag to lock purchases
- poplock is handled entirely by the buyable uplink items
- tgui antag intro (for selected ones)
This commit is contained in:
LetterN
2021-10-30 11:45:50 +08:00
parent f7b898a2a9
commit 99019166e4
117 changed files with 3049 additions and 1868 deletions
@@ -12,13 +12,13 @@
rad_flags = RAD_PROTECT_CONTENTS
armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
var/last_world_time = "00:00"
var/list/last_header_icons
///Looping sound for when the computer is on
@@ -26,19 +26,19 @@
///Whether or not this modular computer uses the looping sound
var/looping_sound = TRUE
var/base_active_power_usage = 50 // 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 = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
var/base_active_power_usage = 50 // 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 = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
// 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.
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/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/display_overlays = TRUE // If FALSE, don't draw overlays on this device at all
var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4.
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
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/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/display_overlays = TRUE // If FALSE, don't draw overlays on this device at all
var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4.
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
/// List of "connection ports" in this computer and the components with which they are plugged
var/list/all_components = list()
@@ -47,11 +47,11 @@
/// Number of total expansion bays this computer has available.
var/max_bays = 0
var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with.
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
var/has_light = FALSE //If the computer has a flashlight/LED light/what-have-you installed
var/comp_light_luminosity = 3 //The brightness of that light
var/comp_light_color //The color of that light
var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with.
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
var/has_light = FALSE //If the computer has a flashlight/LED light/what-have-you installed
var/comp_light_luminosity = 3 //The brightness of that light
var/comp_light_color //The color of that light
/obj/item/modular_computer/Initialize()
@@ -62,13 +62,12 @@
comp_light_color = "#FFFFFF"
idle_threads = list()
if(looping_sound)
soundloop = new(list(src), enabled)
update_icon()
soundloop = new(src, enabled)
update_appearance()
/obj/item/modular_computer/Destroy()
kill_program(forced = TRUE)
STOP_PROCESSING(SSobj, src)
QDEL_NULL(soundloop)
for(var/H in all_components)
var/obj/item/computer_hardware/CH = all_components[H]
if(CH.holder == src)
@@ -76,9 +75,19 @@
CH.holder = null
all_components.Remove(CH.device_type)
qdel(CH)
//Some components will actually try and interact with this, so let's do it later
QDEL_NULL(soundloop)
physical = null
return ..()
/**
* Plays a ping sound.
*
* Timers runtime if you try to make them call playsound. Yep.
*/
/obj/item/modular_computer/proc/play_ping()
playsound(loc, 'sound/machines/ping.ogg', get_clamped_volume(), FALSE, -1)
/obj/item/modular_computer/AltClick(mob/user)
..()
if(issilicon(user))
@@ -98,14 +107,34 @@
/obj/item/modular_computer/GetID()
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
if(card_slot)
return card_slot.GetID()
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
var/obj/item/card/id/first_id = card_slot?.GetID()
var/obj/item/card/id/second_id = card_slot2?.GetID()
// If we don't have both ID slots filled, pick the one that is filled.
if(first_id)
return first_id
if(second_id)
return second_id
// Otherwise, we have no ID at all.
return ..()
/obj/item/modular_computer/RemoveID()
var/obj/item/computer_hardware/card_slot/card_slot2 = all_components[MC_CARD2]
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
return (card_slot2?.try_eject() || card_slot?.try_eject()) //Try the secondary one first.
var/removed_id = (card_slot2?.try_eject() || card_slot?.try_eject())
if(removed_id)
if(ishuman(loc))
var/mob/living/carbon/human/human_wearer = loc
if(human_wearer.wear_id == src)
human_wearer.sec_hud_set_ID()
update_slot_icon()
return removed_id
return ..()
/obj/item/modular_computer/InsertID(obj/item/inserting_item)
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
@@ -118,7 +147,13 @@
return FALSE
if((card_slot?.try_insert(inserting_id)) || (card_slot2?.try_insert(inserting_id)))
if(ishuman(loc))
var/mob/living/carbon/human/human_wearer = loc
if(human_wearer.wear_id == src)
human_wearer.sec_hud_set_ID()
update_slot_icon()
return TRUE
return FALSE
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
@@ -142,9 +177,8 @@
turn_on(user)
/obj/item/modular_computer/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
obj_flags |= EMAGGED //Mostly for consistancy purposes; the programs will do their own emag handling
var/newemag = FALSE
@@ -155,36 +189,31 @@
if(app.run_emag())
newemag = TRUE
if(newemag)
to_chat(user, "<span class='notice'>You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past.</span>")
to_chat(user, span_notice("You swipe \the [src]. A console window momentarily fills the screen, with white text rapidly scrolling past."))
return TRUE
to_chat(user, "<span class='notice'>You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it.</span>")
to_chat(user, span_notice("You swipe \the [src]. A console window fills the screen, but it quickly closes itself after only a few lines are written to it."))
return FALSE
/obj/item/modular_computer/examine(mob/user)
. = ..()
if(obj_integrity <= integrity_failure * max_integrity)
. += "<span class='danger'>It is heavily damaged!</span>"
. += span_danger("It is heavily damaged!")
else if(obj_integrity < max_integrity)
. += "<span class='warning'>It is damaged.</span>"
. += span_warning("It is damaged.")
. += get_modular_computer_parts_examine(user)
/obj/item/modular_computer/update_icon_state()
if(!enabled)
icon_state = icon_state_unpowered
else
icon_state = icon_state_powered
icon_state = enabled ? icon_state_powered : icon_state_unpowered
return ..()
/obj/item/modular_computer/update_overlays()
. = ..()
if(!display_overlays)
return
if(enabled)
if(active_program)
. += active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu
else
. += icon_state_menu
if(enabled)
. += active_program?.program_icon_state || icon_state_menu
if(obj_integrity <= integrity_failure * max_integrity)
. += "bsod"
. += "broken"
@@ -201,9 +230,9 @@
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
if(obj_integrity <= integrity_failure * max_integrity)
if(issynth)
to_chat(user, "<span class='warning'>You send an activation signal to \the [src], but it responds with an error code. It must be damaged.</span>")
to_chat(user, span_warning("You send an activation signal to \the [src], but it responds with an error code. It must be damaged."))
else
to_chat(user, "<span class='warning'>You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.</span>")
to_chat(user, span_warning("You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."))
return FALSE
// If we have a recharger, enable it automatically. Lets computer without a battery work.
@@ -213,20 +242,20 @@
if(all_components[MC_CPU] && use_power()) // use_power() checks if the PC is powered
if(issynth)
to_chat(user, "<span class='notice'>You send an activation signal to \the [src], turning it on.</span>")
to_chat(user, span_notice("You send an activation signal to \the [src], turning it on."))
else
to_chat(user, "<span class='notice'>You press the power button and start up \the [src].</span>")
to_chat(user, span_notice("You press the power button and start up \the [src]."))
if(looping_sound)
soundloop.start()
enabled = 1
update_icon()
update_appearance()
ui_interact(user)
return TRUE
else // Unpowered
if(issynth)
to_chat(user, "<span class='warning'>You send an activation signal to \the [src] but it does not respond.</span>")
to_chat(user, span_warning("You send an activation signal to \the [src] but it does not respond."))
else
to_chat(user, "<span class='warning'>You press the power button but \the [src] does not respond.</span>")
to_chat(user, span_warning("You press the power button but \the [src] does not respond."))
return FALSE
// Process currently calls handle_power(), may be expanded in future if more things are added.
@@ -282,10 +311,10 @@
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
playsound(src, sound, 50, TRUE)
visible_message("<span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
visible_message(span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]"))
var/mob/living/holder = loc
if(istype(holder))
to_chat(holder, "[icon2html(src)] <span class='notice'>The [src] displays a [caller.filedesc] notification: [alerttext]</span>")
to_chat(holder, "[icon2html(src)] [span_notice("The [src] displays a [caller.filedesc] notification: [alerttext]")]")
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
/obj/item/modular_computer/proc/get_header_data()
@@ -349,14 +378,13 @@
// Relays kill program request to currently active program. Use this to quit current program.
/obj/item/modular_computer/proc/kill_program(forced = FALSE)
set waitfor = FALSE
if(active_program)
active_program.kill_program(forced)
active_program = null
var/mob/user = usr
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
update_icon()
update_appearance()
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0)
@@ -370,6 +398,7 @@
if(!get_ntnet_status())
return FALSE
var/obj/item/computer_hardware/network_card/network_card = all_components[MC_NET]
return SSnetworks.station_network.add_log(text, network_card)
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
@@ -380,9 +409,9 @@
if(looping_sound)
soundloop.stop()
if(loud)
physical.visible_message("<span class='notice'>\The [src] shuts down.</span>")
physical.visible_message(span_notice("\The [src] shuts down."))
enabled = 0
update_icon()
update_appearance()
/**
* Toggles the computer's flashlight, if it has one.
@@ -412,20 +441,20 @@
if(!has_light || !color)
return FALSE
comp_light_color = color
// set_light_color(color)
set_light_color(color)
update_light()
return TRUE
/obj/item/modular_computer/screwdriver_act(mob/user, obj/item/tool)
if(!all_components.len)
to_chat(user, "<span class='warning'>This device doesn't have any components installed.</span>")
to_chat(user, span_warning("This device doesn't have any components installed."))
return
var/list/component_names = list()
for(var/h in all_components)
var/obj/item/computer_hardware/H = all_components[h]
component_names.Add(H.name)
var/choice = tgui_input_list(user, "Which component do you want to uninstall?", "Computer maintenance", sortList(component_names))
var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in sortList(component_names)
if(!choice)
return
@@ -460,28 +489,34 @@
if(W.tool_behaviour == TOOL_WRENCH)
if(all_components.len)
to_chat(user, "<span class='warning'>Remove all components from \the [src] before disassembling it.</span>")
to_chat(user, span_warning("Remove all components from \the [src] before disassembling it."))
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
physical.visible_message("<span class='notice'>\The [src] is disassembled by [user].</span>")
physical.visible_message(span_notice("\The [src] is disassembled by [user]."))
relay_qdel()
qdel(src)
return
if(W.tool_behaviour == TOOL_WELDER)
if(obj_integrity == max_integrity)
to_chat(user, "<span class='warning'>\The [src] does not require repairs.</span>")
to_chat(user, span_warning("\The [src] does not require repairs."))
return
if(!W.tool_start_check(user, amount=1))
return
to_chat(user, "<span class='notice'>You begin repairing damage to \the [src]...</span>")
to_chat(user, span_notice("You begin repairing damage to \the [src]..."))
if(W.use_tool(src, user, 20, volume=50, amount=1))
obj_integrity = max_integrity
to_chat(user, "<span class='notice'>You repair \the [src].</span>")
to_chat(user, span_notice("You repair \the [src]."))
return
var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
// Check to see if we have an ID inside, and a valid input for money
if(card_slot?.GetID() && iscash(W))
var/obj/item/card/id/id = card_slot.GetID()
id.attackby(W, user) // If we do, try and put that attacking object in
return
..()
// Used by processor to relay qdel() to machinery type.
@@ -118,12 +118,6 @@
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")
if(istype(src, /obj/item/modular_computer/tablet))
var/obj/item/modular_computer/tablet/self = src
if(self.can_have_pen)
self.remove_pen()
return
if("PC_killprogram")
var/prog = params["name"]