From aa74179ecf721285f6970652f4a7a91c40046ad5 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 10 May 2022 02:34:38 +0200 Subject: [PATCH] [MIRROR] Titan's Final Lament - Colossus and hierophant crusher trophy rework [MDB IGNORE] (#13478) * Titan's Final Lament - Colossus and hierophant crusher trophy rework (#66793) This is somewhat a port of BeeStation/BeeStation-Hornet#6805 with slight changes, credits to Rukofamicom for the original PR. Kinetic crusher is supposed to be a high risk high reward weapon, but with current hiero wall trophy it just ends up with the player cheesing mob and boss AIs. To fix this, here we change hiero trophy to spawn a hierophant chaser instead of a wall, which will increase player's DPS without offering them any protection. However, this creates another issue: right now colossus is unbeatable with crusher without cheesing it with the wall due to it's shotgun attack which kills and dusts you point blank or 1 tile away, which is extremely unfair and unfun. To fix this, I add what should've been done from the start - make colossus telegraph it's attacks before starting them. Player has 1.5 seconds to react(unlike 3 seconds in the original PR which made the fight much easier) and dodge the attack or at least get away from the colossus to have a chance to survive. Since this does make the fight significantly easier, colossus gets a special final attack during which it shouts "Perish" and uses different attacks. Unlike in the original PR, he can only use it once, so it's not as deadly and bullshit. This should make the fight more epic and similar to other bossfights which get cool attacks near the end of the battle. Goodbye 4 GBP, you served me well. * Titan's Final Lament - Colossus and hierophant crusher trophy rework Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> --- code/datums/actions/mobs/projectileattack.dm | 77 ++++++++++++++++++- .../mining/equipment/kinetic_crusher.dm | 17 ++-- .../hostile/megafauna/colossus.dm | 69 ++++++++++------- 3 files changed, 123 insertions(+), 40 deletions(-) diff --git a/code/datums/actions/mobs/projectileattack.dm b/code/datums/actions/mobs/projectileattack.dm index dba06851d30..6649e72bd42 100644 --- a/code/datums/actions/mobs/projectileattack.dm +++ b/code/datums/actions/mobs/projectileattack.dm @@ -27,7 +27,7 @@ default_projectile_spread = spread /datum/action/cooldown/mob_cooldown/projectile_attack/Activate(atom/target_atom) - StartCooldown(100) + StartCooldown(10 SECONDS) attack_sequence(owner, target_atom) StartCooldown() @@ -142,6 +142,13 @@ playsound(get_turf(firer), projectile_sound, 20, TRUE) SLEEP_CHECK_DEATH(0.1 SECONDS, firer) +/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus + cooldown_time = 1.5 SECONDS + +/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus/Activate(atom/target_atom) + SLEEP_CHECK_DEATH(1.5 SECONDS, owner) + return ..() + /datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe name = "All Directions" icon_icon = 'icons/effects/effects.dmi' @@ -157,6 +164,13 @@ for(var/i in 1 to 32) shoot_projectile(firer, target, rand(0, 360), firer, null, null) +/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus + cooldown_time = 1.5 SECONDS + +/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus/Activate(atom/target_atom) + SLEEP_CHECK_DEATH(1.5 SECONDS, owner) + return ..() + /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast name = "Shotgun Fire" icon_icon = 'icons/obj/guns/ballistic.dmi' @@ -180,6 +194,14 @@ for(var/spread in chosen_angles) shoot_projectile(firer, target, null, firer, spread, null) + +/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus + cooldown_time = 0.5 SECONDS + +/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus/Activate(atom/target_atom) + SLEEP_CHECK_DEATH(1.5 SECONDS, owner) + return ..() + /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern name = "Alternating Shotgun Fire" desc = "Fires projectiles in an alternating shotgun pattern." @@ -235,6 +257,13 @@ SLEEP_CHECK_DEATH(1 SECONDS, firer) fire_in_directions(firer, target, GLOB.cardinals) +/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus + cooldown_time = 2.5 SECONDS + +/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus/Activate(atom/target_atom) + SLEEP_CHECK_DEATH(1.5 SECONDS, owner) + return ..() + /datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator name = "Fire Kinetic Accelerator" icon_icon = 'icons/obj/guns/energy.dmi' @@ -250,3 +279,49 @@ owner.visible_message(span_danger("[owner] fires the proto-kinetic accelerator!")) owner.face_atom(target_atom) new /obj/effect/temp_visual/dir_setting/firing_effect(owner.loc, owner.dir) + +/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final + name = "Titan's Finale" + desc = "A single-use ability that shoots a large amount of projectiles around you." + cooldown_time = 2.5 SECONDS + +/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/Activate(atom/target_atom) + StartCooldown(30 SECONDS) + attack_sequence(owner, target_atom) + StartCooldown() + Remove(owner) + +/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/attack_sequence(mob/living/firer, atom/target) + var/mob/living/simple_animal/hostile/megafauna/colossus/colossus + if(istype(firer, /mob/living/simple_animal/hostile/megafauna/colossus)) + colossus = firer + colossus.say("Perish.", spans = list("colossus", "yell")) + + var/finale_counter = 10 + for(var/i in 1 to 20) + if(finale_counter > 4 && colossus) + colossus.telegraph() + colossus.shotgun_blast.attack_sequence(firer, target) + + if(finale_counter > 1) + finale_counter -= 1 + + var/turf/start_turf = get_turf(firer) + for(var/turf/target_turf in RANGE_TURFS(12, start_turf)) + if(prob(min(finale_counter, 2)) && target_turf != get_turf(firer)) + shoot_projectile(firer, target_turf, null, firer, null, null) + + SLEEP_CHECK_DEATH(finale_counter + 1, firer) + + for(var/i in 1 to 3) + if(colossus) + colossus.telegraph() + colossus.random_shots.attack_sequence(firer, target) + finale_counter += 6 + SLEEP_CHECK_DEATH(finale_counter, firer) + + for(var/i in 1 to 3) + if(colossus) + colossus.telegraph() + colossus.dir_shots.attack_sequence(firer, target) + SLEEP_CHECK_DEATH(1 SECONDS, firer) diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 594c9d9964d..43c04f8db73 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -449,17 +449,10 @@ denied_type = /obj/item/crusher_trophy/vortex_talisman /obj/item/crusher_trophy/vortex_talisman/effect_desc() - return "mark detonation to create a barrier you can pass" + return "mark detonation to create a homing hierophant chaser" /obj/item/crusher_trophy/vortex_talisman/on_mark_detonation(mob/living/target, mob/living/user) - var/turf/T = get_turf(user) - new /obj/effect/temp_visual/hierophant/wall/crusher(T, user) //a wall only you can pass! - var/turf/otherT = get_step(T, turn(user.dir, 90)) - if(otherT) - new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) - otherT = get_step(T, turn(user.dir, -90)) - if(otherT) - new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) - -/obj/effect/temp_visual/hierophant/wall/crusher - duration = 75 + 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 + log_combat(user, target, "fired a chaser at", src) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index 494e046b865..8d77efc2a55 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -1,4 +1,4 @@ -#define COLOSSUS_ENRAGED (health < maxHealth/3) +#define COLOSSUS_ENRAGED (health <= maxHealth / 3) /** * COLOSSUS @@ -57,25 +57,31 @@ deathsound = 'sound/magic/demon_dies.ogg' small_sprite_type = /datum/action/small_sprite/megafauna/colossus /// Spiral shots ability - var/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/spiral_shots + var/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus/spiral_shots /// Random shots ablity - var/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/random_shots + var/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus/random_shots /// Shotgun blast ability - var/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/shotgun_blast + var/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus/shotgun_blast /// Directional shots ability - var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/dir_shots + var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus/dir_shots + /// Final attack ability + var/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/colossus_final + /// Have we used DIE yet? + var/final_availible = TRUE /mob/living/simple_animal/hostile/megafauna/colossus/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT) //we don't want this guy to float, messes up his animations. - spiral_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots() - random_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe() - shotgun_blast = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast() - dir_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating() + spiral_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus() + random_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus() + shotgun_blast = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus() + dir_shots = new /datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus() + colossus_final = new /datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final() spiral_shots.Grant(src) random_shots.Grant(src) shotgun_blast.Grant(src) dir_shots.Grant(src) + colossus_final.Grant(src) RegisterSignal(src, COMSIG_ABILITY_STARTED, .proc/start_attack) RegisterSignal(src, COMSIG_ABILITY_FINISHED, .proc/finished_attack) AddElement(/datum/element/projectile_shield) @@ -89,7 +95,7 @@ return ..() /mob/living/simple_animal/hostile/megafauna/colossus/OpenFire() - anger_modifier = clamp(((maxHealth - health)/50),0,20) + anger_modifier = clamp(((maxHealth - health) / 40), 0, 20) if(client) return @@ -97,7 +103,7 @@ if(enrage(target)) if(move_to_delay == initial(move_to_delay)) visible_message(span_colossus("\"You can't dodge.\"")) - ranged_cooldown = world.time + 30 + ranged_cooldown = world.time + 3 SECONDS telegraph() dir_shots.fire_in_directions(src, target, GLOB.alldirs) move_to_delay = 3 @@ -105,21 +111,24 @@ else move_to_delay = initial(move_to_delay) - if(prob(20+anger_modifier)) //Major attack + if(health <= maxHealth / 10 && !final_availible) + final_availible = FALSE + colossus_final.Trigger(target = target) + else if(prob(20 + anger_modifier)) //Major attack spiral_shots.Trigger(target = target) else if(prob(20)) random_shots.Trigger(target = target) else - if(prob(70)) + if(prob(60 + anger_modifier)) shotgun_blast.Trigger(target = target) else dir_shots.Trigger(target = target) /mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph() - for(var/mob/M in range(10,src)) - if(M.client) - flash_color(M.client, "#C80000", 1) - shake_camera(M, 4, 3) + for(var/mob/viewer as anything in viewers(10, src)) + if(viewer.client) + flash_color(viewer.client, "#C80000", 1) + shake_camera(viewer, 4, 3) playsound(src, 'sound/magic/clockwork/narsie_attack.ogg', 200, TRUE) /mob/living/simple_animal/hostile/megafauna/colossus/proc/start_attack(mob/living/owner, datum/action/cooldown/activated) @@ -128,25 +137,31 @@ spiral_shots.enraged = COLOSSUS_ENRAGED telegraph() icon_state = "eva_attack" - visible_message(COLOSSUS_ENRAGED ? span_colossus("\"Die.\"") : span_colossus("\"Judgement.\"")) + INVOKE_ASYNC(src, /atom/movable.proc/say, "Judgement.", null, list("colossus", "yell")) + else if(activated == random_shots) + INVOKE_ASYNC(src, /atom/movable.proc/say, "Wrath.", null, list("colossus", "yell")) + else if(activated == shotgun_blast) + INVOKE_ASYNC(src, /atom/movable.proc/say, "Retribution.", null, list("colossus", "yell")) + else if(activated == dir_shots) + INVOKE_ASYNC(src, /atom/movable.proc/say, "Lament.", null, list("colossus", "yell")) /mob/living/simple_animal/hostile/megafauna/colossus/proc/finished_attack(mob/living/owner, datum/action/cooldown/finished) SIGNAL_HANDLER if(finished == spiral_shots) icon_state = initial(icon_state) -/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L) - if(ishuman(L)) - var/mob/living/carbon/human/H = L - if(H.mind) - if(istype(H.mind.martial_art, /datum/martial_art/the_sleeping_carp)) +/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/victim) + if(ishuman(victim)) + var/mob/living/carbon/human/human_victim = victim + if(human_victim.mind) + if(istype(human_victim.mind.martial_art, /datum/martial_art/the_sleeping_carp)) . = TRUE - if (is_species(H, /datum/species/golem/sand)) + if (is_species(human_victim, /datum/species/golem/sand)) . = TRUE -/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L) - visible_message(span_colossus("[src] disintegrates [L]!")) - L.dust() +/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/victim) + visible_message(span_colossus("[src] disintegrates [victim]!")) + victim.dust() /obj/effect/temp_visual/at_shield name = "anti-toolbox field"