fix: AI only plays lands — sync card enrichment, mana pool check, field alignment
- Add _enrichCardFromCache() in precon-loader.js for synchronous card enrichment at draw time (typeLine, cmc, oracle roles available before async Scryfall batch completes) - Call _enrichCardFromCache in drawCard() so AI has complete card data on its first turn - Improve _canAfford in ai-bridge.js: check actual mana pool before falling back to untapped land count; free spells (cmc 0) always castable - Fix totalCards field name mismatch in ui.js and engine.js (lab.py returns totalCards, not card_count/total_cards) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
9eaa41a4ae
commit
44123f7622
4 files changed
+40
-3
No files matched your search
+13
-1
@@ -895,10 +895,22 @@ class MacroActionMapper {
|
||||
|
||||
static _canAfford(playerIdx, card, gameState) {
|
||||
if (!gameState) return false;
|
||||
const cmc = MacroActionMapper._cmc(card);
|
||||
if (cmc === 0) return true; // Free spells always castable
|
||||
|
||||
// Prefer actual mana pool if populated
|
||||
const player = gameState.players[playerIdx];
|
||||
const pool = player?.manaPool;
|
||||
if (pool) {
|
||||
const total = Object.values(pool).reduce((s, v) => s + (v || 0), 0);
|
||||
if (total > 0) return total >= cmc;
|
||||
}
|
||||
|
||||
// Fallback: count untapped lands
|
||||
const available = typeof aiCountUntappedLands === 'function'
|
||||
? aiCountUntappedLands(playerIdx)
|
||||
: 0;
|
||||
return available >= MacroActionMapper._cmc(card);
|
||||
return available >= cmc;
|
||||
}
|
||||
|
||||
static _creatureScore(card) {
|
||||
|
||||
@@ -8241,6 +8241,7 @@ function drawCard(playerId) {
|
||||
}
|
||||
|
||||
const card = player.zones.library.shift(); // Take from top (index 0)
|
||||
if (typeof _enrichCardFromCache === 'function') _enrichCardFromCache(card);
|
||||
player.zones.hand.push(card);
|
||||
addLogEntry('<strong>' + player.name + '</strong> drew a card (' + player.zones.hand.length + ' in hand)');
|
||||
updatePlayerZones();
|
||||
@@ -12604,7 +12605,7 @@ function _loadUserDecksForSetup() {
|
||||
var html = '';
|
||||
for (var di = 0; di < decks.length; di++) {
|
||||
var d = decks[di];
|
||||
var cardCount = d.card_count || d.total_cards || 0;
|
||||
var cardCount = d.totalCards || d.card_count || d.total_cards || 0;
|
||||
var cmdr = d.commander || '';
|
||||
html += '<button class="setup-custom-deck-btn" id="setup-custom-deck-btn-' + i + '-' + di + '"' +
|
||||
' onclick="selectSetupUserDeck(' + i + ',' + d.deck_id + ',\'' + (d.name || 'Untitled').replace(/'/g, "\\'") + '\')">' +
|
||||
|
||||
@@ -281,6 +281,30 @@ function _applyScryfallDataToAllCards() {
|
||||
if (typeof updateZoneCounts === 'function') updateZoneCounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously enrich a single card from the Scryfall cache.
|
||||
* Called at draw time so cards have typeLine/cmc/oracle data
|
||||
* before the AI's first turn, even if async enrichment hasn't completed.
|
||||
*/
|
||||
function _enrichCardFromCache(card) {
|
||||
if (!card || !card.name) return;
|
||||
const data = _scryfallCache[card.name];
|
||||
if (!data) return;
|
||||
card.imageUrl = data.imageUrl || card.imageUrl || '';
|
||||
card.typeLine = data.typeLine || card.typeLine || '';
|
||||
card.oracleText = data.oracleText || card.oracleText || '';
|
||||
card.manaCost = data.manaCost || card.manaCost || '';
|
||||
card.cmc = data.cmc || card.cmc || 0;
|
||||
if (data.power) card.power = data.power;
|
||||
if (data.toughness) card.toughness = data.toughness;
|
||||
|
||||
// Tag oracle roles
|
||||
const ot = (card.oracleText || '').toLowerCase();
|
||||
if (!card.isRamp) card.isRamp = /search your library for a.*land|add \{|adds? one mana/i.test(ot);
|
||||
if (!card.isRemoval) card.isRemoval = /destroy target|exile target|counter target spell/i.test(ot);
|
||||
if (!card.isBoardWipe) card.isBoardWipe = /destroy all|exile all|all creatures get -/i.test(ot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enrich a single card object on-demand (useful for cards drawn or played after initial load).
|
||||
* Returns a Promise that resolves when the card's imageUrl is set.
|
||||
|
||||
+1
-1
@@ -1434,7 +1434,7 @@ function _loadMyDecksTab(playerIdx) {
|
||||
decks.forEach(function(d) {
|
||||
var name = d.name || 'Untitled';
|
||||
var cmdr = d.commander || d.commander_name || '';
|
||||
var count = d.card_count || d.total_cards || 0;
|
||||
var count = d.totalCards || d.card_count || d.total_cards || 0;
|
||||
html += '<button class="deck-precon-item" onclick="selectUserDeck(' + playerIdx + ',' + d.deck_id + ',\'' + name.replace(/'/g, "\\'") + '\')">' +
|
||||
'<span class="deck-precon-name">' + name.replace(/</g, '<') + '</span>' +
|
||||
'<span class="deck-precon-cmdr">' + (cmdr ? cmdr.replace(/</g, '<') + ' \u2014 ' : '') + count + ' cards</span>' +
|
||||
|
||||
Reference in new issue
Block a user