Files
SkyratBot e229fa010f [MIRROR] Wendigo Mob Abilities (#27872)
* Wendigo Mob Abilities (#83325)

## About The Pull Request

Converts wendigo's abilities into mob abilities, behavior should be
almost identical to how it was before. Also gave megafauna the same
night vision as normal lavaland mobs since controlling them and being
unable to see was difficult while testing. Wendigo's scream and slam
were made into global procs so they could be used across these
abilities, but if there's a better way to do that I'm open to it.

## Why It's Good For The Game

More refactoring to make way for converting these all to basic
megafauna.

## Changelog

🆑
refactor: Wendigos abilities have been changed into actions that can be
added to any mob.
/🆑

* Wendigo Mob Abilities

---------

Co-authored-by: Whoneedspacee <yougotreallyowned@gmail.com>
2024-05-28 05:11:31 +02:00

416 lines
17 KiB
Plaintext

/datum/action/cooldown/mob_cooldown/projectile_attack
name = "Projectile Attack"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Fires a set of projectiles at a selected target."
cooldown_time = 1.5 SECONDS
/// The type of the projectile to be fired
var/projectile_type
/// The sound played when a projectile is fired
var/projectile_sound
/// If the projectile should home in on its target
var/has_homing = FALSE
/// The turning speed if there is homing
var/homing_turn_speed = 30
/// The variance in the projectiles direction
var/default_projectile_spread = 0
/// The multiplier to the projectiles speed (a value of 2 makes it twice as slow, 0.5 makes it twice as fast)
var/projectile_speed_multiplier = 1
/// Whether the target can move or not while the attack is occurring
var/can_move = TRUE
/datum/action/cooldown/mob_cooldown/projectile_attack/Activate(atom/target_atom)
disable_cooldown_actions()
RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move), override = TRUE)
attack_sequence(owner, target_atom)
UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE)
StartCooldown()
enable_cooldown_actions()
return TRUE
/datum/action/cooldown/mob_cooldown/projectile_attack/proc/on_move(atom/source, atom/new_loc)
SIGNAL_HANDLER
if(!can_move)
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
/datum/action/cooldown/mob_cooldown/projectile_attack/proc/attack_sequence(mob/living/firer, atom/target)
shoot_projectile(firer, target, null, firer, rand(-default_projectile_spread, default_projectile_spread), null)
/datum/action/cooldown/mob_cooldown/projectile_attack/proc/shoot_projectile(atom/origin, atom/target, set_angle, mob/firer, projectile_spread, speed_multiplier, override_projectile_type, override_homing)
var/turf/startloc = get_turf(origin)
var/turf/endloc = get_turf(target)
if(!startloc || !endloc)
return
var/obj/projectile/our_projectile
if(override_projectile_type)
our_projectile = new override_projectile_type(startloc)
else
our_projectile = new projectile_type(startloc)
if(!isnum(speed_multiplier))
speed_multiplier = projectile_speed_multiplier
our_projectile.speed *= speed_multiplier
our_projectile.preparePixelProjectile(endloc, startloc, null, projectile_spread)
our_projectile.firer = firer
if(target)
our_projectile.original = target
if(override_homing == null && has_homing || override_homing)
our_projectile.homing_turn_speed = homing_turn_speed
our_projectile.set_homing_target(target)
if(isnum(set_angle))
our_projectile.fire(set_angle)
return
our_projectile.fire()
return our_projectile
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire
name = "Rapid Fire"
button_icon = 'icons/obj/weapons/guns/energy.dmi'
button_icon_state = "kineticgun"
desc = "Fires projectiles repeatedly at a given target."
cooldown_time = 1.5 SECONDS
projectile_type = /obj/projectile/colossus/snowball
default_projectile_spread = 45
/// Total shot count
var/shot_count = 60
/// Delay between shots
var/shot_delay = 0.1 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/attack_sequence(mob/living/firer, atom/target)
for(var/i in 1 to shot_count)
shoot_projectile(firer, target, null, firer, rand(-default_projectile_spread, default_projectile_spread), null)
SLEEP_CHECK_DEATH(shot_delay, src)
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/direct
shot_count = 40
default_projectile_spread = 5
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel
name = "Shrapnel Fire"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Fires projectiles that will split into shrapnel after a period of time."
cooldown_time = 6 SECONDS
projectile_type = /obj/projectile/colossus/frost_orb
has_homing = TRUE
default_projectile_spread = 180
shot_count = 8
shot_delay = 1 SECONDS
var/shrapnel_projectile_type = /obj/projectile/colossus/ice_blast
var/shrapnel_angles = list(0, 60, 120, 180, 240, 300)
var/shrapnel_spread = 60
var/break_time = 2 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel/attack_sequence(mob/living/firer, atom/target)
for(var/i in 1 to shot_count)
var/obj/projectile/to_explode = shoot_projectile(firer, target, null, firer, rand(-default_projectile_spread, default_projectile_spread), null)
addtimer(CALLBACK(src, PROC_REF(explode_into_shrapnel), firer, target, to_explode), break_time)
SLEEP_CHECK_DEATH(shot_delay, src)
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel/proc/explode_into_shrapnel(mob/living/firer, atom/target, obj/projectile/to_explode)
if(!to_explode)
return
for(var/angle in shrapnel_angles)
// no speed multiplier for shrapnel
shoot_projectile(to_explode, target, angle + rand(-shrapnel_spread, shrapnel_spread), firer, null, 1, shrapnel_projectile_type, FALSE)
qdel(to_explode)
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/shrapnel/strong
name = "Strong Shrapnel Fire"
shot_count = 16
shot_delay = 0.5 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots
name = "Spiral Shots"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Fires projectiles in a spiral pattern."
cooldown_time = 3 SECONDS
projectile_type = /obj/projectile/colossus
projectile_sound = 'sound/magic/clockwork/invoke_general.ogg'
/// Whether or not the attack is the enraged form
var/enraged = FALSE
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/attack_sequence(mob/living/firer, atom/target)
if(enraged)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
INVOKE_ASYNC(src, PROC_REF(create_spiral_attack), firer, target, TRUE)
create_spiral_attack(firer, target, FALSE)
return
create_spiral_attack(firer, target)
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/proc/create_spiral_attack(mob/living/firer, atom/target, negative = pick(TRUE, FALSE))
var/counter = 8
for(var/i in 1 to 80)
if(negative)
counter--
else
counter++
if(counter > 16)
counter = 1
if(counter < 1)
counter = 16
shoot_projectile(firer, target, counter * 22.5, firer, null, null)
playsound(get_turf(firer), projectile_sound, 20, TRUE)
SLEEP_CHECK_DEATH(0.1 SECONDS, firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus
cooldown_time = 1.5 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/colossus/Activate(atom/target_atom)
SLEEP_CHECK_DEATH(1.5 SECONDS, owner)
return ..()
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/wendigo
cooldown_time = 10 SECONDS
projectile_type = /obj/projectile/colossus/wendigo_shockwave/spiral
can_move = FALSE
/datum/action/cooldown/mob_cooldown/projectile_attack/spiral_shots/wendigo/create_spiral_attack(mob/living/firer, atom/target, negative = pick(TRUE, FALSE))
wendigo_scream(firer)
var/shots_spiral = 40
var/angle_to_target = get_angle(firer, target)
var/spiral_direction = pick(-1, 1)
for(var/shot in 1 to shots_spiral)
var/shots_per_tick = 5 - enraged * 3
var/angle_change = (5 + enraged * shot / 6) * spiral_direction
for(var/count in 1 to shots_per_tick)
var/angle = angle_to_target + shot * angle_change + count * 360 / shots_per_tick
shoot_projectile(firer, target, angle, firer, null, null)
SLEEP_CHECK_DEATH(1, firer)
SLEEP_CHECK_DEATH(3 SECONDS, firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe
name = "All Directions"
button_icon = 'icons/effects/effects.dmi'
button_icon_state = "at_shield2"
desc = "Fires projectiles in all directions."
cooldown_time = 3 SECONDS
projectile_type = /obj/projectile/colossus
projectile_sound = 'sound/magic/clockwork/invoke_general.ogg'
/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/attack_sequence(mob/living/firer, atom/target)
var/turf/U = get_turf(firer)
playsound(U, projectile_sound, 300, TRUE, 5)
for(var/i in 1 to 32)
shoot_projectile(firer, target, rand(0, 360), firer, null, null)
/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus
cooldown_time = 1.5 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/random_aoe/colossus/Activate(atom/target_atom)
SLEEP_CHECK_DEATH(1.5 SECONDS, owner)
return ..()
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast
name = "Shotgun Fire"
button_icon = 'icons/obj/weapons/guns/ballistic.dmi'
button_icon_state = "shotgun"
desc = "Fires projectiles in a shotgun pattern."
cooldown_time = 2 SECONDS
projectile_type = /obj/projectile/colossus
projectile_sound = 'sound/magic/clockwork/invoke_general.ogg'
var/list/shot_angles = list(12.5, 7.5, 2.5, -2.5, -7.5, -12.5)
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/attack_sequence(mob/living/firer, atom/target)
fire_shotgun(firer, target, shot_angles)
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/proc/fire_shotgun(mob/living/firer, atom/target, list/chosen_angles)
playsound(firer, projectile_sound, 200, TRUE, 2)
for(var/spread in chosen_angles)
shoot_projectile(firer, target, null, firer, spread, null)
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/wendigo
cooldown_time = 10 SECONDS
projectile_type = /obj/projectile/colossus/wendigo_shockwave
shot_angles = list(-20, -10, 0, 10, 20)
projectile_speed_multiplier = 4
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus
cooldown_time = 0.5 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/colossus/Activate(atom/target_atom)
SLEEP_CHECK_DEATH(1.5 SECONDS, owner)
return ..()
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern
name = "Alternating Shotgun Fire"
desc = "Fires projectiles in an alternating shotgun pattern."
projectile_type = /obj/projectile/colossus/ice_blast
projectile_sound = null
shot_angles = list(list(-40, -20, 0, 20, 40), list(-30, -10, 10, 30))
var/shot_count = 5
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern/attack_sequence(mob/living/firer, atom/target)
for(var/i in 1 to shot_count)
var/list/pattern = shot_angles[i % length(shot_angles) + 1] // changing patterns
fire_shotgun(firer, target, pattern)
SLEEP_CHECK_DEATH(0.8 SECONDS, firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern/circular
name = "Circular Shotgun Fire"
shot_angles = list(list(0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330), list(-30, -15, 0, 15, 30))
/datum/action/cooldown/mob_cooldown/projectile_attack/shotgun_blast/pattern/circular/complete
shot_angles = list(list(-180, -140, -100, -60, -20, 20, 60, 100, 140), list(-160, -120, -80, -40, 0, 40, 80, 120, 160))
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots
name = "Directional Shots"
button_icon = 'icons/obj/weapons/guns/ballistic.dmi'
button_icon_state = "pistol"
desc = "Fires projectiles in specific directions."
cooldown_time = 4 SECONDS
projectile_type = /obj/projectile/colossus
projectile_sound = 'sound/magic/clockwork/invoke_general.ogg'
var/list/firing_directions
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/New(Target)
. = ..()
if(!firing_directions)
firing_directions = GLOB.alldirs.Copy()
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/attack_sequence(mob/living/firer, atom/target)
fire_in_directions(firer, target, firing_directions)
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/proc/fire_in_directions(mob/living/firer, atom/target, list/dirs)
if(!islist(dirs))
dirs = GLOB.alldirs.Copy()
playsound(firer, projectile_sound, 200, TRUE, 2)
for(var/dir in dirs)
shoot_projectile(firer, target, dir2angle(dir), firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating
name = "Alternating Shots"
desc = "Fires projectiles in alternating directions."
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/attack_sequence(mob/living/firer, atom/target)
fire_in_directions(firer, target, GLOB.diagonals)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
fire_in_directions(firer, target, GLOB.cardinals)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
fire_in_directions(firer, target, GLOB.diagonals)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
fire_in_directions(firer, target, GLOB.cardinals)
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus
cooldown_time = 2.5 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/dir_shots/alternating/colossus/Activate(atom/target_atom)
SLEEP_CHECK_DEATH(1.5 SECONDS, owner)
return ..()
/datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator
name = "Fire Kinetic Accelerator"
button_icon = 'icons/obj/weapons/guns/energy.dmi'
button_icon_state = "kineticgun"
desc = "Fires a kinetic accelerator projectile at the target."
cooldown_time = 1.5 SECONDS
projectile_type = /obj/projectile/kinetic/miner
projectile_sound = 'sound/weapons/kinetic_accel.ogg'
/datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator/Activate(atom/target_atom)
. = ..()
playsound(owner, projectile_sound, 200, TRUE, 2)
owner.visible_message(span_danger("[owner] fires the proto-kinetic accelerator!"))
owner.face_atom(target_atom)
new /obj/effect/temp_visual/dir_setting/firing_effect(owner.loc, owner.dir)
/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final
name = "Titan's Finale"
desc = "A single-use ability that shoots a large amount of projectiles around you."
cooldown_time = 2.5 SECONDS
projectile_type = /obj/projectile/colossus
/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/Activate(atom/target_atom)
. = ..()
Remove(owner)
/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/attack_sequence(mob/living/firer, atom/target)
var/mob/living/simple_animal/hostile/megafauna/colossus/colossus
if(istype(firer, /mob/living/simple_animal/hostile/megafauna/colossus))
colossus = firer
colossus.say("Perish.", spans = list("colossus", "yell"))
SLEEP_CHECK_DEATH(0.5 SECONDS, firer) //gives dumbasses in melee range a slim chance to retreat
var/finale_counter = 10
for(var/i in 1 to 20)
if(finale_counter > 4 && colossus)
colossus.telegraph()
colossus.shotgun_blast.attack_sequence(firer, target)
if(finale_counter > 1)
finale_counter -= 1
var/turf/start_turf = get_turf(firer)
for(var/turf/target_turf in RANGE_TURFS(12, start_turf))
if(prob(min(finale_counter, 2)) && target_turf != get_turf(firer))
shoot_projectile(firer, target_turf, null, firer, null, null)
SLEEP_CHECK_DEATH(finale_counter + 1, firer)
for(var/i in 1 to 3)
if(colossus)
colossus.telegraph()
colossus.random_shots.attack_sequence(firer, target)
finale_counter += 6
SLEEP_CHECK_DEATH(finale_counter, firer)
for(var/i in 1 to 3)
if(colossus)
colossus.telegraph()
colossus.dir_shots.attack_sequence(firer, target)
SLEEP_CHECK_DEATH(1 SECONDS, firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/alternating_circle
name = "Alternating Shots"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Fires projectiles around you in an alternating fashion."
cooldown_time = 10 SECONDS
projectile_type = /obj/projectile/colossus/wendigo_shockwave
can_move = FALSE
var/enraged = FALSE
/datum/action/cooldown/mob_cooldown/projectile_attack/alternating_circle/attack_sequence(mob/living/firer, atom/target)
wendigo_scream(firer)
if(enraged)
projectile_speed_multiplier = 1
else
projectile_speed_multiplier = 1.5
var/shots_per = 24
for(var/shoot_times in 1 to 8)
var/offset = shoot_times % 2
for(var/shot in 1 to shots_per)
var/angle = shot * 360 / shots_per + (offset * 360 / shots_per) * 0.5
shoot_projectile(firer, target, angle, firer, null, null)
SLEEP_CHECK_DEATH(6 - enraged * 2, firer)
SLEEP_CHECK_DEATH(3 SECONDS, firer)
/datum/action/cooldown/mob_cooldown/projectile_attack/wave
name = "Wave Shots"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
desc = "Fires projectiles around you in a circular wave."
cooldown_time = 10 SECONDS
projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave
can_move = FALSE
/datum/action/cooldown/mob_cooldown/projectile_attack/wave/attack_sequence(mob/living/firer, atom/target)
wendigo_scream(firer)
var/shots_per = 7
var/difference = 360 / shots_per
var/wave_direction = pick(-1, 1)
switch(wave_direction)
if(-1)
projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave/alternate
if(1)
projectile_type = /obj/projectile/colossus/wendigo_shockwave/wave
for(var/shoot_times in 1 to 32)
for(var/shot in 1 to shots_per)
var/angle = shot * difference + shoot_times * 5 * wave_direction * -1
shoot_projectile(firer, target, angle, firer, null, null)
SLEEP_CHECK_DEATH(2, firer)
SLEEP_CHECK_DEATH(3 SECONDS, firer)