bump mission gold rewards and hive_link values; unlock all faction commanders on first campaign clear; enhance Fusion Lab UI

This commit is contained in:
Brian Fertig 2026-03-25 19:32:50 -06:00
parent b336f60197
commit 662147cdfb
10 changed files with 149 additions and 89 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

View File

@ -34,7 +34,7 @@
},
{
"attack": 0,
"health": 68,
"health": 136,
"armor": 5,
"delay": 0,
"skills": [
@ -47,7 +47,7 @@
},
{
"attack": 0,
"health": 102,
"health": 204,
"armor": 7,
"delay": 0,
"skills": [
@ -60,7 +60,7 @@
},
{
"attack": 0,
"health": 152,
"health": 304,
"armor": 10,
"delay": 0,
"skills": [
@ -112,7 +112,7 @@
},
{
"attack": 0,
"health": 68,
"health": 136,
"armor": 9,
"delay": 0,
"skills": [
@ -126,7 +126,7 @@
},
{
"attack": 0,
"health": 102,
"health": 204,
"armor": 13,
"delay": 0,
"skills": [
@ -140,7 +140,7 @@
},
{
"attack": 0,
"health": 152,
"health": 304,
"armor": 20,
"delay": 0,
"skills": [
@ -193,7 +193,7 @@
},
{
"attack": 0,
"health": 57,
"health": 114,
"armor": 3,
"delay": 0,
"skills": [
@ -207,7 +207,7 @@
},
{
"attack": 0,
"health": 85,
"health": 170,
"armor": 4,
"delay": 0,
"skills": [
@ -221,7 +221,7 @@
},
{
"attack": 0,
"health": 127,
"health": 254,
"armor": 5,
"delay": 0,
"skills": [
@ -286,7 +286,7 @@
},
{
"attack": 0,
"health": 68,
"health": 136,
"armor": 7,
"delay": 0,
"skills": [
@ -306,7 +306,7 @@
},
{
"attack": 0,
"health": 102,
"health": 204,
"armor": 10,
"delay": 0,
"skills": [
@ -326,7 +326,7 @@
},
{
"attack": 0,
"health": 152,
"health": 304,
"armor": 15,
"delay": 0,
"skills": [
@ -6256,7 +6256,7 @@
"skills": [
{
"name": "hive_link",
"value": 2,
"value": 3,
"trigger": "passive"
}
]
@ -6269,7 +6269,7 @@
"skills": [
{
"name": "hive_link",
"value": 4,
"value": 5,
"trigger": "passive"
}
]
@ -6282,7 +6282,7 @@
"skills": [
{
"name": "hive_link",
"value": 8,
"value": 10,
"trigger": "passive"
}
]

View File

@ -381,7 +381,7 @@
]
},
"rewards": {
"gold": 150,
"gold": 1200,
"cards": [
"xeno_drone_1"
]
@ -408,7 +408,7 @@
]
},
"rewards": {
"gold": 200,
"gold": 1300,
"cards": [
"xeno_spitter_1"
]
@ -435,7 +435,7 @@
]
},
"rewards": {
"gold": 250,
"gold": 1400,
"cards": [
"xeno_beetle_1"
]
@ -463,7 +463,7 @@
]
},
"rewards": {
"gold": 300,
"gold": 1500,
"cards": [
"xeno_worker_1"
]
@ -491,7 +491,7 @@
]
},
"rewards": {
"gold": 350,
"gold": 1600,
"cards": [
"xeno_guard_1"
]
@ -519,7 +519,7 @@
]
},
"rewards": {
"gold": 400,
"gold": 1700,
"cards": [
"xeno_mantis_1"
]
@ -547,7 +547,7 @@
]
},
"rewards": {
"gold": 450,
"gold": 1800,
"cards": [
"xeno_horror_1"
]
@ -575,7 +575,7 @@
]
},
"rewards": {
"gold": 500,
"gold": 1900,
"cards": [
"xeno_hiveguard_1"
]
@ -602,7 +602,7 @@
]
},
"rewards": {
"gold": 100,
"gold": 2000,
"cards": [
"right_acolyte_1"
]
@ -629,7 +629,7 @@
]
},
"rewards": {
"gold": 150,
"gold": 2100,
"cards": [
"right_pilgrim_1"
]
@ -656,7 +656,7 @@
]
},
"rewards": {
"gold": 200,
"gold": 2200,
"cards": [
"right_sentinel_1"
]
@ -683,7 +683,7 @@
]
},
"rewards": {
"gold": 250,
"gold": 2300,
"cards": [
"right_hacker_1"
]
@ -710,7 +710,7 @@
]
},
"rewards": {
"gold": 300,
"gold": 2400,
"cards": [
"right_zealot_1"
]
@ -737,7 +737,7 @@
]
},
"rewards": {
"gold": 350,
"gold": 2500,
"cards": [
"right_templar_1"
]
@ -762,7 +762,7 @@
]
},
"rewards": {
"gold": 400,
"gold": 2600,
"cards": [
"right_purifier_1"
]
@ -789,7 +789,7 @@
]
},
"rewards": {
"gold": 450,
"gold": 2700,
"cards": [
"right_prophet_1"
]
@ -816,7 +816,7 @@
]
},
"rewards": {
"gold": 200,
"gold": 2800,
"cards": [
"imp_trooper_1"
]
@ -843,7 +843,7 @@
]
},
"rewards": {
"gold": 250,
"gold": 2900,
"cards": [
"imp_shieldwall_1"
]
@ -870,7 +870,7 @@
]
},
"rewards": {
"gold": 300,
"gold": 3000,
"cards": [
"imp_gunner_1"
]
@ -898,7 +898,7 @@
]
},
"rewards": {
"gold": 350,
"gold": 3100,
"cards": [
"imp_sniper_1"
]
@ -926,7 +926,7 @@
]
},
"rewards": {
"gold": 400,
"gold": 3200,
"cards": [
"imp_mortar_1"
]
@ -953,7 +953,7 @@
]
},
"rewards": {
"gold": 450,
"gold": 3300,
"cards": [
"imp_praetorian_1"
]
@ -981,7 +981,7 @@
]
},
"rewards": {
"gold": 500,
"gold": 3400,
"cards": [
"imp_sentinel_1"
]
@ -1008,7 +1008,7 @@
]
},
"rewards": {
"gold": 600,
"gold": 3500,
"cards": [
"imp_dreadnought_1"
]

View File

@ -4129,15 +4129,21 @@ export class BattleScene extends Phaser.Scene {
rewards.cards.forEach(cardId => SaveManager.addCard(save, cardId));
}
// Check if this is the final mission of a campaign — if so, unlock the enemy commander (once only)
let unlockedCommander = null;
const campaigns = this.registry.get('campaigns') || [];
const campaign = campaigns.find(c => c.missions && c.missions[c.missions.length - 1] === this.missionData.id);
if (campaign) {
const commanderId = this.missionData.opponent?.commander;
if (commanderId && !save.collection[commanderId]) {
SaveManager.addCard(save, commanderId);
unlockedCommander = commanderId;
// Check if this is the final mission of a campaign — if so, unlock all faction commanders (first clear only)
let unlockedCommanders = [];
if (firstClear) {
const campaigns = this.registry.get('campaigns') || [];
const campaign = campaigns.find(c => c.missions && c.missions[c.missions.length - 1] === this.missionData.id);
if (campaign) {
const faction = this.missionData.campaignId.replace('campaign_', '');
const cardManager = this.registry.get('cardManager');
const factionCommanders = cardManager.getAllCards().filter(c => c.type === 'commander' && c.faction === faction);
for (const cmd of factionCommanders) {
if (!save.collection[cmd.id]) {
SaveManager.addCard(save, cmd.id);
unlockedCommanders.push(cmd);
}
}
}
}
@ -4158,12 +4164,10 @@ export class BattleScene extends Phaser.Scene {
}).setOrigin(0.5);
}
if (unlockedCommander) {
const cardManager = this.registry.get('cardManager');
const cmdCard = cardManager.getCard(unlockedCommander);
const cmdName = cmdCard ? cmdCard.name : unlockedCommander;
this.add.text(width / 2, height / 2 + 110, `Commander unlocked: ${cmdName}!`, {
fontSize: '22px', color: '#ffdd44', fontFamily: 'Audiowide'
if (unlockedCommanders.length > 0) {
const names = unlockedCommanders.map(c => c.name).join(', ');
this.add.text(width / 2, height / 2 + 110, `Commanders unlocked: ${names}!`, {
fontSize: '20px', color: '#ffdd44', fontFamily: 'Audiowide'
}).setOrigin(0.5);
}
} else if (!won && this.missionData) {

View File

@ -16,9 +16,9 @@ const RARITY_COLORS = {
// Layout constants
const STACKS_LEFT = 20;
const STACKS_TOP = 100;
const STACKS_TOP = 120;
const STACKS_W = 700;
const STACKS_H = 710;
const STACKS_H = 690;
const CARD_W = 185;
const CARD_H = 255;
const CELL_W = 205;
@ -104,10 +104,81 @@ export class FusionScene extends Phaser.Scene {
// ── Header ─────────────────────────────────────────────────────────────────
_buildHeader() {
this.add.text(360, 28, 'FUSION LAB', {
fontSize: '36px', color: '#d4af37', fontStyle: 'bold', fontFamily: 'RaiderCrusader'
const cx = 360;
const titleY = 48;
// ── Layered pulsing plasma glow behind the title ──────────────────────
// Three concentric layers: wide+faint → narrow+bright, each pulsing at a
// different rate to create a breathing, living energy effect.
const glowLayers = [
{ w: 580, h: 84, color: 0x001500, alphaMin: 0.08, alphaMax: 0.18, dur: 2200 },
{ w: 400, h: 60, color: 0x004400, alphaMin: 0.12, alphaMax: 0.26, dur: 1700, delay: 350 },
{ w: 240, h: 38, color: 0x00bb44, alphaMin: 0.16, alphaMax: 0.42, dur: 1200, delay: 700 },
];
for (const l of glowLayers) {
const g = this.add.graphics();
g.fillStyle(l.color, 1);
g.fillRect(cx - l.w / 2, titleY - l.h / 2, l.w, l.h);
g.setAlpha(l.alphaMin);
this.tweens.add({
targets: g,
alpha: { from: l.alphaMin, to: l.alphaMax },
duration: l.dur,
delay: l.delay || 0,
yoyo: true,
repeat: -1,
ease: 'Sine.InOut'
});
}
// ── Horizontal accent lines (top & bottom of glow) ────────────────────
for (const yOff of [-34, 34]) {
const line = this.add.graphics();
line.fillStyle(0x00cc44, 1);
line.fillRect(cx - 240, titleY + yOff, 480, 1);
line.setAlpha(0.35);
this.tweens.add({
targets: line,
alpha: { from: 0.2, to: 0.6 },
duration: 2400,
yoyo: true,
repeat: -1,
ease: 'Sine.InOut'
});
}
// ── Periodic scan sweep across the glow ──────────────────────────────
// A thin vertical bar of light drifts left→right every few seconds,
// like an energy pulse charging through the machine.
const sweep = this.add.graphics();
sweep.fillStyle(0x88ffb0, 1);
sweep.fillRect(0, titleY - 36, 3, 72);
sweep.setAlpha(0);
const doSweep = () => {
if (!sweep.scene) return;
sweep.x = cx - 260;
this.tweens.add({
targets: sweep,
x: cx + 260,
alpha: { from: 0.75, to: 0 },
duration: 650,
ease: 'Quad.In',
onComplete: () => { this.time.delayedCall(4500, doSweep); }
});
};
this.time.delayedCall(1200, doSweep);
// ── Title text with a soft cyan postFX glow ───────────────────────────
const titleText = this.add.text(cx, titleY, 'FUSION LAB', {
fontSize: '36px', color: '#d4af37', fontStyle: 'bold', fontFamily: 'RaiderCrusader',
stroke: '#001a00', strokeThickness: 4
}).setOrigin(0.5);
this.add.text(360, 58, 'Combine 3 copies of a card to forge a stronger one', {
if (titleText.postFX) {
titleText.postFX.addGlow(0x00ff55, 5, 0, false, 0.14, 14);
}
this.add.text(cx, 82, 'Combine 3 copies of a card to forge a stronger one', {
fontSize: '16px', color: '#888888', fontFamily: 'Audiowide'
}).setOrigin(0.5);
}
@ -257,16 +328,16 @@ export class FusionScene extends Phaser.Scene {
});
// Info text (visible when a stack is selected)
this._fuseInfoText = this.add.text(1060, 855, '', {
this._fuseInfoText = this.add.text(1060, 900, '', {
fontSize: '20px', color: '#ffffff', fontFamily: 'Audiowide'
}).setOrigin(0.5).setVisible(false);
// Fuse button
this._fuseBtnBg = this.add.rectangle(1060, 920, 260, 65, 0x553300)
this._fuseBtnBg = this.add.rectangle(1060, 970, 260, 65, 0x553300)
.setStrokeStyle(3, 0xffaa00)
.setInteractive({ useHandCursor: true })
.setVisible(false);
this._fuseBtnText = this.add.text(1060, 920, 'FUSE', {
this._fuseBtnText = this.add.text(1060, 970, 'FUSE', {
fontSize: '26px', color: '#ffd700', fontStyle: 'bold', fontFamily: 'Audiowide'
}).setOrigin(0.5).setVisible(false);
@ -520,7 +591,7 @@ export class FusionScene extends Phaser.Scene {
const col = i % 4;
const row = Math.floor(i / 4);
const x = startX + col * (pw + gap);
const y = PREVIEW_TOP + 80 + row * (ph + 30);
const y = PREVIEW_TOP + 130 + row * (ph + 20);
const instance = this.cardManager.createInstance(card.id, this.save.level || 1);
const cardObj = new CardObject(this, x, y, instance, {

View File

@ -37,6 +37,11 @@ export class StoreScene extends Phaser.Scene {
preload() {
this.load.video('corridors', 'assets/video/corridors.mp4');
this.load.image('pack_imperial', 'assets/images/ui/pack_imperial.png');
this.load.image('pack_raider', 'assets/images/ui/pack_raider.png');
this.load.image('pack_bloodthirsty', 'assets/images/ui/pack_bloodthirsty.png');
this.load.image('pack_xeno', 'assets/images/ui/pack_xeno.png');
this.load.image('pack_righteous', 'assets/images/ui/pack_righteous.png');
}
create() {
@ -122,32 +127,12 @@ export class StoreScene extends Phaser.Scene {
.setStrokeStyle(3, unlocked ? factionColor : 0x333333);
elements.push(packBg);
// Placeholder pack art
const artBg = this.add.rectangle(x, y - 100, 220, 180, factionColor, unlocked ? 0.8 : 0.2)
.setStrokeStyle(2, unlocked ? 0xffffff : 0x444444, unlocked ? 0.3 : 0.1);
elements.push(artBg);
// Faction icon text on art
const artLabel = this.add.text(x, y - 115, FACTION_LABELS[pack.faction] || '?', {
fontSize: '22px', color: unlocked ? '#ffffff' : '#444444',
fontStyle: 'bold', fontFamily: 'RaiderCrusader'
}).setOrigin(0.5);
elements.push(artLabel);
const artSub = this.add.text(x, y - 80, 'BOOSTER', {
fontSize: '14px', color: unlocked ? '#aaaaaa' : '#333333', fontFamily: 'Audiowide'
}).setOrigin(0.5);
elements.push(artSub);
// Decorative lines on art
const artGfx = this.add.graphics();
const lineColor = unlocked ? factionColor : 0x333333;
const lineAlpha = unlocked ? 0.5 : 0.15;
artGfx.lineStyle(1, lineColor, lineAlpha);
artGfx.strokeRect(x - 100, y - 180, 200, 160);
artGfx.lineStyle(1, lineColor, lineAlpha * 0.5);
artGfx.strokeRect(x - 90, y - 170, 180, 140);
elements.push(artGfx);
// Pack art image
const packImageKey = `pack_${pack.faction}`;
const packArt = this.add.image(x, y - 100, packImageKey)
.setDisplaySize(220, 180)
.setAlpha(unlocked ? 1 : 0.25);
elements.push(packArt);
// Pack name
const nameText = this.add.text(x, y + 10, pack.name, {