From a97599ced190eb7d351abef44d580fbe53c50ae8 Mon Sep 17 00:00:00 2001
From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Date: Wed, 13 Mar 2024 20:41:56 -0400
Subject: [PATCH] (upstream PR 81940)
---
.../status_effects/_status_effect_helpers.dm | 13 +-
code/datums/status_effects/debuffs/debuffs.dm | 8 +-
.../orders/order_items/mining/order_pka.dm | 8 +
.../mining/equipment/kinetic_crusher.dm | 186 ++++++++++--------
.../hostile/megafauna/hierophant.dm | 1 +
.../guns/energy/kinetic_accelerator.dm | 77 +++++---
code/modules/projectiles/projectile.dm | 2 +-
7 files changed, 176 insertions(+), 119 deletions(-)
diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm
index 0ee95220061..f887afd9142 100644
--- a/code/datums/status_effects/_status_effect_helpers.dm
+++ b/code/datums/status_effects/_status_effect_helpers.dm
@@ -56,7 +56,7 @@
. = FALSE
for(var/datum/status_effect/existing_effect as anything in status_effects)
- if(existing_effect.id == initial(removed_effect.id) && existing_effect.before_remove(arguments))
+ if(existing_effect.id == initial(removed_effect.id) && existing_effect.before_remove(arglist(arguments)))
qdel(existing_effect)
. = TRUE
@@ -84,6 +84,17 @@
return null
+///Gets every status effect of an ID and returns all of them in a list, rather than the individual 'has_status_effect'
+/mob/living/proc/get_all_status_effect_of_id(datum/status_effect/checked_effect)
+ RETURN_TYPE(/list/datum/status_effect)
+
+ var/list/all_effects_of_type = list()
+ for(var/datum/status_effect/present_effect as anything in status_effects)
+ if(present_effect.id == initial(checked_effect.id))
+ all_effects_of_type += present_effect
+
+ return all_effects_of_type
+
/**
* Checks if this mob has a status effect that shares the passed effect's ID
* and has the passed sources are in its list of sources (ONLY works for grouped efects!)
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
index 685ca49011a..f03aa98c6cb 100644
--- a/code/datums/status_effects/debuffs/debuffs.dm
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -343,7 +343,7 @@
/datum/status_effect/crusher_mark
id = "crusher_mark"
duration = 300 //if you leave for 30 seconds you lose the mark, deal with it
- status_type = STATUS_EFFECT_REPLACE
+ status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
var/mutable_appearance/marked_underlay
var/obj/item/kinetic_crusher/hammer_synced
@@ -370,9 +370,9 @@
QDEL_NULL(marked_underlay)
return ..()
-/datum/status_effect/crusher_mark/be_replaced()
- owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
- ..()
+//we will only clear ourselves if the crusher is the one that owns us.
+/datum/status_effect/crusher_mark/before_remove(obj/item/kinetic_crusher/attacking_hammer)
+ return (attacking_hammer == hammer_synced)
/datum/status_effect/stacking/saw_bleed
id = "saw_bleed"
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_pka.dm b/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
index 7ba37721e36..107c4954d3a 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_pka.dm
@@ -39,4 +39,12 @@
/datum/orderable_item/accelerator/minebot_passthrough
item_path = /obj/item/borg/upgrade/modkit/minebot_passthrough
+<<<<<<< HEAD
cost_per_order = 1000
+=======
+ cost_per_order = 800
+
+/datum/orderable_item/accelerator/friendly_fire
+ item_path = /obj/item/borg/upgrade/modkit/human_passthrough
+ cost_per_order = 750
+>>>>>>> 405d369694e (Crushers and PKAs: Coop Upgrades (#81940))
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 6a6df5452bd..92ded187109 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -1,4 +1,10 @@
-/*********************Mining Hammer****************/
+/**
+ * Kinetic Crusher
+ *
+ * Lavaland's "Hard Mode" option for players, requiring melee attacks (backstabs even better),
+ * but allowing you to upgrade it with trophies gained from fighting lavaland monsters, making it
+ * a good tradeoff and a decent playstyle.
+ */
/obj/item/kinetic_crusher
icon = 'icons/obj/mining.dmi'
icon_state = "crusher"
@@ -6,8 +12,9 @@
lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi'
name = "proto-kinetic crusher"
- desc = "An early design of the proto-kinetic accelerator, it is little more than a combination of various mining tools cobbled together, forming a high-tech club. \
- While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna."
+ desc = "An early design of the proto-kinetic accelerator, it is little more than a combination of various mining tools cobbled together, \
+ forming a high-tech club. While it is an effective mining tool, it did little to aid any but the most skilled and/or \
+ suicidal miners against local fauna."
force = 0 //You can't hit stuff unless wielded
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
@@ -26,9 +33,10 @@
light_power = 1.2
light_color = "#ffff66"
light_on = FALSE
- var/list/trophies = list()
+ ///List of all crusher trophies attached to this.
+ var/list/obj/item/crusher_trophy/trophies = list()
var/charged = TRUE
- var/charge_time = 15
+ var/charge_time = 1.5 SECONDS
var/detonation_damage = 50
var/backstab_bonus = 30
@@ -54,75 +62,81 @@
. = ..()
. += span_notice("Mark a large creature with a destabilizing force with right-click, then hit them in melee to do [force + detonation_damage] damage.")
. += span_notice("Does [force + detonation_damage + backstab_bonus] damage if the target is backstabbed, instead of [force + detonation_damage].")
- for(var/t in trophies)
- var/obj/item/crusher_trophy/T = t
- . += span_notice("It has \a [T] attached, which causes [T.effect_desc()].")
-
-/obj/item/kinetic_crusher/attackby(obj/item/I, mob/living/user)
- if(I.tool_behaviour == TOOL_CROWBAR)
- if(LAZYLEN(trophies))
- to_chat(user, span_notice("You remove [src]'s trophies."))
- I.play_tool_sound(src)
- for(var/t in trophies)
- var/obj/item/crusher_trophy/T = t
- T.remove_from(src, user)
- else
- to_chat(user, span_warning("There are no trophies on [src]."))
- else if(istype(I, /obj/item/crusher_trophy))
- var/obj/item/crusher_trophy/T = I
- T.add_to(src, user)
- else
- return ..()
+ for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
+ . += span_notice("It has \a [crusher_trophy] attached, which causes [crusher_trophy.effect_desc()].")
+
+/obj/item/kinetic_crusher/attackby(obj/item/attacking_item, mob/user, params)
+ if(istype(attacking_item, /obj/item/crusher_trophy))
+ var/obj/item/crusher_trophy/crusher_trophy = attacking_item
+ crusher_trophy.add_to(src, user)
+ return
+ return ..()
+
+/obj/item/kinetic_crusher/crowbar_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(!LAZYLEN(trophies))
+ user.balloon_alert(user, "no trophies!")
+ return ITEM_INTERACT_BLOCKING
+ user.balloon_alert(user, "trophies removed")
+ tool.play_tool_sound(src)
+ for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
+ crusher_trophy.remove_from(src, user)
+ return ITEM_INTERACT_SUCCESS
/obj/item/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
to_chat(user, span_warning("[src] is too heavy to use with one hand! You fumble and drop everything."))
user.drop_all_held_items()
return
- var/datum/status_effect/crusher_damage/C = target.has_status_effect(/datum/status_effect/crusher_damage)
- if(!C)
- C = target.apply_status_effect(/datum/status_effect/crusher_damage)
+ var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage)
+ if(!crusher_damage_effect)
+ crusher_damage_effect = target.apply_status_effect(/datum/status_effect/crusher_damage)
var/target_health = target.health
..()
- for(var/t in trophies)
+ for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
if(!QDELETED(target))
- var/obj/item/crusher_trophy/T = t
- T.on_melee_hit(target, user)
- if(!QDELETED(C) && !QDELETED(target))
- C.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did
-
-/obj/item/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams)
- if(proximity_flag && isliving(target))
- var/mob/living/L = target
- var/datum/status_effect/crusher_mark/CM = L.has_status_effect(/datum/status_effect/crusher_mark)
- if(!CM || CM.hammer_synced != src || !L.remove_status_effect(/datum/status_effect/crusher_mark))
- return
- var/datum/status_effect/crusher_damage/C = L.has_status_effect(/datum/status_effect/crusher_damage)
- if(!C)
- C = L.apply_status_effect(/datum/status_effect/crusher_damage)
- var/target_health = L.health
- for(var/t in trophies)
- var/obj/item/crusher_trophy/T = t
- T.on_mark_detonation(target, user)
- if(!QDELETED(L))
- if(!QDELETED(C))
- C.total_damage += target_health - L.health //we did some damage, but let's not assume how much we did
- new /obj/effect/temp_visual/kinetic_blast(get_turf(L))
- var/backstabbed = FALSE
- var/combined_damage = detonation_damage
- var/backstab_dir = get_dir(user, L)
- var/def_check = L.getarmor(type = BOMB)
- if((user.dir & backstab_dir) && (L.dir & backstab_dir))
- backstabbed = TRUE
- combined_damage += backstab_bonus
- playsound(user, 'sound/weapons/kinetic_accel.ogg', 100, TRUE) //Seriously who spelled it wrong
-
- if(!QDELETED(C))
- C.total_damage += combined_damage
-
-
- SEND_SIGNAL(user, COMSIG_LIVING_CRUSHER_DETONATE, L, src, backstabbed)
- L.apply_damage(combined_damage, BRUTE, blocked = def_check)
+ crusher_trophy.on_melee_hit(target, user)
+ if(!QDELETED(crusher_damage_effect) && !QDELETED(target))
+ crusher_damage_effect.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did
+
+/obj/item/kinetic_crusher/afterattack(mob/living/target, mob/living/user, proximity_flag, clickparams)
+ . = ..()
+ if(.)
+ return
+ if(!proximity_flag || !isliving(target))
+ return
+ var/valid_crusher_attack = FALSE
+ for(var/datum/status_effect/crusher_mark/crusher_mark_effect as anything in target.get_all_status_effect_of_id(/datum/status_effect/crusher_mark))
+ //this will erase ALL crusher marks, not only ones by you.
+ if(crusher_mark_effect.hammer_synced != src || !target.remove_status_effect(/datum/status_effect/crusher_mark, src))
+ continue
+ valid_crusher_attack = TRUE
+ break
+ if(!valid_crusher_attack)
+ return
+ var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage)
+ if(!crusher_damage_effect)
+ crusher_damage_effect = target.apply_status_effect(/datum/status_effect/crusher_damage)
+ var/target_health = target.health
+ for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
+ crusher_trophy.on_mark_detonation(target, user)
+ if(QDELETED(target))
+ return
+ if(!QDELETED(crusher_damage_effect))
+ crusher_damage_effect.total_damage += target_health - target.health //we did some damage, but let's not assume how much we did
+ new /obj/effect/temp_visual/kinetic_blast(get_turf(target))
+ var/backstabbed = FALSE
+ var/combined_damage = detonation_damage
+ var/backstab_dir = get_dir(user, target)
+ var/def_check = target.getarmor(type = BOMB)
+ if((user.dir & backstab_dir) && (target.dir & backstab_dir))
+ backstabbed = TRUE
+ combined_damage += backstab_bonus
+ playsound(user, 'sound/weapons/kinetic_accel.ogg', 100, TRUE) //Seriously who spelled it wrong
+ if(!QDELETED(crusher_damage_effect))
+ crusher_damage_effect.total_damage += combined_damage
+ SEND_SIGNAL(user, COMSIG_LIVING_CRUSHER_DETONATE, target, src, backstabbed)
+ target.apply_damage(combined_damage, BRUTE, blocked = def_check)
/obj/item/kinetic_crusher/attack_secondary(atom/target, mob/living/user, clickparams)
return SECONDARY_ATTACK_CONTINUE_CHAIN
@@ -155,9 +169,9 @@
destabilizer.fire()
charged = FALSE
update_appearance()
- addtimer(CALLBACK(src, PROC_REF(Recharge)), charge_time)
+ addtimer(CALLBACK(src, PROC_REF(recharge_projectile)), charge_time)
-/obj/item/kinetic_crusher/proc/Recharge()
+/obj/item/kinetic_crusher/proc/recharge_projectile()
if(!charged)
charged = TRUE
update_appearance()
@@ -197,6 +211,7 @@
armor_flag = BOMB
range = 6
log_override = TRUE
+ ///The crusher that's firing this projectile.
var/obj/item/kinetic_crusher/hammer_synced
/obj/projectile/destabilizer/Destroy()
@@ -205,19 +220,21 @@
/obj/projectile/destabilizer/on_hit(atom/target, blocked = 0, pierce_hit)
if(isliving(target))
- var/mob/living/L = target
- var/had_effect = (L.has_status_effect(/datum/status_effect/crusher_mark)) //used as a boolean
- var/datum/status_effect/crusher_mark/CM = L.apply_status_effect(/datum/status_effect/crusher_mark, hammer_synced)
- if(hammer_synced)
- for(var/t in hammer_synced.trophies)
- var/obj/item/crusher_trophy/T = t
- T.on_mark_application(target, CM, had_effect)
+ var/mob/living/living_target = target
+ var/has_mark_from_this_crusher = FALSE
+ for(var/datum/status_effect/crusher_mark/crusher_mark_effect as anything in living_target.get_all_status_effect_of_id(/datum/status_effect/crusher_mark))
+ if(crusher_mark_effect.hammer_synced != hammer_synced)
+ continue
+ has_mark_from_this_crusher = TRUE
+ break
+ if(!has_mark_from_this_crusher)
+ living_target.apply_status_effect(/datum/status_effect/crusher_mark, hammer_synced)
var/target_turf = get_turf(target)
if(ismineralturf(target_turf))
- var/turf/closed/mineral/M = target_turf
- new /obj/effect/temp_visual/kinetic_blast(M)
- M.gets_drilled(firer)
- ..()
+ var/turf/closed/mineral/hit_mineral = target_turf
+ new /obj/effect/temp_visual/kinetic_blast(hit_mineral)
+ hit_mineral.gets_drilled(firer)
+ return ..()
//trophies
/obj/item/crusher_trophy
@@ -258,7 +275,6 @@
/obj/item/crusher_trophy/proc/on_melee_hit(mob/living/target, mob/living/user) //the target and the user
/obj/item/crusher_trophy/proc/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user) //the projectile fired and the user
-/obj/item/crusher_trophy/proc/on_mark_application(mob/living/target, datum/status_effect/crusher_mark/mark, had_mark) //the target, the mark applied, and if the target had a mark before
/obj/item/crusher_trophy/proc/on_mark_detonation(mob/living/target, mob/living/user) //the target and the user
//watcher
@@ -350,13 +366,13 @@
return "mark detonation to do [bonus_value] damage to nearby creatures and push them back"
/obj/item/crusher_trophy/tail_spike/on_mark_detonation(mob/living/target, mob/living/user)
- for(var/mob/living/L in oview(2, user))
- if(L.stat == DEAD)
+ for(var/mob/living/living_target in oview(2, user))
+ if(user.faction_check_atom(living_target) || living_target.stat == DEAD)
continue
- playsound(L, 'sound/magic/fireball.ogg', 20, TRUE)
- new /obj/effect/temp_visual/fire(L.loc)
- addtimer(CALLBACK(src, PROC_REF(pushback), L, user), 1) //no free backstabs, we push AFTER module stuff is done
- L.adjustFireLoss(bonus_value, forced = TRUE)
+ playsound(living_target, 'sound/magic/fireball.ogg', 20, TRUE)
+ new /obj/effect/temp_visual/fire(living_target.loc)
+ addtimer(CALLBACK(src, PROC_REF(pushback), living_target, user), 1) //no free backstabs, we push AFTER module stuff is done
+ living_target.adjustFireLoss(bonus_value, forced = TRUE)
/obj/item/crusher_trophy/tail_spike/proc/pushback(mob/living/target, mob/living/user)
if(!QDELETED(target) && !QDELETED(user) && (!target.anchored || ismegafauna(target))) //megafauna will always be pushed
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 375d4993cfd..d7fceecf053 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -618,6 +618,7 @@ Difficulty: Hard
moving--
sleep(speed)
targetturf = get_turf(target)
+
/obj/effect/temp_visual/hierophant/chaser/proc/make_blast()
var/obj/effect/temp_visual/hierophant/blast/damaging/B = new(loc, caster, friendly_fire_check)
B.damage = damage
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 71d28e70a5e..ba6b5d89223 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -11,11 +11,13 @@
can_bayonet = TRUE
knife_x_offset = 20
knife_y_offset = 12
- var/mob/holder
- var/max_mod_capacity = 100
- var/list/modkits = list()
gun_flags = NOT_A_REAL_GUN
-
+ ///List of all mobs that projectiles fired from this gun will ignore.
+ var/list/ignored_mob_types
+ ///List of all modkits currently in the kinetic accelerator.
+ var/list/obj/item/borg/upgrade/modkit/modkits = list()
+ ///The max capacity of modkits the PKA can have installed at once.
+ var/max_mod_capacity = 100
/obj/item/gun/energy/recharge/kinetic_accelerator/Initialize(mapload)
. = ..()
@@ -68,18 +70,16 @@
if(max_mod_capacity)
. += "[get_remaining_mod_capacity()]% mod capacity remaining."
. += span_info("You can use a crowbar to remove all modules or right-click with an empty hand to remove a specific one.")
- for(var/A in modkits)
- var/obj/item/borg/upgrade/modkit/M = A
- . += span_notice("There is \a [M] installed, using [M.cost]% capacity.")
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in modkits)
+ . += span_notice("There is \a [modkit_upgrade] installed, using [modkit_upgrade.cost]% capacity.")
/obj/item/gun/energy/recharge/kinetic_accelerator/crowbar_act(mob/living/user, obj/item/I)
. = TRUE
if(modkits.len)
to_chat(user, span_notice("You pry all the modifications out."))
I.play_tool_sound(src, 100)
- for(var/a in modkits)
- var/obj/item/borg/upgrade/modkit/M = a
- M.forceMove(drop_location()) //uninstallation handled in Exited(), or /mob/living/silicon/robot/remove_from_upgrades() for borgs
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in modkits)
+ modkit_upgrade.forceMove(drop_location()) //uninstallation handled in Exited(), or /mob/living/silicon/robot/remove_from_upgrades() for borgs
else
to_chat(user, span_notice("There are no modifications currently installed."))
@@ -138,16 +138,14 @@
/obj/item/gun/energy/recharge/kinetic_accelerator/proc/get_remaining_mod_capacity()
var/current_capacity_used = 0
- for(var/A in modkits)
- var/obj/item/borg/upgrade/modkit/M = A
- current_capacity_used += M.cost
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in modkits)
+ current_capacity_used += modkit_upgrade.cost
return max_mod_capacity - current_capacity_used
-/obj/item/gun/energy/recharge/kinetic_accelerator/proc/modify_projectile(obj/projectile/kinetic/K)
- K.kinetic_gun = src //do something special on-hit, easy!
- for(var/A in modkits)
- var/obj/item/borg/upgrade/modkit/M = A
- M.modify_projectile(K)
+/obj/item/gun/energy/recharge/kinetic_accelerator/proc/modify_projectile(obj/projectile/kinetic/kinetic_projectile)
+ kinetic_projectile.kinetic_gun = src //do something special on-hit, easy!
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in modkits)
+ modkit_upgrade.modify_projectile(kinetic_projectile)
/obj/item/gun/energy/recharge/kinetic_accelerator/cyborg
icon_state = "kineticgun_b"
@@ -193,13 +191,14 @@
return ..()
/obj/projectile/kinetic/prehit_pierce(atom/target)
+ if(is_type_in_typecache(target, kinetic_gun.ignored_mob_types))
+ return PROJECTILE_PIERCE_PHASE
. = ..()
if(. == PROJECTILE_PIERCE_PHASE)
return
if(kinetic_gun)
- var/list/mods = kinetic_gun.modkits
- for(var/obj/item/borg/upgrade/modkit/modkit in mods)
- modkit.projectile_prehit(src, target, kinetic_gun)
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in kinetic_gun.modkits)
+ modkit_upgrade.projectile_prehit(src, target, kinetic_gun)
if(!pressure_decrease_active && !lavaland_equipment_pressure_check(get_turf(target)))
name = "weakened [name]"
damage = damage * pressure_decrease
@@ -219,10 +218,10 @@
target_turf = get_turf(src)
if(kinetic_gun) //hopefully whoever shot this was not very, very unfortunate.
var/list/mods = kinetic_gun.modkits
- for(var/obj/item/borg/upgrade/modkit/M in mods)
- M.projectile_strike_predamage(src, target_turf, target, kinetic_gun)
- for(var/obj/item/borg/upgrade/modkit/M in mods)
- M.projectile_strike(src, target_turf, target, kinetic_gun)
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in mods)
+ modkit_upgrade.projectile_strike_predamage(src, target_turf, target, kinetic_gun)
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in mods)
+ modkit_upgrade.projectile_strike(src, target_turf, target, kinetic_gun)
if(ismineralturf(target_turf))
var/turf/closed/mineral/M = target_turf
M.gets_drilled(firer, TRUE)
@@ -284,9 +283,8 @@
return FALSE
if(denied_type)
var/number_of_denied = 0
- for(var/A in KA.modkits)
- var/obj/item/borg/upgrade/modkit/M = A
- if(istype(M, denied_type))
+ for(var/obj/item/borg/upgrade/modkit/modkit_upgrade as anything in KA.modkits)
+ if(istype(modkit_upgrade, denied_type))
number_of_denied++
if(number_of_denied >= maximum_of_type)
. = FALSE
@@ -434,8 +432,31 @@
/obj/item/borg/upgrade/modkit/minebot_passthrough
name = "minebot passthrough"
desc = "Causes kinetic accelerator shots to pass through minebots."
+ denied_type = /obj/item/borg/upgrade/modkit/human_passthrough
+ cost = 0
+
+/obj/item/borg/upgrade/modkit/minebot_passthrough/install(obj/item/gun/energy/recharge/kinetic_accelerator/KA, mob/user, transfer_to_loc)
+ . = ..()
+ LAZYADD(KA.ignored_mob_types, typecacheof(/mob/living/basic/mining_drone))
+
+/obj/item/borg/upgrade/modkit/minebot_passthrough/uninstall(obj/item/gun/energy/recharge/kinetic_accelerator/KA)
+ . = ..()
+ LAZYREMOVE(KA.ignored_mob_types, typecacheof(/mob/living/basic/mining_drone))
+
+/obj/item/borg/upgrade/modkit/human_passthrough
+ name = "human passthrough"
+ desc = "Causes kinetic accelerator shots to pass through humans, good for preventing friendly fire."
+ denied_type = /obj/item/borg/upgrade/modkit/minebot_passthrough
cost = 0
+/obj/item/borg/upgrade/modkit/human_passthrough/install(obj/item/gun/energy/recharge/kinetic_accelerator/KA, mob/user, transfer_to_loc)
+ . = ..()
+ LAZYADD(KA.ignored_mob_types, typecacheof(/mob/living/carbon/human))
+
+/obj/item/borg/upgrade/modkit/human_passthrough/uninstall(obj/item/gun/energy/recharge/kinetic_accelerator/KA)
+ . = ..()
+ LAZYREMOVE(KA.ignored_mob_types, typecacheof(/mob/living/carbon/human))
+
//Tendril-unique modules
/obj/item/borg/upgrade/modkit/cooldown/repeater
name = "rapid repeater"
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index d1dd5364477..60adbfed24d 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -707,7 +707,7 @@
if(ismovable(A))
var/atom/movable/AM = A
if(AM.throwing)
- return (projectile_phasing & LETPASSTHROW)? PROJECTILE_PIERCE_PHASE : ((projectile_piercing & LETPASSTHROW)? PROJECTILE_PIERCE_HIT : PROJECTILE_PIERCE_NONE)
+ return (projectile_phasing & LETPASSTHROW) ? PROJECTILE_PIERCE_PHASE : ((projectile_piercing & LETPASSTHROW)? PROJECTILE_PIERCE_HIT : PROJECTILE_PIERCE_NONE)
return PROJECTILE_PIERCE_NONE
/obj/projectile/proc/check_ricochet(atom/A)