// ==UserScript==
// @name WoD 战斗设置增强
// @namespace https://www.christophero.xyz
// @description 增强设置页面操作
// @author DotIN13
// @include https://*.wannaexpresso.com/wod/spiel/hero/skillconf*
// @include http*://*.world-of-dungeons.*/wod/spiel/hero/skillconf*
// @grant none
// @modifier Christophero
// @version 2023.04.02.1
// ==/UserScript==
(function () {
("use strict");
const btnStyle =
"color: white; background-color: #191919; width: 24px; height: 24px; padding: 0; text-align: center; font-weight: bold;border: 1px solid #8b8b8b;";
WodUiActionList.prototype.insertAction = function (action, index) {
this.list.insertItem(new WodUiActionListItem(action), index);
};
function moveTo(index) {
if (index) {
assert(
index >= 0,
"WodUiList.moveTo(index), IndexOutOfBoundsException: index < 0"
);
assert(
index <= this.items.length,
"WodUiList.moveTo(index), IndexOutOfBoundsException: index >= itemCount"
);
}
if (index >= 0 && this.items.length > 1) {
// Elemente im DOM tauschen.
if (index == this.selectedIndex) return;
const selectedItem = this.items[this.selectedIndex];
this.listTd.removeChild(selectedItem);
if (index < this.items.length) {
const aboveItem = this.items[index];
this.listTd.insertChild(selectedItem, aboveItem);
} else {
this.listTd.appendChild(selectedItem);
}
let tempArr = this.items.splice(this.selectedIndex, 1);
this.items.splice(index, 0, ...tempArr);
this.setSelectedIndex(index == this.items.length ? index - 1 : index);
}
}
WodUiList.prototype.moveTo = moveTo;
WodUiPositionList.prototype.moveTo = moveTo;
/**
* 创建一个按钮
* @param {string} innerHTML
* @param {string} title
* @param {function} callback
*/
function createBtn(innerHTML, title, iconUrl, callback) {
const button = document.createElement("button");
button.innerHTML = innerHTML;
button.title = title;
button.setAttribute(
"style",
`${btnStyle}background: url(${iconUrl}),linear-gradient(180deg, #535353, transparent); background-size: contain;`
);
button.addEventListener("click", callback);
return button;
}
// 地城添加
addActionBtns(THE_ORDERS.dungeon.level.preroundActionList);
addActionBtns(THE_ORDERS.dungeon.level.roundActionList);
addPositionBtns(THE_ORDERS.dungeon.level.preroundActionList.positionList);
addPositionBtns(THE_ORDERS.dungeon.level.roundActionList.positionList);
// 决斗添加
addActionBtns(THE_ORDERS.duel.level.preroundActionList);
addActionBtns(THE_ORDERS.duel.level.roundActionList);
addPositionBtns(THE_ORDERS.duel.level.preroundActionList.positionList);
addPositionBtns(THE_ORDERS.duel.level.roundActionList.positionList);
function parseNum(numStr) {
let num = 1;
try {
num = parseInt(numStr);
} catch (ex) {
num = 1;
}
if (isNaN(num) || num < 0) {
num = 1;
}
return num;
}
function addActionBtns(actionList) {
let list = actionList.list;
// 添加置顶按钮
const headerButton = createBtn(
"",
"将选中条目移至顶部",
"https://christophero.xyz/imgs/top.png",
function (e) {
e.preventDefault();
list.moveTo(0);
actionList.rebuildModel();
}
);
// 添加置底按钮
const footerButton = createBtn(
"",
"将选中条目移至底部",
"https://christophero.xyz/imgs/bottom.png",
function (e) {
e.preventDefault();
list.moveTo(actionList.actions.length);
actionList.rebuildModel();
}
);
// 添加禁用其他按钮
const disableOthersButton = createBtn(
"限",
"仅启用选中条目",
"",
function (e) {
e.preventDefault();
const selectedItem = list.getSelectedItem();
if (!selectedItem) return;
for (let item of list.items) {
item.setEnabled(item === selectedItem);
}
actionList.rebuildModel();
}
);
// 添加启用所有按钮
const allButton = createBtn(
"",
"启用所有条目",
"https://christophero.xyz/imgs/select-all.png",
function (e) {
e.preventDefault();
for (let item of list.items) {
item.setEnabled(true);
}
actionList.rebuildModel();
}
);
const insertButton = createBtn(
"",
"复制选中条目并插入下方",
"https://christophero.xyz/imgs/append.png",
function (e) {
e.preventDefault();
const src = actionList.getSelectedAction();
if (typeof src != undefined) {
const dst = new WodAction();
dst.copyFrom(src);
if (dst.skill && dst.skill.name === "干等着") {
let times = prompt("请输入干等次数", 1);
if (times == null) return;
times = parseNum(times);
if (actionList.actions.length + times > 200) {
alert("插入循环后动作超出200条,禁止插入!");
return;
}
for (let i = 0; i < times; i++) {
actionList.insertAction(dst, list.getSelectedIndex());
}
actionList.rebuildModel();
list.setSelectedIndex(list.getSelectedIndex() + times);
} else {
actionList.insertAction(dst, list.getSelectedIndex());
actionList.rebuildModel();
list.setSelectedIndex(list.getSelectedIndex() + 1);
}
}
}
);
const clearButton = createBtn(
"",
"清空条目",
"https://christophero.xyz/imgs/clear.png",
function (e) {
e.preventDefault();
list.removeAllItems();
actionList.addAction(new WodAction());
list.setSelectedIndex(0);
actionList.rebuildModel();
}
);
const cycleButton = createBtn("循", "重复环节", "", function (e) {
e.preventDefault();
const src = actionList.getSelectedAction();
if (typeof src != undefined) {
let cycleRange = prompt("请输入循环长度(包含当前选中行动)", 1);
if (cycleRange == null) return;
cycleRange = parseNum(cycleRange);
let cycleTimes = prompt("请输入额外循环次数(不算原始行动)", 1);
if (cycleTimes == null) return;
cycleTimes = parseNum(cycleTimes);
const actions = actionList.actions;
let selectedIndex = list.getSelectedIndex();
// 判断区间是否超出行动数组限界,超出则循环节到结束
let overlimit = selectedIndex + cycleRange > actions.length;
if (overlimit) {
cycleRange = actions.length - selectedIndex;
}
if (actions.length + cycleTimes * cycleRange > 200) {
alert("插入循环后动作超出200条,禁止插入!");
return;
}
// 确定插入起始点并插入指定循环节
let startIndex = overlimit
? actions.length
: selectedIndex + cycleRange;
let offset = 0;
for (let loop = 0; loop < cycleTimes; loop++) {
for (let index = selectedIndex; index < startIndex; index++) {
const dst = new WodAction();
dst.copyFrom(actions[index]);
actionList.insertAction(dst, startIndex + offset);
offset++;
}
}
// 重新渲染行动并变更当前选定行动
actionList.rebuildModel();
list.setSelectedIndex(
list.getSelectedIndex() + offset + cycleRange - 1
);
}
});
let element = list.buttonTd.element ? list.buttonTd.element : list.buttonTd;
element.appendChild(headerButton);
element.appendChild(footerButton);
element.appendChild(disableOthersButton);
element.appendChild(allButton);
element.appendChild(clearButton);
element.appendChild(cycleButton);
element.appendChild(insertButton);
// Make buttons sticky
const stickyButtons = document.createElement("div");
while (element.childNodes.length) {
stickyButtons.appendChild(element.firstChild);
}
element.appendChild(stickyButtons);
stickyButtons.setAttribute("style", "position: sticky; top: 0;");
list.buttonTd = stickyButtons;
// Make modBox sticky
actionList.modBox.element.setAttribute(
"style",
"width: 300px; padding-bottom: 10px; float: right; position: sticky; top: 0;"
);
}
function addPositionBtns(positionList) {
// 添加置顶按钮
const headerButton = createBtn(
"",
"将选中条目移至顶部",
"https://christophero.xyz/imgs/top.png",
function (e) {
e.preventDefault();
positionList.moveTo(0);
positionList.rebuildPositions();
positionList.firePositionsChangeEvent();
}
);
// 添加置底按钮
const footerButton = createBtn(
"",
"将选中条目移至底部",
"https://christophero.xyz/imgs/bottom.png",
function (e) {
e.preventDefault();
positionList.moveTo(positionList.items.length);
positionList.rebuildPositions();
positionList.firePositionsChangeEvent();
}
);
// 添加禁用其他按钮
const disableOthersButton = createBtn(
"限",
"仅启用选中条目",
"",
function (e) {
e.preventDefault();
const selectedItem = positionList.getSelectedItem();
if (!selectedItem) return;
for (let item of positionList.items) {
item.setEnabled(item === selectedItem);
}
positionList.rebuildPositions();
positionList.firePositionsChangeEvent();
}
);
// 添加启用所有按钮
const allButton = createBtn(
"",
"启用所有条目",
"https://christophero.xyz/imgs/select-all.png",
function (e) {
e.preventDefault();
for (let item of positionList.items) {
item.setEnabled(true);
}
positionList.rebuildPositions();
positionList.firePositionsChangeEvent();
}
);
// 添加翻转按钮
const reverseButton = createBtn(
"",
"翻转条目",
"https://christophero.xyz/imgs/reverse.png",
function (e) {
e.preventDefault();
positionList.setPositions(positionList.positions.reverse());
positionList.rebuildPositions();
positionList.firePositionsChangeEvent();
}
);
let element = positionList.buttonTd.element
? positionList.buttonTd.element
: positionList.buttonTd;
element.appendChild(headerButton);
element.appendChild(footerButton);
element.appendChild(disableOthersButton);
element.appendChild(allButton);
element.appendChild(reverseButton);
}
})();