refactor: dying

This commit is contained in:
cha0s 2021-02-02 00:23:38 -06:00
parent 381fb7cb4b
commit 390520715f
7 changed files with 45 additions and 40 deletions

View File

@ -108,8 +108,8 @@ export default (latus) => class Behaved extends decorate(Trait) {
this.updateCurrentRoutine(currentRoutine);
},
isDyingChanged: (_, isDying) => {
this.entity.isBehaving = !isDying;
startedDying: () => {
this.entity.isBehaving = false;
},
};

View File

@ -11,9 +11,6 @@ import {StateProperty, Trait} from '@avocado/traits';
import {compose} from '@latus/core';
const decorate = compose(
StateProperty('isDying', {
track: true,
}),
StateProperty('life', {
track: true,
}),
@ -32,6 +29,10 @@ export default (latus) => class Alive extends decorate(Trait) {
#hasDied = false;
#isDying = false;
#packets = [];
constructor() {
super();
const {deathActions, deathCondition} = this.constructor.defaultParams();
@ -52,6 +53,10 @@ export default (latus) => class Alive extends decorate(Trait) {
}
}
cleanPackets() {
this.#packets = [];
}
get deathSound() {
return this.params.deathSound;
}
@ -87,7 +92,6 @@ export default (latus) => class Alive extends decorate(Trait) {
static defaultState() {
return {
isDying: false,
life: 100,
maxLife: 100,
};
@ -105,11 +109,6 @@ export default (latus) => class Alive extends decorate(Trait) {
label: 'Death sound',
readOnly: true,
},
// TODO should not be prop
isDying: {
type: 'bool',
label: 'Is dying',
},
life: {
type: 'number',
label: 'Life points',
@ -128,7 +127,7 @@ export default (latus) => class Alive extends decorate(Trait) {
hooks() {
return {
destroy: () => () => (this.entity.isDying ? this.#hasDied : true),
destroy: () => () => this.#hasDied,
};
}
@ -145,6 +144,10 @@ export default (latus) => class Alive extends decorate(Trait) {
listeners() {
return {
startedDying: () => {
this.#packets.push(['Died']);
},
tookHarm: (harm) => {
this.entity.life += (harm.isDamage ? -1 : 1) * harm.amount;
},
@ -177,10 +180,11 @@ export default (latus) => class Alive extends decorate(Trait) {
return {
die: async () => {
if (this.entity.isDying) {
if (this.#isDying) {
return;
}
this.entity.isDying = true;
this.#isDying = true;
this.entity.emit('startedDying');
await this.entity.addTickingPromise(this.#deathActions.tickingPromise(this.#context));
const died = this.entity.invokeHookFlat('died');
await this.entity.addTickingPromise(new TickingPromise(
@ -199,8 +203,8 @@ export default (latus) => class Alive extends decorate(Trait) {
}
packets() {
const packets = [];
const {isDying, life, maxLife} = this.stateDifferences();
const packets = this.#packets.concat();
const {life, maxLife} = this.stateDifferences();
if (life || maxLife) {
packets.push([
'TraitUpdateAlive',
@ -210,15 +214,12 @@ export default (latus) => class Alive extends decorate(Trait) {
},
]);
}
if (isDying) {
packets.push(['Died']);
}
return packets;
}
tick() {
if ('client' !== process.env.SIDE) {
if (!this.entity.isDying && this.#deathCondition(this.#context)) {
if (!this.#isDying && this.#deathCondition(this.#context)) {
this.entity.die();
}
}

View File

@ -171,8 +171,8 @@ export default (latus) => class Spawner extends decorate(Trait) {
listeners() {
return {
isDyingChanged: (_, isDying) => {
this.isSpawning = !isDying;
startedDying: () => {
this.isSpawning = false;
},
};

View File

@ -32,14 +32,15 @@ describe('Alive', () => {
it('exists', async () => {
expect(entity.is('Alive')).to.be.true;
});
it('is alive', async () => {
expect(entity.isDying).to.be.false;
});
if ('client' !== process.env.SIDE) {
it('can die', async () => {
let isDying = false;
entity.once('startedDying', () => {
isDying = true;
});
entity.life = 0;
entity.tick(0);
expect(entity.isDying).to.be.true;
expect(isDying).to.be.true;
});
}
it('clamps life', async () => {
@ -62,11 +63,15 @@ describe('Alive', () => {
},
},
});
let isDying = false;
entity.on('startedDying', () => {
isDying = true;
});
entity.tick(0);
expect(entity.isDying).to.be.false;
expect(isDying).to.be.false;
entity.life = 10;
entity.tick(0);
expect(entity.isDying).to.be.true;
expect(isDying).to.be.true;
});
}
it('runs actions on death', async () => {
@ -121,14 +126,15 @@ describe('Alive', () => {
entity.tick();
const packets = entity.trait('Alive').packets();
expect(packets).to.have.lengthOf(2);
expect(packets[0][0]).to.equal('TraitUpdateAlive');
expect(packets[0][1]).to.deep.equal({life: 0, maxLife: 100});
expect(packets[1][0]).to.equal('Died');
expect(entity2.isDying).to.be.false;
expect(packets[0][0]).to.equal('Died');
expect(packets[1][0]).to.equal('TraitUpdateAlive');
expect(packets[1][1]).to.deep.equal({life: 0, maxLife: 100});
const promise = new Promise((resolve) => {
entity2.on('isDyingChanged', resolve);
entity2.once('startedDying', resolve);
});
entity2.trait('Alive').acceptPacket(normalize(latus, packets[0]));
entity2.trait('Alive').acceptPacket(normalize(latus, packets[1]));
expect(entity2.life).to.equal(0);
return promise;
});
}

View File

@ -108,8 +108,8 @@ export default () => class Physical extends decorate(Trait) {
}
},
isDyingChanged: (_, isDying) => {
this.entity.addedToPhysics = !isDying;
startedDying: () => {
this.entity.addedToPhysics = false;
},
positionChanged: () => {

View File

@ -169,8 +169,8 @@ export default (latus) => class Animated extends decorate(Trait) {
}
},
isDyingChanged: (_, isDying) => {
this.isAnimating = !isDying;
startedDying: () => {
this.isAnimating = false;
},
traitAdded: () => {

View File

@ -20,7 +20,7 @@ class TestTrait extends Trait {
}
it('can set and override default params and state', async () => {
it('optimizes output based on deltas', async () => {
const testTrait = await TestTrait.load({
params: {
asd: 'boo',
@ -32,11 +32,9 @@ it('can set and override default params and state', async () => {
expect(testTrait.toJSON()).to.deep.equal({
params: {
asd: 'boo',
sdf: 311,
},
state: {
bar: 'yee',
foo: 69,
},
});
});