mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-18 21:53:22 +00:00
333 lines
12 KiB
Plaintext
333 lines
12 KiB
Plaintext
#define CELL_DRAIN_TIME 35
|
|
#define CELL_POWER_GAIN (0.06 * STANDARD_CELL_CHARGE)
|
|
#define CELL_POWER_DRAIN (0.75 * STANDARD_CELL_CHARGE)
|
|
|
|
/**
|
|
* # Power store abstract type
|
|
*
|
|
* Abstract type for a stock part that holds power.
|
|
*/
|
|
/obj/item/stock_parts/power_store
|
|
name = "power store abstract"
|
|
/// The size icon overlay prefix.
|
|
var/cell_size_prefix = "cell"
|
|
///Current charge in cell units
|
|
var/charge = 0
|
|
/// Standard cell charge used for rating
|
|
var/rating_base = STANDARD_CELL_CHARGE
|
|
///Maximum charge in cell units
|
|
var/maxcharge = STANDARD_CELL_CHARGE
|
|
///If the cell has been booby-trapped by injecting it with plasma. Chance on use() to explode.
|
|
var/rigged = FALSE
|
|
///If the power cell was damaged by an explosion, chance for it to become corrupted and function the same as rigged.
|
|
var/corrupted = FALSE
|
|
///How much power is given per second in a recharger.
|
|
var/chargerate = STANDARD_CELL_RATE * 0.05
|
|
///If true, the cell will state it's maximum charge in it's description
|
|
var/ratingdesc = TRUE
|
|
///If it's a grown that acts as a battery, add a wire overlay to it.
|
|
var/grown_battery = FALSE
|
|
///What charge lige sprite to use, null if no light
|
|
var/charge_light_type = "standard"
|
|
///What connector sprite to use when in a cell charger, null if no connectors
|
|
var/connector_type = "standard"
|
|
///Does the cell start without any charge?
|
|
var/empty = FALSE
|
|
|
|
/obj/item/stock_parts/power_store/get_cell()
|
|
return src
|
|
|
|
/obj/item/stock_parts/power_store/Initialize(mapload, override_maxcharge)
|
|
. = ..()
|
|
create_reagents(5, INJECTABLE | DRAINABLE)
|
|
if (override_maxcharge)
|
|
maxcharge = override_maxcharge
|
|
rating = max(round(maxcharge / (rating_base * 10), 1), 1)
|
|
if(!charge)
|
|
charge = maxcharge
|
|
if(empty)
|
|
charge = 0
|
|
if(ratingdesc)
|
|
desc += " This one has a rating of [display_energy(maxcharge)][prob(10) ? ", and you should not swallow it" : ""]." //joke works better if it's not on every cell
|
|
update_appearance()
|
|
|
|
RegisterSignal(src, COMSIG_ITEM_MAGICALLY_CHARGED, PROC_REF(on_magic_charge))
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_ITEM_MAGICALLY_CHARGED = PROC_REF(on_magic_charge),
|
|
)
|
|
AddElement(/datum/element/connect_loc, loc_connections)
|
|
|
|
|
|
/obj/item/stock_parts/power_store/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
|
|
. = ..()
|
|
if(!isturf(old_loc))
|
|
update_appearance()
|
|
|
|
|
|
/**
|
|
* Signal proc for [COMSIG_ITEM_MAGICALLY_CHARGED]
|
|
*
|
|
* If we, or the item we're located in, is subject to the charge spell, gain some charge back
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/on_magic_charge(datum/source, datum/action/cooldown/spell/charge/spell, mob/living/caster)
|
|
SIGNAL_HANDLER
|
|
|
|
// This shouldn't be running if we're not being held by a mob,
|
|
// or if we're not within an object being held by a mob, but just in case...
|
|
if(!ismovable(loc))
|
|
return
|
|
|
|
. = COMPONENT_ITEM_CHARGED
|
|
|
|
if(prob(80))
|
|
maxcharge -= rating_base * 0.2
|
|
|
|
if(maxcharge <= 1) // Div by 0 protection
|
|
maxcharge = 1
|
|
. |= COMPONENT_ITEM_BURNT_OUT
|
|
|
|
charge = maxcharge
|
|
update_appearance()
|
|
|
|
// Guns need to process their chamber when we've been charged
|
|
if(isgun(loc))
|
|
var/obj/item/gun/gun_loc = loc
|
|
gun_loc.process_chamber()
|
|
|
|
// The thing we're in might have overlays or icon states for whether the cell is charged
|
|
if(!ismob(loc))
|
|
loc.update_appearance()
|
|
|
|
return .
|
|
|
|
/obj/item/stock_parts/power_store/create_reagents(max_vol, flags)
|
|
. = ..()
|
|
RegisterSignals(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), PROC_REF(on_reagent_change))
|
|
RegisterSignal(reagents, COMSIG_QDELETING, PROC_REF(on_reagents_del))
|
|
|
|
/// Handles properly detaching signal hooks.
|
|
/obj/item/stock_parts/power_store/proc/on_reagents_del(datum/reagents/reagents)
|
|
SIGNAL_HANDLER
|
|
UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_QDELETING))
|
|
return NONE
|
|
|
|
/obj/item/stock_parts/power_store/update_overlays()
|
|
. = ..()
|
|
if(grown_battery)
|
|
. += mutable_appearance('icons/obj/machines/cell_charger.dmi', "grown_wires")
|
|
if((charge < 0.01) || !charge_light_type)
|
|
return
|
|
. += mutable_appearance('icons/obj/machines/cell_charger.dmi', "[cell_size_prefix]-[charge_light_type]-o[(percent() >= 99.5) ? 2 : 1]")
|
|
|
|
/obj/item/stock_parts/power_store/vv_edit_var(vname, vval)
|
|
if(vname == NAMEOF(src, charge))
|
|
charge = clamp(vval, 0, maxcharge)
|
|
return TRUE
|
|
if(vname == NAMEOF(src, maxcharge))
|
|
if(charge > vval)
|
|
charge = vval
|
|
if(vname == NAMEOF(src, corrupted) && vval && !corrupted)
|
|
corrupt(TRUE)
|
|
return TRUE
|
|
return ..()
|
|
|
|
|
|
/**
|
|
* Returns the percentage of the cell's charge.
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/percent() // return % charge of cell
|
|
return 100 * charge / maxcharge
|
|
|
|
/**
|
|
* Returns the maximum charge of the cell.
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/max_charge()
|
|
return maxcharge
|
|
|
|
/**
|
|
* Returns the current charge of the cell.
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/charge()
|
|
return charge
|
|
|
|
/**
|
|
* Returns the amount of charge used on the cell.
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/used_charge()
|
|
return maxcharge - charge
|
|
|
|
/// Use power from the cell.
|
|
/// Args:
|
|
/// - used: Amount of power in joules to use.
|
|
/// - force: If true, uses the remaining power from the cell if there isn't enough power to supply the demand.
|
|
/// Returns: The power used from the cell in joules.
|
|
/obj/item/stock_parts/power_store/use(used, force = FALSE)
|
|
var/power_used = min(used, charge)
|
|
if(rigged && power_used > 0)
|
|
explode()
|
|
return 0 // The cell decided to explode so we won't be able to use it.
|
|
if(!force && charge < used)
|
|
return 0
|
|
charge -= power_used
|
|
if(!istype(loc, /obj/machinery/power/apc))
|
|
SSblackbox.record_feedback("tally", "cell_used", 1, type)
|
|
return power_used
|
|
|
|
/// Recharge the cell.
|
|
/// Args:
|
|
/// - amount: The amount of energy to give to the cell in joules.
|
|
/// Returns: The power given to the cell in joules.
|
|
/obj/item/stock_parts/power_store/proc/give(amount)
|
|
var/power_used = min(maxcharge-charge,amount)
|
|
charge += power_used
|
|
if(rigged && amount > 0)
|
|
explode()
|
|
return power_used
|
|
|
|
/**
|
|
* Changes the charge of the cell.
|
|
* Args:
|
|
* - amount: The energy to give to the cell (can be negative).
|
|
* Returns: The energy that was given to the cell (can be negative).
|
|
*/
|
|
/obj/item/stock_parts/power_store/proc/change(amount)
|
|
var/energy_used = clamp(amount, -charge, maxcharge - charge)
|
|
charge += energy_used
|
|
if(rigged && energy_used)
|
|
explode()
|
|
return energy_used
|
|
|
|
/obj/item/stock_parts/power_store/examine(mob/user)
|
|
. = ..()
|
|
if(rigged)
|
|
. += span_danger("This [name] seems to be faulty!")
|
|
else
|
|
. += "The charge meter reads [CEILING(percent(), 0.1)]%." //so it doesn't say 0% charge when the overlay indicates it still has charge
|
|
|
|
/obj/item/stock_parts/power_store/proc/on_reagent_change(datum/reagents/holder, ...)
|
|
SIGNAL_HANDLER
|
|
rigged = (corrupted || holder.has_reagent(/datum/reagent/toxin/plasma, 5)) ? TRUE : FALSE //has_reagent returns the reagent datum
|
|
return NONE
|
|
|
|
|
|
/obj/item/stock_parts/power_store/proc/explode()
|
|
if(!charge)
|
|
return
|
|
var/range_devastation = -1
|
|
var/range_heavy = round(sqrt(charge / (3.6 * rating_base)))
|
|
var/range_light = round(sqrt(charge / (0.9 * rating_base)))
|
|
var/range_flash = range_light
|
|
if(!range_light)
|
|
rigged = FALSE
|
|
corrupt()
|
|
return
|
|
|
|
message_admins("[ADMIN_LOOKUPFLW(usr)] has triggered a rigged/corrupted power cell explosion at [AREACOORD(loc)].")
|
|
usr?.log_message("triggered a rigged/corrupted power cell explosion", LOG_GAME)
|
|
usr?.log_message("triggered a rigged/corrupted power cell explosion", LOG_VICTIM, log_globally = FALSE)
|
|
|
|
explosion(src, devastation_range = range_devastation, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_flash)
|
|
qdel(src)
|
|
|
|
/obj/item/stock_parts/power_store/proc/corrupt(force)
|
|
charge /= 2
|
|
maxcharge = max(maxcharge/2, chargerate)
|
|
if (force || prob(10))
|
|
rigged = TRUE //broken batterys are dangerous
|
|
corrupted = TRUE
|
|
|
|
/obj/item/stock_parts/power_store/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF)
|
|
return
|
|
use(STANDARD_CELL_CHARGE / severity, force = TRUE)
|
|
|
|
/obj/item/stock_parts/power_store/ex_act(severity, target)
|
|
. = ..()
|
|
if(QDELETED(src))
|
|
return FALSE
|
|
|
|
switch(severity)
|
|
if(EXPLODE_HEAVY)
|
|
if(prob(50))
|
|
corrupt()
|
|
if(EXPLODE_LIGHT)
|
|
if(prob(25))
|
|
corrupt()
|
|
|
|
return TRUE
|
|
|
|
/obj/item/stock_parts/power_store/suicide_act(mob/living/user)
|
|
user.visible_message(span_suicide("[user] is licking the electrodes of [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
do_sparks(2, TRUE, user)
|
|
var/eating_success = do_after(user, 5 SECONDS, src)
|
|
if(QDELETED(user))
|
|
return SHAME
|
|
if(!eating_success || QDELETED(src) || charge == 0)
|
|
user.visible_message(span_suicide("[user] chickens out!"))
|
|
return SHAME
|
|
playsound(user, 'sound/effects/sparks/sparks1.ogg', charge / maxcharge)
|
|
var/damage = charge / (1 KILO JOULES)
|
|
user.electrocute_act(damage, src, 1, SHOCK_IGNORE_IMMUNITY|SHOCK_DELAY_STUN|SHOCK_NOGLOVES)
|
|
charge = 0
|
|
update_appearance()
|
|
if(user.stat != DEAD)
|
|
to_chat(user, span_suicide("There's not enough charge in [src] to kill you!"))
|
|
return SHAME
|
|
addtimer(CALLBACK(src, PROC_REF(gib_user), user, charge), 3 SECONDS)
|
|
return MANUAL_SUICIDE
|
|
|
|
/obj/item/stock_parts/power_store/proc/gib_user(mob/living/user, discharged_energy)
|
|
if(QDELETED(user))
|
|
return
|
|
if(discharged_energy < STANDARD_BATTERY_CHARGE)
|
|
return
|
|
user.dropItemToGround(src)
|
|
user.dust(just_ash = TRUE)
|
|
playsound(src, 'sound/effects/magic/lightningshock.ogg', 50, TRUE, 10)
|
|
tesla_zap(source = src, zap_range = 10, power = discharged_energy)
|
|
|
|
/obj/item/stock_parts/power_store/attack_self(mob/user)
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/H = user
|
|
var/obj/item/organ/internal/stomach/maybe_stomach = H.get_organ_slot(ORGAN_SLOT_STOMACH)
|
|
|
|
if(istype(maybe_stomach, /obj/item/organ/internal/stomach/ethereal))
|
|
|
|
var/charge_limit = ETHEREAL_CHARGE_DANGEROUS - CELL_POWER_GAIN
|
|
var/obj/item/organ/internal/stomach/ethereal/stomach = maybe_stomach
|
|
var/obj/item/stock_parts/power_store/stomach_cell = stomach.cell
|
|
if((stomach.drain_time > world.time) || !stomach)
|
|
return
|
|
if(charge < CELL_POWER_DRAIN)
|
|
to_chat(H, span_warning("[src] doesn't have enough power!"))
|
|
return
|
|
if(stomach_cell.charge() > charge_limit)
|
|
to_chat(H, span_warning("Your charge is full!"))
|
|
return
|
|
H.visible_message(span_notice("[user] hovers their fingers above [src], arcs forming from its surface!")) //SKYRAT EDIT CHANGE - Ethereal Rework 2024 - ORIGINAL: to_chat(H, span_notice("You begin clumsily channeling power from [src] into your body."))
|
|
stomach.drain_time = world.time + CELL_DRAIN_TIME
|
|
while(do_after(user, CELL_DRAIN_TIME, target = src))
|
|
if((charge < CELL_POWER_DRAIN) || (stomach_cell.charge() > charge_limit))
|
|
return
|
|
if(istype(stomach))
|
|
to_chat(H, span_notice("You receive some charge from [src], wasting some in the process."))
|
|
stomach.adjust_charge(CELL_POWER_GAIN)
|
|
charge -= CELL_POWER_DRAIN //you waste way more than you receive, so that ethereals cant just steal one cell and forget about hunger
|
|
else
|
|
to_chat(H, span_warning("You can't receive charge from [src]!"))
|
|
return
|
|
|
|
/obj/item/stock_parts/power_store/blob_act(obj/structure/blob/B)
|
|
SSexplosions.high_mov_atom += src
|
|
|
|
/obj/item/stock_parts/power_store/proc/get_electrocute_damage()
|
|
return ELECTROCUTE_DAMAGE(charge / max(0.001 * STANDARD_CELL_CHARGE, 1)) // Wouldn't want it to consider more energy than whatever is actually in the cell if for some strange reason someone set the STANDARD_CELL_CHARGE to below 1kJ.
|
|
|
|
/obj/item/stock_parts/power_store/get_part_rating()
|
|
return maxcharge * 10 + charge
|
|
|
|
#undef CELL_DRAIN_TIME
|
|
#undef CELL_POWER_GAIN
|
|
#undef CELL_POWER_DRAIN
|