mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
Adds the option for cooldown action sequences which has a list of sequence actions, the owner of the sequence doesn't have direct control over any of the actions in the sequence but is still considered the owner of the sequence actions, the main ability simply handles calling whatever those sub actions should do. Adds melee cooldown times to cooldown actions. Cooldown actions now use bitflags so an ability can share its cooldown to multiple other types of abilities Cooldown times are now handled by the base activate proc, cleaning up copy paste of StartCooldown() Reworks the admin verb for adding cooldown abilities to where it has significantly more customization (and tells you to mark the mob you want to modify instead of just doing nothing) and also allows for creation of the new sequences, allowing entirely new and unseen abilities to be formed out of existing ones. Also adds a verb for removal of mob abilities.
327 lines
13 KiB
Plaintext
327 lines
13 KiB
Plaintext
/datum/action/cooldown/mob_cooldown/projectile_attack
|
|
name = "Projectile Attack"
|
|
icon_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
|
|
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/Activate(atom/target_atom)
|
|
attack_sequence(owner, target_atom)
|
|
StartCooldown()
|
|
|
|
/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"
|
|
icon_icon = 'icons/obj/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"
|
|
icon_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/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"
|
|
icon_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/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/random_aoe
|
|
name = "All Directions"
|
|
icon_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"
|
|
icon_icon = 'icons/obj/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/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"
|
|
icon_icon = 'icons/obj/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/d in dirs)
|
|
var/turf/E = get_step(firer, d)
|
|
shoot_projectile(firer, E, null, firer, null, null)
|
|
|
|
/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"
|
|
icon_icon = 'icons/obj/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/kenetic_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
|
|
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/colossus_final/Activate(atom/target_atom)
|
|
attack_sequence(owner, target_atom)
|
|
StartCooldown()
|
|
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"))
|
|
|
|
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)
|