From 441a73355e1cd294bd36733df8a0125da0baed51 Mon Sep 17 00:00:00 2001 From: Thayol Date: Wed, 22 Jan 2025 23:41:53 +0900 Subject: [PATCH] untangle abilities --- src/ability.js | 382 +++++++++++++++++++++++-------------------------- src/entity.js | 29 +++- 2 files changed, 202 insertions(+), 209 deletions(-) diff --git a/src/ability.js b/src/ability.js index 34e8f2e..491365e 100644 --- a/src/ability.js +++ b/src/ability.js @@ -29,131 +29,6 @@ export default class Ability { static get noEffect() { return function noEffect() {} } - 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 (projectile.game == null) { return } - if (collidingEntity == null) { return } - if (collidingEntity.id == caster.id) { return } - if (collidingEntity.team == (caster.team ?? 'unknown')) { return } - - collidingEntity.damage(ability.damage, caster) - projectile.despawn() - } - - const projectile = new Projectile({ - onCollide: straightShotCollision, - owner: caster.id, - 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, targetId) { - const ability = this - const target = caster.game?.entities.find((it) => it.id == targetId) - if (target == null) { return } - - const rangedAttackAfter = function rangedAttackAfter() { - target.damage(ability.damage, caster) - } - - const projectile = new Projectile({ - after: rangedAttackAfter, - homingTarget: target, - owner: caster.id, - 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, targetId) { - const ability = this - const target = caster.game?.entities.find((it) => it.id == targetId) - if (target == null) { return } - - target.damage(ability.damage, caster) - 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.id, - position: projectile.position.clone(), - radius: ability.radius, - speed: ability.speed, - homingTarget: caster, - }) - - caster.game?.spawnProjectile(returnProjectile) - } - - const projectile = new Projectile({ - after: shieldThrowReturn, - owner: caster.id, - 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', @@ -174,92 +49,13 @@ export default class Ability { }, }) - static expose = new Ability({ - id: 'expose', - name: 'Expose', - castTime: 0.25, - cooldown: 6, - radius: 80, - range: 1200, - speed: 1700, - visualRadius: 50, - effect: function exposeEffect(caster, cursor) { - const ability = this - const exposeCollision = function exposeCollision(projectile, collidingEntity) { - if (projectile.game == null) { return } - if (collidingEntity == null) { return } - if (collidingEntity.team == caster.id) { return } - if (collidingEntity.team == (caster.team ?? 'unknown')) { return } - - collidingEntity.applyBuff(Buff.exposed.id, caster.id) - projectile.despawn() - } - - const projectile = new Projectile({ - onCollide: exposeCollision, - owner: caster.id, - 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 control = new Ability({ - id: 'control', - name: 'Control', - castTime: 1, - cooldown: 5, - effect: function controlEffect(caster, cursor) { }, - }) - - static castingVision = new Ability({ - id: 'casting_vision', - name: 'Casting Vision', - radius: 300, - duration: 2, - effect: function castingVisionEffect(caster, cursor) { - const ability = this - - const currentTick = caster.game?.currentTick ?? 0 - const duration = caster.game?.secToTick(ability.duration) ?? 0 - const despawnAfter = currentTick + duration - - const castingVisionLogic = function castingVisionLogic(projectile) { - const currentTick = projectile.game?.currentTick ?? 0 - if (currentTick > despawnAfter) { - projectile.despawn() - } - } - - const projectile = new Projectile({ - logic: castingVisionLogic, - owner: caster.id, - position: cursor.clone(), - visionRange: ability.radius, - }) - - caster.game?.spawnProjectile(projectile) - }, - }) - - static circleOfResurrectionChannel = new Ability({ - id: 'channel:circle_of_resurrection', - name: 'Channeling: Circle of Resurrection', - castTime: 3, - }) - static circleOfResurrection = new Ability({ id: 'circle_of_resurrection', name: 'Circle of Resurrection', castTime: 0.5, cooldown: 100, duration: 3, + moveCancelable: true, radius: 300, range: 300, effect: function circleOfResurrectionEffect(caster, cursor) { @@ -312,4 +108,180 @@ export default class Ability { } }, }) + + static circleOfResurrectionChannel = new Ability({ + id: 'channel:circle_of_resurrection', + name: 'Channeling: Circle of Resurrection', + castTime: 3, + moveCancelable: true, + }) + + static control = new Ability({ + id: 'control', + name: 'Control', + castTime: 1, + cooldown: 5, + effect: function controlEffect(caster, cursor) { }, + }) + + static expose = new Ability({ + id: 'expose', + name: 'Expose', + castTime: 0.25, + cooldown: 6, + radius: 80, + range: 1200, + speed: 1700, + visualRadius: 50, + effect: function exposeEffect(caster, cursor) { + const ability = this + const exposeCollision = function exposeCollision(projectile, collidingEntity) { + if (projectile.game == null) { return } + if (collidingEntity == null) { return } + if (collidingEntity.team == caster.id) { return } + if (collidingEntity.team == (caster.team ?? 'unknown')) { return } + + collidingEntity.applyBuff(Buff.exposed.id, caster.id) + projectile.despawn() + } + + const projectile = new Projectile({ + onCollide: exposeCollision, + owner: caster.id, + 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 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, targetId) { + const ability = this + const target = caster.game?.entities.find((it) => it.id == targetId) + if (target == null) { return } + + target.damage(ability.damage, caster) + 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, targetId) { + const ability = this + const target = caster.game?.entities.find((it) => it.id == targetId) + if (target == null) { return } + + const rangedAttackAfter = function rangedAttackAfter() { + target.damage(ability.damage, caster) + } + + const projectile = new Projectile({ + after: rangedAttackAfter, + homingTarget: target, + owner: caster.id, + position: caster.position.clone(), + radius: ability.radius, + speed: ability.speed, + }) + + caster.game?.spawnProjectile(projectile) + 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.id, + position: projectile.position.clone(), + radius: ability.radius, + speed: ability.speed, + homingTarget: caster, + }) + + caster.game?.spawnProjectile(returnProjectile) + } + + const projectile = new Projectile({ + after: shieldThrowReturn, + owner: caster.id, + 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 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 (projectile.game == null) { return } + if (collidingEntity == null) { return } + if (collidingEntity.id == caster.id) { return } + if (collidingEntity.team == (caster.team ?? 'unknown')) { return } + + collidingEntity.damage(ability.damage, caster) + projectile.despawn() + } + + const projectile = new Projectile({ + onCollide: straightShotCollision, + owner: caster.id, + 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) + }, + }) } diff --git a/src/entity.js b/src/entity.js index 3fae6ed..4624b9b 100644 --- a/src/entity.js +++ b/src/entity.js @@ -1,7 +1,7 @@ import { Vector2 } from 'three' -import Ability from './ability.js' import Buff from './buff.js' import Pathfind from './pathfind.js' +import Projectile from './projectile.js' import SAT from 'sat' import SATX from './satx.js' import Team from './team.js' @@ -184,7 +184,7 @@ export default class Entity { if (ability == null) { return } if (this.casting != null) { - const abilityBeingCasted = this.game?.abilities.filter((it) => it.id == this.casting.ability) + const abilityBeingCasted = this.game?.abilities.find((it) => it.id == this.casting.ability) if (abilityBeingCasted != null && abilityBeingCasted.id == ability.id) { return false } @@ -229,7 +229,7 @@ export default class Entity { moveAction(cursor, attack = false) { if (this.dead) { return } - if (this.casting != null && this.game?.abilities.filter((it) => it.id == this.casting.ability)?.moveCancelable) { + if (this.casting != null && this.game?.abilities.find((it) => it.id == this.casting.ability)?.moveCancelable) { if (!attack && !(this.casting != null && this.casting.ability == this.abilities[0])) { this.casting = null } @@ -637,7 +637,28 @@ export default class Entity { const enemiesNearby = (this.game?.entities ?? []).some((it) => !it.dead && it.team == enemyTeam && it.distanceTo(this.position) <= (it.visionRange + this.radius)) if (enemiesNearby) { - Ability.castingVision.effect(this, this.position) + const radius = 300 + const duration = this.game?.secToTick(2) ?? 0 + if (duration <= 0) { return } + + const currentTick = this.game?.currentTick ?? 0 + const despawnAfter = currentTick + duration + + const castingVisionLogic = function castingVisionLogic(projectile) { + const currentTick = projectile.game?.currentTick ?? 0 + if (currentTick > despawnAfter) { + projectile.despawn() + } + } + + const projectile = new Projectile({ + logic: castingVisionLogic, + owner: this.id, + position: this.position.clone(), + visionRange: radius, + }) + + this.game?.spawnProjectile(projectile) } }