diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 611b9ca5d8f..1bb5578122f 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -139,7 +139,6 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define EMBEDDED_JOSTLE_CHANCE 5 //Chance for embedded objects to cause pain every time they move (jostle) #define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 //Coefficient of multiplication for the damage the item does while #define EMBEDDED_PAIN_STAM_PCT 0.0 //This percentage of all pain will be dealt as stam damage rather than brute (0-1) -#define EMBED_CHANCE_TURF_MOD -15 //You are this many percentage points less likely to embed into a turf (good for things glass shards and spears vs walls) #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) diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index 2803fee3060..06dcc0bfd1a 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -3,16 +3,11 @@ and when it impacts and meets the requirements to stick into something, it instantiates an embedded component. Once the item falls out, the component is destroyed, while the element survives to embed another day. - There are 2 different things that can be embedded presently: carbons, and closed turfs (see: walls) - - Carbon embedding has all the classical embedding behavior, and tracks more events and signals. The main behaviors and hooks to look for are: -- Every process tick, there is a chance to randomly proc pain, controlled by pain_chance. There may also be a chance for the object to fall out randomly, per fall_chance -- Every time the mob moves, there is a chance to proc jostling pain, controlled by jostle_chance (and only 50% as likely if the mob is walking or crawling) -- Various signals hooking into carbon topic() and the embed removal surgery in order to handle removals. - - Turf embedding is much simpler. All we do here is draw an overlay of the item's inhand on the turf, hide the item, and create an HTML link in the turf's inspect - that allows you to rip the item out. There's nothing dynamic about this, so far less checks. - In addition, there are 2 cases of embedding: embedding, and sticking @@ -24,8 +19,7 @@ Stickables differ from embeds in the following ways: -- Text descriptors use phrasing like "X is stuck to Y" rather than "X is embedded in Y" -- There is no slicing sound on impact - -- All damage checks and bloodloss are skipped for carbons - -- Pointy objects create sparks when embedding into a turf + -- All damage checks and bloodloss are skipped */ @@ -47,11 +41,9 @@ var/jostle_chance var/jostle_pain_mult var/pain_stam_pct - var/embed_chance_turf_mod ///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/mutable_appearance/overlay /datum/component/embedded/Initialize(obj/item/I, datum/thrownthing/throwingdatum, @@ -66,10 +58,9 @@ ignore_throwspeed_threshold = FALSE, jostle_chance = EMBEDDED_JOSTLE_CHANCE, jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER, - pain_stam_pct = EMBEDDED_PAIN_STAM_PCT, - embed_chance_turf_mod = EMBED_CHANCE_TURF_MOD) + pain_stam_pct = EMBEDDED_PAIN_STAM_PCT) - if((!iscarbon(parent) && !isclosedturf(parent)) || !isitem(I)) + if(!iscarbon(parent) || !isitem(I)) return COMPONENT_INCOMPATIBLE if(part) @@ -85,186 +76,54 @@ src.jostle_chance = jostle_chance src.jostle_pain_mult = jostle_pain_mult src.pain_stam_pct = pain_stam_pct - src.embed_chance_turf_mod = embed_chance_turf_mod - src.weapon = I if(!weapon.isEmbedHarmless()) harmful = TRUE weapon.embedded(parent) - - if(iscarbon(parent)) - initCarbon() - else if(isclosedturf(parent)) - initTurf(throwingdatum) - -/datum/component/embedded/RegisterWithParent() - if(iscarbon(parent)) - RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck) - RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOutCarbon) - RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemoveCarbon) - else if(isclosedturf(parent)) - RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examineTurf) - RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/itemMoved) - -/datum/component/embedded/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL, COMSIG_PARENT_EXAMINE)) - -/datum/component/embedded/process() - if(iscarbon(parent)) - processCarbon() - -/datum/component/embedded/Destroy() - if(weapon) - UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) - if(overlay) - var/atom/A = parent - UnregisterSignal(A,COMSIG_ATOM_UPDATE_OVERLAYS) - qdel(overlay) - - return ..() - -//////////////////////////////////////// -/////////////HUMAN PROCS//////////////// -//////////////////////////////////////// - -/// Set up an instance of embedding for a carbon. This is basically an extension of Initialize() so not much to say -/datum/component/embedded/proc/initCarbon() START_PROCESSING(SSdcs, src) var/mob/living/carbon/victim = parent - if(!istype(limb)) - limb = pick(victim.bodyparts) limb.embedded_objects |= weapon // on the inside... on the inside... weapon.forceMove(victim) - RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon) + RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/weaponDeleted) + victim.visible_message("[weapon] [harmful ? "embeds" : "sticks"] itself [harmful ? "in" : "to"] [victim]'s [limb.name]!", "[weapon] [harmful ? "embeds" : "sticks"] itself [harmful ? "in" : "to"] your [limb.name]!") if(harmful) - victim.visible_message("[weapon] embeds itself in [victim]'s [limb.name]!",ignored_mobs=victim) - to_chat(victim, "[weapon] embeds itself in your [limb.name]!") victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) playsound(victim,'sound/weapons/bladeslice.ogg', 40) weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody! var/damage = weapon.w_class * impact_pain_mult - limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus=-30, sharpness = TRUE) + limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded) - else - victim.visible_message("[weapon] sticks itself to [victim]'s [limb.name]!",ignored_mobs=victim) - to_chat(victim, "[weapon] sticks itself to your [limb.name]!") -/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking. -/datum/component/embedded/proc/jostleCheck() +/datum/component/embedded/Destroy() var/mob/living/carbon/victim = parent - - var/chance = jostle_chance - if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND)) - chance *= 0.5 - - if(harmful && prob(chance)) - var/damage = weapon.w_class * jostle_pain_mult - limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) - to_chat(victim, "[weapon] embedded in your [limb.name] jostles and stings!") - - -/// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove() -/datum/component/embedded/proc/fallOutCarbon() - var/mob/living/carbon/victim = parent - - if(harmful) - var/damage = weapon.w_class * remove_pain_mult - limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) - victim.visible_message("[weapon] falls out of [victim.name]'s [limb.name]!", ignored_mobs=victim) - to_chat(victim, "[weapon] falls out of your [limb.name]!") - else - victim.visible_message("[weapon] falls off of [victim.name]'s [limb.name]!", ignored_mobs=victim) - to_chat(victim, "[weapon] falls off of your [limb.name]!") - - safeRemoveCarbon() - - -/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove() -/datum/component/embedded/proc/ripOutCarbon(datum/source, obj/item/I, obj/item/bodypart/limb) - if(I != weapon || src.limb != limb) - return - - var/mob/living/carbon/victim = parent - var/time_taken = rip_time * weapon.w_class - - victim.visible_message("[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].","You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)") - if(do_after(victim, time_taken, target = victim)) - if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects)) - qdel(src) - return - - if(harmful) - var/damage = weapon.w_class * remove_pain_mult - limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE) //It hurts to rip it out, get surgery you dingus. - victim.emote("scream") - victim.visible_message("[victim] successfully rips [weapon] out of [victim.p_their()] [limb.name]!", "You successfully remove [weapon] from your [limb.name].") - else - victim.visible_message("[victim] successfully rips [weapon] off of [victim.p_their()] [limb.name]!", "You successfully remove [weapon] from your [limb.name].") - - safeRemoveCarbon(TRUE) - - -/// 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. -/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out -/datum/component/embedded/proc/safeRemoveCarbon(to_hands) - var/mob/living/carbon/victim = parent - limb.embedded_objects -= weapon - - UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) // have to unhook these here so they don't also register as having disappeared - - if(!weapon) - if(!victim.has_embedded_objects()) - victim.clear_alert("embeddedobject") - SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded") - qdel(src) - return - - if(weapon.unembedded()) // if it deleted itself - weapon = null - if(!victim.has_embedded_objects()) - victim.clear_alert("embeddedobject") - SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded") - qdel(src) - return - - if(to_hands) - victim.put_in_hands(weapon) - else - weapon.forceMove(get_turf(victim)) - - if(!victim.has_embedded_objects()) + if(victim && !victim.has_embedded_objects()) victim.clear_alert("embeddedobject") SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded") - qdel(src) - - -/// Something deleted or moved our weapon while it was embedded, how rude! -/datum/component/embedded/proc/byeItemCarbon() - var/mob/living/carbon/victim = parent - limb.embedded_objects -= weapon - UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) - - if(victim) - to_chat(victim, "\The [weapon] that was embedded in your [limb.name] disappears!") - if(!victim.has_embedded_objects()) - victim.clear_alert("embeddedobject") - SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded") + if(weapon) + UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) weapon = null - qdel(src) + limb = null + return ..() +/datum/component/embedded/RegisterWithParent() + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck) + RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOut) + RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemove) -/// Items embedded/stuck to carbons both check whether they randomly fall out (if applicable), as well as if the target mob and limb still exists. -/// Items harmfully embedded in carbons have an additional check for random pain (if applicable) -/datum/component/embedded/proc/processCarbon() +/datum/component/embedded/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL)) + +/datum/component/embedded/process() var/mob/living/carbon/victim = parent if(!victim || !limb) // in case the victim and/or their limbs exploded (say, due to a sticky bomb) weapon.forceMove(get_turf(weapon)) qdel(src) + return if(victim.stat == DEAD) return @@ -272,95 +131,90 @@ var/damage = weapon.w_class * pain_mult var/chance = pain_chance if(pain_stam_pct && victim.stam_paralyzed) //if it's a less-lethal embed, give them a break if they're already stamcritted - chance *= 0.3 - damage *= 0.7 + chance *= 0.2 + damage *= 0.5 if(harmful && prob(chance)) - limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) + limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND) to_chat(victim, "[weapon] embedded in your [limb.name] hurts!") if(prob(fall_chance)) - fallOutCarbon() - - + fallOut() //////////////////////////////////////// -//////////////TURF PROCS//////////////// +////////////BEHAVIOR PROCS////////////// //////////////////////////////////////// -/// Turfs are much lower maintenance, since we don't care if they're in pain, but since they don't bleed or scream, we draw an overlay to show their status. -/// The only difference pointy/sticky items make here is text descriptors and pointy objects making a spark shower on impact. -/datum/component/embedded/proc/initTurf(datum/thrownthing/throwingdatum) - var/turf/closed/hit = parent - // we can't store the item IN the turf (cause turfs are just kinda... there), so we fake it by making the item invisible and bailing if it moves due to a blast - weapon.forceMove(hit) - weapon.invisibility = INVISIBILITY_ABSTRACT - RegisterSignal(weapon, COMSIG_MOVABLE_MOVED, .proc/itemMoved) +/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking. +/datum/component/embedded/proc/jostleCheck() + var/mob/living/carbon/victim = parent + var/chance = jostle_chance + if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND)) + chance *= 0.5 - var/pixelX = rand(-2, 2) - var/pixelY = rand(-1, 3) // bias this upwards since in-hands are usually on the lower end of the sprite + if(harmful && prob(chance)) + var/damage = weapon.w_class * jostle_pain_mult + limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND) + to_chat(victim, "[weapon] embedded in your [limb.name] jostles and stings!") - switch(throwingdatum.init_dir) - if(NORTH) - pixelY -= 2 - if(SOUTH) - pixelY += 2 - if(WEST) - pixelX += 2 - if(EAST) - pixelX -= 2 - if(throwingdatum.init_dir in list(NORTH, WEST, NORTHWEST, SOUTHWEST)) - overlay = mutable_appearance(icon=weapon.righthand_file,icon_state=weapon.inhand_icon_state) - else - overlay = mutable_appearance(icon=weapon.lefthand_file,icon_state=weapon.inhand_icon_state) - - var/matrix/M = matrix() - M.Translate(pixelX, pixelY) - overlay.transform = M - RegisterSignal(hit,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/apply_overlay) - hit.update_icon() +/// 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() + var/mob/living/carbon/victim = parent if(harmful) - hit.visible_message("[weapon] embeds itself in [hit]!") - playsound(hit,'sound/weapons/bladeslice.ogg', 70) + var/damage = weapon.w_class * remove_pain_mult + limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE, wound_bonus = CANT_WOUND) - var/datum/effect_system/spark_spread/sparks = new - sparks.set_up(1, 1, parent) - sparks.attach(parent) - sparks.start() - else - hit.visible_message("[weapon] sticks itself to [hit]!") + victim.visible_message("[weapon] falls [harmful ? "out" : "off"] of [victim.name]'s [limb.name]!", "[weapon] falls [harmful ? "out" : "off"] of your [limb.name]!") + safeRemove() -/datum/component/embedded/proc/apply_overlay(atom/source, list/overlay_list) - overlay_list += overlay +/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove() +/datum/component/embedded/proc/ripOut(datum/source, obj/item/I, obj/item/bodypart/limb) + if(I != weapon || src.limb != limb) + return + + var/mob/living/carbon/victim = parent + var/time_taken = rip_time * weapon.w_class + victim.visible_message("[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].","You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)") + + if(!do_after(victim, time_taken, target = victim)) + return + if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects)) + qdel(src) + return -/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list) if(harmful) - examine_list += "\t There is \a [weapon] embedded in [parent]!" - else - examine_list += "\t There is \a [weapon] stuck to [parent]!" + var/damage = weapon.w_class * remove_pain_mult + limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, sharpness=TRUE) //It hurts to rip it out, get surgery you dingus. + victim.emote("scream") + victim.visible_message("[victim] successfully rips [weapon] [harmful ? "out" : "off"] of [victim.p_their()] [limb.name]!", "You successfully remove [weapon] from your [limb.name].") + safeRemove(TRUE) -/// Someone is ripping out the item from the turf by hand -/datum/component/embedded/Topic(datum/source, href_list) - var/mob/living/us = usr - if(in_range(us, parent) && locate(href_list["embedded_object"]) == weapon) - if(harmful) - us.visible_message("[us] begins unwedging [weapon] from [parent].", "You begin unwedging [weapon] from [parent]...") +/// 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. +/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out +/datum/component/embedded/proc/safeRemove(to_hands) + var/mob/living/carbon/victim = parent + limb.embedded_objects -= weapon + UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) // have to do it here otherwise we trigger weaponDeleted() + + if(!weapon.unembedded()) // if it hasn't deleted itself due to drop del + UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) + if(to_hands) + victim.put_in_hands(weapon) else - us.visible_message("[us] begins unsticking [weapon] from [parent].", "You begin unsticking [weapon] from [parent]...") + weapon.forceMove(get_turf(victim)) + + qdel(src) + +/// Something deleted or moved our weapon while it was embedded, how rude! +/datum/component/embedded/proc/weaponDeleted() + var/mob/living/carbon/victim = parent + limb.embedded_objects -= weapon + + if(victim) + to_chat(victim, "\The [weapon] that was embedded in your [limb.name] disappears!") - if(do_after(us, 30, target = parent)) - us.put_in_hands(weapon) - weapon.unembedded() - qdel(src) - - -/// This proc handles if something knocked the invisible item loose from the turf somehow (probably an explosion). Just make it visible and say it fell loose, then get outta here. -/datum/component/embedded/proc/itemMoved() - weapon.invisibility = initial(weapon.invisibility) - weapon.visible_message("[weapon] falls loose from [parent].") - weapon.unembedded() qdel(src) diff --git a/code/datums/elements/embed.dm b/code/datums/elements/embed.dm index 1e7ae9baebb..301799316d3 100644 --- a/code/datums/elements/embed.dm +++ b/code/datums/elements/embed.dm @@ -1,16 +1,14 @@ /* - The presence of this element allows an item (or a projectile carrying an item) to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave) with either + The presence of this element allows an item (or a projectile carrying an item) to embed itself in a carbon when it is thrown into a target (whether by hand, gun, or explosive wave) with either at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE. Items meant to be used as shrapnel for projectiles should have ignore_throwspeed_threshold set to true. Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them. - Items simply make their COMSIG_MOVABLE_IMPACT or COMSIG_MOVABLE_IMPACT_ZONE check (against a closed turf or a carbon, respectively), while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT. + Items simply make their COMSIG_MOVABLE_IMPACT_ZONE check, while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT. Upon a projectile hitting a valid target, it spawns whatever type of payload it has defined, then has that try to embed itself in the target on its own. Otherwise non-embeddable or stickable items can be made embeddable/stickable through wizard events/sticky tape/admin memes. */ -#define STANDARD_WALL_HARDNESS 40 - /datum/element/embed element_flags = ELEMENT_BESPOKE id_arg_index = 2 @@ -29,17 +27,15 @@ var/jostle_pain_mult var/pain_stam_pct var/payload_type - var/embed_chance_turf_mod -/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, embed_chance_turf_mod, projectile_payload=/obj/item/shard) +/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)) return ELEMENT_INCOMPATIBLE if(isitem(target)) - RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob) - RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther) + RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbed) RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage) RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined) RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, .proc/tryForceEmbed) @@ -56,7 +52,6 @@ src.jostle_chance = jostle_chance src.jostle_pain_mult = jostle_pain_mult src.pain_stam_pct = pain_stam_pct - src.embed_chance_turf_mod = embed_chance_turf_mod initialized = TRUE else payload_type = projectile_payload @@ -72,7 +67,7 @@ /// Checking to see if we're gonna embed into a human -/datum/element/embed/proc/checkEmbedMob(obj/item/weapon, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum, forced=FALSE) +/datum/element/embed/proc/checkEmbed(obj/item/weapon, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum, forced=FALSE) if(!istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE)) return @@ -107,42 +102,7 @@ ignore_throwspeed_threshold = ignore_throwspeed_threshold,\ jostle_chance = jostle_chance,\ jostle_pain_mult = jostle_pain_mult,\ - pain_stam_pct = pain_stam_pct,\ - embed_chance_turf_mod = embed_chance_turf_mod) - - return TRUE - -/// We need the hit_zone if we're embedding into a human, so this proc only handles if we're embedding into a turf -/datum/element/embed/proc/checkEmbedOther(obj/item/weapon, turf/closed/hit, datum/thrownthing/throwingdatum, forced=FALSE) - if(!istype(hit)) - return - - var/chance = embed_chance + embed_chance_turf_mod - if(iswallturf(hit)) - var/turf/closed/wall/W = hit - chance += 2 * (W.hardness - STANDARD_WALL_HARDNESS) - - if(!forced && chance <= 0 || embed_chance_turf_mod <= -100) - return - - var/pass = ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(chance)) - if(!pass) - return - - hit.AddComponent(/datum/component/embedded,\ - weapon,\ - throwingdatum,\ - 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,\ - embed_chance_turf_mod = embed_chance_turf_mod) + pain_stam_pct = pain_stam_pct) return TRUE @@ -165,46 +125,39 @@ /** * checkEmbedProjectile() is what we get when a projectile with a defined shrapnel_type impacts a target. * - * If we hit a valid target (carbon or closed turf), we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead + * If we hit a valid target, we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead * it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to. */ /datum/element/embed/proc/checkEmbedProjectile(obj/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone) - if(!iscarbon(hit) && !isclosedturf(hit)) + if(!iscarbon(hit)) Detach(P) return // we don't care var/obj/item/payload = new payload_type(get_turf(hit)) - var/did_embed - if(iscarbon(hit)) - var/mob/living/carbon/C = hit - var/obj/item/bodypart/limb - limb = C.get_bodypart(hit_zone) - if(!limb) - limb = C.get_bodypart() - did_embed = payload.tryEmbed(limb) - else - did_embed = payload.tryEmbed(hit) + var/mob/living/carbon/C = hit + var/obj/item/bodypart/limb = C.get_bodypart(hit_zone) + if(!limb) + limb = C.get_bodypart() - if(!did_embed) + if(!payload.tryEmbed(limb)) payload.failedEmbed() Detach(P) /** * 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. * - * 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 (which likely represents said bullet), and possibly - * AGAIN if we actually embed. This way, we save on at least one message. Runs the standard embed checks on the mob/turf. + * 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. * * Arguments: - * * I- what we're trying to embed, obviously - * * target- what we're trying to shish-kabob, either a bodypart, a carbon, or a closed turf + * * I- the item we're trying to insert into the target + * * target- what we're trying to shish-kabob, either a bodypart or a carbon * * 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% */ /datum/element/embed/proc/tryForceEmbed(obj/item/I, atom/target, hit_zone, forced=FALSE) var/obj/item/bodypart/limb var/mob/living/carbon/C - var/turf/closed/T if(!forced && !prob(embed_chance)) return @@ -218,10 +171,5 @@ limb = target hit_zone = limb.body_zone C = limb.owner - else if(isclosedturf(target)) - T = target - if(C) - return checkEmbedMob(I, C, hit_zone, forced=TRUE) - else if(T) - return checkEmbedOther(I, T, forced=TRUE) + return checkEmbed(I, C, hit_zone, forced=TRUE) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index db396017a5d..e911786a8e1 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -974,11 +974,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb * Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements. * * Arguments: - * * target- Either a body part, a carbon, or a closed turf. What are we hitting? + * * target- Either a body part or a carbon. What are we hitting? * * forced- Do we want this to go through 100%? */ /obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE) - if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target)) + if(!isbodypart(target) && !iscarbon(target)) return if(!forced && !LAZYLEN(embedding)) return @@ -1008,6 +1008,5 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb 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),\ - embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD)) + pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT)) return TRUE diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm index 9ac91317cd1..91df52a6ea5 100644 --- a/code/game/objects/items/shrapnel.dm +++ b/code/game/objects/items/shrapnel.dm @@ -1,6 +1,6 @@ /obj/item/shrapnel // frag grenades name = "shrapnel shard" - embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=4, embed_chance_turf_mod=-100) + embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=4) custom_materials = list(/datum/material/iron=50) armour_penetration = -20 icon = 'icons/obj/shards.dmi' @@ -11,7 +11,7 @@ /obj/item/shrapnel/stingball // stingbang grenades name = "stingball" - 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_chance_turf_mod=-100) + 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) icon_state = "tiny" sharpness = FALSE @@ -26,7 +26,7 @@ /obj/item/shrapnel/bullet/c38/dumdum // .38 DumDum round name = "\improper .38 DumDum bullet" - embedding = list(embed_chance=70, fall_chance=7, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10, embed_chance_turf_mod=-100) + embedding = list(embed_chance=70, fall_chance=7, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) /obj/projectile/bullet/shrapnel name = "flying shrapnel shard" diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 645b861c2b4..fd92c3643aa 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -292,7 +292,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 2 throwforce = 20 //20 + 2 (WEIGHT_CLASS_SMALL) * 4 (EMBEDDED_IMPACT_PAIN_MULTIPLIER) = 28 damage on hit due to guaranteed embedding throw_speed = 4 - embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15) + embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0) armour_penetration = 40 w_class = WEIGHT_CLASS_SMALL diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 18f5ce5130f..b6676e954af 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -14,7 +14,7 @@ flags_ricochet = RICOCHET_HARD - ///lower numbers are harder. Used to determine the probability of a hulk smashing through. Also, (hardness - 40) is used as a modifier for objects trying to embed in this (hardness of 30 results in a -10% chance) + ///lower numbers are harder. Used to determine the probability of a hulk smashing through. var/hardness = 40 var/slicing_duration = 100 //default time taken to slice the wall var/sheet_type = /obj/item/stack/sheet/metal diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm index 508722ecf2a..ccce6c3af2b 100644 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm +++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm @@ -15,4 +15,4 @@ /obj/item/throwing_star/ninja name = "ninja throwing star" throwforce = 30 - embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15) + embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0)