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

@@ -180,38 +180,11 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define UNARMED_MISS_CHANCE_MAX 80 #define UNARMED_MISS_CHANCE_MAX 80
//Combat object defines //Combat object defines
/// The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
//Embedded objects
///Chance for embedded objects to cause pain (damage user)
#define EMBEDDED_PAIN_CHANCE 15
///Chance for embedded object to fall out (causing pain but removing the object)
#define EMBEDDED_ITEM_FALLOUT 5
///Chance for an object to embed into somebody when thrown
#define EMBED_CHANCE 45
///Coefficient of multiplication for the damage the item does while embedded (this*item.w_class)
#define EMBEDDED_PAIN_MULTIPLIER 2
///Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class)
#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4
///The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
#define EMBED_THROWSPEED_THRESHOLD 4 #define EMBED_THROWSPEED_THRESHOLD 4
///Coefficient of multiplication for the damage the item does when it falls out or is removed without a surgery (this*item.w_class) /// For thrown embedding weapons, every extra speed it's thrown at above its normal throwspeed will add this to the embed chance
#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 6
///A Time in ticks, total removal time = (this*item.w_class)
#define EMBEDDED_UNSAFE_REMOVAL_TIME 30
///Chance for embedded objects to cause pain every time they move (jostle)
#define EMBEDDED_JOSTLE_CHANCE 5
///Coefficient of multiplication for the damage the item does while
#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1
///This percentage of all pain will be dealt as stam damage rather than brute (0-1)
#define EMBEDDED_PAIN_STAM_PCT 0.0
///For thrown weapons, every extra speed it's thrown at above its normal throwspeed will add this to the embed chance
#define EMBED_CHANCE_SPEED_BONUS 10 #define EMBED_CHANCE_SPEED_BONUS 10
#define EMBED_HARMLESS list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
#define EMBED_HARMLESS_SUPERIOR list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE, "embed_chance" = 100, "fall_chance" = 0.1)
#define EMBED_POINTY list("ignore_throwspeed_threshold" = TRUE)
#define EMBED_POINTY_SUPERIOR list("embed_chance" = 100, "ignore_throwspeed_threshold" = TRUE)
//Gun weapon weight //Gun weapon weight
#define WEAPON_LIGHT 1 #define WEAPON_LIGHT 1
#define WEAPON_MEDIUM 2 #define WEAPON_MEDIUM 2

View File

@@ -142,11 +142,8 @@
projectile.wound_bonus += var_modifiers["wound_bonus"] projectile.wound_bonus += var_modifiers["wound_bonus"]
projectile.bare_wound_bonus += var_modifiers["bare_wound_bonus"] projectile.bare_wound_bonus += var_modifiers["bare_wound_bonus"]
projectile.demolition_mod += var_modifiers["demolition_mod"] projectile.demolition_mod += var_modifiers["demolition_mod"]
if(islist(var_modifiers["embedding"])) if(var_modifiers["embedding"])
var/list/embed_params = var_modifiers["embedding"] projectile.set_embed(var_modifiers["embedding"])
for(var/embed_param in embed_params - "ignore_throwspeed_threshold")
LAZYADDASSOC(projectile.embedding, embed_param, embed_params[embed_param])
projectile.updateEmbedding()
/datum/component/dart_insert/proc/remove_var_modifiers(obj/projectile/projectile) /datum/component/dart_insert/proc/remove_var_modifiers(obj/projectile/projectile)
projectile.damage -= var_modifiers["damage"] projectile.damage -= var_modifiers["damage"]
@@ -155,9 +152,6 @@
projectile.wound_bonus -= var_modifiers["wound_bonus"] projectile.wound_bonus -= var_modifiers["wound_bonus"]
projectile.bare_wound_bonus -= var_modifiers["bare_wound_bonus"] projectile.bare_wound_bonus -= var_modifiers["bare_wound_bonus"]
projectile.demolition_mod -= var_modifiers["demolition_mod"] projectile.demolition_mod -= var_modifiers["demolition_mod"]
if(islist(var_modifiers["embedding"])) if(var_modifiers["embedding"])
var/list/embed_params = var_modifiers["embedding"] projectile.set_embed(initial(projectile.embed_type))
for(var/embed_param in embed_params - "ignore_throwspeed_threshold")
LAZYADDASSOC(projectile.embedding, embed_param, -embed_params[embed_param])
projectile.updateEmbedding()
var_modifiers.Cut() var_modifiers.Cut()

View File

@@ -27,63 +27,28 @@
dupe_mode = COMPONENT_DUPE_ALLOWED dupe_mode = COMPONENT_DUPE_ALLOWED
var/obj/item/bodypart/limb var/obj/item/bodypart/limb
var/obj/item/weapon var/obj/item/weapon
// all of this stuff is explained in _DEFINES/combat.dm
var/embed_chance // not like we really need it once we're already stuck in but hey
var/fall_chance
var/pain_chance
var/pain_mult
var/impact_pain_mult
var/remove_pain_mult
var/rip_time
var/ignore_throwspeed_threshold
var/jostle_chance
var/jostle_pain_mult
var/pain_stam_pct
///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff ///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff
var/harmful var/harmful
/datum/component/embedded/Initialize(obj/item/I, /datum/component/embedded/Initialize(obj/item/weapon,
datum/thrownthing/throwingdatum, datum/thrownthing/throwingdatum,
obj/item/bodypart/part, obj/item/bodypart/part)
embed_chance = EMBED_CHANCE,
fall_chance = EMBEDDED_ITEM_FALLOUT,
pain_chance = EMBEDDED_PAIN_CHANCE,
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
ignore_throwspeed_threshold = FALSE,
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT)
if(!iscarbon(parent) || !isitem(I)) if(!iscarbon(parent) || !isitem(weapon))
return COMPONENT_INCOMPATIBLE return COMPONENT_INCOMPATIBLE
src.weapon = weapon
if(part) if(part)
limb = part limb = part
src.embed_chance = embed_chance
src.fall_chance = fall_chance
src.pain_chance = pain_chance
src.pain_mult = pain_mult
src.remove_pain_mult = remove_pain_mult
src.rip_time = rip_time
src.impact_pain_mult = impact_pain_mult
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
src.jostle_chance = jostle_chance
src.jostle_pain_mult = jostle_pain_mult
src.pain_stam_pct = pain_stam_pct
src.weapon = I
if(!weapon.isEmbedHarmless()) if(!weapon.is_embed_harmless())
harmful = TRUE harmful = TRUE
weapon.embedded(parent, part) weapon.embedded(parent, part)
START_PROCESSING(SSdcs, src) START_PROCESSING(SSdcs, src)
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
var/datum/embed_data/embed_data = weapon.get_embed()
limb._embed_object(weapon) // on the inside... on the inside... limb._embed_object(weapon) // on the inside... on the inside...
weapon.forceMove(victim) weapon.forceMove(victim)
RegisterSignals(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING), PROC_REF(weaponDeleted)) RegisterSignals(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING), PROC_REF(weaponDeleted))
@@ -95,13 +60,13 @@
playsound(victim,'sound/weapons/bladeslice.ogg', 40) playsound(victim,'sound/weapons/bladeslice.ogg', 40)
if (limb.can_bleed()) if (limb.can_bleed())
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody! weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
damage += weapon.w_class * impact_pain_mult damage += weapon.w_class * embed_data.impact_pain_mult
victim.add_mood_event("embedded", /datum/mood_event/embedded) victim.add_mood_event("embedded", /datum/mood_event/embedded)
if(damage > 0) if(damage > 0)
var/armor = victim.run_armor_check(limb.body_zone, MELEE, "Your armor has protected your [limb.plaintext_zone].", "Your armor has softened a hit to your [limb.plaintext_zone].",I.armour_penetration, weak_against_armour = I.weak_against_armour) var/armor = victim.run_armor_check(limb.body_zone, MELEE, "Your armor has protected your [limb.plaintext_zone].", "Your armor has softened a hit to your [limb.plaintext_zone].", weapon.armour_penetration, weak_against_armour = weapon.weak_against_armour)
limb.receive_damage(brute=(1-pain_stam_pct) * damage, blocked=armor, wound_bonus = I.wound_bonus, bare_wound_bonus = I.bare_wound_bonus, sharpness = I.get_sharpness()) limb.receive_damage(brute = (1 - embed_data.pain_stam_pct) * damage, blocked = armor, wound_bonus = weapon.wound_bonus, bare_wound_bonus = weapon.bare_wound_bonus, sharpness = weapon.get_sharpness())
victim.adjustStaminaLoss(pain_stam_pct * damage) victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
/datum/component/embedded/Destroy() /datum/component/embedded/Destroy()
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
@@ -135,20 +100,21 @@
if(victim.stat == DEAD) if(victim.stat == DEAD)
return return
var/damage = weapon.w_class * pain_mult var/datum/embed_data/embed_data = weapon.get_embed()
var/pain_chance_current = SPT_PROB_RATE(pain_chance / 100, seconds_per_tick) * 100 var/damage = weapon.w_class * embed_data.pain_mult
if(pain_stam_pct && HAS_TRAIT_FROM(victim, TRAIT_INCAPACITATED, STAMINA)) //if it's a less-lethal embed, give them a break if they're already stamcritted var/pain_chance_current = SPT_PROB_RATE(embed_data.pain_chance / 100, seconds_per_tick) * 100
if(embed_data.pain_stam_pct && HAS_TRAIT_FROM(victim, TRAIT_INCAPACITATED, STAMINA)) //if it's a less-lethal embed, give them a break if they're already stamcritted
pain_chance_current *= 0.2 pain_chance_current *= 0.2
damage *= 0.5 damage *= 0.5
else if(victim.body_position == LYING_DOWN) else if(victim.body_position == LYING_DOWN)
pain_chance_current *= 0.2 pain_chance_current *= 0.2
if(harmful && prob(pain_chance_current)) if(harmful && prob(pain_chance_current))
limb.receive_damage(brute=(1-pain_stam_pct) * damage, wound_bonus = CANT_WOUND) limb.receive_damage(brute = (1 - embed_data.pain_stam_pct) * damage, wound_bonus = CANT_WOUND)
victim.adjustStaminaLoss(pain_stam_pct * damage) victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
to_chat(victim, span_userdanger("[weapon] embedded in your [limb.plaintext_zone] hurts!")) to_chat(victim, span_userdanger("[weapon] embedded in your [limb.plaintext_zone] hurts!"))
var/fall_chance_current = SPT_PROB_RATE(fall_chance / 100, seconds_per_tick) * 100 var/fall_chance_current = SPT_PROB_RATE(embed_data.fall_chance / 100, seconds_per_tick) * 100
if(victim.body_position == LYING_DOWN) if(victim.body_position == LYING_DOWN)
fall_chance_current *= 0.2 fall_chance_current *= 0.2
@@ -165,25 +131,27 @@
SIGNAL_HANDLER SIGNAL_HANDLER
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
var/chance = jostle_chance var/datum/embed_data/embed_data = weapon.get_embed()
var/chance = embed_data.jostle_chance
if(victim.move_intent == MOVE_INTENT_WALK || victim.body_position == LYING_DOWN) if(victim.move_intent == MOVE_INTENT_WALK || victim.body_position == LYING_DOWN)
chance *= 0.5 chance *= 0.5
if(harmful && prob(chance)) if(harmful && prob(chance))
var/damage = weapon.w_class * jostle_pain_mult var/damage = weapon.w_class * embed_data.jostle_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, wound_bonus = CANT_WOUND) limb.receive_damage(brute = (1 - embed_data.pain_stam_pct) * damage, wound_bonus = CANT_WOUND)
victim.adjustStaminaLoss(pain_stam_pct * damage) victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
to_chat(victim, span_userdanger("[weapon] embedded in your [limb.plaintext_zone] jostles and stings!")) to_chat(victim, span_userdanger("[weapon] embedded in your [limb.plaintext_zone] jostles and stings!"))
/// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove() /// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove()
/datum/component/embedded/proc/fallOut() /datum/component/embedded/proc/fallOut()
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
var/datum/embed_data/embed_data = weapon.get_embed()
if(harmful) if(harmful)
var/damage = weapon.w_class * remove_pain_mult var/damage = weapon.w_class * embed_data.remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, wound_bonus = CANT_WOUND) limb.receive_damage(brute= (1 - embed_data.pain_stam_pct) * damage, wound_bonus = CANT_WOUND)
victim.adjustStaminaLoss(pain_stam_pct * damage) victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
victim.visible_message(span_danger("[weapon] falls [harmful ? "out" : "off"] of [victim.name]'s [limb.plaintext_zone]!"), span_userdanger("[weapon] falls [harmful ? "out" : "off"] of your [limb.plaintext_zone]!")) victim.visible_message(span_danger("[weapon] falls [harmful ? "out" : "off"] of [victim.name]'s [limb.plaintext_zone]!"), span_userdanger("[weapon] falls [harmful ? "out" : "off"] of your [limb.plaintext_zone]!"))
safeRemove() safeRemove()
@@ -195,7 +163,8 @@
if(I != weapon || src.limb != limb) if(I != weapon || src.limb != limb)
return return
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
var/time_taken = rip_time * weapon.w_class var/datum/embed_data/embed_data = weapon.get_embed()
var/time_taken = embed_data.rip_time * weapon.w_class
INVOKE_ASYNC(src, PROC_REF(complete_rip_out), victim, I, limb, time_taken) INVOKE_ASYNC(src, PROC_REF(complete_rip_out), victim, I, limb, time_taken)
/// everything async that ripOut used to do /// everything async that ripOut used to do
@@ -214,9 +183,10 @@
/// Proc that actually does the damage associated with ripping something out of yourself. Call this before safeRemove. /// Proc that actually does the damage associated with ripping something out of yourself. Call this before safeRemove.
/datum/component/embedded/proc/damaging_removal(mob/living/carbon/victim, obj/item/removed, obj/item/bodypart/limb, ouch_multiplier = 1) /datum/component/embedded/proc/damaging_removal(mob/living/carbon/victim, obj/item/removed, obj/item/bodypart/limb, ouch_multiplier = 1)
var/damage = weapon.w_class * remove_pain_mult * ouch_multiplier var/datum/embed_data/embed_data = weapon.get_embed()
limb.receive_damage(brute=(1-pain_stam_pct) * damage, sharpness=SHARP_EDGED) //It hurts to rip it out, get surgery you dingus. unlike the others, this CAN wound + increase slash bloodflow var/damage = weapon.w_class * embed_data.remove_pain_mult * ouch_multiplier
victim.adjustStaminaLoss(pain_stam_pct * damage) limb.receive_damage(brute= (1 - embed_data.pain_stam_pct) * damage, sharpness = SHARP_EDGED) //It hurts to rip it out, get surgery you dingus. unlike the others, this CAN wound + increase slash bloodflow
victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
victim.emote("scream") victim.emote("scream")
/// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely. /// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely.
@@ -271,12 +241,13 @@
/// The actual action for pulling out an embedded object with a hemostat /// The actual action for pulling out an embedded object with a hemostat
/datum/component/embedded/proc/tweezePluck(obj/item/possible_tweezers, mob/user) /datum/component/embedded/proc/tweezePluck(obj/item/possible_tweezers, mob/user)
var/mob/living/carbon/victim = parent var/mob/living/carbon/victim = parent
var/datum/embed_data/embed_data = weapon.get_embed()
var/self_pluck = (user == victim) var/self_pluck = (user == victim)
// quality of the tool we're using // quality of the tool we're using
var/tweezer_speed = possible_tweezers.toolspeed var/tweezer_speed = possible_tweezers.toolspeed
// is this an actual piece of medical equipment // is this an actual piece of medical equipment
var/tweezer_safe = (possible_tweezers.tool_behaviour == TOOL_HEMOSTAT) var/tweezer_safe = (possible_tweezers.tool_behaviour == TOOL_HEMOSTAT)
var/pluck_time = rip_time * (weapon.w_class * 0.3) * (self_pluck ? 1.5 : 1) * tweezer_speed * (tweezer_safe ? 1 : 1.5) var/pluck_time = embed_data.rip_time * (weapon.w_class * 0.3) * (self_pluck ? 1.5 : 1) * tweezer_speed * (tweezer_safe ? 1 : 1.5)
if(self_pluck) if(self_pluck)
user.visible_message(span_danger("[user] begins plucking [weapon] from [user.p_their()] [limb.plaintext_zone] with [possible_tweezers]..."), span_notice("You start plucking [weapon] from your [limb.plaintext_zone] with [possible_tweezers]... (It will take [DisplayTimeText(pluck_time)])"),\ user.visible_message(span_danger("[user] begins plucking [weapon] from [user.p_their()] [limb.plaintext_zone] with [possible_tweezers]..."), span_notice("You start plucking [weapon] from your [limb.plaintext_zone] with [possible_tweezers]... (It will take [DisplayTimeText(pluck_time)])"),\
@@ -313,10 +284,12 @@
if(!harmful) if(!harmful)
victim.visible_message(span_danger("[marked_item] vanishes from [victim.name]'s [limb.plaintext_zone]!"), span_userdanger("[weapon] vanishes from [limb.plaintext_zone]!")) victim.visible_message(span_danger("[marked_item] vanishes from [victim.name]'s [limb.plaintext_zone]!"), span_userdanger("[weapon] vanishes from [limb.plaintext_zone]!"))
return return
var/damage = weapon.w_class * remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage * 1.5, sharpness=SHARP_EDGED) // Performs exit wounds and flings the user to the caster if nearby var/datum/embed_data/embed_data = weapon.get_embed()
var/damage = weapon.w_class * embed_data.remove_pain_mult
limb.receive_damage(brute = (1 - embed_data.pain_stam_pct) * damage * 1.5, sharpness = SHARP_EDGED) // Performs exit wounds and flings the user to the caster if nearby
victim.cause_wound_of_type_and_severity(WOUND_PIERCE, limb, WOUND_SEVERITY_MODERATE) victim.cause_wound_of_type_and_severity(WOUND_PIERCE, limb, WOUND_SEVERITY_MODERATE)
victim.adjustStaminaLoss(pain_stam_pct * damage) victim.adjustStaminaLoss(embed_data.pain_stam_pct * damage)
playsound(get_turf(victim), 'sound/effects/wounds/blood2.ogg', 50, TRUE) playsound(get_turf(victim), 'sound/effects/wounds/blood2.ogg', 50, TRUE)
var/dist = get_dist(caster, victim) //Check if the caster is close enough to yank them in var/dist = get_dist(caster, victim) //Check if the caster is close enough to yank them in

View File

@@ -596,11 +596,9 @@
if(W.type in list(/obj/structure/window, /obj/structure/window/fulltile, /obj/structure/window/unanchored, /obj/structure/window/fulltile/unanchored)) // boring unreinforced windows if(W.type in list(/obj/structure/window, /obj/structure/window/fulltile, /obj/structure/window/unanchored, /obj/structure/window/fulltile/unanchored)) // boring unreinforced windows
for(var/i in 1 to speed) for(var/i in 1 to speed)
var/obj/item/shard/shard = new /obj/item/shard(get_turf(user)) var/obj/item/shard/shard = new /obj/item/shard(get_turf(user))
shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5) shard.set_embed(/datum/embed_data/glass_candy)
shard.updateEmbedding()
user.hitby(shard, skipcatch = TRUE, hitpush = FALSE) user.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
shard.embedding = null shard.set_embed(initial(shard.embed_type))
shard.updateEmbedding()
W.atom_destruction() W.atom_destruction()
user.adjustStaminaLoss(10 * speed) user.adjustStaminaLoss(10 * speed)
user.Paralyze(3 SECONDS) user.Paralyze(3 SECONDS)

View File

@@ -24,7 +24,6 @@
if(reusable) if(reusable)
if(!ispath(proj.shrapnel_type)) if(!ispath(proj.shrapnel_type))
proj.shrapnel_type = shell.type proj.shrapnel_type = shell.type
proj.updateEmbedding()
proj.AddElement(/datum/element/projectile_drop, shell.type) proj.AddElement(/datum/element/projectile_drop, shell.type)
/datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) /datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj)

View File

@@ -10,64 +10,33 @@
*/ */
/datum/element/embed /datum/element/embed
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
var/initialized = FALSE /// whether we can skip assigning all the vars (since these are bespoke elements, we don't have to reset the vars every time we attach to something, we already know what we are!)
// all of this stuff is explained in _DEFINES/combat.dm /datum/element/embed/Attach(datum/target)
var/embed_chance
var/fall_chance
var/pain_chance
var/pain_mult
var/remove_pain_mult
var/impact_pain_mult
var/rip_time
var/ignore_throwspeed_threshold
var/jostle_chance
var/jostle_pain_mult
var/pain_stam_pct
var/payload_type
/datum/element/embed/Attach(datum/target, embed_chance, fall_chance, pain_chance, pain_mult, remove_pain_mult, impact_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct, projectile_payload=/obj/item/shard)
. = ..() . = ..()
if(!isitem(target) && !isprojectile(target)) if(!isitem(target) && !isprojectile(target))
return ELEMENT_INCOMPATIBLE return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ELEMENT_ATTACH, PROC_REF(severancePackage)) RegisterSignal(target, COMSIG_ELEMENT_ATTACH, PROC_REF(sever_element))
if(isitem(target)) if(isprojectile(target))
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, PROC_REF(checkEmbed)) RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(check_embed_projectile))
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(examined)) return
RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, PROC_REF(tryForceEmbed))
RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, PROC_REF(detachFromWeapon))
else
payload_type = projectile_payload
RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(checkEmbedProjectile))
if(!initialized) RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, PROC_REF(check_embed))
src.embed_chance = embed_chance RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(examined))
src.fall_chance = fall_chance RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, PROC_REF(try_force_embed))
src.pain_chance = pain_chance RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, PROC_REF(detach_from_weapon))
src.pain_mult = pain_mult
src.remove_pain_mult = remove_pain_mult
src.rip_time = rip_time
src.impact_pain_mult = impact_pain_mult
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
src.jostle_chance = jostle_chance
src.jostle_pain_mult = jostle_pain_mult
src.pain_stam_pct = pain_stam_pct
initialized = TRUE
/datum/element/embed/Detach(obj/target) /datum/element/embed/Detach(obj/target)
. = ..() . = ..()
if(isitem(target)) if(isprojectile(target))
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_ATOM_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
else
UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT, COMSIG_ELEMENT_ATTACH)) UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT, COMSIG_ELEMENT_ATTACH))
return
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_ATOM_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
/// Checking to see if we're gonna embed into a human /// Checking to see if we're gonna embed into a human
/datum/element/embed/proc/checkEmbed(obj/item/weapon, mob/living/carbon/victim, hit_zone, blocked, datum/thrownthing/throwingdatum, forced=FALSE) /datum/element/embed/proc/check_embed(obj/item/weapon, mob/living/carbon/victim, hit_zone, blocked, datum/thrownthing/throwingdatum, forced=FALSE)
SIGNAL_HANDLER SIGNAL_HANDLER
if(forced) if(forced)
@@ -82,7 +51,7 @@
var/flying_speed = throwingdatum?.speed || weapon.throw_speed var/flying_speed = throwingdatum?.speed || weapon.throw_speed
if(flying_speed < EMBED_THROWSPEED_THRESHOLD && !ignore_throwspeed_threshold) if(flying_speed < EMBED_THROWSPEED_THRESHOLD && !weapon.get_embed().ignore_throwspeed_threshold)
return FALSE return FALSE
if(!roll_embed_chance(weapon, victim, hit_zone, throwingdatum)) if(!roll_embed_chance(weapon, victim, hit_zone, throwingdatum))
@@ -97,27 +66,17 @@
victim.AddComponent(/datum/component/embedded,\ victim.AddComponent(/datum/component/embedded,\
weapon,\ weapon,\
throwingdatum,\ throwingdatum,\
part = limb,\ part = limb)
embed_chance = embed_chance,\
fall_chance = fall_chance,\
pain_chance = pain_chance,\
pain_mult = pain_mult,\
remove_pain_mult = remove_pain_mult,\
rip_time = rip_time,\
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
jostle_chance = jostle_chance,\
jostle_pain_mult = jostle_pain_mult,\
pain_stam_pct = pain_stam_pct)
///A different embed element has been attached, so we'll detach and let them handle things ///A different embed element has been attached, so we'll detach and let them handle things
/datum/element/embed/proc/severancePackage(obj/weapon, datum/element/E) /datum/element/embed/proc/sever_element(obj/weapon, datum/element/E)
SIGNAL_HANDLER SIGNAL_HANDLER
if(istype(E, /datum/element/embed)) if(istype(E, /datum/element/embed))
Detach(weapon) Detach(weapon)
///If we don't want to be embeddable anymore (deactivating an e-dagger for instance) ///If we don't want to be embeddable anymore (deactivating an e-dagger for instance)
/datum/element/embed/proc/detachFromWeapon(obj/weapon) /datum/element/embed/proc/detach_from_weapon(obj/weapon)
SIGNAL_HANDLER SIGNAL_HANDLER
Detach(weapon) Detach(weapon)
@@ -126,26 +85,26 @@
/datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list) /datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list)
SIGNAL_HANDLER SIGNAL_HANDLER
if(I.isEmbedHarmless()) if(I.is_embed_harmless())
examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!" examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!"
else else
examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!" examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!"
/** /**
* checkEmbedProjectile() is what we get when a projectile with a defined shrapnel_type impacts a target. * check_embed_projectile() is what we get when a projectile with a defined shrapnel_type impacts a target.
* *
* If we hit a valid target, we create the shrapnel_type object and then forcefully try to embed it on its * If we hit a valid target, we create the shrapnel_type object and then forcefully try to embed it on its
* behalf. DO NOT EVER add an embed element to the payload and let it do the rest. * behalf. DO NOT EVER add an embed element to the payload and let it do the rest.
* That's awful, and it'll limit us to drop-deletable shrapnels in the worry of stuff like * That's awful, and it'll limit us to drop-deletable shrapnels in the worry of stuff like
* arrows and harpoons being embeddable even when not let loose by their weapons. * arrows and harpoons being embeddable even when not let loose by their weapons.
*/ */
/datum/element/embed/proc/checkEmbedProjectile(obj/projectile/source, atom/movable/firer, atom/hit, angle, hit_zone) /datum/element/embed/proc/check_embed_projectile(obj/projectile/source, atom/movable/firer, atom/hit, angle, hit_zone, blocked)
SIGNAL_HANDLER SIGNAL_HANDLER
if(!source.can_embed_into(hit)) if(!source.can_embed_into(hit) || blocked)
Detach(source) Detach(source)
return // we don't care return // we don't care
var/payload_type = source.shrapnel_type
var/obj/item/payload = new payload_type(get_turf(hit)) var/obj/item/payload = new payload_type(get_turf(hit))
if(istype(payload, /obj/item/shrapnel/bullet)) if(istype(payload, /obj/item/shrapnel/bullet))
payload.name = source.name payload.name = source.name
@@ -155,12 +114,12 @@
if(!limb) if(!limb)
limb = C.get_bodypart() limb = C.get_bodypart()
if(!tryForceEmbed(payload, limb)) if(!try_force_embed(payload, limb))
payload.failedEmbed() payload.failedEmbed()
Detach(source) Detach(source)
/** /**
* tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it. * try_force_embed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it.
* *
* The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel, and possibly * The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel, and possibly
* AGAIN if we actually embed. This way, we save on at least one message. * AGAIN if we actually embed. This way, we save on at least one message.
@@ -171,7 +130,7 @@
* * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting. * * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting.
* * forced- if we want this to succeed 100% * * forced- if we want this to succeed 100%
*/ */
/datum/element/embed/proc/tryForceEmbed(obj/item/embedding_item, atom/target, hit_zone, forced=FALSE) /datum/element/embed/proc/try_force_embed(obj/item/embedding_item, atom/target, hit_zone, forced=FALSE)
SIGNAL_HANDLER SIGNAL_HANDLER
var/obj/item/bodypart/limb var/obj/item/bodypart/limb
@@ -190,16 +149,16 @@
if(!forced && !roll_embed_chance(embedding_item, victim, hit_zone)) if(!forced && !roll_embed_chance(embedding_item, victim, hit_zone))
return return
return checkEmbed(embedding_item, victim, hit_zone, forced=TRUE) // Don't repeat the embed roll, we already did it return check_embed(embedding_item, victim, hit_zone, forced=TRUE) // Don't repeat the embed roll, we already did it
/// Calculates the actual chance to embed based on armour penetration and throwing speed, then returns true if we pass that probability check /// Calculates the actual chance to embed based on armour penetration and throwing speed, then returns true if we pass that probability check
/datum/element/embed/proc/roll_embed_chance(obj/item/embedding_item, mob/living/victim, hit_zone, datum/thrownthing/throwingdatum) /datum/element/embed/proc/roll_embed_chance(obj/item/embedding_item, mob/living/victim, hit_zone, datum/thrownthing/throwingdatum)
var/actual_chance = embed_chance var/actual_chance = embedding_item.get_embed().embed_chance
if(throwingdatum?.speed > embedding_item.throw_speed) if(throwingdatum?.speed > embedding_item.throw_speed)
actual_chance += (throwingdatum.speed - embedding_item.throw_speed) * EMBED_CHANCE_SPEED_BONUS actual_chance += (throwingdatum.speed - embedding_item.throw_speed) * EMBED_CHANCE_SPEED_BONUS
if(embedding_item.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign if(embedding_item.is_embed_harmless()) // all the armor in the world won't save you from a kick me sign
return prob(actual_chance) return prob(actual_chance)
var/armor = max(victim.run_armor_check(hit_zone, BULLET, silent=TRUE), victim.run_armor_check(hit_zone, BOMB, silent=TRUE)) * 0.5 // we'll be nice and take the better of bullet and bomb armor, halved var/armor = max(victim.run_armor_check(hit_zone, BULLET, silent=TRUE), victim.run_armor_check(hit_zone, BOMB, silent=TRUE)) * 0.5 // we'll be nice and take the better of bullet and bomb armor, halved

54
code/datums/embed_data.dm Normal file
View File

@@ -0,0 +1,54 @@
/// Assosciative list of type -> embed data.
GLOBAL_LIST_INIT(embed_by_type, generate_embed_type_cache())
/proc/generate_embed_type_cache()
var/list/embed_cache = list()
for(var/datum/embed_data/embed_type as anything in subtypesof(/datum/embed_data))
var/datum/embed_data/embed = new embed_type
embed_cache[embed_type] = embed
return embed_cache
/proc/get_embed_by_type(embed_type)
var/datum/embed_data/embed = GLOB.embed_by_type[embed_type]
if(embed)
return embed
CRASH("Attempted to get an embed type that did not exist! '[embed_type]'")
/datum/embed_data
/// Chance for an object to embed into somebody when thrown
var/embed_chance = 45
/// Chance for embedded object to fall out (causing pain but removing the object)
var/fall_chance = 5
/// Chance for embedded objects to cause pain (damage user)
var/pain_chance = 15
/// Coefficient of multiplication for the damage the item does while embedded (this*item.w_class)
var/pain_mult = 2
/// Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class)
var/impact_pain_mult = 4
/// Coefficient of multiplication for the damage the item does when it falls out or is removed without a surgery (this*item.w_class)
var/remove_pain_mult = 6
/// Time in ticks, total removal time = (this*item.w_class)
var/rip_time = 30
/// If this should ignore throw speed threshold of 4
var/ignore_throwspeed_threshold = FALSE
/// Chance for embedded objects to cause pain every time they move (jostle)
var/jostle_chance = 5
/// Coefficient of multiplication for the damage the item does while
var/jostle_pain_mult = 1
/// This percentage of all pain will be dealt as stam damage rather than brute (0-1)
var/pain_stam_pct = 0
/datum/embed_data/proc/generate_with_values(embed_chance, fall_chance, pain_chance, pain_mult, impact_pain_mult, remove_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct)
var/datum/embed_data/data = new()
data.embed_chance = !isnull(embed_chance) ? embed_chance : src.embed_chance
data.fall_chance = !isnull(fall_chance) ? fall_chance : src.fall_chance
data.pain_chance = !isnull(pain_chance) ? pain_chance : src.pain_chance
data.pain_mult = !isnull(pain_mult) ? pain_mult : src.pain_mult
data.impact_pain_mult = !isnull(impact_pain_mult) ? impact_pain_mult : src.impact_pain_mult
data.remove_pain_mult = !isnull(remove_pain_mult) ? remove_pain_mult : src.remove_pain_mult
data.rip_time = !isnull(rip_time) ? rip_time : src.rip_time
data.ignore_throwspeed_threshold = !isnull(ignore_throwspeed_threshold) ? ignore_throwspeed_threshold : src.ignore_throwspeed_threshold
data.jostle_chance = !isnull(jostle_chance) ? jostle_chance : src.jostle_chance
data.jostle_pain_mult = !isnull(jostle_pain_mult) ? jostle_pain_mult : src.jostle_pain_mult
data.pain_stam_pct = !isnull(pain_stam_pct) ? pain_stam_pct : src.pain_stam_pct

View File

@@ -48,13 +48,7 @@
force = 2 force = 2
throwforce = 25 throwforce = 25
throw_speed = 4 throw_speed = 4
embedding = list( embed_type = /datum/embed_data/tongue_spike
"impact_pain_mult" = 0,
"embedded_pain_multiplier" = 15,
"embed_chance" = 100,
"embedded_fall_chance" = 0,
"embedded_ignore_throwspeed_threshold" = TRUE,
)
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
sharpness = SHARP_POINTY sharpness = SHARP_POINTY
custom_materials = list(/datum/material/biomass = SMALL_MATERIAL_AMOUNT * 5) custom_materials = list(/datum/material/biomass = SMALL_MATERIAL_AMOUNT * 5)
@@ -63,6 +57,13 @@
/// if we missed our target /// if we missed our target
var/missed = TRUE var/missed = TRUE
/datum/embed_data/tongue_spike
impact_pain_mult = 0
pain_mult = 15
embed_chance = 100
fall_chance = 0
ignore_throwspeed_threshold = TRUE
/obj/item/hardened_spike/Initialize(mapload, mob/living/carbon/source) /obj/item/hardened_spike/Initialize(mapload, mob/living/carbon/source)
. = ..() . = ..()
src.fired_by_ref = WEAKREF(source) src.fired_by_ref = WEAKREF(source)
@@ -110,17 +111,14 @@
desc = "Hardened biomass, shaped into... something." desc = "Hardened biomass, shaped into... something."
icon_state = "tonguespikechem" icon_state = "tonguespikechem"
throwforce = 2 throwforce = 2
embedding = list( embed_type = /datum/embed_data/tongue_spike/chem
"impact_pain_mult" = 0,
"embedded_pain_multiplier" = 0,
"embed_chance" = 100,
"embedded_fall_chance" = 0,
"embedded_pain_chance" = 0,
"embedded_ignore_throwspeed_threshold" = TRUE, //never hurts once it's in you
)
/// Whether the tongue's already embedded in a target once before /// Whether the tongue's already embedded in a target once before
var/embedded_once_alread = FALSE var/embedded_once_alread = FALSE
/datum/embed_data/tongue_spike/chem
pain_mult = 0
pain_chance = 0
/obj/item/hardened_spike/chem/embedded(mob/living/carbon/human/embedded_mob) /obj/item/hardened_spike/chem/embedded(mob/living/carbon/human/embedded_mob)
. = ..() . = ..()
if(embedded_once_alread) if(embedded_once_alread)

View File

@@ -163,8 +163,10 @@
///the icon to indicate this object is being dragged ///the icon to indicate this object is being dragged
mouse_drag_pointer = MOUSE_ACTIVE_POINTER mouse_drag_pointer = MOUSE_ACTIVE_POINTER
///Does it embed and if yes, what kind of embed /// Does it embed and if yes, what kind of embed
var/list/embedding var/embed_type
/// Stores embedding data
var/datum/embed_data/embed_data
///for flags such as [GLASSESCOVERSEYES] ///for flags such as [GLASSESCOVERSEYES]
var/flags_cover = 0 var/flags_cover = 0
@@ -263,8 +265,8 @@
add_weapon_description() add_weapon_description()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_ITEM, src) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_ITEM, src)
if(LAZYLEN(embedding)) if(get_embed())
updateEmbedding() AddElement(/datum/element/embed)
setup_reskinning() setup_reskinning()
@@ -1246,9 +1248,11 @@
return owner.dropItemToGround(src) return owner.dropItemToGround(src)
///Does the current embedding var meet the criteria for being harmless? Namely, does it have a pain multiplier and jostle pain mult of 0? If so, return true. ///Does the current embedding var meet the criteria for being harmless? Namely, does it have a pain multiplier and jostle pain mult of 0? If so, return true.
/obj/item/proc/isEmbedHarmless() /obj/item/proc/is_embed_harmless()
if(embedding) if (!get_embed())
return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0 return FALSE
return !isnull(embed_data.pain_mult) && !isnull(embed_data.jostle_pain_mult) && embed_data.pain_mult == 0 && embed_data.jostle_pain_mult == 0
///In case we want to do something special (like self delete) upon failing to embed in something. ///In case we want to do something special (like self delete) upon failing to embed in something.
/obj/item/proc/failedEmbed() /obj/item/proc/failedEmbed()
@@ -1281,11 +1285,13 @@
/obj/item/proc/tryEmbed(atom/target, forced=FALSE) /obj/item/proc/tryEmbed(atom/target, forced=FALSE)
if(!isbodypart(target) && !iscarbon(target)) if(!isbodypart(target) && !iscarbon(target))
return NONE return NONE
if(!forced && !LAZYLEN(embedding))
if(!forced && !get_embed())
return NONE return NONE
if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target = target, forced = forced)) if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target = target, forced = forced))
return COMPONENT_EMBED_SUCCESS return COMPONENT_EMBED_SUCCESS
failedEmbed() failedEmbed()
///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it. ///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it.
@@ -1293,29 +1299,6 @@
SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED) SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED)
return return
///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/var/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item.
/obj/item/proc/updateEmbedding()
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_EMBEDDING_UPDATE)
if(!LAZYLEN(embedding))
disableEmbedding()
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))
return TRUE
/// How many different types of mats will be counted in a bite? /// How many different types of mats will be counted in a bite?
#define MAX_MATS_PER_BITE 2 #define MAX_MATS_PER_BITE 2
@@ -1733,6 +1716,18 @@
SEND_SIGNAL(loc, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, src, old_w_class, new_w_class) SEND_SIGNAL(loc, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, src, old_w_class, new_w_class)
return TRUE return TRUE
/// Fetches embedding data
/obj/item/proc/get_embed()
RETURN_TYPE(/datum/embed_data)
return embed_type ? (embed_data ||= get_embed_by_type(embed_type)) : null
/obj/item/proc/set_embed(datum/embed_data/embed)
if(embed_data == embed)
return
if(!GLOB.embed_by_type[embed_data?.type])
qdel(embed_data)
embed_data = ispath(embed) ? get_embed_by_type(armor) : embed
SEND_SIGNAL(src, COMSIG_ITEM_EMBEDDING_UPDATE)
/** /**
* Returns the atom(either itself or an internal module) that will interact/attack the target on behalf of us * Returns the atom(either itself or an internal module) that will interact/attack the target on behalf of us

View File

@@ -145,9 +145,8 @@
var/obj/item/thrown_weapon = bomb_target var/obj/item/thrown_weapon = bomb_target
thrown_weapon.throw_speed = max(1, (thrown_weapon.throw_speed - 3)) thrown_weapon.throw_speed = max(1, (thrown_weapon.throw_speed - 3))
thrown_weapon.throw_range = max(1, (thrown_weapon.throw_range - 3)) thrown_weapon.throw_range = max(1, (thrown_weapon.throw_range - 3))
if(thrown_weapon.embedding) if(thrown_weapon.get_embed())
thrown_weapon.embedding["embed_chance"] = 0 thrown_weapon.set_embed(thrown_weapon.get_embed().generate_with_values(embed_chance = 0))
thrown_weapon.updateEmbedding()
else if(isliving(bomb_target)) else if(isliving(bomb_target))
plastic_overlay.layer = FLOAT_LAYER plastic_overlay.layer = FLOAT_LAYER

View File

@@ -124,13 +124,19 @@
icon_state = "buckknife" icon_state = "buckknife"
worn_icon_state = "buckknife" worn_icon_state = "buckknife"
desc = "A military combat utility survival knife." desc = "A military combat utility survival knife."
embedding = list("pain_mult" = 4, "embed_chance" = 65, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE) embed_type = /datum/embed_data/combat_knife
force = 20 force = 20
throwforce = 20 throwforce = 20
attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "cuts") attack_verb_continuous = list("slashes", "stabs", "slices", "tears", "lacerates", "rips", "cuts")
attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "cut") attack_verb_simple = list("slash", "stab", "slice", "tear", "lacerate", "rip", "cut")
slot_flags = ITEM_SLOT_MASK slot_flags = ITEM_SLOT_MASK
/datum/embed_data/combat_knife
pain_mult = 4
embed_chance = 65
fall_chance = 10
ignore_throwspeed_threshold = TRUE
/obj/item/knife/combat/Initialize(mapload) /obj/item/knife/combat/Initialize(mapload)
. = ..() . = ..()
AddComponent(/datum/component/knockoff, 90, list(BODY_ZONE_PRECISE_MOUTH), slot_flags) //90% to knock off when wearing a mask AddComponent(/datum/component/knockoff, 90, list(BODY_ZONE_PRECISE_MOUTH), slot_flags) //90% to knock off when wearing a mask
@@ -155,7 +161,7 @@
icon = 'icons/obj/weapons/stabby.dmi' icon = 'icons/obj/weapons/stabby.dmi'
icon_state = "survivalknife" icon_state = "survivalknife"
worn_icon_state = "survivalknife" worn_icon_state = "survivalknife"
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10) embed_type = /datum/embed_data/combat_knife/weak
desc = "A hunting grade survival knife." desc = "A hunting grade survival knife."
force = 15 force = 15
throwforce = 15 throwforce = 15
@@ -169,13 +175,16 @@
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
desc = "A sharpened bone. The bare minimum in survival." desc = "A sharpened bone. The bare minimum in survival."
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10) embed_type = /datum/embed_data/combat_knife/weak
obj_flags = parent_type::obj_flags & ~CONDUCTS_ELECTRICITY obj_flags = parent_type::obj_flags & ~CONDUCTS_ELECTRICITY
slot_flags = NONE slot_flags = NONE
force = 15 force = 15
throwforce = 15 throwforce = 15
custom_materials = null custom_materials = null
/datum/embed_data/combat_knife/weak
embed_chance = 35
/obj/item/knife/combat/cyborg /obj/item/knife/combat/cyborg
name = "cyborg knife" name = "cyborg knife"
icon = 'icons/obj/items_cyborg.dmi' icon = 'icons/obj/items_cyborg.dmi'

View File

@@ -113,13 +113,9 @@
SIGNAL_HANDLER SIGNAL_HANDLER
if(active) if(active)
if(embedding)
updateEmbedding()
heat = active_heat heat = active_heat
START_PROCESSING(SSobj, src) START_PROCESSING(SSobj, src)
else else
if(embedding)
disableEmbedding()
heat = initial(heat) heat = initial(heat)
STOP_PROCESSING(SSobj, src) STOP_PROCESSING(SSobj, src)
@@ -173,6 +169,10 @@
return (BRUTELOSS|FIRELOSS) return (BRUTELOSS|FIRELOSS)
/// Energy swords. /// Energy swords.
/datum/embed_data/esword
embed_chance = 75
impact_pain_mult = 10
/obj/item/melee/energy/sword /obj/item/melee/energy/sword
name = "energy sword" name = "energy sword"
desc = "May the force be within you." desc = "May the force be within you."
@@ -189,7 +189,7 @@
armour_penetration = 35 armour_penetration = 35
block_chance = 50 block_chance = 50
block_sound = 'sound/weapons/block_blade.ogg' block_sound = 'sound/weapons/block_blade.ogg'
embedding = list("embed_chance" = 75, "impact_pain_mult" = 10) embed_type = /datum/embed_data/esword
/obj/item/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) /obj/item/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))

View File

@@ -186,7 +186,7 @@
icon_state = "gumball" icon_state = "gumball"
damage = 0 damage = 0
speed = 0.5 speed = 0.5
embedding = null embed_type = null
/obj/projectile/bullet/gumball/Initialize(mapload) /obj/projectile/bullet/gumball/Initialize(mapload)
. = ..() . = ..()
@@ -219,29 +219,30 @@
icon_state = "lollipop_1" icon_state = "lollipop_1"
damage = 0 damage = 0
speed = 0.5 speed = 0.5
embedding = null embed_type = null
var/head_color var/head_color
/obj/projectile/bullet/lollipop/harmful /obj/projectile/bullet/lollipop/harmful
embedding = list( embed_type = /datum/embed_data/lollipop
embed_chance = 35,
fall_chance = 2,
jostle_chance = 0,
ignore_throwspeed_threshold = TRUE,
pain_stam_pct = 0.5,
pain_mult = 3,
rip_time = 10,
)
damage = 10 damage = 10
shrapnel_type = /obj/item/food/lollipop/cyborg shrapnel_type = /obj/item/food/lollipop/cyborg
embed_falloff_tile = 0 embed_falloff_tile = 0
/datum/embed_data/lollipop
embed_chance = 35
fall_chance = 2
jostle_chance = 0
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.5
pain_mult = 3
rip_time = 10
/obj/projectile/bullet/lollipop/Initialize(mapload) /obj/projectile/bullet/lollipop/Initialize(mapload)
. = ..() . = ..()
var/mutable_appearance/head = mutable_appearance('icons/obj/weapons/guns/projectiles.dmi', "lollipop_2") var/mutable_appearance/head = mutable_appearance('icons/obj/weapons/guns/projectiles.dmi', "lollipop_2")
head.color = head_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) head.color = head_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
add_overlay(head) add_overlay(head)
if(!embedding) if(!embed_type)
AddElement(/datum/element/projectile_drop, /obj/item/food/lollipop/cyborg) AddElement(/datum/element/projectile_drop, /obj/item/food/lollipop/cyborg)
RegisterSignals(src, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(handle_drop)) RegisterSignals(src, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(handle_drop))

View File

@@ -17,8 +17,7 @@
name = "bullet" name = "bullet"
icon = 'icons/obj/weapons/guns/ammo.dmi' icon = 'icons/obj/weapons/guns/ammo.dmi'
icon_state = "s-casing" icon_state = "s-casing"
embedding = null // embedding vars are taken from the projectile itself embed_type = null
/obj/projectile/bullet/shrapnel /obj/projectile/bullet/shrapnel
name = "flying shrapnel shard" name = "flying shrapnel shard"
@@ -34,7 +33,12 @@
ignore_range_hit_prone_targets = TRUE ignore_range_hit_prone_targets = TRUE
sharpness = SHARP_EDGED sharpness = SHARP_EDGED
wound_bonus = 30 wound_bonus = 30
embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=1) embed_type = /datum/embed_data/shrapnel
/datum/embed_data/shrapnel
embed_chance = 70
ignore_throwspeed_threshold = TRUE
fall_chance = 1
/obj/projectile/bullet/shrapnel/short_range /obj/projectile/bullet/shrapnel/short_range
range = 5 range = 5
@@ -70,7 +74,17 @@
ricochet_incidence_leeway = 0 ricochet_incidence_leeway = 0
embed_falloff_tile = -2 embed_falloff_tile = -2
shrapnel_type = /obj/item/shrapnel/stingball shrapnel_type = /obj/item/shrapnel/stingball
embedding = list(embed_chance=55, fall_chance=2, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.7, pain_mult=3, jostle_pain_mult=3, rip_time=15) embed_type = /datum/embed_data/stingball
/datum/embed_data/stingball
embed_chance = 55
fall_chance = 2
jostle_chance = 7
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.7
pain_mult = 3
jostle_pain_mult = 3
rip_time = 15
/obj/projectile/bullet/pellet/stingball/on_ricochet(atom/A) /obj/projectile/bullet/pellet/stingball/on_ricochet(atom/A)
hit_prone_targets = TRUE // ducking will save you from the first wave, but not the rebounds hit_prone_targets = TRUE // ducking will save you from the first wave, but not the rebounds
@@ -92,10 +106,20 @@
ricochets_max = 2 ricochets_max = 2
ricochet_chance = 140 ricochet_chance = 140
shrapnel_type = /obj/item/shrapnel/capmine shrapnel_type = /obj/item/shrapnel/capmine
embedding = list(embed_chance=90, fall_chance=3, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.7, pain_mult=5, jostle_pain_mult=6, rip_time=15) embed_type = /datum/embed_data/capmine
wound_falloff_tile = 0 wound_falloff_tile = 0
embed_falloff_tile = 0 embed_falloff_tile = 0
/datum/embed_data/capmine
embed_chance = 90
fall_chance = 3
jostle_chance = 7
ignore_throwspeed_threshold = TRUE
pain_stam_pct = 0.7
pain_mult = 5
jostle_pain_mult = 6
rip_time = 15
/obj/item/shrapnel/capmine /obj/item/shrapnel/capmine
name = "\improper AP shrapnel shard" name = "\improper AP shrapnel shard"
custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5) custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5)

View File

@@ -12,7 +12,7 @@
throwforce = 20 throwforce = 20
throw_speed = 4 throw_speed = 4
demolition_mod = 0.75 demolition_mod = 0.75
embedding = list("impact_pain_mult" = 2, "remove_pain_mult" = 4, "jostle_chance" = 2.5) embed_type = /datum/embed_data/spear
armour_penetration = 10 armour_penetration = 10
custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass= HALF_SHEET_MATERIAL_AMOUNT * 2) custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT, /datum/material/glass= HALF_SHEET_MATERIAL_AMOUNT * 2)
hitsound = 'sound/weapons/bladeslice.ogg' hitsound = 'sound/weapons/bladeslice.ogg'
@@ -32,6 +32,11 @@
/// How much damage to do wielded /// How much damage to do wielded
var/force_wielded = 18 var/force_wielded = 18
/datum/embed_data/spear
impact_pain_mult = 2
remove_pain_mult = 4
jostle_chance = 2.5
/datum/armor/item_spear /datum/armor/item_spear
fire = 50 fire = 50
acid = 30 acid = 30

View File

@@ -33,13 +33,16 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
attack_verb_continuous = list("hits", "bludgeons", "whacks") attack_verb_continuous = list("hits", "bludgeons", "whacks")
attack_verb_simple = list("hit", "bludgeon", "whack") attack_verb_simple = list("hit", "bludgeon", "whack")
hitsound = 'sound/weapons/gun/general/grenade_launch.ogg' hitsound = 'sound/weapons/gun/general/grenade_launch.ogg'
embedding = list(embed_chance = 50) embed_type = /datum/embed_data/rods
novariants = TRUE novariants = TRUE
matter_amount = 2 matter_amount = 2
cost = HALF_SHEET_MATERIAL_AMOUNT cost = HALF_SHEET_MATERIAL_AMOUNT
source = /datum/robot_energy_storage/material/iron source = /datum/robot_energy_storage/material/iron
merge_type = /obj/item/stack/rods merge_type = /obj/item/stack/rods
/datum/embed_data/rods
embed_chance = 50
/obj/item/stack/rods/suicide_act(mob/living/carbon/user) /obj/item/stack/rods/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins to stuff \the [src] down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide!"))//it looks like theyre ur mum user.visible_message(span_suicide("[user] begins to stuff \the [src] down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide!"))//it looks like theyre ur mum
return BRUTELOSS return BRUTELOSS

View File

@@ -293,7 +293,16 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
var/shiv_type = /obj/item/knife/shiv var/shiv_type = /obj/item/knife/shiv
var/craft_time = 3.5 SECONDS var/craft_time = 3.5 SECONDS
var/obj/item/stack/sheet/weld_material = /obj/item/stack/sheet/glass var/obj/item/stack/sheet/weld_material = /obj/item/stack/sheet/glass
embedding = list("embed_chance" = 65) embed_type = /datum/embed_data/shard
/datum/embed_data/shard
embed_chance = 65
/datum/embed_data/glass_candy
embed_chance = 100
ignore_throwspeed_threshold = TRUE
impact_pain_mult = 1
pain_chance = 5
/datum/armor/item_shard /datum/armor/item_shard
melee = 100 melee = 100

View File

@@ -14,12 +14,17 @@
grind_results = list(/datum/reagent/cellulose = 5) grind_results = list(/datum/reagent/cellulose = 5)
splint_factor = 0.65 splint_factor = 0.65
merge_type = /obj/item/stack/sticky_tape merge_type = /obj/item/stack/sticky_tape
var/list/conferred_embed = EMBED_HARMLESS var/conferred_embed = /datum/embed_data/sticky_tape
///The tape type you get when ripping off a piece of tape. ///The tape type you get when ripping off a piece of tape.
var/obj/tape_gag = /obj/item/clothing/mask/muzzle/tape var/obj/tape_gag = /obj/item/clothing/mask/muzzle/tape
greyscale_config = /datum/greyscale_config/tape greyscale_config = /datum/greyscale_config/tape
greyscale_colors = "#B2B2B2#BD6A62" greyscale_colors = "#B2B2B2#BD6A62"
/datum/embed_data/sticky_tape
pain_mult = 0
jostle_pain_mult = 0
ignore_throwspeed_threshold = 0
/obj/item/stack/sticky_tape/attack_hand(mob/user, list/modifiers) /obj/item/stack/sticky_tape/attack_hand(mob/user, list/modifiers)
if(user.get_inactive_held_item() == src) if(user.get_inactive_held_item() == src)
if(is_zero_amount(delete_if_zero = TRUE)) if(is_zero_amount(delete_if_zero = TRUE))
@@ -43,7 +48,7 @@
if(!isitem(target)) if(!isitem(target))
return NONE return NONE
if(target.embedding && target.embedding == conferred_embed) if(target.get_embed()?.type == conferred_embed)
to_chat(user, span_warning("[target] is already coated in [src]!")) to_chat(user, span_warning("[target] is already coated in [src]!"))
return ITEM_INTERACT_BLOCKING return ITEM_INTERACT_BLOCKING
@@ -60,12 +65,11 @@
user.put_in_hands(O) user.put_in_hands(O)
return ITEM_INTERACT_SUCCESS return ITEM_INTERACT_SUCCESS
if(target.embedding && target.embedding == conferred_embed) if(target.get_embed() && target.get_embed().type == conferred_embed)
to_chat(user, span_warning("[target] is already coated in [src]!")) to_chat(user, span_warning("[target] is already coated in [src]!"))
return ITEM_INTERACT_BLOCKING return ITEM_INTERACT_BLOCKING
target.embedding = conferred_embed target.set_embed(conferred_embed)
target.updateEmbedding()
to_chat(user, span_notice("You finish wrapping [target] with [src].")) to_chat(user, span_notice("You finish wrapping [target] with [src]."))
target.name = "[prefix] [target.name]" target.name = "[prefix] [target.name]"
@@ -80,34 +84,44 @@
singular_name = "super sticky tape" singular_name = "super sticky tape"
desc = "Quite possibly the most mischevious substance in the galaxy. Use with extreme lack of caution." desc = "Quite possibly the most mischevious substance in the galaxy. Use with extreme lack of caution."
prefix = "super sticky" prefix = "super sticky"
conferred_embed = EMBED_HARMLESS_SUPERIOR conferred_embed = /datum/embed_data/sticky_tape/super
splint_factor = 0.4 splint_factor = 0.4
merge_type = /obj/item/stack/sticky_tape/super merge_type = /obj/item/stack/sticky_tape/super
greyscale_colors = "#4D4D4D#75433F" greyscale_colors = "#4D4D4D#75433F"
tape_gag = /obj/item/clothing/mask/muzzle/tape/super tape_gag = /obj/item/clothing/mask/muzzle/tape/super
/datum/embed_data/sticky_tape/super
embed_chance = 100
fall_chance = 0.1
/obj/item/stack/sticky_tape/pointy /obj/item/stack/sticky_tape/pointy
name = "pointy tape" name = "pointy tape"
singular_name = "pointy tape" singular_name = "pointy tape"
desc = "Used for sticking to things for sticking said things inside people." desc = "Used for sticking to things for sticking said things inside people."
icon_state = "tape_spikes" icon_state = "tape_spikes"
prefix = "pointy" prefix = "pointy"
conferred_embed = EMBED_POINTY conferred_embed = /datum/embed_data/pointy_tape
merge_type = /obj/item/stack/sticky_tape/pointy merge_type = /obj/item/stack/sticky_tape/pointy
greyscale_config = /datum/greyscale_config/tape/spikes greyscale_config = /datum/greyscale_config/tape/spikes
greyscale_colors = "#E64539#808080#AD2F45" greyscale_colors = "#E64539#808080#AD2F45"
tape_gag = /obj/item/clothing/mask/muzzle/tape/pointy tape_gag = /obj/item/clothing/mask/muzzle/tape/pointy
/datum/embed_data/pointy_tape
ignore_throwspeed_threshold = TRUE
/obj/item/stack/sticky_tape/pointy/super /obj/item/stack/sticky_tape/pointy/super
name = "super pointy tape" name = "super pointy tape"
singular_name = "super pointy tape" singular_name = "super pointy tape"
desc = "You didn't know tape could look so sinister. Welcome to Space Station 13." desc = "You didn't know tape could look so sinister. Welcome to Space Station 13."
prefix = "super pointy" prefix = "super pointy"
conferred_embed = EMBED_POINTY_SUPERIOR conferred_embed = /datum/embed_data/pointy_tape/super
merge_type = /obj/item/stack/sticky_tape/pointy/super merge_type = /obj/item/stack/sticky_tape/pointy/super
greyscale_colors = "#8C0A00#4F4F4F#300008" greyscale_colors = "#8C0A00#4F4F4F#300008"
tape_gag = /obj/item/clothing/mask/muzzle/tape/pointy/super tape_gag = /obj/item/clothing/mask/muzzle/tape/pointy/super
/datum/embed_data/pointy_tape/super
embed_chance = 100
/obj/item/stack/sticky_tape/surgical /obj/item/stack/sticky_tape/surgical
name = "surgical tape" name = "surgical tape"
singular_name = "surgical tape" singular_name = "surgical tape"

View File

@@ -7,7 +7,6 @@
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
throwforce = 0 throwforce = 0
throw_speed = 1 throw_speed = 1
embedding = EMBED_HARMLESS
custom_materials = list(/datum/material/iron= HALF_SHEET_MATERIAL_AMOUNT) custom_materials = list(/datum/material/iron= HALF_SHEET_MATERIAL_AMOUNT)
hitsound = 'sound/weapons/bladeslice.ogg' hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb_continuous = list("pokes", "jabs", "pins the tail on") attack_verb_continuous = list("pokes", "jabs", "pins the tail on")
@@ -15,6 +14,12 @@
sharpness = SHARP_POINTY sharpness = SHARP_POINTY
max_integrity = 200 max_integrity = 200
layer = CORGI_ASS_PIN_LAYER layer = CORGI_ASS_PIN_LAYER
embed_type = /datum/embed_data/corgi_pin
/datum/embed_data/corgi_pin
pain_chance = 0
jostle_pain_mult = 0
ignore_throwspeed_threshold = TRUE
/obj/item/poster/tail_board /obj/item/poster/tail_board
name = "party game poster" name = "party game poster"

View File

@@ -387,7 +387,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
force = 2 force = 2
throwforce = 10 //10 + 2 (WEIGHT_CLASS_SMALL) * 4 (EMBEDDED_IMPACT_PAIN_MULTIPLIER) = 18 damage on hit due to guaranteed embedding throwforce = 10 //10 + 2 (WEIGHT_CLASS_SMALL) * 4 (EMBEDDED_IMPACT_PAIN_MULTIPLIER) = 18 damage on hit due to guaranteed embedding
throw_speed = 4 throw_speed = 4
embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0) embed_type = /datum/embed_data/throwing_star
armour_penetration = 40 armour_penetration = 40
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
@@ -395,11 +395,22 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 5, /datum/material/glass= SMALL_MATERIAL_AMOUNT * 5) custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 5, /datum/material/glass= SMALL_MATERIAL_AMOUNT * 5)
resistance_flags = FIRE_PROOF resistance_flags = FIRE_PROOF
/datum/embed_data/throwing_star
pain_mult = 4
embed_chance = 100
fall_chance = 0
/obj/item/throwing_star/stamina /obj/item/throwing_star/stamina
name = "shock throwing star" name = "shock throwing star"
desc = "An aerodynamic disc designed to cause excruciating pain when stuck inside fleeing targets, hopefully without causing fatal harm." desc = "An aerodynamic disc designed to cause excruciating pain when stuck inside fleeing targets, hopefully without causing fatal harm."
throwforce = 5 throwforce = 5
embedding = list("pain_chance" = 5, "embed_chance" = 100, "fall_chance" = 0, "jostle_chance" = 10, "pain_stam_pct" = 0.8, "jostle_pain_mult" = 3) embed_type = /datum/embed_data/throwing_star/stamina
/datum/embed_data/throwing_star/stamina
pain_mult = 5
jostle_chance = 10
pain_stam_pct = 0.8
jostle_pain_mult = 3
/obj/item/throwing_star/toy /obj/item/throwing_star/toy
name = "toy throwing star" name = "toy throwing star"
@@ -407,7 +418,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
sharpness = NONE sharpness = NONE
force = 0 force = 0
throwforce = 0 throwforce = 0
embedding = list("pain_mult" = 0, "jostle_pain_mult" = 0, "embed_chance" = 100, "fall_chance" = 0) embed_type = /datum/embed_data/throwing_star/toy
/datum/embed_data/throwing_star/toy
pain_mult = 0
jostle_pain_mult = 0
/obj/item/switchblade /obj/item/switchblade
name = "switchblade" name = "switchblade"
@@ -1082,7 +1097,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
throwforce = 25 throwforce = 25
throw_speed = 4 throw_speed = 4
attack_speed = CLICK_CD_HYPER_RAPID attack_speed = CLICK_CD_HYPER_RAPID
embedding = list("embed_chance" = 100) embed_type = /datum/embed_data/hfr_blade
block_chance = 25 block_chance = 25
block_sound = 'sound/weapons/parry.ogg' block_sound = 'sound/weapons/parry.ogg'
sharpness = SHARP_EDGED sharpness = SHARP_EDGED
@@ -1097,6 +1112,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/// The previous target we attacked /// The previous target we attacked
var/datum/weakref/previous_target var/datum/weakref/previous_target
/datum/embed_data/hfr_blade
embed_chance = 100
/obj/item/highfrequencyblade/Initialize(mapload) /obj/item/highfrequencyblade/Initialize(mapload)
. = ..() . = ..()
AddComponent(/datum/component/two_handed, \ AddComponent(/datum/component/two_handed, \

View File

@@ -89,7 +89,7 @@
force = 0 force = 0
throwforce = 0 throwforce = 0
hitsound = null hitsound = null
embedding = null embed_type = null
light_color = COLOR_YELLOW light_color = COLOR_YELLOW
sword_color_icon = "bananium" sword_color_icon = "bananium"
active_heat = 0 active_heat = 0

View File

@@ -15,15 +15,7 @@
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends") attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends")
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend") attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend")
actions_types = list(/datum/action/item_action/rune_shatter) actions_types = list(/datum/action/item_action/rune_shatter)
embedding = list( embed_type = /datum/embed_data/rune_carver
ignore_throwspeed_threshold = TRUE,
embed_chance = 75,
jostle_chance = 2,
jostle_pain_mult = 5,
pain_stam_pct = 0.4,
pain_mult = 3,
rip_time = 15,
)
/// Whether we're currently drawing a rune /// Whether we're currently drawing a rune
var/drawing = FALSE var/drawing = FALSE
@@ -34,6 +26,15 @@
/// Turfs that you cannot draw carvings on /// Turfs that you cannot draw carvings on
var/static/list/blacklisted_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava)) var/static/list/blacklisted_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava))
/datum/embed_data/rune_carver
ignore_throwspeed_threshold = TRUE
embed_chance = 75
jostle_chance = 2
jostle_pain_mult = 5
pain_stam_pct = 0.4
pain_mult = 3
rip_time = 15
/obj/item/melee/rune_carver/examine(mob/user) /obj/item/melee/rune_carver/examine(mob/user)
. = ..() . = ..()
if(!IS_HERETIC_OR_MONSTER(user) && !isobserver(user)) if(!IS_HERETIC_OR_MONSTER(user) && !isobserver(user))

View File

@@ -43,9 +43,12 @@ GLOBAL_DATUM(global_funny_embedding, /datum/global_funny_embedding)
* Makes every item in the world embed when thrown, but also hooks into global signals for new items created to also bless them with embed-ability(??). * Makes every item in the world embed when thrown, but also hooks into global signals for new items created to also bless them with embed-ability(??).
*/ */
/datum/global_funny_embedding /datum/global_funny_embedding
var/embed_type = EMBED_POINTY var/embed_type = /datum/embed_data/global_funny
var/prefix = "error" var/prefix = "error"
/datum/embed_data/global_funny
ignore_throwspeed_threshold = TRUE
/datum/global_funny_embedding/New() /datum/global_funny_embedding/New()
. = ..() . = ..()
//second operation takes MUCH longer, so lets set up signals first. //second operation takes MUCH longer, so lets set up signals first.
@@ -61,11 +64,11 @@ GLOBAL_DATUM(global_funny_embedding, /datum/global_funny_embedding)
SIGNAL_HANDLER SIGNAL_HANDLER
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:) // this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
if(LAZYLEN(created_item.embedding)) if(created_item.get_embed())
return //already embeds to some degree, so whatever 🐀 return //already embeds to some degree, so whatever // No rat allowed
created_item.embedding = embed_type
created_item.name = "[prefix] [created_item.name]" created_item.name = "[prefix] [created_item.name]"
created_item.updateEmbedding() created_item.set_embed(embed_type)
/** /**
* ### handle_current_items * ### handle_current_items
@@ -77,17 +80,20 @@ GLOBAL_DATUM(global_funny_embedding, /datum/global_funny_embedding)
CHECK_TICK CHECK_TICK
if(!(embed_item.flags_1 & INITIALIZED_1)) if(!(embed_item.flags_1 & INITIALIZED_1))
continue continue
if(!embed_item.embedding) if(embed_item.get_embed())
embed_item.embedding = embed_type continue
embed_item.updateEmbedding() embed_item.set_embed(embed_type)
embed_item.name = "[prefix] [embed_item.name]" embed_item.name = "[prefix] [embed_item.name]"
///everything will be... POINTY!!!! ///everything will be... POINTY!!!!
/datum/global_funny_embedding/pointy /datum/global_funny_embedding/pointy
embed_type = EMBED_POINTY
prefix = "pointy" prefix = "pointy"
///everything will be... sticky? sure, why not ///everything will be... sticky? sure, why not
/datum/global_funny_embedding/sticky /datum/global_funny_embedding/sticky
embed_type = EMBED_HARMLESS embed_type = /datum/embed_data/global_funny/sticky
prefix = "sticky" prefix = "sticky"
/datum/embed_data/global_funny/sticky
pain_mult = 0
jostle_pain_mult = 0

View File

@@ -14,7 +14,7 @@
throw_speed = 2 throw_speed = 2
block_chance = 0 block_chance = 0
throwforce = 0 throwforce = 0
embedding = null embed_type = null
sword_color_icon = null sword_color_icon = null
active_throwforce = 0 active_throwforce = 0

View File

@@ -478,13 +478,18 @@
throwforce = 15 throwforce = 15
throw_speed = 4 throw_speed = 4
throw_range = 7 throw_range = 7
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10) embed_type = /datum/embed_data/hatchet
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*7.5) custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*7.5)
attack_verb_continuous = list("chops", "tears", "lacerates", "cuts") attack_verb_continuous = list("chops", "tears", "lacerates", "cuts")
attack_verb_simple = list("chop", "tear", "lacerate", "cut") attack_verb_simple = list("chop", "tear", "lacerate", "cut")
hitsound = 'sound/weapons/bladeslice.ogg' hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = SHARP_EDGED sharpness = SHARP_EDGED
/datum/embed_data/hatchet
pain_mult = 4
embed_chance = 35
fall_chance = 10
/obj/item/hatchet/Initialize(mapload) /obj/item/hatchet/Initialize(mapload)
. = ..() . = ..()
AddComponent(/datum/component/butchering, \ AddComponent(/datum/component/butchering, \

View File

@@ -859,12 +859,15 @@
return return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed() var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/stinging))
our_plant.embedding = EMBED_POINTY
else
our_plant.embedding = EMBED_HARMLESS
our_plant.updateEmbedding()
our_plant.throwforce = (our_seed.potency/20) our_plant.throwforce = (our_seed.potency/20)
if (!our_plant.get_embed())
return
if(our_seed.get_gene(/datum/plant_gene/trait/stinging))
our_plant.set_embed(our_plant.get_embed().generate_with_values(ignore_throwspeed_threshold = TRUE))
return
our_plant.set_embed(our_plant.get_embed().generate_with_values(ignore_throwspeed_threshold = TRUE, pain_mult = 0, jostle_pain_mult = 0))
/** /**
* This trait automatically heats up the plant's chemical contents when harvested. * This trait automatically heats up the plant's chemical contents when harvested.

View File

@@ -415,7 +415,7 @@
// this way, we only visibly try to examine ourselves if we have something embedded, otherwise we'll still hug ourselves :) // this way, we only visibly try to examine ourselves if we have something embedded, otherwise we'll still hug ourselves :)
visible_message(span_notice("[src] examines [p_them()]self."), \ visible_message(span_notice("[src] examines [p_them()]self."), \
span_notice("You check yourself for shrapnel.")) span_notice("You check yourself for shrapnel."))
if(I.isEmbedHarmless()) if(I.is_embed_harmless())
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>") to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
else else
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>") to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")

View File

@@ -36,7 +36,7 @@
var/list/msg = list("<span class='warning'>") var/list/msg = list("<span class='warning'>")
for(var/obj/item/bodypart/bodypart as anything in bodyparts) for(var/obj/item/bodypart/bodypart as anything in bodyparts)
for(var/obj/item/embedded_item as anything in bodypart.embedded_objects) for(var/obj/item/embedded_item as anything in bodypart.embedded_objects)
if(embedded_item.isEmbedHarmless()) if(embedded_item.is_embed_harmless())
msg += "<B>[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] stuck to [t_his] [bodypart.name]!</B>\n" msg += "<B>[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] stuck to [t_his] [bodypart.name]!</B>\n"
else else
msg += "<B>[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] embedded in [t_his] [bodypart.name]!</B>\n" msg += "<B>[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] embedded in [t_his] [bodypart.name]!</B>\n"

View File

@@ -138,7 +138,7 @@
disabled += body_part disabled += body_part
missing -= body_part.body_zone missing -= body_part.body_zone
for(var/obj/item/I in body_part.embedded_objects) for(var/obj/item/I in body_part.embedded_objects)
if(I.isEmbedHarmless()) if(I.is_embed_harmless())
msg += "<B>[t_He] [t_has] [icon2html(I, user)] \a [I] stuck to [t_his] [body_part.name]!</B>\n" msg += "<B>[t_He] [t_has] [icon2html(I, user)] \a [I] stuck to [t_his] [body_part.name]!</B>\n"
else else
msg += "<B>[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [body_part.name]!</B>\n" msg += "<B>[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [body_part.name]!</B>\n"

View File

@@ -375,7 +375,7 @@
name = "mending globule" name = "mending globule"
icon_state = "glob_projectile" icon_state = "glob_projectile"
shrapnel_type = /obj/item/mending_globule shrapnel_type = /obj/item/mending_globule
embedding = list("embed_chance" = 100, ignore_throwspeed_threshold = TRUE, "pain_mult" = 0, "jostle_pain_mult" = 0, "fall_chance" = 0.5) embed_type = /datum/embed_data/mending_globule
damage = 0 damage = 0
///This item is what is embedded into the mob, and actually handles healing of mending globules ///This item is what is embedded into the mob, and actually handles healing of mending globules
@@ -384,10 +384,17 @@
desc = "It somehow heals those who touch it." desc = "It somehow heals those who touch it."
icon = 'icons/obj/science/vatgrowing.dmi' icon = 'icons/obj/science/vatgrowing.dmi'
icon_state = "globule" icon_state = "globule"
embedding = list("embed_chance" = 100, ignore_throwspeed_threshold = TRUE, "pain_mult" = 0, "jostle_pain_mult" = 0, "fall_chance" = 0.5) embed_type = /datum/embed_data/mending_globule
var/obj/item/bodypart/bodypart var/obj/item/bodypart/bodypart
var/heals_left = 35 var/heals_left = 35
/datum/embed_data/mending_globule
embed_chance = 100
ignore_throwspeed_threshold = TRUE
pain_mult = 0
jostle_pain_mult = 0
fall_chance = 0.5
/obj/item/mending_globule/Destroy() /obj/item/mending_globule/Destroy()
. = ..() . = ..()
bodypart = null bodypart = null

View File

@@ -559,7 +559,7 @@
light_range = 1 light_range = 1
light_power = 1 light_power = 1
light_color = COLOR_LIGHT_ORANGE light_color = COLOR_LIGHT_ORANGE
embedding = null embed_type = null
/obj/projectile/bullet/mining_bomb/Initialize(mapload) /obj/projectile/bullet/mining_bomb/Initialize(mapload)
. = ..() . = ..()

View File

@@ -29,7 +29,7 @@
var/degrees = 0 var/degrees = 0
var/font = PEN_FONT var/font = PEN_FONT
var/requires_gravity = TRUE // can you use this to write in zero-g var/requires_gravity = TRUE // can you use this to write in zero-g
embedding = list(embed_chance = 50) embed_type = /datum/embed_data/pen
sharpness = SHARP_POINTY sharpness = SHARP_POINTY
var/dart_insert_icon = 'icons/obj/weapons/guns/toy.dmi' var/dart_insert_icon = 'icons/obj/weapons/guns/toy.dmi'
var/dart_insert_casing_icon_state = "overlay_pen" var/dart_insert_casing_icon_state = "overlay_pen"
@@ -37,6 +37,9 @@
/// If this pen can be clicked in order to retract it /// If this pen can be clicked in order to retract it
var/can_click = TRUE var/can_click = TRUE
/datum/embed_data/pen
embed_chance = 50
/obj/item/pen/Initialize(mapload) /obj/item/pen/Initialize(mapload)
. = ..() . = ..()
AddComponent(/datum/component/dart_insert, \ AddComponent(/datum/component/dart_insert, \
@@ -86,7 +89,7 @@
return list( return list(
"damage" = max(5, throwforce), "damage" = max(5, throwforce),
"speed" = max(0, throw_speed - 3), "speed" = max(0, throw_speed - 3),
"embedding" = embedding, "embedding" = get_embed(),
"armour_penetration" = armour_penetration, "armour_penetration" = armour_penetration,
"wound_bonus" = wound_bonus, "wound_bonus" = wound_bonus,
"bare_wound_bonus" = bare_wound_bonus, "bare_wound_bonus" = bare_wound_bonus,
@@ -191,7 +194,7 @@
"Black and Silver" = "pen-fountain-b", "Black and Silver" = "pen-fountain-b",
"Command Blue" = "pen-fountain-cb" "Command Blue" = "pen-fountain-cb"
) )
embedding = list("embed_chance" = 75) embed_type = /datum/embed_data/pen/captain
dart_insert_casing_icon_state = "overlay_fountainpen_gold" dart_insert_casing_icon_state = "overlay_fountainpen_gold"
dart_insert_projectile_icon_state = "overlay_fountainpen_gold_proj" dart_insert_projectile_icon_state = "overlay_fountainpen_gold_proj"
var/list/overlay_reskin = list( var/list/overlay_reskin = list(
@@ -202,6 +205,9 @@
"Command Blue" = "overlay_fountainpen_gold" "Command Blue" = "overlay_fountainpen_gold"
) )
/datum/embed_data/pen/captain
embed_chance = 50
/obj/item/pen/fountain/captain/Initialize(mapload) /obj/item/pen/fountain/captain/Initialize(mapload)
. = ..() . = ..()
AddComponent(/datum/component/butchering, \ AddComponent(/datum/component/butchering, \
@@ -414,7 +420,7 @@
inhand_icon_state = hidden_icon inhand_icon_state = hidden_icon
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
embedding = list(embed_chance = 100) // Rule of cool set_embed(/datum/embed_data/edagger_active)
else else
name = initial(name) name = initial(name)
desc = initial(desc) desc = initial(desc)
@@ -422,15 +428,17 @@
inhand_icon_state = initial(inhand_icon_state) inhand_icon_state = initial(inhand_icon_state)
lefthand_file = initial(lefthand_file) lefthand_file = initial(lefthand_file)
righthand_file = initial(righthand_file) righthand_file = initial(righthand_file)
embedding = list(embed_chance = EMBED_CHANCE) set_embed(embed_type)
updateEmbedding()
if(user) if(user)
balloon_alert(user, "[hidden_name] [active ? "active" : "concealed"]") balloon_alert(user, "[hidden_name] [active ? "active" : "concealed"]")
playsound(src, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 5, TRUE) playsound(src, active ? 'sound/weapons/saberon.ogg' : 'sound/weapons/saberoff.ogg', 5, TRUE)
set_light_on(active) set_light_on(active)
return COMPONENT_NO_DEFAULT_MESSAGE return COMPONENT_NO_DEFAULT_MESSAGE
/datum/embed_data/edagger_active
embed_chance = 100
/obj/item/pen/edagger/proc/on_scan(datum/source, mob/user, list/extra_data) /obj/item/pen/edagger/proc/on_scan(datum/source, mob/user, list/extra_data)
SIGNAL_HANDLER SIGNAL_HANDLER
LAZYADD(extra_data[DETSCAN_CATEGORY_ILLEGAL], "Hard-light generator detected.") LAZYADD(extra_data[DETSCAN_CATEGORY_ILLEGAL], "Hard-light generator detected.")

View File

@@ -33,16 +33,17 @@
speed = 1 speed = 1
range = 25 range = 25
shrapnel_type = null shrapnel_type = null
embedding = list( embed_type = /datum/embed_data/arrow
embed_chance = 90,
fall_chance = 2, /datum/embed_data/arrow
jostle_chance = 2, embed_chance = 90
ignore_throwspeed_threshold = TRUE, fall_chance = 2
pain_stam_pct = 0.5, jostle_chance = 2
pain_mult = 3, ignore_throwspeed_threshold = TRUE
jostle_pain_mult = 3, pain_stam_pct = 0.5
rip_time = 1 SECONDS pain_mult = 3
) jostle_pain_mult = 3
rip_time = 1 SECONDS
/// holy arrows /// holy arrows
/obj/item/ammo_casing/arrow/holy /obj/item/ammo_casing/arrow/holy
@@ -99,7 +100,7 @@
desc = "THE UNMATCHED POWER OF THE SUN" desc = "THE UNMATCHED POWER OF THE SUN"
icon_state = "holy_arrow_projectile" icon_state = "holy_arrow_projectile"
damage = 20 damage = 20
embedding = null embed_type = null
/obj/projectile/bullet/arrow/blazing/on_hit(atom/target, blocked, pierce_hit) /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 ///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 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 ///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 ///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 var/hit_prone_targets = FALSE
///if TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets ///if TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets
@@ -218,8 +220,8 @@
/obj/projectile/Initialize(mapload) /obj/projectile/Initialize(mapload)
. = ..() . = ..()
decayedRange = range decayedRange = range
if(embedding) if(get_embed())
updateEmbedding() AddElement(/datum/element/embed)
AddElement(/datum/element/connect_loc, projectile_connections) AddElement(/datum/element/connect_loc, projectile_connections)
/obj/projectile/proc/Range() /obj/projectile/proc/Range()
@@ -227,8 +229,8 @@
if(wound_bonus != CANT_WOUND) if(wound_bonus != CANT_WOUND)
wound_bonus += wound_falloff_tile wound_bonus += wound_falloff_tile
bare_wound_bonus = max(0, bare_wound_bonus + wound_falloff_tile) bare_wound_bonus = max(0, bare_wound_bonus + wound_falloff_tile)
if(embedding) if(get_embed())
embedding["embed_chance"] += embed_falloff_tile 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) if(damage_falloff_tile && damage >= 0)
damage += damage_falloff_tile damage += damage_falloff_tile
if(stamina_falloff_tile && stamina >= 0) if(stamina_falloff_tile && stamina >= 0)
@@ -1130,26 +1132,6 @@
/obj/projectile/experience_pressure_difference() /obj/projectile/experience_pressure_difference()
return 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"? * Is this projectile considered "hostile"?
* *
@@ -1169,7 +1151,7 @@
///Checks if the projectile can embed into someone ///Checks if the projectile can embed into someone
/obj/projectile/proc/can_embed_into(atom/hit) /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 /// Reflects the projectile off of something
/obj/projectile/proc/reflect(atom/hit_atom) /obj/projectile/proc/reflect(atom/hit_atom)
@@ -1212,3 +1194,16 @@
bullet.preparePixelProjectile(target, src) bullet.preparePixelProjectile(target, src)
bullet.fire() bullet.fire()
return bullet 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 sharpness = SHARP_POINTY
impact_effect_type = /obj/effect/temp_visual/impact_effect impact_effect_type = /obj/effect/temp_visual/impact_effect
shrapnel_type = /obj/item/shrapnel/bullet 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_bonus = 0
wound_falloff_tile = -5 wound_falloff_tile = -5
embed_falloff_tile = -3 embed_falloff_tile = -3
@@ -16,3 +16,12 @@
/obj/projectile/bullet/smite /obj/projectile/bullet/smite
name = "divine retribution" name = "divine retribution"
damage = 10 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 pass_flags = PASSTABLE | PASSMOB
sharpness = NONE sharpness = NONE
shrapnel_type = null shrapnel_type = null
embedding = null embed_type = null
impact_effect_type = null impact_effect_type = null
suppressed = SUPPRESSED_VERY suppressed = SUPPRESSED_VERY
damage_type = BURN damage_type = BURN

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,11 +4,21 @@
name = "junk bullet" name = "junk bullet"
icon_state = "trashball" icon_state = "trashball"
damage = 30 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_mob_biotypes = MOB_ROBOTIC
var/bane_multiplier = 1.5 var/bane_multiplier = 1.5
var/bane_added_damage = 0 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) /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) 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" name = "bundle of live electrical parts"
icon_state = "tesla_projectile" icon_state = "tesla_projectile"
damage = 15 damage = 15
embedding = null embed_type = null
shrapnel_type = null shrapnel_type = null
bane_multiplier = 3 bane_multiplier = 3
@@ -49,10 +59,20 @@
name = "junk ripper bullet" name = "junk ripper bullet"
icon_state = "redtrac" icon_state = "redtrac"
damage = 10 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 wound_bonus = 10
bare_wound_bonus = 30 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 /obj/projectile/bullet/junk/reaper
name = "junk reaper bullet" name = "junk reaper bullet"
tracer_type = /obj/effect/projectile/tracer/sniper tracer_type = /obj/effect/projectile/tracer/sniper

View File

@@ -3,13 +3,23 @@
/obj/projectile/bullet/c9mm /obj/projectile/bullet/c9mm
name = "9mm bullet" name = "9mm bullet"
damage = 30 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 /obj/projectile/bullet/c9mm/ap
name = "9mm armor-piercing bullet" name = "9mm armor-piercing bullet"
damage = 27 damage = 27
armour_penetration = 40 armour_penetration = 40
embedding = null embed_type = null
shrapnel_type = null shrapnel_type = null
/obj/projectile/bullet/c9mm/hp /obj/projectile/bullet/c9mm/hp

View File

@@ -21,9 +21,19 @@
ricochet_auto_aim_range = 3 ricochet_auto_aim_range = 3
wound_bonus = -20 wound_bonus = -20
bare_wound_bonus = 10 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 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 /obj/projectile/bullet/c38/match
name = ".38 Match bullet" name = ".38 Match bullet"
ricochets_max = 4 ricochets_max = 4
@@ -45,7 +55,7 @@
ricochet_decay_damage = 0.8 ricochet_decay_damage = 0.8
shrapnel_type = null shrapnel_type = null
sharpness = NONE 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 // 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 /obj/projectile/bullet/c38/dumdum
@@ -56,10 +66,20 @@
sharpness = SHARP_EDGED sharpness = SHARP_EDGED
wound_bonus = 20 wound_bonus = 20
bare_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 wound_falloff_tile = -5
embed_falloff_tile = -15 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 /obj/projectile/bullet/c38/trac
name = ".38 TRAC bullet" name = ".38 TRAC bullet"
damage = 10 damage = 10

View File

@@ -48,10 +48,20 @@
armour_penetration = 50 armour_penetration = 50
wound_bonus = -20 wound_bonus = -20
bare_wound_bonus = 80 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 wound_falloff_tile = -5
shrapnel_type = null 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) // Rebar (Rebar Crossbow)
/obj/projectile/bullet/rebar /obj/projectile/bullet/rebar
name = "rebar" name = "rebar"
@@ -62,11 +72,21 @@
armour_penetration = 10 armour_penetration = 10
wound_bonus = -20 wound_bonus = -20
bare_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 embed_falloff_tile = -5
wound_falloff_tile = -2 wound_falloff_tile = -2
shrapnel_type = /obj/item/ammo_casing/rebar 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/proc/handle_drop(datum/source, obj/item/ammo_casing/rebar/newcasing)
/obj/projectile/bullet/rebar/syndie /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. 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 wound_bonus = 10
bare_wound_bonus = 20 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_falloff_tile = -3
embed_type = /datum/embed_data/rebar_syndie
shrapnel_type = /obj/item/ammo_casing/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 /obj/projectile/bullet/rebar/zaukerite
name = "zaukerite shard" name = "zaukerite shard"
icon_state = "rebar_zaukerite" icon_state = "rebar_zaukerite"
@@ -93,10 +123,20 @@
armour_penetration = 20 // not nearly as good, as its not as sharp. armour_penetration = 20 // not nearly as good, as its not as sharp.
wound_bonus = 10 wound_bonus = 10
bare_wound_bonus = 40 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. embed_falloff_tile = 0 // very spiky.
shrapnel_type = /obj/item/ammo_casing/rebar/zaukerite 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 /obj/projectile/bullet/rebar/hydrogen
name = "metallic hydrogen bolt" name = "metallic hydrogen bolt"
icon_state = "rebar_hydrogen" 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 projectile_piercing = PASSMOB //felt this might have been a nice compromise for the lower damage for the difficulty of getting it
wound_bonus = -15 wound_bonus = -15
bare_wound_bonus = 10 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 embed_falloff_tile = -3
shrapnel_type = /obj/item/ammo_casing/rebar/hydrogen 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 /obj/projectile/bullet/rebar/healium
name = "healium bolt" name = "healium bolt"
icon_state = "rebar_healium" icon_state = "rebar_healium"
@@ -122,7 +172,7 @@
armour_penetration = 100 armour_penetration = 100
wound_bonus = -100 wound_bonus = -100
bare_wound_bonus = -100 bare_wound_bonus = -100
embedding = list(embed_chance = 0) embed_type = null
embed_falloff_tile = -3 embed_falloff_tile = -3
shrapnel_type = /obj/item/ammo_casing/rebar/healium shrapnel_type = /obj/item/ammo_casing/rebar/healium
@@ -139,7 +189,6 @@
return BULLET_ACT_HIT return BULLET_ACT_HIT
/obj/projectile/bullet/rebar/supermatter /obj/projectile/bullet/rebar/supermatter
name = "supermatter bolt" name = "supermatter bolt"
icon_state = "rebar_supermatter" icon_state = "rebar_supermatter"
@@ -147,6 +196,7 @@
speed = 0.4 speed = 0.4
dismemberment = 0 dismemberment = 0
damage_type = TOX damage_type = TOX
embed_type = null
armour_penetration = 100 armour_penetration = 100
shrapnel_type = /obj/item/ammo_casing/rebar/supermatter shrapnel_type = /obj/item/ammo_casing/rebar/supermatter
@@ -164,7 +214,6 @@
return BULLET_ACT_HIT return BULLET_ACT_HIT
/obj/projectile/bullet/rebar/supermatter/proc/dust_feedback(atom/target) /obj/projectile/bullet/rebar/supermatter/proc/dust_feedback(atom/target)
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 10, TRUE) 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!")) 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. damage = 1 // It's a damn toy.
range = 10 range = 10
shrapnel_type = null shrapnel_type = null
embedding = null embed_type = null
name = "paper ball" name = "paper ball"
desc = "doink!" desc = "doink!"
damage_type = BRUTE damage_type = BRUTE

View File

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

View File

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

View File

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

View File

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

View File

@@ -252,7 +252,7 @@
ricochet_auto_aim_angle = 10 ricochet_auto_aim_angle = 10
ricochet_auto_aim_range = 3 ricochet_auto_aim_range = 3
wound_bonus = -10 wound_bonus = -10
embedding = null embed_type = null
/obj/projectile/bullet/c38/holy/on_hit(atom/target, blocked, pierce_hit) /obj/projectile/bullet/c38/holy/on_hit(atom/target, blocked, pierce_hit)
. = ..() . = ..()

View File

@@ -351,7 +351,7 @@
check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!!")]" check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [LOWER_TEXT(wound.name)]!!!")]"
for(var/obj/item/embedded_thing in embedded_objects) for(var/obj/item/embedded_thing in embedded_objects)
var/stuck_word = embedded_thing.isEmbedHarmless() ? "stuck" : "embedded" var/stuck_word = embedded_thing.is_embed_harmless() ? "stuck" : "embedded"
check_list += "\t <a href='?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]' class='warning'>There is \a [embedded_thing] [stuck_word] in your [name]!</a>" check_list += "\t <a href='?src=[REF(examiner)];embedded_object=[REF(embedded_thing)];embedded_limb=[REF(src)]' class='warning'>There is \a [embedded_thing] [stuck_word] in your [name]!</a>"
/obj/item/bodypart/blob_act() /obj/item/bodypart/blob_act()
@@ -1096,15 +1096,15 @@
if(embed in embedded_objects) // go away if(embed in embedded_objects) // go away
return return
// We don't need to do anything with projectile embedding, because it will never reach this point // We don't need to do anything with projectile embedding, because it will never reach this point
RegisterSignal(embed, COMSIG_ITEM_EMBEDDING_UPDATE, PROC_REF(embedded_object_changed))
embedded_objects += embed embedded_objects += embed
RegisterSignal(embed, COMSIG_ITEM_EMBEDDING_UPDATE, PROC_REF(embedded_object_changed))
refresh_bleed_rate() refresh_bleed_rate()
/// INTERNAL PROC, DO NOT USE /// INTERNAL PROC, DO NOT USE
/// Cleans up any attachment we have to the embedded object, removes it from our list /// Cleans up any attachment we have to the embedded object, removes it from our list
/obj/item/bodypart/proc/_unembed_object(obj/item/unembed) /obj/item/bodypart/proc/_unembed_object(obj/item/unembed)
UnregisterSignal(unembed, COMSIG_ITEM_EMBEDDING_UPDATE)
embedded_objects -= unembed embedded_objects -= unembed
UnregisterSignal(unembed, COMSIG_ITEM_EMBEDDING_UPDATE)
refresh_bleed_rate() refresh_bleed_rate()
/obj/item/bodypart/proc/embedded_object_changed(obj/item/embedded_source) /obj/item/bodypart/proc/embedded_object_changed(obj/item/embedded_source)
@@ -1157,7 +1157,7 @@
cached_bleed_rate += 0.5 cached_bleed_rate += 0.5
for(var/obj/item/embeddies in embedded_objects) for(var/obj/item/embeddies in embedded_objects)
if(!embeddies.isEmbedHarmless()) if(!embeddies.is_embed_harmless())
cached_bleed_rate += 0.25 cached_bleed_rate += 0.25
for(var/datum/wound/iter_wound as anything in wounds) for(var/datum/wound/iter_wound as anything in wounds)

View File

@@ -139,7 +139,7 @@
/mob/living/carbon/proc/has_embedded_objects(include_harmless=FALSE) /mob/living/carbon/proc/has_embedded_objects(include_harmless=FALSE)
for(var/obj/item/bodypart/bodypart as anything in bodyparts) for(var/obj/item/bodypart/bodypart as anything in bodyparts)
for(var/obj/item/embedded in bodypart.embedded_objects) for(var/obj/item/embedded in bodypart.embedded_objects)
if(!include_harmless && embedded.isEmbedHarmless()) if(!include_harmless && embedded.is_embed_harmless())
continue continue
return TRUE return TRUE

View File

@@ -33,10 +33,15 @@
attack_verb_continuous = list("stubs", "pokes") attack_verb_continuous = list("stubs", "pokes")
attack_verb_simple = list("stub", "poke") attack_verb_simple = list("stub", "poke")
sharpness = SHARP_EDGED sharpness = SHARP_EDGED
embedding = list("pain_mult" = 1, "embed_chance" = 30, "fall_chance" = 70) embed_type = /datum/embed_data/janicart_key
wound_bonus = -1 wound_bonus = -1
bare_wound_bonus = 2 bare_wound_bonus = 2
/datum/embed_data/janicart_key
pain_mult = 1
embed_chance = 30
fall_chance = 70
/obj/item/key/janitor/suicide_act(mob/living/carbon/user) /obj/item/key/janitor/suicide_act(mob/living/carbon/user)
switch(user.mind?.get_skill_level(/datum/skill/cleaning)) switch(user.mind?.get_skill_level(/datum/skill/cleaning))
if(SKILL_LEVEL_NONE to SKILL_LEVEL_NOVICE) //Their mind is too weak to ascend as a janny if(SKILL_LEVEL_NONE to SKILL_LEVEL_NOVICE) //Their mind is too weak to ascend as a janny

View File

@@ -1074,11 +1074,9 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
var/mob/living/carbon/carbon_target = atom_target var/mob/living/carbon/carbon_target = atom_target
for(var/i in 1 to num_shards) for(var/i in 1 to num_shards)
var/obj/item/shard/shard = new /obj/item/shard(get_turf(carbon_target)) var/obj/item/shard/shard = new /obj/item/shard(get_turf(carbon_target))
shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult = 1, pain_chance = 5) shard.set_embed(/datum/embed_data/glass_candy)
shard.updateEmbedding()
carbon_target.hitby(shard, skipcatch = TRUE, hitpush = FALSE) carbon_target.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
shard.embedding = list() shard.set_embed(initial(shard.embed_type))
shard.updateEmbedding()
return TRUE return TRUE
if (VENDOR_CRUSH_CRIT_PIN) // pin them beneath the machine until someone untilts it if (VENDOR_CRUSH_CRIT_PIN) // pin them beneath the machine until someone untilts it
if (!isliving(atom_target)) if (!isliving(atom_target))

View File

@@ -776,6 +776,7 @@
#include "code\datums\dog_fashion.dm" #include "code\datums\dog_fashion.dm"
#include "code\datums\ductnet.dm" #include "code\datums\ductnet.dm"
#include "code\datums\eigenstate.dm" #include "code\datums\eigenstate.dm"
#include "code\datums\embed_data.dm"
#include "code\datums\emotes.dm" #include "code\datums\emotes.dm"
#include "code\datums\ert.dm" #include "code\datums\ert.dm"
#include "code\datums\hailer_phrase.dm" #include "code\datums\hailer_phrase.dm"