mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-21 20:20:33 +01:00
Mob Abilities (#63520)
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
This commit is contained in:
co-authored by
Mothblocks
parent
b396e73eb7
commit
155bd7d9ab
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user