Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Crushers and PKAs: Coop Upgrades #2909

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion code/datums/status_effects/_status_effect_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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!)
Expand Down
8 changes: 4 additions & 4 deletions code/datums/status_effects/debuffs/debuffs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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))
186 changes: 101 additions & 85 deletions code/modules/mining/equipment/kinetic_crusher.dm
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
/*********************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"
inhand_icon_state = "crusher0"
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
Expand All @@ -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

Expand All @@ -54,75 +62,81 @@
. = ..()
. += span_notice("Mark a large creature with a destabilizing force with right-click, then hit them in melee to do <b>[force + detonation_damage]</b> damage.")
. += span_notice("Does <b>[force + detonation_damage + backstab_bonus]</b> damage if the target is backstabbed, instead of <b>[force + detonation_damage]</b>.")
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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -350,13 +366,13 @@
return "mark detonation to do <b>[bonus_value]</b> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading