avocado-old/packages/entity/traits/alive.trait.js

172 lines
3.6 KiB
JavaScript
Raw Normal View History

import {
behaviorItemFromJSON,
buildCondition,
buildInvoke,
buildTraversal,
2019-09-08 04:33:13 -05:00
Context,
} from '@avocado/behavior';
import {compose} from '@avocado/core';
import {StateProperty, Trait} from '../trait';
2019-10-02 00:10:14 -05:00
import {DiedPacket} from '../packets/died.packet';
2019-09-30 20:57:04 -05:00
import {TraitUpdateAlivePacket} from '../packets/trait-update-alive.packet';
const decorate = compose(
2019-10-10 01:27:02 -05:00
StateProperty('isDying', {
track: true,
}),
StateProperty('life', {
track: true,
}),
StateProperty('maxLife', {
track: true,
}),
);
export class Alive extends decorate(Trait) {
static defaultParams() {
const playDeathSound = buildInvoke(['entity', 'playSound'], [
buildTraversal(['entity', 'deathSound']),
]);
const squeeze = buildInvoke(['entity', 'transition'], [
{
opacity: 0,
visibleScaleX: .3,
visibleScaleY: 3,
},
0.2,
]);
const isLifeGone = buildCondition('<=', [
buildTraversal(['entity', 'life']),
0,
]);
return {
deathActions: {
type: 'actions',
traversals: [
playDeathSound,
squeeze,
],
},
deathCondition: isLifeGone,
deathSound: 'deathSound',
};
}
static defaultState() {
return {
2019-10-02 00:10:14 -05:00
isDying: false,
life: 100,
maxLife: 100,
};
}
static type() {
return 'alive';
}
constructor(entity, params, state) {
super(entity, params, state);
2019-09-08 06:04:31 -05:00
this._context = new Context({
entity: this.entity,
});
2019-10-10 01:15:38 -05:00
this._deathActions = behaviorItemFromJSON(this.params.deathActions);
this._deathSound = this.params.deathSound;
2019-10-10 01:15:38 -05:00
this._deathCondition = behaviorItemFromJSON(this.params.deathCondition);
2019-09-08 08:12:31 -05:00
this._dyingTickingPromise = false;
}
destroy() {
2019-09-08 04:33:13 -05:00
this._context.destroy();
}
acceptPacket(packet) {
2019-09-30 20:57:04 -05:00
if (packet instanceof TraitUpdateAlivePacket) {
this.entity.life = packet.data.life;
this.entity.maxLife = packet.data.maxLife;
}
2019-10-02 00:10:14 -05:00
if (packet instanceof DiedPacket) {
this.entity.forceDeath();
}
}
get deathSound() {
return this._deathSound;
}
2019-09-30 20:57:04 -05:00
packets(informed) {
2019-10-02 00:10:14 -05:00
const packets = [];
const {isDying, life, maxLife} = this.stateDifferences();
2019-09-30 20:57:04 -05:00
if (life || maxLife) {
2019-10-03 15:33:39 -05:00
packets.push(new TraitUpdateAlivePacket({
life: this.state.life,
maxLife: this.state.maxLife,
}));
2019-10-02 00:10:14 -05:00
}
if (isDying) {
packets.push(new DiedPacket());
2019-09-30 20:57:04 -05:00
}
2019-10-02 00:10:14 -05:00
return packets;
}
listeners() {
return {
tookDamage: (damage, source) => {
if (damage.damageSpec.power > 0) {
this.entity.life -= damage.amount;
}
else {
this.entity.life += damage.amount;
}
// Clamp health between 0 and max.
this.entity.life = Math.min(
Math.max(0, this.entity.life),
this.entity.maxLife
);
},
}
}
methods() {
return {
dieIfPossible: () => {
if (this._deathCondition.check(this._context)) {
this.entity.forceDeath();
}
},
forceDeath: () => {
2019-09-08 08:12:31 -05:00
if (this._dyingTickingPromise) {
return;
}
2019-10-10 01:27:02 -05:00
this.entity.isDying = true;
2019-09-08 08:12:31 -05:00
this._dyingTickingPromise = this._deathActions.tickingPromise(
this._context
)
this._dyingTickingPromise.then(() => {
2019-10-08 03:23:36 -05:00
this.entity.emit('died');
2019-09-08 08:12:31 -05:00
this.entity.destroy();
});
},
};
}
tick(elapsed) {
2019-09-08 08:12:31 -05:00
if (this._dyingTickingPromise) {
this._dyingTickingPromise.tick(elapsed);
}
else {
2019-10-02 00:10:14 -05:00
if (AVOCADO_SERVER) {
this.entity.dieIfPossible();
}
}
}
}