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 moveCancelable = false 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) } static straightShot = new Ability({ id: 'straight_shot', name: 'Straight Shot', castTime: 0.25, cooldown: 1, damage: 83, radius: 60, range: 1200, visualRadius: 20, speed: 2000, effect: function straightShotEffect(caster, cursor) { const ability = this const straightShotCollision = function straightShotCollision(projectile, collidingEntity) { if (collidingEntity == null) { return } if (collidingEntity.team == (projectile.owner?.team ?? 'unknown')) { return } collidingEntity.damage(ability.damage) projectile.despawn() } const projectile = new Projectile({ onCollide: straightShotCollision, owner: caster, position: caster.position.clone(), radius: ability.radius, speed: ability.speed, visualRadius: ability.visualRadius, }) projectile.destination = caster.position.clone().add(cursor.clone().sub(caster.position).normalize().multiplyScalar(ability.range + caster.radius)) caster.game?.spawnProjectile(projectile) caster.cooldown(ability.id) }, }) static rangedAttack = new Ability({ id: 'ranged_attack', name: 'Ranged Attack', castTime: (1.6 * 0.18839), cooldown: 1.6, damage: 60, moveCancelable: true, radius: 5, range: 500, speed: 2000, effect: function rangedAttackEffect(caster, cursor) { const ability = this const target = caster.closestTargetTo(cursor, ability.range) if (target == null) { return } const rangedAttackAfter = function rangedAttackAfter() { target.damage(ability.damage) } const projectile = new Projectile({ after: rangedAttackAfter, homingTarget: target, 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: (1.4 * 0.22), cooldown: 1.4, moveCancelable: true, damage: 60, radius: 5, range: 100, effect: function meleeAttackEffect(caster, cursor) { const ability = this const target = caster.closestTargetTo(cursor, ability.range) if (target == null) { return } target.damage(ability.damage) caster.cooldown(ability.id) }, }) static shieldThrow = new Ability({ id: 'shield_throw', name: 'Shield Throw', castTime: 0.25, cooldown: 5, radius: 110, range: 1025, speed: 2400, 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.radius)) caster.game?.spawnProjectile(projectile) caster.cooldown(ability.id) }, }) static blink = new Ability({ id: 'blink', name: 'Blink', castTime: 0.25, cooldown: 2, range: 475, effect: function blinkEffect(caster, cursor) { const ability = this const direction = cursor.clone().sub(caster.position) const realRange = ability.range + caster.radius if (direction.length() > realRange) { direction.normalize().multiplyScalar(realRange) } 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) { }, }) }