diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 3d62e850e8..bc9251d9fc 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -35,7 +35,6 @@
..()
if(randomdir)
setDir(pick(GLOB.cardinal))
- flick("[icon_state]", src) //Because we might be pulling it from a pool, flick whatever icon it uses so it starts at the start of the icon's animation.
timerid = QDEL_IN(src, duration)
@@ -214,7 +213,7 @@
icon = 'icons/effects/fire.dmi'
icon_state = "3"
duration = 20
-
+
/obj/effect/overlay/temp/cult
randomdir = 0
duration = 10
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 2e64ee526e..fa61a16e51 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -150,7 +150,7 @@ Difficulty: Hard
var/turf/T = get_turf(target)
if(!T || T == loc)
return
- new /obj/effect/overlay/temp/dragon_swoop(T)
+ new /obj/effect/overlay/temp/dragon_swoop/bubblegum(T)
charging = TRUE
DestroySurroundings()
walk(src, 0)
@@ -276,6 +276,9 @@ Difficulty: Hard
addtimer(CALLBACK(src, .proc/devour, L), 2)
sleep(1)
+/obj/effect/overlay/temp/dragon_swoop/bubblegum
+ duration = 10
+
/obj/effect/overlay/temp/bubblegum_hands
icon = 'icons/effects/bubblegum.dmi'
duration = 9
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
index c56e963aef..3425d08e23 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
@@ -1,4 +1,10 @@
#define MEDAL_PREFIX "Drake"
+
+#define DRAKE_SWOOP_HEIGHT 270 //how high up drakes go, in pixels
+#define DRAKE_SWOOP_DIRECTION_CHANGE_RANGE 5 //the range our x has to be within to not change the direction we slam from
+
+#define SWOOP_DAMAGEABLE 1
+#define SWOOP_INVULNERABLE 2
/*
ASH DRAKE
@@ -9,8 +15,9 @@ It acts as a melee creature, chasing down and attacking its target while also us
Whenever possible, the drake will breathe fire in the four cardinal directions, igniting and heavily damaging anything caught in the blast.
It also often causes fire to rain from the sky - many nearby turfs will flash red as a fireball crashes into them, dealing damage to anything on the turfs.
-The drake also utilizes its wings to fly into the sky and crash down onto a specified point. Anything on this point takes tremendous damage.
+The drake also utilizes its wings to fly into the sky, flying after its target and attempting to slam down on them. Anything near when it slams down takes huge damage.
- Sometimes it will chain these swooping attacks over and over, making swiftness a necessity.
+ - Sometimes, it will spew fire while flying at its target.
When an ash drake dies, it leaves behind a chest that can contain four things:
1. A spectral blade that allows its wielder to call ghosts to it, enhancing its power
@@ -46,7 +53,7 @@ Difficulty: Medium
pixel_x = -16
loot = list(/obj/structure/closet/crate/necropolis/dragon)
butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30)
- var/swooping = 0
+ var/swooping = NONE
var/swoop_cooldown = 0
medal_type = MEDAL_PREFIX
score_type = DRAKE_SCORE
@@ -63,10 +70,15 @@ Difficulty: Medium
..()
/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
- if(!forced && swooping)
+ 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 ..()
@@ -86,62 +98,15 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/Process_Spacemove(movement_dir = 0)
return 1
-/obj/effect/overlay/temp/fireball
- icon = 'icons/obj/wizard.dmi'
- icon_state = "fireball"
- name = "fireball"
- desc = "Get out of the way!"
- layer = FLY_LAYER
- randomdir = 0
- duration = 12
- pixel_z = 500
-
-/obj/effect/overlay/temp/fireball/Initialize(loc)
- . = ..()
- animate(src, pixel_z = 0, time = 12)
-
-/obj/effect/overlay/temp/target
- icon = 'icons/mob/actions.dmi'
- icon_state = "sniper_zoom"
- layer = BELOW_MOB_LAYER
- light_range = 2
- duration = 12
-
-/obj/effect/overlay/temp/dragon_swoop
- name = "certain death"
- desc = "Don't just stand there, move!"
- icon = 'icons/effects/96x96.dmi'
- icon_state = "landing"
- layer = BELOW_MOB_LAYER
- pixel_x = -32
- pixel_y = -32
- color = "#FF0000"
- duration = 10
-
-/obj/effect/overlay/temp/target/ex_act()
- return
-
-/obj/effect/overlay/temp/target/Initialize(loc)
- . = ..()
- INVOKE_ASYNC(src, .proc/fall)
-
-/obj/effect/overlay/temp/target/proc/fall()
- var/turf/T = get_turf(src)
- playsound(T,'sound/magic/Fireball.ogg', 200, 1)
- new /obj/effect/overlay/temp/fireball(T)
- sleep(12)
- explosion(T, 0, 0, 1, 0, 0, 0, 1)
-
/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(swooping)
- fire_rain()
- return
if(prob(15 + anger_modifier) && !client)
if(health < maxHealth/2)
- INVOKE_ASYNC(src, .proc/swoop_attack, 1)
+ INVOKE_ASYNC(src, .proc/swoop_attack, TRUE, null, 50)
else
fire_rain()
@@ -154,9 +119,11 @@ Difficulty: Medium
fire_walls()
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain()
- visible_message("Fire rains from the sky!")
- for(var/turf/turf in range(12,get_turf(src)))
- if(prob(10))
+ if(!target)
+ return
+ target.visible_message("Fire rains from the sky!")
+ for(var/turf/turf in range(9,get_turf(target)))
+ if(prob(11))
new /obj/effect/overlay/temp/target(turf)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls()
@@ -177,6 +144,8 @@ Difficulty: Medium
new /obj/effect/hotspot(J)
J.hotspot_expose(700,50,1)
for(var/mob/living/L in J.contents - hit_things)
+ if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
+ continue
L.adjustFireLoss(20)
to_chat(L, "You're hit by the drake's fire breath!")
hit_things += L
@@ -184,43 +153,86 @@ Difficulty: Medium
sleep(1)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop()
- swoop_attack()
- swoop_attack()
- swoop_attack()
+ swoop_attack(swoop_duration = 30)
+ swoop_attack(swoop_duration = 30)
+ swoop_attack(swoop_duration = 30)
-/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain = 0, atom/movable/manual_target)
+/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain, atom/movable/manual_target, swoop_duration = 40)
if(stat || swooping)
return
- swoop_cooldown = world.time + 200
- var/atom/swoop_target
if(manual_target)
- swoop_target = manual_target
- else
- swoop_target = target
+ target = manual_target
+ if(!target)
+ return
+ swoop_cooldown = world.time + 200
stop_automated_movement = TRUE
- swooping = 1
- density = 0
- icon_state = "swoop"
+ swooping |= SWOOP_DAMAGEABLE
+ density = FALSE
+ icon_state = "shadow"
visible_message("[src] swoops up high!")
- if(prob(50))
- animate(src, pixel_x = 500, pixel_z = 500, time = 10)
+
+ var/negative
+ var/initial_x = x
+ if(target.x < initial_x) //if the target's x is lower than ours, swoop to the left
+ negative = TRUE
+ else if(target.x > initial_x)
+ negative = FALSE
+ else if(target.x == initial_x) //if their x is the same, pick a direction
+ negative = prob(50)
+ var/obj/effect/overlay/temp/dragon_flight/F = new /obj/effect/overlay/temp/dragon_flight(loc, negative)
+
+ negative = !negative //invert it for the swoop down later
+
+ var/oldtransform = transform
+ animate(src, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING)
+ for(var/i in 1 to 3)
+ sleep(1)
+ if(QDELETED(src)) //we got hit and died, rip us
+ qdel(F)
+ return
+ animate(src, transform = matrix()*0.7, time = 7)
+ swooping |= SWOOP_INVULNERABLE
+ sleep(7)
+ var/list/flame_hit = list()
+ while(swoop_duration > 0)
+ if(!target && !FindTarget())
+ break //we lost our target while chasing it down and couldn't get a new one
+ if(swoop_duration < 7)
+ fire_rain = FALSE //stop raining fire near the end of the swoop
+ if(loc == get_turf(target))
+ if(!fire_rain)
+ break //we're not spewing fire at our target, slam they
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ break //target is dead and we're on em, slam they
+ if(fire_rain)
+ new /obj/effect/overlay/temp/target(loc, flame_hit)
+ forceMove(get_step(src, get_dir(src, target)))
+ if(loc == get_turf(target))
+ if(!fire_rain)
+ break
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ break
+ var/swoop_speed = 1.5
+ swoop_duration -= swoop_speed
+ sleep(swoop_speed)
+
+ //ensure swoop direction continuity.
+ if(negative)
+ if(IsInRange(x, initial_x + 1, initial_x + DRAKE_SWOOP_DIRECTION_CHANGE_RANGE))
+ negative = FALSE
else
- animate(src, pixel_x = -500, pixel_z = 500, time = 10)
- sleep(30)
-
- var/turf/tturf
- if(fire_rain)
- fire_rain()
-
+ if(IsInRange(x, initial_x - DRAKE_SWOOP_DIRECTION_CHANGE_RANGE, initial_x - 1))
+ negative = TRUE
+ new /obj/effect/overlay/temp/dragon_flight/end(loc, negative)
+ new /obj/effect/overlay/temp/dragon_swoop(loc)
+ animate(src, transform = oldtransform, time = 5)
+ sleep(5)
+ swooping &= ~SWOOP_INVULNERABLE
icon_state = "dragon"
- if(swoop_target && !QDELETED(swoop_target) && swoop_target.z == src.z)
- tturf = get_turf(swoop_target)
- else
- tturf = get_turf(src)
- forceMove(tturf)
- new /obj/effect/overlay/temp/dragon_swoop(tturf)
- animate(src, pixel_x = initial(pixel_x), pixel_z = 0, time = 10)
- sleep(10)
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1)
for(var/mob/living/L in orange(1, src))
if(L.stat)
@@ -239,9 +251,9 @@ Difficulty: Medium
for(var/mob/M in range(7, src))
shake_camera(M, 15, 1)
- stop_automated_movement = FALSE
- swooping = 0
- density = 1
+ density = TRUE
+ sleep(1)
+ swooping &= ~SWOOP_DAMAGEABLE
/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A)
if(!istype(A))
@@ -249,7 +261,7 @@ Difficulty: Medium
if(swoop_cooldown >= world.time)
to_chat(src, "You need to wait 20 seconds between swoop attacks!")
return
- swoop_attack(1, A)
+ swoop_attack(TRUE, A, 25)
/obj/item/device/gps/internal/dragon
icon_state = null
@@ -257,6 +269,103 @@ Difficulty: Medium
desc = "Here there be dragons."
invisibility = 100
+
+/obj/effect/overlay/temp/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 = DRAKE_SWOOP_HEIGHT
+
+/obj/effect/overlay/temp/fireball/Initialize()
+ . = ..()
+ animate(src, pixel_z = 0, time = duration)
+
+/obj/effect/overlay/temp/target
+ icon = 'icons/mob/actions.dmi'
+ icon_state = "sniper_zoom"
+ layer = BELOW_MOB_LAYER
+ light_range = 2
+ duration = 9
+
+/obj/effect/overlay/temp/target/ex_act()
+ return
+
+/obj/effect/overlay/temp/target/Initialize(mapload, list/flame_hit)
+ . = ..()
+ INVOKE_ASYNC(src, .proc/fall, flame_hit)
+
+/obj/effect/overlay/temp/target/proc/fall(list/flame_hit)
+ var/turf/T = get_turf(src)
+ playsound(T,'sound/magic/Fireball.ogg', 80, 1)
+ new /obj/effect/overlay/temp/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, "You're hit by the drake's fire breath!")
+ flame_hit[L] = TRUE
+ else
+ L.adjustFireLoss(10) //if we've already hit them, do way less damage
+
+/obj/effect/overlay/temp/dragon_swoop
+ name = "certain death"
+ desc = "Don't just stand there, move!"
+ icon = 'icons/effects/96x96.dmi'
+ icon_state = "landing"
+ layer = BELOW_MOB_LAYER
+ pixel_x = -32
+ pixel_y = -32
+ color = "#FF0000"
+ duration = 5
+
+/obj/effect/overlay/temp/dragon_flight
+ icon = 'icons/mob/lavaland/dragon.dmi'
+ icon_state = "dragon"
+ layer = ABOVE_ALL_MOB_LAYER
+ pixel_x = -16
+ duration = 10
+ randomdir = FALSE
+
+/obj/effect/overlay/temp/dragon_flight/Initialize(mapload, negative)
+ . = ..()
+ INVOKE_ASYNC(src, .proc/flight, negative)
+
+/obj/effect/overlay/temp/dragon_flight/proc/flight(negative)
+ if(negative)
+ animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT*0.10, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
+ else
+ animate(src, pixel_x = DRAKE_SWOOP_HEIGHT*0.10, pixel_z = DRAKE_SWOOP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING)
+ sleep(3)
+ icon_state = "swoop"
+ if(negative)
+ animate(src, pixel_x = -DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
+ else
+ animate(src, pixel_x = DRAKE_SWOOP_HEIGHT, pixel_z = DRAKE_SWOOP_HEIGHT, time = 7)
+
+/obj/effect/overlay/temp/dragon_flight/end
+ pixel_x = DRAKE_SWOOP_HEIGHT
+ pixel_z = DRAKE_SWOOP_HEIGHT
+ duration = 5
+
+/obj/effect/overlay/temp/dragon_flight/end/flight(negative)
+ if(negative)
+ pixel_x = -DRAKE_SWOOP_HEIGHT
+ animate(src, pixel_x = -16, pixel_z = 0, time = 5)
+ else
+ animate(src, pixel_x = -16, pixel_z = 0, time = 5)
+
/mob/living/simple_animal/hostile/megafauna/dragon/lesser
name = "lesser ash drake"
maxHealth = 200
diff --git a/icons/mob/lavaland/dragon.dmi b/icons/mob/lavaland/dragon.dmi
index 7e44b775de..911d7288d1 100644
Binary files a/icons/mob/lavaland/dragon.dmi and b/icons/mob/lavaland/dragon.dmi differ