import { behaviorItemFromJSON, buildCondition, buildInvoke, buildTraversal, createContext, } from '@avocado/behavior'; import {compose} from '@avocado/core'; import {StateProperty, Trait} from '@avocado/entity'; 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 { life: 100, maxLife: 100, }; } initialize() { this._context = createContext(); this._context.add('entity', this.entity); const actionsJSON = this.params.get('deathActions').toJS(); this._deathActions = behaviorItemFromJSON(actionsJSON); this._deathSound = this.params.get('deathSound'); const conditionJSON = this.params.get('deathCondition').toJS(); this._deathCondition = behaviorItemFromJSON(conditionJSON); this._isDying = false; } get deathSound() { return this._deathSound; } 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: () => { this._isDying = true; this.entity.emit('dying'); this._deathActions.on('actionsFinished', () => { if (this.entity.is('existent')) { this.entity.destroy(); } }); }, }; } tick(elapsed) { if (this._isDying) { this._deathActions.tick(this._context, elapsed); } else { this.entity.dieIfPossible(); } } }