274 lines
8.9 KiB
JavaScript
274 lines
8.9 KiB
JavaScript
const Phaser = require('phaser');
|
|
|
|
const { DELAYS, TEXT, POSITIONS: { COMBAT }, COLOURS } = require('./constants');
|
|
|
|
const CRYP_MARGIN = COMBAT.height() / 5;
|
|
const TEXT_MARGIN = COMBAT.height() / 35;
|
|
const TEAM_MARGIN = COMBAT.width() * 0.7;
|
|
|
|
const healthBarDimensions = (team, iter) => {
|
|
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 nameX = 1.25 * TEAM_MARGIN * team;
|
|
const nameY = COMBAT.y() + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
|
|
const healthX = 1.25 * TEAM_MARGIN * team;
|
|
const healthY = COMBAT.y() + TEXT_MARGIN * 2 + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
|
|
const statusX = 1.25 * TEAM_MARGIN * team;
|
|
const statusY = COMBAT.y() + TEXT_MARGIN * 3 + CRYP_MARGIN * iter + COMBAT.height() * 0.07;
|
|
return { statusX, statusY, nameX, nameY, healthX, healthY };
|
|
};
|
|
|
|
const crypEffects = (team, iter) => {
|
|
const crypEffectsX = COMBAT.width() / 7.5 + TEAM_MARGIN * team;
|
|
const crypEffectsY = TEXT_MARGIN * 2 + CRYP_MARGIN * iter;
|
|
return { crypEffectsX, crypEffectsY };
|
|
};
|
|
|
|
const crypPosition = (team, iter) => {
|
|
const crypAvatarX = COMBAT.width() / 7.5 + TEAM_MARGIN * team;
|
|
const crypAvatarY = TEXT_MARGIN * 5 + CRYP_MARGIN * iter;
|
|
return { crypAvatarX, crypAvatarY };
|
|
};
|
|
|
|
|
|
class HealthBar extends Phaser.GameObjects.Graphics {
|
|
constructor(scene, cryp, crypHpText) {
|
|
super(scene);
|
|
this.crypObj = cryp;
|
|
this.hpText = crypHpText;
|
|
|
|
this.hp = this.crypObj.cryp.hp.base;
|
|
this.stam = this.crypObj.cryp.stamina.base;
|
|
this.drawHealthBar();
|
|
}
|
|
|
|
drawHealthBar() {
|
|
this.clear();
|
|
const {
|
|
healthBarX, healthBarY, healthBarWidth, healthBarHeight,
|
|
} = healthBarDimensions(this.crypObj.team, this.crypObj.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(value) {
|
|
if (value > 0) {
|
|
this.hp = (value >= this.hp) ? 0 : this.hp -= value;
|
|
} else {
|
|
this.hp = (this.hp - value > this.stam) ? this.stam : this.hp -= value;
|
|
}
|
|
if (this.hp === 0) this.crypObj.setKo();
|
|
this.drawHealthBar();
|
|
}
|
|
}
|
|
|
|
class Effects extends Phaser.GameObjects.Group {
|
|
constructor(scene, team, iter) {
|
|
super(scene);
|
|
this.scene = scene;
|
|
const { crypEffectsX, crypEffectsY } = crypEffects(team, iter);
|
|
this.x = crypEffectsX; this.y = crypEffectsY;
|
|
this.effectCount = 0;
|
|
}
|
|
|
|
addEffect(effect) {
|
|
const y = this.y + this.effectCount * TEXT_MARGIN;
|
|
const text = `${effect.effect} for ${effect.duration} turn`;
|
|
const e = this.scene.add.text(this.x, y, text, TEXT.NORMAL);
|
|
e.effect = effect.effect;
|
|
this.add(e);
|
|
this.effectCount += 1;
|
|
}
|
|
|
|
removeEffect(effect) {
|
|
this.children.entries.forEach((e) => {
|
|
if (e.effect === effect) e.destroy();
|
|
});
|
|
}
|
|
|
|
update(effects) {
|
|
this.effectCount = 0;
|
|
this.children.entries.forEach(e => e.destroy());
|
|
effects.forEach((effect) => {
|
|
this.addEffect(effect);
|
|
});
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class CrypImage extends Phaser.GameObjects.Image {
|
|
constructor(scene, team, iter, cryp) {
|
|
// Get coords
|
|
const { crypAvatarX, crypAvatarY } = crypPosition(team, iter);
|
|
const {
|
|
statusX, statusY, nameX, nameY, healthX, healthY,
|
|
} = crypAvatarText(team, iter);
|
|
|
|
// Cryp display
|
|
// const avatar = team ? 'magmar' : 'alk';
|
|
super(scene, crypAvatarX, crypAvatarY, 'aztec', `sprite${Math.floor(Math.random() * 19) + 1}`);
|
|
this.setScale(0.5);
|
|
|
|
if (!team) this.flipX = true;
|
|
|
|
// Save position and cryp details
|
|
this.scene = scene;
|
|
this.iter = iter;
|
|
this.team = team;
|
|
this.cryp = cryp;
|
|
this.state = 'deselect';
|
|
|
|
// Add cryp name
|
|
scene.add.text(nameX, nameY, cryp.name, TEXT.NORMAL);
|
|
// Add cryp hp
|
|
const healthText = scene.add.text(healthX, healthY, '', TEXT.NORMAL);
|
|
this.healthBar = scene.add.existing(new HealthBar(scene, this, healthText));
|
|
this.effects = scene.add.existing(new Effects(scene, team, iter));
|
|
this.statusText = scene.add.text(statusX, statusY, '', TEXT.NORMAL);
|
|
}
|
|
|
|
select() {
|
|
this.setTint('0x00bb00');
|
|
this.state = 'select';
|
|
}
|
|
|
|
setKo() {
|
|
this.state = 'ko';
|
|
this.setTint('0x9d9ea0');
|
|
}
|
|
|
|
deselect() {
|
|
if (this.state !== 'ko') {
|
|
this.clearTint();
|
|
this.state = 'deselect';
|
|
}
|
|
}
|
|
|
|
clearStatus() {
|
|
this.statusText.text = '';
|
|
}
|
|
|
|
takeDamage(damage) {
|
|
if (damage > 0) this.setTint(0xff0000);
|
|
else this.setTint(0x00bb00);
|
|
this.healthBar.takeDamage(damage);
|
|
this.scene.time.delayedCall(DELAYS.DAMAGE_TICK, () => {
|
|
if (this.state !== 'ko') this.clearTint();
|
|
});
|
|
}
|
|
}
|
|
|
|
class CombatCryps extends Phaser.Scene {
|
|
constructor() {
|
|
super({ key: 'CombatCryps' });
|
|
}
|
|
|
|
create(game) {
|
|
this.cryps = this.add.group();
|
|
this.phase = game.phase;
|
|
this.account = this.registry.get('account');
|
|
this.drawCryps(game);
|
|
this.registry.events.on('changedata', this.updateData, this);
|
|
this.registry.set('crypStatusUpdate', false);
|
|
}
|
|
|
|
updateData(parent, key, data) {
|
|
if (key === 'game' && data) {
|
|
const isAnimating = this.phase === 'animating';
|
|
if (isAnimating) return false;
|
|
this.drawCryps(data);
|
|
}
|
|
|
|
if (key === 'gamePhase' && data) {
|
|
const shouldUpdate = data !== this.phase;
|
|
this.phase = data;
|
|
if (shouldUpdate) this.cryps.children.entries.forEach(c => c.clearStatus());
|
|
}
|
|
|
|
if (key === 'crypStatusUpdate' && data) {
|
|
this.updateCrypStatus(data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
drawCryps(game) {
|
|
const renderCryp = (cryp, iter, team) => {
|
|
// Add Image Avatar Class
|
|
const crypObj = new CrypImage(this, team, iter, cryp);
|
|
this.add.existing(crypObj);
|
|
this.cryps.add(crypObj);
|
|
return crypObj;
|
|
};
|
|
|
|
const renderTeam = (cryp, iter, team) => {
|
|
const crypObj = this.cryps.children.entries
|
|
.find(c => c.cryp.id === cryp.id)
|
|
|| renderCryp(cryp, iter, team);
|
|
crypObj.healthBar.hp = cryp.hp.base;
|
|
crypObj.healthBar.drawHealthBar();
|
|
crypObj.effects.update(cryp.effects);
|
|
};
|
|
|
|
const allyTeam = game.teams.find(t => t.id === this.account.id);
|
|
// in future there will be more than one
|
|
const [enemyTeam] = game.teams.filter(t => t.id !== this.account.id);
|
|
|
|
allyTeam.cryps.forEach((cryp, i) => renderTeam(cryp, i, 0));
|
|
if (!enemyTeam) return false;
|
|
enemyTeam.cryps.forEach((cryp, i) => renderTeam(cryp, i, 1));
|
|
return true;
|
|
}
|
|
|
|
selectCryp(crypId) {
|
|
this.cryps.children.entries.forEach(c => c.deselect());
|
|
if (crypId) this.cryps.children.entries.find(c => c.cryp.id === crypId).select();
|
|
}
|
|
|
|
updateCrypStatus(status) {
|
|
const targetCryp = this.cryps.children.entries
|
|
.find(c => c.cryp.id === status.id);
|
|
|
|
if (this.phase === 'Skill') {
|
|
targetCryp.statusText.text = status.target === targetCryp.cryp.account
|
|
? `${status.skill} on ally team`
|
|
: `${status.skill} on enemy team`;
|
|
}
|
|
|
|
if (this.phase === 'Target') {
|
|
const sourceCryp = this.cryps.children.entries
|
|
.find(c => c.cryp.id === status.skill.source_cryp_id);
|
|
targetCryp.statusText.text = `${sourceCryp.cryp.name} ${status.skill.skill} ${targetCryp.cryp.name}`;
|
|
}
|
|
}
|
|
|
|
cleanUp() {
|
|
this.registry.events.off('changedata', this.updateData);
|
|
this.scene.remove();
|
|
}
|
|
}
|
|
|
|
module.exports = CombatCryps;
|