Refactors embedding to use datums instead of storing data in bespoke elements (#84599)

## About The Pull Request

This refactors embedding elements to make them use singleton datums
(similarly to armor) instead being bespoke and creating a new element
every time armor values are supposed to be adjusted.
Default values have been removed from defines due to now being declared
in base class itself.
Additionally fixes vending machines and tackling gloves setting
generated shards (which they instantly embed into their victim) embed
properties to null after running the embedding code, despite said shards
having non-null embedding values by default, making them not be able to
embed into anyone else, also potentially breaking the pain/jostling code
if they somehow get updated.

## Why It's Good For The Game

Current embedding system is an unnecessarily complicated mess as bespoke
elements are hard to work with, and creating a new element every time
you change values is hacky at best. This change should make it easier to
read and work with.

## Changelog
🆑
fix: Fixed glass shards generated from falling vending machines or
tackling windows not being able to embed into anyone.
refactor: Refactored embedding code to use datums instead of bespoke
elements and ugly associated lists.
/🆑
This commit is contained in:
SmArtKar
2024-07-08 00:20:07 +03:00
committed by GitHub
parent a358dc15ec
commit b6c84135c3
55 changed files with 558 additions and 390 deletions

View File

@@ -33,16 +33,17 @@
speed = 1
range = 25
shrapnel_type = null
embedding = list(
embed_chance = 90,
fall_chance = 2,
jostle_chance = 2,
ignore_throwspeed_threshold = TRUE,
pain_stam_pct = 0.5,
pain_mult = 3,
jostle_pain_mult = 3,
rip_time = 1 SECONDS
)
embed_type = /datum/embed_data/arrow
/datum/embed_data/arrow
embed_chance = 90
fall_chance = 2
jostle_chance = 2
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.5
pain_mult = 3
jostle_pain_mult = 3
rip_time = 1 SECONDS
/// holy arrows
/obj/item/ammo_casing/arrow/holy
@@ -99,7 +100,7 @@
desc = "THE UNMATCHED POWER OF THE SUN"
icon_state = "holy_arrow_projectile"
damage = 20
embedding = null
embed_type = null
/obj/projectile/bullet/arrow/blazing/on_hit(atom/target, blocked, pierce_hit)
. = ..()

View File

@@ -191,7 +191,9 @@
///If defined, on hit we create an item of this type then call hitby() on the hit target with this, mainly used for embedding items (bullets) in targets
var/shrapnel_type
///If we have a shrapnel_type defined, these embedding stats will be passed to the spawned shrapnel type, which will roll for embedding on the target
var/list/embedding
var/embed_type
///Saves embedding data
var/datum/embed_data/embed_data
///If TRUE, hit mobs, even if they are lying on the floor and are not our target within MAX_RANGE_HIT_PRONE_TARGETS tiles
var/hit_prone_targets = FALSE
///if TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets
@@ -218,8 +220,8 @@
/obj/projectile/Initialize(mapload)
. = ..()
decayedRange = range
if(embedding)
updateEmbedding()
if(get_embed())
AddElement(/datum/element/embed)
AddElement(/datum/element/connect_loc, projectile_connections)
/obj/projectile/proc/Range()
@@ -227,8 +229,8 @@
if(wound_bonus != CANT_WOUND)
wound_bonus += wound_falloff_tile
bare_wound_bonus = max(0, bare_wound_bonus + wound_falloff_tile)
if(embedding)
embedding["embed_chance"] += embed_falloff_tile
if(get_embed())
set_embed(embed_data.generate_with_values(embed_data.embed_chance + embed_falloff_tile)) // Should be rewritten in projecitle refactor
if(damage_falloff_tile && damage >= 0)
damage += damage_falloff_tile
if(stamina_falloff_tile && stamina >= 0)
@@ -1130,26 +1132,6 @@
/obj/projectile/experience_pressure_difference()
return
///Like [/obj/item/proc/updateEmbedding] but for projectiles instead, call this when you want to add embedding or update the stats on the embedding element
/obj/projectile/proc/updateEmbedding()
if(!shrapnel_type || !LAZYLEN(embedding))
return
AddElement(/datum/element/embed,\
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\
pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\
remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\
rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\
ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\
impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\
jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\
projectile_payload = shrapnel_type)
return TRUE
/**
* Is this projectile considered "hostile"?
*
@@ -1169,7 +1151,7 @@
///Checks if the projectile can embed into someone
/obj/projectile/proc/can_embed_into(atom/hit)
return embedding && shrapnel_type && iscarbon(hit) && !HAS_TRAIT(hit, TRAIT_PIERCEIMMUNE)
return get_embed() && shrapnel_type && iscarbon(hit) && !HAS_TRAIT(hit, TRAIT_PIERCEIMMUNE)
/// Reflects the projectile off of something
/obj/projectile/proc/reflect(atom/hit_atom)
@@ -1212,3 +1194,16 @@
bullet.preparePixelProjectile(target, src)
bullet.fire()
return bullet
/// Fetches embedding data
/obj/projectile/proc/get_embed()
return embed_type ? (embed_data ||= get_embed_by_type(embed_type)) : null
/obj/projectile/proc/set_embed(datum/embed_data/embed)
if(embed_data == embed)
return
// GLOB.embed_by_type stores shared "default" embedding values of datums
// Dynamically generated embeds use the base class and thus are not present in there, and should be qdeleted upon being discarded
if(!isnull(embed_data) && !GLOB.embed_by_type[embed_data.type])
qdel(embed_data)
embed_data = ispath(embed) ? get_embed_by_type(armor) : embed

View File

@@ -8,7 +8,7 @@
sharpness = SHARP_POINTY
impact_effect_type = /obj/effect/temp_visual/impact_effect
shrapnel_type = /obj/item/shrapnel/bullet
embedding = list(embed_chance=20, fall_chance=2, jostle_chance=0, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.5, pain_mult=3, rip_time=10)
embed_type = /datum/embed_data/bullet
wound_bonus = 0
wound_falloff_tile = -5
embed_falloff_tile = -3
@@ -16,3 +16,12 @@
/obj/projectile/bullet/smite
name = "divine retribution"
damage = 10
/datum/embed_data/bullet
embed_chance=20
fall_chance=2
jostle_chance=0
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.5
pain_mult=3
rip_time=10

View File

@@ -30,7 +30,7 @@
pass_flags = PASSTABLE | PASSMOB
sharpness = NONE
shrapnel_type = null
embedding = null
embed_type = null
impact_effect_type = null
suppressed = SUPPRESSED_VERY
damage_type = BURN

View File

@@ -8,7 +8,7 @@
dismemberment = 0
paralyze = 5 SECONDS
stutter = 20 SECONDS
embedding = null
embed_type = null
hitsound = 'sound/effects/meteorimpact.ogg'
hitsound_wall = 'sound/weapons/sonic_jackhammer.ogg'
/// If our cannonball hits something, it reduces the damage by this value.

View File

@@ -2,7 +2,7 @@
name = "dart"
icon_state = "cbbolt"
damage = 6
embedding = null
embed_type = null
shrapnel_type = null
var/inject_flags = null

View File

@@ -4,7 +4,7 @@
var/obj/item/dnainjector/injector
damage = 5
hitsound_wall = SFX_SHATTER
embedding = null
embed_type = null
shrapnel_type = null
/obj/projectile/bullet/dnainjector/on_hit(atom/target, blocked = 0, pierce_hit)

View File

@@ -8,7 +8,7 @@
base_icon_state = "foamdart"
range = 10
shrapnel_type = null
embedding = null
embed_type = null
var/modified = FALSE
var/obj/item/pen/pen = null

View File

@@ -5,7 +5,7 @@
desc = "USE A WEEL GUN"
icon_state= "bolter"
damage = 60
embedding = null
embed_type = null
shrapnel_type = null
/obj/projectile/bullet/a40mm/on_hit(atom/target, blocked = 0, pierce_hit)

View File

@@ -4,11 +4,21 @@
name = "junk bullet"
icon_state = "trashball"
damage = 30
embedding = list(embed_chance=15, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
embed_type = /datum/embed_data/bullet_junk
var/bane_mob_biotypes = MOB_ROBOTIC
var/bane_multiplier = 1.5
var/bane_added_damage = 0
/datum/embed_data/bullet_junk
embed_chance=15
fall_chance=3
jostle_chance=4
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=5
jostle_pain_mult=6
rip_time=10
/obj/projectile/bullet/junk/Initialize(mapload)
. = ..()
AddElement(/datum/element/bane, mob_biotypes = bane_mob_biotypes, target_type = /mob/living, damage_multiplier = bane_multiplier, added_damage = bane_added_damage, requires_combat_mode = FALSE)
@@ -28,7 +38,7 @@
name = "bundle of live electrical parts"
icon_state = "tesla_projectile"
damage = 15
embedding = null
embed_type = null
shrapnel_type = null
bane_multiplier = 3
@@ -49,10 +59,20 @@
name = "junk ripper bullet"
icon_state = "redtrac"
damage = 10
embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
embed_type = /datum/embed_data/bullet_junk_ripper
wound_bonus = 10
bare_wound_bonus = 30
/datum/embed_data/bullet_junk_ripper
embed_chance=100
fall_chance=3
jostle_chance=4
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=5
jostle_pain_mult=6
rip_time=10
/obj/projectile/bullet/junk/reaper
name = "junk reaper bullet"
tracer_type = /obj/effect/projectile/tracer/sniper

View File

@@ -3,13 +3,23 @@
/obj/projectile/bullet/c9mm
name = "9mm bullet"
damage = 30
embedding = list(embed_chance=15, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
embed_type = /datum/embed_data/bullet_c9mm
/datum/embed_data/bullet_c9mm
embed_chance=15
fall_chance=3
jostle_chance=4
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=5
jostle_pain_mult=6
rip_time=10
/obj/projectile/bullet/c9mm/ap
name = "9mm armor-piercing bullet"
damage = 27
armour_penetration = 40
embedding = null
embed_type = null
shrapnel_type = null
/obj/projectile/bullet/c9mm/hp

View File

@@ -21,9 +21,19 @@
ricochet_auto_aim_range = 3
wound_bonus = -20
bare_wound_bonus = 10
embedding = list(embed_chance=25, fall_chance=2, jostle_chance=2, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=5, rip_time=1 SECONDS)
embed_type = /datum/embed_data/bullet_c38
embed_falloff_tile = -4
/datum/embed_data/bullet_c38
embed_chance=25
fall_chance=2
jostle_chance=2
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=3
jostle_pain_mult=5
rip_time=1 SECONDS
/obj/projectile/bullet/c38/match
name = ".38 Match bullet"
ricochets_max = 4
@@ -45,7 +55,7 @@
ricochet_decay_damage = 0.8
shrapnel_type = null
sharpness = NONE
embedding = null
embed_type = null
// premium .38 ammo from cargo, weak against armor, lower base damage, but excellent at embedding and causing slice wounds at close range
/obj/projectile/bullet/c38/dumdum
@@ -56,10 +66,20 @@
sharpness = SHARP_EDGED
wound_bonus = 20
bare_wound_bonus = 20
embedding = list(embed_chance=75, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=1 SECONDS)
embed_type = /datum/embed_data/bullet_c38_dumdum
wound_falloff_tile = -5
embed_falloff_tile = -15
/datum/embed_data/bullet_c38_dumdum
embed_chance=75
fall_chance=3
jostle_chance=4
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=5
jostle_pain_mult=6
rip_time=1 SECONDS
/obj/projectile/bullet/c38/trac
name = ".38 TRAC bullet"
damage = 10

View File

@@ -48,10 +48,20 @@
armour_penetration = 50
wound_bonus = -20
bare_wound_bonus = 80
embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
embed_type = /datum/embed_data/harpoon
wound_falloff_tile = -5
shrapnel_type = null
/datum/embed_data/harpoon
embed_chance=100
fall_chance=3
jostle_chance=4
ignore_throwspeed_threshold=TRUE
pain_stam_pct=0.4
pain_mult=5
jostle_pain_mult=6
rip_time=10
// Rebar (Rebar Crossbow)
/obj/projectile/bullet/rebar
name = "rebar"
@@ -62,11 +72,21 @@
armour_penetration = 10
wound_bonus = -20
bare_wound_bonus = 20
embedding = list("embed_chance" = 60, "fall_chance" = 2, "jostle_chance" = 2, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.4, "pain_mult" = 4, "jostle_pain_mult" = 2, "rip_time" = 10)
embed_type = /datum/embed_data/rebar
embed_falloff_tile = -5
wound_falloff_tile = -2
shrapnel_type = /obj/item/ammo_casing/rebar
/datum/embed_data/rebar
embed_chance = 60
fall_chance = 2
jostle_chance = 2
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.4
pain_mult = 4
jostle_pain_mult = 2
rip_time = 10
/obj/projectile/bullet/rebar/proc/handle_drop(datum/source, obj/item/ammo_casing/rebar/newcasing)
/obj/projectile/bullet/rebar/syndie
@@ -78,10 +98,20 @@
armour_penetration = 20 //A bit better versus armor. Gets past anti laser armor or a vest, but doesnt wound proc on sec armor.
wound_bonus = 10
bare_wound_bonus = 20
embedding = list("embed_chance" = 80, "fall_chance" = 1, "jostle_chance" = 3, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.4, "pain_mult" = 3, "jostle_pain_mult" = 2, "rip_time" = 14)
embed_falloff_tile = -3
embed_type = /datum/embed_data/rebar_syndie
shrapnel_type = /obj/item/ammo_casing/rebar/syndie
/datum/embed_data/rebar_syndie
embed_chance = 80
fall_chance = 1
jostle_chance = 3
ignore_throwspeed_threshold
pain_stam_pct = 0.4
pain_mult = 3
jostle_pain_mult = 2
rip_time = 14
/obj/projectile/bullet/rebar/zaukerite
name = "zaukerite shard"
icon_state = "rebar_zaukerite"
@@ -93,10 +123,20 @@
armour_penetration = 20 // not nearly as good, as its not as sharp.
wound_bonus = 10
bare_wound_bonus = 40
embedding = list("embed_chance" =100, "fall_chance" = 0, "jostle_chance" = 5, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.8, "pain_mult" = 6, "jostle_pain_mult" = 2, "rip_time" = 30)
embed_type = /datum/embed_data/rebar_zaukerite
embed_falloff_tile = 0 // very spiky.
shrapnel_type = /obj/item/ammo_casing/rebar/zaukerite
/datum/embed_data/rebar_zaukerite
embed_chance = 100
fall_chance = 0
jostle_chance = 5
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.8
pain_mult = 6
jostle_pain_mult = 2
rip_time = 30
/obj/projectile/bullet/rebar/hydrogen
name = "metallic hydrogen bolt"
icon_state = "rebar_hydrogen"
@@ -108,10 +148,20 @@
projectile_piercing = PASSMOB //felt this might have been a nice compromise for the lower damage for the difficulty of getting it
wound_bonus = -15
bare_wound_bonus = 10
embedding = list("embed_chance" = 50, "fall_chance" = 2, "jostle_chance" = 3, "ignore_throwspeed_threshold" = TRUE, "pain_stam_pct" = 0.6, "pain_mult" = 4, "jostle_pain_mult" = 2, "rip_time" =18)
embed_type = /datum/embed_data/rebar_hydrogen
embed_falloff_tile = -3
shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen
/datum/embed_data/rebar_hydrogen
embed_chance = 50
fall_chance = 2
jostle_chance = 3
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.6
pain_mult = 4
jostle_pain_mult = 2
rip_time =18
/obj/projectile/bullet/rebar/healium
name = "healium bolt"
icon_state = "rebar_healium"
@@ -122,7 +172,7 @@
armour_penetration = 100
wound_bonus = -100
bare_wound_bonus = -100
embedding = list(embed_chance = 0)
embed_type = null
embed_falloff_tile = -3
shrapnel_type = /obj/item/ammo_casing/rebar/healium
@@ -139,7 +189,6 @@
return BULLET_ACT_HIT
/obj/projectile/bullet/rebar/supermatter
name = "supermatter bolt"
icon_state = "rebar_supermatter"
@@ -147,6 +196,7 @@
speed = 0.4
dismemberment = 0
damage_type = TOX
embed_type = null
armour_penetration = 100
shrapnel_type = /obj/item/ammo_casing/rebar/supermatter
@@ -164,7 +214,6 @@
return BULLET_ACT_HIT
/obj/projectile/bullet/rebar/supermatter/proc/dust_feedback(atom/target)
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 10, TRUE)
visible_message(span_danger("[target] is hit by [src], turning [target.p_them()] to dust in a brilliant flash of light!"))
@@ -174,7 +223,7 @@
damage = 1 // It's a damn toy.
range = 10
shrapnel_type = null
embedding = null
embed_type = null
name = "paper ball"
desc = "doink!"
damage_type = BRUTE

View File

@@ -22,7 +22,7 @@
stamina = 55
wound_bonus = 20
sharpness = NONE
embedding = null
embed_type = null
/obj/projectile/bullet/shotgun_beanbag/a40mm
name = "rubber slug"
@@ -55,7 +55,7 @@
range = 7
icon_state = "spark"
color = COLOR_YELLOW
embedding = null
embed_type = null
/obj/projectile/bullet/shotgun_frag12
name ="frag12 slug"
@@ -84,7 +84,7 @@
damage = 3
stamina = 11
sharpness = NONE
embedding = null
embed_type = null
speed = 1.2
stamina_falloff_tile = -0.25
ricochets_max = 4
@@ -106,7 +106,7 @@
name = "incapacitating pellet"
damage = 1
stamina = 6
embedding = null
embed_type = null
// Mech Scattershot

View File

@@ -33,7 +33,7 @@
name = "4.6x30mm armor-piercing bullet"
damage = 15
armour_penetration = 40
embedding = null
embed_type = null
/obj/projectile/bullet/incendiary/c46x30mm
name = "4.6x30mm incendiary bullet"

View File

@@ -9,7 +9,7 @@
icon = 'icons/obj/service/hydroponics/harvest.dmi'
icon_state = "banana"
range = 200
embedding = null
embed_type = null
shrapnel_type = null
/obj/projectile/bullet/honker/Initialize(mapload)

View File

@@ -2,7 +2,7 @@
name ="explosive bolt"
icon_state= "bolter"
damage = 50
embedding = null
embed_type = null
shrapnel_type = null
/obj/projectile/bullet/gyro/on_hit(atom/target, blocked = 0, pierce_hit)
@@ -17,7 +17,7 @@
icon_state= "missile"
damage = 50
sharpness = NONE
embedding = null
embed_type = null
shrapnel_type = null
ricochets_max = 0
/// Whether we do extra damage when hitting a mech or silicon