190 lines
5.1 KiB
JavaScript
190 lines
5.1 KiB
JavaScript
import Projectile from './projectile.js'
|
|
|
|
// major damage OR minor self sustain / crowd control
|
|
// major support OR minor vision / selfless support / creative
|
|
// major control OR minor mobility
|
|
|
|
export default class Ability {
|
|
id = crypto.randomUUID()
|
|
name = 'Ability'
|
|
|
|
castTime = 0
|
|
cooldown = 0
|
|
damage = 0
|
|
radius = 1
|
|
range = 0
|
|
speed = 1000
|
|
|
|
#effect = () => {}
|
|
|
|
get effect() { return this.#effect }
|
|
set effect(value) { this.#effect = value }
|
|
|
|
constructor(options = {}) {
|
|
Object.entries(options).forEach(([key, value]) => this[key] = value)
|
|
}
|
|
|
|
// TODO: skill seemingly going right through minions without a registered hit
|
|
static straightShot = new Ability({
|
|
id: 'straight_shot',
|
|
name: 'Straight Shot',
|
|
castTime: 0.1,
|
|
cooldown: 1,
|
|
damage: 10,
|
|
radius: 7,
|
|
range: 800,
|
|
speed: 3000,
|
|
effect: function straightShotEffect(caster, cursor) {
|
|
const ability = this
|
|
const straightShotCollision = function straightShotCollision(projectile, collidingEntity) {
|
|
collidingEntity.damage(ability.damage)
|
|
projectile.despawn()
|
|
}
|
|
|
|
const projectile = new Projectile({
|
|
onCollide: straightShotCollision,
|
|
owner: caster,
|
|
position: caster.position.clone(),
|
|
radius: ability.radius,
|
|
speed: ability.speed,
|
|
})
|
|
|
|
projectile.destination = caster.position.clone().add(cursor.clone().sub(caster.position).normalize().multiplyScalar(ability.range))
|
|
caster.game?.spawnProjectile(projectile)
|
|
caster.cooldown(ability.id)
|
|
},
|
|
})
|
|
|
|
static rangedAttack = new Ability({
|
|
id: 'ranged_attack',
|
|
name: 'Ranged Attack',
|
|
castTime: 0.25,
|
|
cooldown: 1.25,
|
|
damage: 5,
|
|
radius: 5,
|
|
range: 500,
|
|
speed: 600,
|
|
effect: function rangedAttackEffect(caster, cursor) {
|
|
const ability = this
|
|
let closest = null
|
|
let distance = Infinity
|
|
caster.game?.entities.filter((e) => e.team != caster.team && e.position.clone().sub(caster.position).length() < ability.range).forEach((e) => {
|
|
const newDistance = e.position.clone().sub(cursor).length()
|
|
if (newDistance < distance) {
|
|
closest = e
|
|
distance = newDistance
|
|
}
|
|
})
|
|
|
|
if (closest == null) { return }
|
|
|
|
const rangedAttackAfter = function rangedAttackAfter() {
|
|
closest.damage(ability.damage)
|
|
}
|
|
|
|
const projectile = new Projectile({
|
|
after: rangedAttackAfter,
|
|
homingTarget: closest,
|
|
owner: caster,
|
|
position: caster.position.clone(),
|
|
radius: ability.radius,
|
|
speed: ability.speed,
|
|
})
|
|
|
|
caster.game?.spawnProjectile(projectile)
|
|
caster.cooldown(ability.id)
|
|
},
|
|
})
|
|
|
|
static meleeAttack = new Ability({
|
|
id: 'melee_attack',
|
|
name: 'Melee Attack',
|
|
castTime: 0.1,
|
|
cooldown: 1.75,
|
|
damage: 10,
|
|
radius: 5,
|
|
range: 100,
|
|
effect: function meleeAttackEffect(caster, cursor) {
|
|
const ability = this
|
|
let closest = null
|
|
let distance = Infinity
|
|
caster.game?.entities.filter((e) => e.team != caster.team && e.position.clone().sub(caster.position).length() < ability.range).forEach((e) => {
|
|
const newDistance = e.position.clone().sub(cursor).length() < distance
|
|
if (newDistance < distance) {
|
|
closest = e
|
|
distance = newDistance
|
|
}
|
|
})
|
|
|
|
if (closest == null) { return }
|
|
|
|
closest.damage(ability.damage)
|
|
caster.cooldown(ability.id)
|
|
},
|
|
})
|
|
|
|
static shieldThrow = new Ability({
|
|
id: 'shield_throw',
|
|
name: 'Shield Throw',
|
|
castTime: 0.15,
|
|
cooldown: 5,
|
|
radius: 20,
|
|
range: 1000,
|
|
speed: 2000,
|
|
effect: function shieldThrowEffect(caster, cursor) {
|
|
const ability = this
|
|
const shieldThrowReturn = function shieldThrowReturn(projectile, homingTarget) {
|
|
const returnProjectile = new Projectile({
|
|
owner: caster,
|
|
position: projectile.position.clone(),
|
|
radius: ability.radius,
|
|
speed: ability.speed,
|
|
homingTarget: caster,
|
|
})
|
|
|
|
caster.game?.spawnProjectile(returnProjectile)
|
|
}
|
|
|
|
const projectile = new Projectile({
|
|
after: shieldThrowReturn,
|
|
owner: caster,
|
|
position: caster.position.clone(),
|
|
radius: ability.radius,
|
|
speed: ability.speed,
|
|
})
|
|
|
|
projectile.destination = caster.position.clone().add(cursor.clone().sub(caster.position).normalize().multiplyScalar(ability.range))
|
|
caster.game?.spawnProjectile(projectile)
|
|
caster.cooldown(ability.id)
|
|
},
|
|
})
|
|
|
|
static blink = new Ability({
|
|
id: 'blink',
|
|
name: 'Blink',
|
|
castTime: 1,
|
|
cooldown: 2,
|
|
range: 400,
|
|
effect: function blinkEffect(caster, cursor) {
|
|
const ability = this
|
|
const direction = cursor.clone().sub(caster.position)
|
|
if (direction.length() > ability.range) {
|
|
direction.normalize().multiplyScalar(ability.range)
|
|
}
|
|
|
|
const destination = caster.position.clone().add(direction)
|
|
|
|
caster.teleport(destination)
|
|
caster.cooldown(ability.id)
|
|
},
|
|
})
|
|
|
|
static control = new Ability({
|
|
id: 'control',
|
|
name: 'Control',
|
|
castTime: 1,
|
|
cooldown: 5,
|
|
effect: function controlEffect(caster, cursor) { },
|
|
})
|
|
}
|