mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-15 11:39:18 +00:00
## About The Pull Request Removes all arbitrary energy and power units in the codebase. Everything is replaced with the joule and watt, with 1 = 1 joule, or 1 watt if you are going to multiply by time. This is a visible change, where all arbitrary energy units you see in the game will get proper prefixed units of energy. With power cells being converted to the joule, charging one joule of a power cell will require one joule of energy. The grid will now store energy, instead of power. When an energy usage is described as using the watt, a power to energy conversion based on the relevant subsystem's timing (usually multiplying by seconds_per_tick or applying power_to_energy()) is needed before adding or removing from the grid. Power usages that are described as the watt is really anything you would scale by time before applying the load. If it's described as a joule, no time conversion is needed. Players will still read the grid as power, having no visible change. Machines that dynamically use power with the use_power() proc will directly drain from the grid (and apc cell if there isn't enough) instead of just tallying it up on the dynamic power usages for the area. This should be more robust at conserving energy as the surplus is updated on the go, preventing charging cells from nothing. APCs no longer consume power for the dynamic power usage channels. APCs will consume power for static power usages. Because static power usages are added up without checking surplus, static power consumption will be applied before any machine processes. This will give a more truthful surplus for dynamic power consumers. APCs will display how much power it is using for charging the cell. APC cell charging applies power in its own channel, which gets added up to the total. This will prevent invisible power usage you see when looking at the power monitoring console. After testing in MetaStation, I found roundstart power consumption to be around 406kW after all APCs get fully charged. During the roundstart APC charge rush, the power consumption can get as high as over 2MW (up to 25kW per roundstart APC charging) as long as there's that much available. Because of the absurd potential power consumption of charging APCs near roundstart, I have changed how APCs decide to charge. APCs will now charge only after all other machines have processed in the machines processing subsystem. This will make sure APC charging won't disrupt machines taking from the grid, and should stop APCs getting their power drained due to others demanding too much power while charging. I have removed the delays for APC charging too, so they start charging immediately whenever there's excess power. It also stops them turning red when a small amount of cell gets drained (airlocks opening and shit during APC charge rush), as they immediately become fully charged (unless too much energy got drained somehow) before changing icon. Engineering SMES now start at 100% charge instead of 75%. I noticed cells were draining earlier than usual after these changes, so I am making them start maxed to try and combat that. These changes will fix all conservation of energy issues relating to charging powercells. ## Why It's Good For The Game Closes #73438 Closes #75789 Closes #80634 Closes #82031 Makes it much easier to interface with the power system in the codebase. It's more intuitive. Removes a bunch of conservation of energy issues, making energy and power much more meaningful. It will help the simulation remain immersive as players won't encounter energy duplication so easily. Arbitrary energy units getting replaced with the joule will also tell people more meaningful information when reading it. APC charging will feel more snappy. ## Changelog 🆑 fix: Fixes conservation of energy issues relating to charging powercells. qol: APCs will display how much power they are using to charge their cell. This is accounted for in the power monitoring console. qol: All arbitrary power cell energy units you see are replaced with prefixed joules. balance: As a consequence of the conservation of energy issues getting fixed, the power consumption for charging cells is now very significant. balance: APCs only use surplus power from the grid after every machine processes when charging, preventing APCs from causing others to discharge while charging. balance: Engineering SMES start at max charge to combat the increased energy loss due to conservation of energy fixes. /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
208 lines
5.6 KiB
Plaintext
208 lines
5.6 KiB
Plaintext
/obj/item/inducer
|
|
name = "inducer"
|
|
desc = "A tool for inductively charging internal power cells."
|
|
icon = 'icons/obj/tools.dmi'
|
|
icon_state = "inducer-engi"
|
|
inhand_icon_state = "inducer-engi"
|
|
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
|
force = 7
|
|
var/powertransfer = STANDARD_CELL_CHARGE
|
|
var/opened = FALSE
|
|
var/cell_type = /obj/item/stock_parts/cell/high
|
|
var/obj/item/stock_parts/cell/cell
|
|
var/recharging = FALSE
|
|
|
|
/obj/item/inducer/Initialize(mapload)
|
|
. = ..()
|
|
if(!cell && cell_type)
|
|
cell = new cell_type
|
|
|
|
/obj/item/inducer/proc/induce(obj/item/stock_parts/cell/target, coefficient)
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
var/totransfer = min(our_cell.charge, (powertransfer * coefficient))
|
|
var/transferred = target.give(totransfer)
|
|
|
|
our_cell.use(transferred)
|
|
our_cell.update_appearance()
|
|
target.update_appearance()
|
|
|
|
/obj/item/inducer/get_cell()
|
|
return cell
|
|
|
|
/obj/item/inducer/emp_act(severity)
|
|
. = ..()
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
if(!isnull(our_cell) && !(. & EMP_PROTECT_CONTENTS))
|
|
our_cell.emp_act(severity)
|
|
|
|
/obj/item/inducer/attack_atom(obj/target, mob/living/carbon/user, params)
|
|
if(user.combat_mode)
|
|
return ..()
|
|
|
|
if(cantbeused(user))
|
|
return
|
|
|
|
if(recharge(target, user))
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/item/inducer/proc/cantbeused(mob/user)
|
|
if(!ISADVANCEDTOOLUSER(user))
|
|
to_chat(user, span_warning("You don't have the dexterity to use [src]!"))
|
|
return TRUE
|
|
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
|
|
if(isnull(our_cell))
|
|
balloon_alert(user, "no cell installed!")
|
|
return TRUE
|
|
|
|
if(!our_cell.charge)
|
|
balloon_alert(user, "no charge!")
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/inducer/screwdriver_act(mob/living/user, obj/item/tool)
|
|
. = TRUE
|
|
tool.play_tool_sound(src)
|
|
if(!opened)
|
|
to_chat(user, span_notice("You unscrew the battery compartment."))
|
|
opened = TRUE
|
|
update_appearance()
|
|
return
|
|
else
|
|
to_chat(user, span_notice("You close the battery compartment."))
|
|
opened = FALSE
|
|
update_appearance()
|
|
return
|
|
|
|
/obj/item/inducer/attackby(obj/item/used_item, mob/user)
|
|
if(istype(used_item, /obj/item/stock_parts/cell))
|
|
if(opened)
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
if(isnull(our_cell))
|
|
if(!user.transferItemToLoc(used_item, src))
|
|
return
|
|
to_chat(user, span_notice("You insert [used_item] into [src]."))
|
|
cell = used_item
|
|
update_appearance()
|
|
return
|
|
else
|
|
to_chat(user, span_warning("[src] already has \a [our_cell] installed!"))
|
|
return
|
|
|
|
if(cantbeused(user))
|
|
return
|
|
|
|
if(recharge(used_item, user))
|
|
return
|
|
|
|
return ..()
|
|
|
|
/obj/item/inducer/proc/recharge(atom/movable/target, mob/user)
|
|
if(!isturf(target) && user.loc == target)
|
|
return FALSE
|
|
if(recharging)
|
|
return TRUE
|
|
|
|
recharging = TRUE
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
var/obj/item/stock_parts/cell/target_cell = target.get_cell()
|
|
var/obj/target_as_object = target
|
|
var/coefficient = 1
|
|
|
|
if(istype(target, /obj/item/gun/energy) || istype(target, /obj/item/clothing/suit/space))
|
|
to_chat(user, span_alert("Error: unable to interface with device."))
|
|
return FALSE
|
|
|
|
if(target_cell)
|
|
var/done_any = FALSE
|
|
if(target_cell.charge >= target_cell.maxcharge)
|
|
balloon_alert(user, "it's fully charged!")
|
|
recharging = FALSE
|
|
return TRUE
|
|
|
|
user.visible_message(span_notice("[user] starts recharging [target] with [src]."), span_notice("You start recharging [target] with [src]."))
|
|
|
|
while(target_cell.charge < target_cell.maxcharge)
|
|
if(do_after(user, 10, target = user) && our_cell.charge)
|
|
done_any = TRUE
|
|
induce(target_cell, coefficient)
|
|
do_sparks(1, FALSE, target)
|
|
if(istype(target_as_object))
|
|
target_as_object.update_appearance()
|
|
else
|
|
break
|
|
if(done_any) // Only show a message if we succeeded at least once
|
|
user.visible_message(span_notice("[user] recharged [target]!"), span_notice("You recharged [target]!"))
|
|
recharging = FALSE
|
|
return TRUE
|
|
recharging = FALSE
|
|
|
|
|
|
/obj/item/inducer/attack(mob/target, mob/living/user)
|
|
if(user.combat_mode)
|
|
return ..()
|
|
|
|
if(cantbeused(user))
|
|
return
|
|
|
|
if(recharge(target, user))
|
|
return
|
|
|
|
return ..()
|
|
|
|
|
|
/obj/item/inducer/attack_self(mob/user)
|
|
if(opened && cell)
|
|
user.visible_message(span_notice("[user] removes [cell] from [src]!"), span_notice("You remove [cell]."))
|
|
cell.update_appearance()
|
|
user.put_in_hands(cell)
|
|
cell = null
|
|
update_appearance()
|
|
|
|
|
|
/obj/item/inducer/examine(mob/living/user)
|
|
. = ..()
|
|
var/obj/item/stock_parts/cell/our_cell = get_cell()
|
|
if(!isnull(our_cell))
|
|
. += span_notice("Its display shows: [display_energy(our_cell.charge)].")
|
|
else
|
|
. += span_notice("Its display is dark.")
|
|
if(opened)
|
|
. += span_notice("Its battery compartment is open.")
|
|
|
|
/obj/item/inducer/update_overlays()
|
|
. = ..()
|
|
if(!opened)
|
|
return
|
|
. += "inducer-[!isnull(get_cell()) ? "bat" : "nobat"]"
|
|
|
|
/obj/item/inducer/empty
|
|
cell_type = null
|
|
opened = TRUE
|
|
|
|
/obj/item/inducer/orderable
|
|
cell_type = /obj/item/stock_parts/cell/inducer_supply
|
|
opened = FALSE
|
|
|
|
/obj/item/inducer/sci
|
|
icon_state = "inducer-sci"
|
|
inhand_icon_state = "inducer-sci"
|
|
desc = "A tool for inductively charging internal power cells. This one has a science color scheme, and is less potent than its engineering counterpart."
|
|
cell_type = null
|
|
opened = TRUE
|
|
|
|
/obj/item/inducer/sci/Initialize(mapload)
|
|
. = ..()
|
|
update_appearance()
|
|
|
|
/obj/item/inducer/syndicate
|
|
icon_state = "inducer-syndi"
|
|
inhand_icon_state = "inducer-syndi"
|
|
desc = "A tool for inductively charging internal power cells. This one has a suspicious colour scheme, and seems to be rigged to transfer charge at a much faster rate."
|
|
powertransfer = 2000
|
|
cell_type = /obj/item/stock_parts/cell/super
|