Buffs the proto-kinetic crusher and cleans up the code a little bit (#88171)

## About The Pull Request
Buffs the crusher:
- Mining with the crusher gives mining XP
- If you mine with the crusher, your mining level will reduce the charge
time (more skilled miners can mine faster)
- Shooting the kinetic blast (crusher right click) no longer puts your
click on cooldown

For the mark, it now has a delay of 0.8 seconds. So even though the
click delay from shooting the mark is gone, you'll still have to wait
for it to be ready to detonate it.

Adds code support for the crusher projectile to have effects on hitting
a mob/mineral
- Buffs the bileworm trophy to give it AOE mining radius

Reorganizes all the crusher code + trophies to be in its own folder +
documents it somewhat
## Why It's Good For The Game
Crusher code is a bit outdated so I wanted to clean it up a bit while I
gave it the buffs I wanted.
I feel like it can afford to be better as a mining tool so I gave it
access to mining XP. I also gave it AOE mining from the bileworm trophy
so it can keep up with the other mining tools (pka/pc)
## Changelog
🆑
add: Bileworm crusher trophy now gives you AOE mining
balance: The pk crusher no longer has click delay after shooting the
projectile
balance: The pk crusher gives mining XP when it mines rocks
balance: the pk crusher charges faster when you mine rocks based on your
skill as a miner
code: cleaned up some of the kinetic crusher code
/🆑
This commit is contained in:
Xander3359
2024-12-26 11:11:49 +01:00
committed by GitHub
parent 6c03bf8501
commit e8877f792c
17 changed files with 970 additions and 855 deletions
@@ -1,631 +0,0 @@
/**
* 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
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."
icon = 'icons/obj/mining.dmi'
icon_state = "crusher"
inhand_icon_state = "crusher0"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi'
resistance_flags = FIRE_PROOF
force = 0 //You can't hit stuff unless wielded
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
throwforce = 5
throw_speed = 4
armour_penetration = 10
custom_materials = list(/datum/material/iron=HALF_SHEET_MATERIAL_AMOUNT*1.15, /datum/material/glass=HALF_SHEET_MATERIAL_AMOUNT*2.075)
hitsound = 'sound/items/weapons/bladeslice.ogg'
attack_verb_continuous = list("smashes", "crushes", "cleaves", "chops", "pulps")
attack_verb_simple = list("smash", "crush", "cleave", "chop", "pulp")
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/toggle_light)
obj_flags = UNIQUE_RENAME
light_system = OVERLAY_LIGHT
light_range = 5
light_power = 1.2
light_color = "#ffff66"
light_on = FALSE
///List of all crusher trophies attached to this.
var/list/obj/item/crusher_trophy/trophies = list()
var/charged = TRUE
var/charge_time = 1.5 SECONDS
var/detonation_damage = 50
var/backstab_bonus = 30
var/current_inhand_icon_state = "crusher" //variable used by retool kits when changing the crusher's appearance
var/projectile_icon = "pulse1" //variable used by retool kits when changing the crusher's projectile sprite
/obj/item/kinetic_crusher/Initialize(mapload)
. = ..()
AddComponent(/datum/component/butchering, \
speed = 6 SECONDS, \
effectiveness = 110, \
)
//technically it's huge and bulky, but this provides an incentive to use it
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20)
register_context()
/obj/item/kinetic_crusher/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(!held_item)
context[SCREENTIP_CONTEXT_RMB] = "Detach trophy"
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item) && held_item.tool_behaviour == TOOL_CROWBAR)
context[SCREENTIP_CONTEXT_LMB] = "Detach all trophies"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/kinetic_crusher/Destroy()
QDEL_LIST(trophies)
return ..()
/obj/item/kinetic_crusher/Exited(atom/movable/gone, direction)
. = ..()
trophies -= gone
/obj/item/kinetic_crusher/examine(mob/living/user)
. = ..()
. += 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/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
// adapted from kinetic accelerator attack_hand_secodary
/obj/item/kinetic_crusher/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!LAZYLEN(trophies))
return SECONDARY_ATTACK_CONTINUE_CHAIN
var/list/display_names = list()
var/list/items = list()
for(var/trophies_length in 1 to length(trophies))
var/obj/item/crusher_trophy/trophy = trophies[trophies_length]
display_names[trophy.name] = REF(trophy)
var/image/item_image = image(icon = trophy.icon, icon_state = trophy.icon_state)
if(length(trophy.overlays))
item_image.copy_overlays(trophy)
items["[trophy.name]"] = item_image
var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 36, require_near = TRUE, tooltips = TRUE)
if(!pick)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/trophy_reference = display_names[pick]
var/obj/item/crusher_trophy/trophy_to_remove = locate(trophy_reference) in trophies
if(!istype(trophy_to_remove))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
trophy_to_remove.remove_from(src, user)
if(!user.put_in_hands(trophy_to_remove))
trophy_to_remove.forceMove(drop_location())
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/kinetic_crusher/proc/check_menu(mob/living/carbon/human/user)
if(!istype(user))
return FALSE
if(user.incapacitated)
return FALSE
return TRUE
/obj/item/kinetic_crusher/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return TRUE
if(!HAS_TRAIT(src, TRAIT_WIELDED))
user.balloon_alert(user, "must be wielded!")
return TRUE
return .
/obj/item/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
target.apply_status_effect(/datum/status_effect/crusher_damage)
return ..()
/obj/item/kinetic_crusher/afterattack(mob/living/target, mob/living/user, clickparams)
if(!isliving(target))
return
// Melee effect
for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
crusher_trophy.on_melee_hit(target, user)
if(QDELETED(target))
return
var/datum/status_effect/crusher_mark/mark = target.has_status_effect(/datum/status_effect/crusher_mark)
var/boosted_mark = mark?.boosted
if(!target.remove_status_effect(mark))
return
// Detonation effect
var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage) || 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/def_check = target.getarmor(type = BOMB)
// Backstab bonus
if(check_behind(user, target) || boosted_mark)
backstabbed = TRUE
combined_damage += backstab_bonus
playsound(user, 'sound/items/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/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
balloon_alert(user, "wield it first!")
return ITEM_INTERACT_BLOCKING
if(interacting_with == user)
balloon_alert(user, "can't aim at yourself!")
return ITEM_INTERACT_BLOCKING
fire_kinetic_blast(interacting_with, user, modifiers)
user.changeNext_move(CLICK_CD_MELEE)
return ITEM_INTERACT_SUCCESS
/obj/item/kinetic_crusher/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/kinetic_crusher/proc/fire_kinetic_blast(atom/target, mob/living/user, list/modifiers)
if(!charged)
return
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
return
var/obj/projectile/destabilizer/destabilizer = new(proj_turf)
destabilizer.icon_state = "[projectile_icon]"
for(var/obj/item/crusher_trophy/attached_trophy as anything in trophies)
attached_trophy.on_projectile_fire(destabilizer, user)
destabilizer.aim_projectile(target, user, modifiers)
destabilizer.firer = user
playsound(user, 'sound/items/weapons/plasma_cutter.ogg', 100, TRUE)
destabilizer.fire()
charged = FALSE
update_appearance()
addtimer(CALLBACK(src, PROC_REF(recharge_projectile)), charge_time)
/obj/item/kinetic_crusher/proc/recharge_projectile()
if(!charged)
charged = TRUE
update_appearance()
playsound(src.loc, 'sound/items/weapons/kinetic_reload.ogg', 60, TRUE)
/obj/item/kinetic_crusher/ui_action_click(mob/user, actiontype)
set_light_on(!light_on)
playsound(user, 'sound/items/weapons/empty.ogg', 100, TRUE)
update_appearance()
/obj/item/kinetic_crusher/on_saboteur(datum/source, disrupt_duration)
. = ..()
set_light_on(FALSE)
playsound(src, 'sound/items/weapons/empty.ogg', 100, TRUE)
return TRUE
/obj/item/kinetic_crusher/update_icon_state()
inhand_icon_state = "[current_inhand_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
return ..()
/obj/item/kinetic_crusher/update_overlays()
. = ..()
if(!charged)
. += "[icon_state]_uncharged"
if(light_on)
. += "[icon_state]_lit"
/obj/item/kinetic_crusher/compact //for admins
name = "compact kinetic crusher"
w_class = WEIGHT_CLASS_NORMAL
//destablizing force
/obj/projectile/destabilizer
name = "destabilizing force"
damage = 0 //We're just here to mark people. This is still a melee weapon.
damage_type = BRUTE
armor_flag = BOMB
range = 6
log_override = TRUE
/// Has this projectile been boosted
var/boosted = FALSE
/obj/projectile/destabilizer/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parriable_projectile, parry_callback = CALLBACK(src, PROC_REF(on_parry)))
/obj/projectile/destabilizer/proc/on_parry(mob/user)
SIGNAL_HANDLER
boosted = TRUE
// Get a bit of a damage/range boost after being parried
damage = 10
range = 9
/obj/projectile/destabilizer/on_hit(atom/target, blocked = 0, pierce_hit)
if(isliving(target))
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/crusher_mark, boosted)
var/target_turf = get_turf(target)
if(ismineralturf(target_turf))
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
name = "tail spike"
desc = "A strange spike with no usage."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "tail_spike"
var/bonus_value = 10 //if it has a bonus effect, this is how much that effect is
var/denied_type = /obj/item/crusher_trophy
/obj/item/crusher_trophy/examine(mob/living/user)
. = ..()
. += span_notice("Causes [effect_desc()] when attached to a kinetic crusher.")
/obj/item/crusher_trophy/proc/effect_desc()
return "errors"
/obj/item/crusher_trophy/attackby(obj/item/A, mob/living/user)
if(istype(A, /obj/item/kinetic_crusher))
add_to(A, user)
else
..()
/obj/item/crusher_trophy/proc/add_to(obj/item/kinetic_crusher/crusher, mob/living/user)
for(var/obj/item/crusher_trophy/trophy as anything in crusher.trophies)
if(istype(trophy, denied_type) || istype(src, trophy.denied_type))
to_chat(user, span_warning("You can't seem to attach [src] to [crusher]. Maybe remove a few trophies?"))
return FALSE
if(!user.transferItemToLoc(src, crusher))
return
crusher.trophies += src
to_chat(user, span_notice("You attach [src] to [crusher]."))
return TRUE
/obj/item/crusher_trophy/proc/remove_from(obj/item/kinetic_crusher/crusher, mob/living/user)
forceMove(get_turf(crusher))
return TRUE
/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_detonation(mob/living/target, mob/living/user) //the target and the user
//watcher
/obj/item/crusher_trophy/watcher_wing
name = "watcher wing"
desc = "A wing ripped from a watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "watcher_wing"
denied_type = /obj/item/crusher_trophy/watcher_wing
bonus_value = 5
/obj/item/crusher_trophy/watcher_wing/effect_desc()
return "mark detonation to prevent certain creatures from using certain attacks for <b>[bonus_value*0.1]</b> second\s"
/obj/item/crusher_trophy/watcher_wing/on_mark_detonation(mob/living/target, mob/living/user)
if(ishostile(target))
var/mob/living/simple_animal/hostile/H = target
if(H.ranged) //briefly delay ranged attacks
if(H.ranged_cooldown >= world.time)
H.ranged_cooldown += bonus_value
else
H.ranged_cooldown = bonus_value + world.time
//magmawing watcher
/obj/item/crusher_trophy/blaster_tubes/magma_wing
name = "magmawing watcher wing"
desc = "A still-searing wing from a magmawing watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "magma_wing"
gender = NEUTER
bonus_value = 5
/obj/item/crusher_trophy/blaster_tubes/magma_wing/effect_desc()
return "mark detonation to make the next destabilizer shot deal <b>[bonus_value]</b> damage"
/obj/item/crusher_trophy/blaster_tubes/magma_wing/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user)
if(deadly_shot)
marker.name = "heated [marker.name]"
marker.icon_state = "lava"
marker.damage = bonus_value
deadly_shot = FALSE
//icewing watcher
/obj/item/crusher_trophy/watcher_wing/ice_wing
name = "icewing watcher wing"
desc = "A carefully preserved frozen wing from an icewing watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "ice_wing"
bonus_value = 8
//legion
/obj/item/crusher_trophy/legion_skull
name = "legion skull"
desc = "A dead and lifeless legion skull. Suitable as a trophy for a kinetic crusher."
icon_state = "legion_skull"
denied_type = /obj/item/crusher_trophy/legion_skull
bonus_value = 3
/obj/item/crusher_trophy/legion_skull/effect_desc()
return "a kinetic crusher to recharge <b>[bonus_value*0.1]</b> second\s faster"
/obj/item/crusher_trophy/legion_skull/add_to(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.charge_time -= bonus_value
/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.charge_time += bonus_value
//blood-drunk hunter
/obj/item/crusher_trophy/miner_eye
name = "eye of a blood-drunk hunter"
desc = "Its pupil is collapsed and turned to mush. Suitable as a trophy for a kinetic crusher."
icon_state = "hunter_eye"
denied_type = /obj/item/crusher_trophy/miner_eye
/obj/item/crusher_trophy/miner_eye/effect_desc()
return "mark detonation to grant stun immunity and <b>90%</b> damage reduction for <b>1</b> second"
/obj/item/crusher_trophy/miner_eye/on_mark_detonation(mob/living/target, mob/living/user)
user.apply_status_effect(/datum/status_effect/blooddrunk)
//ash drake
/obj/item/crusher_trophy/tail_spike
desc = "A spike taken from an ash drake's tail. Suitable as a trophy for a kinetic crusher."
denied_type = /obj/item/crusher_trophy/tail_spike
bonus_value = 5
/obj/item/crusher_trophy/tail_spike/effect_desc()
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/living_target in oview(2, user))
if(user.faction_check_atom(living_target) || living_target.stat == DEAD)
continue
playsound(living_target, 'sound/effects/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
step(target, get_dir(user, target))
//bubblegum
/obj/item/crusher_trophy/demon_claws
name = "demon claws"
desc = "A set of blood-drenched claws from a massive demon's hand. Suitable as a trophy for a kinetic crusher."
icon_state = "demon_claws"
gender = PLURAL
denied_type = /obj/item/crusher_trophy/demon_claws
bonus_value = 10
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
/obj/item/crusher_trophy/demon_claws/effect_desc()
return "melee hits to do <b>[bonus_value * 0.2]</b> more damage and heal you for <b>[bonus_value * 0.1]</b>, with <b>5X</b> effect on mark detonation"
/obj/item/crusher_trophy/demon_claws/add_to(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.force += bonus_value * 0.2
pkc.detonation_damage += bonus_value * 0.8
AddComponent(/datum/component/two_handed, force_wielded=(20 + bonus_value * 0.2))
/obj/item/crusher_trophy/demon_claws/remove_from(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.force -= bonus_value * 0.2
pkc.detonation_damage -= bonus_value * 0.8
AddComponent(/datum/component/two_handed, force_wielded=20)
/obj/item/crusher_trophy/demon_claws/on_melee_hit(mob/living/target, mob/living/user)
user.heal_ordered_damage(bonus_value * 0.1, damage_heal_order)
/obj/item/crusher_trophy/demon_claws/on_mark_detonation(mob/living/target, mob/living/user)
user.heal_ordered_damage(bonus_value * 0.4, damage_heal_order)
//colossus
/obj/item/crusher_trophy/blaster_tubes
name = "blaster tubes"
desc = "The blaster tubes from a colossus's arm. Suitable as a trophy for a kinetic crusher."
icon_state = "blaster_tubes"
gender = PLURAL
denied_type = /obj/item/crusher_trophy/blaster_tubes
bonus_value = 15
var/deadly_shot = FALSE
/obj/item/crusher_trophy/blaster_tubes/effect_desc()
return "mark detonation to make the next destabilizer shot deal <b>[bonus_value]</b> damage but move slower"
/obj/item/crusher_trophy/blaster_tubes/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user)
if(deadly_shot)
marker.name = "deadly [marker.name]"
marker.icon_state = "chronobolt"
marker.damage = bonus_value
marker.speed = 0.5
deadly_shot = FALSE
/obj/item/crusher_trophy/blaster_tubes/on_mark_detonation(mob/living/target, mob/living/user)
deadly_shot = TRUE
addtimer(CALLBACK(src, PROC_REF(reset_deadly_shot)), 300, TIMER_UNIQUE|TIMER_OVERRIDE)
/obj/item/crusher_trophy/blaster_tubes/proc/reset_deadly_shot()
deadly_shot = FALSE
//hierophant
/obj/item/crusher_trophy/vortex_talisman
name = "vortex talisman"
desc = "A glowing trinket that was originally the Hierophant's beacon. Suitable as a trophy for a kinetic crusher."
icon_state = "vortex_talisman"
denied_type = /obj/item/crusher_trophy/vortex_talisman
/obj/item/crusher_trophy/vortex_talisman/effect_desc()
return "mark detonation to create a homing hierophant chaser"
/obj/item/crusher_trophy/vortex_talisman/on_mark_detonation(mob/living/target, mob/living/user)
if(isliving(target))
var/obj/effect/temp_visual/hierophant/chaser/chaser = new(get_turf(user), user, target, 3, TRUE)
chaser.monster_damage_boost = FALSE // Weaker cuz no cooldown
chaser.damage = 20
log_combat(user, target, "fired a chaser at", src)
/obj/item/crusher_trophy/ice_demon_cube
name = "demonic cube"
desc = "A stone cold cube dropped from an ice demon."
icon_state = "ice_demon_cube"
denied_type = /obj/item/crusher_trophy/ice_demon_cube
///how many will we summon?
var/summon_amount = 2
///cooldown to summon demons upon the target
COOLDOWN_DECLARE(summon_cooldown)
/obj/item/crusher_trophy/ice_demon_cube/effect_desc()
return "mark detonation to unleash demonic ice clones upon the target"
/obj/item/crusher_trophy/ice_demon_cube/on_mark_detonation(mob/living/target, mob/living/user)
if(isnull(target) || !COOLDOWN_FINISHED(src, summon_cooldown))
return
for(var/i in 1 to summon_amount)
var/turf/drop_off = find_dropoff_turf(target, user)
var/mob/living/basic/mining/demon_afterimage/crusher/friend = new(drop_off)
friend.faction = list(FACTION_NEUTRAL)
friend.befriend(user)
friend.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target)
COOLDOWN_START(src, summon_cooldown, 30 SECONDS)
///try to make them spawn all around the target to surround him
/obj/item/crusher_trophy/ice_demon_cube/proc/find_dropoff_turf(mob/living/target, mob/living/user)
var/list/turfs_list = get_adjacent_open_turfs(target)
for(var/turf/possible_turf in turfs_list)
if(possible_turf.is_blocked_turf())
continue
return possible_turf
return get_turf(user)
//wolf trophy
/obj/item/crusher_trophy/wolf_ear
name = "wolf ear"
desc = "It's a wolf ear."
icon_state = "wolf_ear"
denied_type = /obj/item/crusher_trophy/wolf_ear
/obj/item/crusher_trophy/wolf_ear/effect_desc()
return "mark detonation to gain a slight speed boost temporarily"
/obj/item/crusher_trophy/wolf_ear/on_mark_detonation(mob/living/target, mob/living/user)
user.apply_status_effect(/datum/status_effect/speed_boost, 1 SECONDS)
//cosmetic items for changing the crusher's look
/obj/item/crusher_trophy/retool_kit
name = "crusher sword retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a sword."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
///Specifies the sprite/icon state which the crusher is changed to as an item. Should appear in the icons/obj/mining.dmi file with accompanying "lit" and "recharging" sprites
var/retool_icon = "crusher_sword"
///Specifies the icon state for the crusher's appearance in hand. Should appear in both icons/mob/inhands/weapons/hammers_lefthand.dmi and icons/mob/inhands/weapons/hammers_righthand.dmi
var/retool_inhand_icon = "crusher_sword"
///For if the retool kit changes the projectile's appearance. The sprite should be in icons/obj/weapons/guns/projectiles.dmi
var/retool_projectile_icon = "pulse1"
/obj/item/crusher_trophy/retool_kit/effect_desc()
return "the crusher to have the appearance of a sword"
/obj/item/crusher_trophy/retool_kit/add_to(obj/item/kinetic_crusher/pkc, mob/user)
. = ..()
if(.)
pkc.icon_state = retool_icon
pkc.current_inhand_icon_state = retool_inhand_icon
pkc.projectile_icon = retool_projectile_icon
if(iscarbon(pkc.loc))
var/mob/living/carbon/holder = pkc.loc
holder.update_worn_back()
holder.update_suit_storage()
holder.update_held_items()
pkc.update_appearance()
/obj/item/crusher_trophy/retool_kit/remove_from(obj/item/kinetic_crusher/pkc)
pkc.icon_state = initial(pkc.icon_state)
pkc.current_inhand_icon_state = initial(pkc.current_inhand_icon_state)
pkc.projectile_icon = initial(pkc.projectile_icon)
if(iscarbon(pkc.loc))
var/mob/living/carbon/holder = pkc.loc
holder.update_worn_back()
holder.update_suit_storage()
holder.update_held_items()
pkc.update_appearance()
..()
/obj/item/crusher_trophy/retool_kit/harpoon
name = "crusher harpoon retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a harpoon."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_harpoon"
retool_inhand_icon = "crusher_harpoon"
retool_projectile_icon = "pulse_harpoon"
/obj/item/crusher_trophy/retool_kit/harpoon/effect_desc()
return "the crusher to have the appearance of a harpoon"
/obj/item/crusher_trophy/retool_kit/dagger
name = "crusher dagger retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a dual dagger and mini-blaster on a chain."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_dagger"
retool_inhand_icon = "crusher_dagger"
/obj/item/crusher_trophy/retool_kit/dagger/effect_desc()
return "the crusher to have the appearance of a dual dagger and blaster"
/obj/item/crusher_trophy/retool_kit/ashenskull
name = "ashen skull"
desc = "It burns with the flame of the necropolis, whispering in your ear. It demands to be bound to a suitable weapon."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit_skull"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_skull"
retool_inhand_icon = "crusher_skull"
retool_projectile_icon = "pulse_skull"
/obj/item/crusher_trophy/retool_kit/ashenskull/effect_desc()
return "the crusher to appear corrupted by infernal powers"
@@ -0,0 +1,329 @@
/**
* 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
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."
icon = 'icons/obj/mining.dmi'
icon_state = "crusher"
inhand_icon_state = "crusher0"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/hammers_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/hammers_righthand.dmi'
resistance_flags = FIRE_PROOF
force = 0 //You can't hit stuff unless wielded
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
throwforce = 5
throw_speed = 4
armour_penetration = 10
custom_materials = list(/datum/material/iron=HALF_SHEET_MATERIAL_AMOUNT*1.15, /datum/material/glass=HALF_SHEET_MATERIAL_AMOUNT*2.075)
hitsound = 'sound/items/weapons/bladeslice.ogg'
attack_verb_continuous = list("smashes", "crushes", "cleaves", "chops", "pulps")
attack_verb_simple = list("smash", "crush", "cleave", "chop", "pulp")
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/toggle_light)
obj_flags = UNIQUE_RENAME
light_system = OVERLAY_LIGHT
light_range = 5
light_power = 1.2
light_color = "#ffff66"
light_on = FALSE
/// List of all crusher trophies attached to this.
var/list/obj/item/crusher_trophy/trophies = list()
/// If our crusher is ready to fire a projectile (FALSE means it's on cooldown)
var/charged = TRUE
/// How long before our crusher will recharge by default
var/charge_time = 1.5 SECONDS
/// Timer before our crusher recharges
var/charge_timer
/// Damage that the mark does when hit by the crusher
var/detonation_damage = 50
/// Damage that the mark additionally does when hit by the crusher via backstab
var/backstab_bonus = 30
/// Used by retool kits when changing the crusher's appearance
var/current_inhand_icon_state = "crusher"
/// Used by retool kits when changing the crusher's projectile sprite
var/projectile_icon = "pulse1"
/obj/item/kinetic_crusher/Initialize(mapload)
. = ..()
AddComponent(/datum/component/butchering, \
speed = 6 SECONDS, \
effectiveness = 110, \
)
//technically it's huge and bulky, but this provides an incentive to use it
AddComponent(/datum/component/two_handed, force_unwielded=0, force_wielded=20)
register_context()
/obj/item/kinetic_crusher/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(!held_item)
context[SCREENTIP_CONTEXT_RMB] = "Detach trophy"
return CONTEXTUAL_SCREENTIP_SET
if(istype(held_item) && held_item.tool_behaviour == TOOL_CROWBAR)
context[SCREENTIP_CONTEXT_LMB] = "Detach all trophies"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/kinetic_crusher/Destroy()
QDEL_LIST(trophies)
return ..()
/obj/item/kinetic_crusher/Exited(atom/movable/gone, direction)
. = ..()
trophies -= gone
/obj/item/kinetic_crusher/examine(mob/living/user)
. = ..()
. += 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/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
// adapted from kinetic accelerator attack_hand_secodary
/obj/item/kinetic_crusher/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(!LAZYLEN(trophies))
return SECONDARY_ATTACK_CONTINUE_CHAIN
var/list/display_names = list()
var/list/items = list()
for(var/trophies_length in 1 to length(trophies))
var/obj/item/crusher_trophy/trophy = trophies[trophies_length]
display_names[trophy.name] = REF(trophy)
var/image/item_image = image(icon = trophy.icon, icon_state = trophy.icon_state)
if(length(trophy.overlays))
item_image.copy_overlays(trophy)
items["[trophy.name]"] = item_image
var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 36, require_near = TRUE, tooltips = TRUE)
if(!pick)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/trophy_reference = display_names[pick]
var/obj/item/crusher_trophy/trophy_to_remove = locate(trophy_reference) in trophies
if(!istype(trophy_to_remove))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
trophy_to_remove.remove_from(src, user)
if(!user.put_in_hands(trophy_to_remove))
trophy_to_remove.forceMove(drop_location())
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/kinetic_crusher/proc/check_menu(mob/living/carbon/human/user)
if(!istype(user))
return FALSE
if(user.incapacitated)
return FALSE
return TRUE
/obj/item/kinetic_crusher/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return TRUE
if(!HAS_TRAIT(src, TRAIT_WIELDED))
user.balloon_alert(user, "must be wielded!")
return TRUE
return .
/obj/item/kinetic_crusher/attack(mob/living/target, mob/living/carbon/user)
target.apply_status_effect(/datum/status_effect/crusher_damage)
return ..()
/obj/item/kinetic_crusher/afterattack(mob/living/target, mob/living/user, clickparams)
if(!isliving(target))
return
// Melee effect
for(var/obj/item/crusher_trophy/crusher_trophy as anything in trophies)
crusher_trophy.on_melee_hit(target, user)
if(QDELETED(target))
return
var/datum/status_effect/crusher_mark/mark = target.has_status_effect(/datum/status_effect/crusher_mark)
var/boosted_mark = mark?.boosted
if(world.time < mark.mark_applied + mark.ready_delay) // Simple way to prevent right+left click at the same time to detonate the mark for free
return
if(!target.remove_status_effect(mark))
return
// Detonation effect
var/datum/status_effect/crusher_damage/crusher_damage_effect = target.has_status_effect(/datum/status_effect/crusher_damage) || 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/def_check = target.getarmor(type = BOMB)
// Backstab bonus
if(check_behind(user, target) || boosted_mark)
backstabbed = TRUE
combined_damage += backstab_bonus
playsound(user, 'sound/items/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/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
balloon_alert(user, "wield it first!")
return ITEM_INTERACT_BLOCKING
if(interacting_with == user)
balloon_alert(user, "can't aim at yourself!")
return ITEM_INTERACT_BLOCKING
fire_kinetic_blast(interacting_with, user, modifiers)
return ITEM_INTERACT_SUCCESS
/obj/item/kinetic_crusher/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/kinetic_crusher/proc/fire_kinetic_blast(atom/target, mob/living/user, list/modifiers)
if(!charged)
return
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
return
var/obj/projectile/destabilizer/destabilizer = new(proj_turf)
destabilizer.icon_state = "[projectile_icon]"
for(var/obj/item/crusher_trophy/attached_trophy as anything in trophies)
attached_trophy.on_projectile_fire(destabilizer, user)
destabilizer.aim_projectile(target, user, modifiers)
destabilizer.firer = user
destabilizer.fired_from = src
playsound(user, 'sound/items/weapons/plasma_cutter.ogg', 100, TRUE)
destabilizer.fire()
charged = FALSE
update_appearance()
attempt_recharge_projectile()
/// Handles the timer for reloading the projectile
/obj/item/kinetic_crusher/proc/attempt_recharge_projectile(set_recharge_time)
if(!set_recharge_time)
set_recharge_time = charge_time
deltimer(charge_timer)
charge_timer = addtimer(CALLBACK(src, PROC_REF(recharge_projectile)), set_recharge_time, TIMER_STOPPABLE)
/// Recharges the projectile
/obj/item/kinetic_crusher/proc/recharge_projectile()
if(!charged)
charged = TRUE
update_appearance()
playsound(src.loc, 'sound/items/weapons/kinetic_reload.ogg', 60, TRUE)
/obj/item/kinetic_crusher/ui_action_click(mob/user, actiontype)
set_light_on(!light_on)
playsound(user, 'sound/items/weapons/empty.ogg', 100, TRUE)
update_appearance()
/obj/item/kinetic_crusher/on_saboteur(datum/source, disrupt_duration)
. = ..()
set_light_on(FALSE)
playsound(src, 'sound/items/weapons/empty.ogg', 100, TRUE)
return TRUE
/obj/item/kinetic_crusher/update_icon_state()
inhand_icon_state = "[current_inhand_icon_state][HAS_TRAIT(src, TRAIT_WIELDED)]" // this is not icon_state and not supported by 2hcomponent
return ..()
/obj/item/kinetic_crusher/update_overlays()
. = ..()
if(!charged)
. += "[icon_state]_uncharged"
if(light_on)
. += "[icon_state]_lit"
/obj/item/kinetic_crusher/compact //for admins
name = "compact kinetic crusher"
w_class = WEIGHT_CLASS_NORMAL
//destablizing force
/obj/projectile/destabilizer
name = "destabilizing force"
damage = 0 //We're just here to mark people. This is still a melee weapon.
damage_type = BRUTE
armor_flag = BOMB
range = 6
log_override = TRUE
/// Has this projectile been boosted
var/boosted = FALSE
/obj/projectile/destabilizer/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parriable_projectile, parry_callback = CALLBACK(src, PROC_REF(on_parry)))
/obj/projectile/destabilizer/Destroy()
fired_from = null
return ..()
/obj/projectile/destabilizer/proc/on_parry(mob/user)
SIGNAL_HANDLER
boosted = TRUE
// Get a bit of a damage/range boost after being parried
damage = 10
range = 9
/obj/projectile/destabilizer/on_hit(atom/target, blocked = 0, pierce_hit)
var/obj/item/kinetic_crusher/used_crusher
if(istype(fired_from, /obj/item/kinetic_crusher))
used_crusher = fired_from
if(isliving(target))
for(var/obj/item/crusher_trophy/crusher_trophy as anything in used_crusher?.trophies)
crusher_trophy.on_projectile_hit_mob(target, firer)
if(QDELETED(target))
return ..()
var/mob/living/living_target = target
living_target.apply_status_effect(/datum/status_effect/crusher_mark, boosted)
return ..()
var/target_turf = get_turf(target)
if(ismineralturf(target_turf))
var/turf/closed/mineral/hit_mineral = target_turf
for(var/obj/item/crusher_trophy/crusher_trophy as anything in used_crusher?.trophies)
crusher_trophy.on_projectile_hit_mineral(hit_mineral, firer)
if(QDELETED(hit_mineral))
return ..()
new /obj/effect/temp_visual/kinetic_blast(hit_mineral)
hit_mineral.gets_drilled(firer, TRUE)
if(!iscarbon(firer))
return ..()
var/mob/living/carbon/carbon_firer = firer
var/skill_modifier = 1
// If there is a mind, check for skill modifier to allow them to reload faster.
if(carbon_firer.mind && used_crusher)
skill_modifier = carbon_firer.mind.get_skill_modifier(/datum/skill/mining, SKILL_SPEED_MODIFIER)
used_crusher.attempt_recharge_projectile(used_crusher.charge_time * skill_modifier) //If you hit a mineral, you might get a quicker reload. epic gamer style.
return ..()
@@ -0,0 +1,63 @@
/*!
* Contains the baseline of kinetic crusher trophies.
*/
/obj/item/crusher_trophy
name = "tail spike"
desc = "A strange spike with no usage."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "tail_spike"
/// if it has a bonus effect, this is how much that effect is
var/bonus_value = 10
/// what type of trophies will block this trophy from being added, must be overriden
var/denied_type = /obj/item/crusher_trophy
/obj/item/crusher_trophy/examine(mob/living/user)
. = ..()
. += span_notice("Causes [effect_desc()] when attached to a kinetic crusher.")
/// Returns a string to get added to the examine
/obj/item/crusher_trophy/proc/effect_desc()
SHOULD_CALL_PARENT(FALSE)
return "errors"
/obj/item/crusher_trophy/attackby(obj/item/attacking_item, mob/living/user)
if(!istype(attacking_item, /obj/item/kinetic_crusher))
return ..()
add_to(attacking_item, user)
/// Tries to add the trophy to our crusher
/obj/item/crusher_trophy/proc/add_to(obj/item/kinetic_crusher/crusher, mob/living/user)
for(var/obj/item/crusher_trophy/trophy as anything in crusher.trophies)
if(istype(trophy, denied_type) || istype(src, trophy.denied_type))
to_chat(user, span_warning("You can't seem to attach [src] to [crusher]. Maybe remove a few trophies?"))
return FALSE
if(!user.transferItemToLoc(src, crusher))
return
crusher.trophies += src
to_chat(user, span_notice("You attach [src] to [crusher]."))
return TRUE
/// Removes the trophy from our crusher
/obj/item/crusher_trophy/proc/remove_from(obj/item/kinetic_crusher/crusher, mob/living/user)
forceMove(get_turf(crusher))
return TRUE
/// Does an effect when you hit a mob with a crusher
/obj/item/crusher_trophy/proc/on_melee_hit(mob/living/target, mob/living/user) //the target and the user
return
/obj/item/crusher_trophy/proc/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user) //the projectile fired and the user
return
/// Does an effect when you hit a mob with the projectile
/obj/item/crusher_trophy/proc/on_projectile_hit_mob(mob/living/target, mob/living/user) //the target and the user
return
/// Does an effect when you hit a mineral turf with the projectile
/obj/item/crusher_trophy/proc/on_projectile_hit_mineral(turf/closed/mineral, mob/living/user) //the target and the user
return
/// Does an effect when you hit a mob that is marked via the projectile
/obj/item/crusher_trophy/proc/on_mark_detonation(mob/living/target, mob/living/user) //the target and the user
return
@@ -0,0 +1,241 @@
/*!
* Contains crusher trophies you can obtain from regular fauna
*/
//watcher
/obj/item/crusher_trophy/watcher_wing
name = "watcher wing"
desc = "A wing ripped from a watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "watcher_wing"
denied_type = /obj/item/crusher_trophy/watcher_wing
bonus_value = 5
/obj/item/crusher_trophy/watcher_wing/effect_desc()
return "mark detonation to prevent certain creatures from using certain attacks for <b>[bonus_value*0.1]</b> second\s"
/obj/item/crusher_trophy/watcher_wing/on_mark_detonation(mob/living/target, mob/living/user)
if(ishostile(target))
var/mob/living/simple_animal/hostile/H = target
if(H.ranged) //briefly delay ranged attacks
if(H.ranged_cooldown >= world.time)
H.ranged_cooldown += bonus_value
else
H.ranged_cooldown = bonus_value + world.time
//magmawing watcher
/obj/item/crusher_trophy/blaster_tubes/magma_wing
name = "magmawing watcher wing"
desc = "A still-searing wing from a magmawing watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "magma_wing"
gender = NEUTER
bonus_value = 5
/obj/item/crusher_trophy/blaster_tubes/magma_wing/effect_desc()
return "mark detonation to make the next destabilizer shot deal <b>[bonus_value]</b> damage"
/obj/item/crusher_trophy/blaster_tubes/magma_wing/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user)
if(deadly_shot)
marker.name = "heated [marker.name]"
marker.icon_state = "lava"
marker.damage = bonus_value
deadly_shot = FALSE
//icewing watcher
/obj/item/crusher_trophy/watcher_wing/ice_wing
name = "icewing watcher wing"
desc = "A carefully preserved frozen wing from an icewing watcher. Suitable as a trophy for a kinetic crusher."
icon_state = "ice_wing"
bonus_value = 8
//legion
/obj/item/crusher_trophy/legion_skull
name = "legion skull"
desc = "A dead and lifeless legion skull. Suitable as a trophy for a kinetic crusher."
icon_state = "legion_skull"
denied_type = /obj/item/crusher_trophy/legion_skull
bonus_value = 3
/obj/item/crusher_trophy/legion_skull/effect_desc()
return "a kinetic crusher to recharge <b>[bonus_value*0.1]</b> second\s faster"
/obj/item/crusher_trophy/legion_skull/add_to(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.charge_time -= bonus_value
/obj/item/crusher_trophy/legion_skull/remove_from(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.charge_time += bonus_value
// Goliath - Increases damage as your health decreases.
/obj/item/crusher_trophy/goliath_tentacle
name = "goliath tentacle"
desc = "A sliced-off goliath tentacle. Suitable as a trophy for a kinetic crusher."
icon_state = "goliath_tentacle"
denied_type = /obj/item/crusher_trophy/goliath_tentacle
bonus_value = 2
/// Your missing health is multiplied by this value to find the bonus damage
var/missing_health_ratio = 0.1
/// Amount of health you must lose to gain damage, according to the examine text. Cached so we don't recalculate it every examine.
var/missing_health_desc
/obj/item/crusher_trophy/goliath_tentacle/Initialize(mapload)
. = ..()
missing_health_desc = 1 / missing_health_ratio / bonus_value
/obj/item/crusher_trophy/goliath_tentacle/effect_desc()
return "mark detonation to do <b>[bonus_value]</b> more damage for every <b>[missing_health_desc]</b> health you are missing"
/obj/item/crusher_trophy/goliath_tentacle/on_mark_detonation(mob/living/target, mob/living/user)
var/missing_health = user.maxHealth - user.health
missing_health *= missing_health_ratio //bonus is active at all times, even if you're above 90 health
missing_health *= bonus_value //multiply the remaining amount by bonus_value
if(missing_health > 0)
target.adjustBruteLoss(missing_health) //and do that much damage
// Lobstrosity - Rebukes targets, increasing their click cooldown.
/obj/item/crusher_trophy/lobster_claw
name = "lobster claw"
icon_state = "lobster_claw"
desc = "A lobster claw."
denied_type = /obj/item/crusher_trophy/lobster_claw
bonus_value = 1
/obj/item/crusher_trophy/lobster_claw/effect_desc()
return "mark detonation to briefly rebuke the target for [bonus_value] seconds"
/obj/item/crusher_trophy/lobster_claw/on_mark_detonation(mob/living/target, mob/living/user)
target.apply_status_effect(/datum/status_effect/rebuked, bonus_value SECONDS)
// Brimdemon - makes a funny sound, the most essential trophy out of all
/obj/item/crusher_trophy/brimdemon_fang
name = "brimdemon's fang"
icon_state = "brimdemon_fang"
desc = "A fang from a brimdemon's corpse."
denied_type = /obj/item/crusher_trophy/brimdemon_fang
/// Cartoon punching vfx
var/static/list/comic_phrases = list("BOOM", "BANG", "KABLOW", "KAPOW", "OUCH", "BAM", "KAPOW", "WHAM", "POW", "KABOOM")
/obj/item/crusher_trophy/brimdemon_fang/effect_desc()
return "mark detonation to create visual and audiosensory effects at the target"
/obj/item/crusher_trophy/brimdemon_fang/on_mark_detonation(mob/living/target, mob/living/user)
target.balloon_alert_to_viewers("[pick(comic_phrases)]!")
playsound(target, 'sound/mobs/non-humanoids/brimdemon/brimdemon_crush.ogg', 100)
// Bileworm
/obj/item/crusher_trophy/bileworm_spewlet
name = "bileworm spewlet"
icon = 'icons/mob/simple/lavaland/bileworm.dmi'
icon_state = "bileworm_spewlet"
desc = "A baby bileworm. Suitable as a trophy for a kinetic crusher."
denied_type = /obj/item/crusher_trophy/bileworm_spewlet
///item ability that handles the effect
var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/spewlet/ability
/obj/item/crusher_trophy/bileworm_spewlet/Initialize(mapload)
. = ..()
ability = new()
/obj/item/crusher_trophy/bileworm_spewlet/Destroy(force)
. = ..()
QDEL_NULL(ability)
/obj/item/crusher_trophy/bileworm_spewlet/add_to(obj/item/kinetic_crusher/crusher, mob/living/user)
. = ..()
if(.)
crusher.add_item_action(ability)
/obj/item/crusher_trophy/bileworm_spewlet/remove_from(obj/item/kinetic_crusher/crusher, mob/living/user)
. = ..()
crusher.remove_item_action(ability)
/obj/item/crusher_trophy/bileworm_spewlet/effect_desc()
return "mark detonation launches projectiles in cardinal directions on a 10 second cooldown. Also gives you an AOE when mining minerals"
/obj/item/crusher_trophy/bileworm_spewlet/on_mark_detonation(mob/living/target, mob/living/user)
//ability itself handles cooldowns.
ability.InterceptClickOn(user, null, target)
/obj/item/crusher_trophy/bileworm_spewlet/on_projectile_hit_mineral(turf/closed/mineral, mob/living/user)
for(var/turf/closed/mineral/mineral_turf in RANGE_TURFS(1, mineral) - mineral)
mineral_turf.gets_drilled(user, TRUE)
//yes this is a /mob_cooldown subtype being added to an item. I can't recommend you do what I'm doing
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/spewlet
check_flags = NONE
owner_has_control = FALSE
cooldown_time = 10 SECONDS
projectile_type = /obj/projectile/bileworm_acid
projectile_sound = 'sound/mobs/non-humanoids/bileworm/bileworm_spit.ogg'
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/spewlet/New(Target)
firing_directions = GLOB.cardinals.Copy()
return ..()
// demonic watcher
/obj/item/crusher_trophy/ice_demon_cube
name = "demonic cube"
desc = "A stone cold cube dropped from an ice demon."
icon_state = "ice_demon_cube"
denied_type = /obj/item/crusher_trophy/ice_demon_cube
///how many will we summon?
var/summon_amount = 2
///cooldown to summon demons upon the target
COOLDOWN_DECLARE(summon_cooldown)
/obj/item/crusher_trophy/ice_demon_cube/effect_desc()
return "mark detonation to unleash demonic ice clones upon the target"
/obj/item/crusher_trophy/ice_demon_cube/on_mark_detonation(mob/living/target, mob/living/user)
if(isnull(target) || !COOLDOWN_FINISHED(src, summon_cooldown))
return
for(var/i in 1 to summon_amount)
var/turf/drop_off = find_dropoff_turf(target, user)
var/mob/living/basic/mining/demon_afterimage/crusher/friend = new(drop_off)
friend.faction = list(FACTION_NEUTRAL)
friend.befriend(user)
friend.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, target)
COOLDOWN_START(src, summon_cooldown, 30 SECONDS)
///try to make them spawn all around the target to surround him
/obj/item/crusher_trophy/ice_demon_cube/proc/find_dropoff_turf(mob/living/target, mob/living/user)
var/list/turfs_list = get_adjacent_open_turfs(target)
for(var/turf/possible_turf in turfs_list)
if(possible_turf.is_blocked_turf())
continue
return possible_turf
return get_turf(user)
// Wolf
/obj/item/crusher_trophy/wolf_ear
name = "wolf ear"
desc = "It's a wolf ear."
icon_state = "wolf_ear"
denied_type = /obj/item/crusher_trophy/wolf_ear
/obj/item/crusher_trophy/wolf_ear/effect_desc()
return "mark detonation to gain a slight speed boost temporarily"
/obj/item/crusher_trophy/wolf_ear/on_mark_detonation(mob/living/target, mob/living/user)
user.apply_status_effect(/datum/status_effect/speed_boost, 1 SECONDS)
// Polar bear
/obj/item/crusher_trophy/bear_paw
name = "polar bear paw"
desc = "It's a polar bear paw."
icon_state = "bear_paw"
denied_type = /obj/item/crusher_trophy/bear_paw
/obj/item/crusher_trophy/bear_paw/effect_desc()
return "mark detonation to attack twice if you are below half your life"
/obj/item/crusher_trophy/bear_paw/on_mark_detonation(mob/living/target, mob/living/user)
if(user.health / user.maxHealth > 0.5)
return
var/obj/item/I = user.get_active_held_item()
if(!I)
return
I.melee_attack_chain(user, target, null)
@@ -0,0 +1,217 @@
/*!
* Contains crusher trophies you can obtain from megafauna
*/
//blood-drunk hunter
/obj/item/crusher_trophy/miner_eye
name = "eye of a blood-drunk hunter"
desc = "Its pupil is collapsed and turned to mush. Suitable as a trophy for a kinetic crusher."
icon_state = "hunter_eye"
denied_type = /obj/item/crusher_trophy/miner_eye
/obj/item/crusher_trophy/miner_eye/effect_desc()
return "mark detonation to grant stun immunity and <b>90%</b> damage reduction for <b>1</b> second"
/obj/item/crusher_trophy/miner_eye/on_mark_detonation(mob/living/target, mob/living/user)
user.apply_status_effect(/datum/status_effect/blooddrunk)
//ash drake
/obj/item/crusher_trophy/tail_spike
desc = "A spike taken from an ash drake's tail. Suitable as a trophy for a kinetic crusher."
denied_type = /obj/item/crusher_trophy/tail_spike
bonus_value = 5
/obj/item/crusher_trophy/tail_spike/effect_desc()
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/living_target in oview(2, user))
if(user.faction_check_atom(living_target) || living_target.stat == DEAD)
continue
playsound(living_target, 'sound/effects/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
step(target, get_dir(user, target))
//bubblegum
/obj/item/crusher_trophy/demon_claws
name = "demon claws"
desc = "A set of blood-drenched claws from a massive demon's hand. Suitable as a trophy for a kinetic crusher."
icon_state = "demon_claws"
gender = PLURAL
denied_type = /obj/item/crusher_trophy/demon_claws
bonus_value = 10
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
/obj/item/crusher_trophy/demon_claws/effect_desc()
return "melee hits to do <b>[bonus_value * 0.2]</b> more damage and heal you for <b>[bonus_value * 0.1]</b>, with <b>5X</b> effect on mark detonation"
/obj/item/crusher_trophy/demon_claws/add_to(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.force += bonus_value * 0.2
pkc.detonation_damage += bonus_value * 0.8
AddComponent(/datum/component/two_handed, force_wielded=(20 + bonus_value * 0.2))
/obj/item/crusher_trophy/demon_claws/remove_from(obj/item/kinetic_crusher/pkc, mob/living/user)
. = ..()
if(.)
pkc.force -= bonus_value * 0.2
pkc.detonation_damage -= bonus_value * 0.8
AddComponent(/datum/component/two_handed, force_wielded=20)
/obj/item/crusher_trophy/demon_claws/on_melee_hit(mob/living/target, mob/living/user)
user.heal_ordered_damage(bonus_value * 0.1, damage_heal_order)
/obj/item/crusher_trophy/demon_claws/on_mark_detonation(mob/living/target, mob/living/user)
user.heal_ordered_damage(bonus_value * 0.4, damage_heal_order)
//colossus
/obj/item/crusher_trophy/blaster_tubes
name = "blaster tubes"
desc = "The blaster tubes from a colossus's arm. Suitable as a trophy for a kinetic crusher."
icon_state = "blaster_tubes"
gender = PLURAL
denied_type = /obj/item/crusher_trophy/blaster_tubes
bonus_value = 15
var/deadly_shot = FALSE
/obj/item/crusher_trophy/blaster_tubes/effect_desc()
return "mark detonation to make the next destabilizer shot deal <b>[bonus_value]</b> damage but move slower"
/obj/item/crusher_trophy/blaster_tubes/on_projectile_fire(obj/projectile/destabilizer/marker, mob/living/user)
if(deadly_shot)
marker.name = "deadly [marker.name]"
marker.icon_state = "chronobolt"
marker.damage = bonus_value
marker.speed = 2
deadly_shot = FALSE
/obj/item/crusher_trophy/blaster_tubes/on_mark_detonation(mob/living/target, mob/living/user)
deadly_shot = TRUE
addtimer(CALLBACK(src, PROC_REF(reset_deadly_shot)), 300, TIMER_UNIQUE|TIMER_OVERRIDE)
/obj/item/crusher_trophy/blaster_tubes/proc/reset_deadly_shot()
deadly_shot = FALSE
//hierophant
/obj/item/crusher_trophy/vortex_talisman
name = "vortex talisman"
desc = "A glowing trinket that was originally the Hierophant's beacon. Suitable as a trophy for a kinetic crusher."
icon_state = "vortex_talisman"
denied_type = /obj/item/crusher_trophy/vortex_talisman
/obj/item/crusher_trophy/vortex_talisman/effect_desc()
return "mark detonation to create a homing hierophant chaser"
/obj/item/crusher_trophy/vortex_talisman/on_mark_detonation(mob/living/target, mob/living/user)
if(isliving(target))
var/obj/effect/temp_visual/hierophant/chaser/chaser = new(get_turf(user), user, target, 3, TRUE)
chaser.monster_damage_boost = FALSE // Weaker cuz no cooldown
chaser.damage = 20
log_combat(user, target, "fired a chaser at", src)
// Demonic frost miner
/obj/item/crusher_trophy/ice_block_talisman
name = "ice block talisman"
desc = "A glowing trinket that a demonic miner had on him, it seems he couldn't utilize it for whatever reason."
icon_state = "ice_trap_talisman"
denied_type = /obj/item/crusher_trophy/ice_block_talisman
/obj/item/crusher_trophy/ice_block_talisman/effect_desc()
return "mark detonation to freeze a creature in a block of ice for a period, preventing them from moving"
/obj/item/crusher_trophy/ice_block_talisman/on_mark_detonation(mob/living/target, mob/living/user)
target.apply_status_effect(/datum/status_effect/ice_block_talisman)
// Wendigo
/obj/item/crusher_trophy/wendigo_horn
name = "wendigo horn"
desc = "A gnarled horn ripped from the skull of a wendigo. Suitable as a trophy for a kinetic crusher."
icon_state = "wendigo_horn"
denied_type = /obj/item/crusher_trophy/wendigo_horn
/obj/item/crusher_trophy/wendigo_horn/effect_desc()
return "melee hits inflict twice as much damage"
/obj/item/crusher_trophy/wendigo_horn/add_to(obj/item/kinetic_crusher/crusher, mob/living/user)
. = ..()
if(.)
crusher.AddComponent(/datum/component/two_handed, force_wielded=40)
/obj/item/crusher_trophy/wendigo_horn/remove_from(obj/item/kinetic_crusher/crusher, mob/living/user)
. = ..()
if(.)
crusher.AddComponent(/datum/component/two_handed, force_wielded=20)
// Goliath Broodmother
/obj/item/crusher_trophy/broodmother_tongue
name = "broodmother tongue"
desc = "The tongue of a broodmother. If attached a certain way, makes for a suitable crusher trophy. It also feels very spongey, I wonder what would happen if you squeezed it?..."
icon = 'icons/obj/mining_zones/elite_trophies.dmi'
icon_state = "broodmother_tongue"
denied_type = /obj/item/crusher_trophy/broodmother_tongue
bonus_value = 10
/// Time at which the item becomes usable again
var/use_time
/obj/item/crusher_trophy/broodmother_tongue/effect_desc()
return "mark detonation to have a <b>[bonus_value]%</b> chance to summon a patch of goliath tentacles at the target's location"
/obj/item/crusher_trophy/broodmother_tongue/on_mark_detonation(mob/living/target, mob/living/user)
if(prob(bonus_value) && target.stat != DEAD)
new /obj/effect/goliath_tentacle/broodmother/patch(get_turf(target), user)
/obj/item/crusher_trophy/broodmother_tongue/attack_self(mob/user)
if(!isliving(user))
return
var/mob/living/living_user = user
if(use_time > world.time)
to_chat(living_user, "<b>The tongue looks dried out. You'll need to wait longer to use it again.</b>")
return
else if(HAS_TRAIT(living_user, TRAIT_LAVA_IMMUNE))
to_chat(living_user, "<b>You stare at the tongue. You don't think this is any use to you.</b>")
return
ADD_TRAIT(living_user, TRAIT_LAVA_IMMUNE, type)
to_chat(living_user, "<b>You squeeze the tongue, and some transluscent liquid shoots out all over you.</b>")
addtimer(TRAIT_CALLBACK_REMOVE(user, TRAIT_LAVA_IMMUNE, type), 10 SECONDS)
use_time = world.time + 60 SECONDS
// Legionnaire
/obj/item/crusher_trophy/legionnaire_spine
name = "legionnaire spine"
desc = "The spine of a legionnaire. With some creativity, you could use it as a crusher trophy. Alternatively, shaking it might do something as well."
icon = 'icons/obj/mining_zones/elite_trophies.dmi'
icon_state = "legionnaire_spine"
denied_type = /obj/item/crusher_trophy/legionnaire_spine
bonus_value = 20
/// Time at which the item becomes usable again
var/next_use_time
/obj/item/crusher_trophy/legionnaire_spine/effect_desc()
return "mark detonation to have a <b>[bonus_value]%</b> chance to summon a loyal legion skull"
/obj/item/crusher_trophy/legionnaire_spine/on_mark_detonation(mob/living/target, mob/living/user)
if(!prob(bonus_value) || target.stat == DEAD)
return
var/mob/living/basic/legion_brood/minion = new (user.loc)
minion.assign_creator(user)
minion.ai_controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET] = target
/obj/item/crusher_trophy/legionnaire_spine/attack_self(mob/user)
if(!isliving(user))
return
var/mob/living/LivingUser = user
if(next_use_time > world.time)
LivingUser.visible_message(span_warning("[LivingUser] shakes the [src], but nothing happens..."))
to_chat(LivingUser, "<b>You need to wait longer to use this again.</b>")
return
LivingUser.visible_message(span_boldwarning("[LivingUser] shakes the [src] and summons a legion skull!"))
var/mob/living/basic/legion_brood/minion = new (LivingUser.loc)
minion.assign_creator(LivingUser)
next_use_time = world.time + 4 SECONDS
@@ -0,0 +1,84 @@
/*!
* Contains crusher trophies that are not obtained from fauna
*/
//cosmetic items for changing the crusher's look
/obj/item/crusher_trophy/retool_kit
name = "crusher sword retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a sword."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
///Specifies the sprite/icon state which the crusher is changed to as an item. Should appear in the icons/obj/mining.dmi file with accompanying "lit" and "recharging" sprites
var/retool_icon = "crusher_sword"
///Specifies the icon state for the crusher's appearance in hand. Should appear in both icons/mob/inhands/weapons/hammers_lefthand.dmi and icons/mob/inhands/weapons/hammers_righthand.dmi
var/retool_inhand_icon = "crusher_sword"
///For if the retool kit changes the projectile's appearance. The sprite should be in icons/obj/weapons/guns/projectiles.dmi
var/retool_projectile_icon = "pulse1"
/obj/item/crusher_trophy/retool_kit/effect_desc()
return "the crusher to have the appearance of a sword"
/obj/item/crusher_trophy/retool_kit/add_to(obj/item/kinetic_crusher/pkc, mob/user)
. = ..()
if(.)
pkc.icon_state = retool_icon
pkc.current_inhand_icon_state = retool_inhand_icon
pkc.projectile_icon = retool_projectile_icon
if(iscarbon(pkc.loc))
var/mob/living/carbon/holder = pkc.loc
holder.update_worn_back()
holder.update_suit_storage()
holder.update_held_items()
pkc.update_appearance()
/obj/item/crusher_trophy/retool_kit/remove_from(obj/item/kinetic_crusher/pkc)
pkc.icon_state = initial(pkc.icon_state)
pkc.current_inhand_icon_state = initial(pkc.current_inhand_icon_state)
pkc.projectile_icon = initial(pkc.projectile_icon)
if(iscarbon(pkc.loc))
var/mob/living/carbon/holder = pkc.loc
holder.update_worn_back()
holder.update_suit_storage()
holder.update_held_items()
pkc.update_appearance()
..()
/obj/item/crusher_trophy/retool_kit/harpoon
name = "crusher harpoon retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a harpoon."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_harpoon"
retool_inhand_icon = "crusher_harpoon"
retool_projectile_icon = "pulse_harpoon"
/obj/item/crusher_trophy/retool_kit/harpoon/effect_desc()
return "the crusher to have the appearance of a harpoon"
/obj/item/crusher_trophy/retool_kit/dagger
name = "crusher dagger retool kit"
desc = "A toolkit for changing the crusher's appearance without affecting the device's function. This one will make it look like a dual dagger and mini-blaster on a chain."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_dagger"
retool_inhand_icon = "crusher_dagger"
/obj/item/crusher_trophy/retool_kit/dagger/effect_desc()
return "the crusher to have the appearance of a dual dagger and blaster"
/obj/item/crusher_trophy/retool_kit/ashenskull
name = "ashen skull"
desc = "It burns with the flame of the necropolis, whispering in your ear. It demands to be bound to a suitable weapon."
icon = 'icons/obj/mining.dmi'
icon_state = "retool_kit_skull"
denied_type = /obj/item/crusher_trophy/retool_kit
retool_icon = "crusher_skull"
retool_inhand_icon = "crusher_skull"
retool_projectile_icon = "pulse_skull"
/obj/item/crusher_trophy/retool_kit/ashenskull/effect_desc()
return "the crusher to appear corrupted by infernal powers"