const Entity = require("./Entity"); const constants = require("../Data/constants"); const { TYPES, EVENTS, TIMING_EVENTS, MAXIMUM } = constants; const { ENTITY_TYPE_PLAYER, ENTITY_TYPE_MONSTER } = TYPES; const { TIMING_EVENT_RESPAWN } = TIMING_EVENTS; const { EVENT_DIE } = EVENTS; const { MAX_SAFE_INTEGER } = MAXIMUM; class Monster extends Entity { constructor(info) { super({ type: ENTITY_TYPE_MONSTER, id: info.id, map: info.map, isAlive: true, position: info.position }); this.hp = { maximum: info.maximumHitpoint, current: info.currentHitpoint }; this.entityTypeID = info.entityTypeID; this.parentEntityTypeID = info.parentEntityTypeID ?? 0; this.respawnTime = info.respawnTime * 1000; this.isAdmiral = info.isAdmiral ?? false; this.attackers = []; this.totalDamageReceived = 0; this.damageReceived = {}; this.dieCallback = info.dieCallback; this.attackCallback = info.attackCallback; this.rewardCallback = info.rewardCallback; this.reward = info.reward; const { map, id } = this; map.monsters.set(id, this); const nearbyPlayersID = map.getNearbyPlayersGameID(this); for (let i = 0; i < nearbyPlayersID.length; i++) { const player = map.getEntityFromSubgroup(nearbyPlayersID[i]); player.inDistance[id] = 0x01; }; } increaseCurrentHitpoint(amount) { this.hp.current = Math.min(this.hp.maximum, this.hp.current + amount); return this.hp.current; } decreaseCurrentHitpoint(amount, author) { const { authorID } = author; amount = Math.abs(amount); const damage = Math.min(this.hp.current, amount); if (this.damageReceived[authorID]) this.damageReceived[authorID] += damage; else this.damageReceived[authorID] = damage; this.totalDamageReceived += damage; this.hp.current -= damage; this.attackCallback({ typeID: this.typeID, entityTypeID: this.entityTypeID, authorID, damage }); const isOverSafeLimit = this.totalDamageReceived >= MAX_SAFE_INTEGER; if (isOverSafeLimit) this.totalDamageReceived = MAX_SAFE_INTEGER; if (this.hp.current === 0 || isOverSafeLimit) { const die = { typeID: this.typeID, lastShotTypeID: 1, lastShotID: author.authorID, targetID: this.id, targetEntityTypeID: this.entityTypeID }; this.die(die); // this.setSingleEvent(11, 0, die); }; return { normalizedAmount: damage, currentHitpoint: this.hp.current }; } isAtMaximumHitpoints() { return this.hp.current === this.hp.maximum; } die(die) { super.die(); this.hp.current = 0; this.attackers.forEach(data => { const attackerEntity = this.map.getEntityFromSubgroup(data.attackerEntry); attackerEntity.wipeAttack(); }); this.attackers.length = 0; this.emit(EVENT_DIE, die, this.id); const admiralProperties = { typeID: this.typeID, entityTypeID: this.entityTypeID, parentEntityTypeID: this.parentEntityTypeID, id: this.id, isAdmiral: this.isAdmiral, authorID: die.lastShotID }; this.dieCallback(admiralProperties); this.removeEvent(11); this.damageReceived = {}; if (!this.isAdmiral) this.setEvent(TIMING_EVENT_RESPAWN, this.respawnTime); } respawn() { if (this.isAlive) return; this.hp.current = this.hp.maximum; super.respawn(); this.removeEvent(TIMING_EVENT_RESPAWN); } getProperties() { const { position, id, hp, type, typeID, isAdmiral, entityTypeID } = this; return { position, id, hp, type, typeID, isAdmiral, entityTypeID }; } }; module.exports = Monster;