pdas now use their cells more (#78580)

## About The Pull Request

So one aspect of PDAs that I quite liked previously was managing and
upgrading your power.
This was lost when all cell parts got removed, mostly, and now I'd like
to re-add it.
PDAs and Tablets now use more power each second it's on
Programs being active/idle now take charge too.
And all this now takes ``seconds_per_tick`` into account.

Screenshots of APC use before and after having 6 programs open at once

![image](https://github.com/tgstation/tgstation/assets/53777086/14699ae7-19a7-4eb6-a211-5944cc1867d0)

![image](https://github.com/tgstation/tgstation/assets/53777086/804fedde-0d5a-43a9-9e61-34139257a16f)

PDA default power cells have a max charge of 1000, each cell use is
around ``1.00970340315`` power, which is ``1.01013789399`` w/ 2 programs
in idle and 1 active program (which is what PDAs are capable of). This
means it takes about 990 ticks to fully drain your power, or about 50
minutes, at max use.

This is completely blasted away the moment you put anything beyond a t1
cell inside of it, which is unfortunate but what can you do about tiered
parts being so poor.

The problem of no public PDA chargers are alleviated by
https://github.com/tgstation/tgstation/pull/78600

### Update

The PDA flashlight being on now also drains the battery 25% times
faster. PDA running out of charge now also turns the flashlight off.

## Why It's Good For The Game

You may or may not have to actually charge your PDA once in a round now,
maybe. I liked this part of tablets and would like to see it brought
back, managing your power to use your apps is important to ensure you're
not just using all apps 24/7

Because this also adds the functionality to add/remove power cells
again, it opens up to some minor little pranks/messing with people that
isn't completely destroying their tools, as well as some minor
upgradeability.

## Changelog

🆑
balance: You can now remove and replace power cells from PDAs (with
screwdriver).
balance: PDAs now drain their power cells harder, and also take into
account active programs & their flashlight being on.
balance: PDAs running out of charge now turn their flashlights off.
/🆑
This commit is contained in:
John Willard
2023-09-28 01:15:19 +00:00
committed by GitHub
parent ae2379d099
commit aaff861c90
5 changed files with 53 additions and 21 deletions
@@ -42,7 +42,7 @@
///The program currently active on the tablet.
var/datum/computer_file/program/active_program
///Idle programs on background. They still receive process calls but can't be interacted with.
var/list/idle_threads = list()
var/list/datum/computer_file/program/idle_threads = list()
/// Amount of programs that can be ran at once
var/max_idle_programs = 2
@@ -72,11 +72,9 @@
/// The built-in light's color, editable by players.
var/comp_light_color = "#FFFFFF"
///The last recorded amount of power used.
var/last_power_usage = 0
///Power usage when the computer is open (screen is active) and can be interacted with.
var/base_active_power_usage = 75
///Power usage when the computer is idle and screen is off (currently only applies to laptops)
var/base_active_power_usage = 125
///Power usage when the computer is idle and screen is off.
var/base_idle_power_usage = 5
// Modular computers can run on various devices. Each DEVICE (Laptop, Console & Tablet)
@@ -369,6 +367,9 @@
/obj/item/modular_computer/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = ..()
if(held_item?.tool_behaviour == TOOL_SCREWDRIVER && internal_cell)
context[SCREENTIP_CONTEXT_RMB] = "Remove Cell"
. = CONTEXTUAL_SCREENTIP_SET
if(held_item?.tool_behaviour == TOOL_WRENCH)
context[SCREENTIP_CONTEXT_RMB] = "Deconstruct"
. = CONTEXTUAL_SCREENTIP_SET
@@ -440,7 +441,7 @@
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(use_power()) // use_power() checks if the PC is powered
if(use_power()) // checks if the PC is powered
if(issynth)
to_chat(user, span_notice("You send an activation signal to \the [src], turning it on."))
else
@@ -462,7 +463,6 @@
// Process currently calls handle_power(), may be expanded in future if more things are added.
/obj/item/modular_computer/process(seconds_per_tick)
if(!enabled) // The computer is turned off
last_power_usage = 0
return
if(atom_integrity <= integrity_failure * max_integrity)
@@ -736,7 +736,7 @@
return
if(istype(attacking_item, /obj/item/stock_parts/cell))
if(ismachinery(loc))
if(ismachinery(physical))
return
if(internal_cell)
to_chat(user, span_warning("You try to connect \the [attacking_item] to \the [src], but its connectors are occupied."))
@@ -800,6 +800,16 @@
return ..()
/obj/item/modular_computer/screwdriver_act_secondary(mob/living/user, obj/item/tool)
. = ..()
if(internal_cell)
user.balloon_alert(user, "cell removed")
internal_cell.forceMove(drop_location())
internal_cell = null
return TOOL_ACT_TOOLTYPE_SUCCESS
else
user.balloon_alert(user, "no cell!")
/obj/item/modular_computer/wrench_act_secondary(mob/living/user, obj/item/tool)
. = ..()
tool.play_tool_sound(src, user, 20, volume=20)
@@ -1,9 +1,13 @@
///The multiplier given to the base overtime charge drain value if its flashlight is on.
#define FLASHLIGHT_DRAIN_MULTIPLIER 1.25
// Tries to draw power from charger or, if no operational charger is present, from power cell.
/obj/item/modular_computer/proc/use_power(amount = 0)
if(check_power_override())
return TRUE
if(ismachinery(loc))
var/obj/machinery/machine_holder = loc
if(ismachinery(physical))
var/obj/machinery/machine_holder = physical
if(machine_holder.powered())
machine_holder.use_power(amount)
return TRUE
@@ -27,20 +31,30 @@
return
if(active_program)
active_program.event_powerfailure()
if(light_on)
set_light_on(FALSE)
for(var/datum/computer_file/program/programs as anything in idle_threads)
programs.event_powerfailure()
shutdown_computer(loud = FALSE)
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
///Takes the charge necessary from the Computer, shutting it off if it's unable to provide it.
///Charge depends on whether the PC is on, and what programs are running/idle on it.
/obj/item/modular_computer/proc/handle_power(seconds_per_tick)
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
if(light_on)
base_active_power_usage *= FLASHLIGHT_DRAIN_MULTIPLIER
if(active_program)
power_usage += active_program.power_cell_use
for(var/datum/computer_file/program/open_programs as anything in idle_threads)
if(!open_programs.power_cell_use)
continue
if(open_programs in idle_threads)
power_usage += (open_programs.power_cell_use / 2)
if(use_power(power_usage))
last_power_usage = power_usage
if(use_power(power_usage * seconds_per_tick))
return TRUE
else
power_failure()
return FALSE
power_failure()
return FALSE
///Used by subtypes for special cases for power usage, returns TRUE if it should stop the use_power chain.
/obj/item/modular_computer/proc/check_power_override()
@@ -49,3 +63,5 @@
//Integrated (Silicon) tablets don't drain power, because the tablet is required to state laws, so it being disabled WILL cause problems.
/obj/item/modular_computer/pda/silicon/check_power_override()
return TRUE
#undef FLASHLIGHT_DRAIN_MULTIPLIER
@@ -44,7 +44,7 @@
// Operates TGUI
/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui)
if(!enabled || !user.can_read(src, READING_CHECK_LITERACY) || !use_power())
if(!enabled || !user.can_read(src, READING_CHECK_LITERACY))
if(ui)
ui.close()
return
@@ -13,8 +13,6 @@
var/internal_cell = null
///A flag that describes this device type
var/hardware_flag = PROGRAM_CONSOLE
///Power usage during last tick
var/last_power_usage = 0
/// Amount of programs that can be ran at once
var/max_idle_programs = 4
@@ -72,7 +70,7 @@
set_light(cpu?.enabled ? light_strength : 0)
/obj/machinery/modular_computer/update_icon_state()
if(!cpu || !cpu.enabled || !cpu.use_power() || (machine_stat & NOPOWER))
if(!cpu || !cpu.enabled || (machine_stat & NOPOWER))
icon_state = icon_state_unpowered
else
icon_state = icon_state_powered
@@ -83,7 +81,7 @@
if(!cpu)
return .
if(cpu.enabled && cpu.use_power())
if(cpu.enabled)
. += cpu.active_program?.program_icon_state || screen_icon_state_menu
else if(!(machine_stat & NOPOWER))
. += screen_icon_screensaver