mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-26 09:32:21 +00:00
## About The Pull Request Refactors status effects to track their durations and tick intervals using counters. In effect, [var/duration] now directly refers to how many deciseconds are left on the status effect. I've also moved the old [var/tick_interval] [world.time] implementation to a tick-based [var/time_until_next_tick] counter. There are a couple, less noteworthy changes in here as well. The main one is that there was an unused bit of bloat code for setting tick intervals based on a random lower and upper threshold, but that can be done in tick() now so it's completely redundant, and I thus removed it entirely. That makes parts of [proc/process] much easier to read. I added/modified some unit tests (which I expect to fail) to verify that [var/duration] and [var/tick_interval] are both multiples of the subsystem wait assigned to the status effect. If the programmer wants a duration of 2.5 seconds, they expect it to work that way, but it won't because SSfastprocess only ticks once every 0.2 seconds, which 2.5 is not a multiple of. This becomes way more apparent when a status effect is set to use SSprocessing. The final, perhaps most important unit test I've added, is one that verifies that the overall tick count and overall accumulated [seconds_between_ticks] are equal to "[var/duration] / [var/tick_interval]" and "[var/duration]" respectively. ## Why It's Good For The Game The main thing this PR fixes is timing inconsistencies. Before this PR, durations and tick intervals were tracked using world.time, while the [proc/tick] call timing was dependent on the wait time of the subsystem the status effect was processing on. Thing is, SSfastprocess and SSprocessing rarely run completely in one tick during real gameplay. This led to a continuous desync where status effects were consistently inconsistent in their overall tick count. This is a big problem as [seconds_between_ticks] is constant and thus doesn't account for this difference in tick count. As an example, Changeling's Fleshmend has a duration of 10 seconds, a tick interval of 1 second and a healing rate of 4 brute per tick. Previously, if the server was lagging even slightly and it only ticked 8 times over the course of 10 seconds, you would heal 32 health rather than the 40 that a full Fleshmend would give you. The total effect potency of a status effect being reliant on server lag is incredibly stupid, especially for status effects that have an associated cost. (like the aforementioned Fleshmend) As for the refactors, they make status effect code easier to read and debug. Unit tests also make verifying things are working as intended much easier. ## Changelog 🆑 fix: Status effects now tick consistently, with Fleshmend and such giving a consistent total healing amount. Report any oddities. refactor: Status effect code is now easier to read and makes more sense. Again, report any oddities, the changes are major. /🆑
184 lines
6.7 KiB
Plaintext
184 lines
6.7 KiB
Plaintext
// .310 Strilka (Sakhno Rifle)
|
|
|
|
/obj/item/ammo_casing/strilka310
|
|
name = ".310 Strilka bullet casing"
|
|
desc = "A .310 Strilka bullet casing. Casing is a bit of a fib; there is no case, it's just a block of red powder."
|
|
icon_state = "310-casing"
|
|
caliber = CALIBER_STRILKA310
|
|
projectile_type = /obj/projectile/bullet/strilka310
|
|
|
|
/obj/item/ammo_casing/strilka310/Initialize(mapload)
|
|
. = ..()
|
|
|
|
AddElement(/datum/element/caseless)
|
|
|
|
/obj/item/ammo_casing/strilka310/surplus
|
|
name = ".310 Strilka surplus bullet casing"
|
|
desc = parent_type::desc + " Damp red powder at that."
|
|
projectile_type = /obj/projectile/bullet/strilka310/surplus
|
|
|
|
/obj/item/ammo_casing/strilka310/enchanted
|
|
projectile_type = /obj/projectile/bullet/strilka310/enchanted
|
|
|
|
/obj/item/ammo_casing/strilka310/phasic
|
|
name = ".310 Strilka phasic bullet casing"
|
|
desc = "A phasic .310 Strilka bullet casing."
|
|
projectile_type = /obj/projectile/bullet/strilka310/phasic
|
|
// .223 (M-90gl Carbine)
|
|
|
|
/obj/item/ammo_casing/a223
|
|
name = ".223 bullet casing"
|
|
desc = "A .223 bullet casing."
|
|
icon_state = "223-casing"
|
|
caliber = CALIBER_A223
|
|
projectile_type = /obj/projectile/bullet/a223
|
|
|
|
/obj/item/ammo_casing/a223/phasic
|
|
name = ".223 phasic bullet casing"
|
|
desc = "A .223 phasic bullet casing."
|
|
projectile_type = /obj/projectile/bullet/a223/phasic
|
|
|
|
/obj/item/ammo_casing/a223/weak
|
|
projectile_type = /obj/projectile/bullet/a223/weak
|
|
|
|
// 40mm (Grenade Launcher)
|
|
|
|
/obj/item/ammo_casing/a40mm
|
|
name = "40mm HE shell"
|
|
desc = "A cased high explosive grenade that can only be activated once fired out of a grenade launcher."
|
|
caliber = CALIBER_40MM
|
|
icon_state = "40mmHE"
|
|
projectile_type = /obj/projectile/bullet/a40mm
|
|
newtonian_force = 1.25
|
|
|
|
/obj/item/ammo_casing/a40mm/rubber
|
|
name = "40mm rubber shell"
|
|
desc = "A cased rubber slug. The big brother of the beanbag slug, this thing will knock someone out in one. Doesn't do so great against anyone in armor."
|
|
projectile_type = /obj/projectile/bullet/shotgun_beanbag/a40mm
|
|
|
|
/obj/item/ammo_casing/rebar
|
|
name = "Sharpened Iron Rod"
|
|
desc = "A Sharpened Iron rod. It's Pointy!"
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_sharp"
|
|
base_icon_state = "rod_sharp"
|
|
projectile_type = /obj/projectile/bullet/rebar
|
|
newtonian_force = 1.5
|
|
|
|
/obj/item/ammo_casing/rebar/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/caseless, TRUE)
|
|
|
|
/obj/item/ammo_casing/rebar/update_icon_state()
|
|
. = ..()
|
|
icon_state = "[base_icon_state]"
|
|
|
|
/obj/item/ammo_casing/rebar/syndie
|
|
name = "Jagged Iron Rod"
|
|
desc = "An Iron rod, with notches cut into it. You really don't want this stuck in you."
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_jagged"
|
|
base_icon_state = "rod_jagged"
|
|
projectile_type = /obj/projectile/bullet/rebar/syndie
|
|
|
|
/obj/item/ammo_casing/rebar/zaukerite
|
|
name = "zaukerite sliver"
|
|
desc = "A sliver of a zaukerite crystal. Due to its irregular, jagged edges, removal of an embedded zaukerite sliver should only be done by trained surgeons."
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_zaukerite"
|
|
base_icon_state = "rod_zaukerite"
|
|
projectile_type = /obj/projectile/bullet/rebar/zaukerite
|
|
|
|
/obj/item/ammo_casing/rebar/hydrogen
|
|
name = "metallic hydrogen bolt"
|
|
desc = "An ultra-sharp rod made from pure metallic hydrogen. Armor may as well not exist."
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_hydrogen"
|
|
base_icon_state = "rod_hydrogen"
|
|
projectile_type = /obj/projectile/bullet/rebar/hydrogen
|
|
|
|
/obj/item/ammo_casing/rebar/healium
|
|
name = "healium crystal bolt"
|
|
desc = "Who needs a syringe gun, anyway?"
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_healium"
|
|
base_icon_state = "rod_healium"
|
|
projectile_type = /obj/projectile/bullet/rebar/healium
|
|
/// How many seconds of healing/sleeping action we have left, once all are spent the bolt dissolves
|
|
var/heals_left = 6 SECONDS
|
|
|
|
/obj/item/ammo_casing/rebar/healium/ready_proj(atom/target, mob/living/user, quiet, zone_override, atom/fired_from)
|
|
if (loaded_projectile)
|
|
var/obj/projectile/bullet/rebar/healium/bolt = loaded_projectile
|
|
bolt.heals_left = heals_left
|
|
return ..()
|
|
|
|
/datum/embedding/rebar_healium
|
|
embed_chance = 100
|
|
fall_chance = 0
|
|
pain_stam_pct = 0.9
|
|
ignore_throwspeed_threshold = TRUE
|
|
rip_time = 1.5 SECONDS
|
|
/// Amount of each type of damage healed per second
|
|
var/healing_per_second = 5
|
|
/// Amount of drowsiness added per second
|
|
var/drowsy_per_second = 2 SECONDS
|
|
/// At what point of drowsiness do we knock out the owner
|
|
var/drowsy_knockout = 5 SECONDS // Actually more like 8 seconds, because you need 4 ticks to reach this
|
|
/// Can this bolt cause sleeping? Used to prevent sleep stacking by shooting multiple bolts
|
|
var/can_sleep = TRUE
|
|
|
|
/datum/embedding/rebar_healium/on_successful_embed(mob/living/carbon/victim, obj/item/bodypart/target_limb)
|
|
. = ..()
|
|
for(var/obj/item/bodypart/limb as anything in victim.bodyparts)
|
|
for(var/obj/item/ammo_casing/rebar/healium/other_rebar in limb.embedded_objects)
|
|
if (other_rebar == parent)
|
|
continue
|
|
var/datum/embedding/rebar_healium/embed_data = other_rebar.get_embed()
|
|
if (istype(embed_data) && embed_data.can_sleep)
|
|
can_sleep = FALSE
|
|
return
|
|
|
|
/datum/embedding/rebar_healium/process(seconds_per_tick)
|
|
. = ..()
|
|
var/obj/item/ammo_casing/rebar/healium/casing = parent
|
|
casing.heals_left -= seconds_per_tick * 1 SECONDS
|
|
var/update_health = FALSE
|
|
var/healing = -healing_per_second * seconds_per_tick
|
|
update_health += owner.adjustBruteLoss(healing, updating_health = FALSE, required_bodytype = BODYTYPE_ORGANIC)
|
|
update_health += owner.adjustFireLoss(healing, updating_health = FALSE, required_bodytype = BODYTYPE_ORGANIC)
|
|
update_health += owner.adjustToxLoss(healing, updating_health = FALSE, required_biotype = BODYTYPE_ORGANIC)
|
|
update_health += owner.adjustOxyLoss(healing, updating_health = FALSE, required_biotype = BODYTYPE_ORGANIC)
|
|
if (update_health)
|
|
owner.updatehealth()
|
|
if (can_sleep && (owner.mob_biotypes & MOB_ORGANIC))
|
|
owner.adjust_drowsiness(drowsy_per_second * seconds_per_tick)
|
|
var/datum/status_effect/drowsiness/drowsiness = owner.has_status_effect(/datum/status_effect/drowsiness)
|
|
if (drowsiness?.duration >= drowsy_knockout)
|
|
owner.Sleeping(3 SECONDS)
|
|
if (casing.heals_left <= 0)
|
|
fall_out()
|
|
|
|
/datum/embedding/rebar_healium/remove_embedding(mob/living/to_hands)
|
|
. = ..()
|
|
var/obj/item/ammo_casing/rebar/healium/casing = parent
|
|
casing.heals_left = initial(casing.heals_left)
|
|
can_sleep = TRUE
|
|
|
|
/obj/item/ammo_casing/rebar/supermatter
|
|
name = "supermatter bolt"
|
|
desc = "Wait, how is the bow capable of firing this without dusting?"
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "rod_supermatter"
|
|
base_icon_state = "rod_supermatter"
|
|
projectile_type = /obj/projectile/bullet/rebar/supermatter
|
|
|
|
/obj/item/ammo_casing/rebar/paperball
|
|
name = "paper ball"
|
|
desc = "Doink!"
|
|
caliber = CALIBER_REBAR
|
|
icon_state = "paperball"
|
|
base_icon_state = "paperball"
|
|
projectile_type = /obj/projectile/bullet/paperball
|
|
newtonian_force = 0.5
|