feat(webui): boosters (#2140)
Co-authored-by: ny <64143453+nyaoouo@users.noreply.github.com> Co-authored-by: nyaoouo <64143453+nyaoouo@users.noreply.github.com> Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Reviewed-on: #2140 Co-authored-by: nyaoouo <nyaoouo@noreply.localhost> Co-committed-by: nyaoouo <nyaoouo@noreply.localhost>
This commit is contained in:
		
							parent
							
								
									1d813a1b1b
								
							
						
					
					
						commit
						62d4b9f6cb
					
				@ -3,6 +3,7 @@ import { getDict, getItemName, getString } from "@/src/services/itemDataService"
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
    ExportArcanes,
 | 
					    ExportArcanes,
 | 
				
			||||||
    ExportAvionics,
 | 
					    ExportAvionics,
 | 
				
			||||||
 | 
					    ExportBoosters,
 | 
				
			||||||
    ExportCustoms,
 | 
					    ExportCustoms,
 | 
				
			||||||
    ExportDrones,
 | 
					    ExportDrones,
 | 
				
			||||||
    ExportGear,
 | 
					    ExportGear,
 | 
				
			||||||
@ -55,6 +56,7 @@ interface ItemLists {
 | 
				
			|||||||
    KubrowPets: ListedItem[];
 | 
					    KubrowPets: ListedItem[];
 | 
				
			||||||
    EvolutionProgress: ListedItem[];
 | 
					    EvolutionProgress: ListedItem[];
 | 
				
			||||||
    mods: ListedItem[];
 | 
					    mods: ListedItem[];
 | 
				
			||||||
 | 
					    Boosters: ListedItem[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
 | 
					const relicQualitySuffixes: Record<TRelicQuality, string> = {
 | 
				
			||||||
@ -86,7 +88,8 @@ const getItemListsController: RequestHandler = (req, response) => {
 | 
				
			|||||||
        QuestKeys: [],
 | 
					        QuestKeys: [],
 | 
				
			||||||
        KubrowPets: [],
 | 
					        KubrowPets: [],
 | 
				
			||||||
        EvolutionProgress: [],
 | 
					        EvolutionProgress: [],
 | 
				
			||||||
        mods: []
 | 
					        mods: [],
 | 
				
			||||||
 | 
					        Boosters: []
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
 | 
					    for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
 | 
				
			||||||
        res[item.productCategory].push({
 | 
					        res[item.productCategory].push({
 | 
				
			||||||
@ -296,6 +299,13 @@ const getItemListsController: RequestHandler = (req, response) => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const item of Object.values(ExportBoosters)) {
 | 
				
			||||||
 | 
					        res.Boosters.push({
 | 
				
			||||||
 | 
					            uniqueName: item.typeName,
 | 
				
			||||||
 | 
					            name: getString(item.name, lang)
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    response.json(res);
 | 
					    response.json(res);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										45
									
								
								src/controllers/custom/setBoosterController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/controllers/custom/setBoosterController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { getInventory } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { ExportBoosters } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const I32_MAX = 0x7fffffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const setBoosterController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const requests = req.body as { ItemType: string; ExpiryDate: number }[];
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId, "Boosters");
 | 
				
			||||||
 | 
					    const boosters = inventory.Boosters;
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					        requests.some(request => {
 | 
				
			||||||
 | 
					            if (typeof request.ItemType !== "string") return true;
 | 
				
			||||||
 | 
					            if (Object.entries(ExportBoosters).find(([_, item]) => item.typeName === request.ItemType) === undefined)
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            if (typeof request.ExpiryDate !== "number") return true;
 | 
				
			||||||
 | 
					            if (request.ExpiryDate < 0 || request.ExpiryDate > I32_MAX) return true;
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        res.status(400).send("Invalid ItemType provided.");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const now = Math.floor(Date.now() / 1000);
 | 
				
			||||||
 | 
					    for (const { ItemType, ExpiryDate } of requests) {
 | 
				
			||||||
 | 
					        if (ExpiryDate < now) {
 | 
				
			||||||
 | 
					            // remove expired boosters
 | 
				
			||||||
 | 
					            const index = boosters.findIndex(item => item.ItemType === ItemType);
 | 
				
			||||||
 | 
					            if (index !== -1) {
 | 
				
			||||||
 | 
					                boosters.splice(index, 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            const boosterItem = boosters.find(item => item.ItemType === ItemType);
 | 
				
			||||||
 | 
					            if (boosterItem) {
 | 
				
			||||||
 | 
					                boosterItem.ExpiryDate = ExpiryDate;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                boosters.push({ ItemType, ExpiryDate });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    res.end();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -23,6 +23,7 @@ import { setEvolutionProgressController } from "@/src/controllers/custom/setEvol
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
 | 
					import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
 | 
				
			||||||
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
 | 
					import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
 | 
				
			||||||
 | 
					import { setBoosterController } from "../controllers/custom/setBoosterController";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const customRouter = express.Router();
 | 
					const customRouter = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,6 +47,7 @@ customRouter.post("/addXp", addXpController);
 | 
				
			|||||||
customRouter.post("/import", importController);
 | 
					customRouter.post("/import", importController);
 | 
				
			||||||
customRouter.post("/manageQuests", manageQuestsController);
 | 
					customRouter.post("/manageQuests", manageQuestsController);
 | 
				
			||||||
customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
 | 
					customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
 | 
				
			||||||
 | 
					customRouter.post("/setBooster", setBoosterController);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
customRouter.get("/config", getConfigDataController);
 | 
					customRouter.get("/config", getConfigDataController);
 | 
				
			||||||
customRouter.post("/config", updateConfigDataController);
 | 
					customRouter.post("/config", updateConfigDataController);
 | 
				
			||||||
 | 
				
			|||||||
@ -416,6 +416,20 @@
 | 
				
			|||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div class="col-lg-6">
 | 
				
			||||||
 | 
					                        <div class="card mb-3" style="height: 400px;">
 | 
				
			||||||
 | 
					                            <h5 class="card-header" data-loc="inventory_Boosters"></h5>
 | 
				
			||||||
 | 
					                            <div class="card-body overflow-auto">
 | 
				
			||||||
 | 
					                                <form class="input-group mb-3" onsubmit="doAcquireBoosters();return false;">
 | 
				
			||||||
 | 
					                                    <input class="form-control" id="acquire-type-Boosters" list="datalist-Boosters" />
 | 
				
			||||||
 | 
					                                    <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
 | 
				
			||||||
 | 
					                                </form>
 | 
				
			||||||
 | 
					                                <table class="table table-hover w-100">
 | 
				
			||||||
 | 
					                                    <tbody id="Boosters-list"></tbody>
 | 
				
			||||||
 | 
					                                </table>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="card mb-3">
 | 
					                <div class="card mb-3">
 | 
				
			||||||
                    <h5 class="card-header" data-loc="general_bulkActions"></h5>
 | 
					                    <h5 class="card-header" data-loc="general_bulkActions"></h5>
 | 
				
			||||||
@ -804,6 +818,7 @@
 | 
				
			|||||||
    <datalist id="datalist-ModularParts-CATBROW_MUTAGEN"></datalist>
 | 
					    <datalist id="datalist-ModularParts-CATBROW_MUTAGEN"></datalist>
 | 
				
			||||||
    <datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
 | 
					    <datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
 | 
				
			||||||
    <datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
 | 
					    <datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
 | 
				
			||||||
 | 
					    <datalist id="datalist-Boosters"></datalist>
 | 
				
			||||||
    <script src="/webui/libs/jquery-3.6.0.min.js"></script>
 | 
					    <script src="/webui/libs/jquery-3.6.0.min.js"></script>
 | 
				
			||||||
    <script src="/webui/libs/whirlpool-js.min.js"></script>
 | 
					    <script src="/webui/libs/whirlpool-js.min.js"></script>
 | 
				
			||||||
    <script src="/webui/libs/single.js"></script>
 | 
					    <script src="/webui/libs/single.js"></script>
 | 
				
			||||||
 | 
				
			|||||||
@ -1011,6 +1011,63 @@ function updateInventory() {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            document.getElementById("changeSyndicate").value = data.SupportedSyndicate ?? "";
 | 
					            document.getElementById("changeSyndicate").value = data.SupportedSyndicate ?? "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            document.getElementById("Boosters-list").innerHTML = "";
 | 
				
			||||||
 | 
					            const now = Math.floor(Date.now() / 1000);
 | 
				
			||||||
 | 
					            data.Boosters.forEach(({ ItemType, ExpiryDate }) => {
 | 
				
			||||||
 | 
					                if (ExpiryDate < now) {
 | 
				
			||||||
 | 
					                    // Booster has expired, skip it
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                const tr = document.createElement("tr");
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const td = document.createElement("td");
 | 
				
			||||||
 | 
					                    td.textContent = itemMap[ItemType]?.name ?? ItemType;
 | 
				
			||||||
 | 
					                    tr.appendChild(td);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    const td = document.createElement("td");
 | 
				
			||||||
 | 
					                    td.classList = "text-end text-nowrap";
 | 
				
			||||||
 | 
					                    const timeString = formatDatetime("%Y-%m-%d %H:%M:%s", ExpiryDate * 1000);
 | 
				
			||||||
 | 
					                    const inlineForm = document.createElement("form");
 | 
				
			||||||
 | 
					                    const input = document.createElement("input");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    inlineForm.style.display = "inline-block";
 | 
				
			||||||
 | 
					                    inlineForm.onsubmit = function (event) {
 | 
				
			||||||
 | 
					                        event.preventDefault();
 | 
				
			||||||
 | 
					                        doChangeBoosterExpiry(ItemType, input);
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    input.type = "datetime-local";
 | 
				
			||||||
 | 
					                    input.classList.add("form-control");
 | 
				
			||||||
 | 
					                    input.classList.add("form-control-sm");
 | 
				
			||||||
 | 
					                    input.value = timeString;
 | 
				
			||||||
 | 
					                    let changed = false;
 | 
				
			||||||
 | 
					                    input.onchange = function () {
 | 
				
			||||||
 | 
					                        changed = true;
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    input.onblur = function () {
 | 
				
			||||||
 | 
					                        if (changed) {
 | 
				
			||||||
 | 
					                            doChangeBoosterExpiry(ItemType, input);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    inlineForm.appendChild(input);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    td.appendChild(inlineForm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const removeButton = document.createElement("a");
 | 
				
			||||||
 | 
					                    removeButton.title = loc("code_remove");
 | 
				
			||||||
 | 
					                    removeButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
 | 
				
			||||||
 | 
					                    removeButton.href = "#";
 | 
				
			||||||
 | 
					                    removeButton.onclick = function (event) {
 | 
				
			||||||
 | 
					                        event.preventDefault();
 | 
				
			||||||
 | 
					                        setBooster(ItemType, 0);
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    td.appendChild(removeButton);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    tr.appendChild(td);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                document.getElementById("Boosters-list").appendChild(tr);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -2027,3 +2084,77 @@ function handleModularSelection(category) {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function setBooster(ItemType, ExpiryDate, callback) {
 | 
				
			||||||
 | 
					    revalidateAuthz(() => {
 | 
				
			||||||
 | 
					        $.post({
 | 
				
			||||||
 | 
					            url: "/custom/setBooster?" + window.authz,
 | 
				
			||||||
 | 
					            contentType: "application/json",
 | 
				
			||||||
 | 
					            data: JSON.stringify([
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    ItemType,
 | 
				
			||||||
 | 
					                    ExpiryDate
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ])
 | 
				
			||||||
 | 
					        }).done(function () {
 | 
				
			||||||
 | 
					            updateInventory();
 | 
				
			||||||
 | 
					            if (callback) callback();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function doAcquireBoosters() {
 | 
				
			||||||
 | 
					    const uniqueName = getKey(document.getElementById("acquire-type-Boosters"));
 | 
				
			||||||
 | 
					    if (!uniqueName) {
 | 
				
			||||||
 | 
					        $("#acquire-type-Boosters").addClass("is-invalid").focus();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const ExpiryDate = Date.now() / 1000 + 3 * 24 * 60 * 60; // default 3 days
 | 
				
			||||||
 | 
					    setBooster(uniqueName, ExpiryDate, () => {
 | 
				
			||||||
 | 
					        $("#acquire-type-Boosters").val("");
 | 
				
			||||||
 | 
					        updateInventory();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function doChangeBoosterExpiry(ItemType, ExpiryDateInput) {
 | 
				
			||||||
 | 
					    console.log("Changing booster expiry for", ItemType, "to", ExpiryDateInput.value);
 | 
				
			||||||
 | 
					    // cast local datetime string to unix timestamp
 | 
				
			||||||
 | 
					    const ExpiryDate = new Date(ExpiryDateInput.value).getTime() / 1000;
 | 
				
			||||||
 | 
					    if (isNaN(ExpiryDate)) {
 | 
				
			||||||
 | 
					        ExpiryDateInput.addClass("is-invalid").focus();
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    setBooster(ItemType, ExpiryDate);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function formatDatetime(fmt, date) {
 | 
				
			||||||
 | 
					    if (typeof date === "number") date = new Date(date);
 | 
				
			||||||
 | 
					    return fmt.replace(/(%[yY]|%m|%[Dd]|%H|%h|%M|%[Ss]|%[Pp])/g, match => {
 | 
				
			||||||
 | 
					        switch (match) {
 | 
				
			||||||
 | 
					            case "%Y":
 | 
				
			||||||
 | 
					                return date.getFullYear().toString();
 | 
				
			||||||
 | 
					            case "%y":
 | 
				
			||||||
 | 
					                return date.getFullYear().toString().slice(-2);
 | 
				
			||||||
 | 
					            case "%m":
 | 
				
			||||||
 | 
					                return (date.getMonth() + 1).toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%D":
 | 
				
			||||||
 | 
					            case "%d":
 | 
				
			||||||
 | 
					                return date.getDate().toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%H":
 | 
				
			||||||
 | 
					                return date.getHours().toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%h":
 | 
				
			||||||
 | 
					                return (date.getHours() % 12).toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%M":
 | 
				
			||||||
 | 
					                return date.getMinutes().toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%S":
 | 
				
			||||||
 | 
					            case "%s":
 | 
				
			||||||
 | 
					                return date.getSeconds().toString().padStart(2, "0");
 | 
				
			||||||
 | 
					            case "%P":
 | 
				
			||||||
 | 
					            case "%p":
 | 
				
			||||||
 | 
					                return date.getHours() < 12 ? "am" : "pm";
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return match;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
 | 
					    inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `[UNTRANSLATED] Boosters`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `Quests`,
 | 
					    quests_list: `Quests`,
 | 
				
			||||||
    quests_completeAll: `Alle Quests abschließen`,
 | 
					    quests_completeAll: `Alle Quests abschließen`,
 | 
				
			||||||
 | 
				
			|||||||
@ -97,6 +97,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
 | 
					    inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `Boosters`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `Quests`,
 | 
					    quests_list: `Quests`,
 | 
				
			||||||
    quests_completeAll: `Complete All Quests`,
 | 
					    quests_completeAll: `Complete All Quests`,
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
 | 
					    inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `[UNTRANSLATED] Boosters`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `Misiones`,
 | 
					    quests_list: `Misiones`,
 | 
				
			||||||
    quests_completeAll: `Completar todas las misiones`,
 | 
					    quests_completeAll: `Completar todas las misiones`,
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
 | 
					    inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `[UNTRANSLATED] Boosters`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `Quêtes`,
 | 
					    quests_list: `Quêtes`,
 | 
				
			||||||
    quests_completeAll: `Compléter toutes les quêtes`,
 | 
					    quests_completeAll: `Compléter toutes les quêtes`,
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
 | 
					    inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `[UNTRANSLATED] Boosters`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `Квесты`,
 | 
					    quests_list: `Квесты`,
 | 
				
			||||||
    quests_completeAll: `Завершить все квесты`,
 | 
					    quests_completeAll: `Завершить все квесты`,
 | 
				
			||||||
 | 
				
			|||||||
@ -98,6 +98,7 @@ dict = {
 | 
				
			|||||||
    inventory_bulkRankUpSentinels: `所有守护升满级`,
 | 
					    inventory_bulkRankUpSentinels: `所有守护升满级`,
 | 
				
			||||||
    inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
 | 
					    inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
 | 
				
			||||||
    inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`,
 | 
					    inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`,
 | 
				
			||||||
 | 
					    inventory_Boosters: `加成器`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    quests_list: `任务`,
 | 
					    quests_list: `任务`,
 | 
				
			||||||
    quests_completeAll: `完成所有任务`,
 | 
					    quests_completeAll: `完成所有任务`,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user