mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 06:29:23 +01:00
[Ready] Adds Support For Player Controlled Megafauna + Megafauna Code Refactors (#44005)
* adds small sprites for many of the large megafauna moves fireball target code back to drake file changes the speed of every megafauna mob to its move to delay so player controlled ones have the same speed adds action abilities to each megafauna so players can select the type of attack they want refactors pretty much all of the megafauna code to be simpler to edit and easier to read as well as have some consistency in where stuff like initialize goes lesser ash drake now inherits alt click on instead of normal ash drake having it hierophant no longer blinks on alt click as well removes pointless check in legion code for ranged timer delay as the proc that calls openfire already checks that adds icon for new bubblegum blood tracks bubblegum blood no longer leaves footstep trails as it caused massive lag when many blood tiles were run over in a fight as well as being way too excessive * fixes a megafauna bug where they could not attack while in space megafauna can now move through space normally as they would anywhere else bubblegum no longer runs from corpses and people dying * fix the weird line errors * lots of sins have been cleansed (0 = false 1 = true) switch cases for player attack selection bubblegum has been bug fixed a bit (steps can be blood warped to, adds blood warp ability) bubblegum now has some slight additions to its attacks to keep the fight faster paced bubblegums enrage mode now lasts longer and makes him move faster legion now has their speed changed properly when they charge (wow this is an old fucking bug like old old) bubblegum now tries to be aggressive towards people that are laying down (no more resting under bubblegum charges without consequences) bubblegum now spawns slaughterlings when he devours targets * fine tunes new bubblegum attacks and replaces some is_procs with defines * fixes stupid snowflake stuff in bdm code specifies in defines for bubblegum lots of sleep_check_death now to avoid stupid stuff removes need for hierophant_dying var as well as combines all the blast procs into one since they were so similar
This commit is contained in:
+16
-2
@@ -706,11 +706,25 @@
|
||||
small_icon = 'icons/mob/alien.dmi'
|
||||
small_icon_state = "alienq"
|
||||
|
||||
/datum/action/small_sprite/drake
|
||||
/datum/action/small_sprite/megafauna
|
||||
icon_icon = 'icons/mob/actions/actions_xeno.dmi'
|
||||
button_icon_state = "smallqueen"
|
||||
background_icon_state = "bg_alien"
|
||||
small_icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
|
||||
|
||||
/datum/action/small_sprite/megafauna/drake
|
||||
small_icon_state = "ash_whelp"
|
||||
|
||||
/datum/action/small_sprite/spacedragon
|
||||
/datum/action/small_sprite/megafauna/colossus
|
||||
small_icon_state = "Basilisk"
|
||||
|
||||
/datum/action/small_sprite/megafauna/bubblegum
|
||||
small_icon_state = "goliath2"
|
||||
|
||||
/datum/action/small_sprite/megafauna/legion
|
||||
small_icon_state = "dwarf_legion"
|
||||
|
||||
/datum/action/small_sprite/megafauna/spacedragon
|
||||
small_icon = 'icons/mob/animal.dmi'
|
||||
small_icon_state = "carp"
|
||||
|
||||
|
||||
@@ -1175,55 +1175,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
msg += "</UL></BODY></HTML>"
|
||||
src << browse(msg.Join(), "window=Player_playtime_check")
|
||||
|
||||
/obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = FALSE
|
||||
duration = 9
|
||||
pixel_z = 270
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, 1)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, 1)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
if(islist(flame_hit) && !flame_hit[L])
|
||||
L.adjustFireLoss(40)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
|
||||
/datum/admins/proc/cmd_show_exp_panel(client/C)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -32,11 +32,11 @@ Difficulty: Medium
|
||||
light_color = "#E4C7C5"
|
||||
movement_type = GROUND
|
||||
speak_emote = list("roars")
|
||||
speed = 1
|
||||
speed = 3
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/kinetic/miner
|
||||
projectilesound = 'sound/weapons/kenetic_accel.ogg'
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
ranged_cooldown_time = 16
|
||||
pixel_x = -16
|
||||
crusher_loot = list(/obj/item/melee/transforming/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator, /obj/item/crusher_trophy/miner_eye)
|
||||
@@ -51,18 +51,56 @@ Difficulty: Medium
|
||||
var/dashing = FALSE
|
||||
var/dash_cooldown = 15
|
||||
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"
|
||||
|
||||
do_footstep = TRUE
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
|
||||
/datum/action/innate/megafauna_attack/kinetic_accelerator,
|
||||
/datum/action/innate/megafauna_attack/transform_weapon)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
miner_saw = new(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/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()
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
|
||||
/obj/item/melee/transforming/cleaving_saw/miner //nerfed saw because it is very murdery
|
||||
force = 6
|
||||
@@ -79,10 +117,6 @@ Difficulty: Medium
|
||||
icon_state = "ka_tracer"
|
||||
range = MINER_DASH_RANGE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
|
||||
. = ..()
|
||||
miner_saw = new(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
var/adjustment_amount = amount * 0.1
|
||||
if(world.time + adjustment_amount > next_move)
|
||||
@@ -90,10 +124,9 @@ Difficulty: Medium
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
|
||||
if(health > 0)
|
||||
return
|
||||
new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
|
||||
return ..()
|
||||
. = ..()
|
||||
if(.)
|
||||
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!
|
||||
@@ -105,11 +138,14 @@ Difficulty: Medium
|
||||
return
|
||||
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(QDELETED(target))
|
||||
return
|
||||
if(next_move > world.time || !Adjacent(target)) //some cheating
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
if(client)
|
||||
transform_stop_attack = FALSE
|
||||
if(QDELETED(target) || transform_stop_attack)
|
||||
return
|
||||
face_atom(target)
|
||||
if(isliving(target))
|
||||
@@ -128,8 +164,6 @@ Difficulty: Medium
|
||||
miner_saw.melee_attack_chain(src, target)
|
||||
if(guidance)
|
||||
adjustHealth(-2)
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
|
||||
@@ -142,16 +176,10 @@ Difficulty: Medium
|
||||
. = ..()
|
||||
if(. && target && !targets_the_same)
|
||||
wander = TRUE
|
||||
transform_weapon()
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
|
||||
Goto(target, move_to_delay, minimum_distance)
|
||||
if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
|
||||
INVOKE_ASYNC(src, .proc/dash, target)
|
||||
else
|
||||
shoot_ka()
|
||||
transform_weapon()
|
||||
/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))
|
||||
@@ -162,21 +190,6 @@ Difficulty: Medium
|
||||
Shoot(target)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
|
||||
//I'm still of the belief that this entire proc needs to be wiped from existence.
|
||||
// do not take my touching of it to be endorsement of it. ~mso
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
|
||||
while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
|
||||
stoplag(1)
|
||||
sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(dashing || next_move > world.time || !Adjacent(target))
|
||||
if(dashing && next_move <= world.time)
|
||||
next_move = world.time + 1
|
||||
INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
|
||||
return
|
||||
AttackingTarget()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
|
||||
if(world.time < dash_cooldown)
|
||||
return
|
||||
@@ -220,19 +233,23 @@ Difficulty: Medium
|
||||
dashing = TRUE
|
||||
alpha = 0
|
||||
animate(src, alpha = 255, time = 5)
|
||||
sleep(2)
|
||||
SLEEP_CHECK_DEATH(2)
|
||||
D.forceMove(step_forward_turf)
|
||||
forceMove(target_turf)
|
||||
playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
|
||||
sleep(1)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
dashing = FALSE
|
||||
shoot_ka()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
|
||||
if(time_until_next_transform <= world.time)
|
||||
miner_saw.transform_cooldown = 0
|
||||
miner_saw.transform_weapon(src, TRUE)
|
||||
if(!miner_saw.active)
|
||||
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.active ? "_transformed":""]"
|
||||
icon_living = "miner[miner_saw.active ? "_transformed":""]"
|
||||
time_until_next_transform = world.time + rand(50, 100)
|
||||
@@ -264,4 +281,12 @@ Difficulty: Medium
|
||||
desc = "The sweet blood, oh, it sings to me."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
|
||||
guidance = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && prob(12))
|
||||
INVOKE_ASYNC(src, .proc/dash)
|
||||
|
||||
#undef MINER_DASH_RANGE
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#define BUBBLEGUM_SMASH (health <= maxHealth*0.5) // angery
|
||||
#define BUBBLEGUM_CAN_ENRAGE (enrage_till + (enrage_time * 2) <= world.time)
|
||||
#define BUBBLEGUM_IS_ENRAGED (enrage_till > world.time)
|
||||
|
||||
/*
|
||||
|
||||
BUBBLEGUM
|
||||
@@ -39,78 +43,32 @@ Difficulty: Hard
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
speed = 5
|
||||
move_to_delay = 5
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
rapid_melee = 8 // every 1/4 second
|
||||
melee_queue_distance = 20 // as far as possible really, need this because of blood warp
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
del_on_death = TRUE
|
||||
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 = 0
|
||||
var/enrage_till = null
|
||||
var/charging = FALSE
|
||||
var/enrage_till = 0
|
||||
var/enrage_time = 70
|
||||
var/revving_charge = FALSE
|
||||
internal_type = /obj/item/gps/internal/bubblegum
|
||||
medal_type = BOSS_MEDAL_BUBBLEGUM
|
||||
score_type = BUBBLEGUM_SCORE
|
||||
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
|
||||
deathsound = 'sound/magic/enter_blood.ogg'
|
||||
|
||||
/obj/item/gps/internal/bubblegum
|
||||
icon_state = null
|
||||
gpstag = "Bloody Signal"
|
||||
desc = "You're not quite sure how a signal can be bloody."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
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))
|
||||
step(B, pick(GLOB.cardinals))
|
||||
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/OpenFire()
|
||||
anger_modifier = CLAMP(((maxHealth - health)/60),0,20)
|
||||
if(charging)
|
||||
return
|
||||
ranged_cooldown = world.time + 50
|
||||
if(!try_bloodattack())
|
||||
blood_warp()
|
||||
|
||||
if(health > maxHealth * 0.5)
|
||||
if(prob(50 + anger_modifier))
|
||||
charge(delay = 6)
|
||||
charge(delay = 4) // The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues.
|
||||
charge(delay = 2)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
hallucination_charge_around(times = 6, delay = 10 - anger_modifier / 5)
|
||||
SetRecoveryTime(10)
|
||||
else
|
||||
if(prob(50 - anger_modifier))
|
||||
hallucination_charge_around(times = 4, delay = 9)
|
||||
hallucination_charge_around(times = 4, delay = 8)
|
||||
hallucination_charge_around(times = 4, delay = 7)
|
||||
SetRecoveryTime(15)
|
||||
else
|
||||
for(var/i = 1 to 5)
|
||||
INVOKE_ASYNC(src, .proc/hallucination_charge_around, 2, 10, 2, 0)
|
||||
sleep(5)
|
||||
SetRecoveryTime(10)
|
||||
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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize()
|
||||
. = ..()
|
||||
@@ -118,64 +76,94 @@ Difficulty: Hard
|
||||
for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_living_list)
|
||||
if(B != src)
|
||||
return INITIALIZE_HINT_QDEL //There can be only one
|
||||
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
|
||||
AddSpell(bloodspell)
|
||||
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
|
||||
bloodspell.phased = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/grant_achievement(medaltype,scoretype)
|
||||
. = ..()
|
||||
if(.)
|
||||
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
|
||||
/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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
|
||||
if(!charging)
|
||||
..()
|
||||
/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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(!charging)
|
||||
. = ..()
|
||||
if(.)
|
||||
recovery_time = world.time + 20 // can only attack melee once every 2 seconds but rapid_melee gives higher priority
|
||||
/datum/action/innate/megafauna_attack/hallucination_surround
|
||||
name = "Surround Target"
|
||||
icon_icon = 'icons/turf/walls/wall.dmi'
|
||||
button_icon_state = "wall"
|
||||
chosen_message = "<span class='colossus'>You are now surrounding the target you click on with hallucinations.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/bullet_act(obj/item/projectile/P)
|
||||
if(is_enraged())
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons while enraged!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 300, 1)
|
||||
return 0
|
||||
return ..()
|
||||
/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/ex_act(severity, target)
|
||||
if(severity >= EXPLODE_LIGHT)
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
|
||||
if(charging)
|
||||
return
|
||||
severity = EXPLODE_LIGHT // puny mortals
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return 1
|
||||
return ..()
|
||||
anger_modifier = CLAMP(((maxHealth - health)/60),0,20)
|
||||
enrage_time = initial(enrage_time) * CLAMP(anger_modifier / 20, 0.5, 1)
|
||||
ranged_cooldown = world.time + 50
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
|
||||
if(!charging)
|
||||
..()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
triple_charge()
|
||||
if(2)
|
||||
hallucination_charge()
|
||||
if(3)
|
||||
surround_with_hallucinations()
|
||||
if(4)
|
||||
blood_warp()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/MoveToTarget(list/possible_targets)
|
||||
if(!charging)
|
||||
..()
|
||||
if(!try_bloodattack() || prob(25 + anger_modifier))
|
||||
blood_warp()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
|
||||
if(charging)
|
||||
new /obj/effect/temp_visual/decoy/fading(loc,src)
|
||||
DestroySurroundings()
|
||||
..()
|
||||
if(!BUBBLEGUM_SMASH)
|
||||
if(prob(50 + anger_modifier))
|
||||
triple_charge()
|
||||
else
|
||||
slaughterlings()
|
||||
else
|
||||
if(prob(50 + anger_modifier))
|
||||
hallucination_charge()
|
||||
else
|
||||
surround_with_hallucinations()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Moved()
|
||||
new /obj/effect/decal/cleanable/blood(src.loc)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
return ..()
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
|
||||
charge(delay = 6)
|
||||
charge(delay = 4)
|
||||
charge(delay = 2)
|
||||
SetRecoveryTime(15)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hallucination_charge()
|
||||
if(!BUBBLEGUM_SMASH || prob(33))
|
||||
hallucination_charge_around(times = 6, delay = 8)
|
||||
SetRecoveryTime(10)
|
||||
else
|
||||
hallucination_charge_around(times = 4, delay = 9)
|
||||
hallucination_charge_around(times = 4, delay = 8)
|
||||
hallucination_charge_around(times = 4, delay = 7)
|
||||
triple_charge()
|
||||
SetRecoveryTime(20)
|
||||
|
||||
/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)
|
||||
SetRecoveryTime(20)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(var/atom/chargeat = target, var/delay = 3, var/chargepast = 2)
|
||||
if(!chargeat)
|
||||
@@ -188,34 +176,21 @@ Difficulty: Hard
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
|
||||
charging = 1
|
||||
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(delay)
|
||||
SLEEP_CHECK_DEATH(delay)
|
||||
revving_charge = FALSE
|
||||
var/movespeed = 0.7
|
||||
walk_towards(src, T, movespeed)
|
||||
sleep(get_dist(src, T) * movespeed)
|
||||
SLEEP_CHECK_DEATH(get_dist(src, T) * movespeed)
|
||||
walk(src, 0) // cancel the movement
|
||||
try_bloodattack()
|
||||
charging = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
if(isturf(A) || isobj(A) && A.density)
|
||||
A.ex_act(EXPLODE_HEAVY)
|
||||
DestroySurroundings()
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] tramples you into the ground!</span>")
|
||||
src.forceMove(get_turf(L))
|
||||
L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE)
|
||||
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
..()
|
||||
charging = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
|
||||
var/list/targets = ListTargets()
|
||||
@@ -269,14 +244,14 @@ Difficulty: Hard
|
||||
new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
|
||||
sleep(4)
|
||||
SLEEP_CHECK_DEATH(4)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
to_chat(L, "<span class='userdanger'>[src] rends you!</span>")
|
||||
playsound(T, attack_sound, 100, 1, -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))
|
||||
sleep(3)
|
||||
SLEEP_CHECK_DEATH(3)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
|
||||
if(handedness)
|
||||
@@ -285,7 +260,7 @@ Difficulty: Hard
|
||||
else
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
|
||||
new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
|
||||
sleep(6)
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
for(var/mob/living/L in T)
|
||||
if(!faction_check_mob(L))
|
||||
if(L.stat != CONSCIOUS)
|
||||
@@ -295,7 +270,226 @@ Difficulty: Hard
|
||||
L.forceMove(targetturf)
|
||||
playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
addtimer(CALLBACK(src, .proc/devour, L), 2)
|
||||
sleep(1)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
|
||||
/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 class='danger'>[src] sinks into the blood...</span>")
|
||||
playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, 1, -1)
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
visible_message("<span class='danger'>And springs back out!</span>")
|
||||
blood_enrage()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/be_aggressive()
|
||||
if(BUBBLEGUM_IS_ENRAGED)
|
||||
return TRUE
|
||||
if(isliving(target))
|
||||
var/mob/living/livingtarget = target
|
||||
return (livingtarget.stat != CONSCIOUS || !(livingtarget.mobility_flags & MOBILITY_STAND))
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_retreat_distance()
|
||||
return (be_aggressive() ? null : initial(retreat_distance))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_minimum_distance()
|
||||
return (be_aggressive() ? 1 : initial(minimum_distance))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/update_approach()
|
||||
retreat_distance = get_retreat_distance()
|
||||
minimum_distance = get_minimum_distance()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage()
|
||||
if(!BUBBLEGUM_CAN_ENRAGE)
|
||||
return FALSE
|
||||
enrage_till = world.time + enrage_time
|
||||
update_approach()
|
||||
change_move_delay(3.75)
|
||||
var/newcolor = rgb(149, 10, 10)
|
||||
add_atom_colour(newcolor, 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/blood_enrage_end(var/newcolor = rgb(149, 10, 10))
|
||||
update_approach()
|
||||
change_move_delay()
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(var/newmove = initial(move_to_delay))
|
||||
move_to_delay = newmove
|
||||
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(var/times = 4, var/delay = 6, var/chargepast = 0, var/useoriginal = 1, var/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)
|
||||
|
||||
/obj/item/gps/internal/bubblegum
|
||||
icon_state = null
|
||||
gpstag = "Bloody Signal"
|
||||
desc = "You're not quite sure how a signal can be bloody."
|
||||
invisibility = 100
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/devour(mob/living/L)
|
||||
var/turf/death_turf = get_turf(L)
|
||||
. = ..()
|
||||
if(. && death_turf)
|
||||
for(var/i in 1 to 3)
|
||||
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter(death_turf)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
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))
|
||||
step(B, pick(GLOB.cardinals))
|
||||
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(.)
|
||||
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
|
||||
if(!charging)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
|
||||
if(!charging)
|
||||
. = ..()
|
||||
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/item/projectile/P)
|
||||
if(BUBBLEGUM_IS_ENRAGED)
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons while enraged!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 300, 1)
|
||||
return BULLET_ACT_BLOCK
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/ex_act(severity, target)
|
||||
if(severity >= EXPLODE_LIGHT)
|
||||
return
|
||||
severity = EXPLODE_LIGHT // puny mortals
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/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)
|
||||
new /obj/effect/decal/cleanable/blood/bubblegum(src.loc)
|
||||
if(charging)
|
||||
DestroySurroundings()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A)
|
||||
if(charging)
|
||||
if(isturf(A) || isobj(A) && A.density)
|
||||
A.ex_act(EXPLODE_HEAVY)
|
||||
DestroySurroundings()
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.visible_message("<span class='danger'>[src] slams into [L]!</span>", "<span class='userdanger'>[src] tramples you into the ground!</span>")
|
||||
src.forceMove(get_turf(L))
|
||||
L.apply_damage(istype(src, /mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination) ? 15 : 30, BRUTE)
|
||||
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1)
|
||||
shake_camera(L, 4, 3)
|
||||
shake_camera(src, 2, 3)
|
||||
..()
|
||||
|
||||
/obj/effect/temp_visual/dragon_swoop/bubblegum
|
||||
duration = 10
|
||||
@@ -324,103 +518,6 @@ Difficulty: Hard
|
||||
/obj/effect/temp_visual/bubblegum_hands/leftsmack
|
||||
icon_state = "leftsmack"
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
|
||||
if(Adjacent(target) || (enrage_till + 30 > world.time))
|
||||
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), 2)
|
||||
var/list/pools_to_remove = get_pools(get_turf(target), 1)
|
||||
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(3)
|
||||
qdel(DA)
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/found_bloodpool
|
||||
pools = get_pools(get_turf(target), 2)
|
||||
pools_to_remove = get_pools(get_turf(target), 1)
|
||||
pools -= pools_to_remove
|
||||
if(pools.len)
|
||||
shuffle_inplace(pools)
|
||||
found_bloodpool = pick(pools)
|
||||
if(found_bloodpool)
|
||||
visible_message("<span class='danger'>[src] sinks into the blood...</span>")
|
||||
playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, 1, -1)
|
||||
forceMove(get_turf(found_bloodpool))
|
||||
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
|
||||
visible_message("<span class='danger'>And springs back out!</span>")
|
||||
blood_enrage()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage(var/boost_time = 30)
|
||||
enrage_till = world.time + boost_time
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
change_move_delay(3.75)
|
||||
var/newcolor = rgb(149, 10, 10)
|
||||
add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
|
||||
var/datum/callback/cb = CALLBACK(src, .proc/blood_enrage_end)
|
||||
addtimer(cb, boost_time)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_enrage_end(var/newcolor = rgb(149, 10, 10))
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
change_move_delay()
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, newcolor)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/is_enraged()
|
||||
return (enrage_till > world.time)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/change_move_delay(var/newmove = initial(move_to_delay))
|
||||
move_to_delay = newmove
|
||||
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(var/times = 4, var/delay = 6, var/chargepast = 0, var/useoriginal = 1)
|
||||
var/startingangle = rand(1, 360)
|
||||
if(!target)
|
||||
return
|
||||
var/turf/chargeat = get_turf(target)
|
||||
var/srcplaced = 0
|
||||
for(var/i = 1 to times)
|
||||
var/ang = (startingangle + 360/times * i)
|
||||
if(!chargeat)
|
||||
return
|
||||
var/turf/place = locate(chargeat.x + cos(ang) * times, chargeat.y + sin(ang) * times, chargeat.z)
|
||||
if(!place)
|
||||
continue
|
||||
if(!nest || nest && nest.parent && get_dist(nest.parent, place) <= nest_range)
|
||||
if(!srcplaced && useoriginal)
|
||||
forceMove(place)
|
||||
srcplaced = 1
|
||||
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/hallucination
|
||||
name = "bubblegum's hallucination"
|
||||
desc = "Is that really just a hallucination?"
|
||||
@@ -433,7 +530,7 @@ Difficulty: Hard
|
||||
score_type = null
|
||||
deathmessage = "Explodes into a pool of blood!"
|
||||
deathsound = 'sound/effects/splat.ogg'
|
||||
true_spawn = 0
|
||||
true_spawn = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Initialize()
|
||||
..()
|
||||
@@ -449,7 +546,7 @@ Difficulty: Hard
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) // hallucinations should not be stopping bubblegum or eachother
|
||||
return 1
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/Life()
|
||||
@@ -469,7 +566,7 @@ Difficulty: Hard
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
|
||||
visible_message("<span class='danger'>[src] summons a shoal of slaughterlings!</span>")
|
||||
var/max_amount = 6
|
||||
var/max_amount = CLAMP(anger_modifier / 4, 3, 5)
|
||||
for(var/H in get_pools(get_turf(src), 1))
|
||||
if(!max_amount)
|
||||
break
|
||||
@@ -492,5 +589,5 @@ Difficulty: Hard
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -37,11 +37,11 @@ Difficulty: Very Hard
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
speed = 10
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
pixel_x = -32
|
||||
del_on_death = 1
|
||||
del_on_death = TRUE
|
||||
internal_type = /obj/item/gps/internal/colossus
|
||||
medal_type = BOSS_MEDAL_COLOSSUS
|
||||
score_type = COLOSSUS_SCORE
|
||||
@@ -49,15 +49,56 @@ Difficulty: Very Hard
|
||||
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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
|
||||
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
|
||||
L.dust()
|
||||
/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/projectile.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/projectile.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/OpenFire()
|
||||
anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
|
||||
ranged_cooldown = world.time + 120
|
||||
|
||||
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 class='colossus'>\"<b>You can't dodge.</b>\"</span>")
|
||||
@@ -70,49 +111,14 @@ Difficulty: Very Hard
|
||||
move_to_delay = initial(move_to_delay)
|
||||
|
||||
if(prob(20+anger_modifier)) //Major attack
|
||||
telegraph()
|
||||
|
||||
if(health < maxHealth/3)
|
||||
INVOKE_ASYNC(src, .proc/double_spiral)
|
||||
else
|
||||
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot, pick(TRUE, FALSE))
|
||||
|
||||
select_spiral_attack()
|
||||
else if(prob(20))
|
||||
ranged_cooldown = world.time + 30
|
||||
random_shots()
|
||||
else
|
||||
if(prob(70))
|
||||
ranged_cooldown = world.time + 20
|
||||
blast()
|
||||
else
|
||||
ranged_cooldown = world.time + 40
|
||||
INVOKE_ASYNC(src, .proc/alternating_dir_shots)
|
||||
|
||||
/obj/effect/temp_visual/at_shield
|
||||
name = "anti-toolbox field"
|
||||
desc = "A shimmering forcefield protecting the colossus."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "at_shield2"
|
||||
layer = FLY_LAYER
|
||||
light_range = 2
|
||||
duration = 8
|
||||
var/target
|
||||
|
||||
/obj/effect/temp_visual/at_shield/Initialize(mapload, new_target)
|
||||
. = ..()
|
||||
target = new_target
|
||||
INVOKE_ASYNC(src, /atom/movable/proc/orbit, target, 0, FALSE, 0, 0, FALSE, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P)
|
||||
if(!stat)
|
||||
var/obj/effect/temp_visual/at_shield/AT = new /obj/effect/temp_visual/at_shield(loc, src)
|
||||
var/random_x = rand(-32, 32)
|
||||
AT.pixel_x += random_x
|
||||
|
||||
var/random_y = rand(0, 72)
|
||||
AT.pixel_y += random_y
|
||||
return ..()
|
||||
alternating_dir_shots()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
|
||||
if(ishuman(L))
|
||||
@@ -122,6 +128,7 @@ Difficulty: Very Hard
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
ranged_cooldown = world.time + 40
|
||||
dir_shots(GLOB.diagonals)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
dir_shots(GLOB.cardinals)
|
||||
@@ -130,14 +137,21 @@ Difficulty: Very Hard
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
dir_shots(GLOB.cardinals)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/select_spiral_attack()
|
||||
telegraph()
|
||||
if(health < maxHealth/3)
|
||||
return double_spiral()
|
||||
visible_message("<span class='colossus'>\"<b>Judgement.</b>\"</span>")
|
||||
return spiral_shoot()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral()
|
||||
visible_message("<span class='colossus'>\"<b>Die.</b>\"</span>")
|
||||
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
INVOKE_ASYNC(src, .proc/spiral_shoot)
|
||||
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 = FALSE, counter_start = 8)
|
||||
/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)
|
||||
@@ -165,6 +179,7 @@ Difficulty: Very Hard
|
||||
P.fire(set_angle)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots()
|
||||
ranged_cooldown = world.time + 30
|
||||
var/turf/U = get_turf(src)
|
||||
playsound(U, 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5)
|
||||
for(var/T in RANGE_TURFS(12, U) - U)
|
||||
@@ -172,6 +187,7 @@ Difficulty: Very Hard
|
||||
shoot_projectile(T)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast(set_angle)
|
||||
ranged_cooldown = world.time + 20
|
||||
var/turf/target_turf = get_turf(target)
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 2)
|
||||
newtonian_move(get_dir(target_turf, src))
|
||||
@@ -198,6 +214,34 @@ Difficulty: Very Hard
|
||||
playsound(src, 'sound/magic/clockwork/narsie_attack.ogg', 200, 1)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L)
|
||||
visible_message("<span class='colossus'>[src] disintegrates [L]!</span>")
|
||||
L.dust()
|
||||
|
||||
/obj/effect/temp_visual/at_shield
|
||||
name = "anti-toolbox field"
|
||||
desc = "A shimmering forcefield protecting the colossus."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "at_shield2"
|
||||
layer = FLY_LAYER
|
||||
light_range = 2
|
||||
duration = 8
|
||||
var/target
|
||||
|
||||
/obj/effect/temp_visual/at_shield/Initialize(mapload, new_target)
|
||||
. = ..()
|
||||
target = new_target
|
||||
INVOKE_ASYNC(src, /atom/movable/proc/orbit, target, 0, FALSE, 0, 0, FALSE, TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P)
|
||||
if(!stat)
|
||||
var/obj/effect/temp_visual/at_shield/AT = new /obj/effect/temp_visual/at_shield(loc, src)
|
||||
var/random_x = rand(-32, 32)
|
||||
AT.pixel_x += random_x
|
||||
|
||||
var/random_y = rand(0, 72)
|
||||
AT.pixel_y += random_y
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/colossus
|
||||
name ="death bolt"
|
||||
@@ -626,7 +670,7 @@ Difficulty: Very Hard
|
||||
obj_damage = 0
|
||||
environment_smash = ENVIRONMENT_SMASH_NONE
|
||||
AIStatus = AI_OFF
|
||||
stop_automated_movement = 1
|
||||
stop_automated_movement = TRUE
|
||||
var/heal_power = 5
|
||||
|
||||
/mob/living/simple_animal/hostile/lightgeist/Initialize()
|
||||
@@ -679,13 +723,13 @@ Difficulty: Very Hard
|
||||
/obj/machinery/anomalous_crystal/possessor/ActivationReaction(mob/user, method)
|
||||
if(..())
|
||||
if(ishuman(user))
|
||||
var/mobcheck = 0
|
||||
var/mobcheck = FALSE
|
||||
for(var/mob/living/simple_animal/A in range(1, src))
|
||||
if(A.melee_damage_upper > 5 || A.mob_size >= MOB_SIZE_LARGE || A.ckey || A.stat)
|
||||
break
|
||||
var/obj/structure/closet/stasis/S = new /obj/structure/closet/stasis(A)
|
||||
user.forceMove(S)
|
||||
mobcheck = 1
|
||||
mobcheck = TRUE
|
||||
break
|
||||
if(!mobcheck)
|
||||
new /mob/living/simple_animal/cockroach(get_step(src,dir)) //Just in case there aren't any animals on the station, this will leave you with a terrible option to possess if you feel like it
|
||||
@@ -750,7 +794,7 @@ Difficulty: Very Hard
|
||||
invocation_type = "none"
|
||||
max_targets = 1
|
||||
range = -1
|
||||
include_user = 1
|
||||
include_user = TRUE
|
||||
selection_type = "view"
|
||||
action_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
action_icon_state = "exit_possession"
|
||||
|
||||
@@ -35,7 +35,6 @@ Difficulty: Medium
|
||||
desc = "Guardians of the necropolis."
|
||||
health = 2500
|
||||
maxHealth = 2500
|
||||
spacewalk = TRUE
|
||||
attacktext = "chomps"
|
||||
attack_sound = 'sound/magic/demon_attack1.ogg'
|
||||
icon = 'icons/mob/lavaland/64x64megafauna.dmi'
|
||||
@@ -47,9 +46,9 @@ Difficulty: Medium
|
||||
armour_penetration = 40
|
||||
melee_damage_lower = 40
|
||||
melee_damage_upper = 40
|
||||
speed = 1
|
||||
speed = 5
|
||||
move_to_delay = 5
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
pixel_x = -16
|
||||
crusher_loot = list(/obj/structure/closet/crate/necropolis/dragon/crusher)
|
||||
loot = list(/obj/structure/closet/crate/necropolis/dragon)
|
||||
@@ -62,71 +61,82 @@ Difficulty: Medium
|
||||
score_type = DRAKE_SCORE
|
||||
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
|
||||
deathsound = 'sound/magic/demon_dies.ogg'
|
||||
var/datum/action/small_sprite/smallsprite = new/datum/action/small_sprite/drake()
|
||||
|
||||
do_footstep = TRUE
|
||||
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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
|
||||
smallsprite.Grant(src)
|
||||
. = ..()
|
||||
/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/death()
|
||||
QDEL_NULL(internal) // so drake corpses don't have a gps signal
|
||||
. = ..()
|
||||
/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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
|
||||
if(severity == 3)
|
||||
return
|
||||
..()
|
||||
/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
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && (swooping & SWOOP_INVULNERABLE))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
|
||||
if(!swooping)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings()
|
||||
if(!swooping)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Move()
|
||||
if(!swooping)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Goto(target, delay, minimum_distance)
|
||||
if(!swooping)
|
||||
..()
|
||||
/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/OpenFire()
|
||||
if(swooping)
|
||||
return
|
||||
|
||||
anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
if(prob(15 + anger_modifier) && !client)
|
||||
if(health < maxHealth*0.5)
|
||||
swoop_attack(lava_arena = TRUE)
|
||||
else
|
||||
lava_swoop()
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
fire_cone(meteors = FALSE)
|
||||
if(2)
|
||||
fire_cone()
|
||||
if(3)
|
||||
mass_fire()
|
||||
if(4)
|
||||
lava_swoop()
|
||||
return
|
||||
|
||||
else if(prob(10+anger_modifier) && !client)
|
||||
if(health < maxHealth*0.5)
|
||||
mass_fire()
|
||||
else
|
||||
fire_cone()
|
||||
if(prob(15 + anger_modifier))
|
||||
lava_swoop()
|
||||
|
||||
else if(prob(10+anger_modifier))
|
||||
shoot_fire_attack()
|
||||
else
|
||||
if(prob(50) && !client)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, 10, 2)
|
||||
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)
|
||||
return
|
||||
target.visible_message("<span class='boldwarning'>Fire rains from the sky!</span>")
|
||||
for(var/turf/turf in range(9,get_turf(target)))
|
||||
if(prob(11))
|
||||
new /obj/effect/temp_visual/target(turf)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_pools(var/amount, var/delay = 0.8)
|
||||
if(!target)
|
||||
return
|
||||
@@ -140,10 +150,11 @@ Difficulty: Medium
|
||||
SLEEP_CHECK_DEATH(delay)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(var/amount = 30)
|
||||
if(health < maxHealth * 0.5)
|
||||
return swoop_attack(lava_arena = TRUE, swoop_cooldown = 60)
|
||||
INVOKE_ASYNC(src, .proc/lava_pools, amount)
|
||||
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
|
||||
if(QDELETED(src) || stat == DEAD)
|
||||
return
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
fire_cone()
|
||||
if(health < maxHealth*0.5)
|
||||
SLEEP_CHECK_DEATH(10)
|
||||
@@ -153,8 +164,7 @@ Difficulty: Medium
|
||||
SetRecoveryTime(40)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/mass_fire(var/spiral_count = 12, var/range = 15, var/times = 3)
|
||||
if(QDELETED(src) || stat == DEAD)
|
||||
return
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
for(var/i = 1 to times)
|
||||
SetRecoveryTime(50)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
@@ -211,26 +221,24 @@ Difficulty: Medium
|
||||
return 1 // attack finished completely
|
||||
|
||||
/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
|
||||
if(QDELETED(src) || stat == DEAD)
|
||||
return //angry but helpless
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
SetRecoveryTime(80)
|
||||
visible_message("<span class='boldwarning'>[src] starts to glow vibrantly as its wounds close up!</span>")
|
||||
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
|
||||
light_range = 10
|
||||
sleep(10) // run.
|
||||
if(!QDELETED(src))
|
||||
if(stat != DEAD)
|
||||
mass_fire(20, 15, 3)
|
||||
move_to_delay = initial(move_to_delay)
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
light_range = initial(light_range)
|
||||
SLEEP_CHECK_DEATH(10) // run.
|
||||
mass_fire(20, 15, 3)
|
||||
move_to_delay = initial(move_to_delay)
|
||||
remove_atom_colour(TEMPORARY_COLOUR_PRIORITY)
|
||||
light_range = initial(light_range)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(var/atom/at = target)
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_cone(var/atom/at = target, var/meteors = TRUE)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
if(QDELETED(src) || stat == DEAD) // we dead no fire
|
||||
return
|
||||
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)
|
||||
@@ -253,6 +261,7 @@ Difficulty: Medium
|
||||
return (getline(src, T) - get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_line(var/list/turfs)
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
dragon_fire_line(src, turfs)
|
||||
|
||||
//fire line keeps going even if dragon is deleted
|
||||
@@ -317,16 +326,15 @@ Difficulty: Medium
|
||||
animate(src, alpha = 100, transform = matrix()*0.7, time = 7)
|
||||
swooping |= SWOOP_INVULNERABLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
sleep(7)
|
||||
//badmins please don't kill it while it's invulnerable
|
||||
SLEEP_CHECK_DEATH(7)
|
||||
|
||||
while(target && loc != get_turf(target))
|
||||
forceMove(get_step(src, get_dir(src, target)))
|
||||
sleep(0.5)
|
||||
SLEEP_CHECK_DEATH(0.5)
|
||||
|
||||
// Ash drake flies onto its target and rains fire down upon them
|
||||
var/descentTime = 10;
|
||||
var/lava_success = 1
|
||||
var/descentTime = 10
|
||||
var/lava_success = TRUE
|
||||
if(lava_arena)
|
||||
lava_success = lava_arena()
|
||||
|
||||
@@ -341,7 +349,7 @@ Difficulty: Medium
|
||||
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(descentTime)
|
||||
SLEEP_CHECK_DEATH(descentTime)
|
||||
swooping &= ~SWOOP_INVULNERABLE
|
||||
mouse_opacity = initial(mouse_opacity)
|
||||
icon_state = "dragon"
|
||||
@@ -366,23 +374,46 @@ Difficulty: Medium
|
||||
shake_camera(M, 15, 1)
|
||||
|
||||
density = TRUE
|
||||
sleep(1)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
swooping &= ~SWOOP_DAMAGEABLE
|
||||
SetRecoveryTime(swoop_cooldown)
|
||||
if(!lava_success)
|
||||
arena_escape_enrage()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
|
||||
if(!istype(A))
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/death()
|
||||
QDEL_NULL(internal) // so drake corpses don't have a gps signal
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target)
|
||||
if(severity == EXPLODE_LIGHT)
|
||||
return
|
||||
if(player_cooldown >= world.time)
|
||||
to_chat(src, "<span class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(!forced && (swooping & SWOOP_INVULNERABLE))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/visible_message()
|
||||
if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit
|
||||
return
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget()
|
||||
if(!swooping)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings()
|
||||
if(!swooping)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Move()
|
||||
if(!swooping)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/Goto(target, delay, minimum_distance)
|
||||
if(!swooping)
|
||||
..()
|
||||
|
||||
/obj/item/gps/internal/dragon
|
||||
icon_state = null
|
||||
@@ -495,6 +526,55 @@ Difficulty: Medium
|
||||
else
|
||||
animate(src, pixel_x = -16, pixel_z = 0, time = 5)
|
||||
|
||||
obj/effect/temp_visual/fireball
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "fireball"
|
||||
name = "fireball"
|
||||
desc = "Get out of the way!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = FALSE
|
||||
duration = 9
|
||||
pixel_z = 270
|
||||
|
||||
/obj/effect/temp_visual/fireball/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_z = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/target
|
||||
icon = 'icons/mob/actions/actions_items.dmi'
|
||||
icon_state = "sniper_zoom"
|
||||
layer = BELOW_MOB_LAYER
|
||||
light_range = 2
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/target/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/target/Initialize(mapload, list/flame_hit)
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/fall, flame_hit)
|
||||
|
||||
/obj/effect/temp_visual/target/proc/fall(list/flame_hit)
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(T,'sound/magic/fleshtostone.ogg', 80, 1)
|
||||
new /obj/effect/temp_visual/fireball(T)
|
||||
sleep(duration)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled()
|
||||
playsound(T, "explosion", 80, 1)
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700, 50, 1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
|
||||
continue
|
||||
if(islist(flame_hit) && !flame_hit[L])
|
||||
L.adjustFireLoss(40)
|
||||
to_chat(L, "<span class='userdanger'>You're hit by the drake's fire breath!</span>")
|
||||
flame_hit[L] = TRUE
|
||||
else
|
||||
L.adjustFireLoss(10) //if we've already hit them, do way less damage
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser
|
||||
name = "lesser ash drake"
|
||||
maxHealth = 200
|
||||
@@ -508,6 +588,17 @@ Difficulty: Medium
|
||||
loot = list()
|
||||
crusher_loot = list()
|
||||
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 class='warning'>You need to wait [(player_cooldown - world.time) / 10] seconds before swooping again!</span>")
|
||||
return
|
||||
swoop_attack(FALSE, A)
|
||||
lava_pools(10, 2) // less pools but longer delay before spawns
|
||||
player_cooldown = world.time + 200 // needs seperate cooldown or cant use fire attacks
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
@@ -534,21 +625,21 @@ Difficulty: Medium
|
||||
move_resist = MOVE_FORCE_NORMAL
|
||||
pull_force = MOVE_FORCE_NORMAL
|
||||
deathmessage = "screeches as its wings turn to dust and it collapses on the floor, life estinguished."
|
||||
var/datum/action/small_sprite/carpsprite = new/datum/action/small_sprite/spacedragon()
|
||||
attack_action_types = list()
|
||||
small_sprite_type = /datum/action/small_sprite/megafauna/spacedragon
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/grant_achievement(medaltype,scoretype)
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/Initialize()
|
||||
carpsprite.Grant(src)
|
||||
mob_spell_list += new /obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon(src)
|
||||
var/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon/repulse_action = new /obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon(src)
|
||||
repulse_action.action.Grant(src)
|
||||
mob_spell_list += repulse_action
|
||||
. = ..()
|
||||
smallsprite.Remove(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/proc/fire_stream(var/atom/at = target)
|
||||
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, 1)
|
||||
if(QDELETED(src) || stat == DEAD) // we dead no fire
|
||||
return
|
||||
SLEEP_CHECK_DEATH(0)
|
||||
var/range = 20
|
||||
var/list/turfs = list()
|
||||
turfs = line_target(0, range, at)
|
||||
@@ -584,3 +675,4 @@ Difficulty: Medium
|
||||
..(targets, user, 60)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/dragon/space_dragon/AltClickOn(atom/movable/A)
|
||||
return
|
||||
@@ -50,9 +50,9 @@ Difficulty: Hard
|
||||
armour_penetration = 50
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
speed = 1
|
||||
speed = 10
|
||||
move_to_delay = 10
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
ranged_cooldown_time = 40
|
||||
aggro_vision_range = 21 //so it can see to one side of the arena to the other
|
||||
loot = list(/obj/item/hierophant_club)
|
||||
@@ -63,6 +63,10 @@ Difficulty: Hard
|
||||
score_type = HIEROPHANT_SCORE
|
||||
del_on_death = TRUE
|
||||
deathsound = 'sound/magic/repulse.ogg'
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/blink,
|
||||
/datum/action/innate/megafauna_attack/chaser_swarm,
|
||||
/datum/action/innate/megafauna_attack/cross_blasts,
|
||||
/datum/action/innate/megafauna_attack/blink_spam)
|
||||
|
||||
var/burst_range = 3 //range on burst aoe
|
||||
var/beam_range = 5 //range on cross blast beams
|
||||
@@ -77,12 +81,301 @@ Difficulty: Hard
|
||||
var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...", "Kix fiex. Liepmrk...")
|
||||
var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
|
||||
var/list/stored_nearby = list() // stores people nearby the hierophant when it enters the death animation
|
||||
var/hierophant_dying = FALSE // if we're in the death animation and don't want to proc death repeatedly every time we take damage, do not set stat = dead or deathsounds and messages wont work
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/Initialize()
|
||||
. = ..()
|
||||
spawned_beacon = new(loc)
|
||||
|
||||
/datum/action/innate/megafauna_attack/blink
|
||||
name = "Blink To Target"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now blinking to your target.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/datum/action/innate/megafauna_attack/chaser_swarm
|
||||
name = "Chaser Swarm"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "hierophant_squares_indefinite"
|
||||
chosen_message = "<span class='colossus'>You are firing a chaser swarm at your target.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/datum/action/innate/megafauna_attack/cross_blasts
|
||||
name = "Cross Blasts"
|
||||
icon_icon = 'icons/effects/effects.dmi'
|
||||
button_icon_state = "hierophant_blast_indefinite"
|
||||
chosen_message = "<span class='colossus'>You are now firing cross blasts at your target.</span>"
|
||||
chosen_attack_num = 3
|
||||
|
||||
/datum/action/innate/megafauna_attack/blink_spam
|
||||
name = "Blink Chase"
|
||||
icon_icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
button_icon_state = "hierophant_club_ready_beacon"
|
||||
chosen_message = "<span class='colossus'>You are now repeatedly blinking at your target.</span>"
|
||||
chosen_attack_num = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
|
||||
if(blinking)
|
||||
return
|
||||
|
||||
calculate_rage()
|
||||
var/blink_counter = 1 + round(anger_modifier * 0.08)
|
||||
var/cross_counter = 1 + round(anger_modifier * 0.12)
|
||||
|
||||
arena_trap(target)
|
||||
ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
|
||||
|
||||
var/target_slowness = 0
|
||||
var/mob/living/L
|
||||
if(isliving(target))
|
||||
L = target
|
||||
target_slowness += L.movement_delay()
|
||||
if(client)
|
||||
target_slowness += 1
|
||||
|
||||
target_slowness = max(target_slowness, 1)
|
||||
chaser_speed = max(1, (3 - anger_modifier * 0.04) + ((target_slowness - 1) * 0.5))
|
||||
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
blink(target)
|
||||
if(2)
|
||||
chaser_swarm(blink_counter, target_slowness, cross_counter)
|
||||
if(3)
|
||||
cross_blast_spam(blink_counter, target_slowness, cross_counter)
|
||||
if(4)
|
||||
blink_spam(blink_counter, target_slowness, cross_counter)
|
||||
return
|
||||
|
||||
if(L?.stat == DEAD && !blinking && get_dist(src, L) > 2)
|
||||
blink(L)
|
||||
return
|
||||
|
||||
if(prob(anger_modifier * 0.75)) //major ranged attack
|
||||
var/list/possibilities = list()
|
||||
if(cross_counter > 1)
|
||||
possibilities += "cross_blast_spam"
|
||||
if(get_dist(src, target) > 2)
|
||||
possibilities += "blink_spam"
|
||||
if(chaser_cooldown < world.time)
|
||||
if(prob(anger_modifier * 2))
|
||||
possibilities = list("chaser_swarm")
|
||||
else
|
||||
possibilities += "chaser_swarm"
|
||||
if(possibilities.len)
|
||||
switch(pick(possibilities))
|
||||
if("blink_spam") //blink either once or multiple times.
|
||||
blink_spam(blink_counter, target_slowness, cross_counter)
|
||||
if("cross_blast_spam") //fire a lot of cross blasts at a target.
|
||||
cross_blast_spam(blink_counter, target_slowness, cross_counter)
|
||||
if("chaser_swarm") //fire four fucking chasers at a target and their friends.
|
||||
chaser_swarm(blink_counter, target_slowness, cross_counter)
|
||||
return
|
||||
|
||||
if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
|
||||
var/obj/effect/temp_visual/hierophant/chaser/C = new /obj/effect/temp_visual/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
|
||||
chaser_cooldown = world.time + initial(chaser_cooldown)
|
||||
if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
|
||||
var/obj/effect/temp_visual/hierophant/chaser/OC = new(loc, src, target, chaser_speed * 1.5, FALSE)
|
||||
OC.moving = 4
|
||||
OC.moving_dir = pick(GLOB.cardinals - C.moving_dir)
|
||||
|
||||
else if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
|
||||
blink(target)
|
||||
|
||||
else if(prob(70 - anger_modifier)) //a cross blast of some type
|
||||
if(prob(anger_modifier * (2 / target_slowness)) && health < maxHealth * 0.5) //we're super angry do it at all dirs
|
||||
INVOKE_ASYNC(src, .proc/blasts, target, GLOB.alldirs)
|
||||
else if(prob(60))
|
||||
INVOKE_ASYNC(src, .proc/blasts, target, GLOB.cardinals)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/blasts, target, GLOB.diagonals)
|
||||
else //just release a burst of power
|
||||
INVOKE_ASYNC(src, .proc/burst, get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink_spam(var/blink_counter, var/target_slowness, var/cross_counter)
|
||||
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
|
||||
if(health < maxHealth * 0.5 && blink_counter > 1)
|
||||
visible_message("<span class='hierophant'>\"Mx ampp rsx iwgeti.\"</span>")
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
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
|
||||
blink_counter--
|
||||
blinking = FALSE
|
||||
blink(target)
|
||||
blinking = TRUE
|
||||
SLEEP_CHECK_DEATH(4 + target_slowness)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
SLEEP_CHECK_DEATH(8)
|
||||
blinking = FALSE
|
||||
else
|
||||
blink(target)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cross_blast_spam(var/blink_counter, var/target_slowness, var/cross_counter)
|
||||
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
|
||||
visible_message("<span class='hierophant'>\"Piezi mx rsalivi xs vyr.\"</span>")
|
||||
blinking = TRUE
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
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)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
SLEEP_CHECK_DEATH(8)
|
||||
blinking = FALSE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/chaser_swarm(var/blink_counter, var/target_slowness, var/cross_counter)
|
||||
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
|
||||
visible_message("<span class='hierophant'>\"Mx gerrsx lmhi.\"</span>")
|
||||
blinking = TRUE
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
SLEEP_CHECK_DEATH(6)
|
||||
var/list/targets = ListTargets()
|
||||
var/list/cardinal_copy = GLOB.cardinals.Copy()
|
||||
while(targets.len && cardinal_copy.len)
|
||||
var/mob/living/pickedtarget = pick(targets)
|
||||
if(targets.len >= cardinal_copy.len)
|
||||
pickedtarget = pick_n_take(targets)
|
||||
if(!istype(pickedtarget) || pickedtarget.stat == DEAD)
|
||||
pickedtarget = target
|
||||
if(QDELETED(pickedtarget) || (istype(pickedtarget) && pickedtarget.stat == DEAD))
|
||||
break //main target is dead and we're out of living targets, cancel out
|
||||
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)
|
||||
chaser_cooldown = world.time + initial(chaser_cooldown)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
SLEEP_CHECK_DEATH(8)
|
||||
blinking = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blasts(mob/victim, var/list/directions = GLOB.cardinals) //fires cross blasts with a delay
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
if(directions == GLOB.cardinals)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/cardinal(T, src)
|
||||
else if(directions == GLOB.diagonals)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/diagonal(T, src)
|
||||
else
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
SLEEP_CHECK_DEATH(2)
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
|
||||
for(var/d in directions)
|
||||
INVOKE_ASYNC(src, .proc/blast_wall, T, d)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, set_dir) //make a wall of blasts beam_range tiles long
|
||||
var/range = beam_range
|
||||
var/turf/previousturf = T
|
||||
var/turf/J = get_step(previousturf, set_dir)
|
||||
for(var/i in 1 to range)
|
||||
new /obj/effect/temp_visual/hierophant/blast(J, src, FALSE)
|
||||
previousturf = J
|
||||
J = get_step(previousturf, set_dir)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_trap(mob/victim) //trap a target in an arena
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!istype(victim) || victim.stat == DEAD || !T || arena_cooldown > world.time)
|
||||
return
|
||||
if((istype(get_area(T), /area/ruin/unpowered/hierophant) || istype(get_area(src), /area/ruin/unpowered/hierophant)) && victim != src)
|
||||
return
|
||||
arena_cooldown = world.time + initial(arena_cooldown)
|
||||
for(var/d in GLOB.cardinals)
|
||||
INVOKE_ASYNC(src, .proc/arena_squares, T, d)
|
||||
for(var/t in RANGE_TURFS(11, T))
|
||||
if(t && get_dist(t, T) == 11)
|
||||
new /obj/effect/temp_visual/hierophant/wall(t, src)
|
||||
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
|
||||
if(get_dist(src, T) >= 11) //hey you're out of range I need to get closer to you!
|
||||
INVOKE_ASYNC(src, .proc/blink, T)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_squares(turf/T, set_dir) //make a fancy effect extending from the arena target
|
||||
var/turf/previousturf = T
|
||||
var/turf/J = get_step(previousturf, set_dir)
|
||||
for(var/i in 1 to 10)
|
||||
var/obj/effect/temp_visual/hierophant/squares/HS = new(J)
|
||||
HS.setDir(set_dir)
|
||||
previousturf = J
|
||||
J = get_step(previousturf, set_dir)
|
||||
SLEEP_CHECK_DEATH(0.5)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
|
||||
if(blinking || !victim)
|
||||
return
|
||||
var/turf/T = get_turf(victim)
|
||||
var/turf/source = get_turf(src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(source, src)
|
||||
playsound(T,'sound/magic/wand_teleport.ogg', 200, 1)
|
||||
playsound(source,'sound/machines/airlockopen.ogg', 200, 1)
|
||||
blinking = TRUE
|
||||
SLEEP_CHECK_DEATH(2) //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))
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
|
||||
B.damage = 30
|
||||
for(var/t in RANGE_TURFS(1, source))
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
|
||||
B.damage = 30
|
||||
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
visible_message("<span class='hierophant_warning'>[src] fades out!</span>")
|
||||
density = FALSE
|
||||
SLEEP_CHECK_DEATH(2)
|
||||
forceMove(T)
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
|
||||
SLEEP_CHECK_DEATH(1)
|
||||
density = TRUE
|
||||
visible_message("<span class='hierophant_warning'>[src] fades in!</span>")
|
||||
SLEEP_CHECK_DEATH(1) //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
|
||||
if(!victim)
|
||||
return
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
SLEEP_CHECK_DEATH(2)
|
||||
for(var/t in RANGE_TURFS(1, T))
|
||||
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
|
||||
|
||||
//expanding square
|
||||
/proc/hierophant_burst(mob/caster, turf/original, burst_range, spread_speed = 0.5)
|
||||
playsound(original,'sound/machines/airlockopen.ogg', 200, 1)
|
||||
var/last_dist = 0
|
||||
for(var/t in spiral_range_turfs(burst_range, original))
|
||||
var/turf/T = t
|
||||
if(!T)
|
||||
continue
|
||||
var/dist = get_dist(original, T)
|
||||
if(dist > last_dist)
|
||||
last_dist = dist
|
||||
sleep(1 + min(burst_range - last_dist, 12) * spread_speed) //gets faster as it gets further out
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, caster, FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original, spread_speed)
|
||||
hierophant_burst(src, original, burst_range, spread_speed)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/Life()
|
||||
. = ..()
|
||||
if(. && spawned_beacon && !QDELETED(spawned_beacon) && !client)
|
||||
@@ -102,16 +395,17 @@ Difficulty: Hard
|
||||
visible_message("<span class='hierophant'>\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/death()
|
||||
if(health > 0 || hierophant_dying)
|
||||
if(health > 0 || stat == DEAD)
|
||||
return
|
||||
else
|
||||
hierophant_dying = TRUE
|
||||
stat = DEAD
|
||||
blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
|
||||
visible_message("<span class='hierophant'>\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"</span>")
|
||||
visible_message("<span class='hierophant_warning'>[src] shrinks, releasing a massive burst of energy!</span>")
|
||||
for(var/mob/living/L in view(7,src))
|
||||
stored_nearby += L // store the people to grant the achievements to once we die
|
||||
hierophant_burst(null, get_turf(src), 10)
|
||||
stat = CONSCIOUS // deathgasp wont run if dead, stupid
|
||||
..(force_grant = stored_nearby)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/Destroy()
|
||||
@@ -142,7 +436,7 @@ Difficulty: Hard
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(src && . > 0 && !blinking)
|
||||
if(src && . && !blinking)
|
||||
wander = TRUE
|
||||
did_reset = FALSE
|
||||
|
||||
@@ -191,260 +485,6 @@ Difficulty: Hard
|
||||
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
|
||||
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
|
||||
calculate_rage()
|
||||
if(blinking)
|
||||
return
|
||||
|
||||
var/target_slowness = 0
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!blinking && L.stat == DEAD && get_dist(src, L) > 2)
|
||||
blink(L)
|
||||
return
|
||||
target_slowness += L.movement_delay()
|
||||
target_slowness = max(target_slowness, 1)
|
||||
chaser_speed = max(1, (3 - anger_modifier * 0.04) + ((target_slowness - 1) * 0.5))
|
||||
|
||||
arena_trap(target)
|
||||
ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
|
||||
|
||||
if(prob(anger_modifier * 0.75)) //major ranged attack
|
||||
var/list/possibilities = list()
|
||||
var/cross_counter = 1 + round(anger_modifier * 0.12)
|
||||
if(cross_counter > 1)
|
||||
possibilities += "cross_blast_spam"
|
||||
if(get_dist(src, target) > 2)
|
||||
possibilities += "blink_spam"
|
||||
if(chaser_cooldown < world.time)
|
||||
if(prob(anger_modifier * 2))
|
||||
possibilities = list("chaser_swarm")
|
||||
else
|
||||
possibilities += "chaser_swarm"
|
||||
if(possibilities.len)
|
||||
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75) //we didn't cancel out of an attack, use the higher cooldown
|
||||
var/blink_counter = 1 + round(anger_modifier * 0.08)
|
||||
switch(pick(possibilities))
|
||||
if("blink_spam") //blink either once or multiple times.
|
||||
if(health < maxHealth * 0.5 && blink_counter > 1)
|
||||
visible_message("<span class='hierophant'>\"Mx ampp rsx iwgeti.\"</span>")
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
sleep(6)
|
||||
while(health && !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
|
||||
blink_counter--
|
||||
blinking = FALSE
|
||||
blink(target)
|
||||
blinking = TRUE
|
||||
sleep(4 + target_slowness)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
sleep(8)
|
||||
blinking = FALSE
|
||||
else
|
||||
blink(target)
|
||||
if("cross_blast_spam") //fire a lot of cross blasts at a target.
|
||||
visible_message("<span class='hierophant'>\"Piezi mx rsalivi xs vyr.\"</span>")
|
||||
blinking = TRUE
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
sleep(6)
|
||||
while(health && !QDELETED(target) && cross_counter)
|
||||
cross_counter--
|
||||
if(prob(60))
|
||||
INVOKE_ASYNC(src, .proc/cardinal_blasts, target)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/diagonal_blasts, target)
|
||||
sleep(6 + target_slowness)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
sleep(8)
|
||||
blinking = FALSE
|
||||
if("chaser_swarm") //fire four fucking chasers at a target and their friends.
|
||||
visible_message("<span class='hierophant'>\"Mx gerrsx lmhi.\"</span>")
|
||||
blinking = TRUE
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#660099", time = 6)
|
||||
sleep(6)
|
||||
var/list/targets = ListTargets()
|
||||
var/list/cardinal_copy = GLOB.cardinals.Copy()
|
||||
while(health && targets.len && cardinal_copy.len)
|
||||
var/mob/living/pickedtarget = pick(targets)
|
||||
if(targets.len >= cardinal_copy.len)
|
||||
pickedtarget = pick_n_take(targets)
|
||||
if(!istype(pickedtarget) || pickedtarget.stat == DEAD)
|
||||
pickedtarget = target
|
||||
if(QDELETED(pickedtarget) || (istype(pickedtarget) && pickedtarget.stat == DEAD))
|
||||
break //main target is dead and we're out of living targets, cancel out
|
||||
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(8 + target_slowness)
|
||||
chaser_cooldown = world.time + initial(chaser_cooldown)
|
||||
animate(src, color = oldcolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
sleep(8)
|
||||
blinking = FALSE
|
||||
return
|
||||
|
||||
if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
|
||||
var/obj/effect/temp_visual/hierophant/chaser/C = new /obj/effect/temp_visual/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
|
||||
chaser_cooldown = world.time + initial(chaser_cooldown)
|
||||
if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
|
||||
var/obj/effect/temp_visual/hierophant/chaser/OC = new(loc, src, target, chaser_speed * 1.5, FALSE)
|
||||
OC.moving = 4
|
||||
OC.moving_dir = pick(GLOB.cardinals - C.moving_dir)
|
||||
|
||||
else if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
|
||||
blink(target)
|
||||
|
||||
else if(prob(70 - anger_modifier)) //a cross blast of some type
|
||||
if(prob(anger_modifier * (2 / target_slowness)) && health < maxHealth * 0.5) //we're super angry do it at all dirs
|
||||
INVOKE_ASYNC(src, .proc/alldir_blasts, target)
|
||||
else if(prob(60))
|
||||
INVOKE_ASYNC(src, .proc/cardinal_blasts, target)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/diagonal_blasts, target)
|
||||
else //just release a burst of power
|
||||
INVOKE_ASYNC(src, .proc/burst, get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/diagonal_blasts(mob/victim) //fire diagonal cross blasts with a delay
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/diagonal(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
sleep(2)
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
|
||||
for(var/d in GLOB.diagonals)
|
||||
INVOKE_ASYNC(src, .proc/blast_wall, T, d)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cardinal_blasts(mob/victim) //fire cardinal cross blasts with a delay
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/telegraph/cardinal(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
sleep(2)
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
|
||||
for(var/d in GLOB.cardinals)
|
||||
INVOKE_ASYNC(src, .proc/blast_wall, T, d)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/alldir_blasts(mob/victim) //fire alldir cross blasts with a delay
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
sleep(2)
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
|
||||
for(var/d in GLOB.alldirs)
|
||||
INVOKE_ASYNC(src, .proc/blast_wall, T, d)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, set_dir) //make a wall of blasts beam_range tiles long
|
||||
var/range = beam_range
|
||||
var/turf/previousturf = T
|
||||
var/turf/J = get_step(previousturf, set_dir)
|
||||
for(var/i in 1 to range)
|
||||
new /obj/effect/temp_visual/hierophant/blast(J, src, FALSE)
|
||||
previousturf = J
|
||||
J = get_step(previousturf, set_dir)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_trap(mob/victim) //trap a target in an arena
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!istype(victim) || victim.stat == DEAD || !T || arena_cooldown > world.time)
|
||||
return
|
||||
if((istype(get_area(T), /area/ruin/unpowered/hierophant) || istype(get_area(src), /area/ruin/unpowered/hierophant)) && victim != src)
|
||||
return
|
||||
arena_cooldown = world.time + initial(arena_cooldown)
|
||||
for(var/d in GLOB.cardinals)
|
||||
INVOKE_ASYNC(src, .proc/arena_squares, T, d)
|
||||
for(var/t in RANGE_TURFS(11, T))
|
||||
if(t && get_dist(t, T) == 11)
|
||||
new /obj/effect/temp_visual/hierophant/wall(t, src)
|
||||
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
|
||||
if(get_dist(src, T) >= 11) //hey you're out of range I need to get closer to you!
|
||||
INVOKE_ASYNC(src, .proc/blink, T)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_squares(turf/T, set_dir) //make a fancy effect extending from the arena target
|
||||
var/turf/previousturf = T
|
||||
var/turf/J = get_step(previousturf, set_dir)
|
||||
for(var/i in 1 to 10)
|
||||
var/obj/effect/temp_visual/hierophant/squares/HS = new(J)
|
||||
HS.setDir(set_dir)
|
||||
previousturf = J
|
||||
J = get_step(previousturf, set_dir)
|
||||
sleep(0.5)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
|
||||
if(blinking || !victim)
|
||||
return
|
||||
var/turf/T = get_turf(victim)
|
||||
var/turf/source = get_turf(src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(source, src)
|
||||
playsound(T,'sound/magic/wand_teleport.ogg', 200, 1)
|
||||
playsound(source,'sound/machines/airlockopen.ogg', 200, 1)
|
||||
blinking = TRUE
|
||||
sleep(2) //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))
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
|
||||
B.damage = 30
|
||||
for(var/t in RANGE_TURFS(1, source))
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
|
||||
B.damage = 30
|
||||
animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
|
||||
sleep(1)
|
||||
visible_message("<span class='hierophant_warning'>[src] fades out!</span>")
|
||||
density = FALSE
|
||||
sleep(2)
|
||||
forceMove(T)
|
||||
sleep(1)
|
||||
animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
|
||||
sleep(1)
|
||||
density = TRUE
|
||||
visible_message("<span class='hierophant_warning'>[src] fades in!</span>")
|
||||
sleep(1) //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
|
||||
if(!victim)
|
||||
return
|
||||
var/turf/T = get_turf(victim)
|
||||
if(!T)
|
||||
return
|
||||
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
|
||||
playsound(T,'sound/effects/bin_close.ogg', 200, 1)
|
||||
sleep(2)
|
||||
for(var/t in RANGE_TURFS(1, T))
|
||||
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
|
||||
|
||||
//expanding square
|
||||
/proc/hierophant_burst(mob/caster, turf/original, burst_range, spread_speed = 0.5)
|
||||
playsound(original,'sound/machines/airlockopen.ogg', 200, 1)
|
||||
var/last_dist = 0
|
||||
for(var/t in spiral_range_turfs(burst_range, original))
|
||||
var/turf/T = t
|
||||
if(!T)
|
||||
continue
|
||||
var/dist = get_dist(original, T)
|
||||
if(dist > last_dist)
|
||||
last_dist = dist
|
||||
sleep(1 + min(burst_range - last_dist, 12) * spread_speed) //gets faster as it gets further out
|
||||
new /obj/effect/temp_visual/hierophant/blast(T, caster, FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original, spread_speed)
|
||||
hierophant_burst(src, original, burst_range, spread_speed)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
|
||||
if(!istype(A) || get_dist(A, src) <= 2)
|
||||
return
|
||||
blink(A)
|
||||
|
||||
//Hierophant overlays
|
||||
/obj/effect/temp_visual/hierophant
|
||||
name = "vortex energy"
|
||||
|
||||
@@ -20,7 +20,6 @@ Difficulty: Medium
|
||||
name = "Legion"
|
||||
health = 800
|
||||
maxHealth = 800
|
||||
spacewalk = TRUE
|
||||
icon_state = "legion"
|
||||
icon_living = "legion"
|
||||
desc = "One of many."
|
||||
@@ -31,14 +30,14 @@ Difficulty: Medium
|
||||
armour_penetration = 50
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
speed = 2
|
||||
ranged = 1
|
||||
del_on_death = 1
|
||||
speed = 5
|
||||
ranged = TRUE
|
||||
del_on_death = TRUE
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
ranged_cooldown_time = 20
|
||||
var/size = 5
|
||||
var/charging = 0
|
||||
var/charging = FALSE
|
||||
internal_type = /obj/item/gps/internal/legion
|
||||
medal_type = BOSS_MEDAL_LEGION
|
||||
score_type = LEGION_SCORE
|
||||
@@ -47,9 +46,60 @@ Difficulty: Medium
|
||||
loot = list(/obj/item/stack/sheet/bone = 3)
|
||||
vision_range = 13
|
||||
wander = FALSE
|
||||
elimination = 1
|
||||
elimination = TRUE
|
||||
appearance_flags = 0
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
attack_action_types = list(/datum/action/innate/megafauna_attack/create_skull,
|
||||
/datum/action/innate/megafauna_attack/charge_target)
|
||||
small_sprite_type = /datum/action/small_sprite/megafauna/legion
|
||||
|
||||
/datum/action/innate/megafauna_attack/create_skull
|
||||
name = "Create Legion Skull"
|
||||
icon_icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
|
||||
button_icon_state = "legion_head"
|
||||
chosen_message = "<span class='colossus'>You are now creating legion skulls.</span>"
|
||||
chosen_attack_num = 1
|
||||
|
||||
/datum/action/innate/megafauna_attack/charge_target
|
||||
name = "Charge Target"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
chosen_message = "<span class='colossus'>You are now charging at your target.</span>"
|
||||
chosen_attack_num = 2
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target)
|
||||
if(charging)
|
||||
return
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
|
||||
if(client)
|
||||
switch(chosen_attack)
|
||||
if(1)
|
||||
create_legion_skull()
|
||||
if(2)
|
||||
charge_target()
|
||||
return
|
||||
|
||||
if(prob(75))
|
||||
create_legion_skull()
|
||||
else
|
||||
charge_target()
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/proc/create_legion_skull()
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
|
||||
A.GiveTarget(target)
|
||||
A.friends = friends
|
||||
A.faction = faction
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/proc/charge_target()
|
||||
visible_message("<span class='warning'><b>[src] charges!</b></span>")
|
||||
SpinAnimation(speed = 20, loops = 5)
|
||||
ranged = FALSE
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
set_varspeed(0)
|
||||
charging = TRUE
|
||||
addtimer(CALLBACK(src, .proc/reset_charge), 50)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/GiveTarget(new_target)
|
||||
. = ..()
|
||||
@@ -69,30 +119,12 @@ Difficulty: Medium
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
|
||||
A.infest(L)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target)
|
||||
if(world.time >= ranged_cooldown && !charging)
|
||||
if(prob(75))
|
||||
var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
|
||||
A.GiveTarget(target)
|
||||
A.friends = friends
|
||||
A.faction = faction
|
||||
ranged_cooldown = world.time + ranged_cooldown_time
|
||||
else
|
||||
visible_message("<span class='warning'><b>[src] charges!</b></span>")
|
||||
SpinAnimation(speed = 20, loops = 5)
|
||||
ranged = 0
|
||||
retreat_distance = 0
|
||||
minimum_distance = 0
|
||||
speed = 0
|
||||
charging = 1
|
||||
addtimer(CALLBACK(src, .proc/reset_charge), 50)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge()
|
||||
ranged = 1
|
||||
ranged = TRUE
|
||||
retreat_distance = 5
|
||||
minimum_distance = 5
|
||||
speed = 2
|
||||
charging = 0
|
||||
set_varspeed(2)
|
||||
charging = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/legion/death()
|
||||
if(health > 0)
|
||||
@@ -130,7 +162,7 @@ Difficulty: Medium
|
||||
break
|
||||
if(last_legion)
|
||||
loot = list(/obj/item/staff/storm)
|
||||
elimination = 0
|
||||
elimination = FALSE
|
||||
else if(prob(5))
|
||||
loot = list(/obj/structure/closet/crate/necropolis/tendril)
|
||||
if(!true_spawn)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
desc = "Attack the weak point for massive damage."
|
||||
health = 1000
|
||||
maxHealth = 1000
|
||||
spacewalk = TRUE
|
||||
a_intent = INTENT_HARM
|
||||
sentience_type = SENTIENCE_BOSS
|
||||
environment_smash = ENVIRONMENT_SMASH_RWALLS
|
||||
@@ -12,7 +13,7 @@
|
||||
faction = list("mining", "boss")
|
||||
weather_immunities = list("lava","ash")
|
||||
movement_type = FLYING
|
||||
robust_searching = 1
|
||||
robust_searching = TRUE
|
||||
ranged_ignores_vision = TRUE
|
||||
stat_attack = DEAD
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
@@ -35,8 +36,11 @@
|
||||
var/obj/item/gps/internal
|
||||
var/internal_type
|
||||
var/recovery_time = 0
|
||||
var/true_spawn = 1 // if this is a megafauna that should grant achievements, or have a gps signal
|
||||
var/true_spawn = TRUE // if this is a megafauna that should grant achievements, or have a gps signal
|
||||
var/nest_range = 10
|
||||
var/chosen_attack = 1 // chosen attack num
|
||||
var/list/attack_action_types = list()
|
||||
var/small_sprite_type
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -44,6 +48,12 @@
|
||||
internal = new internal_type(src)
|
||||
apply_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
|
||||
ADD_TRAIT(src, TRAIT_NO_TELEPORT, MEGAFAUNA_TRAIT)
|
||||
for(var/action_type in attack_action_types)
|
||||
var/datum/action/innate/megafauna_attack/attack_action = new action_type()
|
||||
attack_action.Grant(src)
|
||||
if(small_sprite_type)
|
||||
var/datum/action/small_sprite/small_action = new small_sprite_type()
|
||||
small_action.Grant(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/Destroy()
|
||||
QDEL_NULL(internal)
|
||||
@@ -109,13 +119,14 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L)
|
||||
if(!L)
|
||||
return
|
||||
return FALSE
|
||||
visible_message(
|
||||
"<span class='danger'>[src] devours [L]!</span>",
|
||||
"<span class='userdanger'>You feast on [L], restoring your health!</span>")
|
||||
if(!is_station_level(z) || client) //NPC monsters won't heal while on station
|
||||
adjustBruteLoss(-L.maxHealth/2)
|
||||
L.gib()
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/ex_act(severity, target)
|
||||
switch (severity)
|
||||
@@ -149,3 +160,21 @@
|
||||
SSmedals.SetScore(BOSS_SCORE, C, 1)
|
||||
SSmedals.SetScore(score_type, C, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/megafauna_attack
|
||||
name = "Megafauna Attack"
|
||||
icon_icon = 'icons/mob/actions/actions_animal.dmi'
|
||||
button_icon_state = ""
|
||||
var/mob/living/simple_animal/hostile/megafauna/M
|
||||
var/chosen_message
|
||||
var/chosen_attack_num = 0
|
||||
|
||||
/datum/action/innate/megafauna_attack/Grant(mob/living/L)
|
||||
if(istype(L, /mob/living/simple_animal/hostile/megafauna))
|
||||
M = L
|
||||
return ..()
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/megafauna_attack/Activate()
|
||||
M.chosen_attack = chosen_attack_num
|
||||
to_chat(M, chosen_message)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 112 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 866 KiB After Width: | Height: | Size: 869 KiB |
Reference in New Issue
Block a user