Mob Abilities (#63520)

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
This commit is contained in:
Whoneedspacee
2021-12-31 15:56:26 -08:00
committed by GitHub
co-authored by Mothblocks
parent b396e73eb7
commit 155bd7d9ab
28 changed files with 1633 additions and 1226 deletions
+1
View File
@@ -107,6 +107,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/show_tip,
/client/proc/smite,
/client/proc/admin_away,
/client/proc/add_mob_ability,
/datum/admins/proc/station_traits_panel,
))
GLOBAL_PROTECT(admin_verbs_fun)
+26
View File
@@ -505,3 +505,29 @@
message_admins("[key_name_admin(usr)] started weather of type [weather_type] on the z-level [z_level].")
log_admin("[key_name(usr)] started weather of type [weather_type] on the z-level [z_level].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Run Weather")
/client/proc/add_mob_ability()
set category = "Admin.Events"
set name = "Add Mob Ability"
set desc = "Adds an ability to a marked mob."
if(!holder)
return
if(!holder.marked_datum || !istype(holder.marked_datum, /mob/living))
return
var/mob/living/marked_mob = holder.marked_datum
var/ability_type = input("Choose an ability", "Ability") as null|anything in sort_list(subtypesof(/datum/action/cooldown/mob_cooldown), /proc/cmp_typepaths_asc)
if(!ability_type)
return
var/datum/action/cooldown/mob_cooldown/add_ability = new ability_type()
add_ability.Grant(marked_mob)
message_admins("[key_name_admin(usr)] added mob ability [ability_type] to mob [marked_mob].")
log_admin("[key_name(usr)] added mob ability [ability_type] to mob [marked_mob].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Add Mob Ability") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -49,7 +49,7 @@
successfulshocks = 0
if(shockallchains())
successfulshocks++
SLEEP_CHECK_DEATH(3)
SLEEP_CHECK_DEATH(3, src)
/mob/living/simple_animal/hostile/guardian/beam/Recall()
. = ..()
@@ -191,17 +191,25 @@
status_flags = NONE
mob_size = MOB_SIZE_LARGE
gold_core_spawnable = NO_SPAWN
charger = TRUE
charge_distance = 4
menu_description = "Tank spider variant with an enormous amount of health and damage, but is very slow when not on webbing. It also has a charge ability to close distance with a target after a small windup. Does not inject toxin."
///Whether or not the tarantula is currently walking on webbing.
/// Whether or not the tarantula is currently walking on webbing.
var/silk_walking = TRUE
/// Charging ability
var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge
/mob/living/simple_animal/hostile/giant_spider/tarantula/ranged_secondary_attack(atom/target, modifiers)
if(COOLDOWN_FINISHED(src, charge_cooldown))
INVOKE_ASYNC(src, /mob/living/simple_animal/hostile/.proc/enter_charge, target)
else
to_chat(src, span_notice("Your charge is still on cooldown!"))
/mob/living/simple_animal/hostile/giant_spider/tarantula/Initialize(mapload)
. = ..()
charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge()
charge.Grant(src)
/mob/living/simple_animal/hostile/giant_spider/tarantula/Destroy()
QDEL_NULL(charge)
return ..()
/mob/living/simple_animal/hostile/giant_spider/tarantula/OpenFire()
if(client)
return
charge.Trigger(target)
/mob/living/simple_animal/hostile/giant_spider/tarantula/Moved(atom/oldloc, dir)
. = ..()
@@ -54,19 +54,6 @@
var/lose_patience_timer_id //id for a timer to call LoseTarget(), used to stop mobs fixating on a target they can't reach
var/lose_patience_timeout = 300 //30 seconds by default, so there's no major changes to AI behaviour, beyond actually bailing if stuck forever
///When a target is found, will the mob attempt to charge at it's target?
var/charger = FALSE
///Tracks if the target is actively charging.
var/charge_state = FALSE
///In a charge, how many tiles will the charger travel?
var/charge_distance = 3
///How often can the charging mob actually charge? Effects the cooldown between charges.
var/charge_frequency = 6 SECONDS
///If the mob is charging, how long will it stun it's target on success, and itself on failure?
var/knockdown_time = 3 SECONDS
///Declares a cooldown for potential charges right off the bat.
COOLDOWN_DECLARE(charge_cooldown)
/mob/living/simple_animal/hostile/Initialize(mapload)
. = ..()
wanted_objects = typecacheof(wanted_objects)
@@ -295,9 +282,6 @@
if(ranged) //We ranged? Shoot at em
if(!target.Adjacent(target_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown
OpenFire(target)
if(charger && (target_distance > minimum_distance) && (target_distance <= charge_distance))//Attempt to close the distance with a charge.
enter_charge(target)
return TRUE
if(!Process_Spacemove()) //Drifting
walk(src,0)
return 1
@@ -604,71 +588,6 @@
else if (M.loc.type in hostile_machines)
. += M.loc
/**
* Proc that handles a charge attack windup for a mob.
*/
/mob/living/simple_animal/hostile/proc/enter_charge(atom/target)
if(charge_state || !(COOLDOWN_FINISHED(src, charge_cooldown)))
return FALSE
if(!can_charge_target(target))
return FALSE
Shake(15, 15, 1 SECONDS)
addtimer(CALLBACK(src, .proc/handle_charge_target, target), 1.5 SECONDS, TIMER_STOPPABLE)
/**
* Proc that checks if the mob can charge attack.
*/
/mob/living/simple_animal/hostile/proc/can_charge_target(atom/target)
if(stat == DEAD || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_IMMOBILIZED) || !has_gravity() || !target.has_gravity())
return FALSE
return TRUE
/**
* Proc that throws the mob at the target after the windup.
*/
/mob/living/simple_animal/hostile/proc/handle_charge_target(atom/target)
if(!can_charge_target(target))
return FALSE
charge_state = TRUE
throw_at(target, charge_distance, 1, src, FALSE, TRUE, callback = CALLBACK(src, .proc/charge_end))
COOLDOWN_START(src, charge_cooldown, charge_frequency)
return TRUE
/**
* Proc that handles a charge attack after it's concluded.
*/
/mob/living/simple_animal/hostile/proc/charge_end()
charge_state = FALSE
/**
* Proc that handles the charge impact of the charging mob.
*/
/mob/living/simple_animal/hostile/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!charge_state)
return ..()
if(hit_atom)
if(isliving(hit_atom))
var/mob/living/L = hit_atom
var/blocked = FALSE
if(ishuman(hit_atom))
var/mob/living/carbon/human/H = hit_atom
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
blocked = TRUE
if(!blocked)
L.visible_message(span_danger("[src] charges on [L]!"), span_userdanger("[src] charges into you!"))
L.Knockdown(knockdown_time)
else
Stun((knockdown_time * 2), ignore_canstun = TRUE)
charge_end()
else if(hit_atom.density && !hit_atom.CanPass(src, get_dir(hit_atom, src)))
visible_message(span_danger("[src] smashes into [hit_atom]!"))
Stun((knockdown_time * 2), ignore_canstun = TRUE)
if(charge_state)
charge_state = FALSE
update_icons()
/mob/living/simple_animal/hostile/proc/get_targets_from()
var/atom/target_from = targets_from.resolve()
if(!target_from)
@@ -1,5 +1,3 @@
#define MINER_DASH_RANGE 4
/*
BLOOD-DRUNK MINER
@@ -35,8 +33,6 @@ Difficulty: Medium
speak_emote = list("roars")
speed = 3
move_to_delay = 3
projectiletype = /obj/projectile/kinetic/miner
projectilesound = 'sound/weapons/kenetic_accel.ogg'
ranged = TRUE
ranged_cooldown_time = 1.6 SECONDS
pixel_x = -16
@@ -51,74 +47,47 @@ Difficulty: Medium
crusher_achievement_type = /datum/award/achievement/boss/blood_miner_crusher
score_achievement_type = /datum/award/score/blood_miner_score
var/obj/item/melee/cleaving_saw/miner/miner_saw
var/time_until_next_transform = 0
var/dashing = FALSE
var/dash_cooldown = 0
var/dash_cooldown_time = 1.5 SECONDS
var/guidance = FALSE
var/transform_stop_attack = FALSE // stops the blood drunk miner from attacking after transforming his weapon until the next attack chain
deathmessage = "falls to the ground, decaying into glowing particles."
deathsound = "bodyfall"
footstep_type = FOOTSTEP_MOB_HEAVY
attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
/datum/action/innate/megafauna_attack/kinetic_accelerator,
/datum/action/innate/megafauna_attack/transform_weapon)
move_force = MOVE_FORCE_NORMAL //Miner beeing able to just move structures like bolted doors and glass looks kinda strange
/// Dash ability
var/datum/action/cooldown/mob_cooldown/dash/dash
/// Kinetic accelerator ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator/kinetic_accelerator
/// Transform weapon ability
var/datum/action/cooldown/mob_cooldown/transform_weapon/transform_weapon
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize(mapload)
. = ..()
miner_saw = new(src)
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
dash = new /datum/action/cooldown/mob_cooldown/dash()
kinetic_accelerator = new /datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator()
transform_weapon = new /datum/action/cooldown/mob_cooldown/transform_weapon()
dash.Grant(src)
kinetic_accelerator.Grant(src)
transform_weapon.Grant(src)
/datum/action/innate/megafauna_attack/dash
name = "Dash To Target"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now dashing to your target.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/kinetic_accelerator
name = "Fire Kinetic Accelerator"
icon_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "<span class='colossus'>You are now shooting your kinetic accelerator.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/transform_weapon
name = "Transform Weapon"
icon_icon = 'icons/obj/lavaland/artefacts.dmi'
button_icon_state = "cleaving_saw"
chosen_message = "<span class='colossus'>You are now transforming your weapon.</span>"
chosen_attack_num = 3
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/update_cooldowns(list/cooldown_updates, ignore_staggered = FALSE)
. = ..()
if(cooldown_updates[COOLDOWN_UPDATE_SET_DASH])
dash_cooldown = world.time + cooldown_updates[COOLDOWN_UPDATE_SET_DASH]
if(cooldown_updates[COOLDOWN_UPDATE_ADD_DASH])
dash_cooldown += cooldown_updates[COOLDOWN_UPDATE_ADD_DASH]
if(cooldown_updates[COOLDOWN_UPDATE_SET_TRANSFORM])
time_until_next_transform = world.time + cooldown_updates[COOLDOWN_UPDATE_SET_TRANSFORM]
if(cooldown_updates[COOLDOWN_UPDATE_ADD_TRANSFORM])
time_until_next_transform += cooldown_updates[COOLDOWN_UPDATE_ADD_TRANSFORM]
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Destroy()
QDEL_NULL(dash)
QDEL_NULL(kinetic_accelerator)
QDEL_NULL(transform_weapon)
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
if(client)
switch(chosen_attack)
if(1)
dash(target)
if(2)
shoot_ka()
if(3)
transform_weapon()
return
Goto(target, move_to_delay, minimum_distance)
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
dash_attack()
if(get_dist(src, target) > 4)
if(dash.Trigger(target))
kinetic_accelerator.StartCooldown(0)
kinetic_accelerator.Trigger(target)
else
shoot_ka()
transform_weapon()
kinetic_accelerator.Trigger(target)
transform_weapon.Trigger(target)
/obj/item/melee/cleaving_saw/miner //nerfed saw because it is very murdery
force = 6
@@ -133,7 +102,7 @@ Difficulty: Medium
damage = 20
speed = 0.9
icon_state = "ka_tracer"
range = MINER_DASH_RANGE
range = 4
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
var/adjustment_amount = amount * 0.1
@@ -147,23 +116,17 @@ Difficulty: Medium
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
if(newloc && newloc.z == z && (islava(newloc) || ischasm(newloc))) //we're not stupid!
return FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
if(dash())
if(dash.Trigger(target))
return FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/MeleeAction(patience = TRUE)
transform_stop_attack = FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
if(client)
transform_stop_attack = FALSE
if(QDELETED(target) || transform_stop_attack)
if(QDELETED(target))
return
face_atom(target)
if(isliving(target))
@@ -195,82 +158,6 @@ Difficulty: Medium
if(. && target && !targets_the_same)
wander = TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash_attack()
INVOKE_ASYNC(src, .proc/dash, target)
shoot_ka()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = ranged_cooldown_time), ignore_staggered = TRUE)
visible_message(span_danger("[src] fires the proto-kinetic accelerator!"))
face_atom(target)
new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
Shoot(target)
changeNext_move(CLICK_CD_RANGE)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
if(world.time < dash_cooldown)
return
var/list/accessable_turfs = list()
var/self_dist_to_target = 0
var/turf/own_turf = get_turf(src)
if(!QDELETED(dash_target))
self_dist_to_target += get_dist(dash_target, own_turf)
for(var/turf/open/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
var/turf_dist_to_target = 0
if(!QDELETED(dash_target))
turf_dist_to_target += get_dist(dash_target, O)
if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
var/valid = TRUE
for(var/turf/T in get_line(own_turf, O))
if(T.is_blocked_turf(TRUE))
valid = FALSE
continue
if(valid)
accessable_turfs[O] = turf_dist_to_target
var/turf/target_turf
if(!QDELETED(dash_target))
var/closest_dist = MINER_DASH_RANGE
for(var/t in accessable_turfs)
if(accessable_turfs[t] < closest_dist)
closest_dist = accessable_turfs[t]
for(var/t in accessable_turfs)
if(accessable_turfs[t] != closest_dist)
accessable_turfs -= t
if(!LAZYLEN(accessable_turfs))
return
update_cooldowns(list(COOLDOWN_UPDATE_SET_DASH = dash_cooldown_time))
target_turf = pick(accessable_turfs)
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
var/obj/effect/temp_visual/decoy/fading/halfsecond/D = new (own_turf, src)
forceMove(step_back_turf)
playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, TRUE, -1)
dashing = TRUE
alpha = 0
animate(src, alpha = 255, time = 5)
SLEEP_CHECK_DEATH(2)
D.forceMove(step_forward_turf)
forceMove(target_turf)
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, TRUE, -1)
SLEEP_CHECK_DEATH(1)
dashing = FALSE
return TRUE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
if(time_until_next_transform <= world.time)
miner_saw.attack_self(src)
if(!miner_saw.is_open)
rapid_melee = 5 // 4 deci cooldown before changes, npcpool subsystem wait is 20, 20/4 = 5
else
rapid_melee = 3 // same thing but halved (slightly rounded up)
transform_stop_attack = TRUE
icon_state = "miner[miner_saw.is_open ? "_transformed":""]"
icon_living = "miner[miner_saw.is_open ? "_transformed":""]"
update_cooldowns(list(COOLDOWN_UPDATE_SET_TRANSFORM = rand(5 SECONDS, 10 SECONDS)))
/obj/effect/temp_visual/dir_setting/miner_death
icon_state = "miner_death"
duration = 15
@@ -298,7 +185,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
. = ..()
if(. && prob(12))
INVOKE_ASYNC(src, .proc/dash)
INVOKE_ASYNC(dash, /datum/action/proc/Trigger, target)
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom
name = "hostile-environment miner"
@@ -306,6 +193,7 @@ Difficulty: Medium
speed = 8
move_to_delay = 8
ranged_cooldown_time = 0.8 SECONDS
dash_cooldown = 0.8 SECONDS
#undef MINER_DASH_RANGE
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom/Initialize(mapload)
. = ..()
dash.cooldown_time = 0.8 SECONDS
@@ -59,55 +59,51 @@ Difficulty: Hard
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
var/charging = FALSE
var/enrage_till = 0
var/enrage_time = 7 SECONDS
var/revving_charge = FALSE
gps_name = "Bloody Signal"
achievement_type = /datum/award/achievement/boss/bubblegum_kill
crusher_achievement_type = /datum/award/achievement/boss/bubblegum_crusher
score_achievement_type = /datum/award/score/bubblegum_score
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
deathsound = 'sound/magic/enter_blood.ogg'
attack_action_types = list(/datum/action/innate/megafauna_attack/triple_charge,
/datum/action/innate/megafauna_attack/hallucination_charge,
/datum/action/innate/megafauna_attack/hallucination_surround,
/datum/action/innate/megafauna_attack/blood_warp)
small_sprite_type = /datum/action/small_sprite/megafauna/bubblegum
faction = list("mining", "boss", "hell")
/// Check to see if we should spawn blood
var/spawn_blood = TRUE
/// Actual time where enrage ends
var/enrage_till = 0
/// Duration of enrage ability
var/enrage_time = 7 SECONDS
/// Triple charge ability
var/datum/action/cooldown/mob_cooldown/charge/triple_charge/triple_charge
/// Hallucination charge ability
var/datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hallucination_charge
/// Hallucination charge surround ability
var/datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hallucination_surround/hallucination_charge_surround
/// Blood warp ability
var/datum/action/cooldown/mob_cooldown/blood_warp/blood_warp
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize(mapload)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
triple_charge = new /datum/action/cooldown/mob_cooldown/charge/triple_charge()
hallucination_charge = new /datum/action/cooldown/mob_cooldown/charge/hallucination_charge()
hallucination_charge_surround = new /datum/action/cooldown/mob_cooldown/charge/hallucination_charge/hallucination_surround()
blood_warp = new /datum/action/cooldown/mob_cooldown/blood_warp()
triple_charge.Grant(src)
hallucination_charge.Grant(src)
hallucination_charge_surround.Grant(src)
blood_warp.Grant(src)
hallucination_charge.spawn_blood = TRUE
hallucination_charge_surround.spawn_blood = TRUE
RegisterSignal(src, COMSIG_BLOOD_WARP, .proc/blood_enrage)
RegisterSignal(src, COMSIG_FINISHED_CHARGE, .proc/after_charge)
/datum/action/innate/megafauna_attack/triple_charge
name = "Triple Charge"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now triple charging at the target you click on.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/hallucination_charge
name = "Hallucination Charge"
icon_icon = 'icons/effects/bubblegum.dmi'
button_icon_state = "smack ya one"
chosen_message = "<span class='colossus'>You are now charging with hallucinations at the target you click on.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/hallucination_surround
name = "Surround Target"
icon_icon = 'icons/turf/walls/wall.dmi'
button_icon_state = "wall-0"
chosen_message = "<span class='colossus'>You are now surrounding the target you click on with hallucinations.</span>"
chosen_attack_num = 3
/datum/action/innate/megafauna_attack/blood_warp
name = "Blood Warp"
icon_icon = 'icons/effects/blood.dmi'
button_icon_state = "floor1"
chosen_message = "<span class='colossus'>You are now warping to blood around your clicked position.</span>"
chosen_attack_num = 4
/mob/living/simple_animal/hostile/megafauna/bubblegum/Destroy()
QDEL_NULL(triple_charge)
QDEL_NULL(hallucination_charge)
QDEL_NULL(hallucination_charge_surround)
QDEL_NULL(blood_warp)
return ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/update_cooldowns(list/cooldown_updates, ignore_staggered = FALSE)
. = ..()
@@ -117,94 +113,25 @@ Difficulty: Hard
enrage_till += cooldown_updates[COOLDOWN_UPDATE_ADD_ENRAGE]
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
if(charging)
return
anger_modifier = clamp(((maxHealth - health)/60),0,20)
enrage_time = initial(enrage_time) * clamp(anger_modifier / 20, 0.5, 1)
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 5 SECONDS))
if(client)
switch(chosen_attack)
if(1)
triple_charge()
if(2)
hallucination_charge()
if(3)
surround_with_hallucinations()
if(4)
blood_warp()
return
if(!try_bloodattack() || prob(25 + anger_modifier))
blood_warp()
blood_warp.Trigger(target)
if(!BUBBLEGUM_SMASH)
triple_charge()
triple_charge.Trigger(target)
else
if(prob(50 + anger_modifier))
hallucination_charge()
hallucination_charge.Trigger(target)
else
surround_with_hallucinations()
hallucination_charge_surround.Trigger(target)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
charge(delay = 6)
charge(delay = 4)
charge(delay = 2)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 1.5 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 1.5 SECONDS))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge()
if(!BUBBLEGUM_SMASH || prob(33))
hallucination_charge_around(times = 6, delay = 8)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 1 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 1 SECONDS))
else
hallucination_charge_around(times = 4, delay = 9)
hallucination_charge_around(times = 4, delay = 8)
hallucination_charge_around(times = 4, delay = 7)
triple_charge()
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 2 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 2 SECONDS))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/surround_with_hallucinations()
for(var/i = 1 to 5)
INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 8, 2, 0, 4)
if(ismob(target))
charge(delay = 6)
else
SLEEP_CHECK_DEATH(6)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 2 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 2 SECONDS))
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(atom/chargeat = target, delay = 3, chargepast = 2)
if(!chargeat)
return
var/chargeturf = get_turf(chargeat)
if(!chargeturf)
return
var/dir = get_dir(src, chargeturf)
var/turf/T = get_ranged_target_turf(chargeturf, dir, chargepast)
if(!T)
return
new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
charging = TRUE
revving_charge = TRUE
DestroySurroundings()
walk(src, 0)
setDir(dir)
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc,src)
animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
SLEEP_CHECK_DEATH(delay)
revving_charge = FALSE
var/movespeed = 0.7
walk_towards(src, T, movespeed)
SLEEP_CHECK_DEATH(get_dist(src, T) * movespeed)
walk(src, 0) // cancel the movement
try_bloodattack()
charging = FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
var/list/targets = ListTargets()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood(mob/target)
var/list/targets = list(target)
. = list()
for(var/mob/living/L in targets)
var/list/bloodpool = get_pools(get_turf(L), 0)
var/list/bloodpool = get_bloodcrawlable_pools(get_turf(L), 0)
if(bloodpool.len && (!faction_check_mob(L) || L.stat == DEAD))
. += L
@@ -243,7 +170,7 @@ Difficulty: Hard
bloodsmack(target_two_turf, handedness)
if(target_one)
var/list/pools = get_pools(get_turf(target_one), 0)
var/list/pools = get_bloodcrawlable_pools(get_turf(target_one), 0)
if(pools.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
@@ -253,7 +180,7 @@ Difficulty: Hard
bloodsmack(target_one_turf, !handedness)
if(!target_two && target_one)
var/list/poolstwo = get_pools(get_turf(target_one), 0)
var/list/poolstwo = get_bloodcrawlable_pools(get_turf(target_one), 0)
if(poolstwo.len)
target_one_turf = get_turf(target_one)
if(target_one_turf)
@@ -267,14 +194,14 @@ Difficulty: Hard
new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
else
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
SLEEP_CHECK_DEATH(4)
SLEEP_CHECK_DEATH(4, src)
for(var/mob/living/L in T)
if(!faction_check_mob(L))
to_chat(L, span_userdanger("[src] rends you!"))
playsound(T, attack_sound, 100, TRUE, -1)
var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
L.apply_damage(10, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, MELEE, null, null, armour_penetration), wound_bonus = CANT_WOUND)
SLEEP_CHECK_DEATH(3)
SLEEP_CHECK_DEATH(3, src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
if(handedness)
@@ -283,7 +210,7 @@ Difficulty: Hard
else
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
SLEEP_CHECK_DEATH(6)
SLEEP_CHECK_DEATH(6, src)
for(var/mob/living/L in T)
if(!faction_check_mob(L))
if(L.stat != CONSCIOUS)
@@ -293,45 +220,8 @@ Difficulty: Hard
L.forceMove(targetturf)
playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, TRUE, -1)
addtimer(CALLBACK(src, .proc/devour, L), 2)
SLEEP_CHECK_DEATH(1)
SLEEP_CHECK_DEATH(1, src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
if(Adjacent(target))
return FALSE
var/list/can_jaunt = get_pools(get_turf(src), 1)
if(!can_jaunt.len)
return FALSE
var/list/pools = get_pools(get_turf(target), 5)
var/list/pools_to_remove = get_pools(get_turf(target), 4)
pools -= pools_to_remove
if(!pools.len)
return FALSE
var/obj/effect/temp_visual/decoy/DA = new /obj/effect/temp_visual/decoy(loc,src)
DA.color = "#FF0000"
var/oldtransform = DA.transform
DA.transform = matrix()*2
animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
SLEEP_CHECK_DEATH(3)
qdel(DA)
var/obj/effect/decal/cleanable/blood/found_bloodpool
pools = get_pools(get_turf(target), 5)
pools_to_remove = get_pools(get_turf(target), 4)
pools -= pools_to_remove
if(pools.len)
shuffle_inplace(pools)
found_bloodpool = pick(pools)
if(found_bloodpool)
visible_message(span_danger("[src] sinks into the blood..."))
playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, TRUE, -1)
forceMove(get_turf(found_bloodpool))
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, TRUE, -1)
visible_message(span_danger("And springs back out!"))
blood_enrage()
return TRUE
return FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/be_aggressive()
@@ -339,7 +229,6 @@ Difficulty: Hard
return TRUE
return isliving(target) && HAS_TRAIT(target, TRAIT_INCAPACITATED)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_retreat_distance()
return (be_aggressive() ? null : initial(retreat_distance))
@@ -351,15 +240,20 @@ Difficulty: Hard
minimum_distance = get_minimum_distance()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage()
SIGNAL_HANDLER
if(!BUBBLEGUM_CAN_ENRAGE)
return FALSE
update_cooldowns(list(COOLDOWN_UPDATE_SET_ENRAGE = enrage_time))
enrage_till = world.time + enrage_time
update_approach()
change_move_delay(3.75)
INVOKE_ASYNC(src, .proc/change_move_delay, 3.75)
add_atom_colour(COLOR_BUBBLEGUM_RED, TEMPORARY_COLOUR_PRIORITY)
var/datum/callback/cb = CALLBACK(src, .proc/blood_enrage_end)
addtimer(cb, enrage_time)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/after_charge()
SIGNAL_HANDLER
try_bloodattack()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end()
update_approach()
change_move_delay()
@@ -370,46 +264,11 @@ Difficulty: Hard
set_varspeed(move_to_delay)
handle_automated_action() // need to recheck movement otherwise move_to_delay won't update until the next checking aka will be wrong speed for a bit
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
. = list()
for(var/obj/effect/decal/cleanable/nearby in view(T, range))
if(nearby.can_bloodcrawl_in())
. += nearby
/obj/effect/decal/cleanable/blood/bubblegum
bloodiness = 0
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge_around(times = 4, delay = 6, chargepast = 0, useoriginal = 1, radius)
var/startingangle = rand(1, 360)
if(!target)
return
var/turf/chargeat = get_turf(target)
var/srcplaced = FALSE
if(!radius)
radius = times
for(var/i = 1 to times)
var/ang = (startingangle + 360/times * i)
if(!chargeat)
return
var/turf/place = locate(chargeat.x + cos(ang) * radius, chargeat.y + sin(ang) * radius, chargeat.z)
if(!place)
continue
if(!nest || nest && nest.parent && get_dist(nest.parent, place) <= nest_range)
if(!srcplaced && useoriginal)
forceMove(place)
srcplaced = TRUE
continue
var/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/B = new /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination(src.loc)
B.forceMove(place)
INVOKE_ASYNC(B, .proc/charge, chargeat, delay, chargepast)
if(useoriginal)
charge(chargeat, delay, chargepast)
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
. = ..()
anger_modifier = clamp(((maxHealth - health)/60),0,20)
enrage_time = initial(enrage_time) * clamp(anger_modifier / 20, 0.5, 1)
hallucination_charge.enraged = BUBBLEGUM_SMASH
if(. > 0 && prob(25))
var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
if(prob(40))
@@ -417,29 +276,15 @@ Difficulty: Hard
else
B.setDir(pick(GLOB.cardinals))
/obj/effect/decal/cleanable/blood/gibs/bubblegum
name = "thick blood"
desc = "Thick, splattered blood."
random_icon_states = list("gib3", "gib5", "gib6")
bloodiness = 20
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/grant_achievement(medaltype,scoretype)
. = ..()
if(!(flags_1 & ADMIN_SPAWNED_1))
SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_BUBBLEGUM] = TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
if(!charging)
. = ..()
if(.)
update_cooldowns(list(COOLDOWN_UPDATE_ADD_MELEE = 2 SECONDS)) // can only attack melee once every 2 seconds but rapid_melee gives higher priority
. = ..()
if(.)
recovery_time = world.time + 20 // can only attack melee once every 2 seconds but rapid_melee gives higher priority
/mob/living/simple_animal/hostile/megafauna/bubblegum/bullet_act(obj/projectile/P)
if(BUBBLEGUM_IS_ENRAGED)
@@ -455,53 +300,70 @@ Difficulty: Hard
severity = EXPLODE_LIGHT // puny mortals
return ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
if(!charging)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
update_approach()
if(revving_charge)
return FALSE
if(charging)
new /obj/effect/temp_visual/decoy/fading(loc,src)
DestroySurroundings()
..()
. = ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved(atom/OldLoc, Dir, Forced = FALSE)
if(Dir)
. = ..()
if(spawn_blood)
new /obj/effect/decal/cleanable/blood/bubblegum(src.loc)
if(charging)
DestroySurroundings()
playsound(src, 'sound/effects/meteorimpact.ogg', 200, TRUE, 2, TRUE)
return ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
if(charging)
if(isturf(A) || isobj(A) && A.density)
if(isobj(A))
SSexplosions.med_mov_atom += A
else
SSexplosions.medturf += A
DestroySurroundings()
if(isliving(A))
var/mob/living/L = A
L.visible_message(span_danger("[src] slams into [L]!"), span_userdanger("[src] tramples you into the ground!"))
src.forceMove(get_turf(L))
L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE, wound_bonus = CANT_WOUND)
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, TRUE)
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination
name = "bubblegum's hallucination"
desc = "Is that really just a hallucination?"
health = 1
maxHealth = 1
alpha = 127.5
crusher_loot = null
loot = null
achievement_type = null
crusher_achievement_type = null
score_achievement_type = null
deathmessage = "Explodes into a pool of blood!"
deathsound = 'sound/effects/splat.ogg'
true_spawn = FALSE
var/move_through_mob
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize()
. = ..()
toggle_ai(AI_OFF)
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Destroy()
if(spawn_blood)
new /obj/effect/decal/cleanable/blood(get_turf(src))
. = ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life(delta_time = SSMOBS_DT, times_fired)
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
return
/obj/effect/decal/cleanable/blood/bubblegum
bloodiness = 0
/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
return TRUE
/obj/effect/decal/cleanable/blood/gibs/bubblegum
name = "thick blood"
desc = "Thick, splattered blood."
random_icon_states = list("gib3", "gib5", "gib6")
bloodiness = 20
/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
return TRUE
/obj/effect/temp_visual/dragon_swoop/bubblegum
duration = 10
@@ -529,50 +391,3 @@ Difficulty: Hard
/obj/effect/temp_visual/bubblegum_hands/leftsmack
icon_state = "leftsmack"
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination
name = "bubblegum's hallucination"
desc = "Is that really just a hallucination?"
health = 1
maxHealth = 1
alpha = 127.5
crusher_loot = null
loot = null
achievement_type = null
crusher_achievement_type = null
score_achievement_type = null
deathmessage = "Explodes into a pool of blood!"
deathsound = 'sound/effects/splat.ogg'
true_spawn = FALSE
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize(mapload)
. = ..()
toggle_ai(AI_OFF)
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/charge(atom/chargeat = target, delay = 3, chargepast = 2)
..()
qdel(src)
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Destroy()
new /obj/effect/decal/cleanable/blood(get_turf(src))
. = ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
return TRUE
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life(delta_time = SSMOBS_DT, times_fired)
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/OpenFire()
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/AttackingTarget()
return
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
return
@@ -1,3 +1,5 @@
#define COLOSSUS_ENRAGED (health < maxHealth/3)
/**
* COLOSSUS
*
@@ -51,80 +53,83 @@
loot = list(/obj/structure/closet/crate/necropolis/colossus)
deathmessage = "disintegrates, leaving a glowing core in its wake."
deathsound = 'sound/magic/demon_dies.ogg'
attack_action_types = list(/datum/action/innate/megafauna_attack/spiral_attack,
/datum/action/innate/megafauna_attack/aoe_attack,
/datum/action/innate/megafauna_attack/shotgun,
/datum/action/innate/megafauna_attack/alternating_cardinals)
small_sprite_type = /datum/action/small_sprite/megafauna/colossus
/// Spiral shots ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/spiral_shots
/// Random shots ablity
var/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/random_shots
/// Shotgun blast ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/shotgun_blast
/// Directional shots ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/dir_shots
/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.Grant(src)
random_shots.Grant(src)
shotgun_blast.Grant(src)
dir_shots.Grant(src)
RegisterSignal(src, COMSIG_ABILITY_STARTED, .proc/start_attack)
RegisterSignal(src, COMSIG_ABILITY_FINISHED, .proc/finished_attack)
/datum/action/innate/megafauna_attack/spiral_attack
name = "Spiral Shots"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now firing in a spiral.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/aoe_attack
name = "All Directions"
icon_icon = 'icons/effects/effects.dmi'
button_icon_state = "at_shield2"
chosen_message = "<span class='colossus'>You are now firing in all directions.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/shotgun
name = "Shotgun Fire"
icon_icon = 'icons/obj/guns/ballistic.dmi'
button_icon_state = "shotgun"
chosen_message = "<span class='colossus'>You are now firing shotgun shots where you aim.</span>"
chosen_attack_num = 3
/datum/action/innate/megafauna_attack/alternating_cardinals
name = "Alternating Shots"
icon_icon = 'icons/obj/guns/ballistic.dmi'
button_icon_state = "pistol"
chosen_message = "<span class='colossus'>You are now firing in alternating cardinal directions.</span>"
chosen_attack_num = 4
/mob/living/simple_animal/hostile/megafauna/colossus/Destroy()
QDEL_NULL(spiral_shots)
QDEL_NULL(random_shots)
QDEL_NULL(shotgun_blast)
QDEL_NULL(dir_shots)
return ..()
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
anger_modifier = clamp(((maxHealth - health)/50),0,20)
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 12 SECONDS))
if(client)
switch(chosen_attack)
if(1)
select_spiral_attack()
if(2)
random_shots()
if(3)
blast()
if(4)
alternating_dir_shots()
return
if(enrage(target))
if(move_to_delay == initial(move_to_delay))
visible_message(span_colossus("\"<b>You can't dodge.</b>\""))
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
ranged_cooldown = world.time + 30
telegraph()
dir_shots(GLOB.alldirs)
dir_shots.fire_in_directions(src, target, GLOB.alldirs)
move_to_delay = 3
return
else
move_to_delay = initial(move_to_delay)
if(prob(20+anger_modifier)) //Major attack
select_spiral_attack()
spiral_shots.Trigger(target)
else if(prob(20))
random_shots()
random_shots.Trigger(target)
else
if(prob(70))
blast()
shotgun_blast.Trigger(target)
else
alternating_dir_shots()
dir_shots.Trigger(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)
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)
SIGNAL_HANDLER
if(activated == spiral_shots)
spiral_shots.enraged = COLOSSUS_ENRAGED
telegraph()
icon_state = "eva_attack"
visible_message(COLOSSUS_ENRAGED ? span_colossus("\"<b>Die.</b>\"") : span_colossus("\"<b>Judgement.</b>\""))
/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))
@@ -135,95 +140,6 @@
if (is_species(H, /datum/species/golem/sand))
. = TRUE
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 4 SECONDS))
dir_shots(GLOB.diagonals)
SLEEP_CHECK_DEATH(10)
dir_shots(GLOB.cardinals)
SLEEP_CHECK_DEATH(10)
dir_shots(GLOB.diagonals)
SLEEP_CHECK_DEATH(10)
dir_shots(GLOB.cardinals)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/select_spiral_attack()
telegraph()
icon_state = "eva_attack"
if(health < maxHealth/3)
return double_spiral()
visible_message(span_colossus("\"<b>Judgement.</b>\""))
return spiral_shoot()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
visible_message(span_colossus("\"<b>Die.</b>\""))
SLEEP_CHECK_DEATH(10)
INVOKE_ASYNC(src, .proc/spiral_shoot, FALSE)
INVOKE_ASYNC(src, .proc/spiral_shoot, TRUE)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = pick(TRUE, FALSE), counter_start = 8)
var/turf/start_turf = get_step(src, pick(GLOB.alldirs))
var/counter = counter_start
for(var/i in 1 to 80)
if(negative)
counter--
else
counter++
if(counter > 16)
counter = 1
if(counter < 1)
counter = 16
shoot_projectile(start_turf, counter * 22.5)
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
SLEEP_CHECK_DEATH(1)
icon_state = initial(icon_state)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker, set_angle)
if(!isnum(set_angle) && (!marker || marker == loc))
return
var/turf/startloc = get_turf(src)
var/obj/projectile/P = new /obj/projectile/colossus(startloc)
P.preparePixelProjectile(marker, startloc)
P.firer = src
if(target)
P.original = target
P.fire(set_angle)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
var/turf/U = get_turf(src)
playsound(U, 'sound/magic/clockwork/invoke_general.ogg', 300, TRUE, 5)
for(var/T in RANGE_TURFS(12, U) - U)
if(prob(5))
shoot_projectile(T)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast(set_angle)
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = 2 SECONDS))
var/turf/target_turf = get_turf(target)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 2)
newtonian_move(get_dir(target_turf, src))
var/angle_to_target = get_angle(src, target_turf)
if(isnum(set_angle))
angle_to_target = set_angle
var/static/list/colossus_shotgun_shot_angles = list(12.5, 7.5, 2.5, -2.5, -7.5, -12.5)
for(var/i in colossus_shotgun_shot_angles)
shoot_projectile(target_turf, angle_to_target + i)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
if(!islist(dirs))
dirs = GLOB.alldirs.Copy()
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 2)
for(var/d in dirs)
var/turf/E = get_step(src, d)
shoot_projectile(E)
/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)
playsound(src, 'sound/magic/clockwork/narsie_attack.ogg', 200, TRUE)
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
visible_message(span_colossus("[src] disintegrates [L]!"))
L.dust()
@@ -1,3 +1,4 @@
#define FROST_MINER_SHOULD_ENRAGE (health <= maxHealth*0.25 && !enraged)
GLOBAL_LIST_EMPTY(frost_miner_prisms)
/*
@@ -42,58 +43,40 @@ Difficulty: Extremely Hard
deathmessage = "falls to the ground, decaying into plasma particles."
deathsound = "bodyfall"
footstep_type = FOOTSTEP_MOB_HEAVY
attack_action_types = list(/datum/action/innate/megafauna_attack/frost_orbs,
/datum/action/innate/megafauna_attack/snowball_machine_gun,
/datum/action/innate/megafauna_attack/ice_shotgun)
/// Modifies the speed of the projectiles the demonic frost miner shoots out
var/projectile_speed_multiplier = 1
/// If the demonic frost miner is in its enraged state
var/enraged = FALSE
/// If the demonic frost miner is currently transforming to its enraged state
var/enraging = FALSE
/// Frost orbs ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel/frost_orbs
/// Snowball Machine gun Ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/snowball_machine_gun
/// Ice Shotgun Ability
var/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern/ice_shotgun
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Initialize(mapload)
. = ..()
frost_orbs = new /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel()
snowball_machine_gun = new /datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire()
ice_shotgun = new /datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern()
frost_orbs.Grant(src)
snowball_machine_gun.Grant(src)
ice_shotgun.Grant(src)
for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms)
prism_to_set.set_prism_light(LIGHT_COLOR_BLUE, 5)
RegisterSignal(src, COMSIG_ABILITY_STARTED, .proc/start_attack)
AddElement(/datum/element/knockback, 7, FALSE, TRUE)
AddElement(/datum/element/lifesteal, 50)
ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, INNATE_TRAIT)
/datum/action/innate/megafauna_attack/frost_orbs
name = "Fire Frost Orbs"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now sending out frost orbs to track in on a target.</span>"
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/snowball_machine_gun
name = "Fire Snowball Machine Gun"
icon_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "<span class='colossus'>You are now firing a snowball machine gun at a target.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/ice_shotgun
name = "Fire Ice Shotgun"
icon_icon = 'icons/obj/guns/ballistic.dmi'
button_icon_state = "shotgun"
chosen_message = "<span class='colossus'>You are now firing shotgun ice blasts.</span>"
chosen_attack_num = 3
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Destroy()
QDEL_NULL(frost_orbs)
QDEL_NULL(snowball_machine_gun)
QDEL_NULL(ice_shotgun)
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/OpenFire()
check_enraged()
projectile_speed_multiplier = 1 - enraged * 0.5
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 10 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 10 SECONDS))
if(client)
switch(chosen_attack)
if(1)
frost_orbs()
if(2)
snowball_machine_gun()
if(3)
ice_shotgun()
return
var/easy_attack = prob(80 - enraged * 40)
@@ -101,20 +84,107 @@ Difficulty: Extremely Hard
switch(chosen_attack)
if(1)
if(easy_attack)
frost_orbs(10, 8)
frost_orbs.shot_count = 8
frost_orbs.shot_delay = 10
frost_orbs.Trigger(target)
else
frost_orbs(5, 16)
frost_orbs.shot_count = 16
frost_orbs.shot_delay = 5
frost_orbs.Trigger(target)
if(2)
if(easy_attack)
snowball_machine_gun()
else
INVOKE_ASYNC(src, .proc/ice_shotgun, 5, list(list(-180, -140, -100, -60, -20, 20, 60, 100, 140), list(-160, -120, -80, -40, 0, 40, 80, 120, 160)))
snowball_machine_gun(5 * 8, 5)
snowball_machine_gun.shot_count = 60
snowball_machine_gun.default_projectile_spread = 45
snowball_machine_gun.Trigger(target)
else if(ice_shotgun.IsAvailable())
ice_shotgun.shot_angles = list(list(-180, -140, -100, -60, -20, 20, 60, 100, 140), list(-160, -120, -80, -40, 0, 40, 80, 120, 160))
INVOKE_ASYNC(ice_shotgun, /datum/action/proc/Trigger, target)
snowball_machine_gun.shot_count = 5 * 8
snowball_machine_gun.default_projectile_spread = 5
snowball_machine_gun.StartCooldown(0)
snowball_machine_gun.Trigger(target)
if(3)
if(easy_attack)
ice_shotgun()
// static lists? remind me later
ice_shotgun.shot_angles = list(list(-40, -20, 0, 20, 40), list(-30, -10, 10, 30))
ice_shotgun.Trigger(target)
else
ice_shotgun(5, list(list(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330), list(-30, -15, 0, 15, 30)))
ice_shotgun.shot_angles = list(list(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330), list(-30, -15, 0, 15, 30))
ice_shotgun.Trigger(target)
/// Pre-ability usage stuff
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/start_attack(mob/living/owner, datum/action/cooldown/activated)
SIGNAL_HANDLER
if(enraging)
return COMPONENT_BLOCK_ABILITY_START
if(FROST_MINER_SHOULD_ENRAGE)
INVOKE_ASYNC(src, .proc/check_enraged)
return COMPONENT_BLOCK_ABILITY_START
var/projectile_speed_multiplier = 1 - enraged * 0.5
frost_orbs.projectile_speed_multiplier = projectile_speed_multiplier
snowball_machine_gun.projectile_speed_multiplier = projectile_speed_multiplier
ice_shotgun.projectile_speed_multiplier = projectile_speed_multiplier
/// Checks if the demonic frost miner is ready to be enraged
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/check_enraged()
if(!FROST_MINER_SHOULD_ENRAGE)
return
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 8 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 8 SECONDS))
frost_orbs.StartCooldown(8 SECONDS)
adjustHealth(-maxHealth)
enraged = TRUE
enraging = TRUE
animate(src, pixel_y = pixel_y + 96, time = 100, easing = ELASTIC_EASING)
spin(100, 10)
SLEEP_CHECK_DEATH(60, src)
playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE)
icon_state = "demonic_miner_phase2"
animate(src, pixel_y = pixel_y - 96, time = 8, flags = ANIMATION_END_NOW)
spin(8, 2)
for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms)
prism_to_set.set_prism_light(LIGHT_COLOR_PURPLE, 5)
SLEEP_CHECK_DEATH(8, src)
for(var/mob/living/L in viewers(src))
shake_camera(L, 3, 2)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
ADD_TRAIT(src, TRAIT_MOVE_FLYING, FROSTMINER_ENRAGE_TRAIT)
enraging = FALSE
adjustHealth(-maxHealth)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/ex_act(severity, target)
adjustBruteLoss(-30 * severity)
visible_message(span_danger("[src] absorbs the explosion!"), span_userdanger("You absorb the explosion!"))
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Goto(target, delay, minimum_distance)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/MoveToTarget(list/possible_targets)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Move()
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/death(gibbed, list/force_grant)
if(health > 0)
return
var/turf/T = get_turf(src)
var/loot = rand(1, 3)
for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms)
prism_to_set.set_prism_light(COLOR_GRAY, 1)
switch(loot)
if(1)
new /obj/item/resurrection_crystal(T)
if(2)
new /obj/item/clothing/shoes/winterboots/ice_boots/ice_trail(T)
if(3)
new /obj/item/pickaxe/drill/jackhammer/demonic(T)
return ..()
/obj/projectile/colossus/frost_orb
name = "frost orb"
@@ -152,139 +222,6 @@ Difficulty: Extremely Hard
if(isturf(target) || isobj(target))
target.ex_act(EXPLODE_HEAVY)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/ex_act(severity, target)
adjustBruteLoss(-30 * severity)
visible_message(span_danger("[src] absorbs the explosion!"), span_userdanger("You absorb the explosion!"))
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Goto(target, delay, minimum_distance)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/MoveToTarget(list/possible_targets)
if(enraging)
return
return ..()
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/Move()
if(enraging)
return
return ..()
/// Shoots out homing frost orbs that explode into ice blast projectiles after a couple seconds
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/frost_orbs(added_delay = 10, shoot_times = 8)
for(var/i in 1 to shoot_times)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/projectile/colossus/frost_orb/P = new(startloc)
P.preparePixelProjectile(endloc, startloc)
P.firer = src
if(target)
P.original = target
P.set_homing_target(target)
P.fire(rand(0, 360))
addtimer(CALLBACK(P, /obj/projectile/colossus/frost_orb/proc/orb_explosion, projectile_speed_multiplier), 20) // make the orbs home in after a second
SLEEP_CHECK_DEATH(added_delay)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 4 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 6 SECONDS))
/// Called when the orb is exploding, shoots out projectiles
/obj/projectile/colossus/frost_orb/proc/orb_explosion(projectile_speed_multiplier)
for(var/i in 0 to 5)
var/angle = i * 60
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(original)
if(!startloc || !endloc)
break
var/obj/projectile/colossus/ice_blast/P = new(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, angle + rand(-10, 10))
P.firer = firer
if(original)
P.original = original
P.fire()
qdel(src)
/// Shoots out snowballs with a random spread
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/snowball_machine_gun(shots = 60, spread = 45)
for(var/i in 1 to shots)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/projectile/P = new /obj/projectile/colossus/snowball(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, rand(-spread, spread))
P.firer = src
if(target)
P.original = target
P.fire()
SLEEP_CHECK_DEATH(1)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 1.5 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 1.5 SECONDS))
/// Shoots out ice blasts in a shotgun like pattern
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/ice_shotgun(shots = 5, list/patterns = list(list(-40, -20, 0, 20, 40), list(-30, -10, 10, 30)))
for(var/i in 1 to shots)
var/list/pattern = patterns[i % length(patterns) + 1] // alternating patterns
for(var/spread in pattern)
var/turf/startloc = get_turf(src)
var/turf/endloc = get_turf(target)
if(!endloc)
break
var/obj/projectile/P = new /obj/projectile/colossus/ice_blast(startloc)
P.speed *= projectile_speed_multiplier
P.preparePixelProjectile(endloc, startloc, null, spread)
P.firer = src
if(target)
P.original = target
P.fire()
SLEEP_CHECK_DEATH(8)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 1.5 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 2 SECONDS))
/// Checks if the demonic frost miner is ready to be enraged
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/proc/check_enraged()
if(enraged)
return
if(health > maxHealth*0.25)
return
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 8 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 8 SECONDS))
adjustHealth(-maxHealth)
enraged = TRUE
enraging = TRUE
animate(src, pixel_y = pixel_y + 96, time = 100, easing = ELASTIC_EASING)
spin(100, 10)
SLEEP_CHECK_DEATH(60)
playsound(src, 'sound/effects/explosion3.ogg', 100, TRUE)
icon_state = "demonic_miner_phase2"
animate(src, pixel_y = pixel_y - 96, time = 8, flags = ANIMATION_END_NOW)
spin(8, 2)
for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms)
prism_to_set.set_prism_light(LIGHT_COLOR_PURPLE, 5)
SLEEP_CHECK_DEATH(8)
for(var/mob/living/L in viewers(src))
shake_camera(L, 3, 2)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
ADD_TRAIT(src, TRAIT_MOVE_FLYING, FROSTMINER_ENRAGE_TRAIT)
enraging = FALSE
adjustHealth(-maxHealth)
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner/death(gibbed, list/force_grant)
if(health > 0)
return
var/turf/T = get_turf(src)
var/loot = rand(1, 3)
for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms)
prism_to_set.set_prism_light(COLOR_GRAY, 1)
switch(loot)
if(1)
new /obj/item/resurrection_crystal(T)
if(2)
new /obj/item/clothing/shoes/winterboots/ice_boots/ice_trail(T)
if(3)
new /obj/item/pickaxe/drill/jackhammer/demonic(T)
return ..()
/obj/item/resurrection_crystal
name = "resurrection crystal"
desc = "When used by anything holding it, this crystal gives them a second chance at life if they die."
@@ -1,13 +1,12 @@
#define DRAKE_SWOOP_HEIGHT 270 //how high up drakes go, in pixels
#define DRAKE_SWOOP_DIRECTION_CHANGE_RANGE 5 //the range our x has to be within to not change the direction we slam from
#define SWOOP_DAMAGEABLE 1
#define SWOOP_INVULNERABLE 2
///used whenever the drake generates a hotspot
#define DRAKE_FIRE_TEMP 500
///used whenever the drake generates a hotspot
#define DRAKE_FIRE_EXPOSURE 50
///used to see if the drake is enraged or not
#define DRAKE_ENRAGED (health < maxHealth*0.5)
#define SWOOP_DAMAGEABLE 1
#define SWOOP_INVULNERABLE 2
/*£
*
@@ -72,211 +71,100 @@
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
deathsound = 'sound/magic/demon_dies.ogg'
footstep_type = FOOTSTEP_MOB_HEAVY
attack_action_types = list(/datum/action/innate/megafauna_attack/fire_cone,
/datum/action/innate/megafauna_attack/fire_cone_meteors,
/datum/action/innate/megafauna_attack/mass_fire,
/datum/action/innate/megafauna_attack/lava_swoop)
small_sprite_type = /datum/action/small_sprite/megafauna/drake
/// Fire cone ability
var/datum/action/cooldown/mob_cooldown/fire_breath/cone/fire_cone
/// Meteors ability
var/datum/action/cooldown/mob_cooldown/meteors/meteors
/// Mass fire ability
var/datum/action/cooldown/mob_cooldown/fire_breath/mass_fire/mass_fire
/// Lava swoop ability
var/datum/action/cooldown/mob_cooldown/lava_swoop/lava_swoop
/datum/action/innate/megafauna_attack/fire_cone
name = "Fire Cone"
icon_icon = 'icons/obj/wizard.dmi'
button_icon_state = "fireball"
chosen_message = "<span class='colossus'>You are now shooting fire at your target.</span>"
chosen_attack_num = 1
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
. = ..()
fire_cone = new /datum/action/cooldown/mob_cooldown/fire_breath/cone()
meteors = new /datum/action/cooldown/mob_cooldown/meteors()
mass_fire = new /datum/action/cooldown/mob_cooldown/fire_breath/mass_fire()
lava_swoop = new /datum/action/cooldown/mob_cooldown/lava_swoop()
fire_cone.Grant(src)
meteors.Grant(src)
mass_fire.Grant(src)
lava_swoop.Grant(src)
RegisterSignal(src, COMSIG_ABILITY_STARTED, .proc/start_attack)
RegisterSignal(src, COMSIG_ABILITY_FINISHED, .proc/finished_attack)
RegisterSignal(src, COMSIG_SWOOP_INVULNERABILITY_STARTED, .proc/swoop_invulnerability_started)
RegisterSignal(src, COMSIG_LAVA_ARENA_FAILED, .proc/on_arena_fail)
/datum/action/innate/megafauna_attack/fire_cone_meteors
name = "Fire Cone With Meteors"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "<span class='colossus'>You are now shooting fire at your target and raining fire around you.</span>"
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/mass_fire
name = "Mass Fire Attack"
icon_icon = 'icons/effects/fire.dmi'
button_icon_state = "1"
chosen_message = "<span class='colossus'>You are now shooting mass fire at your target.</span>"
chosen_attack_num = 3
/datum/action/innate/megafauna_attack/lava_swoop
name = "Lava Swoop"
icon_icon = 'icons/effects/effects.dmi'
button_icon_state = "lavastaff_warn"
chosen_message = "<span class='colossus'>You are now swooping and raining lava at your target.</span>"
chosen_attack_num = 4
/mob/living/simple_animal/hostile/megafauna/dragon/Destroy()
QDEL_NULL(fire_cone)
QDEL_NULL(meteors)
QDEL_NULL(mass_fire)
QDEL_NULL(lava_swoop)
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire()
if(swooping)
return
anger_modifier = clamp(((maxHealth - health)/50),0,20)
update_cooldowns(list(COOLDOWN_UPDATE_SET_RANGED = ranged_cooldown_time), ignore_staggered = TRUE)
if(client)
switch(chosen_attack)
if(1)
fire_cone(meteors = FALSE)
if(2)
fire_cone()
if(3)
mass_fire()
if(4)
lava_swoop()
return
if(prob(15 + anger_modifier))
lava_swoop()
else if(prob(10+anger_modifier))
shoot_fire_attack()
else
fire_cone()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/shoot_fire_attack()
if(health < maxHealth*0.5)
mass_fire()
else
fire_cone()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
if(!target)
if(DRAKE_ENRAGED)
// Lava Arena
lava_swoop.Trigger(target)
return
// Lava Pools
if(lava_swoop.Trigger(target))
SLEEP_CHECK_DEATH(0, src)
fire_cone.StartCooldown(0)
fire_cone.Trigger(target)
meteors.StartCooldown(0)
INVOKE_ASYNC(meteors, /datum/action/proc/Trigger, target)
return
else if(prob(10+anger_modifier) && DRAKE_ENRAGED)
mass_fire.Trigger(target)
return
target.visible_message(span_boldwarning("Fire rains from the sky!"))
var/turf/targetturf = get_turf(target)
for(var/turf/turf as anything in RANGE_TURFS(9,targetturf))
if(prob(11))
new /obj/effect/temp_visual/target(turf)
if(fire_cone.Trigger(target))
if(prob(50))
meteors.StartCooldown(0)
meteors.Trigger(target)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_pools(amount, delay = 0.8)
if(!target)
return
target.visible_message(span_boldwarning("Lava starts to pool up around you!"))
/mob/living/simple_animal/hostile/megafauna/dragon/proc/start_attack(mob/living/owner, datum/action/cooldown/activated)
SIGNAL_HANDLER
if(activated == lava_swoop)
icon_state = "shadow"
swooping = SWOOP_DAMAGEABLE
while(amount > 0)
if(QDELETED(target))
break
var/turf/TT = get_turf(target)
var/turf/T = pick(RANGE_TURFS(1,TT))
new /obj/effect/temp_visual/lava_warning(T, 60) // longer reset time for the lava
amount--
SLEEP_CHECK_DEATH(delay)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_invulnerability_started()
SIGNAL_HANDLER
swooping = SWOOP_INVULNERABLE
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(amount = 30)
if(health < maxHealth * 0.5)
return swoop_attack(lava_arena = TRUE, swoop_cooldown = 6 SECONDS)
INVOKE_ASYNC(src, .proc/lava_pools, amount)
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
SLEEP_CHECK_DEATH(0)
fire_cone()
if(health < maxHealth*0.5)
SLEEP_CHECK_DEATH(10)
fire_cone()
SLEEP_CHECK_DEATH(10)
fire_cone()
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 4 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 4 SECONDS))
/mob/living/simple_animal/hostile/megafauna/dragon/proc/finished_attack(mob/living/owner, datum/action/cooldown/finished)
SIGNAL_HANDLER
if(finished == lava_swoop)
icon_state = initial(icon_state)
swooping = NONE
/mob/living/simple_animal/hostile/megafauna/dragon/proc/mass_fire(spiral_count = 12, range = 15, times = 3)
SLEEP_CHECK_DEATH(0)
for(var/i = 1 to times)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 5 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 5 SECONDS))
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
var/increment = 360 / spiral_count
for(var/j = 1 to spiral_count)
var/list/turfs = line_target(j * increment + i * increment / 2, range, src)
INVOKE_ASYNC(src, .proc/fire_line, turfs)
SLEEP_CHECK_DEATH(25)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 3 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_arena()
if(!target)
return
target.visible_message(span_boldwarning("[src] encases you in an arena of fire!"))
var/amount = 3
var/turf/center = get_turf(target)
var/list/walled = RANGE_TURFS(3, center) - RANGE_TURFS(2, center)
var/list/drakewalls = list()
for(var/turf/T in walled)
drakewalls += new /obj/effect/temp_visual/drakewall(T) // no people with lava immunity can just run away from the attack for free
var/list/indestructible_turfs = list()
for(var/turf/T in RANGE_TURFS(2, center))
if(istype(T, /turf/open/indestructible))
continue
if(!istype(T, /turf/closed/indestructible))
T.ChangeTurf(/turf/open/floor/plating/asteroid/basalt/lava_land_surface, flags = CHANGETURF_INHERIT_AIR)
else
indestructible_turfs += T
SLEEP_CHECK_DEATH(10) // give them a bit of time to realize what attack is actually happening
var/list/turfs = RANGE_TURFS(2, center)
var/list/mobs_with_clients = list()
while(amount > 0)
var/list/empty = indestructible_turfs.Copy() // can't place safe turfs on turfs that weren't changed to be open
var/any_attack = FALSE
for(var/turf/T in turfs)
for(var/mob/living/L in T.contents)
if(L.client)
empty += pick(((RANGE_TURFS(2, L) - RANGE_TURFS(1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield
any_attack = TRUE
mobs_with_clients |= L
for(var/obj/vehicle/sealed/mecha/M in T.contents)
empty += pick(((RANGE_TURFS(2, M) - RANGE_TURFS(1, M)) & turfs) - empty)
any_attack = TRUE
if(!any_attack) // nothing to attack in the arena, time for enraged attack if we still have a cliented target.
for(var/obj/effect/temp_visual/drakewall/D in drakewalls)
qdel(D)
for(var/a in mobs_with_clients)
var/mob/living/L = a
if(!QDELETED(L) && L.client)
return FALSE
return TRUE
for(var/turf/T in turfs)
if(!(T in empty))
new /obj/effect/temp_visual/lava_warning(T)
else if(!istype(T, /turf/closed/indestructible))
new /obj/effect/temp_visual/lava_safe(T)
amount--
SLEEP_CHECK_DEATH(24)
return TRUE // attack finished completely
/mob/living/simple_animal/hostile/megafauna/dragon/proc/on_arena_fail()
SIGNAL_HANDLER
INVOKE_ASYNC(src, .proc/arena_escape_enrage)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/arena_escape_enrage() // you ran somehow / teleported away from my arena attack now i'm mad fucker
SLEEP_CHECK_DEATH(0)
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 8 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 8 SECONDS))
SLEEP_CHECK_DEATH(0, src)
visible_message(span_boldwarning("[src] starts to glow vibrantly as its wounds close up!"))
adjustBruteLoss(-250) // yeah you're gonna pay for that, don't run nerd
add_atom_colour(rgb(255, 255, 0), TEMPORARY_COLOUR_PRIORITY)
move_to_delay = move_to_delay / 2
set_light_range(10)
SLEEP_CHECK_DEATH(10) // run.
mass_fire(20, 15, 3)
SLEEP_CHECK_DEATH(5 SECONDS, src) // run.
mass_fire.Activate(target)
mass_fire.StartCooldown(8 SECONDS)
move_to_delay = initial(move_to_delay)
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
set_light_range(initial(light_range))
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(atom/at = target, meteors = TRUE)
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
SLEEP_CHECK_DEATH(0)
if(prob(50) && meteors)
INVOKE_ASYNC(src, .proc/fire_rain)
var/range = 15
var/list/turfs = list()
turfs = line_target(-40, range, at)
INVOKE_ASYNC(src, .proc/fire_line, turfs)
turfs = line_target(0, range, at)
INVOKE_ASYNC(src, .proc/fire_line, turfs)
turfs = line_target(40, range, at)
INVOKE_ASYNC(src, .proc/fire_line, turfs)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/line_target(offset, range, atom/at = target)
if(!at)
return
var/turf/T = get_ranged_target_turf_direct(src, at, range, offset)
return (get_line(src, T) - get_turf(src))
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_line(list/turfs)
SLEEP_CHECK_DEATH(0)
dragon_fire_line(src, turfs)
//fire line keeps going even if dragon is deleted
/proc/dragon_fire_line(atom/source, list/turfs, frozen = FALSE)
var/list/hit_list = list()
@@ -307,105 +195,14 @@
M.take_damage(45, BRUTE, MELEE, 1)
sleep(1.5)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(lava_arena = FALSE, atom/movable/manual_target, swoop_cooldown = 30)
if(stat || swooping)
return
if(manual_target)
GiveTarget(manual_target)
if(!target)
return
stop_automated_movement = TRUE
swooping |= SWOOP_DAMAGEABLE
set_density(FALSE)
icon_state = "shadow"
visible_message(span_boldwarning("[src] swoops up high!"))
var/negative
var/initial_x = x
if(target.x < initial_x) //if the target's x is lower than ours, swoop to the left
negative = TRUE
else if(target.x > initial_x)
negative = FALSE
else if(target.x == initial_x) //if their x is the same, pick a direction
negative = prob(50)
var/obj/effect/temp_visual/dragon_flight/F = new /obj/effect/temp_visual/dragon_flight(loc, negative)
negative = !negative //invert it for the swoop down later
var/oldtransform = transform
alpha = 255
animate(src, alpha = 204, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING)
for(var/i in 1 to 3)
sleep(1)
if(QDELETED(src) || stat == DEAD) //we got hit and died, rip us
qdel(F)
if(stat == DEAD)
swooping &= ~SWOOP_DAMAGEABLE
animate(src, alpha = 255, transform = oldtransform, time = 0, flags = ANIMATION_END_NOW) //reset immediately
return
animate(src, alpha = 100, transform = matrix()*0.7, time = 7)
swooping |= SWOOP_INVULNERABLE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
SLEEP_CHECK_DEATH(7)
while(target && loc != get_turf(target))
forceMove(get_step(src, get_dir(src, target)))
SLEEP_CHECK_DEATH(0.5)
// Ash drake flies onto its target and rains fire down upon them
var/descentTime = 10
var/lava_success = TRUE
if(lava_arena)
lava_success = lava_arena()
//ensure swoop direction continuity.
if(negative)
if(ISINRANGE(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
negative = FALSE
else
if(ISINRANGE(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
negative = TRUE
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
new /obj/effect/temp_visual/dragon_swoop(loc)
animate(src, alpha = 255, transform = oldtransform, descentTime)
SLEEP_CHECK_DEATH(descentTime)
swooping &= ~SWOOP_INVULNERABLE
mouse_opacity = initial(mouse_opacity)
icon_state = "dragon"
playsound(loc, 'sound/effects/meteorimpact.ogg', 200, TRUE)
for(var/mob/living/L in orange(1, src))
if(L.stat)
visible_message(span_warning("[src] slams down on [L], crushing [L.p_them()]!"))
L.gib()
else
L.adjustBruteLoss(75)
if(L && !QDELETED(L)) // Some mobs are deleted on death
var/throw_dir = get_dir(src, L)
if(L.loc == loc)
throw_dir = pick(GLOB.alldirs)
var/throwtarget = get_edge_target_turf(src, throw_dir)
L.throw_at(throwtarget, 3)
visible_message(span_warning("[L] is thrown clear of [src]!"))
for(var/obj/vehicle/sealed/mecha/M in orange(1, src))
M.take_damage(75, BRUTE, MELEE, 1)
for(var/mob/M in range(7, src))
shake_camera(M, 15, 1)
set_density(TRUE)
SLEEP_CHECK_DEATH(1)
swooping &= ~SWOOP_DAMAGEABLE
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = swoop_cooldown, COOLDOWN_UPDATE_SET_RANGED = swoop_cooldown))
if(!lava_success)
arena_escape_enrage()
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
anger_modifier = clamp(((maxHealth - health)/60),0,20)
lava_swoop.enraged = DRAKE_ENRAGED
if(!forced && (swooping & SWOOP_INVULNERABLE))
return FALSE
return ..()
@@ -436,6 +233,7 @@
layer = BELOW_MOB_LAYER
light_range = 2
duration = 13
var/mob/owner
/obj/effect/temp_visual/lava_warning/Initialize(mapload, reset_time = 10)
. = ..()
@@ -449,7 +247,7 @@
sleep(duration)
playsound(T,'sound/magic/fireball.ogg', 200, TRUE)
for(var/mob/living/L in T.contents)
for(var/mob/living/L in T.contents - owner)
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
continue
L.adjustFireLoss(10)
@@ -485,53 +283,6 @@
light_range = 2
duration = 13
/obj/effect/temp_visual/dragon_swoop
name = "certain death"
desc = "Don't just stand there, move!"
icon = 'icons/effects/96x96.dmi'
icon_state = "landing"
layer = BELOW_MOB_LAYER
pixel_x = -32
pixel_y = -32
color = "#FF0000"
duration = 10
/obj/effect/temp_visual/dragon_flight
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
icon_state = "dragon"
layer = ABOVE_ALL_MOB_LAYER
pixel_x = -16
duration = 10
randomdir = FALSE
/obj/effect/temp_visual/dragon_flight/Initialize(mapload, negative)
. = ..()
INVOKE_ASYNC(src, .proc/flight, negative)
/obj/effect/temp_visual/dragon_flight/proc/flight(negative)
if(negative)
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
else
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT*0.1, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
sleep(3)
icon_state = "swoop"
if(negative)
animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
else
animate(src, pixel_x = DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
/obj/effect/temp_visual/dragon_flight/end
pixel_x = DRAKE_SWOOP_HEIGHT
pixel_z = DRAKE_SWOOP_HEIGHT
duration = 10
/obj/effect/temp_visual/dragon_flight/end/flight(negative)
if(negative)
pixel_x = -DRAKE_SWOOP_HEIGHT
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
else
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
/obj/effect/temp_visual/fireball
icon = 'icons/obj/wizard.dmi'
icon_state = "fireball"
@@ -593,15 +344,19 @@
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
attack_action_types = list()
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/AltClickOn(atom/movable/A)
if(!istype(A))
return
if(player_cooldown >= world.time)
to_chat(src, span_warning("You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!"))
return
swoop_attack(FALSE, A)
lava_pools(10, 2) // less pools but longer delay before spawns
player_cooldown = world.time + 20 SECONDS // needs separate cooldown or cant use fire attacks
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/Initialize()
. = ..()
fire_cone.Remove(src)
meteors.Remove(src)
mass_fire.Remove(src)
lava_swoop.cooldown_time = 20 SECONDS
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
. = ..()
lava_swoop.enraged = FALSE
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
#undef SWOOP_DAMAGEABLE
#undef SWOOP_INVULNERABLE
@@ -220,7 +220,7 @@ Difficulty: Hard
visible_message(span_hierophant("\"Mx ampp rsx iwgeti.\""))
var/oldcolor = color
animate(src, color = "#660099", time = 6)
SLEEP_CHECK_DEATH(6)
SLEEP_CHECK_DEATH(6, src)
while(!QDELETED(target) && blink_counter)
if(loc == target.loc || loc == target) //we're on the same tile as them after about a second we can stop now
break
@@ -228,10 +228,10 @@ Difficulty: Hard
blinking = FALSE
blink(target)
blinking = TRUE
SLEEP_CHECK_DEATH(4 + target_slowness)
SLEEP_CHECK_DEATH(4 + target_slowness, src)
animate(src, color = oldcolor, time = 8)
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
SLEEP_CHECK_DEATH(8)
SLEEP_CHECK_DEATH(8, src)
blinking = FALSE
else
blink(target)
@@ -242,17 +242,17 @@ Difficulty: Hard
blinking = TRUE
var/oldcolor = color
animate(src, color = "#660099", time = 6)
SLEEP_CHECK_DEATH(6)
SLEEP_CHECK_DEATH(6, src)
while(!QDELETED(target) && cross_counter)
cross_counter--
if(prob(60))
INVOKE_ASYNC(src, .proc/blasts, target, GLOB.cardinals)
else
INVOKE_ASYNC(src, .proc/blasts, target, GLOB.diagonals)
SLEEP_CHECK_DEATH(6 + target_slowness)
SLEEP_CHECK_DEATH(6 + target_slowness, src)
animate(src, color = oldcolor, time = 8)
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
SLEEP_CHECK_DEATH(8)
SLEEP_CHECK_DEATH(8, src)
blinking = FALSE
@@ -262,7 +262,7 @@ Difficulty: Hard
blinking = TRUE
var/oldcolor = color
animate(src, color = "#660099", time = 6)
SLEEP_CHECK_DEATH(6)
SLEEP_CHECK_DEATH(6, src)
var/list/targets = ListTargets()
var/list/cardinal_copy = GLOB.cardinals.Copy()
while(targets.len && cardinal_copy.len)
@@ -276,11 +276,11 @@ Difficulty: Hard
var/obj/effect/temp_visual/hierophant/chaser/C = new(loc, src, pickedtarget, chaser_speed, FALSE)
C.moving = 3
C.moving_dir = pick_n_take(cardinal_copy)
SLEEP_CHECK_DEATH(8 + target_slowness)
SLEEP_CHECK_DEATH(8 + target_slowness, src)
update_cooldowns(list(COOLDOWN_UPDATE_SET_CHASER = chaser_cooldown_time))
animate(src, color = oldcolor, time = 8)
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
SLEEP_CHECK_DEATH(8)
SLEEP_CHECK_DEATH(8, src)
blinking = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blasts(mob/victim, list/directions = GLOB.cardinals) //fires cross blasts with a delay
@@ -294,7 +294,7 @@ Difficulty: Hard
else
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
SLEEP_CHECK_DEATH(2)
SLEEP_CHECK_DEATH(2, src)
new /obj/effect/temp_visual/hierophant/blast/damaging(T, src, FALSE)
for(var/d in directions)
INVOKE_ASYNC(src, .proc/blast_wall, T, d)
@@ -332,7 +332,7 @@ Difficulty: Hard
HS.setDir(set_dir)
previousturf = J
J = get_step(previousturf, set_dir)
SLEEP_CHECK_DEATH(0.5)
SLEEP_CHECK_DEATH(0.5, src)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
if(blinking || !victim)
@@ -344,7 +344,7 @@ Difficulty: Hard
playsound(T,'sound/magic/wand_teleport.ogg', 200, TRUE)
playsound(source,'sound/machines/airlockopen.ogg', 200, TRUE)
blinking = TRUE
SLEEP_CHECK_DEATH(2) //short delay before we start...
SLEEP_CHECK_DEATH(2, src) //short delay before we start...
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, src)
for(var/t in RANGE_TURFS(1, T))
@@ -354,17 +354,17 @@ Difficulty: Hard
var/obj/effect/temp_visual/hierophant/blast/damaging/B = new(t, src, FALSE)
B.damage = 30
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
SLEEP_CHECK_DEATH(1)
SLEEP_CHECK_DEATH(1, src)
visible_message(span_hierophant_warning("[src] fades out!"))
set_density(FALSE)
SLEEP_CHECK_DEATH(2)
SLEEP_CHECK_DEATH(2, src)
forceMove(T)
SLEEP_CHECK_DEATH(1)
SLEEP_CHECK_DEATH(1, src)
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
SLEEP_CHECK_DEATH(1)
SLEEP_CHECK_DEATH(1, src)
set_density(TRUE)
visible_message(span_hierophant_warning("[src] fades in!"))
SLEEP_CHECK_DEATH(1) //at this point the blasts we made detonate
SLEEP_CHECK_DEATH(1, src) //at this point the blasts we made detonate
blinking = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target
@@ -375,7 +375,7 @@ Difficulty: Hard
return
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
SLEEP_CHECK_DEATH(2)
SLEEP_CHECK_DEATH(2, src)
for(var/t in RANGE_TURFS(1, T))
new /obj/effect/temp_visual/hierophant/blast/damaging(t, src, FALSE)
@@ -206,17 +206,17 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/wendigo/proc/shockwave_scream()
can_move = FALSE
COOLDOWN_START(src, scream_cooldown, scream_cooldown_time)
SLEEP_CHECK_DEATH(5)
SLEEP_CHECK_DEATH(5, src)
playsound(loc, 'sound/magic/demon_dies.ogg', 600, FALSE, 10)
animate(src, pixel_z = rand(5, 15), time = 1, loop = 20)
animate(pixel_z = 0, time = 1)
for(var/mob/living/dizzy_target in get_hearers_in_view(7, src) - src)
dizzy_target.Dizzy(6)
to_chat(dizzy_target, span_danger("The wendigo screams loudly!"))
SLEEP_CHECK_DEATH(1 SECONDS)
SLEEP_CHECK_DEATH(1 SECONDS, src)
spiral_attack()
update_cooldowns(list(COOLDOWN_UPDATE_SET_MELEE = 3 SECONDS, COOLDOWN_UPDATE_SET_RANGED = 3 SECONDS))
SLEEP_CHECK_DEATH(3 SECONDS)
SLEEP_CHECK_DEATH(3 SECONDS, src)
can_move = TRUE
/// Shoots shockwave projectiles in a random preset pattern
@@ -236,7 +236,7 @@ Difficulty: Hard
shockwave.firer = src
shockwave.speed = 3 - WENDIGO_ENRAGED
shockwave.fire(angle)
SLEEP_CHECK_DEATH(6 - WENDIGO_ENRAGED * 2)
SLEEP_CHECK_DEATH(6 - WENDIGO_ENRAGED * 2, src)
if("Spiral")
var/shots_spiral = WENDIGO_SPIRAL_SHOTCOUNT
var/angle_to_target = get_angle(src, target)
@@ -250,7 +250,7 @@ Difficulty: Hard
shockwave.firer = src
shockwave.damage = 15
shockwave.fire(angle)
SLEEP_CHECK_DEATH(1)
SLEEP_CHECK_DEATH(1, src)
if("Wave")
var/shots_per = WENDIGO_WAVE_SHOTCOUNT
var/difference = 360 / shots_per
@@ -264,7 +264,7 @@ Difficulty: Hard
shockwave.speed = 8
shockwave.wave_speed = 10 * wave_direction
shockwave.fire(angle)
SLEEP_CHECK_DEATH(2)
SLEEP_CHECK_DEATH(2, src)
/mob/living/simple_animal/hostile/megafauna/wendigo/death(gibbed, list/force_grant)
if(health > 0)
@@ -69,7 +69,7 @@
return ..()
var/turf/end = pick(possible_ends)
do_teleport(src, end, 0, channel=TELEPORT_CHANNEL_BLUESPACE, forced = TRUE)
SLEEP_CHECK_DEATH(8)
SLEEP_CHECK_DEATH(8, src)
return ..()
/mob/living/simple_animal/hostile/asteroid/ice_demon/Life(delta_time = SSMOBS_DT, times_fired)
@@ -28,18 +28,26 @@
weather_immunities = list(TRAIT_SNOWSTORM_IMMUNE)
vision_range = 5
aggro_vision_range = 7
charger = TRUE
charge_distance = 4
butcher_results = list(/obj/item/food/meat/crab = 2, /obj/item/stack/sheet/bone = 2)
robust_searching = TRUE
footstep_type = FOOTSTEP_MOB_CLAW
gold_core_spawnable = HOSTILE_SPAWN
/// Charging ability
var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge
/mob/living/simple_animal/hostile/asteroid/lobstrosity/ranged_secondary_attack(atom/target, modifiers)
if(COOLDOWN_FINISHED(src, charge_cooldown))
INVOKE_ASYNC(src, /mob/living/simple_animal/hostile/.proc/enter_charge, target)
else
to_chat(src, span_notice("Your charge is still on cooldown!"))
/mob/living/simple_animal/hostile/asteroid/lobstrosity/Initialize(mapload)
. = ..()
charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge()
charge.Grant(src)
/mob/living/simple_animal/hostile/asteroid/lobstrosity/Destroy()
QDEL_NULL(charge)
return ..()
/mob/living/simple_animal/hostile/asteroid/lobstrosity/OpenFire()
if(client)
return
charge.Trigger(target)
/mob/living/simple_animal/hostile/asteroid/lobstrosity/lava
name = "tropical lobstrosity"