mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
## About The Pull Request **Skyrat killer! I kill the skyrat sprites!** In all seriousness, the main part of this pr was to replace the skyrat sprites for cells because it was bothering me that they were in a different perspective from most things. This grew into changing stock parts to fit in with the cells, then grew into respriting telecoms parts, then grew into respriting the intercom, THEN grew into respriting the apc! - For cells, extra states were added for the emp-proof cell, the miniature cell and the AA megacell. - For intercoms, extra states were added for the syndicate variant and all departmental encryption key variants. ## Why It's Good For The Game More uniformity and consistency for our sprite replacements! Fixes for edge cases like command/prison intercoms not having a state despite tg having it and the broken apc sticker not being accounted for, yay! ## Proof Of Testing <details> <summary>Screenshots/Videos</summary> <img width="832" height="384" alt="image" src="https://github.com/user-attachments/assets/56f49ed3-f4f2-44a5-9310-25db3649c345" /> </details> ## Changelog 🆑 Robwo image: Cells, stock parts, apcs and intercoms have been resprited. /🆑
349 lines
12 KiB
Plaintext
349 lines
12 KiB
Plaintext
#define ETHEREAL_CELL_DRAIN_TIME (3.5 SECONDS)
|
|
#define ETHEREAL_CELL_POWER_DRAIN (0.75 * STANDARD_CELL_CHARGE)
|
|
/// The factor by which we multiply drain to get how much we gain
|
|
#define ETHEREAL_CELL_POWER_GAIN_FACTOR 0.08
|
|
|
|
/**
|
|
* # 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 power cell was damaged by an explosion, chance for it to become corrupted and function the same as if it was rigged with plasma.
|
|
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
|
|
// Damage multiplier the cells take from emps to prevent stuff like bluespace cells taking 40 shots to drain.
|
|
var/emp_damage_modifier = 1
|
|
|
|
/obj/item/stock_parts/power_store/get_cell()
|
|
return src
|
|
|
|
/obj/item/stock_parts/power_store/get_save_vars()
|
|
. = ..()
|
|
. += NAMEOF(src, charge)
|
|
. += NAMEOF(src, corrupted)
|
|
return .
|
|
|
|
/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(!empty && !charge)
|
|
charge = maxcharge
|
|
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 .
|
|
|
|
/* OVERWRITTEN IN modular_skyrat\modules\aesthetics\cells\cell.dm
|
|
/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(power_used > 0 && try_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 (amount)
|
|
try_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(energy_used)
|
|
try_explode()
|
|
return energy_used
|
|
|
|
/obj/item/stock_parts/power_store/examine(mob/user)
|
|
. = ..()
|
|
if(corrupted)
|
|
. += span_danger("This [name] seems to be faulty!")
|
|
else if(!isnull(charge_light_type))
|
|
. += "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/try_explode(max_charge = FALSE)
|
|
var/check_charge = charge
|
|
if (max_charge)
|
|
check_charge = maxcharge
|
|
|
|
if(!check_charge)
|
|
return FALSE
|
|
|
|
if (!corrupted)
|
|
if (!(reagents?.spark_act(check_charge, SPARK_ACT_ENCLOSED) & SPARK_ACT_DESTRUCTIVE))
|
|
return FALSE
|
|
message_admins("[ADMIN_LOOKUPFLW(usr)] has triggered a rigged power cell explosion at [AREACOORD(loc)].")
|
|
usr?.log_message("triggered a rigged power cell explosion", LOG_GAME)
|
|
usr?.log_message("triggered a rigged power cell explosion", LOG_VICTIM, log_globally = FALSE)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
var/range_heavy = round(sqrt(check_charge / (3.6 * rating_base)))
|
|
var/range_light = round(sqrt(check_charge / (0.9 * rating_base)))
|
|
if(!range_light)
|
|
corrupt()
|
|
return FALSE
|
|
|
|
message_admins("[ADMIN_LOOKUPFLW(usr)] has triggered a corrupted power cell explosion at [AREACOORD(loc)].")
|
|
usr?.log_message("triggered a corrupted power cell explosion", LOG_GAME)
|
|
usr?.log_message("triggered a corrupted power cell explosion", LOG_VICTIM, log_globally = FALSE)
|
|
explosion(src, devastation_range = -1, heavy_impact_range = range_heavy, light_impact_range = range_light, flash_range = range_light)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
/obj/item/stock_parts/power_store/proc/corrupt(force)
|
|
charge /= 2
|
|
maxcharge = max(maxcharge/2, chargerate)
|
|
if (force || prob(10))
|
|
corrupted = TRUE
|
|
|
|
/obj/item/stock_parts/power_store/emp_act(severity)
|
|
. = ..()
|
|
if(. & EMP_PROTECT_SELF)
|
|
return
|
|
use((STANDARD_CELL_CHARGE /severity) * emp_damage_modifier , 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)
|
|
var/discharged_energy = charge
|
|
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, discharged_energy), 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, drop_items = 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(.)
|
|
return
|
|
|
|
if(!ishuman(user))
|
|
return
|
|
|
|
var/mob/living/carbon/human/human_user = user
|
|
var/obj/item/organ/stomach/ethereal/user_stomach = human_user.get_organ_slot(ORGAN_SLOT_STOMACH)
|
|
if(!istype(user_stomach))
|
|
return
|
|
if(user_stomach.drain_time > world.time)
|
|
return
|
|
|
|
ethereal_drain(human_user, user_stomach)
|
|
|
|
/// Handles letting an ethereal drain our charge into their stomach
|
|
/obj/item/stock_parts/power_store/proc/ethereal_drain(mob/living/carbon/human/user, obj/item/organ/stomach/ethereal/used_stomach)
|
|
if(charge() <= 0)
|
|
balloon_alert(user, "out of charge!")
|
|
return
|
|
|
|
var/obj/item/stock_parts/power_store/stomach_cell = used_stomach.cell
|
|
used_stomach.drain_time = world.time + ETHEREAL_CELL_DRAIN_TIME
|
|
to_chat(user, span_notice("You begin clumsily channeling power from [src] into your body."))
|
|
|
|
while(do_after(user, ETHEREAL_CELL_DRAIN_TIME, target = src))
|
|
if(isnull(used_stomach) || (used_stomach != user.get_organ_slot(ORGAN_SLOT_STOMACH)))
|
|
balloon_alert(user, "stomach removed!?")
|
|
return
|
|
|
|
var/our_charge = charge()
|
|
var/scaled_stomach_used_charge = stomach_cell.used_charge() / ETHEREAL_CELL_POWER_GAIN_FACTOR
|
|
var/potential_charge = min(our_charge, scaled_stomach_used_charge)
|
|
var/to_drain = min(ETHEREAL_CELL_POWER_DRAIN, potential_charge)
|
|
var/energy_drained = use(to_drain, force = TRUE)
|
|
used_stomach.adjust_charge(energy_drained * ETHEREAL_CELL_POWER_GAIN_FACTOR)
|
|
update_appearance(UPDATE_OVERLAYS)
|
|
|
|
if(stomach_cell.used_charge() <= 0)
|
|
balloon_alert(user, "your charge is full!")
|
|
return
|
|
if(charge() <= 0)
|
|
balloon_alert(user, "out of charge!")
|
|
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 ETHEREAL_CELL_DRAIN_TIME
|
|
#undef ETHEREAL_CELL_POWER_DRAIN
|
|
#undef ETHEREAL_CELL_POWER_GAIN_FACTOR
|