diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index d0159cd4a47b7..9dc3442380dc8 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -92,6 +92,8 @@ if(!weapon.isEmbedHarmless()) harmful = TRUE + weapon.embedded(parent) + if(iscarbon(parent)) initCarbon() else if(isclosedturf(parent)) diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index b0e9a3fccccda..2fc4fd929c6d8 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -17,20 +17,34 @@ */ /datum/component/pellet_cloud - var/projectile_type /// What's the projectile path of the shrapnel we're shooting? - - var/num_pellets /// How many shrapnel projectiles are we responsible for tracking? May be reduced for grenades if someone dives on top of it. Defined by ammo casing for casings, derived from magnitude otherwise - var/radius = 4 /// For grenades/landmines, how big is the radius of turfs we're targeting? Note this does not effect the projectiles range, only how many we generate - - var/list/pellets = list() /// The list of pellets we're responsible for tracking, once these are all accounted for, we finalize. - var/list/targets_hit = list() /// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages - var/list/bodies /// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()] - var/list/purple_hearts /// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()] - - var/terminated /// how many pellets ranged out without hitting anything - var/hits /// how many pellets impacted something - - var/mob/living/shooter /// for if we're an ammo casing being fired + /// What's the projectile path of the shrapnel we're shooting? + var/projectile_type + + /// How many shrapnel projectiles are we responsible for tracking? May be reduced for grenades if someone dives on top of it. Defined by ammo casing for casings, derived from magnitude otherwise + var/num_pellets + /// For grenades/landmines, how big is the radius of turfs we're targeting? Note this does not effect the projectiles range, only how many we generate + var/radius = 4 + + /// The list of pellets we're responsible for tracking, once these are all accounted for, we finalize. + var/list/pellets = list() + /// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages + var/list/targets_hit = list() + /// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()] + var/list/bodies + /// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()] + var/list/purple_hearts + + /// For grenades, tracking how many pellets are removed due to martyrs and how many pellets are added due to the last person to touch it being on top of it + var/pellet_delta = 0 + /// how many pellets ranged out without hitting anything + var/terminated + /// how many pellets impacted something + var/hits + /// If the parent tried deleting and we're not done yet, we send it to nullspace then delete it after + var/queued_delete = FALSE + + /// for if we're an ammo casing being fired + var/mob/living/shooter /datum/component/pellet_cloud/Initialize(projectile_type=/obj/item/shrapnel, magnitude=5) if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent)) @@ -55,6 +69,7 @@ return ..() /datum/component/pellet_cloud/RegisterWithParent() + RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/nullspace_parent) if(isammocasing(parent)) RegisterSignal(parent, COMSIG_PELLET_CLOUD_INIT, .proc/create_casing_pellets) else if(isgrenade(parent)) @@ -64,7 +79,7 @@ RegisterSignal(parent, COMSIG_MINE_TRIGGERED, .proc/create_blast_pellets) /datum/component/pellet_cloud/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNCROSSED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED)) + UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNCROSSED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED)) /** * create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance) @@ -72,45 +87,44 @@ * Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes. * The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here. */ -/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/A, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro) +/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro) shooter = user var/targloc = get_turf(target) if(!zone_override) zone_override = shooter.zone_selected for(var/i in 1 to num_pellets) - A.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from) + shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from) if(distro) if(randomspread) spread = round((rand() - 0.5) * distro) else //Smart spread spread = round((i / num_pellets - 0.5) * distro) - RegisterSignal(A.BB, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit) - RegisterSignal(A.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range) - pellets += A.BB - if(!A.throw_proj(target, targloc, shooter, params, spread)) + RegisterSignal(shell.BB, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit) + RegisterSignal(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range) + pellets += shell.BB + if(!shell.throw_proj(target, targloc, shooter, params, spread)) return if(i != num_pellets) - A.newshot() + shell.newshot() /** * create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines. * * Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()] */ -/datum/component/pellet_cloud/proc/create_blast_pellets() +/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by) var/atom/A = parent - var/total_pellets_absorbed = 0 if(isgrenade(parent)) // handle_martyrs can reduce the radius and thus the number of pellets we produce if someone dives on top of a frag grenade - total_pellets_absorbed = handle_martyrs() // note that we can modify radius in this proc + handle_martyrs(lanced_by) // note that we can modify radius in this proc if(radius < 1) return var/list/all_the_turfs_were_gonna_lacerate = RANGE_TURFS(radius, A) - RANGE_TURFS(radius-1, A) - num_pellets = all_the_turfs_were_gonna_lacerate.len + total_pellets_absorbed + num_pellets = all_the_turfs_were_gonna_lacerate.len + pellet_delta for(var/T in all_the_turfs_were_gonna_lacerate) var/turf/shootat_turf = T @@ -125,15 +139,27 @@ * * Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later */ -/datum/component/pellet_cloud/proc/handle_martyrs() +/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/lanced_by) + var/magnitude_absorbed var/list/martyrs = list() + + var/self_harm_radius_mult = 3 + + if(lanced_by && prob(60)) + to_chat(lanced_by, "Your plan to whack someone with a grenade on a stick backfires on you, literally!") + self_harm_radius_mult = 1 // we'll still give the guy who got hit some extra shredding, but not 3*radius + pellet_delta += radius + for(var/i in 1 to radius) + pew(lanced_by) // thought you could be tricky and lance someone with no ill effects!! + for(var/mob/living/body in get_turf(parent)) - if(!(body in bodies)) + if(body == shooter) + pellet_delta += radius * self_harm_radius_mult + for(var/i in 1 to radius * self_harm_radius_mult) + pew(body) // free shrapnel if it goes off in your hand, and it doesn't even count towards the absorbed. fun! + else if(!(body in bodies)) martyrs += body // promoted from a corpse to a hero - var/magnitude_absorbed - var/total_pellets_absorbed - for(var/M in martyrs) var/mob/living/martyr = M if(radius > 4) @@ -148,25 +174,26 @@ var/pellets_absorbed = (radius ** 2) - ((radius - magnitude_absorbed - 1) ** 2) radius -= magnitude_absorbed - total_pellets_absorbed += round(pellets_absorbed/2) + pellet_delta -= round(pellets_absorbed * 0.5) if(martyr.stat != DEAD && martyr.client) LAZYADD(purple_hearts, martyr) + RegisterSignal(martyr, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE) - for(var/i in 1 to round(pellets_absorbed/2)) + for(var/i in 1 to round(pellets_absorbed * 0.5)) pew(martyr) if(radius < 1) break - return total_pellets_absorbed - ///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets) /datum/component/pellet_cloud/proc/pellet_hit(obj/projectile/P, atom/movable/firer, atom/target, Angle) pellets -= P terminated++ hits++ targets_hit[target]++ + if(targets_hit[target] == 1) + RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE) UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT)) if(terminated == num_pellets) finalize() @@ -203,34 +230,58 @@ for(var/atom/target in targets_hit) var/num_hits = targets_hit[target] + UnregisterSignal(target, COMSIG_PARENT_QDELETING) if(num_hits > 1) target.visible_message("[target] is hit by [num_hits] [proj_name]s!", null, null, COMBAT_MESSAGE_RANGE, target) to_chat(target, "You're hit by [num_hits] [proj_name]s!") else target.visible_message("[target] is hit by a [proj_name]!", null, null, COMBAT_MESSAGE_RANGE, target) - to_chat(target, "You're hit by [num_hits] [proj_name]s!") + to_chat(target, "You're hit by a [proj_name]!") for(var/M in purple_hearts) var/mob/living/martyr = M if(martyr.stat == DEAD && martyr.client) martyr.client.give_award(/datum/award/achievement/misc/lookoutsir, martyr) - - qdel(parent) + UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED) + if(queued_delete) + qdel(parent) qdel(src) /// Look alive, we're armed! Now we start watching to see if anyone's covering us -/datum/component/pellet_cloud/proc/grenade_armed() +/datum/component/pellet_cloud/proc/grenade_armed(obj/item/nade) + if(ismob(nade.loc)) + shooter = nade.loc LAZYINITLIST(bodies) - RegisterSignal(parent, list(COMSIG_ITEM_DROPPED, COMSIG_MOVABLE_MOVED), .proc/grenade_moved) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/grenade_dropped) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/grenade_moved) RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/grenade_uncrossed) +/// Someone dropped the grenade, so set them to the shooter in case they're on top of it when it goes off +/datum/component/pellet_cloud/proc/grenade_dropped(obj/item/nade, mob/living/slick_willy) + shooter = slick_willy + grenade_moved() + /// Our grenade has moved, reset var/list/bodies so we're "on top" of any mobs currently on the tile /datum/component/pellet_cloud/proc/grenade_moved() LAZYCLEARLIST(bodies) for(var/mob/living/L in get_turf(parent)) + RegisterSignal(L, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE) bodies += L /// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it /datum/component/pellet_cloud/proc/grenade_uncrossed(datum/source, atom/movable/AM) bodies -= AM +/// Our grenade or landmine or caseless shell or whatever tried deleting itself, so we intervene and nullspace it until we're done here +/datum/component/pellet_cloud/proc/nullspace_parent() + var/atom/movable/AM = parent + AM.moveToNullspace() + queued_delete = TRUE + return TRUE + +/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it +/datum/component/pellet_cloud/proc/on_target_qdel(atom/target) + UnregisterSignal(target, COMSIG_PARENT_QDELETING) + targets_hit -= target + bodies -= target + purple_hearts -= target diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index e5b3e0e529056..1d05a8b31bc78 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -287,6 +287,8 @@ sharpness = IS_SHARP custom_materials = list(/datum/material/biomass = 500) var/mob/living/carbon/human/fired_by + /// if we missed our target + var/missed = TRUE /obj/item/hardened_spike/Initialize(mapload, firedby) . = ..() @@ -294,13 +296,12 @@ addtimer(CALLBACK(src, .proc/checkembedded), 5 SECONDS) /obj/item/hardened_spike/proc/checkembedded() - if(ishuman(loc)) - var/mob/living/carbon/human/embedtest = loc - for(var/l in embedtest.bodyparts) - var/obj/item/bodypart/limb = l - if(src in limb.embedded_objects) - return limb - unembedded() + if(missed) + unembedded() + +/obj/item/hardened_spike/embedded(atom/target) + if(isbodypart(target)) + missed = FALSE /obj/item/hardened_spike/unembedded() var/turf/T = get_turf(src) diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index 146a3c3d338fe..aa622afd9bc66 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -206,7 +206,7 @@ icon_state = "moustacheg" clumsy_check = GRENADE_NONCLUMSY_FUMBLE -/obj/item/grenade/chem_grenade/teargas/moustache/prime() +/obj/item/grenade/chem_grenade/teargas/moustache/prime(mob/living/lanced_by) var/myloc = get_turf(src) . = ..() for(var/mob/living/carbon/M in view(6, myloc)) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index ed9d16a5e6ef3..d18e31e184047 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -167,7 +167,7 @@ to_chat(user, "[src] is now in [mode] mode.") -/obj/item/grenade/barrier/prime() +/obj/item/grenade/barrier/prime(mob/living/lanced_by) . = ..() new /obj/structure/barricade/security(get_turf(src.loc)) switch(mode) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 119a0893d4779..05fca65f70f4b 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -5,20 +5,25 @@ anchored = TRUE icon = 'icons/obj/items_and_weapons.dmi' icon_state = "uglymine" - var/triggered = 0 + /// We manually check to see if we've been triggered in case multiple atoms cross us in the time between the mine being triggered and it actually deleting, to avoid a race condition with multiple detonations + var/triggered = FALSE /obj/effect/mine/proc/mineEffect(mob/victim) to_chat(victim, "*click*") -/obj/effect/mine/Crossed(AM as mob|obj) +/obj/effect/mine/Crossed(atom/movable/AM) + if(triggered || !isturf(loc)) + return + . = ..() + + if(AM.movement_type & FLYING) + return + + triggermine(AM) + +/obj/effect/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir) . = ..() - if(isturf(loc)) - if(ismob(AM)) - var/mob/MM = AM - if(!(MM.movement_type & FLYING)) - triggermine(AM) - else - triggermine(AM) + triggermine() /obj/effect/mine/proc/triggermine(mob/victim) if(triggered) @@ -28,11 +33,10 @@ s.set_up(3, 1, src) s.start() mineEffect(victim) + triggered = TRUE SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED) - triggered = 1 qdel(src) - /obj/effect/mine/explosive name = "explosive mine" var/range_devastation = 0 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9588854a6d118..5724cdb795ac7 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -912,7 +912,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb dropped(M, FALSE) return ..() -/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob) +/obj/item/proc/embedded(atom/embedded_target) return /obj/item/proc/unembedded() diff --git a/code/game/objects/items/grenades/antigravity.dm b/code/game/objects/items/grenades/antigravity.dm index 313b91acd71bc..b6700599a3edb 100644 --- a/code/game/objects/items/grenades/antigravity.dm +++ b/code/game/objects/items/grenades/antigravity.dm @@ -7,7 +7,7 @@ var/forced_value = 0 var/duration = 300 -/obj/item/grenade/antigravity/prime() +/obj/item/grenade/antigravity/prime(mob/living/lanced_by) . = ..() update_mob() @@ -15,4 +15,4 @@ T.AddElement(/datum/element/forced_gravity, forced_value) addtimer(CALLBACK(T, /datum/.proc/_RemoveElement, list(forced_value)), duration) - resolve() + qdel(src) diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm index c39d9783710e8..ed798621007ee 100644 --- a/code/game/objects/items/grenades/chem_grenade.dm +++ b/code/game/objects/items/grenades/chem_grenade.dm @@ -174,7 +174,7 @@ active = TRUE addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride) -/obj/item/grenade/chem_grenade/prime() +/obj/item/grenade/chem_grenade/prime(mob/living/lanced_by) if(stage != GRENADE_READY) return @@ -213,7 +213,7 @@ ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades. threatscale = 1.1 // 10% more effective. -/obj/item/grenade/chem_grenade/large/prime() +/obj/item/grenade/chem_grenade/large/prime(mob/living/lanced_by) if(stage != GRENADE_READY) return @@ -280,7 +280,7 @@ to_chat(user, "The new value is out of bounds. Minimum spread is 5 units, maximum is 100 units.") ..() -/obj/item/grenade/chem_grenade/adv_release/prime() +/obj/item/grenade/chem_grenade/adv_release/prime(mob/living/lanced_by) if(stage != GRENADE_READY) return diff --git a/code/game/objects/items/grenades/clusterbuster.dm b/code/game/objects/items/grenades/clusterbuster.dm index 6e4687d72c324..f7409c619fd9b 100644 --- a/code/game/objects/items/grenades/clusterbuster.dm +++ b/code/game/objects/items/grenades/clusterbuster.dm @@ -14,7 +14,7 @@ var/max_spawned = 8 var/segment_chance = 35 -/obj/item/grenade/clusterbuster/prime() +/obj/item/grenade/clusterbuster/prime(mob/living/lanced_by) . = ..() update_mob() var/numspawned = rand(min_spawned,max_spawned) @@ -30,7 +30,7 @@ new payload_spawner(drop_location(), payload, numspawned)//Launches payload playsound(src, prime_sound, 75, TRUE, -3) - resolve() + qdel(src) ////////////////////// //Clusterbang segment @@ -60,10 +60,10 @@ step_away(src,loc) addtimer(CALLBACK(src, .proc/prime), rand(15,60)) -/obj/item/grenade/clusterbuster/segment/prime() +/obj/item/grenade/clusterbuster/segment/prime(mob/living/lanced_by) new payload_spawner(drop_location(), payload, rand(min_spawned,max_spawned)) playsound(src, prime_sound, 75, TRUE, -3) - resolve() + qdel(src) ////////////////////////////////// //The payload spawner effect diff --git a/code/game/objects/items/grenades/emgrenade.dm b/code/game/objects/items/grenades/emgrenade.dm index 4ed36176dc413..dde2d36f14f2b 100644 --- a/code/game/objects/items/grenades/emgrenade.dm +++ b/code/game/objects/items/grenades/emgrenade.dm @@ -4,8 +4,8 @@ icon_state = "emp" item_state = "emp" -/obj/item/grenade/empgrenade/prime() +/obj/item/grenade/empgrenade/prime(mob/living/lanced_by) . = ..() update_mob() empulse(src, 4, 10) - resolve() + qdel(src) diff --git a/code/game/objects/items/grenades/festive.dm b/code/game/objects/items/grenades/festive.dm index af68f7566a3ea..a32ffb4b560f5 100644 --- a/code/game/objects/items/grenades/festive.dm +++ b/code/game/objects/items/grenades/festive.dm @@ -108,11 +108,11 @@ obj/item/grenade/firecracker/preprime(mob/user, delayoverride, msg = TRUE, volum icon_state = initial(icon_state) + "_active" addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride) -/obj/item/grenade/firecracker/prime() +/obj/item/grenade/firecracker/prime(mob/living/lanced_by) . = ..() update_mob() var/explosion_loc = get_turf(src) - resolve() + qdel(src) explosion(explosion_loc,-1,-1,2) diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm index cbce3cff51f19..881e50d071f4d 100644 --- a/code/game/objects/items/grenades/flashbang.dm +++ b/code/game/objects/items/grenades/flashbang.dm @@ -6,7 +6,7 @@ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' var/flashbang_range = 7 //how many tiles away the mob will be stunned. -/obj/item/grenade/flashbang/prime() +/obj/item/grenade/flashbang/prime(mob/living/lanced_by) . = ..() update_mob() var/flashbang_turf = get_turf(src) @@ -17,7 +17,7 @@ new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 4, 2) for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) bang(get_turf(M), M) - resolve() + qdel(src) /obj/item/grenade/flashbang/proc/bang(turf/T , mob/living/M) if(M.stat == DEAD) //They're dead! @@ -57,15 +57,17 @@ shrapnel_type = /obj/projectile/bullet/pellet/stingball/mega shrapnel_radius = 12 -/obj/item/grenade/stingbang/prime() +/obj/item/grenade/stingbang/prime(mob/living/lanced_by) if(iscarbon(loc)) var/mob/living/carbon/C = loc var/obj/item/bodypart/B = C.get_holding_bodypart_of_item(src) if(B) + forceMove(get_turf(C)) C.visible_message("[src] goes off in [C]'s hand, blowing [C.p_their()] [B.name] to bloody shreds!", "[src] goes off in your hand, blowing your [B.name] to bloody shreds!") B.dismember() . = ..() + update_mob() var/flashbang_turf = get_turf(src) if(!flashbang_turf) @@ -75,7 +77,7 @@ new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 2, 1) for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) pop(get_turf(M), M) - resolve() + qdel(src) /obj/item/grenade/stingbang/proc/pop(turf/T , mob/living/M) if(M.stat == DEAD) //They're dead! @@ -88,7 +90,7 @@ M.Knockdown(max(100/max(1,distance), 60)) //Bang - if(!distance || loc == M || loc == M.loc) //Stop allahu akbarring rooms with this. + if(!distance || loc == M || loc == M.loc) M.Paralyze(20) M.Knockdown(200) M.soundbang_act(1, 200, 10, 15) @@ -116,10 +118,10 @@ rots++ user.changeNext_move(CLICK_CD_RAPID) -/obj/item/grenade/primer/prime() +/obj/item/grenade/primer/prime(mob/living/lanced_by) shrapnel_radius = round(rots / rots_per_mag) . = ..() - resolve() + qdel(src) /obj/item/grenade/primer/stingbang name = "rotsting" diff --git a/code/game/objects/items/grenades/ghettobomb.dm b/code/game/objects/items/grenades/ghettobomb.dm index 7eb71d05db78a..717db0f81db61 100644 --- a/code/game/objects/items/grenades/ghettobomb.dm +++ b/code/game/objects/items/grenades/ghettobomb.dm @@ -63,11 +63,11 @@ cut_overlay("improvised_grenade_filled") preprime(user, null, FALSE) -/obj/item/grenade/iedcasing/prime() //Blowing that can up +/obj/item/grenade/iedcasing/prime(mob/living/lanced_by) //Blowing that can up . = ..() update_mob() explosion(src.loc,-1,-1,2, flame_range = 4) // small explosion, plus a very large fireball. - resolve() + qdel(src) /obj/item/grenade/iedcasing/change_det_time() return //always be random. diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm index 641b0f6562729..45e09d5eb10cd 100644 --- a/code/game/objects/items/grenades/grenade.dm +++ b/code/game/objects/items/grenades/grenade.dm @@ -105,12 +105,12 @@ SEND_SIGNAL(src, COMSIG_GRENADE_ARMED, det_time, delayoverride) addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride) -/obj/item/grenade/proc/prime() +/obj/item/grenade/proc/prime(mob/living/lanced_by) if(shrapnel_type && shrapnel_radius && !shrapnel_initialized) // add a second check for adding the component in case whatever triggered the grenade went straight to prime (badminnery for example) shrapnel_initialized = TRUE AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_radius) - SEND_SIGNAL(src, COMSIG_GRENADE_PRIME) + SEND_SIGNAL(src, COMSIG_GRENADE_PRIME, lanced_by) if(ex_dev || ex_heavy || ex_light || ex_flame) explosion(loc, ex_dev, ex_heavy, ex_light, flame_range = ex_flame) @@ -170,10 +170,3 @@ . = ..() if(active) user.throw_item(target) - -/// Don't call qdel() directly on the grenade after it booms, call this instead so it can still resolve its pellet_cloud component if it has shrapnel, then the component will qdel it -/obj/item/grenade/proc/resolve() - if(shrapnel_type) - moveToNullspace() - else - qdel(src) diff --git a/code/game/objects/items/grenades/hypno.dm b/code/game/objects/items/grenades/hypno.dm index d9c954fb92d4d..b9bbc9187581c 100644 --- a/code/game/objects/items/grenades/hypno.dm +++ b/code/game/objects/items/grenades/hypno.dm @@ -7,7 +7,7 @@ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' var/flashbang_range = 7 -/obj/item/grenade/hypnotic/prime() +/obj/item/grenade/hypnotic/prime(mob/living/lanced_by) . = ..() update_mob() var/flashbang_turf = get_turf(src) @@ -18,7 +18,7 @@ new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_PURPLE, (flashbang_range + 2), 4, 2) for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) bang(get_turf(M), M) - resolve() + qdel(src) /obj/item/grenade/hypnotic/proc/bang(turf/T, mob/living/M) if(M.stat == DEAD) //They're dead! diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index a1b169189d3f4..9abf434809c0e 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -41,7 +41,7 @@ else return ..() -/obj/item/grenade/c4/prime() +/obj/item/grenade/c4/prime(mob/living/lanced_by) if(QDELETED(src)) return @@ -61,7 +61,7 @@ explosion(get_step(T, aim_dir), boom_sizes[1], boom_sizes[2], boom_sizes[3]) else explosion(location, boom_sizes[1], boom_sizes[2], boom_sizes[3]) - resolve() + qdel(src) //assembly stuff /obj/item/grenade/c4/receive_signal() @@ -149,7 +149,7 @@ shout_syndicate_crap(user) explosion(user,0,2,0) //Cheap explosion imitation because putting prime() here causes runtimes user.gib(1, 1) - resolve() + qdel(src) // X4 is an upgraded directional variant of c4 which is relatively safe to be standing next to. And much less safe to be standing on the other side of. // C4 is intended to be used for infiltration, and destroying tech. X4 is intended to be used for heavy breaching and tight spaces. diff --git a/code/game/objects/items/grenades/smokebomb.dm b/code/game/objects/items/grenades/smokebomb.dm index 590312772efca..d42d7ccb5acdb 100644 --- a/code/game/objects/items/grenades/smokebomb.dm +++ b/code/game/objects/items/grenades/smokebomb.dm @@ -19,7 +19,7 @@ desc = "The word '[pick(bruh_moment)]' is scribbled on it in crayon." ///Here we generate some smoke and also damage blobs??? for some reason. Honestly not sure why we do that. -/obj/item/grenade/smokebomb/prime() +/obj/item/grenade/smokebomb/prime(mob/living/lanced_by) . = ..() update_mob() playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3) @@ -30,4 +30,4 @@ for(var/obj/structure/blob/B in view(8,src)) var/damage = round(30/(get_dist(B,src)+1)) B.take_damage(damage, BURN, "melee", 0) - resolve() + qdel(src) diff --git a/code/game/objects/items/grenades/spawnergrenade.dm b/code/game/objects/items/grenades/spawnergrenade.dm index dfa0b6b63d18c..fdcfa2f61ec22 100644 --- a/code/game/objects/items/grenades/spawnergrenade.dm +++ b/code/game/objects/items/grenades/spawnergrenade.dm @@ -7,7 +7,7 @@ var/spawner_type = null // must be an object path var/deliveryamt = 1 // amount of type to deliver -/obj/item/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it. +/obj/item/grenade/spawnergrenade/prime(mob/living/lanced_by) // Prime now just handles the two loops that query for people in lockers and people who can see it. . = ..() update_mob() if(spawner_type && deliveryamt) @@ -21,7 +21,7 @@ var/list/spawned = spawn_and_random_walk(spawner_type, T, deliveryamt, walk_chance=50, admin_spawn=((flags_1 & ADMIN_SPAWNED_1) ? TRUE : FALSE)) afterspawn(spawned) - resolve() + qdel(src) /obj/item/grenade/spawnergrenade/proc/afterspawn(list/mob/spawned) return diff --git a/code/game/objects/items/grenades/syndieminibomb.dm b/code/game/objects/items/grenades/syndieminibomb.dm index 446b27d5a404e..940cecb46e5e2 100644 --- a/code/game/objects/items/grenades/syndieminibomb.dm +++ b/code/game/objects/items/grenades/syndieminibomb.dm @@ -9,10 +9,10 @@ ex_light = 4 ex_flame = 2 -/obj/item/grenade/syndieminibomb/prime() +/obj/item/grenade/syndieminibomb/prime(mob/living/lanced_by) . = ..() update_mob() - resolve() + qdel(src) /obj/item/grenade/syndieminibomb/concussion name = "HE Grenade" @@ -38,10 +38,10 @@ shrapnel_type = /obj/projectile/bullet/shrapnel/mega shrapnel_radius = 12 -/obj/item/grenade/frag/prime() +/obj/item/grenade/frag/prime(mob/living/lanced_by) . = ..() update_mob() - resolve() + qdel(src) /obj/item/grenade/gluon desc = "An advanced grenade that releases a harmful stream of gluons inducing radiation in those nearby. These gluon streams will also make victims feel exhausted, and induce shivering. This extreme coldness will also likely wet any nearby floors." @@ -53,7 +53,7 @@ var/rad_damage = 350 var/stamina_damage = 30 -/obj/item/grenade/gluon/prime() +/obj/item/grenade/gluon/prime(mob/living/lanced_by) . = ..() update_mob() playsound(loc, 'sound/effects/empulse.ogg', 50, TRUE) @@ -65,4 +65,4 @@ for(var/mob/living/carbon/L in T) L.adjustStaminaLoss(stamina_damage) L.adjust_bodytemperature(-230) - resolve() + qdel(src) diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm index 5936a45f63219..f9d9e294fb790 100644 --- a/code/game/objects/items/spear.dm +++ b/code/game/objects/items/spear.dm @@ -122,7 +122,7 @@ if(wielded) user.say("[war_cry]", forced="spear warcry") explosive.forceMove(AM) - explosive.prime() + explosive.prime(lanced_by=user) qdel(src) //GREY TIDE diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 170154fcd7db5..76a1885398452 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -252,7 +252,7 @@ /datum/supply_pack/security group = "Security" - access_any = ACCESS_FORENSICS_LOCKERS //| ACCESS_SECURITY + access = ACCESS_SECURITY crate_type = /obj/structure/closet/crate/secure/gear /datum/supply_pack/security/ammo diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm index 5ccc1c0ae773d..9294cd6aae07c 100644 --- a/code/modules/hydroponics/grown/citrus.dm +++ b/code/modules/hydroponics/grown/citrus.dm @@ -135,7 +135,7 @@ /obj/item/reagent_containers/food/snacks/grown/firelemon/ex_act(severity) qdel(src) //Ensuring that it's deleted by its own explosion -/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime() +/obj/item/reagent_containers/food/snacks/grown/firelemon/proc/prime(mob/living/lanced_by) switch(seed.potency) //Combustible lemons are alot like IEDs, lots of flame, very little bang. if(0 to 30) update_mob() diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm index 4db4b0fbf986d..8d6704c92e827 100644 --- a/code/modules/hydroponics/grown/misc.dm +++ b/code/modules/hydroponics/grown/misc.dm @@ -228,7 +228,7 @@ /obj/item/reagent_containers/food/snacks/grown/cherry_bomb/ex_act(severity) qdel(src) //Ensuring that it's deleted by its own explosion. Also prevents mass chain reaction with piles of cherry bombs -/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime() +/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime(mob/living/lanced_by) icon_state = "cherry_bomb_lit" playsound(src, 'sound/effects/fuse.ogg', seed.potency, FALSE) reagents.chem_temp = 1000 //Sets off the gunpowder diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index efa00c25414ea..cd140faac95c8 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -1,5 +1,5 @@ -/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null, silent=FALSE, armour_penetration, penetrated_text) +/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null, armour_penetration, penetrated_text, silent=FALSE) var/armor = getarmor(def_zone, attack_flag) if(armor <= 0)