// ==UserScript==
// @name [MWI] Realtime Import Of Battle Simulation
// @name:zh-CN [银河奶牛]战斗模拟实时导入
// @namespace http://tampermonkey.net/
// @version 0.1.5
// @description Battle simulation imports the realtime configuration of the current character.
// @description:zh-CN 战斗模拟辅助工具,实时监听角色配置变化,导入当前角色实时配置
// @icon https://www.milkywayidle.com/favicon.svg
// @author Yannis
// @license CC-BY-NC-SA-4.0
// @match https://www.milkywayidle.com/*
// @match https://test.milkywayidle.com/*
// @match https://*/MWICombatSimulatorTest/dist/*
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
/**
* 感谢 'MWITool' 为本脚本提供的技术参考,本脚本部分代码来源于 MWITool,请勿删除本版权声明
* 本脚本若有任何问题,欢迎随时与开发者联系与反馈,感谢使用
* Thanks 'MWITool' for the technical reference provided for this script.
* Some of the code in this script is sourced from MWITool.
* Please do not delete this copyright notice.
*
* https://greasyfork.runtimutd.eu.org/en/scripts/494467-mwitools
*/
(function () {
'use strict';
const debug = console.log.bind(null, '%c[BatSync]%c', 'color:cyan', 'color:black');
const info = console.log.bind(null, '%c[BatSync]%c', 'color:green', 'color:black');
const error = console.log.bind(null, '%c[BatSync]%c', 'color:red', 'color:black');
// 语言设定
const isZHInGameSetting = localStorage.getItem("i18nextLng")?.toLowerCase()?.startsWith("zh");
let isZH = isZHInGameSetting;
let playerId;
let clientData = {};
// 监听WebSocket
function hookWS() {
const dataProperty = Object.getOwnPropertyDescriptor(MessageEvent.prototype, "data");
const oriGet = dataProperty.get;
dataProperty.get = hookedGet;
Object.defineProperty(MessageEvent.prototype, "data", dataProperty);
function hookedGet() {
const socket = this.currentTarget;
if (!(socket instanceof WebSocket)) {
return oriGet.call(this);
}
if (socket.url.indexOf("api.milkywayidle.com/ws") <= -1 && socket.url.indexOf("api-test.milkywayidle.com/ws") <= -1) {
return oriGet.call(this);
}
const message = oriGet.call(this);
Object.defineProperty(this, "data", { value: message }); // Anti-loop
try {
handleMessage(message);
} catch (e) {
error(`处理消息协议时出错: ${e}`);
console.log(e.stack);
}
return message;
}
}
// 获取客户端初始化数据
function getInitClientData() {
return JSON.parse(GM_getValue("init_client_data", ""));
}
// 获取当前角色数据
function getCurrentPlayerData() {
let playersDataStr = GM_getValue("init_character_data", "");
if (playersDataStr) {
let playerData = JSON.parse(playersDataStr);
return getPlayerData(playerData.character.id);
} else {
return;
}
}
// 获取角色数据
function getPlayerData(id) {
let playersDataStr = GM_getValue("mwi_players_data", null) || JSON.stringify(new Array());
let playersData = JSON.parse(playersDataStr);
const pIndex = playersData.findIndex(obj => obj.character.id === id);
if (pIndex !== -1) {
return playersData[pIndex];
} else {
return;
}
}
// 保存角色数据
function saveCharacterData(obj) {
let playersDataStr = GM_getValue("mwi_players_data", null) || JSON.stringify(new Array());
let playersData = JSON.parse(playersDataStr);
playersData = playersData.filter(e => e.character.id !== obj.character.id);
playersData.unshift(obj);
if (playersData.length > 20) {
playersData.pop();
}
GM_setValue("mwi_players_data", JSON.stringify(playersData));
}
// 消息处理
function handleMessage(message) {
let obj = JSON.parse(message);
if (!obj) {
return;
}
switch (obj.type) {
case 'pong': {
// ping-pong
break;
}
case 'active_player_count_updated': {
// 活跃人数更新
break;
}
case 'init_client_data': {
// 客户端数据
GM_setValue("init_client_data", message);
clientData.actionDetailMap = obj.actionDetailMap;
clientData.levelExperienceTable = obj.levelExperienceTable;
clientData.itemDetailMap = obj.itemDetailMap;
clientData.actionCategoryDetailMap = obj.actionCategoryDetailMap;
clientData.abilityDetailMap = obj.abilityDetailMap;
break;
}
case 'init_character_data': {
// 初始化信息
GM_setValue("init_character_data", message);
playerId = obj.character.id;
obj.battleObj = buildBattleObjFromPlayer(obj, true);
saveCharacterData(obj);
break;
}
case 'profile_shared': {
// 角色详情
let player = getPlayerData(obj.profile.characterSkills[0].characterID)
let battleObj = buildBattleObjFromProfileShared(player, obj);
if (!player) {
// 不是本角色
player = {}
player.character = {}
player.character.id = battleObj.character.id
player.character.name = battleObj.character.name
}
player.battleObj = battleObj;
saveCharacterData(player);
break;
}
case 'new_battle': {
// 战斗更新
for (const battlePlayer of obj.players) {
let player = getPlayerData(battlePlayer.character.id);
let battleObj = buildBattleObjFromNewBattle(player, battlePlayer);
if (!player) {
// 不是本角色
player = {}
player.character = {}
player.character.id = battleObj.character.id
player.character.name = battleObj.character.name
}
player.battleObj = battleObj;
saveCharacterData(player);
}
break;
}
case 'items_updated': {
// 物品更新
let player = getPlayerData(playerId);
let update = false;
if (obj.endCharacterItems) {
for (const item of Object.values(obj.endCharacterItems)) {
if (item.itemLocationHrid !== "/item_locations/inventory" && item.count > 0) {
// 装备更新
let equipment = player.battleObj.player.equipment;
equipment = equipment.filter(e => e.itemLocationHrid !== item.itemLocationHrid);
equipment.push({
itemLocationHrid: item.itemLocationHrid,
itemHrid: item.itemHrid,
enhancementLevel: item.enhancementLevel,
})
player.battleObj.player.equipment = equipment;
update = true;
}
}
}
if (update) {
saveCharacterData(player);
}
break;
}
case 'action_type_consumable_slots_updated': {
// 消耗栏更新
let player = getPlayerData(playerId);
player.actionTypeDrinkSlotsMap = obj.actionTypeDrinkSlotsMap;
player.actionTypeFoodSlotsMap = obj.actionTypeFoodSlotsMap;
player.battleObj = buildBattleObjFromPlayer(player, false);
saveCharacterData(player);
break;
}
case 'abilities_updated': {
// 技能更新
let player = getPlayerData(playerId);
let equippedAbilities = JSON.parse(JSON.stringify(player.combatUnit.combatAbilities));
for (let i = equippedAbilities.length; i < 5; i++) {
equippedAbilities.push({})
}
if (obj.endCharacterAbilities) {
for (const ability of obj.endCharacterAbilities) {
const aIndex = equippedAbilities.findIndex(obj => obj.abilityHrid === ability.abilityHrid);
if (aIndex >= 0) {
equippedAbilities[aIndex] = {}
}
if (ability.slotNumber > 0) {
equippedAbilities.splice(ability.slotNumber - 1, 0, {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
})
}
}
}
player.combatUnit.combatAbilities = equippedAbilities.filter(e => e.abilityHrid && e.abilityHrid.length > 0);
player.battleObj = buildBattleObjFromPlayer(player, false);
saveCharacterData(player);
break;
}
case 'combat_triggers_updated': {
let player = getPlayerData(playerId);
if (obj.combatTriggerTypeHrid === '/combat_trigger_types/ability') {
// 技能栏 Trigger 更新
player.abilityCombatTriggersMap[obj.abilityHrid] = obj.combatTriggers;
} else if (obj.combatTriggerTypeHrid === '/combat_trigger_types/consumable') {
// 消耗栏 Trigger 更新
player.consumableCombatTriggersMap[obj.itemHrid] = obj.combatTriggers;
} else {
break;
}
player.battleObj = buildBattleObjFromPlayer(player, false);
saveCharacterData(player);
break;
}
case 'all_combat_triggers_updated': {
// 所有 Triggers 更新
let player = getPlayerData(playerId);
player.abilityCombatTriggersMap = { ...player.abilityCombatTriggersMap, ...obj.abilityCombatTriggersMap };
player.consumableCombatTriggersMap = { ...player.consumableCombatTriggersMap, ...obj.consumableCombatTriggersMap };
player.battleObj = buildBattleObjFromPlayer(player, false);
saveCharacterData(player);
break;
}
case 'party_updated': {
// 队伍更新
let player = getPlayerData(playerId);
player.partyInfo = obj.partyInfo;
saveCharacterData(player);
break;
}
case 'chat_message_received': {
// 聊天消息
break;
}
case 'action_completed': {
// 行动完成
break;
}
default: {
// debug(obj);
}
}
}
// 添加实时导入按钮
function addImportButtonForMWICombatSimulate() {
const checkElem = () => {
const btnEquipSets = document.querySelector(`button#buttonEquipmentSets`);
if (btnEquipSets) {
clearInterval(timer);
let divRow = document.createElement("div");
divRow.className = "row";
btnEquipSets.parentElement.parentElement.prepend(divRow);
// 导入按钮
let div1 = document.createElement("div");
div1.className = "col-md-auto mb-3 pt-1";
divRow.append(div1);
let button = document.createElement("button");
div1.append(button);
button.textContent = isZH ? "实时导入数据" : "Real-time Import";
button.className = "btn btn-warning";
button.onclick = function () {
const btnGetPrice = document.querySelector(`button#buttonGetPrices`);
if (btnGetPrice) {
btnGetPrice.click();
}
importDataForMWICombatSimulate(button);
return false;
};
}
};
let timer = setInterval(checkElem, 200);
}
// 导入数据
async function importDataForMWICombatSimulate(button) {
clientData = getInitClientData();
let player = getCurrentPlayerData();
const BLANK_PLAYER_JSON_STR = `{\"player\":{\"attackLevel\":1,\"magicLevel\":1,\"powerLevel\":1,\"rangedLevel\":1,\"defenseLevel\":1,\"staminaLevel\":1,\"intelligenceLevel\":1,\"equipment\":[]},\"food\":{\"/action_types/combat\":[{\"itemHrid\":\"\"},{\"itemHrid\":\"\"},{\"itemHrid\":\"\"}]},\"drinks\":{\"/action_types/combat\":[{\"itemHrid\":\"\"},{\"itemHrid\":\"\"},{\"itemHrid\":\"\"}]},\"abilities\":[{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"},{\"abilityHrid\":\"\",\"level\":\"1\"}],\"triggerMap\":{},\"zone\":\"/actions/combat/fly\",\"simulationTime\":\"100\",\"houseRooms\":{\"/house_rooms/dairy_barn\":0,\"/house_rooms/garden\":0,\"/house_rooms/log_shed\":0,\"/house_rooms/forge\":0,\"/house_rooms/workshop\":0,\"/house_rooms/sewing_parlor\":0,\"/house_rooms/kitchen\":0,\"/house_rooms/brewery\":0,\"/house_rooms/laboratory\":0,\"/house_rooms/observatory\":0,\"/house_rooms/dining_room\":0,\"/house_rooms/library\":0,\"/house_rooms/dojo\":0,\"/house_rooms/gym\":0,\"/house_rooms/armory\":0,\"/house_rooms/archery_range\":0,\"/house_rooms/mystical_study\":0}}`;
const playerNames = {};
const imported = {};
const battleData = {};
let isParty = false;
let zone = "/actions/combat/fly";
let isZoneDungeon = false;
if (!player?.partyInfo?.partySlotMap) {
// 个人
playerNames[0] = player.character.name;
imported[0] = true;
battleData[0] = player.battleObj;
// Zone
for (const action of player.characterActions) {
if (action && action.actionHrid.includes("/actions/combat/")) {
zone = action.actionHrid;
isZoneDungeon = clientData.actionDetailMap[action.actionHrid]?.combatZoneInfo?.isDungeon;
break;
}
}
} else {
// 队伍
isParty = true;
let i = 0;
for (const member of Object.values(player.partyInfo.partySlotMap)) {
i++;
if (member.characterID) {
if (member.characterID === player.character.id) {
playerNames[i] = player.character.name;
imported[i] = true;
battleData[i] = JSON.stringify(player.battleObj);
continue;
} else {
let memberData = getPlayerData(member.characterID);
if (memberData && memberData.battleObj?.valid) {
playerNames[i] = memberData.character.name;
imported[i] = true;
battleData[i] = JSON.stringify(memberData.battleObj);
continue;
} else {
playerNames[i] = isZH ? "需要点开个人资料" : "Open profile in game";
imported[i] = true;
battleData[i] = BLANK_PLAYER_JSON_STR;
}
}
}
}
// Zone
zone = player.partyInfo?.party?.actionHrid;
isZoneDungeon = clientData.actionDetailMap[zone]?.combatZoneInfo?.isDungeon;
}
// Select zone or dungeon
if (zone) {
if (isZoneDungeon) {
document.querySelector(`input#simDungeonToggle`).checked = true;
document.querySelector(`input#simDungeonToggle`).dispatchEvent(new Event("change"));
const selectDungeon = document.querySelector(`select#selectDungeon`);
for (let i = 0; i < selectDungeon.options.length; i++) {
if (selectDungeon.options[i].value === zone) {
selectDungeon.options[i].selected = true;
break;
}
}
} else {
document.querySelector(`input#simDungeonToggle`).checked = false;
document.querySelector(`input#simDungeonToggle`).dispatchEvent(new Event("change"));
const selectZone = document.querySelector(`select#selectZone`);
for (let i = 0; i < selectZone.options.length; i++) {
if (selectZone.options[i].value === zone) {
selectZone.options[i].selected = true;
break;
}
}
}
}
for (let i = 1; i <= 5; i++) {
if (!battleData[i]) {
battleData[i] = BLANK_PLAYER_JSON_STR;
playerNames[i] = `Player ${i}`;
imported[i] = false;
}
document.querySelector(`a#player${i}-tab`).textContent = playerNames[i];
if (document.querySelector(`input#player${i}.form-check-input.player-checkbox`)) {
document.querySelector(`input#player${i}.form-check-input.player-checkbox`).checked = imported[i];
document.querySelector(`input#player${i}.form-check-input.player-checkbox`).dispatchEvent(new Event("change"));
}
}
document.querySelector(`a#group-combat-tab`).click();
const editImport = document.querySelector(`input#inputSetGroupCombatAll`);
editImport.value = JSON.stringify(battleData);
document.querySelector(`button#buttonImportSet`).click();
// 模拟时长
document.querySelector(`input#inputSimulationTime`).value = 24;
button.textContent = isZH ? "成功导入数据" : "Imported Successful";
button.className = "btn btn-success";
setTimeout(() => {
button.textContent = isZH ? "实时导入数据" : "Real-time Import";
button.className = "btn btn-warning";
}, 1000);
if (!isParty) {
setTimeout(() => {
document.querySelector(`button#buttonStartSimulation`).click();
}, 500);
}
}
// 监听模拟结果
async function observeResultsForMWICombatSimulate() {
let resultDiv = document.querySelector(`div.row`)?.querySelectorAll(`div.col-md-5`)?.[2]?.querySelector(`div.row > div.col-md-5`);
while (!resultDiv) {
await new Promise((resolve) => setTimeout(resolve, 100));
resultDiv = document.querySelector(`div.row`)?.querySelectorAll(`div.col-md-5`)?.[2]?.querySelector(`div.row > div.col-md-5`);
}
const deathDiv = document.querySelector(`div#simulationResultPlayerDeaths`);
const expDiv = document.querySelector(`div#simulationResultExperienceGain`);
const consumeDiv = document.querySelector(`div#simulationResultConsumablesUsed`);
deathDiv.style.backgroundColor = "#FFEAE9";
deathDiv.style.color = "black";
expDiv.style.backgroundColor = "#CDFFDD";
expDiv.style.color = "black";
consumeDiv.style.backgroundColor = "#F0F8FF";
consumeDiv.style.color = "black";
let div = document.createElement("div");
div.id = "tillLevel";
div.style.backgroundColor = "#FFFFE0";
div.style.color = "black";
div.textContent = "";
resultDiv.append(div);
}
// 构建战斗模拟信息(InitData)
function buildBattleObjFromPlayer(obj, init) {
let battleObj = init ? {} : obj.battleObj;
// Base
battleObj.character = {}
battleObj.character.id = obj.character.id;
battleObj.character.name = obj.character.name;
battleObj.character.gameMode = obj.character.gameMode;
battleObj.timestamp = Date.now();
battleObj.valid = true;
if (init) {
// Levels
battleObj.player = {}
for (const skill of obj.characterSkills) {
if (skill.skillHrid.includes("stamina")) {
battleObj.player.staminaLevel = skill.level;
} else if (skill.skillHrid.includes("intelligence")) {
battleObj.player.intelligenceLevel = skill.level;
} else if (skill.skillHrid.includes("attack")) {
battleObj.player.attackLevel = skill.level;
} else if (skill.skillHrid.includes("power")) {
battleObj.player.powerLevel = skill.level;
} else if (skill.skillHrid.includes("defense")) {
battleObj.player.defenseLevel = skill.level;
} else if (skill.skillHrid.includes("ranged")) {
battleObj.player.rangedLevel = skill.level;
} else if (skill.skillHrid.includes("magic")) {
battleObj.player.magicLevel = skill.level;
}
}
// Equipments
battleObj.player.equipment = [];
if (obj.characterItems) {
for (const item of obj.characterItems) {
if (!item.itemLocationHrid.includes("/item_locations/inventory")) {
battleObj.player.equipment.push({
itemLocationHrid: item.itemLocationHrid,
itemHrid: item.itemHrid,
enhancementLevel: item.enhancementLevel,
});
}
}
}
}
// Food
battleObj.food = {}
battleObj.food["/action_types/combat"] = [];
if (obj.actionTypeFoodSlotsMap["/action_types/combat"]) {
for (const food of obj.actionTypeFoodSlotsMap["/action_types/combat"]) {
if (food) {
battleObj.food["/action_types/combat"].push({
itemHrid: food.itemHrid,
});
} else {
battleObj.food["/action_types/combat"].push({
itemHrid: "",
});
}
}
}
// Drinks
battleObj.drinks = {}
battleObj.drinks["/action_types/combat"] = [];
if (obj.actionTypeDrinkSlotsMap["/action_types/combat"]) {
for (const drink of obj.actionTypeDrinkSlotsMap["/action_types/combat"]) {
if (drink) {
battleObj.drinks["/action_types/combat"].push({
itemHrid: drink.itemHrid,
});
} else {
battleObj.drinks["/action_types/combat"].push({
itemHrid: "",
});
}
}
}
// Abilities
battleObj.abilities = [];
for (let i = 0; i < 5; i++) {
battleObj.abilities.push({
abilityHrid: "",
level: "1",
})
}
if (obj.combatUnit.combatAbilities) {
let index = 1;
for (const ability of obj.combatUnit.combatAbilities) {
if (ability && clientData.abilityDetailMap[ability.abilityHrid].isSpecialAbility) {
battleObj.abilities[0] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
} else if (ability) {
battleObj.abilities[index++] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
}
}
}
// TriggerMap
battleObj.triggerMap = { ...obj.abilityCombatTriggersMap, ...obj.consumableCombatTriggersMap };
// HouseRooms
battleObj.houseRooms = {};
if (obj.characterHouseRoomMap) {
for (const house of Object.values(obj.characterHouseRoomMap)) {
battleObj.houseRooms[house.houseRoomHrid] = house.level;
}
}
return battleObj;
}
// 构建战斗模拟信息(ProfileShared)
function buildBattleObjFromProfileShared(player, obj) {
let battleObj = {};
// Base
battleObj.character = {}
battleObj.character.id = player ? player.character.id : obj.profile.characterSkills[0].characterID;
battleObj.character.name = obj.profile.sharableCharacter.name;
battleObj.character.gameMode = obj.profile.sharableCharacter.gameMode;
battleObj.timestamp = Date.now();
battleObj.valid = true;
// Levels
battleObj.player = {}
for (const skill of obj.profile.characterSkills) {
if (skill.skillHrid.includes("stamina")) {
battleObj.player.staminaLevel = skill.level;
} else if (skill.skillHrid.includes("intelligence")) {
battleObj.player.intelligenceLevel = skill.level;
} else if (skill.skillHrid.includes("attack")) {
battleObj.player.attackLevel = skill.level;
} else if (skill.skillHrid.includes("power")) {
battleObj.player.powerLevel = skill.level;
} else if (skill.skillHrid.includes("defense")) {
battleObj.player.defenseLevel = skill.level;
} else if (skill.skillHrid.includes("ranged")) {
battleObj.player.rangedLevel = skill.level;
} else if (skill.skillHrid.includes("magic")) {
battleObj.player.magicLevel = skill.level;
}
}
// Equipments
battleObj.player.equipment = [];
if (obj.profile.wearableItemMap) {
for (const key in obj.profile.wearableItemMap) {
const item = obj.profile.wearableItemMap[key];
battleObj.player.equipment.push({
itemLocationHrid: item.itemLocationHrid,
itemHrid: item.itemHrid,
enhancementLevel: item.enhancementLevel,
});
}
}
// Food and Drinks
battleObj.food = {}
battleObj.food["/action_types/combat"] = [];
battleObj.drinks = {}
battleObj.drinks["/action_types/combat"] = [];
let wearableItemMap = obj.profile.wearableItemMap;
let weapon = null;
if (wearableItemMap) {
weapon = wearableItemMap["/item_locations/main_hand"]?.itemHrid ||
wearableItemMap["/item_locations/two_hand"]?.itemHrid;
}
if (player) {
battleObj.food = player.battleObj.food;
battleObj.drinks = player.battleObj.drinks;
} else if (weapon) {
if (weapon.includes("shooter") || weapon.includes("bow")) {
// 远程
battleObj.food["/action_types/combat"] = [
// 2红1蓝
{ itemHrid: "/items/spaceberry_donut" },
{ itemHrid: "/items/spaceberry_cake" },
{ itemHrid: "/items/star_fruit_yogurt" }
]
battleObj.drinks["/action_types/combat"] = [
// 经验.超远.暴击
{ itemHrid: "/items/wisdom_coffee" },
{ itemHrid: "/items/super_ranged_coffee" },
{ itemHrid: "/items/critical_coffee" }
]
} else if (weapon.includes("boomstick") || weapon.includes("staff") || weapon.includes("trident")) {
// 法师
battleObj.food["/action_types/combat"] = [
// 1红2蓝
{ itemHrid: "/items/spaceberry_cake" },
{ itemHrid: "/items/star_fruit_gummy" },
{ itemHrid: "/items/star_fruit_yogurt" }
]
battleObj.drinks["/action_types/combat"] = [
// 经验.超魔.吟唱
{ itemHrid: "/items/wisdom_coffee" },
{ itemHrid: "/items/super_magic_coffee" },
{ itemHrid: "/items/channeling_coffee" }
]
} else if (weapon.includes("bulwark")) {
// 双手盾
battleObj.food["/action_types/combat"] = [
// 2红1蓝
{ itemHrid: "/items/spaceberry_donut" },
{ itemHrid: "/items/spaceberry_cake" },
{ itemHrid: "/items/star_fruit_yogurt" }
]
battleObj.drinks["/action_types/combat"] = [
// 经验.超防.超耐
{ itemHrid: "/items/wisdom_coffee" },
{ itemHrid: "/items/super_defense_coffee" },
{ itemHrid: "/items/super_stamina_coffee" }
]
} else {
// 近战
battleObj.food["/action_types/combat"] = [
// 2红1蓝
{ itemHrid: "/items/spaceberry_donut" },
{ itemHrid: "/items/spaceberry_cake" },
{ itemHrid: "/items/star_fruit_yogurt" }
]
battleObj.drinks["/action_types/combat"] = [
// 经验.超力.迅捷
{ itemHrid: "/items/wisdom_coffee" },
{ itemHrid: "/items/super_power_coffee" },
{ itemHrid: "/items/swiftness_coffee" }
]
}
}
// Abilities
battleObj.abilities = [];
for (let i = 0; i < 5; i++) {
battleObj.abilities.push({
abilityHrid: "",
level: "1",
})
}
if (obj.profile.equippedAbilities) {
let index = 1;
for (const ability of obj.profile.equippedAbilities) {
if (ability && clientData.abilityDetailMap[ability.abilityHrid].isSpecialAbility) {
battleObj.abilities[0] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
} else if (ability) {
battleObj.abilities[index++] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
}
}
}
// TriggerMap
if (player) {
battleObj.triggerMap = player.battleObj.triggerMap;
}
// HouseRooms
battleObj.houseRooms = {};
for (const house of Object.values(obj.profile.characterHouseRoomMap)) {
battleObj.houseRooms[house.houseRoomHrid] = house.level;
}
return battleObj;
}
// 构建战斗模拟信息(NewBattle)
function buildBattleObjFromNewBattle(player, obj) {
let battleObj = {};
if (player) {
battleObj = player.battleObj;
}
// Base
battleObj.character = battleObj.character ?? {};
battleObj.character.id = obj.character.id;
battleObj.character.name = obj.character.name;
battleObj.character.gameMode = obj.character.gameMode;
battleObj.timestamp = Date.now();
battleObj.valid = battleObj.valid;
// Levels
battleObj.player = battleObj.player ?? {};
battleObj.player.staminaLevel = battleObj.player.staminaLevel ?? 1;
battleObj.player.intelligenceLevel = battleObj.player.intelligenceLevel ?? 1;
battleObj.player.attackLevel = battleObj.player.attackLevel ?? 1;
battleObj.player.powerLevel = battleObj.player.powerLevel ?? 1;
battleObj.player.defenseLevel = battleObj.player.defenseLevel ?? 1;
battleObj.player.rangedLevel = battleObj.player.rangedLevel ?? 1;
battleObj.player.magicLevel = battleObj.player.magicLevel ?? 1;
// Equipments
battleObj.player.equipment = battleObj.player.equipment ?? [];
// Food and Drinks
battleObj.food = {};
battleObj.food["/action_types/combat"] = [];
battleObj.drinks = {};
battleObj.drinks["/action_types/combat"] = [];
if (obj.combatConsumables) {
for (const consumable of obj.combatConsumables) {
if (consumable.itemHrid.includes("coffee")) {
battleObj.drinks["/action_types/combat"].push({
itemHrid: consumable.itemHrid
})
} else {
battleObj.food["/action_types/combat"].push({
itemHrid: consumable.itemHrid
})
}
}
}
// Abilities
battleObj.abilities = [];
for (let i = 0; i < 5; i++) {
battleObj.abilities.push({
abilityHrid: "",
level: "1",
})
}
if (obj.combatAbilities) {
let index = 1;
for (const ability of obj.combatAbilities) {
if (ability && clientData.abilityDetailMap[ability.abilityHrid].isSpecialAbility) {
battleObj.abilities[0] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
} else if (ability) {
battleObj.abilities[index++] = {
abilityHrid: ability.abilityHrid,
level: ability.level,
experience: ability.experience,
availableTime: ability.updatedAt
};
}
}
}
// TriggerMap
battleObj.triggerMap = { ...battleObj.triggerMap };
// HouseRooms
battleObj.houseRooms = { ...battleObj.houseRooms };
return battleObj;
}
if (localStorage.getItem("initClientData")) {
const obj = JSON.parse(localStorage.getItem("initClientData"));
GM_setValue("init_client_data", localStorage.getItem("initClientData"));
clientData.actionDetailMap = obj.actionDetailMap;
clientData.levelExperienceTable = obj.levelExperienceTable;
clientData.itemDetailMap = obj.itemDetailMap;
clientData.actionCategoryDetailMap = obj.actionCategoryDetailMap;
clientData.abilityDetailMap = obj.abilityDetailMap;
}
if (document.URL.includes("/MWICombatSimulatorTest/dist")) {
addImportButtonForMWICombatSimulate();
observeResultsForMWICombatSimulate();
}
hookWS();
})();