const Phaser = require('phaser'); const { TEXT, POSITIONS: { COMBAT } } = require('./constants'); const CRYP_KEY_MAP = ['keydown_ONE', 'keydown_TWO', 'keydown_THREE']; const SKILL_KEY_MAP = ['keydown_Q', 'keydown_W', 'keydown_E', 'keydown_R']; const TARGET_KEY_MAP = ['keydown_SEVEN', 'keydown_EIGHT', 'keydown_NINE', 'keydown_ZERO']; const CRYP_MARGIN = COMBAT.height() / 5; const TEXT_MARGIN = COMBAT.height() / 35; const TEAM_MARGIN = COMBAT.width() * 0.7; const SKILL_WIDTH = COMBAT.width() / 10; const SKILL_HEIGHT = COMBAT.height() / 20; const skillPosition = (crypIter, skillIter) => { const skillTextX = COMBAT.width() / 3.8 + (SKILL_WIDTH + COMBAT.width() * 0.01) * skillIter; const skillTextY = TEXT_MARGIN * 5 + CRYP_MARGIN * crypIter; return [skillTextX, skillTextY]; }; const targetTextPosition = (crypIter, teamIter) => { const skillTextX = COMBAT.width() / 3.8 + 0.63 * TEAM_MARGIN * teamIter; const skillTextY = TEXT_MARGIN * 4 + CRYP_MARGIN * crypIter; return [ skillTextX, skillTextY ]; }; const skillCheckHitBox = (scenePlugin, pointer) => { const { list } = scenePlugin.get('CombatHitBox').children; for (let i = 0; i < list.length; i += 1) { if (Phaser.Geom.Rectangle.ContainsPoint(list[i].getBounds(), pointer.position)) return list[i]; } // If we didn't find a hitbox deselect them all for (let i = 0; i < list.length; i += 1) list[i].deselect(); return false; }; class CrypSkill extends Phaser.GameObjects.Container { constructor(scene, x, y, skill, cryp) { // Avatar will be a property of cryp super(scene, x, y); const CD_TEXT = skill.cd ? `(${skill.cd}T)` : ''; const SKILL_TEXT = `${skill.skill} ${CD_TEXT}`; this.origX = x; this.origY = y; this.skillBox = scene.add.rectangle(0, 0, SKILL_WIDTH, SKILL_HEIGHT, 0x222222); this.skillText = scene.add.text(0, 0, SKILL_TEXT, TEXT.NORMAL).setOrigin(0.5, 0.5); this.add(this.skillBox); this.add(this.skillText); this.state = 'deselect'; this.cryp = cryp; this.skill = skill; this.scene = scene; this.setSize(SKILL_WIDTH, SKILL_HEIGHT); this.setInteractive(); } clickHandler() { if (this.scene.phase === 'Skill') this.scene.activeSkill = this; if (this.scene.phase === 'Target') this.scene.activeTarget = this; this.select(); } select() { this.scene.children.list.forEach((skill) => { if (skill.state === 'select') skill.deselect(); }); this.skillBox.setFillStyle(0x9d9ea0); this.state = 'select'; } activate() { this.scene.children.list.forEach((skill) => { if (skill.state === 'select') skill.deselect(); }); this.skillBox.setFillStyle(0xff0000); this.state = 'activate'; } deselect() { this.skillBox.setFillStyle(0x222222); this.state = 'deselect'; } } class CombatSkills extends Phaser.Scene { constructor() { super({ key: 'CombatSkills' }); } create(phase) { this.phase = phase; this.registry.events.off('changedata', this.updateData); this.registry.events.on('changedata', this.updateData, this); this.account = this.registry.get('account'); this.input.on('dragstart', (pointer, box) => { box.clickHandler(); }); this.input.on('drag', (pointer, box, dragX, dragY) => { const hitBox = skillCheckHitBox(this.scene, pointer); if (hitBox) hitBox.select(); box.setPosition(dragX, dragY); }); this.input.on('dragend', (pointer, box) => { box.deselect(); const hitBox = skillCheckHitBox(this.scene, pointer); if (hitBox) { hitBox.clickHandler(); } box.setPosition(box.origX, box.origY); }); if (phase === 'animating') return true; // can't set this.game cause of phaser class named the same const game = this.registry.get('game'); this.renderSkills(game, phase); return true; } updateData(parent, key, data) { if (key === 'gamePhase' && data) { const shouldUpdate = data !== this.phase; if (shouldUpdate) { this.scene.get('CombatCryps').selectCryp(null); return this.scene.restart(data); } return false; } return true; } renderSkills(game, phase) { if (phase === 'Skill') return this.renderSkillPhase(game); if (phase === 'Target') return this.renderTargetPhase(game); return false; } renderSkillPhase(game) { const { account } = this; const { keyboard } = this.input; const { events } = this.game; const addSkill = (i, j, skill, cryp) => { const skillTextPos = skillPosition(i, j); const skillObj = new CrypSkill(this, skillTextPos[0], skillTextPos[1], skill, cryp); this.input.setDraggable(skillObj); this.add.existing(skillObj); return skillObj; }; const team = game.teams.find(t => t.id === account.id); const enemyTeam = game.teams.find(t => t.id !== account.id); team.cryps.forEach((cryp) => { const { iter } = this.scene.get('CombatCryps').cryps.children.entries.find(c => c.cryp.id === cryp.id); // return early if KOd if (cryp.hp.base === 0) return true; // draw the skills const skillButtons = cryp.skills.map((skill, j) => addSkill(iter, j, skill, cryp)); const bindCrypKeys = () => this.mapSkillKeys(skillButtons, game.id, cryp.id, team.id, enemyTeam.id, iter); // reset everything keyboard.on('keydown_ESC', bindCrypKeys, this); events.on('SEND_SKILL', bindCrypKeys, this); bindCrypKeys(); return true; }); return true; } mapSkillKeys(skillButtons, gameId, crypId, alliesId, enemyId, i) { const { keyboard } = this.input; keyboard.removeListener(CRYP_KEY_MAP[i]); keyboard.on(CRYP_KEY_MAP[i], () => { SKILL_KEY_MAP.forEach(k => keyboard.removeListener(k)); this.scene.get('CombatCryps').selectCryp(crypId); skillButtons.forEach((button, j) => { keyboard.on(SKILL_KEY_MAP[j], () => { this.activeSkill = button; button.select(); // clear existing keys CRYP_KEY_MAP.forEach(k => keyboard.removeListener(k)); TARGET_KEY_MAP.forEach(k => keyboard.removeListener(k)); CRYP_KEY_MAP.forEach(k => keyboard.on(k, () => { button.activate(); this.activeSkill = null; this.game.events.emit('SEND_SKILL', gameId, crypId, alliesId, button.skill.skill); })); TARGET_KEY_MAP.forEach(k => keyboard.on(k, () => { button.activate(); this.activeSkill = null; this.game.events.emit('SEND_SKILL', gameId, crypId, enemyId, button.skill.skill); })); }, this); }); }, this); return true; } renderTargetPhase(game) { const { account } = this; const { keyboard } = this.input; const skills = game.stack.filter(skill => skill.target_team_id === account.id); const friendlyCryps = game.teams.find(t => t.id === account.id).cryps; skills.forEach((skill, i) => { const crypTeam = game.teams.find(t => t.cryps.find(c => c.id === skill.source_cryp_id)); const cryp = crypTeam.cryps.find(c => c.id === skill.source_cryp_id); // Draw the cryp name const sourceCryp = this.scene.get('CombatCryps').cryps.children.entries .find(c => c.cryp.id === cryp.id); const skillPos = targetTextPosition(sourceCryp.iter, sourceCryp.team); const skillObj = new CrypSkill(this, skillPos[0], skillPos[1], skill, cryp); this.add.existing(skillObj); this.input.setDraggable(skillObj); keyboard.on( TARGET_KEY_MAP[i], () => this.mapTargetKeys(skillObj, game.id, friendlyCryps, i), this ); }); return true; } mapTargetKeys(button, gameId, friendlyCryps) { const { keyboard } = this.input; CRYP_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey)); // deselect any currently active button if (this.activeTarget) { this.activeTarget.deselect(); } button.select(); this.activeTarget = button; friendlyCryps.forEach((cryp, j) => { keyboard.on( CRYP_KEY_MAP[j], () => { this.game.events.emit('SEND_TARGET', gameId, cryp.id, button.skill); button.activate(); this.activeTarget = null; }, this ); }); return true; } clearKeys() { TARGET_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey)); CRYP_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey)); SKILL_KEY_MAP.forEach(tKey => this.input.keyboard.removeListener(tKey)); } cleanUp() { this.registry.events.off('changedata', this.updateData); this.scene.remove(); } } module.exports = CombatSkills;