untangle abilities
This commit is contained in:
+177
-205
@@ -29,131 +29,6 @@ export default class Ability {
|
|||||||
|
|
||||||
static get noEffect() { return function noEffect() {} }
|
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({
|
static blink = new Ability({
|
||||||
id: 'blink',
|
id: 'blink',
|
||||||
name: '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({
|
static circleOfResurrection = new Ability({
|
||||||
id: 'circle_of_resurrection',
|
id: 'circle_of_resurrection',
|
||||||
name: 'Circle of Resurrection',
|
name: 'Circle of Resurrection',
|
||||||
castTime: 0.5,
|
castTime: 0.5,
|
||||||
cooldown: 100,
|
cooldown: 100,
|
||||||
duration: 3,
|
duration: 3,
|
||||||
|
moveCancelable: true,
|
||||||
radius: 300,
|
radius: 300,
|
||||||
range: 300,
|
range: 300,
|
||||||
effect: function circleOfResurrectionEffect(caster, cursor) {
|
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)
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-4
@@ -1,7 +1,7 @@
|
|||||||
import { Vector2 } from 'three'
|
import { Vector2 } from 'three'
|
||||||
import Ability from './ability.js'
|
|
||||||
import Buff from './buff.js'
|
import Buff from './buff.js'
|
||||||
import Pathfind from './pathfind.js'
|
import Pathfind from './pathfind.js'
|
||||||
|
import Projectile from './projectile.js'
|
||||||
import SAT from 'sat'
|
import SAT from 'sat'
|
||||||
import SATX from './satx.js'
|
import SATX from './satx.js'
|
||||||
import Team from './team.js'
|
import Team from './team.js'
|
||||||
@@ -184,7 +184,7 @@ export default class Entity {
|
|||||||
if (ability == null) { return }
|
if (ability == null) { return }
|
||||||
|
|
||||||
if (this.casting != null) {
|
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) {
|
if (abilityBeingCasted != null && abilityBeingCasted.id == ability.id) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ export default class Entity {
|
|||||||
moveAction(cursor, attack = false) {
|
moveAction(cursor, attack = false) {
|
||||||
if (this.dead) { return }
|
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])) {
|
if (!attack && !(this.casting != null && this.casting.ability == this.abilities[0])) {
|
||||||
this.casting = null
|
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))
|
const enemiesNearby = (this.game?.entities ?? []).some((it) => !it.dead && it.team == enemyTeam && it.distanceTo(this.position) <= (it.visionRange + this.radius))
|
||||||
if (enemiesNearby) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user