[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:
Whoneedspacee
2019-06-09 17:24:38 -04:00
committed by moo
parent 907375f5c6
commit 7c674ea486
11 changed files with 1085 additions and 761 deletions
+16 -2
View File
@@ -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"
-49
View File
@@ -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