const Phaser = require('phaser'); const { DELAYS, TEXT, POSITIONS: { COMBAT }, COLOURS } = require('./constants'); const calcMargin = () => { const CRYP_MARGIN = COMBAT.height() / 5; const TEXT_MARGIN = COMBAT.height() / 35; const TEAM_MARGIN = COMBAT.width() * 0.7; const X_PADDING = COMBAT.width() / 10; const Y_PADDING = COMBAT.height() / 7; return { CRYP_MARGIN, TEXT_MARGIN, TEAM_MARGIN, X_PADDING, Y_PADDING }; }; const healthBarDimensions = (team, iter) => { const { TEAM_MARGIN, TEXT_MARGIN, CRYP_MARGIN } = calcMargin(); const healthBarX = 1.25 * TEAM_MARGIN * team; const healthBarY = COMBAT.y() + TEXT_MARGIN + CRYP_MARGIN * iter + COMBAT.height() * 0.07; const healthBarWidth = TEAM_MARGIN / 10; const healthBarHeight = TEXT_MARGIN / 1.5; return { healthBarX, healthBarY, healthBarWidth, healthBarHeight }; }; const crypAvatarText = (team, iter) => { const { TEAM_MARGIN, CRYP_MARGIN, TEXT_MARGIN } = calcMargin(); const nameTextX = 1.25 * TEAM_MARGIN * team; const nameTextY = COMBAT.y() + CRYP_MARGIN * iter + COMBAT.height() * 0.07; const healthTextX = 1.25 * TEAM_MARGIN * team; const healthTextY = COMBAT.y() + TEXT_MARGIN * 2 + CRYP_MARGIN * iter + COMBAT.height() * 0.07; return { nameTextX, nameTextY, healthTextX, healthTextY }; }; const skillTextPosition = (crypIter, skillIter) => { const { TEXT_MARGIN } = calcMargin(); const skillTextX = 0.15 * COMBAT.width() * crypIter; const skillTextY = COMBAT.y() + COMBAT.height() * 0.7 + TEXT_MARGIN * skillIter; return [skillTextX, skillTextY]; }; const crypPosition = (team, iter) => { const { CRYP_MARGIN, TEAM_MARGIN, Y_PADDING } = calcMargin(); const crypAvatarX = COMBAT.width() / 8 + TEAM_MARGIN * team; const crypAvatarY = Y_PADDING * 1.25 + CRYP_MARGIN * iter; return { crypAvatarX, crypAvatarY }; }; class CrypImage extends Phaser.GameObjects.Image { constructor(scene, team, iter, avatar, cryp, healthbar) { // Avatar will be a property of cryp const { crypAvatarX, crypAvatarY } = crypPosition(team, iter); super(scene, crypAvatarX, crypAvatarY, avatar); this.scene = scene; this.cryp = cryp; this.iter = iter; this.healthbar = healthbar; } clickHandler() { this.scene.game.events.emit('SEND_ACTIVE_SKILL', this.cryp); } takeDamage(damage) { this.setTint(0xff0000); this.healthbar.takeDamage(damage); this.scene.time.delayedCall(DELAYS.DAMAGE_TICK, () => { this.clearTint(); }); } } class CrypSkill extends Phaser.GameObjects.Text { constructor(scene, x, y, skill, cryp) { // Avatar will be a property of cryp if (skill) { const CD_TEXT = skill.cd ? `(${skill.cd}T)` : ''; const SKILL_TEXT = `${skill.skill} ${CD_TEXT}`; super(scene, x, y, SKILL_TEXT, TEXT.NORMAL); this.cryp = cryp; this.skill = skill; this.scene = scene; this.setInteractive(); } else { super(scene, x, y, cryp.name, TEXT.HEADER); } } clickHandler() { this.scene.game.events.emit('SET_ACTIVE_SKILL', this); } } class HealthBar extends Phaser.GameObjects.Graphics { constructor(scene, cryp, team, iter, crypHpText) { super(scene); this.team = team; this.iter = iter; this.hp = cryp.hp.base; this.stam = cryp.stamina.base; this.hpText = crypHpText; this.drawHealthBar(); } drawHealthBar() { this.clear(); const { healthBarX, healthBarY, healthBarWidth, healthBarHeight, } = healthBarDimensions(this.team, this.iter); this.hpText.text = `${this.hp.toString()} / ${this.stam.toString()} HP`; // Draw Black Border this.fillStyle(COLOURS.BLACK); this.fillRect(healthBarX, healthBarY, healthBarWidth, healthBarHeight); // White fill this.fillStyle(COLOURS.WHITE); this.fillRect(healthBarX + 2, healthBarY + 2, healthBarWidth - 4, healthBarHeight - 4); // Fill the health bar const healthPercentage = this.hp / this.stam; if (healthPercentage < 0.3) { this.fillStyle(COLOURS.RED); } else if (healthPercentage < 0.65) { this.fillStyle(COLOURS.YELLOW); } else { this.fillStyle(0x00ff00); // str8 up green } const healthWidth = Math.floor(healthBarWidth * healthPercentage); this.fillRect(healthBarX + 2, healthBarY + 2, healthWidth, healthBarHeight - 4); } takeDamage(damage) { const takeDamage = (damage > this.hp) ? this.hp : damage; this.hp -= takeDamage; this.drawHealthBar(); } } function renderCryp(scene, group, cryp, game, team, iter) { // Add Image Avatar Class const avatar = team ? 'magmar' : 'alk'; // Add cryp hp const { nameTextX, nameTextY, healthTextX, healthTextY } = crypAvatarText(team, iter); const crypName = scene.add.text(nameTextX, nameTextY, cryp.name, TEXT.NORMAL); const crypHpText = scene.add.text(healthTextX, healthTextY, '', TEXT.NORMAL); const healthBar = scene.add.existing(new HealthBar(scene, cryp, team, iter, crypHpText)); // Add cryp name const crypSpawn = new CrypImage(scene, team, iter, avatar, cryp, healthBar); scene.add.existing(crypSpawn) .setScale(0.5) .setInteractive(); group.addMultiple([crypHpText, healthBar, crypSpawn, crypName]); return crypSpawn; } function renderSkills(scene, group, cryp, game, iter) { const skillList = []; // If the cryps have been spawned already put the skills in a corresponding pos const namePos = skillTextPosition(iter, 0); const addSkill = (skill, i) => { // Draw skill group name as part of the "skill class" so we can destroy it later if (i === 0) group.add(scene.add.existing(new CrypSkill(scene, namePos[0], namePos[1], false, cryp))); const skillTextPos = skillTextPosition(iter, i + 2); const skillObj = new CrypSkill(scene, skillTextPos[0], skillTextPos[1], skill, cryp); group.add(scene.add.existing(skillObj)); skillList.push(skillObj); }; if (game.phase === 'Skill' && cryp.account === scene.account.id) { if (cryp.hp.base === 0) return true; cryp.skills.forEach(addSkill); } else if (game.phase === 'Target' && cryp.account !== scene.account.id) { const blockSkill = game.stack.find(skill => skill.source_cryp_id === cryp.id); // cryp not casting this turn if (!blockSkill) return false; addSkill(blockSkill, 0); } return skillList; } class CombatCryps extends Phaser.GameObjects.Group { constructor(scene) { super(scene); this.scene = scene; } update(game, createCryps) { // Setting gamePhase will stop redraw unless phase changes again if (!createCryps) this.clearSkills(); // Destroy skills currently shown as the game state has changed const account = this.scene.registry.get('account'); const allyTeam = game.teams.find(t => t.id === account.id); // in future there will be more than one const [enemyTeam] = game.teams.filter(t => t.id !== account.id); const renderTeam = (cryp, iter, team) => { const crypObj = createCryps ? renderCryp(this.scene, this, cryp, game, team, iter) : this.children.entries .filter(obj => obj instanceof CrypImage) .find(c => c.cryp.id === cryp.id); // Update to health bars wont be needed when dmg taken is done properly crypObj.healthbar.hp = cryp.hp.base; crypObj.healthbar.drawHealthBar(); crypObj.skills = renderSkills(this.scene, this, cryp, game, crypObj.iter); const addKeys = (game.phase === 'Skill' && !team) || (game.phase === 'Target' && team); if (addKeys) this.scene.crypKeyHandler(crypObj, crypObj.iter); }; allyTeam.cryps.forEach((cryp, i) => renderTeam(cryp, i, 0)); enemyTeam.cryps.forEach((cryp, i) => renderTeam(cryp, i, 1)); return true; } clearSkills() { // console.log(this.scene.gameStart); this.children.entries.filter(obj => obj instanceof CrypSkill).forEach(obj => obj.destroy()); } } module.exports = { CombatCryps, CrypImage, CrypSkill };