MediaWiki

MediaWiki:TeamBuilder.js

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献2025年10月18日 (六) 19:10的版本

注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
(function() {
    'use strict';
    mw.loader.load(mw.util.getUrl('MediaWiki:TeamBuilder.css', { action: 'raw', ctype: 'text/css' }), 'text/css');
    
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initTeamBuilder);
    } else {
        initTeamBuilder();
    }
    
    function initTeamBuilder() {
        if (!document.getElementById('team-builder')) return;
        
        const state = {
            selectedCharacter: null,
            selectedPartner: null,
            selectedWeapon: null,
            selectedArmor: null,
            selectedRing: null,
            deckCards: [],
            availableCards: [],
            currentEquipmentType: null,
            equipmentCache: {} // 添加装备缓存
        };
        
        // === 模态框通用函数 ===
        function showModal(modalId) {
            const modal = document.getElementById(modalId);
            if (modal) {
                modal.style.display = 'flex';
                modal.style.position = 'fixed';
                modal.style.top = '0';
                modal.style.left = '0';
                modal.style.width = '100vw';
                modal.style.height = '100vh';
                modal.style.backgroundColor = 'rgba(0,0,0,0.8)';
                modal.style.alignItems = 'center';
                modal.style.justifyContent = 'center';
                modal.style.zIndex = '10000';
                document.body.style.overflow = 'hidden';
            }
        }
        
        function hideModal(modalId) {
            const modal = document.getElementById(modalId);
            if (modal) {
                modal.style.display = 'none';
                document.body.style.overflow = 'auto';
            }
        }
        
        // === 事件绑定 ===
        const characterSlot = document.getElementById('character-slot');
        if (characterSlot) {
            characterSlot.addEventListener('click', function() {
                showModal('character-modal');
            });
        }
        
        const partnerSlot = document.getElementById('partner-slot');
        if (partnerSlot) {
            partnerSlot.addEventListener('click', function() {
                showModal('partner-modal');
            });
        }
        
        const deckArea = document.getElementById('deck-area');
        if (deckArea) {
            deckArea.addEventListener('click', function(e) {
                if (e.target === this || e.target.closest('.deck-area') === this) {
                    if (state.selectedCharacter) {
                        showModal('card-modal');
                    } else {
                        alert('请先选择战斗员');
                    }
                }
            });
        }
        
        document.querySelectorAll('.equip-slot').forEach(slot => {
            slot.addEventListener('click', function() {
                const type = this.getAttribute('data-type');
                state.currentEquipmentType = type;
                loadEquipmentList(type);
                document.getElementById('equipment-modal-title').textContent = '选择' + type;
                showModal('equipment-modal');
            });
        });
        
        document.querySelectorAll('.tb-modal-close').forEach(btn => {
            btn.addEventListener('click', function() {
                this.closest('.tb-modal').style.display = 'none';
                document.body.style.overflow = 'auto';
            });
        });
        
        document.querySelectorAll('.tb-modal').forEach(modal => {
            modal.addEventListener('click', function(e) {
                if (e.target === this) {
                    this.style.display = 'none';
                    document.body.style.overflow = 'auto';
                }
            });
        });
        
        // === 战斗员列表点击 ===
        const characterList = document.getElementById('character-list');
        if (characterList) {
            characterList.addEventListener('click', function(e) {
                const card = e.target.closest('[data-character-name]');
                if (card) {
                    const name = card.getAttribute('data-character-name');
                    selectCharacter(name);
                    hideModal('character-modal');
                }
            });
        }
        
        // === 伙伴列表点击 ===
        const partnerList = document.getElementById('partner-list');
        if (partnerList) {
            partnerList.addEventListener('click', function(e) {
                const card = e.target.closest('[data-partner-name]');
                if (card) {
                    const name = card.getAttribute('data-partner-name');
                    const id = card.getAttribute('data-partner-id');
                    selectPartner(name, id);
                    hideModal('partner-modal');
                }
            });
        }
        
        // === 选择战斗员 ===
        function selectCharacter(name) {
            state.selectedCharacter = name;
            const slot = document.getElementById('character-slot');
            
            const imgPath = mw.config.get('wgScriptPath') + '/index.php?title=Special:Redirect/file/战斗员图鉴_' + encodeURIComponent(name) + '.png';
            
            slot.innerHTML = `
                <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
                    <img src="${imgPath}" style="width: 100%; height: 100%; object-fit: cover;" 
                         onerror="this.src='${mw.config.get('wgScriptPath')}/resources/assets/file-type-icons/fileicon-image.png';" />
                </div>
            `;
            
            // 清空卡组
            state.deckCards = [];
            state.availableCards = [];
            updateDeckDisplay();
            
            // 加载并自动显示卡牌
            loadCharacterCards(name);
        }
        
        // === 选择伙伴(修复文件名) ===
        function selectPartner(name, id) {
            state.selectedPartner = { name, id };
            const slot = document.getElementById('partner-slot');
            
            // 修复:使用正确的文件名格式
            const imgPath = mw.config.get('wgScriptPath') + '/index.php?title=Special:Redirect/file/face_character_wide_' + encodeURIComponent(id) + '.png';
            
            slot.innerHTML = `
                <div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
                    <img src="${imgPath}" style="width: 100%; height: 100%; object-fit: cover;" 
                         onerror="this.src='${mw.config.get('wgScriptPath')}/resources/assets/file-type-icons/fileicon-image.png';" />
                </div>
            `;
        }
        
        // === 加载装备列表(添加缓存) ===
        function loadEquipmentList(type) {
            const listContainer = document.getElementById('equipment-list');
            
            // 检查缓存
            if (state.equipmentCache[type]) {
                listContainer.innerHTML = '';
                state.equipmentCache[type].forEach(item => {
                    listContainer.appendChild(item.cloneNode(true));
                });
                attachEquipmentClickHandlers();
                return;
            }
            
            listContainer.innerHTML = '<p style="color: white;">加载中...</p>';
            
            new mw.Api().post({
                action: 'parse',
                text: '{{#invoke:装备|generateCards}}',
                contentmodel: 'wikitext',
                prop: 'text',
                disablelimitreport: 1,
                disableeditsection: 1
            }).done(function(data) {
                if (data.parse && data.parse.text) {
                    const tempDiv = document.createElement('div');
                    tempDiv.innerHTML = data.parse.text['*'];
                    
                    const allEquips = tempDiv.querySelectorAll('.equipment-wrapper');
                    const filteredEquips = [];
                    listContainer.innerHTML = '';
                    
                    allEquips.forEach(function(equipWrapper) {
                        const equipType = equipWrapper.getAttribute('data-param3');
                        if (equipType === type) {
                            filteredEquips.push(equipWrapper.cloneNode(true));
                            listContainer.appendChild(equipWrapper.cloneNode(true));
                        }
                    });
                    
                    // 缓存结果
                    state.equipmentCache[type] = filteredEquips;
                    
                    if (listContainer.children.length === 0) {
                        listContainer.innerHTML = '<p style="color: white;">没有找到该类型装备</p>';
                    }
                    
                    attachEquipmentClickHandlers();
                }
            }).fail(function() {
                listContainer.innerHTML = '<p style="color: red;">加载失败</p>';
            });
        }
        
        // === 装备点击处理 ===
        function attachEquipmentClickHandlers() {
            document.querySelectorAll('#equipment-list .equipment-card').forEach(card => {
                card.style.cursor = 'pointer';
                card.addEventListener('click', function() {
                    const name = this.getAttribute('data-equipment');
                    const wrapper = this.closest('.equipment-wrapper');
                    const rarity = wrapper ? wrapper.getAttribute('data-param1') : '蓝';
                    selectEquipment(state.currentEquipmentType, name, rarity);
                    hideModal('equipment-modal');
                });
            });
        }
        
        // === 选择装备(修复ID格式化) ===
        function selectEquipment(type, name, rarity) {
            const slotMap = {
                '武器': 'weapon-slot',
                '装甲': 'armor-slot',
                '戒指': 'ring-slot'
            };
            const slotId = slotMap[type];
            if (!slotId) return;
            
            const slot = document.getElementById(slotId);
            if (!slot) return;
            
            if (type === '武器') state.selectedWeapon = name;
            else if (type === '装甲') state.selectedArmor = name;
            else if (type === '戒指') state.selectedRing = name;
            
            // 从装备data中查找ID
            new mw.Api().post({
                action: 'scribunto-console',
                question: `return require('Module:装备/data')['${name.replace(/'/g, "\\'")}'].id`,
                clear: true
            }).done(function(data) {
                let equipId = '0000';
                if (data && data.return) {
                    equipId = String(data.return).padStart(4, '0');
                }
                
                const imgPath = mw.config.get('wgScriptPath') + '/index.php?title=Special:Redirect/file/relic_' + equipId + '.png';
                const framePath = mw.config.get('wgScriptPath') + '/index.php?title=Special:Redirect/file/frame_item_rarity_' + encodeURIComponent(rarity) + '.png';
                const textShadow = '-1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000';
                
                slot.innerHTML = `
                    <div style="position:relative;width:124px;height:124px">
                        <div style="position:absolute;top:0px;left:0px">
                            <img src="${framePath}" style="width:124px;height:124px;" 
                                 onerror="this.style.display='none'" />
                        </div>
                        <div style="position:absolute;top:8px;left:8px;width:108px;height:108px;border:1px solid #fff;"></div>
                        <div style="position:absolute;top:6px;left:6px;">
                            <img src="${imgPath}" style="width:112px;height:112px;" 
                                 onerror="this.src='${mw.config.get('wgScriptPath')}/resources/assets/file-type-icons/fileicon-image.png';" />
                        </div>
                        <div style="position:absolute;bottom:2px;left:6px;right:6px;color:white;font-size:12px;text-shadow:${textShadow};overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${mw.html.escape(name)}</div>
                    </div>
                `;
            }).fail(function() {
                // 备用方案:直接显示名称
                slot.innerHTML = `
                    <div style="position:relative;width:124px;height:124px;display:flex;align-items:center;justify-content:center;background:#4a4a4a;border-radius:4px;">
                        <span style="color:white;font-size:12px;text-align:center;padding:5px;">${mw.html.escape(name)}</span>
                    </div>
                `;
            });
        }
        
        // === 加载角色卡牌 ===
        function loadCharacterCards(characterName) {
            const listContainer = document.getElementById('available-cards-list');
            listContainer.innerHTML = '<p style="color: white;">加载卡牌...</p>';
            
            new mw.Api().get({
                action: 'parse',
                page: characterName,
                prop: 'wikitext'
            }).done(function(data) {
                if (data.parse && data.parse.wikitext) {
                    const wikitext = data.parse.wikitext['*'];
                    parseCharacterCards(wikitext, characterName);
                }
            }).fail(function() {
                listContainer.innerHTML = '<p style="color: red;">加载失败</p>';
            });
        }
        
        // === 解析角色卡牌 ===
        function parseCharacterCards(wikitext, characterName) {
            const cards = [];
            
            const patterns = {
                selfAware: /\|自我意识技能\s*=\s*([^\n]+)/,
                startCards: [
                    /\|起始卡牌_1\s*=\s*([^\n]+)/,
                    /\|起始卡牌_2\s*=\s*([^\n]+)/,
                    /\|起始卡牌_3\s*=\s*([^\n]+)/,
                    /\|起始卡牌_4\s*=\s*([^\n]+)/
                ],
                uniqueCards: [
                    /\|独特卡牌_1\s*=\s*([^\n]+)/,
                    /\|独特卡牌_2\s*=\s*([^\n]+)/,
                    /\|独特卡牌_3\s*=\s*([^\n]+)/,
                    /\|独特卡牌_4\s*=\s*([^\n]+)/
                ]
            };
            
            const selfAwareMatch = wikitext.match(patterns.selfAware);
            if (selfAwareMatch && selfAwareMatch[1].trim()) {
                cards.push({ type: 'self', name: selfAwareMatch[1].trim() });
            }
            
            patterns.startCards.forEach(pattern => {
                const match = wikitext.match(pattern);
                if (match && match[1].trim()) {
                    cards.push({ type: 'start', name: match[1].trim() });
                }
            });
            
            patterns.uniqueCards.forEach(pattern => {
                const match = wikitext.match(pattern);
                if (match && match[1].trim()) {
                    cards.push({ type: 'unique', name: match[1].trim() });
                }
            });
            
            state.availableCards = cards;
            
            // 自动显示所有卡牌到卡组区域
            displayCardsInDeck(cards, characterName);
        }
        
        // === 自动显示卡牌到卡组(修复点4) ===
        function displayCardsInDeck(cards, characterName) {
            const deckCards = document.getElementById('deck-cards');
            const plusSign = document.querySelector('#deck-area > span');
            
            if (cards.length === 0) {
                deckCards.style.display = 'none';
                if (plusSign) plusSign.style.display = 'block';
                return;
            }
            
            deckCards.style.display = 'flex';
            if (plusSign) plusSign.style.display = 'none';
            deckCards.innerHTML = '<p style="color: white;">加载中...</p>';
            
            let loadedCount = 0;
            const totalCards = cards.length;
            
            // 先清空
            if (loadedCount === 0) {
                deckCards.innerHTML = '';
            }
            
            cards.forEach((card, index) => {
                const cardWrapper = document.createElement('div');
                cardWrapper.style.position = 'relative';
                
                new mw.Api().post({
                    action: 'parse',
                    text: `{{#invoke:卡牌|main|${characterName}|${card.name}}}`,
                    contentmodel: 'wikitext',
                    prop: 'text',
                    disablelimitreport: 1,
                    disableeditsection: 1
                }).done(function(data) {
                    if (data.parse && data.parse.text) {
                        cardWrapper.innerHTML = data.parse.text['*'];
                        
                        // 添加到状态
                        state.deckCards.push({
                            cardName: card.name,
                            characterName: characterName,
                            cardHtml: data.parse.text['*']
                        });
                        
                        // 添加删除按钮
                        const removeBtn = document.createElement('div');
                        removeBtn.className = 'tb-remove-btn';
                        removeBtn.innerHTML = '×';
                        removeBtn.style.cssText = 'position: absolute; top: 5px; right: 5px; background: #ff4444; color: white; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 100; font-size: 20px; font-weight: bold; box-shadow: 0 2px 4px rgba(0,0,0,0.3);';
                        removeBtn.addEventListener('click', function(e) {
                            e.stopPropagation();
                            const cardIndex = state.deckCards.findIndex(c => c.cardName === card.name);
                            if (cardIndex > -1) {
                                state.deckCards.splice(cardIndex, 1);
                                updateDeckDisplay();
                            }
                        });
                        cardWrapper.appendChild(removeBtn);
                        
                        deckCards.appendChild(cardWrapper);
                    }
                    loadedCount++;
                }).fail(function() {
                    cardWrapper.innerHTML = '<div style="color:red;padding:10px;">加载失败</div>';
                    loadedCount++;
                    deckCards.appendChild(cardWrapper);
                });
            });
        }
        
        // === 更新卡组显示 ===
        function updateDeckDisplay() {
            const deckCards = document.getElementById('deck-cards');
            const plusSign = document.querySelector('#deck-area > span');
            
            deckCards.innerHTML = '';
            
            if (state.deckCards.length === 0) {
                deckCards.style.display = 'none';
                if (plusSign) plusSign.style.display = 'block';
                return;
            }
            
            deckCards.style.display = 'flex';
            if (plusSign) plusSign.style.display = 'none';
            
            state.deckCards.forEach((card, index) => {
                const cardDiv = document.createElement('div');
                cardDiv.style.position = 'relative';
                cardDiv.innerHTML = card.cardHtml;
                
                const removeBtn = document.createElement('div');
                removeBtn.className = 'tb-remove-btn';
                removeBtn.innerHTML = '×';
                removeBtn.style.cssText = 'position: absolute; top: 5px; right: 5px; background: #ff4444; color: white; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 100; font-size: 20px; font-weight: bold; box-shadow: 0 2px 4px rgba(0,0,0,0.3);';
                removeBtn.addEventListener('click', function(e) {
                    e.stopPropagation();
                    state.deckCards.splice(index, 1);
                    updateDeckDisplay();
                });
                cardDiv.appendChild(removeBtn);
                
                deckCards.appendChild(cardDiv);
            });
        }
    }
    
    if (typeof mw !== 'undefined' && mw.hook) {
        mw.hook('wikipage.content').add(initTeamBuilder);
    }
})();