2019-05-14 05:58:04 -05:00
|
|
|
import {
|
|
|
|
behaviorItemFromJSON,
|
|
|
|
buildCondition,
|
|
|
|
buildInvoke,
|
|
|
|
buildTraversal,
|
2019-09-08 04:33:13 -05:00
|
|
|
Context,
|
2019-05-14 05:58:04 -05:00
|
|
|
} 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';
|
2019-05-14 05:58:04 -05:00
|
|
|
|
|
|
|
const decorate = compose(
|
|
|
|
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,
|
2019-05-14 05:58:04 -05:00
|
|
|
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-05-14 05:58:04 -05:00
|
|
|
const actionsJSON = this.params.deathActions;
|
|
|
|
this._deathActions = behaviorItemFromJSON(actionsJSON);
|
|
|
|
this._deathSound = this.params.deathSound;
|
|
|
|
const conditionJSON = this.params.deathCondition;
|
|
|
|
this._deathCondition = behaviorItemFromJSON(conditionJSON);
|
2019-09-08 08:12:31 -05:00
|
|
|
this._dyingTickingPromise = false;
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
destroy() {
|
2019-09-08 04:33:13 -05:00
|
|
|
this._context.destroy();
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
acceptPacket(packet) {
|
2019-09-30 20:57:04 -05:00
|
|
|
if (packet instanceof TraitUpdateAlivePacket) {
|
2019-05-14 05:58:04 -05:00
|
|
|
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();
|
|
|
|
}
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2019-05-14 05:58:04 -05:00
|
|
|
return;
|
|
|
|
}
|
2019-10-08 03:23:36 -05:00
|
|
|
this.entity.emit('dying');
|
2019-10-02 00:10:14 -05:00
|
|
|
this.state.isDying = true;
|
2019-10-03 00:53:56 -05:00
|
|
|
this.entity._fastDirtyCheck = true;
|
|
|
|
this._fastDirtyCheck = 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();
|
2019-05-14 05:58:04 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
tick(elapsed) {
|
2019-09-08 08:12:31 -05:00
|
|
|
if (this._dyingTickingPromise) {
|
|
|
|
this._dyingTickingPromise.tick(elapsed);
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
else {
|
2019-10-02 00:10:14 -05:00
|
|
|
if (AVOCADO_SERVER) {
|
|
|
|
this.entity.dieIfPossible();
|
|
|
|
}
|
2019-05-14 05:58:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|