feat: Update card skills, mission rosters, and enhance DeckBuilder UI
- **Data Updates**: - `cards.json`: Changed a skill from `rally` (preBattle) to `strike` (preAttack) with global effect. - `missions.json`: Swapped opponent cards in the raider mission roster (`raider_berserker_1` -> `raider_grunt_1`, `raider_reaver_1` -> `raider_scout_1`). - **DeckBuilderScene.js Enhancements**: - **Visual Feedback**: Distinguishes between "unavailable" (greyed out) and "deck full" states. Cards remain visible when the deck is full, but the Add button turns red. - **Fusion Lab Integration**: Adds a pulsing "Fusion Available" overlay on assault cards where the player has 3+ spare copies, linking directly to the `FusionScene`. - **Button States**: Refined Add button logic to display specific messages for available, deck-full, and unavailable states with corresponding colors.
This commit is contained in:
parent
20e05116fe
commit
d3f9facb4a
|
|
@ -1380,9 +1380,10 @@
|
||||||
"delay": 2,
|
"delay": 2,
|
||||||
"skills": [
|
"skills": [
|
||||||
{
|
{
|
||||||
"name": "rally",
|
"name": "strike",
|
||||||
"value": 3,
|
"all": true,
|
||||||
"trigger": "preBattle"
|
"value": 2,
|
||||||
|
"trigger": "preAttack"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -119,12 +119,12 @@
|
||||||
"opponent": {
|
"opponent": {
|
||||||
"commander": "raider_cmd_1",
|
"commander": "raider_cmd_1",
|
||||||
"cards": [
|
"cards": [
|
||||||
"raider_berserker_1",
|
"raider_grunt_1",
|
||||||
"raider_berserker_1",
|
"raider_berserker_1",
|
||||||
"raider_cutthroat_1",
|
"raider_cutthroat_1",
|
||||||
"raider_warlord_1",
|
"raider_warlord_1",
|
||||||
"raider_marauder_1",
|
"raider_marauder_1",
|
||||||
"raider_reaver_1"
|
"raider_scout_1"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"rewards": {
|
"rewards": {
|
||||||
|
|
|
||||||
|
|
@ -185,26 +185,94 @@ export class DeckBuilderScene extends Phaser.Scene {
|
||||||
const remaining = Math.max(0, owned - used);
|
const remaining = Math.max(0, owned - used);
|
||||||
const canAdd = this._canAdd(card);
|
const canAdd = this._canAdd(card);
|
||||||
|
|
||||||
|
// Deck-full block: assault card has available copies but the deck is at capacity.
|
||||||
|
// The card stays fully visible; only the button turns red.
|
||||||
|
const deckFull = card.type === 'assault' && this.workingDeck.cards.length >= 10;
|
||||||
|
const deckFullBlocked = deckFull && owned > 0 && remaining > 0;
|
||||||
|
|
||||||
// Card instance for display
|
// Card instance for display
|
||||||
const inst = this.cardManager.createInstance(card.id);
|
const inst = this.cardManager.createInstance(card.id);
|
||||||
const cardObj = new CardObject(this, cx, cy, inst, { width: this.CARD_W, height: this.CARD_H });
|
const cardObj = new CardObject(this, cx, cy, inst, { width: this.CARD_W, height: this.CARD_H });
|
||||||
if (!canAdd) cardObj.setAlpha(0.4);
|
// Only dim cards that are genuinely unavailable (not owned / no copies left).
|
||||||
|
// When the deck is merely full, keep cards at full alpha so the player can browse.
|
||||||
|
if (!canAdd && !deckFullBlocked) cardObj.setAlpha(0.4);
|
||||||
this.scrollContainer.add(cardObj);
|
this.scrollContainer.add(cardObj);
|
||||||
|
|
||||||
|
// ── Fusion available overlay ──────────────────────────────────────────────
|
||||||
|
// Show when the player has 3+ spare copies of a fusible card (assault, non-legendary).
|
||||||
|
if (card.type === 'assault' && card.rarity !== 'legendary' && remaining >= 3) {
|
||||||
|
// Sits over the art area (~upper-centre of the card)
|
||||||
|
const ovY = cy - Math.round(this.CARD_H * 0.18);
|
||||||
|
const ovW = this.CARD_W - 8;
|
||||||
|
const ovH = 46;
|
||||||
|
|
||||||
|
const ovBg = this.add.rectangle(cx, ovY, ovW, ovH, 0x0d0022, 0.92)
|
||||||
|
.setStrokeStyle(1, 0xaa44ff)
|
||||||
|
.setInteractive({ useHandCursor: true });
|
||||||
|
|
||||||
|
const ovIcon = this.add.text(cx, ovY - 9, '⚗ FUSION AVAILABLE', {
|
||||||
|
fontSize: '11px', color: '#cc88ff', fontStyle: 'bold', fontFamily: 'Audiowide'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
const ovSub = this.add.text(cx, ovY + 9, 'Click to open Fusion Lab →', {
|
||||||
|
fontSize: '10px', color: '#7744aa', fontFamily: 'Audiowide'
|
||||||
|
}).setOrigin(0.5);
|
||||||
|
|
||||||
|
// Hover tint
|
||||||
|
ovBg.on('pointerover', () => {
|
||||||
|
ovBg.setFillStyle(0x220044);
|
||||||
|
ovBg.setStrokeStyle(2, 0xdd88ff);
|
||||||
|
ovIcon.setColor('#ee99ff');
|
||||||
|
});
|
||||||
|
ovBg.on('pointerout', () => {
|
||||||
|
ovBg.setFillStyle(0x0d0022);
|
||||||
|
ovBg.setStrokeStyle(1, 0xaa44ff);
|
||||||
|
ovIcon.setColor('#cc88ff');
|
||||||
|
});
|
||||||
|
ovBg.on('pointerdown', () => this.scene.start('FusionScene'));
|
||||||
|
|
||||||
|
// Pulsing glow
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [ovBg, ovIcon, ovSub],
|
||||||
|
alpha: { from: 0.75, to: 1 },
|
||||||
|
duration: 1100,
|
||||||
|
yoyo: true,
|
||||||
|
repeat: -1,
|
||||||
|
ease: 'Sine.easeInOut'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scrollContainer.add([ovBg, ovIcon, ovSub]);
|
||||||
|
}
|
||||||
|
|
||||||
// Owned/used count
|
// Owned/used count
|
||||||
const countY = cy + this.CARD_H / 2 + 4;
|
const countY = cy + this.CARD_H / 2 + 4;
|
||||||
|
const countColor = canAdd ? '#88cc88' : deckFullBlocked ? '#aaaaaa' : '#555555';
|
||||||
const countText = this.add.text(cx, countY, `Owned: ${owned} | In Deck: ${used}`, {
|
const countText = this.add.text(cx, countY, `Owned: ${owned} | In Deck: ${used}`, {
|
||||||
fontSize: '11px', color: canAdd ? '#88cc88' : '#555555', fontFamily: 'Audiowide'
|
fontSize: '11px', color: countColor, fontFamily: 'Audiowide'
|
||||||
}).setOrigin(0.5, 0);
|
}).setOrigin(0.5, 0);
|
||||||
this.scrollContainer.add(countText);
|
this.scrollContainer.add(countText);
|
||||||
|
|
||||||
// +ADD button with remaining count
|
// +ADD button — three visual states:
|
||||||
|
// green = can add (deck has room, copies available)
|
||||||
|
// red = copies available but deck is full
|
||||||
|
// grey = no copies available or not owned
|
||||||
const btnY = countY + 16;
|
const btnY = countY + 16;
|
||||||
const btnLabel = canAdd ? `+ ADD (remain: ${remaining})` : '+ ADD';
|
let btnBgColor, btnStroke, btnTextColor, btnLabel;
|
||||||
const btnBg = this.add.rectangle(cx, btnY, this.CARD_W - 10, this.BTN_H, canAdd ? 0x225522 : 0x222222)
|
if (canAdd) {
|
||||||
.setStrokeStyle(1, canAdd ? 0x44aa44 : 0x333333);
|
btnBgColor = 0x225522; btnStroke = 0x44aa44; btnTextColor = '#44ff44';
|
||||||
|
btnLabel = `+ ADD (remain: ${remaining})`;
|
||||||
|
} else if (deckFullBlocked) {
|
||||||
|
btnBgColor = 0x552222; btnStroke = 0xaa4444; btnTextColor = '#ff4444';
|
||||||
|
btnLabel = `DECK FULL (${remaining} avail)`;
|
||||||
|
} else {
|
||||||
|
btnBgColor = 0x222222; btnStroke = 0x333333; btnTextColor = '#444444';
|
||||||
|
btnLabel = '+ ADD';
|
||||||
|
}
|
||||||
|
|
||||||
|
const btnBg = this.add.rectangle(cx, btnY, this.CARD_W - 10, this.BTN_H, btnBgColor)
|
||||||
|
.setStrokeStyle(1, btnStroke);
|
||||||
const btnTxt = this.add.text(cx, btnY, btnLabel, {
|
const btnTxt = this.add.text(cx, btnY, btnLabel, {
|
||||||
fontSize: '12px', color: canAdd ? '#44ff44' : '#444444', fontFamily: 'Audiowide'
|
fontSize: '12px', color: btnTextColor, fontFamily: 'Audiowide'
|
||||||
}).setOrigin(0.5);
|
}).setOrigin(0.5);
|
||||||
this.scrollContainer.add(btnBg);
|
this.scrollContainer.add(btnBg);
|
||||||
this.scrollContainer.add(btnTxt);
|
this.scrollContainer.add(btnTxt);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue