MediaWiki:Card.js
来自卡厄思梦境WIKI
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
(function() {
'use strict';
// 加载CSS
mw.loader.load('/index.php?title=Mediawiki:Card.css&action=raw&ctype=text/css', 'text/css');
console.log('Card Manager: 脚本已加载');
class CardManager {
constructor() {
console.log('Card Manager: 初始化中...');
this.currentFighter = '';
this.cards = {};
this.currentCard = null;
this.fighters = ['示例战斗员1', '示例战斗员2'];
this.defaultData = {
order: [],
ego: ''
};
this.cardData = {
name: '',
displayname: '',
art: '',
group: '',
rarity: '',
god: '',
ap: '',
type: '攻击',
dict: '',
desc_global: '',
sub: '',
isinspiration: false,
isgod_inspiration: false,
inspirations: [],
god_inspirations: {
circen: [],
diallos: [],
nihilum: [],
secred: [],
vitor: []
}
};
}
async init() {
console.log('Card Manager: 开始初始化');
await this.loadFighters();
this.render();
console.log('Card Manager: 初始化完成');
}
async loadFighters() {
try {
const api = new mw.Api();
const response = await api.get({
action: 'query',
list: 'categorymembers',
cmtitle: 'Category:战斗员',
cmlimit: 500
});
if (response.query && response.query.categorymembers) {
this.fighters = response.query.categorymembers.map(page => page.title);
console.log('Card Manager: 加载了', this.fighters.length, '个战斗员');
}
} catch (error) {
console.error('Card Manager: 加载战斗员列表失败:', error);
}
}
render() {
console.log('Card Manager: 开始渲染');
const contentDiv = document.getElementById('mw-content-text');
if (!contentDiv) {
console.error('Card Manager: 找不到内容容器');
return;
}
contentDiv.innerHTML = '';
const container = document.createElement('div');
container.className = 'card-manager';
const leftPanel = document.createElement('div');
leftPanel.className = 'card-input-panel';
leftPanel.appendChild(this.renderFighterSelect());
leftPanel.appendChild(this.renderDefaultInfo());
leftPanel.appendChild(this.renderCardInput());
const middlePanel = document.createElement('div');
middlePanel.className = 'card-list-panel';
middlePanel.appendChild(this.renderCardLists());
const rightPanel = document.createElement('div');
rightPanel.className = 'card-preview-panel';
rightPanel.appendChild(this.renderPreview());
container.appendChild(leftPanel);
container.appendChild(middlePanel);
container.appendChild(rightPanel);
contentDiv.appendChild(container);
console.log('Card Manager: 渲染完成');
}
renderFighterSelect() {
const container = document.createElement('div');
container.className = 'form-group';
const label = document.createElement('div');
label.className = 'form-label';
label.textContent = '当前战斗员';
const selectContainer = document.createElement('div');
selectContainer.className = 'custom-select';
const display = document.createElement('div');
display.className = 'select-display';
display.textContent = this.currentFighter || '请选择战斗员...';
const arrow = document.createElement('span');
arrow.className = 'select-arrow';
arrow.textContent = '▼';
display.appendChild(arrow);
const dropdown = document.createElement('div');
dropdown.className = 'select-dropdown';
this.fighters.forEach(fighter => {
const option = document.createElement('div');
option.className = 'select-option';
option.textContent = fighter;
if (fighter === this.currentFighter) {
option.classList.add('selected');
}
option.onclick = async () => {
this.currentFighter = fighter;
display.firstChild.textContent = fighter;
dropdown.querySelectorAll('.select-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
dropdown.classList.remove('active');
await this.loadFighterData();
};
dropdown.appendChild(option);
});
display.onclick = (e) => {
e.stopPropagation();
dropdown.classList.toggle('active');
};
document.addEventListener('click', () => {
dropdown.classList.remove('active');
});
selectContainer.appendChild(display);
selectContainer.appendChild(dropdown);
container.appendChild(label);
container.appendChild(selectContainer);
return container;
}
renderDefaultInfo() {
const container = document.createElement('div');
container.className = 'default-info-section';
const title = document.createElement('div');
title.className = 'section-title';
title.textContent = '默认信息';
container.appendChild(title);
const orderGroup = document.createElement('div');
orderGroup.className = 'form-group';
const orderLabel = document.createElement('div');
orderLabel.className = 'form-label';
orderLabel.textContent = '卡牌顺序(card.order)';
const orderInput = document.createElement('div');
orderInput.className = 'custom-input';
orderInput.contentEditable = true;
orderInput.id = 'order-input';
orderInput.textContent = this.defaultData.order.join(',');
orderInput.addEventListener('input', () => {
this.defaultData.order = orderInput.textContent.split(',').map(s => s.trim()).filter(s => s);
this.updatePreview();
});
orderGroup.appendChild(orderLabel);
orderGroup.appendChild(orderInput);
container.appendChild(orderGroup);
const egoGroup = document.createElement('div');
egoGroup.className = 'form-group';
const egoLabel = document.createElement('div');
egoLabel.className = 'form-label';
egoLabel.textContent = '属性(ego)';
const egoInput = document.createElement('div');
egoInput.className = 'custom-input';
egoInput.contentEditable = true;
egoInput.id = 'ego-input';
egoInput.textContent = this.defaultData.ego;
egoInput.addEventListener('input', () => {
this.defaultData.ego = egoInput.textContent;
this.updatePreview();
});
egoGroup.appendChild(egoLabel);
egoGroup.appendChild(egoInput);
container.appendChild(egoGroup);
return container;
}
renderCardInput() {
const container = document.createElement('div');
const title = document.createElement('div');
title.className = 'section-title';
title.textContent = '卡牌数据';
container.appendChild(title);
container.appendChild(this.createInputField('卡牌名称', 'name'));
container.appendChild(this.createInputField('显示名称(displayname)', 'displayname'));
container.appendChild(this.createInputField('图片(art)', 'art'));
container.appendChild(this.createGroupSelect());
container.appendChild(this.createRaritySelect());
container.appendChild(this.createGodSelect());
container.appendChild(this.createInputField('AP', 'ap'));
container.appendChild(this.createTypeSelect());
container.appendChild(this.createInputField('机制(dict)', 'dict'));
const descGroup = document.createElement('div');
descGroup.className = 'form-group';
const descLabel = document.createElement('div');
descLabel.className = 'form-label';
descLabel.textContent = '描述(desc_global)';
const formatButtons = this.createFormatButtons();
const descInput = document.createElement('div');
descInput.className = 'custom-textarea';
descInput.contentEditable = true;
descInput.textContent = this.cardData.desc_global;
descInput.id = 'desc-input';
descInput.addEventListener('input', () => {
this.cardData.desc_global = descInput.textContent;
this.updatePreview();
});
descGroup.appendChild(descLabel);
descGroup.appendChild(formatButtons);
descGroup.appendChild(descInput);
container.appendChild(descGroup);
container.appendChild(this.createInputField('衍生卡牌(sub)', 'sub'));
container.appendChild(this.createCheckboxField('是否存在灵光一闪', 'isinspiration'));
container.appendChild(this.createCheckboxField('是否存在神光一闪', 'isgod_inspiration'));
// 添加灵光一闪变体显示
if (this.cardData.isinspiration && this.cardData.inspirations.length > 0) {
container.appendChild(this.renderInspirations());
}
// 添加神光一闪变体显示
if (this.cardData.isgod_inspiration) {
container.appendChild(this.renderGodInspirations());
}
const btnGroup = document.createElement('div');
btnGroup.className = 'btn-group';
const saveBtn = document.createElement('div');
saveBtn.className = 'btn btn-primary';
saveBtn.textContent = '保存卡牌';
saveBtn.onclick = () => this.saveCard();
const newBtn = document.createElement('div');
newBtn.className = 'btn btn-success';
newBtn.textContent = '新建卡牌';
newBtn.onclick = () => this.newCard();
btnGroup.appendChild(saveBtn);
btnGroup.appendChild(newBtn);
container.appendChild(btnGroup);
return container;
}
renderInspirations() {
const container = document.createElement('div');
container.className = 'variant-section';
const title = document.createElement('div');
title.className = 'section-title';
title.textContent = '灵光一闪变体';
container.appendChild(title);
this.cardData.inspirations.forEach((inspiration, index) => {
const variantBox = document.createElement('div');
variantBox.className = 'variant-box';
const variantTitle = document.createElement('div');
variantTitle.className = 'variant-title';
variantTitle.textContent = `变体 ${index + 1}`;
variantBox.appendChild(variantTitle);
const variantContent = document.createElement('div');
variantContent.className = 'variant-content';
if (inspiration.ap) {
const apLine = document.createElement('div');
apLine.textContent = `AP: ${inspiration.ap}`;
variantContent.appendChild(apLine);
}
if (inspiration.type) {
const typeLine = document.createElement('div');
typeLine.textContent = `类型: ${inspiration.type}`;
variantContent.appendChild(typeLine);
}
if (inspiration.dict) {
const dictLine = document.createElement('div');
dictLine.textContent = `机制: ${inspiration.dict}`;
variantContent.appendChild(dictLine);
}
if (inspiration.desc_global) {
const descLine = document.createElement('div');
descLine.className = 'variant-desc';
descLine.textContent = `描述: ${inspiration.desc_global}`;
variantContent.appendChild(descLine);
}
variantBox.appendChild(variantContent);
container.appendChild(variantBox);
});
return container;
}
renderGodInspirations() {
const container = document.createElement('div');
container.className = 'variant-section';
const title = document.createElement('div');
title.className = 'section-title';
title.textContent = '神光一闪变体';
container.appendChild(title);
const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
const godNames = {
'circen': '瑟肯',
'diallos': '迪亚罗斯',
'nihilum': '虚无',
'secred': '萨克雷德',
'vitor': '维托尔'
};
gods.forEach(god => {
const godInspirations = this.cardData.god_inspirations[god];
if (!godInspirations || godInspirations.length === 0) return;
const godSection = document.createElement('div');
godSection.className = 'god-section';
const godTitle = document.createElement('div');
godTitle.className = 'god-title';
godTitle.textContent = godNames[god] || god;
godSection.appendChild(godTitle);
godInspirations.forEach((inspiration, index) => {
const variantBox = document.createElement('div');
variantBox.className = 'variant-box small';
const variantTitle = document.createElement('div');
variantTitle.className = 'variant-title';
variantTitle.textContent = `${godNames[god]} 变体 ${index + 1}`;
variantBox.appendChild(variantTitle);
const variantContent = document.createElement('div');
variantContent.className = 'variant-content';
if (inspiration.ap) {
const apLine = document.createElement('div');
apLine.textContent = `AP: ${inspiration.ap}`;
variantContent.appendChild(apLine);
}
if (inspiration.type) {
const typeLine = document.createElement('div');
typeLine.textContent = `类型: ${inspiration.type}`;
variantContent.appendChild(typeLine);
}
if (inspiration.dict) {
const dictLine = document.createElement('div');
dictLine.textContent = `机制: ${inspiration.dict}`;
variantContent.appendChild(dictLine);
}
if (inspiration.desc_global) {
const descLine = document.createElement('div');
descLine.className = 'variant-desc';
descLine.textContent = `描述: ${inspiration.desc_global}`;
variantContent.appendChild(descLine);
}
variantBox.appendChild(variantContent);
godSection.appendChild(variantBox);
});
container.appendChild(godSection);
});
return container;
}
createInputField(label, field) {
const group = document.createElement('div');
group.className = 'form-group';
const labelDiv = document.createElement('div');
labelDiv.className = 'form-label';
labelDiv.textContent = label;
const input = document.createElement('div');
input.className = 'custom-input';
input.contentEditable = true;
input.dataset.field = field;
input.textContent = this.cardData[field] || '';
input.addEventListener('input', () => {
this.cardData[field] = input.textContent;
this.updatePreview();
});
group.appendChild(labelDiv);
group.appendChild(input);
return group;
}
createCheckboxField(label, field) {
const group = document.createElement('div');
group.className = 'form-group';
const labelDiv = document.createElement('div');
labelDiv.className = 'form-label';
labelDiv.textContent = label;
const checkboxContainer = document.createElement('div');
checkboxContainer.className = 'checkbox-group';
const checkbox = document.createElement('div');
checkbox.className = 'custom-checkbox';
checkbox.dataset.field = field;
if (this.cardData[field]) {
checkbox.classList.add('checked');
}
const statusLabel = document.createElement('div');
statusLabel.textContent = this.cardData[field] ? '是' : '否';
checkbox.onclick = () => {
checkbox.classList.toggle('checked');
this.cardData[field] = checkbox.classList.contains('checked');
statusLabel.textContent = this.cardData[field] ? '是' : '否';
this.updatePreview();
};
checkboxContainer.appendChild(checkbox);
checkboxContainer.appendChild(statusLabel);
group.appendChild(labelDiv);
group.appendChild(checkboxContainer);
return group;
}
createFormatButtons() {
const container = document.createElement('div');
container.className = 'format-buttons';
const buttons = [
{ label: '蓝色文本', class: 'blue', template: '{{文本|蓝|%s}}' },
{ label: '绿色文本', class: 'green', template: '{{文本|绿|%s}}' },
{ label: '绿色描边', class: 'green', template: '{{描边|绿|%s}}' },
{ label: '词典', class: '', template: '{{词典|%s}}' },
{ label: '换行', class: '', template: '<br>' }
];
buttons.forEach(btn => {
const button = document.createElement('div');
button.className = 'format-btn ' + btn.class;
button.textContent = btn.label;
button.onclick = () => {
const textarea = document.getElementById('desc-input');
if (textarea) {
this.insertTemplate(textarea, btn.template);
}
};
container.appendChild(button);
});
return container;
}
insertTemplate(element, template) {
element.focus();
const selection = window.getSelection();
let selectedText = '';
// 获取选中的文本
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
// 确保选区在目标元素内
if (element.contains(range.commonAncestorContainer)) {
selectedText = range.toString();
}
}
// 处理不同类型的模板
let insertText;
if (template === '<br>') {
insertText = '<br>';
document.execCommand('insertHTML', false, insertText);
} else {
// 如果有选中文本,包裹它;否则插入模板
insertText = template.replace('%s', selectedText || '选择文字');
document.execCommand('insertText', false, insertText);
}
// 更新数据
this.cardData.desc_global = element.textContent;
this.updatePreview();
}
createGroupSelect() {
const group = document.createElement('div');
group.className = 'form-group';
const label = document.createElement('div');
label.className = 'form-label';
label.textContent = '卡组(group)';
const container = document.createElement('div');
container.className = 'group-options';
const groups = ['自我意识技能', '起始卡牌', '独特卡牌', '灵光一闪', '神光一闪'];
groups.forEach(groupName => {
const option = document.createElement('div');
option.className = 'group-option';
option.textContent = groupName;
if (this.cardData.group === groupName) {
option.classList.add('selected');
}
option.onclick = () => {
container.querySelectorAll('.group-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
this.cardData.group = groupName;
this.updatePreview();
};
container.appendChild(option);
});
group.appendChild(label);
group.appendChild(container);
return group;
}
createRaritySelect() {
const group = document.createElement('div');
group.className = 'form-group';
const label = document.createElement('div');
label.className = 'form-label';
label.textContent = '稀有度(rarity)';
const container = document.createElement('div');
container.className = 'rarity-options';
const rarities = ['白', '蓝', '橙', '彩'];
rarities.forEach(rarity => {
const option = document.createElement('div');
option.className = 'rarity-option';
option.textContent = rarity;
if (this.cardData.rarity === rarity) {
option.classList.add('selected');
}
option.onclick = () => {
container.querySelectorAll('.rarity-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
this.cardData.rarity = rarity;
this.updatePreview();
};
container.appendChild(option);
});
group.appendChild(label);
group.appendChild(container);
return group;
}
createGodSelect() {
const group = document.createElement('div');
group.className = 'form-group';
const label = document.createElement('div');
label.className = 'form-label';
label.textContent = '神明';
const container = document.createElement('div');
container.className = 'god-options';
const gods = ['circen', 'diallos', 'nihilum', 'secred', 'vitor'];
gods.forEach(god => {
const option = document.createElement('div');
option.className = 'god-option';
option.textContent = god;
if (this.cardData.god === god) {
option.classList.add('selected');
}
option.onclick = () => {
container.querySelectorAll('.god-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
this.cardData.god = god;
this.updatePreview();
};
container.appendChild(option);
});
group.appendChild(label);
group.appendChild(container);
return group;
}
createTypeSelect() {
const group = document.createElement('div');
group.className = 'form-group';
const label = document.createElement('div');
label.className = 'form-label';
label.textContent = '卡牌类型(type)';
const container = document.createElement('div');
container.className = 'type-options';
const types = ['攻击', '技能', '强化'];
types.forEach(type => {
const option = document.createElement('div');
option.className = 'type-option';
option.textContent = type;
if (this.cardData.type === type) {
option.classList.add('selected');
}
option.onclick = () => {
container.querySelectorAll('.type-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
this.cardData.type = type;
this.updatePreview();
};
container.appendChild(option);
});
group.appendChild(label);
group.appendChild(container);
return group;
}
renderCardLists() {
const container = document.createElement('div');
const title = document.createElement('div');
title.className = 'panel-title';
title.textContent = '卡牌列表';
container.appendChild(title);
const listContainer = document.createElement('div');
listContainer.className = 'list-container';
listContainer.id = 'card-list';
this.updateCardList(listContainer);
container.appendChild(listContainer);
return container;
}
updateCardList(container) {
container.innerHTML = '';
const cardNames = Object.keys(this.cards);
if (cardNames.length === 0) {
const empty = document.createElement('div');
empty.className = 'list-empty';
empty.textContent = '暂无卡牌';
container.appendChild(empty);
return;
}
cardNames.forEach(name => {
const card = this.cards[name];
const item = document.createElement('div');
item.className = 'card-list-item';
const info = document.createElement('div');
const nameDiv = document.createElement('div');
nameDiv.className = 'card-list-item-name';
nameDiv.textContent = name;
const detailDiv = document.createElement('div');
detailDiv.className = 'card-list-item-info';
detailDiv.textContent = `${card.type || '攻击'} | AP:${card.ap || 0} | ${card.rarity || ''}`;
info.appendChild(nameDiv);
info.appendChild(detailDiv);
const deleteBtn = document.createElement('div');
deleteBtn.className = 'delete-btn';
deleteBtn.textContent = '删除';
deleteBtn.onclick = (e) => {
e.stopPropagation();
if (confirm(`确定要删除卡牌"${name}"吗?`)) {
delete this.cards[name];
this.updateCardList(container);
this.updatePreview();
if (this.currentCard === name) {
this.newCard();
}
}
};
item.appendChild(info);
item.appendChild(deleteBtn);
item.onclick = () => {
this.loadCard(name);
container.querySelectorAll('.card-list-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
};
container.appendChild(item);
});
}
renderPreview() {
const container = document.createElement('div');
const title = document.createElement('div');
title.className = 'panel-title';
title.textContent = 'Lua代码预览';
container.appendChild(title);
const preview = document.createElement('div');
preview.className = 'preview-code';
preview.id = 'code-preview';
container.appendChild(preview);
const copyBtn = document.createElement('div');
copyBtn.className = 'btn btn-primary';
copyBtn.textContent = '复制代码';
copyBtn.style.marginTop = '10px';
copyBtn.onclick = () => this.copyCode();
container.appendChild(copyBtn);
this.updatePreview();
return container;
}
updatePreview() {
const preview = document.getElementById('code-preview');
if (!preview) return;
preview.textContent = this.generateLuaCode();
}
generateLuaCode() {
let code = 'local card = {}\n\n';
if (this.defaultData.order.length > 0) {
code += `card.order = { "${this.defaultData.order.join(',')}" }\n\n`;
}
code += 'card.info = {\n';
if (this.defaultData.ego) {
code += ` ego = "${this.defaultData.ego}",\n`;
}
code += '}\n\n';
Object.keys(this.cards).forEach(name => {
const card = this.cards[name];
code += this.generateCardCode(name, card);
});
code += 'return card';
return code;
}
generateCardCode(name, card) {
let code = `card["${name}"] = {\n`;
code += ' base = {\n';
if (card.displayname) code += ` displayname = "${card.displayname}",\n`;
if (card.art) code += ` art = "${card.art}",\n`;
if (card.group) code += ` group = "${card.group}",\n`;
if (card.rarity) code += ` rarity = "${card.rarity}",\n`;
if (card.ap) code += ` ap = ${isNaN(card.ap) ? `"${card.ap}"` : card.ap},\n`;
if (card.type) code += ` type = "${card.type}",\n`;
if (card.dict) code += ` dict = "${card.dict}",\n`;
if (card.desc_global) {
const desc = card.desc_global.replace(/\n/g, '<br>').replace(/"/g, '\\"');
code += ` desc_global = "${desc}",\n`;
}
if (card.sub) code += ` sub = "${card.sub}",\n`;
if (card.isinspiration) code += ` isinspiration = 1,\n`;
if (card.isgod_inspiration) code += ` isgod_inspiration = 1,\n`;
code += ' },\n';
code += '}\n\n';
return code;
}
saveCard() {
if (!this.cardData.name) {
alert('请输入卡牌名称!');
return;
}
this.cards[this.cardData.name] = JSON.parse(JSON.stringify(this.cardData));
this.currentCard = this.cardData.name;
if (!this.defaultData.order.includes(this.cardData.name)) {
this.defaultData.order.push(this.cardData.name);
// 更新order输入框
const orderInput = document.getElementById('order-input');
if (orderInput) {
orderInput.textContent = this.defaultData.order.join(',');
}
}
const listContainer = document.getElementById('card-list');
if (listContainer) {
this.updateCardList(listContainer);
}
this.updatePreview();
alert('卡牌保存成功!');
}
newCard() {
this.currentCard = null;
this.cardData = {
name: '',
displayname: '',
art: '',
group: '',
rarity: '',
god: '',
ap: '',
type: '攻击',
dict: '',
desc_global: '',
sub: '',
isinspiration: false,
isgod_inspiration: false,
inspirations: [],
god_inspirations: {
circen: [],
diallos: [],
nihilum: [],
secred: [],
vitor: []
}
};
this.render();
}
loadCard(name) {
if (!this.cards[name]) return;
this.currentCard = name;
this.cardData = JSON.parse(JSON.stringify(this.cards[name]));
this.render();
}
async loadFighterData() {
if (!this.currentFighter) return;
try {
const api = new mw.Api();
const moduleName = `模块:卡牌/${this.currentFighter}`;
const response = await api.get({
action: 'query',
prop: 'revisions',
titles: moduleName,
rvprop: 'content',
rvslots: 'main'
});
const pages = response.query.pages;
const page = Object.values(pages)[0];
if (page.revisions && page.revisions[0]) {
const content = page.revisions[0].slots.main['*'];
console.log('Card Manager: 加载了战斗员数据');
// 解析Lua代码
this.parseLuaContent(content);
// 重新渲染界面
this.render();
alert(`成功加载战斗员"${this.currentFighter}"的数据!`);
} else {
console.log('Card Manager: 该战斗员暂无数据');
alert(`战斗员"${this.currentFighter}"暂无卡牌数据`);
}
} catch (error) {
console.error('Card Manager: 加载战斗员数据失败:', error);
alert('加载失败: ' + error.message);
}
}
parseLuaContent(content) {
// 重置数据
this.cards = {};
this.defaultData = { order: [], ego: '' };
try {
// 解析 card.order
const orderMatch = content.match(/card\.order\s*=\s*\{\s*"([^"]+)"\s*\}/);
if (orderMatch) {
this.defaultData.order = orderMatch[1].split(',').map(s => s.trim()).filter(s => s);
}
// 解析 card.info.ego
const infoBlockMatch = content.match(/card\.info\s*=\s*\{([^}]*)\}/);
if (infoBlockMatch) {
const egoMatch = infoBlockMatch[1].match(/ego\s*=\s*"([^"]+)"/);
if (egoMatch) {
this.defaultData.ego = egoMatch[1];
}
}
// 使用更复杂的解析逻辑来处理嵌套结构
const lines = content.split('\n');
let currentCard = null;
let currentSection = null; // 'base' 或 'var'
let currentVarType = null; // 'inspiration' 或 'god_inspiration'
let currentGodName = null; // circen, diallos 等
let braceStack = [];
let sectionContent = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmedLine = line.trim();
// 匹配卡牌定义开始 card["卡牌名"] = {
const cardMatch = line.match(/^card\["([^"]+)"\]\s*=\s*\{/);
if (cardMatch) {
currentCard = cardMatch[1];
braceStack = ['{'];
continue;
}
if (!currentCard) continue;
// 匹配 base = {
if (trimmedLine.match(/^base\s*=\s*\{/)) {
currentSection = 'base';
sectionContent = [];
continue;
}
// 匹配 var = {
if (trimmedLine.match(/^var\s*=\s*\{/)) {
currentSection = 'var';
sectionContent = [];
continue;
}
// 如果在 base 部分
if (currentSection === 'base') {
if (trimmedLine === '},') {
// base 部分结束
this.parseCardBase(currentCard, sectionContent.join('\n'));
currentSection = null;
sectionContent = [];
} else {
sectionContent.push(line);
}
continue;
}
// 如果在 var 部分
if (currentSection === 'var') {
// 匹配 inspiration = {
if (trimmedLine.match(/^inspiration\s*=\s*\{/)) {
currentVarType = 'inspiration';
sectionContent = [];
continue;
}
// 匹配 god_inspiration = {
if (trimmedLine.match(/^god_inspiration\s*=\s*\{/)) {
currentVarType = 'god_inspiration';
sectionContent = [];
continue;
}
// 在 inspiration 中
if (currentVarType === 'inspiration') {
if (trimmedLine === '},') {
// inspiration 部分结束
this.parseInspirations(currentCard, sectionContent.join('\n'));
currentVarType = null;
sectionContent = [];
} else {
sectionContent.push(line);
}
continue;
}
// 在 god_inspiration 中
if (currentVarType === 'god_inspiration') {
// 匹配神明名称 circen = {
const godMatch = trimmedLine.match(/^(circen|diallos|nihilum|secred|vitor)\s*=\s*\{/);
if (godMatch) {
currentGodName = godMatch[1];
sectionContent = [];
continue;
}
if (currentGodName) {
if (trimmedLine === '},') {
// 某个神明的部分结束
this.parseGodInspirations(currentCard, currentGodName, sectionContent.join('\n'));
currentGodName = null;
sectionContent = [];
} else {
sectionContent.push(line);
}
continue;
}
// god_inspiration 整体结束
if (trimmedLine === '},') {
currentVarType = null;
}
continue;
}
// var 部分结束
if (trimmedLine === '},') {
currentSection = null;
}
}
// 卡牌定义结束
if (trimmedLine === '}' && braceStack.length === 1) {
currentCard = null;
braceStack = [];
}
}
console.log('Card Manager: 解析完成');
console.log('Card Manager: order =', this.defaultData.order);
console.log('Card Manager: ego =', this.defaultData.ego);
console.log('Card Manager: 卡牌数量 =', Object.keys(this.cards).length);
console.log('Card Manager: 卡牌列表 =', Object.keys(this.cards));
} catch (error) {
console.error('Card Manager: 解析Lua内容时出错:', error);
alert('解析卡牌数据失败: ' + error.message);
}
}
parseCardBase(cardName, baseContent) {
const card = {
name: cardName,
displayname: this.extractFieldValue(baseContent, 'displayname'),
art: this.extractFieldValue(baseContent, 'art'),
group: this.extractFieldValue(baseContent, 'group'),
rarity: this.extractFieldValue(baseContent, 'rarity'),
god: this.extractFieldValue(baseContent, 'god'),
ap: this.extractFieldValue(baseContent, 'ap'),
type: this.extractFieldValue(baseContent, 'type') || '攻击',
dict: this.extractFieldValue(baseContent, 'dict'),
desc_global: this.extractFieldValue(baseContent, 'desc_global').replace(/<br>/g, '\n'),
sub: this.extractFieldValue(baseContent, 'sub'),
isinspiration: baseContent.includes('isinspiration = 1'),
isgod_inspiration: baseContent.includes('isgod_inspiration = 1'),
inspirations: [],
god_inspirations: {
circen: [],
diallos: [],
nihilum: [],
secred: [],
vitor: []
}
};
this.cards[cardName] = card;
}
parseInspirations(cardName, content) {
if (!this.cards[cardName]) return;
// 分割成单个灵光一闪变体
const variants = this.splitVariants(content);
variants.forEach(variantContent => {
const variant = {
ap: this.extractFieldValue(variantContent, 'ap'),
type: this.extractFieldValue(variantContent, 'type'),
dict: this.extractFieldValue(variantContent, 'dict'),
desc_global: this.extractFieldValue(variantContent, 'desc_global').replace(/<br>/g, '\n')
};
this.cards[cardName].inspirations.push(variant);
});
console.log(`Card Manager: 卡牌 "${cardName}" 有 ${this.cards[cardName].inspirations.length} 个灵光一闪变体`);
}
parseGodInspirations(cardName, godName, content) {
if (!this.cards[cardName]) return;
// 分割成单个神光一闪变体
const variants = this.splitVariants(content);
variants.forEach(variantContent => {
const variant = {
ap: this.extractFieldValue(variantContent, 'ap'),
type: this.extractFieldValue(variantContent, 'type'),
dict: this.extractFieldValue(variantContent, 'dict'),
desc_global: this.extractFieldValue(variantContent, 'desc_global').replace(/<br>/g, '\n')
};
this.cards[cardName].god_inspirations[godName].push(variant);
});
console.log(`Card Manager: 卡牌 "${cardName}" 的神明 "${godName}" 有 ${this.cards[cardName].god_inspirations[godName].length} 个神光一闪变体`);
}
splitVariants(content) {
const variants = [];
const lines = content.split('\n');
let currentVariant = [];
let braceCount = 0;
for (let line of lines) {
const trimmed = line.trim();
if (trimmed === '{') {
braceCount++;
if (braceCount === 1) {
currentVariant = [];
}
} else if (trimmed === '},' || trimmed === '}') {
braceCount--;
if (braceCount === 0 && currentVariant.length > 0) {
variants.push(currentVariant.join('\n'));
currentVariant = [];
}
} else if (braceCount === 1) {
currentVariant.push(line);
}
}
return variants;
}
extractFieldValue(content, fieldName) {
// 匹配 fieldName = "value" 格式
const pattern = new RegExp(`${fieldName}\\s*=\\s*"([^"]*)"`, 'i');
const match = content.match(pattern);
if (match) {
return match[1];
}
// 匹配 fieldName = value 格式(数字)
const numPattern = new RegExp(`${fieldName}\\s*=\\s*([\\d.]+)`, 'i');
const numMatch = content.match(numPattern);
if (numMatch) {
return numMatch[1];
}
return '';
}
copyCode() {
const code = this.generateLuaCode();
const textarea = document.createElement('textarea');
textarea.value = code;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('代码已复制到剪贴板!');
}
}
// 初始化函数
function initCardManager() {
console.log('Card Manager: 准备启动');
const manager = new CardManager();
manager.init();
}
// 在页面加载完成后启动
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
mw.loader.using(['mediawiki.api']).then(initCardManager);
});
} else {
mw.loader.using(['mediawiki.api']).then(initCardManager);
}
})();