HWHT ToE Module

ToE Counter Picker & AutoToE for HWH Tweaker

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.org/scripts/569616/1774147/HWHT%20ToE%20Module.js

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            HWHT ToE Module
// @namespace       http://tampermonkey.net/
// @version         1.0.0
// @description     ToE Counter Picker & AutoToE for HWH Tweaker
// @author          AI Assistant
// @license         MIT
// @match           https://www.hero-wars.com/*
// @match           https://apps-1701433570146040.apps.fbsbx.com/*
// @run-at          document-idle
// @grant           unsafeWindow
// ==/UserScript==

// debugLog stub - uses Tweaker's version when available, falls back to console
function debugLog(...args) {
    if (window._tweakerDebugLog) return window._tweakerDebugLog(...args);
    if (localStorage.getItem('hwh_debug_mode') === 'true') console.log('[ToE]', ...args);
}

// Wait for game dependencies
(function waitForDeps() {
    const check = () => {
        return typeof cheats !== 'undefined' && cheats.translate &&
               typeof Caller !== 'undefined' && Caller.send &&
               typeof getToeCounterData === 'function';
    };
    if (check()) { initToEModule(); return; }
    let attempts = 0;
    const timer = setInterval(() => {
        attempts++;
        if (check()) { clearInterval(timer); initToEModule(); }
        else if (attempts > 60) { clearInterval(timer); console.warn('[ToE Module] Dependencies not found after 120s'); }
    }, 2000);
})();

function initToEModule() {


//
// ToE Counter Picker v2 - Smart team selection with auto-retry
//

const ToeCounterPicker = (() => {
    let counterDB = {};
    let titanNameToId = {};
    let titanIdToName = {};
    let initialized = false;
    let ownedTitanIds = [];

    // Retry tracking
    let triedCounters = {};      // { rivalId: Set of tried keys }
    let currentRivalId = null;   // Who we're currently fighting
    let currentCounter = null;   // What counter we used
    let retryInProgress = false; // Prevent double-retry

    // Build titan name lookups from game library
    const buildTitanMappings = () => {
        titanNameToId = {};
        titanIdToName = {};
        if (typeof cheats === 'undefined' || !cheats.translate) return false;

        for (let id = 4000; id < 4050; id++) {
            try {
                const name = cheats.translate('LIB_HERO_NAME_' + id);
                if (name && !name.startsWith('LIB_HERO_NAME_')) {
                    titanNameToId[name.toLowerCase()] = id;
                    titanIdToName[id] = name;
                }
            } catch (e) {}
        }
        debugLog(`[ToE] Built mappings for ${Object.keys(titanIdToName).length} titans`);
        return true;
    };

    // Load counter database
    const loadCounterData = () => {
        const TOE_COUNTER_DATA = getToeCounterData();
        if (!TOE_COUNTER_DATA) return false;
        buildTitanMappings();
        counterDB = {};

        for (const [winRate, attackerStr, defenderStr] of TOE_COUNTER_DATA) {
            const attackerNames = attackerStr.split(',');
            const defenderNames = defenderStr.split(',');
            const attackerIds = attackerNames.map(n => titanNameToId[n.toLowerCase()]).filter(Boolean);
            const defenderIds = defenderNames.map(n => titanNameToId[n.toLowerCase()]).filter(Boolean);

            if (attackerIds.length !== 5 || defenderIds.length !== 5) continue;

            const defKey = defenderIds.slice().sort((a,b) => a-b).join('_');
            if (!counterDB[defKey]) counterDB[defKey] = [];

            const attackKey = attackerIds.slice().sort((a,b) => a-b).join('_');
            if (!counterDB[defKey].some(c => c.key === attackKey)) {
                counterDB[defKey].push({ attackerNames, attackerIds, winRate, key: attackKey });
            }
        }

        for (const defKey in counterDB) {
            counterDB[defKey].sort((a, b) => b.winRate - a.winRate);
        }

        initialized = true;
        console.log(`[ToE] Loaded ${Object.keys(counterDB).length} defender teams`);
        return true;
    };

    // Get owned titan IDs from multiple sources
    const getOwnedTitanIds = () => {
        if (ownedTitanIds.length > 0) return ownedTitanIds;
        if (window._myTitans?.length > 0) { ownedTitanIds = window._myTitans; return ownedTitanIds; }
        if (window.gameLoadData?.titans) {
            const ids = Object.keys(window.gameLoadData.titans).map(id => parseInt(id));
            if (ids.length > 0) { ownedTitanIds = ids; return ids; }
        }
        return [];
    };

    const loadOwnedTitans = async () => {
        try {
            const titans = await Caller.send('titanGetAll');
            ownedTitanIds = Object.keys(titans).map(id => parseInt(id));
            window._myTitans = ownedTitanIds;
            window._myTitansFull = Object.values(titans);
            debugLog(`[ToE] Loaded ${ownedTitanIds.length} owned titans`);
            if (Object.keys(counterDB).length < 200) loadCounterData();
        } catch (e) {}
    };

    // Element fallback
    const ELEMENT_MAP = { 0: 'water', 1: 'fire', 2: 'earth', 3: 'dark', 4: 'light' };
    const ELEMENT_ADVANTAGE = { water: 'fire', fire: 'earth', earth: 'water', dark: 'light', light: 'dark' };
    const getTitanElement = (id) => ELEMENT_MAP[Math.floor((id % 100) / 10)] || 'neutral';

    const getElementFallbackTeam = (enemyTitanIds) => {
        let titans = window._myTitansFull?.length > 0 ? [...window._myTitansFull] :
        window.gameLoadData?.titans ? Object.values(window.gameLoadData.titans) : null;
        if (!titans || titans.length < 5) return null;

        const enemyElements = {};
        for (const id of enemyTitanIds) {
            const elem = getTitanElement(id);
            enemyElements[elem] = (enemyElements[elem] || 0) + 1;
        }
        const dominantEnemy = Object.entries(enemyElements).sort((a, b) => b[1] - a[1])[0]?.[0];
        const counterElement = ELEMENT_ADVANTAGE[dominantEnemy];

        titans.sort((a, b) => {
            const elemA = getTitanElement(a.id), elemB = getTitanElement(b.id);
            const scoreA = elemA === counterElement ? 2 : (elemA === 'dark' || elemA === 'light' ? 1 : 0);
            const scoreB = elemB === counterElement ? 2 : (elemB === 'dark' || elemB === 'light' ? 1 : 0);
            if (scoreA !== scoreB) return scoreB - scoreA;
            return (b.power || 0) - (a.power || 0);
        });

        const team = titans.slice(0, 5).map(t => t.id);
        const names = team.map(id => titanIdToName[id] || `#${id}`);
        return { team, names, winRate: 0, matchType: `element (vs ${dominantEnemy})`, key: 'element_' + dominantEnemy };
    };

    // Find counter, skipping already-tried ones
    const findCounter = (enemyTitanIds, rivalId = null) => {
        if (!initialized) loadCounterData();
        if (!enemyTitanIds || enemyTitanIds.length !== 5) return null;

        const owned = new Set(getOwnedTitanIds());
        const tried = triedCounters[rivalId] || new Set();
        const enemySet = new Set(enemyTitanIds);
        const defKey = enemyTitanIds.slice().sort((a,b) => a-b).join('_');

        // 1. Exact matches
        const exactCounters = counterDB[defKey] || [];
        for (const counter of exactCounters) {
            if (tried.has(counter.key)) {
                debugLog(`[ToE] Skip tried: ${counter.attackerNames.join(', ')}`);
                continue;
            }
            if (counter.attackerIds.every(id => owned.has(id))) {
                return { team: counter.attackerIds, names: counter.attackerNames,
                        winRate: counter.winRate, matchType: 'exact', key: counter.key };
            }
        }

        // 2. Fuzzy matches (4/5)
        let bestFuzzy = null;
        for (const [key, counters] of Object.entries(counterDB)) {
            const dbTitans = key.split('_').map(Number);
            const matchCount = dbTitans.filter(id => enemySet.has(id)).length;
            if (matchCount >= 4) {
                for (const counter of counters) {
                    if (tried.has(counter.key)) continue;
                    if (counter.attackerIds.every(id => owned.has(id))) {
                        const adjustedRate = Math.round(counter.winRate * (matchCount / 5));
                        if (!bestFuzzy || adjustedRate > bestFuzzy.winRate) {
                            bestFuzzy = { team: counter.attackerIds, names: counter.attackerNames,
                                         winRate: adjustedRate, matchType: `fuzzy (${matchCount}/5)`, key: counter.key };
                        }
                    }
                }
            }
        }
        if (bestFuzzy && !tried.has(bestFuzzy.key)) return bestFuzzy;

        // 3. Element fallback
        const elementKey = 'element_fallback';
        if (!tried.has(elementKey)) {
            const elem = getElementFallbackTeam(enemyTitanIds);
            if (elem) { elem.key = elementKey; return elem; }
        }

        return null;
    };

    // Get counter for rival object
    const getCounterForRival = (rival, rivalId) => {
        if (!rival?.titans) return null;
        let titanList = Array.isArray(rival.titans) ? rival.titans : Object.values(rival.titans);
        const enemyIds = titanList.map(t => parseInt(t.id || t));
        return findCounter(enemyIds, rivalId);
    };

    // Retry management
    const markTried = (rivalId, key) => {
        if (!triedCounters[rivalId]) triedCounters[rivalId] = new Set();
        triedCounters[rivalId].add(key);
        console.log(`[ToE] Marked tried: ${key}`);
    };
    const clearTried = () => { triedCounters = {}; currentRivalId = null; currentCounter = null; };
    const setCurrentBattle = (rivalId, counter) => { currentRivalId = rivalId; currentCounter = counter; };
    const getCurrentBattle = () => ({ rivalId: currentRivalId, counter: currentCounter });

    // Auto-retry on loss
    const handleBattleEnd = async (win, cachedRivals) => {
        if (retryInProgress) return;

        const { rivalId, counter } = getCurrentBattle();
        if (!rivalId || !counter) return;

        if (win) {
            console.log(`[ToE] ✓ Won with ${counter.names.join(', ')}`);
            return;
        }

        // Lost - mark and retry
        console.log(`[ToE] ✗ Lost with ${counter.names.join(', ')}`);
        markTried(rivalId, counter.key);

        const rival = cachedRivals?.[rivalId];
        if (!rival) return;

        const nextCounter = getCounterForRival(rival, rivalId);
        if (!nextCounter) {
            console.log('[ToE] No more counters to try');
            return;
        }

        console.log(`[ToE] ↻ Retrying with ${nextCounter.names.join(', ')} (${nextCounter.winRate}% ${nextCounter.matchType})`);
        retryInProgress = true;

        try {
            await Caller.send('titanArenaStartBattle', { visitorId: parseInt(rivalId), titans: nextCounter.team });
            setCurrentBattle(rivalId, nextCounter);
        } catch (e) {
            console.warn('[ToE] Retry failed:', e);
        }
        retryInProgress = false;
    };

    const getTitanName = (id) => { if (!initialized) buildTitanMappings(); return titanIdToName[id] || `#${id}`; };
    const getTitanId = (name) => { if (!initialized) buildTitanMappings(); return titanNameToId[name.toLowerCase()] || null; };

    return {
        loadCounterData, loadOwnedTitans, findCounter, getCounterForRival, getElementFallbackTeam,
        getTitanName, getTitanId, getOwnedTitanIds, markTried, clearTried,
        setCurrentBattle, getCurrentBattle, handleBattleEnd,
        get initialized() { return initialized; },
        get counterDB() { return counterDB; },
        get retryInProgress() { return retryInProgress; }
    };
})();

// Initialize when ready
const initToeCounter = () => {
    try {
        const test = cheats.translate('LIB_HERO_NAME_4001');
        if (test && !test.startsWith('LIB_')) { ToeCounterPicker.loadCounterData(); return true; }
    } catch (e) {}
    return false;
};
if (!initToeCounter()) {
    const initInterval = setInterval(() => { if (initToeCounter()) clearInterval(initInterval); }, 2000);
}
unsafeWindow.ToeCounterPicker = window.ToeCounterPicker = ToeCounterPicker;

//
// AutoToE Configuration & UI
//

const AutoToEConfig = {
    _defaults: {
        strategies: ['power','exact', 'meta', 'element'],
        seedRetries: 10,
        maxRetries: 10,
        enabled: { exact: true, meta: true, element: true, power: true },
        customTeam: []  // User's selected fallback team (5 titan IDs)
    },

    // Load from localStorage
    load() {
        try {
            const saved = localStorage.getItem('AutoToEConfig');
            if (saved) {
                const parsed = JSON.parse(saved);
                Object.assign(this, this._defaults, parsed);
            } else {
                Object.assign(this, this._defaults);
            }
        } catch (e) {
            Object.assign(this, this._defaults);
        }
        return this;
    },

    // Save to localStorage
    save() {
        const toSave = {
            strategies: this.strategies,
            seedRetries: this.seedRetries,
            maxRetries: this.maxRetries,
            enabled: this.enabled,
            customTeam: this.customTeam || []
        };
        localStorage.setItem('AutoToEConfig', JSON.stringify(toSave));
        console.log('[AutoToE] Config saved');
    },

    // Reset to defaults
    reset() {
        Object.assign(this, this._defaults);
        this.save();
    }
}.load();

unsafeWindow.AutoToEConfig = window.AutoToEConfig = AutoToEConfig;





//
// Custom Auto ToE with smart counter-picking and retry on loss
//

const AutoToE = {
    running: false,

    get maxRetries() { return AutoToEConfig.maxRetries || 20; },
    get seedRetries() { return AutoToEConfig.seedRetries || 10; },

    async run() {
        if (this.running) { console.log('[AutoToE] Already running'); return null; }
        this.running = true;
        console.log('[AutoToE] Starting...');

        const results = {
            wins: 0,
            losses: 0,
            totalAttempts: 0,
            scoreGained: 0,
            tiersCompleted: 0,
            rivals: []
        };

        try {
            // Get team setup
            const teamData = await Caller.send('teamGetAll');
            const titanTeam = teamData?.titan_arena || [];
            if (titanTeam.length === 0) {
                console.warn('[AutoToE] No titan_arena team set');
            }

            // Load counter data if needed
            if (ToeCounterPicker.getOwnedTitanIds().length === 0) {
                await ToeCounterPicker.loadOwnedTitans();
            }
            if (Object.keys(ToeCounterPicker.counterDB).length < 200) {
                ToeCounterPicker.loadCounterData();
            }

            let startScore = 0;
            let keepGoing = true;

            while (keepGoing && this.running) {
                const status = await Caller.send('titanArenaGetStatus');

                if (!status) {
                    console.log('[AutoToE] Could not get status');
                    break;
                }

                console.log(`[AutoToE] Status: ${status.status}, Tier: ${status.tier}, canRaid: ${status.canRaid}`);

                if (startScore === 0) startScore = status.dailyScore || 0;

                // Check status
                if (status.status === 'disabled') {
                    console.log('[AutoToE] ToE is disabled');
                    break;
                }

                if (status.status === 'peace_time') {
                    console.log('[AutoToE] Peace time - ToE not active');
                    break;
                }

                // Completed tier - advance to next
                if (status.status === 'completed_tier') {
                    console.log(`[AutoToE] ═══ Completing Tier ${status.tier} ═══`);
                    await Caller.send({ name: 'titanArenaCompleteTier', args: {} });
                    results.tiersCompleted++;
                    await this.delay(500);
                    continue; // Loop back to get new status
                }

                // Can raid - use quick raid
                if (status.canRaid) {
                    console.log(`[AutoToE] ═══ Raiding Tier ${status.tier} ═══`);
                    await this.doRaid(titanTeam, results);
                    results.tiersCompleted++;
                    await this.delay(500);
                    continue; // Loop back to check next tier
                }

                // Normal battle - fight unbeaten rivals
                if (!status.rivals || Object.keys(status.rivals).length === 0) {
                    console.log('[AutoToE] No rivals available');
                    break;
                }

                const rivals = Object.entries(status.rivals).filter(([id, rival]) => {
                    return rival.attackScore < 250;
                });

                if (rivals.length === 0) {
                    console.log('[AutoToE] All rivals beaten on tier ' + status.tier);
                    // Check once more for completed_tier status
                    const recheck = await Caller.send('titanArenaGetStatus');
                    if (recheck?.status === 'completed_tier') {
                        console.log(`[AutoToE] ═══ Completing Tier ${recheck.tier} ═══`);
                        await Caller.send({ name: 'titanArenaCompleteTier', args: {} });
                        results.tiersCompleted++;
                        await this.delay(500);
                        continue;
                    }
                    // If still not completed_tier, we're done with this tier
                    console.log('[AutoToE] Tier not completable (not enough score or canRaid=false)');
                    break;
                }

                console.log(`[AutoToE] ═══ Tier ${status.tier}: ${rivals.length} rivals remaining ═══`);

                for (const [rivalId, rival] of rivals) {
                    if (!this.running) break;

                    const result = await this.fightRival(rivalId, rival);
                    results.totalAttempts += result.attempts;
                    results.rivals.push({
                        id: rivalId,
                        name: rival.userData?.name || rivalId,
                        won: result.won,
                        attempts: result.attempts
                    });

                    if (result.won) results.wins++;
                    else results.losses++;

                    await this.delay(300);
                }

                // After fighting all rivals, loop back to check status
                await this.delay(500);
            }

            // Get final score
            const finalStatus = await Caller.send('titanArenaGetStatus');
            results.scoreGained = (finalStatus?.dailyScore || 0) - startScore;

            // Collect daily rewards
            try {
                const rewards = await Caller.send({ name: 'titanArenaFarmDailyReward', args: {} });
                if (rewards && Object.keys(rewards).length > 0) {
                    console.log(`[AutoToE] 🎁 Collected daily rewards:`, Object.keys(rewards).length, 'tiers');
                }
            } catch (e) {
                // May fail if already collected or not enough score
                console.log('[AutoToE] No daily rewards to collect');
            }

            console.log(`[AutoToE] Done! Tiers: ${results.tiersCompleted}, Wins: ${results.wins}, Losses: ${results.losses}, Score: +${results.scoreGained}`);

        } catch (e) {
            console.error('[AutoToE] Error:', e);
        }

        this.running = false;
        return results;
    },

    // Quick raid (when canRaid is true)
    async doRaid(titanTeam, results) {
        try {
            const raidData = await Caller.send({
                name: 'titanArenaStartRaid',
                args: { titans: titanTeam }
            });

            if (!raidData?.rivals) {
                console.log('[AutoToE] Raid returned no data');
                return;
            }

            const { attackers, rivals } = raidData;
            const endResults = {};

            // Calculate all battles
            for (const [rivalId, rival] of Object.entries(rivals)) {
                const battleData = {
                    attackers: attackers,
                    defenders: [rival.team],
                    seed: rival.seed,
                    typeId: rivalId
                };

                const battleResult = await new Promise(resolve => {
                    BattleCalc(battleData, "get_titanClanPvp", resolve);
                });

                endResults[rivalId] = {
                    progress: battleResult.progress,
                    result: battleResult.result
                };

                if (battleResult.result?.win) results.wins++;
                else results.losses++;
            }

            // Submit raid results
            await Caller.send({
                name: 'titanArenaEndRaid',
                args: { results: endResults }
            });

            console.log(`[AutoToE] Raid complete: ${Object.keys(rivals).length} rivals`);

        } catch (e) {
            console.error('[AutoToE] Raid error:', e);
        }
    },


    // ... rest of AutoToE methods (fightRival, findUntriedCounter, tryStrategy, doBattle, delay, stop)

    async fightRival(rivalId, rival) {
        const titanList = Array.isArray(rival.titans) ? rival.titans : Object.values(rival.titans);
        const enemyIds = titanList.map(t => parseInt(t.id));
        const enemyNames = enemyIds.map(id => ToeCounterPicker.getTitanName(id));

        console.log(`[AutoToE] ═══ Rival ${rivalId}: ${enemyNames.join(', ')} ═══`);

        const triedKeys = new Set();
        let attempts = 0;

        while (attempts < this.maxRetries) {
            attempts++;

            // Find a counter we haven't tried
            const counter = this.findUntriedCounter(enemyIds, triedKeys);

            if (!counter) {
                console.log(`[AutoToE] No more counters to try`);
                return { won: false, attempts };
            }

            console.log(`[AutoToE] Attempt ${attempts}: ${counter.names.join(', ')} (${counter.winRate}% ${counter.matchType})`);
            triedKeys.add(counter.key);

            // Start battle
            const battleResult = await this.doBattle(rivalId, counter.team);

            if (battleResult.won) {
                console.log(`[AutoToE] ✓ Won on attempt ${attempts}`);
                return { won: true, attempts };
            }

            console.log(`[AutoToE] ✗ Lost, trying next counter...`);
            await this.delay(300);
        }

        console.log(`[AutoToE] Failed after ${attempts} attempts`);
        return { won: false, attempts };
    },

    findUntriedCounter(enemyIds, triedKeys) {
        const owned = new Set(ToeCounterPicker.getOwnedTitanIds());
        const enemySet = new Set(enemyIds);
        const defKey = enemyIds.slice().sort((a,b) => a-b).join('_');

        for (const strategy of AutoToEConfig.strategies) {
            if (AutoToEConfig.enabled[strategy] === false) continue;

            const result = this.tryStrategy(strategy, { enemyIds, enemySet, defKey, owned, triedKeys });
            if (result) return result;
        }

        return null;
    },

    tryStrategy(strategy, ctx) {
        const { enemyIds, enemySet, defKey, owned, triedKeys } = ctx;

        switch (strategy) {
            case 'exact': {
                const exactCounters = ToeCounterPicker.counterDB[defKey] || [];
                for (const counter of exactCounters) {
                    if (triedKeys.has(counter.key)) continue;
                    if (counter.attackerIds.every(id => owned.has(id))) {
                        return { team: counter.attackerIds, names: counter.attackerNames,
                                winRate: counter.winRate, matchType: 'exact', key: counter.key };
                    }
                }
                break;
            }

            case 'meta': {
                if (typeof TOE_META_TEAMS === 'undefined') break;
                for (let i = 0; i < TOE_META_TEAMS.length; i++) {
                    const metaKey = 'meta_' + i;
                    if (triedKeys.has(metaKey)) continue;

                    const names = TOE_META_TEAMS[i];
                    const team = names.map(n => ToeCounterPicker.getTitanId(n)).filter(Boolean);

                    if (team.length === 5 && team.every(id => owned.has(id))) {
                        return { team, names, winRate: 0, matchType: `meta #${i+1}`, key: metaKey };
                    }
                }
                break;
            }

            case 'element': {
                const elementKey = 'element_fallback';
                if (triedKeys.has(elementKey)) break;
                const elem = ToeCounterPicker.getElementFallbackTeam(enemyIds);
                if (elem) { elem.key = elementKey; return elem; }
                break;
            }

            case 'power': {
                const powerKey = 'power_fallback';
                if (triedKeys.has(powerKey)) break;

                let team, names;
                if (AutoToEConfig.customTeam?.length === 5) {
                    team = AutoToEConfig.customTeam;
                    names = team.map(id => ToeCounterPicker.getTitanName(id));
                } else if (window._myTitansFull?.length >= 5) {
                    const sorted = [...window._myTitansFull].sort((a,b) => (b.power||0) - (a.power||0));
                    team = sorted.slice(0,5).map(t => t.id);
                    names = team.map(id => ToeCounterPicker.getTitanName(id));
                } else {
                    break;
                }

                return { team, names, winRate: 0, matchType: 'custom', key: powerKey };
            }
        }

        return null;
    },

    async doBattle(rivalId, titanTeam) {
        try {
            // Start battle
            const startResult = await Caller.send({
                name: 'titanArenaStartBattle',
                args: {
                    rivalId: parseInt(rivalId),
                    titans: titanTeam
                }
            });

            if (!startResult?.battle) {
                console.error('[AutoToE] No battle data returned');
                return { won: false, error: 'No battle data' };
            }

            // Calculate battle result using game's BattleCalc
            let battleResult = await new Promise(resolve => {
                BattleCalc(startResult.battle, "get_titanClanPvp", e => resolve(e));
            });

            // Try different seeds if first calc loses
            if (!battleResult.result?.win) {
                for (let i = 0; i < AutoToEConfig.seedRetries; i++) {
                    const battle = structuredClone(startResult.battle);
                    battle.seed = Math.floor(Date.now() / 1000) + Math.floor(Math.random() * 1000);
                    const retry = await new Promise(resolve => {
                        BattleCalc(battle, "get_titanClanPvp", e => resolve(e));
                    });
                    if (retry.result?.win) {
                        console.log(`[AutoToE] Found winning seed on try ${i+1}`);
                        battleResult = retry;
                        break;
                    }
                }
            }

            console.log('[AutoToE] Battle calc:', battleResult.result?.win ? 'WIN' : 'LOSE');

            // End battle with calculated result
            const endResult = await Caller.send({
                name: 'titanArenaEndBattle',
                args: {
                    rivalId: parseInt(rivalId),
                    progress: battleResult.progress,
                    result: battleResult.result
                }
            });

            const won = battleResult.result?.win === true;
            return { won, result: endResult, battleResult };

        } catch (e) {
            console.error('[AutoToE] Battle error:', e);
            return { won: false, error: e };
        }
    },

    delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    },

    stop() {
        this.running = false;
        console.log('[AutoToE] Stopped');
    }
};

// Expose globally
unsafeWindow.AutoToE = window.AutoToE = AutoToE;
console.log('[AutoToE] Ready - run with: AutoToE.run()');



//
// AutoToE UI - Summary & Config Popup
//

const AutoToEUI = {
    lastResults: null,

    // Strategy display names
    strategyNames: {
        exact: '📚 Counter Library',
        meta: '⭐ Meta Teams',
        element: '🔥 Element Counter',
        power: '💪 Selected Team'
    },

    // Show config/summary popup
    showPopup(results = null) {
        this.lastResults = results || this.lastResults;

        // Remove existing popup
        document.querySelector('.autotoe-popup')?.remove();

        const popup = document.createElement('div');
        popup.className = 'autotoe-popup';
        popup.innerHTML = `
       <style>
                .autotoe-popup {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: linear-gradient(180deg, #3d2817 0%, #2a1810 100%);
                    border: 3px solid #8b6914;
                    border-radius: 10px;
                    padding: 14px;
                    z-index: 999999;
                    min-width: 360px;
                    max-width: 440px;
                    color: #e8d5b0;
                    font-family: "Twemoji Country Flags", Arial, sans-serif;
                    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
                    font-size: 12px;
                }
                .autotoe-popup h2 {
                    margin: 0 0 10px 0;
                    color: #ffd700;
                    font-size: 16px;
                    display: flex;
                    align-items: center;
                    gap: 8px;
                }
                .autotoe-popup .close-btn {
                    position: absolute;
                    top: 6px;
                    right: 10px;
                    background: none;
                    border: none;
                    color: #8b7355;
                    font-size: 20px;
                    cursor: pointer;
                }
                .autotoe-popup .close-btn:hover { color: #ffd700; }
                .autotoe-popup .tabs {
                    display: flex;
                    gap: 4px;
                    margin-bottom: 10px;
                }
                .autotoe-popup .tab {
                    padding: 5px 12px;
                    background: rgba(139,105,20,0.3);
                    border: 1px solid #5a4a2a;
                    border-radius: 5px;
                    color: #c9a84c;
                    cursor: pointer;
                    font-size: 11px;
                    transition: all 0.15s;
                }
                .autotoe-popup .tab:hover { background: rgba(139,105,20,0.5); }
                .autotoe-popup .tab.active { background: #8b6914; color: #fff; border-color: #8b6914; }
                .autotoe-popup .tab-content { display: none; }
                .autotoe-popup .tab-content.active { display: block; }
                .autotoe-popup .config-section {
                    background: rgba(0,0,0,0.2);
                    border: 1px solid #5a4a2a;
                    border-radius: 6px;
                    padding: 8px 10px;
                    margin-bottom: 8px;
                }
                .autotoe-popup .config-section h3 {
                    margin: 0 0 6px 0;
                    font-size: 12px;
                    color: #ffd700;
                }
                .autotoe-popup .strategy-list {
                    list-style: none;
                    padding: 0;
                    margin: 0;
                }
                .autotoe-popup .strategy-item {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    padding: 5px 6px;
                    background: rgba(0,0,0,0.15);
                    border: 1px solid transparent;
                    border-radius: 4px;
                    margin-bottom: 3px;
                    cursor: grab;
                    font-size: 11px;
                }
                .autotoe-popup .strategy-item:hover { border-color: #5a4a2a; }
                .autotoe-popup .strategy-item:active { cursor: grabbing; }
                .autotoe-popup .strategy-item.dragging { opacity: 0.5; }
                .autotoe-popup .strategy-item .drag-handle { color: #5a4a2a; font-size: 14px; }
                .autotoe-popup .strategy-item label { flex: 1; cursor: pointer; color: #e8d5b0; }
                .autotoe-popup .strategy-item input[type="checkbox"] {
                    width: 15px;
                    height: 15px;
                    cursor: pointer;
                    accent-color: #4ae29a;
                }
                .autotoe-popup .input-row {
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    margin-bottom: 6px;
                }
                .autotoe-popup .input-row label { color: #c9a84c; font-size: 11px; }
                .autotoe-popup .input-row input[type="number"] {
                    width: 50px;
                    padding: 3px 6px;
                    border: 1px solid #5a4a2a;
                    border-radius: 4px;
                    background: rgba(0,0,0,0.3);
                    color: #ffd700;
                    font-size: 12px;
                    text-align: center;
                }
                .autotoe-popup .btn-row {
                    display: flex;
                    gap: 6px;
                    margin-top: 10px;
                }
                .autotoe-popup .btn {
                    flex: 1;
                    padding: 7px 12px;
                    border: none;
                    border-radius: 5px;
                    font-size: 12px;
                    cursor: pointer;
                    transition: all 0.15s;
                }
                .autotoe-popup .btn-primary {
                    background: #8b6914;
                    color: #fff;
                    border: 1px solid #a67c00;
                }
                .autotoe-popup .btn-primary:hover { background: #a67c00; }
                .autotoe-popup .btn-secondary {
                    background: rgba(0,0,0,0.3);
                    color: #c9a84c;
                    border: 1px solid #5a4a2a;
                }
                .autotoe-popup .btn-secondary:hover { background: rgba(139,105,20,0.3); }
                .autotoe-popup .btn-success {
                    background: linear-gradient(180deg, #4a8b3a 0%, #2d6620 100%);
                    color: #fff;
                    border: 1px solid #5a9e45;
                }
                .autotoe-popup .btn-success:hover { background: linear-gradient(180deg, #5a9e45 0%, #3a7a2a 100%); }
                .autotoe-popup .summary-grid {
                    display: grid;
                    grid-template-columns: 1fr 1fr 1fr 1fr;
                    gap: 6px;
                }
                .autotoe-popup .summary-card {
                    background: rgba(0,0,0,0.2);
                    border: 1px solid #5a4a2a;
                    border-radius: 6px;
                    padding: 8px;
                    text-align: center;
                }
                .autotoe-popup .summary-card .value {
                    font-size: 20px;
                    font-weight: bold;
                    color: #ffd700;
                }
                .autotoe-popup .summary-card .label {
                    font-size: 10px;
                    color: #8b7355;
                    margin-top: 2px;
                }
                .autotoe-popup .rival-list {
                    max-height: 160px;
                    overflow-y: auto;
                    margin-top: 8px;
                }
                .autotoe-popup .rival-item {
                    display: flex;
                    justify-content: space-between;
                    padding: 4px 8px;
                    background: rgba(0,0,0,0.15);
                    border-radius: 3px;
                    margin-bottom: 2px;
                    font-size: 11px;
                }
                .autotoe-popup .rival-item.win { border-left: 3px solid #4ae29a; }
                .autotoe-popup .rival-item.lose { border-left: 3px solid #c94040; }
            </style>

            <button class="close-btn">&times;</button>
            <h2>⚔️ AutoToE</h2>

            <div class="tabs">
                <button class="tab active" data-tab="config">⚙️ Config</button>
                <button class="tab" data-tab="summary">📊 Summary</button>
            </div>

            <div class="tab-content active" data-tab="config">
                <div class="config-section">
                    <h3>📋 Strategy Order (drag to reorder)</h3>
                    <ul class="strategy-list" id="autotoe-strategies">
                        ${this.renderStrategyList()}
                    </ul>
                </div>

                <div class="config-section">
                    <h3>⚡ Battle Settings</h3>
                    <div class="input-row">
                        <label>Max Attempts per Rival:</label>
                        <input type="number" id="autotoe-maxRetries" value="${AutoToEConfig.maxRetries}" min="1" max="50">
                    </div>
                    <div class="input-row">
                        <label>Seed Retries per Battle:</label>
                        <input type="number" id="autotoe-seedRetries" value="${AutoToEConfig.seedRetries}" min="0" max="50">
                    </div>
                </div>

<div class="config-section">
                    <h3>💪 Selected Team</h3>
                    <div style="display: flex; justify-content: space-between; align-items: center;">
                        <span style="color: #ccc; font-size: 12px;">
                            ${AutoToEConfig.customTeam?.length === 5
            ? AutoToEConfig.customTeam.map(id => ToeCounterPicker.getTitanName(id)).join(', ')
        : 'Not set (using top 5 by power)'}
                        </span>
                        <button class="btn btn-secondary" id="autotoe-select-team" style="flex: 0; padding: 6px 12px;">Select</button>
                    </div>
                </div>

                <div class="btn-row">
                    <button class="btn btn-secondary" id="autotoe-reset">Reset Defaults</button>
                    <button class="btn btn-primary" id="autotoe-save">💾 Save</button>
                </div>
            </div>

            <div class="tab-content" data-tab="summary">
                ${this.renderSummary()}
            </div>

            <div class="btn-row">
                <button class="btn btn-success" id="autotoe-run" style="font-size: 16px;">
                    ▶️ Start AutoToE Raid
                </button>
            </div>
        `;

        document.body.appendChild(popup);
        this.attachEvents(popup);
    },

    renderStrategyList() {
        const allStrategies = ['exact', 'meta', 'element', 'power'];
        const ordered = [...AutoToEConfig.strategies];

        // Add any missing strategies at the end
        for (const s of allStrategies) {
            if (!ordered.includes(s)) ordered.push(s);
        }

        return ordered.map(s => `
            <li class="strategy-item" data-strategy="${s}" draggable="true">
                <span class="drag-handle">☰</span>
                <input type="checkbox" id="strat-${s}" ${AutoToEConfig.enabled[s] !== false ? 'checked' : ''}>
                <label for="strat-${s}">${this.strategyNames[s] || s}</label>
            </li>
        `).join('');
    },

    renderSummary() {
        if (!this.lastResults) {
            return `
                <div style="text-align: center; color: #888; padding: 30px;">
                    No raid results yet.<br>Run AutoToE to see summary.
                </div>
            `;
        }

        const r = this.lastResults;
        return `
            <div class="summary-grid">
                <div class="summary-card">
                    <div class="value" style="color: #00d26a;">${r.wins}</div>
                    <div class="label">Wins</div>
                </div>
                <div class="summary-card">
                    <div class="value" style="color: #e94560;">${r.losses}</div>
                    <div class="label">Losses</div>
                </div>
                <div class="summary-card">
                    <div class="value">${r.totalAttempts || 0}</div>
                    <div class="label">Total Attempts</div>
                </div>
                <div class="summary-card">
                    <div class="value">${r.scoreGained || 0}</div>
                    <div class="label">Score Gained</div>
                </div>
            </div>
            <div class="rival-list">
                ${(r.rivals || []).map(rival => `
                    <div class="rival-item ${rival.won ? 'win' : 'lose'}">
                        <span>${rival.name || rival.id}</span>
                        <span>${rival.won ? '✓ Won' : '✗ Lost'} (${rival.attempts} tries)</span>
                    </div>
                `).join('')}
            </div>
        `;
    },

    attachEvents(popup) {
        // Close button
        popup.querySelector('.close-btn').onclick = () => popup.remove();

        // Tab switching
        popup.querySelectorAll('.tab').forEach(tab => {
            tab.onclick = () => {
                popup.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                popup.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                tab.classList.add('active');
                popup.querySelector(`.tab-content[data-tab="${tab.dataset.tab}"]`).classList.add('active');
            };
        });

        // Drag and drop for strategy reordering
        const strategyList = popup.querySelector('#autotoe-strategies');
        let draggedItem = null;

        strategyList.querySelectorAll('.strategy-item').forEach(item => {
            item.addEventListener('dragstart', (e) => {
                draggedItem = item;
                item.classList.add('dragging');
            });

            item.addEventListener('dragend', () => {
                item.classList.remove('dragging');
                draggedItem = null;
            });

            item.addEventListener('dragover', (e) => {
                e.preventDefault();
                if (draggedItem && draggedItem !== item) {
                    const rect = item.getBoundingClientRect();
                    const midY = rect.top + rect.height / 2;
                    if (e.clientY < midY) {
                        strategyList.insertBefore(draggedItem, item);
                    } else {
                        strategyList.insertBefore(draggedItem, item.nextSibling);
                    }
                }
            });
        });

        // Save button
        popup.querySelector('#autotoe-save').onclick = () => {
            // Get strategy order from DOM
            const strategies = [];
            const enabled = {};
            popup.querySelectorAll('.strategy-item').forEach(item => {
                const s = item.dataset.strategy;
                strategies.push(s);
                enabled[s] = item.querySelector('input[type="checkbox"]').checked;
            });

            AutoToEConfig.strategies = strategies;
            AutoToEConfig.enabled = enabled;
            AutoToEConfig.maxRetries = parseInt(popup.querySelector('#autotoe-maxRetries').value) || 10;
            AutoToEConfig.seedRetries = parseInt(popup.querySelector('#autotoe-seedRetries').value) || 10;
            AutoToEConfig.save();

            // Visual feedback
            const btn = popup.querySelector('#autotoe-save');
            btn.textContent = '✓ Saved!';
            setTimeout(() => btn.textContent = '💾 Save', 1500);
        };

        // Reset button
        popup.querySelector('#autotoe-reset').onclick = () => {
            AutoToEConfig.reset();
            this.showPopup(); // Refresh popup
        };

        // Select team button
        popup.querySelector('#autotoe-select-team').onclick = () => {
            this.showTeamSelector();
        };

        // Run button
        popup.querySelector('#autotoe-run').onclick = async () => {
            const btn = popup.querySelector('#autotoe-run');
            btn.disabled = true;
            btn.textContent = '⏳ Running...';

            try {
                const results = await AutoToE.run();
                this.lastResults = results;

                // Switch to summary tab
                popup.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                popup.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                popup.querySelector('.tab[data-tab="summary"]').classList.add('active');
                popup.querySelector('.tab-content[data-tab="summary"]').classList.add('active');
                popup.querySelector('.tab-content[data-tab="summary"]').innerHTML = this.renderSummary();
            } finally {
                btn.disabled = false;
                btn.textContent = '▶️ Start AutoToE Raid';
            }
        };
    },

    async showTeamSelector() {
        document.querySelector('.toe-team-popup')?.remove();

        // Load titan data if not available
        let owned = window._myTitansFull || Object.values(window.gameLoadData?.titans || {});
        if (!owned || owned.length < 5) {
            try {
                const titans = await Caller.send('titanGetAll');
                window._myTitans = Object.keys(titans).map(id => parseInt(id));
                window._myTitansFull = Object.values(titans);
                owned = window._myTitansFull;
                console.log('[AutoToE] Loaded', owned.length, 'titans');
            } catch (e) {
                console.error('[AutoToE] Failed to load titans:', e);
                return;
            }
        }

        if (!owned || owned.length < 5) {
            console.error('[AutoToE] No titan data available');
            return;
        }

        // Sort by power
        const titans = [...owned].sort((a, b) => (b.power || 0) - (a.power || 0));
        const currentTeam = AutoToEConfig.customTeam || [];

        const popup = document.createElement('div');
        popup.className = 'toe-team-popup';
        popup.innerHTML = `
         <style>
                .toe-team-popup {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: linear-gradient(180deg, #3d2817 0%, #2a1810 100%);
                    border: 3px solid #8b6914;
                    border-radius: 10px;
                    padding: 14px;
                    z-index: 1000000;
                    min-width: 380px;
                    max-width: 480px;
                    color: #e8d5b0;
                    font-family: "Twemoji Country Flags", Arial, sans-serif;
                    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
                    font-size: 12px;
                }
                .toe-team-popup h3 {
                    margin: 0 0 6px 0;
                    color: #ffd700;
                    font-size: 14px;
                }
                .toe-team-popup .close-btn {
                    position: absolute;
                    top: 6px;
                    right: 10px;
                    background: none;
                    border: none;
                    color: #8b7355;
                    font-size: 20px;
                    cursor: pointer;
                }
                .toe-team-popup .close-btn:hover { color: #ffd700; }
                .toe-team-popup .selected-team {
                    display: flex;
                    gap: 6px;
                    padding: 8px;
                    background: rgba(0,0,0,0.3);
                    border: 1px solid #5a4a2a;
                    border-radius: 6px;
                    margin-bottom: 10px;
                    min-height: 44px;
                    flex-wrap: wrap;
                    align-items: center;
                }
                .toe-team-popup .selected-titan {
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    padding: 3px 8px;
                    background: rgba(74,226,154,0.15);
                    border: 1px solid rgba(74,226,154,0.4);
                    border-radius: 4px;
                    font-size: 10px;
                    cursor: pointer;
                }
                .toe-team-popup .selected-titan:hover {
                    background: rgba(201,64,64,0.2);
                    border-color: #c94040;
                }
                .toe-team-popup .selected-titan .power {
                    font-size: 10px;
                    color: #8b7355;
                }
                .toe-team-popup .empty-slot {
                    width: 55px;
                    height: 36px;
                    border: 1px dashed #5a4a2a;
                    border-radius: 4px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    color: #5a4a2a;
                    font-size: 16px;
                }
                .toe-team-popup .titan-grid {
                    display: grid;
                    grid-template-columns: repeat(6, 1fr);
                    gap: 4px;
                    max-height: 240px;
                    overflow-y: auto;
                    padding: 4px;
                }
                .toe-team-popup .titan-card {
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    padding: 5px 3px;
                    background: rgba(0,0,0,0.2);
                    border: 1px solid transparent;
                    border-radius: 4px;
                    cursor: pointer;
                    transition: all 0.1s;
                    font-size: 10px;
                    text-align: center;
                }
                .toe-team-popup .titan-card:hover {
                    background: rgba(139,105,20,0.2);
                    border-color: #5a4a2a;
                }
                .toe-team-popup .titan-card.selected {
                    background: rgba(74,226,154,0.15);
                    border-color: rgba(74,226,154,0.5);
                }
                .toe-team-popup .titan-card.disabled {
                    opacity: 0.3;
                    cursor: not-allowed;
                }
                .toe-team-popup .titan-card .name {
                    font-weight: bold;
                    color: #e8d5b0;
                    margin-bottom: 1px;
                }
                .toe-team-popup .titan-card .power {
                    font-size: 10px;
                    color: #8b7355;
                }
                .toe-team-popup .titan-card .element {
                    font-size: 10px;
                    padding: 0px 3px;
                    border-radius: 2px;
                    margin-top: 1px;
                }
                .toe-team-popup .elem-fire { background: rgba(255,80,20,0.3); color: #ffa07a; }
                .toe-team-popup .elem-water { background: rgba(30,90,180,0.3); color: #87ceeb; }
                .toe-team-popup .elem-earth { background: rgba(45,100,30,0.3); color: #90ee90; }
                .toe-team-popup .elem-light { background: rgba(180,180,30,0.3); color: #ffff99; }
                .toe-team-popup .elem-dark { background: rgba(100,30,140,0.3); color: #dda0dd; }
                .toe-team-popup .btn-row {
                    display: flex;
                    gap: 6px;
                    margin-top: 10px;
                }
                .toe-team-popup .btn {
                    flex: 1;
                    padding: 7px 12px;
                    border: none;
                    border-radius: 5px;
                    font-size: 12px;
                    cursor: pointer;
                }
                .toe-team-popup .btn-primary {
                    background: #8b6914;
                    color: #fff;
                    border: 1px solid #a67c00;
                }
                .toe-team-popup .btn-primary:hover { background: #a67c00; }
                .toe-team-popup .btn-secondary {
                    background: rgba(0,0,0,0.3);
                    color: #c9a84c;
                    border: 1px solid #5a4a2a;
                }
                .toe-team-popup .hint {
                    font-size: 10px;
                    color: #8b7355;
                    margin-bottom: 8px;
                }
            </style>

            <button class="close-btn">&times;</button>
            <h3>💪 Selected Team</h3>
            <p class="hint">Click titans to add/remove. This team is used when counter library, meta teams, and element counter all fail.</p>

            <div class="selected-team" id="toe-selected-team">
                ${this.renderSelectedTeam(currentTeam)}
            </div>

            <div class="titan-grid" id="toe-titan-grid">
                ${titans.map(t => this.renderTitanCard(t, currentTeam.includes(t.id))).join('')}
            </div>

            <div class="btn-row">
                <button class="btn btn-secondary" id="toe-team-clear">Clear</button>
                <button class="btn btn-primary" id="toe-team-save">💾 Save Team</button>
            </div>
        `;

        document.body.appendChild(popup);

        let selected = [...currentTeam];

        const updateDisplay = () => {
            popup.querySelector('#toe-selected-team').innerHTML = this.renderSelectedTeam(selected);
            popup.querySelectorAll('.titan-card').forEach(card => {
                const id = parseInt(card.dataset.id);
                card.classList.toggle('selected', selected.includes(id));
                card.classList.toggle('disabled', selected.length >= 5 && !selected.includes(id));
            });

            // Click to remove from selected
            popup.querySelectorAll('.selected-titan').forEach(el => {
                el.onclick = () => {
                    const id = parseInt(el.dataset.id);
                    selected = selected.filter(x => x !== id);
                    updateDisplay();
                };
            });
        };

        // Close
        popup.querySelector('.close-btn').onclick = () => popup.remove();

        // Titan selection
        popup.querySelectorAll('.titan-card').forEach(card => {
            card.onclick = () => {
                const id = parseInt(card.dataset.id);
                if (selected.includes(id)) {
                    selected = selected.filter(x => x !== id);
                } else if (selected.length < 5) {
                    selected.push(id);
                }
                updateDisplay();
            };
        });

        // Clear
        popup.querySelector('#toe-team-clear').onclick = () => {
            selected = [];
            updateDisplay();
        };

        // Save
        popup.querySelector('#toe-team-save').onclick = () => {
            if (selected.length !== 5) {
                alert('Please select exactly 5 titans');
                return;
            }
            AutoToEConfig.customTeam = selected;
            AutoToEConfig.save();
            popup.remove();
            console.log('[AutoToE] Custom team saved:', selected.map(id => ToeCounterPicker.getTitanName(id)));
        };

        updateDisplay();
    },

    renderSelectedTeam(teamIds) {
        const slots = [];
        for (let i = 0; i < 5; i++) {
            if (teamIds[i]) {
                const id = teamIds[i];
                const titan = window._myTitansFull?.find(t => t.id === id) ||
                      Object.values(window.gameLoadData?.titans || {}).find(t => t.id === id);
                const name = ToeCounterPicker.getTitanName(id);
                const power = titan?.power || '?';
                slots.push(`
                    <div class="selected-titan" data-id="${id}">
                        <span class="name">${name}</span>
                        <span class="power">${power}</span>
                    </div>
                `);
            } else {
                slots.push('<div class="empty-slot">+</div>');
            }
        }
        return slots.join('');
    },

    renderTitanCard(titan, isSelected) {
        const name = ToeCounterPicker.getTitanName(titan.id);
        const element = this.getTitanElement(titan.id);
        return `
            <div class="titan-card ${isSelected ? 'selected' : ''}" data-id="${titan.id}">
                <span class="name">${name}</span>
                <span class="power">${titan.power || '?'}</span>
                <span class="element elem-${element}">${element}</span>
            </div>
        `;
    },

    getTitanElement(id) {
        const map = { 0: 'water', 1: 'fire', 2: 'earth', 3: 'dark', 4: 'light' };
        return map[Math.floor((id % 100) / 10)] || 'neutral';
    }
};

unsafeWindow.AutoToEUI = window.AutoToEUI = AutoToEUI;

}