From 6c815e77494916d199dc5d4e888c2b8c79c39411 Mon Sep 17 00:00:00 2001 From: cha0s Date: Fri, 18 Oct 2024 07:49:15 -0500 Subject: [PATCH] refactor: harm --- app/ecs/components/harmful.js | 31 ++++++++++++++++ app/ecs/components/vulnerable.js | 36 +++++++++++++++++-- app/ecs/systems/harm.js | 24 +++++++++++++ app/server/create/ecs.js | 1 + .../{collision-start.js => harm.js} | 10 +++++- resources/magic-swords/start.js | 4 ++- 6 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 app/ecs/components/harmful.js create mode 100644 app/ecs/systems/harm.js rename resources/magic-swords/{collision-start.js => harm.js} (69%) diff --git a/app/ecs/components/harmful.js b/app/ecs/components/harmful.js new file mode 100644 index 0000000..9dec10c --- /dev/null +++ b/app/ecs/components/harmful.js @@ -0,0 +1,31 @@ +import Component from '@/ecs/component.js'; + +export default class Harmful extends Component { + instanceFromSchema() { + const {ecs} = this; + return class HarmfulInstance extends super.instanceFromSchema() { + harm(other) { + const entity = ecs.get(this.entity); + const script = this.$$harm.clone(); + script.locals.other = other; + script.locals.entity = entity; + entity.Ticking.add(script.ticker()); + } + } + } + load(instance) { + // heavy handed... + if ('undefined' !== typeof window) { + return; + } + instance.$$harm = this.ecs.readScript( + instance.harmScript, + { + ecs: this.ecs, + }, + ); + } + static properties = { + harmScript: {type: 'string'}, + }; +} diff --git a/app/ecs/components/vulnerable.js b/app/ecs/components/vulnerable.js index 773e053..b2e28dc 100644 --- a/app/ecs/components/vulnerable.js +++ b/app/ecs/components/vulnerable.js @@ -1,4 +1,6 @@ import Component from '@/ecs/component.js'; +import * as Math from '@/util/math.js'; +import Ticker from '@/util/ticker.js'; export const DamageTypes = { PAIN: 0, @@ -21,12 +23,20 @@ export default class Vulnerable extends Component { const Component = this; return class VulnerableInstance extends super.instanceFromSchema() { id = 0; + locked = new Set(); Types = DamageTypes; - damage(specification) { + damage(fullSpecification) { if (this.isInvulnerable) { return; } - const {Alive} = Component.ecs.get(this.entity); + const { + lockout, + ...specification + } = fullSpecification; + if (lockout && this.locked.has(lockout.subject)) { + return; + } + const {Alive, Forces, Position, Ticking} = Component.ecs.get(this.entity); if (Alive) { switch (specification.type) { case DamageTypes.HEALING: @@ -35,6 +45,28 @@ export default class Vulnerable extends Component { } } } + if (specification.knockback) { + const diff = Math.normalizeVector({ + x: Position.x - specification.knockback.origin.x, + y: Position.y - specification.knockback.origin.y, + }); + Forces.applyImpulse({ + x: diff.x * specification.knockback.magnitude, + y: diff.y * specification.knockback.magnitude, + }); + } + if (lockout) { + let {duration, subject} = lockout; + const self = this; + self.locked.add(subject); + Ticking.add(new Ticker(function*() { + while (duration > 0) { + const elapsed = yield; + duration -= elapsed; + } + self.locked.delete(subject); + })); + } Component.markChange( this.entity, 'damage', diff --git a/app/ecs/systems/harm.js b/app/ecs/systems/harm.js new file mode 100644 index 0000000..b04b154 --- /dev/null +++ b/app/ecs/systems/harm.js @@ -0,0 +1,24 @@ +import {System} from '@/ecs/index.js'; + +export default class Harm extends System { + + static queries() { + return { + default: ['Collider', 'Harmful'], + }; + } + + tick() { + for (const entity of this.select('default')) { + const intersecting = new Set(); + for (const [other] of entity.Collider.$$intersections) { + intersecting.add(this.ecs.get(other.entity)); + } + for (const other of intersecting) { + entity.Harmful.harm(other); + } + } + } + +} + diff --git a/app/server/create/ecs.js b/app/server/create/ecs.js index 8f55fe4..c6aea9a 100644 --- a/app/server/create/ecs.js +++ b/app/server/create/ecs.js @@ -9,6 +9,7 @@ export default function createEcs(Ecs) { 'Attract', 'ResetForces', 'ApplyControlMovement', + 'Harm', 'IntegratePhysics', 'ClampPositions', 'PlantGrowth', diff --git a/resources/magic-swords/collision-start.js b/resources/magic-swords/harm.js similarity index 69% rename from resources/magic-swords/collision-start.js rename to resources/magic-swords/harm.js index 1786aa4..0937da9 100644 --- a/resources/magic-swords/collision-start.js +++ b/resources/magic-swords/harm.js @@ -3,12 +3,20 @@ import * as Math from '@/util/math.js'; export default function*({ecs, entity, other}) { const playerEntity = ecs.lookupPlayerEntity(entity.Owned.owner); if (playerEntity !== other && other.Vulnerable) { - const magnitude = Math.floor(Math.random() * 2) + const magnitude = Math.floor(Math.random() * 1); other.Vulnerable.damage({ amount: -Math.floor( Math.pow(10, magnitude) + Math.random() * (Math.pow(10, magnitude + 1) - Math.pow(10, magnitude)), ), + knockback: { + magnitude: 150, + origin: entity.Position, + }, + lockout: { + duration: 0.5, + subject: entity, + }, position: other.Position.toJSON(), type: other.Vulnerable.Types.PAIN, }) diff --git a/resources/magic-swords/start.js b/resources/magic-swords/start.js index 8f2d55a..c0b59c3 100644 --- a/resources/magic-swords/start.js +++ b/resources/magic-swords/start.js @@ -28,11 +28,13 @@ export default function*(locals) { unstoppable: 1, }, ], - collisionStartScript: '/resources/magic-swords/collision-start.js', }, Controlled: {}, Direction: {direction: offset + Math.TAU * (i / N)}, Forces: {}, + Harmful: { + harmScript: '/resources/magic-swords/harm.js', + }, Light: {brightness: 0}, Owned: {owner: Player ? Player.id : 0}, Position: {x: Position.x, y: Position.y},