diff --git a/.eslintrc.json b/.eslintrc.json index f0d2bdc86..fde84ce4b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,16 +2,19 @@ "extends": "eslint:recommended", "env": { "browser": true, - "node": true, "es6": true, + "node": true, + "serviceworker": true, "worker": true }, "rules": { "no-console": 0, - "no-unused-vars": 0, - "no-undef": 0, - "no-redeclare": 0, - "require-yield": 0, + "no-constant-condition": [ + "error", + { + "checkLoops": false + } + ], "no-irregular-whitespace": [ "error", { @@ -19,13 +22,13 @@ "skipTemplates": true } ], - "no-constant-condition": [ - "error", - { - "checkLoops": false - } - ] /* , - "comma-dangle": ["error", "only-multiline"], - "complexity": ["error",100] */ + "no-redeclare": 0, + "no-undef": 0, + "no-unused-vars": 0, + "require-yield": 0 + }, + "parserOptions": { + "ecmaVersion": 13, + "sourceType": "module" } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 576ce9437..41a5761d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,25 @@ +!extension/boss +!extension/cardpile +!extension/coin +!extension/wuxing +!node_modules/options +!node_modules/ultron +!node_modules/ws +._* .DS_Store .DS_Store? -._* +.idea .Spotlight-V100 .Trashes -ehthumbs.db -Thumbs.db -localStorage.json .vscode -.idea +app +app.html +ehthumbs.db +extension +jsconfig.json +localStorage.json +main.js +node_modules +noname.ico +package.json +Thumbs.db diff --git a/noname.js b/noname.js new file mode 100644 index 000000000..e69de29bb diff --git a/noname/ai.js b/noname/ai.js new file mode 100644 index 000000000..69a980d9a --- /dev/null +++ b/noname/ai.js @@ -0,0 +1,7 @@ +import { Basic } from "./ai/basic.js"; +import { Get } from "./get.js"; + +export const ai = { + basic: Basic, + get: Get +}; diff --git a/noname/ai/basic.js b/noname/ai/basic.js new file mode 100644 index 000000000..739447fb1 --- /dev/null +++ b/noname/ai/basic.js @@ -0,0 +1,190 @@ +import { Game } from "../game.js"; +import { Get } from "../get.js"; +import { status } from "../status.js"; +import { Click } from "../ui/click.js"; +import { selected } from "../ui/selected.js"; + +export class Basic { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static chooseButton(check) { + var event = status.event; + var i, j, range, buttons, buttons2; + var ok = false, forced = event.forced; + var iwhile = 100; + while (iwhile--) { + range = Get.select(event.selectButton); + if (selected.buttons.length >= range[0]) { + ok = true; + } + if (range[1] <= -1) { + j = 0; + for (i = 0; i < selected.buttons.length; i++) { + j += check(selected.buttons[i]); + } + return (j > 0); + } + buttons = Get.selectableButtons(); + if (buttons.length == 0) { + return ok; + } + buttons2 = buttons.slice(0); + var ix = 0; + var checkix = check(buttons[0], buttons2); + for (i = 1; i < buttons.length; i++) { + var checkixtmp = check(buttons[i], buttons2); + if (checkixtmp > checkix) { + ix = i; + checkix = checkixtmp; + } + } + // buttons.sort(function(a,b){ + // return check(b,buttons2)-check(a,buttons2); + // }); + if (check(buttons[ix]) <= 0) { + if (!forced || ok) { + return ok; + } + } + buttons[ix].classList.add('selected'); + selected.buttons.add(buttons[ix]); + Game.check(); + if (selected.buttons.length >= range[0]) { + ok = true; + } + if (selected.buttons.length == range[1]) { + return true; + } + } + } + + static chooseCard(check) { + var event = status.event; + if (event.filterCard == undefined) return (check() > 0); + var i, j, range, cards, cards2, skills, check, effect; + var ok = false, forced = event.forced; + var iwhile = 100; + while (iwhile--) { + range = Get.select(event.selectCard); + if (selected.cards.length >= range[0]) { + ok = true; + } + if (range[1] <= -1) { + if (selected.cards.length == 0) return true; + j = 0; + for (i = 0; i < selected.cards.length; i++) { + effect = check(selected.cards[i]); + if (effect < 0) j -= Math.sqrt(-effect); + else j += Math.sqrt(effect); + } + return (j > 0); + } + cards = Get.selectableCards(); + if (!status.event.player._noSkill) { + cards = cards.concat(Get.skills()); + } + if (cards.length == 0) { + return ok; + } + cards2 = cards.slice(0); + // cards.sort(function(a,b){ + // return (check(b,cards2)-check(a,cards2)); + // }); + var ix = 0; + var checkix = check(cards[0], cards2); + for (i = 1; i < cards.length; i++) { + var checkixtmp = check(cards[i], cards2); + if (checkixtmp > checkix) { + ix = i; + checkix = checkixtmp; + } + } + if (check(cards[ix]) <= 0) { + if (!forced || ok) { + return ok; + } + } + if (typeof cards[ix] == 'string') { + Click.skill(cards[ix]); + var info = Get.info(event.skill); + if (info.filterCard) { + check = info.check || Get.unuseful2; + return (this.chooseCard(check)); + } + else { + return true; + } + } + else { + cards[ix].classList.add('selected'); + selected.cards.add(cards[ix]); + Game.check(); + if (selected.cards.length >= range[0]) { + ok = true; + } + if (selected.cards.length == range[1]) { + return true; + } + } + } + } + + static chooseTarget(check) { + var event = status.event; + if (event.filterTarget == undefined) return (check() > 0); + var i, j, range, targets, targets2, effect; + var ok = false, forced = event.forced; + var iwhile = 100; + while (iwhile--) { + range = Get.select(event.selectTarget); + if (selected.targets.length >= range[0]) { + ok = true; + } + if (range[1] <= -1) { + j = 0; + for (i = 0; i < selected.targets.length; i++) { + effect = check(selected.targets[i]); + if (effect < 0) j -= Math.sqrt(-effect); + else j += Math.sqrt(effect); + } + return (j > 0); + } + else if (range[1] == 0) { + return check() > 0 + } + targets = Get.selectableTargets(); + if (targets.length == 0) { + return range[0] == 0 || ok; + } + targets2 = targets.slice(0); + // targets.sort(function(a,b){ + // return check(b)-check(a); + // }); + var ix = 0; + var checkix = check(targets[0], targets2); + for (i = 1; i < targets.length; i++) { + var checkixtmp = check(targets[i], targets2); + if (checkixtmp > checkix) { + ix = i; + checkix = checkixtmp; + } + } + if (check(targets[ix]) <= 0) { + if (!forced || ok) { + return ok; + } + } + targets[ix].classList.add('selected'); + selected.targets.add(targets[ix]); + Game.check(); + if (selected.targets.length >= range[0]) { + ok = true; + } + if (selected.targets.length == range[1]) { + return true; + } + } + } +} diff --git a/noname/game-status/ai.d.ts b/noname/game-status/ai.d.ts new file mode 100644 index 000000000..614bad741 --- /dev/null +++ b/noname/game-status/ai.d.ts @@ -0,0 +1,7 @@ +import { Player } from "../library/element/player.js"; + +interface AI extends Record { + customAttitude: ((from: Player, to: Player) => number)[]; +} + +export const ai: AI; diff --git a/noname/game-status/ai.js b/noname/game-status/ai.js new file mode 100644 index 000000000..746fcf74d --- /dev/null +++ b/noname/game-status/ai.js @@ -0,0 +1,3 @@ +export const ai = { + customAttitude: [] +}; diff --git a/noname/game-status/card-tag.d.ts b/noname/game-status/card-tag.d.ts new file mode 100644 index 000000000..2b7a904dd --- /dev/null +++ b/noname/game-status/card-tag.d.ts @@ -0,0 +1,4 @@ +interface CardTag extends Record { +} + +export const cardTag: CardTag; diff --git a/noname/game-status/card-tag.js b/noname/game-status/card-tag.js new file mode 100644 index 000000000..6006ca59e --- /dev/null +++ b/noname/game-status/card-tag.js @@ -0,0 +1,7 @@ +export const cardTag = { + yingbian_zhuzhan: [], + yingbian_kongchao: [], + yingbian_fujia: [], + yingbian_canqu: [], + yingbian_force: [] +}; diff --git a/noname/game-status/global-history.d.ts b/noname/game-status/global-history.d.ts new file mode 100644 index 000000000..d93c2ca1e --- /dev/null +++ b/noname/game-status/global-history.d.ts @@ -0,0 +1,9 @@ +import { GameEvent } from "../library/element/game-event"; + +export interface GlobalHistory { + cardMove: GameEvent[]; + custom: unknown[]; + useCard: GameEvent[]; + changeHp: GameEvent[]; + everything: GameEvent[]; +} diff --git a/noname/game-status/post-reconnect.js b/noname/game-status/post-reconnect.js new file mode 100644 index 000000000..81d5bfa86 --- /dev/null +++ b/noname/game-status/post-reconnect.js @@ -0,0 +1 @@ +export const postReconnect = {}; diff --git a/noname/game.js b/noname/game.js new file mode 100644 index 000000000..42dc0c8b0 --- /dev/null +++ b/noname/game.js @@ -0,0 +1,8022 @@ +export class Game { + static promises = { + /** + * 模仿h5的prompt,用于显示可提示用户进行输入的对话框 + * + * 注: 由于参数列表是随意的,在这里我准备限制一下这个函数的参数顺序 + * + * @type {{ + * (title: string, forced?: boolean): Promise; + * (alertOption: "alert", title: string, forced?: boolean): Promise; + * }} + * + * @param { string } title 设置prompt标题与input内容 + * @param { boolean } [forced] 为true的话将没有"取消按钮" + * @param { string } alertOption 设置prompt是否模拟alert + * @example + * ```js + * // 只设置标题(但是input的初始值就变成了undefined) + * game.promises.prompt("###prompt标题").then(value => console.log(value)); + * // 设置标题和input初始内容 + * game.promises.prompt("###prompt标题###input初始内容").then(value => console.log(value)); + * ``` + * @returns { Promise } + */ + prompt(alertOption, title, forced) { + return new Promise((resolve, reject) => { + if (alertOption != "alert") { + forced = title || false; + title = option; + game.prompt(title, forced, resolve); + } else { + game.prompt(alertOption, title, forced, resolve); + } + }); + }, + /** + * 模仿h5的alert,用于显示信息的对话框 + * + * @param { string } title + * @example + * ```js + * await game.promises.alert("弹窗内容"); + * ``` + * @returns { Promise } + */ + alert(title) { + return new Promise((resolve, reject) => { + game.prompt("alert", title, resolve); + }); + }, + // 读写函数promises化(不用考虑其对应函数是否存在) + download(url, folder, dev, onprogress) { + return new Promise((resolve, reject) => { + game.download(url, folder, resolve, reject, dev, onprogress); + }); + }, + readFile(filename) { + return new Promise((resolve, reject) => { + game.readFile(filename, resolve, reject); + }); + }, + readFileAsText(filename) { + return new Promise((resolve, reject) => { + game.readFileAsText(filename, resolve, reject); + }); + }, + writeFile(data, path, name) { + return (new Promise((resolve, reject) => { + game.writeFile(data, path, name, resolve); + })).then(result => { + return new Promise((resolve, reject) => { + if (result instanceof Error) { + reject(result); + } else { + resolve(result); + } + }); + }); + }, + ensureDirectory(list, callback, file) { + return new Promise((resolve, reject) => { + game.ensureDirectory(list, callback, file).then(resolve).catch(reject); + }); + }, + createDir(directory) { + return new Promise((resolve, reject) => { + game.createDir(directory, resolve, reject); + }); + }, + } + static globalEventHandlers = new class { + constructor() { + this._handlers = {}; + } + + getHandler(name, type) { + if (!type) + type = this.getDefaultHandlerType(name); + if (!this._handlers[name]) + return null; + if (!this._handlers[name][type]) + return null; + return this._handlers[name][type]; + } + + ensureHandlerList(name, type) { + if (!type) + type = this.getDefaultHandlerType(name); + if (!this._handlers[name]) + this._handlers[name] = {}; + if (!this._handlers[name][type]) + this._handlers[name][type] = []; + return this._handlers[name][type]; + } + + removeHandler(name, type, func) { + const list = this.ensureHandlerList(name, type); + list.remove(func); + if (list.length == 0) { + delete this._handlers[name][type]; + if (Object.keys(this._handlers[name]).length == 0) { + delete this._handlers[name]; + } + } + } + + pushHandler(name, type) { + const args = Array.from(arguments); + const functions = (typeof type == "string" ? args.slice(2) : args.slice(1)); + type = (typeof type == "string" ? type : this.getDefaultHandlerType(name)); + this.ensureHandlerList(name, type).addArray(functions); + } + + getDefaultHandlerType(name) { + return `on${name[0].toUpperCase()}${name.slice(1)}`; + } + + addHandlerToEvent(event) { + if (typeof event.name != "string") return; + const handlerMap = this._handlers[event.name]; + if (!handlerMap) return; + Object.keys(handlerMap).forEach((key) => { + const list = handlerMap[key]; + if (!list) return; + list.forEach((handler) => { + event.pushHandler(key, handler); + }); + }); + } + } + /** + * Dynamic Style Manager + * 动态CSS管理对象 + * + * > No idea to write, it’s just a tool to handle css. + * > 暂时不知道写啥,反正就是个管CSS的工具 + * + * @example + * // 为符合".content"的元素增加"text-align: center"的样式 + * game.dynamicStyle.add(".content", { + * textAlign: "center" + * }); + * + * // 在上一条的基础上,再为".content"增加"color: #FFFFFF"的样式 + * game.dynamicStyle.add(".content", { + * color: "#FFFFFF" + * }); + * + * @example + * // 批量添加符合对应选择器元素的样式 + * game.dynamicStyle.addObject({ + * ".content": { + * textAlign: "center" + * }, + * ".ansory": { + * fontSize: "16px" + * } + * }); + * + * @example + * // 移除".content"元素的样式 + * game.dynamicStyle.remove(".content"); + * + * @example + * // 移除".content"元素的"textAlign"样式 + * game.dynamicStyle.removeStyles(".content", ["textAligh"]); + * + * @example + * // 如果".content"元素的样式存在,则将".content"的样式修改为给定的样式 + * // 反之效果同`game.dynamicStyle.add` + * game.dynamicStyle.update(".content", { + * textAlign: "center" + * }); + */ + static dynamicStyle = new class { + /** + * Object of style + * 表示样式的对象 + * + * @typedef {Record} StyleObject + */ + /** + * Rule to record style info. + * 用于记录样式信息的规则 + * + * @typedef {[string, StyleObject]} Rule + */ + /** + * Type used to declare the place to store css info. + * 用来存CSS信息的空间的类型 + * + * @typedef {object} DynamicStyleCache + * @property {Rule[]} rules 记录的规则 + * @property {HTMLStyleElement} style 全局Style标签 + * @property {CSSStyleSheet} sheet Style标签的Sheet + */ + + /** + * Initialize dynamicStyle. + * 初始化数据 + */ + constructor() { + /** + * @type {DynamicStyleCache} + */ + let cache = Object.create(null); + cache.rules = new Array; + cache.style = document.createElement("style"); + cache.style.id = "game.dynamicStyle"; + document.head.appendChild(cache.style); + cache.sheet = cache.style.sheet; + /** + * Place to store css info. + * 存CSS信息的空间 + * + * @type {DynamicStyleCache} + */ + this._cache = cache; + } + + /** + * Turn the Object Style to string format. + * 将给定的对象样式转换成字符串的形式 + * + * @param {StyleObject} style 给定的对象样式 + * @returns {string} 样式的字符串形式 + */ + translate(style) { + return Object.entries(style).map(item => + `${item[0].replace(/([A-Z])/g, match => + `-${match.toLowerCase()}`)}: ${item[1]};`).join(" "); + } + + /** + * Generate the common css selector. + * 生成标准的CSS样式 + * + * @param {string} name 选择器 + * @param {StyleObject} style 对象样式 + * @returns {string} 标准的CSS样式 + */ + generate(name, style) { + return `${name} { ${this.translate(style)} }`; + } + + /** + * Determine the selector is in rules. + * 检查是否存在对应选择器的规则 + * + * @param {string} name 选择器 + * @returns {boolean} + */ + has(name) { + return this._cache.rules.some(item => item[0] == name); + } + + /** + * Get the style of given selector, or return null. + * 获得对应选择器的样式对象,若不存在,则返回`null` + * + * @param {string} name 选择器 + * @returns {?StyleObject} + */ + get(name) { + const result = this.find(item => item[0] == name); + return result ? result[1] : null; + } + + /** + * Callback of `DynamicStyle#find`, getting the rule wanted. + * `DynamicStyle#find`的回调函数,用于获取符合要求的规则 + * + * @callback FindCallback + * @param {Rule} rule 样式规则 + * @param {number} index 样式编号 + * @param {Rule[]} rules 规则集 + * @returns {boolean} + */ + + /** + * Get the rule wanted by given function. + * 通过给定的函数,获取符合要求的规则 + * + * @param {FindCallback} fn 用于检查的函数 + * @returns {?StyleObject} + */ + find(fn) { + return this._cache.rules.find(fn); + } + + /** + * Length of rules. + * 规则集的长度 + * + * @returns {number} + */ + size() { + return this._cache.rules.length; + } + + /** + * Get the index of given selector, or return `-1`. + * 获得对应选择器的位置,若不存在,则返回`-1` + * + * @param {string} name 选择器 + * @returns {number} + */ + indexOf(name) { + for (let i = 0; i < this._cache.rules.length; ++i) { + if (name == this._cache.rules[i][0]) return i; + } + return -1; + } + + // 后面部分就不说明了,可以顾名思义 + /** + * @param {string} name 选择器 + * @param {StyleObject} style 要添加的样式对象 + * @returns {boolean} 添加的结果,为`true`则添加成功,为`false`则添加失败 + */ + add(name, style) { + return this.update(name, this.has(name) ? Object.assign({}, this.get(name), style) : style); + } + + /** + * @param {Record} object 以`name: style`存储的映射 + * @returns {boolean} 添加的结果,为`true`则添加成功,为`false`则添加失败 + */ + addObject(object) { + return Object.entries(object).map(item => this.add(item[0], item[1])); + } + + /** + * @param {string} name 要移除规则的选择器 + * @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败 + */ + remove(name) { + if (!this.has(name)) return false; + try { + const index = this.indexOf(name); + this._cache.rules.splice(index, 1); + this._cache.sheet.deleteRule(index); + return true; + } + catch (e) { + console.log(e); + return false; + } + } + + /** + * @param {string} name 要移除规则的选择器 + * @param {string[]} styles 要移除的样式 + * @returns {boolean} 移除的结果,为`true`则移除成功,为`false`则移除失败 + */ + removeStyles(name, styles) { + if (!this.has(name)) return false; + const style = this.get(name); + styles.forEach(styleName => { + delete style[styleName]; + }); + return this.update(name, style); + } + + /** + * 添加或修改一个规则所对应的样式 + * + * @param {string} name 要变更规则的选择器 + * @param {StyleObject} style 变更规则的样式 + * @returns {boolean} 更新的结果,为`true`则更新成功,为`false`则更新失败 + */ + update(name, style) { + try { + if (this.has(name)) { + const index = this.indexOf(name); + this._cache.sheet.deleteRule(index); + this._cache.sheet.insertRule(this.generate(name, style), index); + this._cache.rules[index] = [name, style]; + } else { + const index = this._cache.rules.length; + this._cache.rules.push([name, style]); + this._cache.sheet.insertRule(this.generate(name, style), index); + } + return true; + } + catch (e) { + console.log(e); + return false; + } + } + } + static online = false; + static onlineID = null; + static onlineKey = null; + static videoContent = { + arrangeLib: function (content) { + for (var i in content) { + for (var j in content[i]) { + lib[i][j] = content[i][j]; + } + } + }, + $syncDisable: function (player, map) { + player.disabledSlots = map; + player.$syncDisable(map) + }, + $syncExpand: function (player, map) { + player.expandedSlots = map; + player.$syncExpand(map) + }, + $disableJudge: function (player, map) { + player.$disableJudge() + }, + $enableJudge: function (player, map) { + player.$enableJudge() + }, + jiuNode: function (player, bool) { + //Powered by 升麻 + if (bool) { + if (!player.node.jiu && lib.config.jiu_effect) { + player.node.jiu = ui.create.div(".playerjiu", player.node.avatar); + player.node.jiu2 = ui.create.div(".playerjiu", player.node.avatar2); + } + } + else { + if (player.node.jiu) { + player.node.jiu.delete(); + player.node.jiu2.delete(); + delete player.node.jiu; + delete player.node.jiu2; + } + } + }, + init: function (players) { + if (game.chess) return; + if (lib.config.mode == "versus") { + players.bool = players.pop(); + } + ui.arena.setNumber(players.length); + ui.arena.classList.add("video"); + game.players.length = 0; + game.dead.length = 0; + ui.create.players(players.length); + game.me = game.players[0]; + ui.handcards1 = game.me.node.handcards1; + ui.handcards2 = game.me.node.handcards2; + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + if (lib.config.mode == "versus") { + if (players.bool) { + ui.arena.setNumber(parseInt(ui.arena.dataset.number) + 1); + for (var i = 0; i < game.players.length; i++) { + game.players[i].dataset.position = parseInt(game.players[i].dataset.position) + 1; + } + game.singleHandcard = true; + ui.arena.classList.add("single-handcard"); + ui.window.classList.add("single-handcard"); + ui.fakeme = ui.create.div(".fakeme.avatar", ui.me); + } + ui.arena.style.display = ""; + ui.refresh(ui.arena); + ui.arena.show(); + } + else if (lib.config.mode == "boss") { + if (!players.boss) { + game.singleHandcard = true; + ui.arena.classList.add("single-handcard"); + ui.window.classList.add("single-handcard"); + ui.fakeme = ui.create.div(".fakeme.avatar", ui.me); + } + ui.arena.setNumber(8); + } + ui.updatehl(); + for (var i = 0; i < players.length; i++) { + if (lib.config.mode == "identity") { + if (_status.mode == "stratagem") { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].identity = players[i].identity; + if (game.players[i].identity == "fan" && game.players[i].isCamouflaged && game.me.identity == "nei" || game.players[i] == game.me) { + game.players[i].setIdentity(players[i].identity); + } + } + else { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].setIdentity(players[i].identity); + } + } + else if (lib.config.mode == "doudizhu" || lib.config.mode == "single") { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].setIdentity(players[i].identity); + } + else if (lib.config.mode == "stone") { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].classList.add("noidentity"); + game.players[i].updateActCount(null, players[i].count, 0); + } + else if (lib.config.mode == "boss") { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].setIdentity(players[i].identity); + game.players[i].dataset.position = players[i].position; + game.players[i].node.action.innerHTML = "行动"; + } + else if (lib.config.mode == "versus") { + game.players[i].init(players[i].name, players[i].name2); + game.players[i].node.identity.firstChild.innerHTML = players[i].identity; + game.players[i].node.identity.dataset.color = players[i].color; + game.players[i].node.action.innerHTML = "行动"; + } + else if (lib.config.mode == "guozhan") { + game.players[i].name = players[i].name; + game.players[i].name1 = players[i].name1; + game.players[i].name2 = players[i].name2; + + game.players[i].sex = "unknown"; + game.players[i].identity = "unknown"; + + lib.translate[game.players[i].name] = players[i].translate; + game.players[i].init(players[i].name1, players[i].name2); + + game.players[i].classList.add("unseen_v"); + game.players[i].classList.add("unseen2_v"); + if (game.players[i] != game.me) { + game.players[i].node.identity.firstChild.innerHTML = "猜"; + game.players[i].node.identity.dataset.color = "unknown"; + } + else { + game.players[i].setIdentity(game.players[i].group); + } + } + } + for (var i = 0; i < game.players.length; i++) { + game.playerMap[game.players[i].dataset.position] = game.players[i]; + } + + if (lib.config.mode == "versus") { + if (players.bool) { + game.onSwapControl(); + } + } + else if (lib.config.mode == "boss") { + if (!players.boss) { + game.onSwapControl(); + } + ui.arena.style.display = ""; + ui.refresh(ui.arena); + ui.arena.show(); + ui.updatehl(); + } + }, + newcard: function (content) { + if (content) { + lib.translate[content.name] = content.translate; + lib.translate[content.name + "_info"] = content.info; + lib.card[content.name] = {}; + lib.card[content.name].cardimage = content.card + for (var i in lib.card[content.card]) { + lib.card[content.name][i] = lib.card[content.card][i]; + } + if (content.legend) { + lib.card[content.name].legend = true; + } + else if (content.epic) { + lib.card[content.name].epic = true; + } + else if (content.unique) { + lib.card[content.name].unique = true; + } + } + }, + changeLand: function (player, url) { + game.changeLand(url, player); + }, + destroyLand: function () { + if (ui.land) { + ui.land.destroy(); + } + }, + playAudio: function (str) { + game.playAudio(str, "video"); + }, + playSkillAudio: function (name) { + game.playSkillAudio(name, "video"); + }, + phaseChange: function (player) { + if (player) { + var glowing = document.querySelector(".glow_phase"); + if (glowing) { + glowing.classList.remove("glow_phase"); + } + if (lib.config.glow_phase) { + player.classList.add("glow_phase"); + // player.dataset.glow_phase=lib.config.glow_phase; + } + } + else { + console.log(player); + } + }, + playerfocus: function (player, time) { + if (player && player.playerfocus) { + player.playerfocus(time); + } + else { + console.log(player); + } + }, + playerfocus2: function () { + ui.arena.classList.add("playerfocus"); + setTimeout(function () { + ui.arena.classList.remove("playerfocus"); + }, 1500) + }, + identityText: function (player, str) { + if (player && str) { + player.node.identity.firstChild.innerHTML = str; + } + else { + console.log(player); + } + }, + identityColor: function (player, str) { + if (player && str) { + player.node.identity.dataset.color = str; + } + else { + console.log(player); + } + }, + chessSwap: function (content) { + var me = game.playerMap[content[0]]; + var player = game.playerMap[content[1]]; + if (me) { + me.classList.remove("current_action"); + } + if (player) { + player.classList.add("current_action"); + } + }, + chessgainmod: function (player, num) { + if (Array.isArray(num)) { + num = get.infoCards(num); + } + if (player && player.$gainmod) { + player.$gainmod(num); + } + else { + console.log(player); + } + }, + moveTo: function (player, pos) { + if (player && player.moveTo && pos) { + player.moveTo(pos[0], pos[1]); + } + else { + console.log(player) + } + }, + addObstacle: function (pos) { + if (pos) { + game.addObstacle(pos[0], pos[1]); + } + }, + removeObstacle: function (pos) { + game.removeObstacle(pos); + }, + moveObstacle: function (pos) { + if (pos) { + game.moveObstacle(pos[0], pos[1], pos[2]); + } + }, + colorObstacle: function (pos) { + if (pos) { + game.colorObstacle(pos[0], pos[1]); + } + }, + thrownhighlight1: function () { + ui.arena.classList.add("thrownhighlight"); + }, + thrownhighlight2: function () { + ui.arena.classList.remove("thrownhighlight"); + }, + chessFocus: function (player) { + if (player) { + player.chessFocus(); + } + else { + console.log("chessFocus"); + } + }, + removeTreasure: function (pos) { + if (game.playerMap[pos]) { + game.playerMap[pos].delete(); + delete game.playerMap[pos]; + } + else { + console.log(pos); + } + }, + initobs: function (obs) { + if (obs) { + for (var i = 0; i < obs.length; i++) { + game.addObstacle(obs[i]); + } + } + else { + console.log(obs); + } + }, + stonePosition: function (content) { + var player = game.playerMap[content[0]]; + if (player) { + delete game.playerMap[content[0]]; + player.dataset.position = content[1]; + game.playerMap[content[1]] = player; + } + else { + console.log(content); + } + }, + bossSwap: function (player, name) { + if (player && name) { + player.delete(); + var noboss = false; + if (name[0] == "_") { + name = name.slice(1); + noboss = true; + } + var boss = ui.create.player().init(name); + boss.dataset.position = player.dataset.position; + game.playerMap[player.dataset.position] = boss; + if (game.me == player) { + game.me = boss; + } + game.players.push(boss); + game.arrangePlayers(); + if (!noboss) { + game.boss = boss; + boss.setIdentity("zhu"); + boss.identity = "zhu"; + } + else { + boss.setIdentity("zhong"); + boss.identity = "zhong"; + } + ui.arena.appendChild(boss.animate("zoominanim")); + } + }, + stoneSwap: function (info) { + var player = ui.create.player(); + player.classList.add("noidentity"); + player.dataset.position = info.position; + player.animate(info.me ? "replaceme" : "replaceenemy"); + player.actcount = info.actcount; + player.init(info.name, info.name2); + game.players.push(player); + player.updateActCount(null, info.actcount, 0); + ui.arena.appendChild(player); + game.playerMap[player.dataset.position] = player; + game.arrangePlayers(); + }, + chess_tongshuai: function (player, content) { + if (player && player.storage) { + player.storage.tongshuai.owned = content; + } + else { + console.log(player); + } + }, + chess_tongshuai_skill: function (player, content) { + if (player && content) { + if (player.marks.tongshuai.firstChild) { + player.marks.tongshuai.firstChild.remove(); + } + player.marks.tongshuai.setBackground(content[0], "character"); + player.additionalSkills.tongshuai = content[1]; + } + else { + console.log(player); + } + }, + smoothAvatar: function (player, vice) { + if (player && player.node) { + if (vice) { + if (player.node.avatar2) { + player.smoothAvatar(vice); + } + } + else { + if (player.node.avatar) { + player.smoothAvatar(vice); + } + } + } + }, + setAvatar: function (player, content) { + if (player && content && content.length == 2) { + player.setAvatar(content[0], content[1]) + } + }, + setAvatarQueue: function (player, content) { + if (player && content && content.length == 2) { + player.setAvatarQueue(content[0], content[1]) + } + }, + addSubPlayer: function (player, content) { + if (player && content && content[0] && content[1] && + content[2] && content[3] && content[4]) { + var skill = content[0]; + lib.skill[skill] = content[1]; + lib.character[skill] = content[2]; + lib.translate[skill] = content[3]; + player.storage[skill] = content[4]; + } + }, + arenaNumber: function (content) { + ui.arena.dataset.number = content; + }, + reinit: function (source, content) { + if (source && content) { + source.uninit(); + source.init(content[0]); + source.node.identity.dataset.color = content[1]; + } + else { + console.log(source); + } + }, + reinit2: function (source, name) { + if (source && name) { + source.init(name); + } + else { + console.log(source); + } + }, + reinit3: function (source, content) { + if (source && content) { + var info1 = lib.character[content.from]; + var info2 = lib.character[content.to]; + if (content.avatar2) { + source.name2 = content.to; + if (source.isUnseen(0)) { + source.sex = info2[0]; + } + source.node.avatar2.setBackground(content.to, "character"); + source.node.name2.innerHTML = get.slimName(content.to); + } + else { + source.name = content.to; + source.sex = info2[0]; + source.node.avatar.setBackground(content.to, "character"); + source.node.name.innerHTML = get.slimName(content.to); + } + source.maxHp = content.hp; + this.update(); + for (var i = 0; i < info1[3].length; i++) { + source.removeSkill(info1[3][i]); + } + for (var i = 0; i < info2[3].length; i++) { + source.addSkill(info2[3][i]); + } + } + }, + skill: function (player, content) { + if (typeof content == "string") { + if (lib.skill[content]) lib.skill[content].video(player); + } + else if (Array.isArray(content)) { + if (lib.skill[content[0]]) lib.skill[content[0]].video(player, content[1]); + } + else { + console.log(player, content) + } + }, + addFellow: function (content) { + var player = game.addFellow(content[0], content[1], content[2]); + game.playerMap[player.dataset.position] = player; + }, + windowzoom1: function () { + ui.window.style.transition = "all 0.5s"; + ui.window.classList.add("zoomout3"); + ui.window.hide(); + }, + windowzoom2: function () { + ui.window.style.transition = "all 0s"; + ui.refresh(ui.window); + }, + windowzoom3: function () { + ui.window.classList.remove("zoomout3"); + ui.window.classList.add("zoomin3"); + }, + windowzoom4: function () { + ui.window.style.transition = "all 0.5s"; + ui.refresh(ui.window); + ui.window.show(); + ui.window.classList.remove("zoomin3"); + }, + windowzoom5: function () { + ui.window.style.transition = ""; + }, + updateActCount: function (player, content) { + if (player && content) { + player.updateActCount(content[0], content[1], content[2]); + } + else { + console.log(player); + } + }, + showIdentity: function (player, identity) { + identity = identity || (player ? player.identity : null); + if (player && player.identity) { + player.showIdentity(identity); + } + else { + console.log(player); + } + }, + setIdentity: function (player, identity) { + if (player && identity) { + player.setIdentity(identity); + } + else { + console.log(num); + } + }, + showCharacter: function (player, num) { + if (player && player.classList) { + switch (num) { + case 0: + player.classList.remove("unseen_v"); + break; + case 1: + player.classList.remove("unseen2_v"); + break; + case 2: + player.classList.remove("unseen_v"); + player.classList.remove("unseen2_v"); + break; + } + if (!player.classList.contains("unseen_v") && (!player.name2 || !player.classList.contains("unseen2_v")) && player.storage.nohp) { + delete player.storage.nohp; + player.node.hp.show(); + player.update(); + } + } + else { + console.log(num); + } + }, + hidePlayer: function (player) { + if (player) { + player.hide(); + } + }, + deleteHandcards: function (player) { + if (player) { + player.node.handcards1.delete(); + player.node.handcards2.delete(); + } + }, + hideCharacter: function (player, num) { + if (player && player.classList) { + switch (num) { + case 0: + player.classList.add("unseen_v"); + break; + case 1: + player.classList.add("unseen2_v"); + break; + case 2: + player.classList.add("unseen_v"); + player.classList.add("unseen2_v"); + break; + } + } + else { + console.log(num); + } + }, + popup: function (player, info) { + if (player && info) { + player.popup(info[0], info[1]); + } + else { + console.log(player); + } + }, + log: function (str) { + game.log(str); + }, + draw: function (player, info) { + if (player && player.$draw) { + player.$draw(info); + } + else { + console.log(player); + } + }, + drawCard: function (player, info) { + if (player && info) { + player.$draw(get.infoCards(info)); + } + else { + console.log(player); + } + }, + throw: function (player, info) { + if (player && info) { + player.$throw(get.infoCards(info[0]), info[1], null, info[2]); + } + else { + console.log(player); + } + }, + compare: function (player, info) { + if (player && info) { + player.$compare(get.infoCard(info[0]), game.playerMap[info[1]], get.infoCard(info[2])); + } + else { + console.log(player); + } + }, + compareMultiple: function (player, info) { + if (player && info) { + player.$compareMultiple(get.infoCard(info[0]), get.infoTargets(info[1]), get.infoCards(info[2])); + } + else { + console.log(player); + } + }, + give: function (player, info) { + if (player && info) { + player.$give(info[0], game.playerMap[info[1]]); + } + else { + console.log(player); + } + }, + giveCard: function (player, info) { + if (player && info) { + player.$give(get.infoCards(info[0]), game.playerMap[info[1]]); + } + else { + console.log(player); + } + }, + gain: function (player, info) { + if (player && player.$gain) { + player.$gain(info); + } + else { + console.log(player); + } + }, + gainCard: function (player, info) { + if (player && info) { + player.$gain(get.infoCards(info)); + } + else { + console.log(player); + } + }, + gain2: function (player, cards) { + if (player && player.$draw) { + var nodeList = document.querySelectorAll("#arena>.card,#chess>.card"); + var nodes = []; + for (var i = 0; i < nodeList.length; i++) { + nodes.push(nodeList[i]); + } + for (var i = 0; i < cards.length; i++) { + for (var j = 0; j < nodes.length; j++) { + if (cards[i][2] == nodes[j].name && cards[i][0] == nodes[j].suit && cards[i][1] == nodes[j].number) { + nodes[j].moveDelete(player); + cards.splice(i--, 1); + nodes.splice(j--, 1); + break; + } + } + } + if (cards.length) { + player.$draw(get.infoCards(cards)); + } + } + else { + console.log(player); + } + }, + deletenode: function (player, cards, method) { + if (cards) { + var nodeList = document.querySelectorAll("#arena>.card,#chess>.card"); + var nodes = []; + for (var i = 0; i < nodeList.length; i++) { + nodes.push(nodeList[i]); + } + for (var i = 0; i < cards.length; i++) { + for (var j = 0; j < nodes.length; j++) { + if (cards[i][2] == nodes[j].name && cards[i][0] == nodes[j].suit && cards[i][1] == nodes[j].number) { + nodes[j].delete(); + if (method == "zoom") { + nodes[j].style.transform = "scale(0)"; + } + cards.splice(i--, 1); + nodes.splice(j--, 1); + break; + } + } + } + } + else { + console.log(player, cards); + } + }, + highlightnode: function (player, card) { + if (card) { + var nodeList = document.querySelectorAll("#arena>.card,#chess>.card"); + var nodes = []; + for (var i = 0; i < nodeList.length; i++) { + nodes.push(nodeList[i]); + } + for (var j = nodes.length - 1; j >= 0; j--) { + if (card[2] == nodes[j].name && card[0] == nodes[j].suit && card[1] == nodes[j].number) { + nodes[j].classList.add("thrownhighlight"); + break; + } + } + } + else { + console.log(player, cards); + } + }, + uiClear: function () { + ui.clear(); + }, + judge1: function (player, content) { + if (player && content) { + var judging = get.infoCard(content[0]); + if (game.chess) { + judging.copy("thrown", "center", "thrownhighlight", ui.arena).animate("start"); + } + else { + player.$throwordered(judging.copy("thrownhighlight"), true); + } + + ui.create.dialog(content[1]).videoId = content[2]; + ui.arena.classList.add("thrownhighlight"); + } + else { + console.log(player); + } + }, + centernode: function (content) { + get.infoCard(content).copy("thrown", "center", "thrownhighlight", ui.arena).animate("start"); + }, + judge2: function (videoId) { + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i].videoId == videoId) { + ui.dialogs[i].close(); + } + } + ui.arena.classList.remove("thrownhighlight"); + }, + unmarkname: function (player, name) { + if (player && player.unmark) { + player.unmark(name); + } + else { + console.log(player); + } + }, + unmark: function (player, name) { + if (player && player.marks && player.marks[name]) { + player.marks[name].delete(); + player.marks[name].style.transform += " scale(0.2)"; + delete player.marks[name]; + ui.updatem(this); + } + }, + flame: function (player, type) { + if (player && type) { + player["$" + type](); + } + else { + console.log(player); + } + }, + throwEmotion: function (player, content) { + if (player && content) { + player.$throwEmotion(game.playerMap[content[0]], content[1]); + } + else { + console.log(player); + } + }, + addGaintag: function (player, content) { + if (player && content) { + var checkMatch = function (l1, l2) { + for (var i = 0; i < l1.length; i++) { + for (var j = 0; j < l2.length; j++) { + if (l2[j].suit == l1[i][0] && l2[j].number == l1[i][1] && l2[j].name == l1[i][2]) { + l2[j].addGaintag(content[1]); + l2.splice(j--, 1); + break; + } + } + } + } + checkMatch(content[0], player.getCards("h")); + } + else { + console.log(player); + } + }, + removeGaintag: function (player, content) { + if (player && content) { + if (Array.isArray(content)) player.removeGaintag.apply(player, content) + else player.removeGaintag(content); + } + else { + console.log(player); + } + }, + line: function (player, content) { + if (player && content) { + player.line(game.playerMap[content[0]], content[1]); + } + else { + console.log(player); + } + }, + fullscreenpop: function (player, content) { + if (player && content) { + player.$fullscreenpop(content[0], content[1], content[2]); + } + else { + console.log(player); + } + }, + damagepop: function (player, content) { + if (player && content) { + player.$damagepop(content[0], content[1], content[2]); + } + else { + console.log(player); + } + }, + damage: function (player, source) { + if (player && player.$damage) { + player.$damage(game.playerMap[source]); + } + else { + console.log(player); + } + }, + diex: function (player) { + if (!player) { + console.log("diex"); + return; + } + var cards = player.getCards("hej"); + for (var i = 0; i < cards.length; i++) { + cards[i].discard(); + } + while (player.node.marks.childNodes.length > 1) { + player.node.marks.lastChild.remove(); + } + player.classList.add("dead"); + player.classList.remove("turnedover"); + player.classList.remove("out"); + player.node.count.innerHTML = "0"; + player.node.hp.hide(); + player.node.equips.hide(); + player.node.count.hide(); + player.previous.next = player.next; + player.next.previous = player.previous; + game.players.remove(player); + game.dead.push(player); + if (lib.config.mode == "stone") { + setTimeout(function () { + player.delete(); + }, 500); + } + }, + tafangMe: function (player) { + if (player) { + game.me = player; + ui.me.lastChild.show(); + ui.create.fakeme(); + ui.handcards1 = player.node.handcards1.animate("start").fix(); + ui.handcards2 = player.node.handcards2.animate("start").fix(); + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + ui.updatehl(); + game.setChessInfo(); + } + }, + deleteChessPlayer: function (player) { + if (player) { + player.delete(); + delete game.playerMap[player.dataset.position]; + game.players.remove(player); + for (var i = 0; i < ui.phasequeue.length; i++) { + if (ui.phasequeue[i].link == player) { + ui.phasequeue[i].remove(); + ui.phasequeue.splice(i, 1); + break; + } + } + } + }, + addChessPlayer: function (content) { + game.addChessPlayer.apply(this, content); + }, + die: function (player) { + if (!player) { + console.log("die"); + return; + } + player.$die(); + if (game.chess) { + delete lib.posmap[player.dataset.position]; + setTimeout(function () { + player.delete(); + }, 500); + for (var i = 0; i < ui.phasequeue.length; i++) { + if (ui.phasequeue[i].link == player) { + ui.phasequeue[i].remove(); + ui.phasequeue.splice(i, 1); + break; + } + } + } + }, + revive: function (player) { + if (!player) { + console.log("revive"); + return; + } + player.classList.remove("dead"); + player.node.hp.show(); + player.node.equips.show(); + player.node.count.show(); + player.node.avatar.style.transform = ""; + player.node.avatar2.style.transform = ""; + player.removeAttribute("style"); + }, + update: function (player, info) { + if (player && info) { + player.hp = info[1]; + player.maxHp = info[2]; + player.hujia = info[3]; + player.update(info[0]); + } + else { + console.log(player); + } + }, + phaseJudge: function (player, card) { + if (player && card) { + // player.$phaseJudge(get.infoCard(card)); + } + else { + console.log(player); + } + }, + directgain: function (player, cards) { + if (player && cards) { + player.directgain(get.infoCards(cards)); + } + else { + console.log(player); + } + }, + directgains: function (player, cards) { + if (player && cards) { + player.directgains(get.infoCards(cards)); + } + else { + console.log(player); + } + }, + directequip: function (player, cards) { + if (player && cards) { + player.directequip(get.infoCards(cards)); + } + else { + console.log(player); + } + }, + gain12: function (player, cards12) { + if (player && cards12) { + var cards1 = get.infoCards(cards12[0]); + var cards2 = get.infoCards(cards12[1]); + for (var i = 0; i < cards1.length; i++) { + cards1[i].classList.add("drawinghidden"); + cards1[i].addGaintag(cards12[2]); + player.node.handcards1.insertBefore(cards1[i], player.node.handcards1.firstChild); + } + for (var i = 0; i < cards2.length; i++) { + cards2[i].classList.add("drawinghidden"); + cards2[i].addGaintag(cards12[2]); + player.node.handcards2.insertBefore(cards2[i], player.node.handcards2.firstChild); + } + ui.updatehl(); + } + else { + console.log(player); + } + }, + equip: function (player, card) { + if (player && card) { + player.$equip(get.infoCard(card)); + } + else { + console.log(player); + } + }, + addJudge: function (player, content) { + if (player && content) { + var card = get.infoCard(content[0]); + card.viewAs = content[1]; + if (card.viewAs && card.viewAs != card.name && (card.classList.contains("fullskin") || card.classList.contains("fullborder"))) { + card.classList.add("fakejudge"); + card.node.background.innerHTML = lib.translate[card.viewAs + "_bg"] || get.translation(card.viewAs)[0] + } + card.classList.add("drawinghidden"); + player.node.judges.insertBefore(card, player.node.judges.firstChild); + ui.updatej(player); + } + else { + console.log(player); + } + }, + markCharacter: function (player, content) { + if (player && content) { + if (game.playerMap[content.target]) { + content.target = game.playerMap[content.target]; + } + var mark = player.markCharacter(content.target, content); + if (content.id) { + player.marks[content.id] = mark; + } + } + else { + console.log(player); + } + }, + changeMarkCharacter: function (player, content) { + if (player && content && player.marks[content.id]) { + player.marks[content.id].info = { + name: content.name, + content: content.content + }; + player.marks[content.id].setBackground(content.target, "character"); + } + }, + mark: function (player, content) { + if (player && content) { + var mark = player.mark(content.id, content); + } + else { + console.log(player); + } + }, + markSkill: function (player, content) { + if (player && content) { + if (content[1]) { + player.markSkill(content[0], null, get.infoCard(content[1])); + } + else { + player.markSkill(content[0]); + } + } + else { + console.log(player); + } + }, + unmarkSkill: function (player, name) { + if (player && player.unmarkSkill) { + player.unmarkSkill(name); + } + else { + console.log(player); + } + }, + storage: function (player, content) { + if (player && content) { + if (content[2]) { + switch (content[2]) { + case "cards": content[1] = get.infoCards(content[1]); break; + case "card": content[1] = get.infoCard(content[1]); break; + } + } + player.storage[content[0]] = content[1]; + } + else { + console.log(player); + } + }, + markId: function (player, content) { + if (player && content) { + player.mark(get.infoCard(content[0]), content[1]); + } + else { + console.log(player); + } + }, + unmarkId: function (player, content) { + if (player && content) { + player.unmark(get.infoCard(content[0]), content[1]); + } + else { + console.log(player); + } + }, + lose: function (player, info) { + if (player && info) { + var hs = info[0] || [], es = info[1] || [], js = info[2] || [], ss = info[3] || []; + var phs = player.getCards("h"), pes = player.getCards("e"), pjs = player.getCards("j"), pss = player.getCards("s"); + var checkMatch = function (l1, l2) { + for (var i = 0; i < l1.length; i++) { + for (var j = 0; j < l2.length; j++) { + if (l2[j].suit == l1[i][0] && l2[j].number == l1[i][1] && l2[j].name == l1[i][2]) { + l2[j].remove(); + l2.splice(j--, 1); + break; + } + } + } + } + checkMatch(hs, phs); + checkMatch(es, pes); + checkMatch(js, pjs); + checkMatch(ss, pss); + ui.updatehl(); + } + else { + console.log(player); + } + }, + loseAfter: function (player) { + if (!player) { + console.log("loseAfter"); + return; + } + }, + link: function (player, bool) { + if (player && player.classList) { + if (bool) { + player.addLink(); + } + else { + player.removeLink(); + } + } + else { + console.log(player); + } + }, + turnOver: function (player, bool) { + if (player && player.classList) { + if (bool) { + player.classList.add("turnedover"); + } + else { + player.classList.remove("turnedover"); + } + } + else { + console.log(player); + } + }, + showCards: function (player, info) { + if (info) { + var dialog = ui.create.dialog(info[0], get.infoCards(info[1])); + setTimeout(function () { + dialog.close(); + }, 1000); + } + else { + console.log(player); + } + }, + cardDialog: function (content) { + if (Array.isArray(content)) { + ui.create.dialog(content[0], get.infoCards(content[1])).videoId = content[2]; + } + else if (typeof content == "number") { + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i].videoId == content) { + ui.dialogs[i].close(); + return; + } + } + } + }, + changeSeat: function (player, info) { + if (player && player.getBoundingClientRect && player.changeSeat) { + player.changeSeat(info); + game.playerMap = {}; + var players = game.players.concat(game.dead); + for (var i = 0; i < players.length; i++) { + game.playerMap[players[i].dataset.position] = players[i]; + } + } + }, + dialogCapt: function (content) { + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i].videoId == content[0]) { + ui.dialogs[i].content.firstChild.innerHTML = content[1]; + return; + } + } + }, + swapSeat: function (content) { + var player1 = game.playerMap[content[0]]; + var player2 = game.playerMap[content[1]]; + if (!player1 || !player2) { + console.log(content); + return; + } + var temp1, pos, i, num; + temp1 = player1.dataset.position; + player1.dataset.position = player2.dataset.position; + player2.dataset.position = temp1; + game.arrangePlayers(); + if (player1.dataset.position == "0" || player2.dataset.position == "0") { + pos = parseInt(player1.dataset.position); + if (pos == 0) pos = parseInt(player2.dataset.position); + num = game.players.length + game.dead.length; + for (i = 0; i < game.players.length; i++) { + temp1 = parseInt(game.players[i].dataset.position) - pos; + if (temp1 < 0) temp1 += num; + game.players[i].dataset.position = temp1; + } + for (i = 0; i < game.dead.length; i++) { + temp1 = parseInt(game.dead[i].dataset.position) - pos; + if (temp1 < 0) temp1 += num; + game.dead[i].dataset.position = temp1; + } + } + game.playerMap = {}; + var players = game.players.concat(game.dead); + for (var i = 0; i < players.length; i++) { + game.playerMap[players[i].dataset.position] = players[i]; + } + }, + removeTafangPlayer: function () { + ui.fakeme.hide(); + ui.handcards1Container.innerHTML = ""; + ui.handcards2Container.innerHTML = ""; + game.me = ui.create.player(); + }, + swapControl: function (player, hs) { + if (player && player.node) { + var cards = get.infoCards(hs); + player.node.handcards1.innerHTML = ""; + player.node.handcards2.innerHTML = ""; + player.directgain(cards, false); + + game.me.node.handcards1.remove(); + game.me.node.handcards2.remove(); + + ui.handcards1 = player.node.handcards1.animate("start").fix(); + ui.handcards2 = player.node.handcards2.animate("start").fix(); + ui.handcards1Container.insertBefore(ui.handcards1, ui.handcards1Container.firstChild); + ui.handcards2Container.insertBefore(ui.handcards2, ui.handcards2Container.firstChild); + + game.me = player; + ui.updatehl(); + if (game.chess) { + ui.create.fakeme(); + } + } + else { + console.log(player); + } + }, + onSwapControl: function () { + game.onSwapControl(); + }, + swapPlayer: function (player, hs) { + if (player && player.node) { + var cards = get.infoCards(hs); + player.node.handcards1.innerHTML = ""; + player.node.handcards2.innerHTML = ""; + player.directgain(cards, false); + + var pos = parseInt(player.dataset.position); + var num = game.players.length + game.dead.length; + var players = game.players.concat(game.dead); + var temp; + for (var i = 0; i < players.length; i++) { + temp = parseInt(players[i].dataset.position) - pos; + if (temp < 0) temp += num; + players[i].dataset.position = temp; + } + game.me.node.handcards1.remove(); + game.me.node.handcards2.remove(); + game.me = player; + ui.handcards1 = player.node.handcards1.animate("start").fix(); + ui.handcards2 = player.node.handcards2.animate("start").fix(); + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + + ui.updatehl(); + + game.playerMap = {}; + var players = game.players.concat(game.dead); + for (var i = 0; i < players.length; i++) { + game.playerMap[players[i].dataset.position] = players[i]; + } + } + else { + console.log(player); + } + }, + over: function (str) { + var dialog = ui.create.dialog("hidden"); + dialog.noforcebutton = true; + dialog.content.innerHTML = str; + dialog.forcebutton = true; + dialog.open(); + if (game.chess) { + dialog.classList.add("center"); + } + if ((game.layout == "long2" || game.layout == "nova") && !game.chess) { + ui.arena.classList.add("choose-character"); + if (ui.me) ui.me.hide(); + if (ui.mebg) ui.mebg.hide() + if (ui.autonode) ui.autonode.hide(); + if (lib.config.radius_size != "off") { + if (ui.historybar) ui.historybar.style.borderRadius = "0 0 0 4px"; + } + } + } + }; + static animate = { + window: function (num) { + switch (num) { + case 1: { + ui.window.style.transition = "all 0.5s"; + ui.window.classList.add("zoomout3"); + ui.window.hide(); + game.addVideo("windowzoom1"); + game.delay(0, 500); + break; + } + case 2: { + ui.window.style.transition = "all 0s"; + ui.refresh(ui.window); + game.addVideo("windowzoom2"); + game.pause(); + setTimeout(function () { + ui.window.classList.remove("zoomout3"); + ui.window.classList.add("zoomin3"); + game.addVideo("windowzoom3"); + setTimeout(function () { + ui.window.style.transition = "all 0.5s"; + ui.refresh(ui.window); + ui.window.show(); + ui.window.classList.remove("zoomin3"); + game.addVideo("windowzoom4"); + setTimeout(function () { + ui.window.style.transition = ""; + game.addVideo("windowzoom5"); + game.resume(); + }, 500); + }, 100); + }, 100); + break; + } + } + }, + flame: function (x, y, duration, type) { + var particles = []; + var particle_count = 50; + if (type == "thunder" || type == "recover") { + particle_count = 30; + } + else if (type == "coin" || type == "dust") { + particle_count = 50; + } + else if (type == "legend") { + particle_count = 120; + } + else if (type == "epic") { + particle_count = 80; + } + else if (type == "rare") { + particle_count = 50; + } + for (var i = 0; i < particle_count; i++) { + particles.push(new particle()); + } + function particle() { + this.speed = { x: -1 + Math.random() * 2, y: -5 + Math.random() * 5 }; + if (type == "thunder" || type == "coin" || type == "dust") { + this.speed.y = -3 + Math.random() * 5; + this.speed.x = -2 + Math.random() * 4; + } + if (type == "legend" || type == "rare" || type == "epic") { + this.speed.x *= 3; + this.speed.y *= 1.5; + } + this.location = { x: x, y: y }; + + this.radius = 0.5 + Math.random() * 1; + + this.life = 10 + Math.random() * 10; + this.death = this.life; + + switch (type) { + case "thunder": { + this.b = 255; + this.r = Math.round(Math.random() * 255); + this.g = Math.round(Math.random() * 255); + this.x += Math.random() * 20 - 10; + this.y += Math.random() * 20 - 10; + + break; + } + case "fire": { + this.r = 255; + this.g = Math.round(Math.random() * 155); + this.b = 0; + break; + } + case "coin": { + this.r = 255; + this.g = Math.round(Math.random() * 25 + 230); + this.b = Math.round(Math.random() * 100 + 50); + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.life *= 1.3; + this.death *= 1.3; + break; + } + case "dust": { + this.r = Math.round(Math.random() * 55) + 105; + this.g = Math.round(Math.random() * 55) + 150; + this.b = 255; + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.life *= 1.3; + this.death *= 1.3; + break; + } + case "legend": { + this.r = 255; + this.g = Math.round(Math.random() * 100 + 155); + this.b = Math.round(Math.random() * 100 + 50); + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.speed.x /= 2; + this.speed.y /= 2; + this.life *= 2; + this.death *= 2; + break; + } + case "epic": { + this.r = Math.round(Math.random() * 55) + 200; + this.g = Math.round(Math.random() * 100) + 55; + this.b = 255; + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.speed.x /= 2; + this.speed.y /= 2; + this.life *= 2; + this.death *= 2; + break; + } + case "rare": { + this.r = Math.round(Math.random() * 55) + 105; + this.g = Math.round(Math.random() * 55) + 150; + this.b = 255; + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.speed.x /= 2; + this.speed.y /= 2; + this.life *= 2; + this.death *= 2; + break; + } + case "recover": { + this.g = 255; + this.r = Math.round(Math.random() * 200 + 55); + this.b = Math.round(Math.random() * 155 + 55); + this.location.x += Math.round(Math.random() * 60) - 30; + this.location.y += Math.round(Math.random() * 40) - 20; + if (this.location.x < x) { + this.speed.x = -Math.abs(this.speed.x); + } + else if (this.location.x > x) { + this.speed.x = Math.abs(this.speed.x); + } + this.speed.x /= 2; + this.speed.y /= 2; + this.life *= 2; + this.death *= 2; + break; + } + default: { + this.r = 255; + this.g = Math.round(Math.random() * 155); + this.b = 0; + } + } + } + + game.draw(function (time, surface) { + surface.globalCompositeOperation = "source-over"; + surface.globalCompositeOperation = "lighter"; + + for (var i = 0; i < particles.length; i++) { + var p = particles[i]; + + surface.beginPath(); + var middle = 0.5; + var radius = p.radius; + if (type == "recover" || type == "legend" || type == "rare" || + type == "epic" || type == "coin" || type == "dust") { + middle = 0.7; + radius /= 3; + } + + p.opacity = Math.round(p.death / p.life * 100) / 100 + var gradient = surface.createRadialGradient(p.location.x, p.location.y, 0, p.location.x, p.location.y, p.radius); + gradient.addColorStop(0, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")"); + gradient.addColorStop(middle, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", " + p.opacity + ")"); + gradient.addColorStop(1, "rgba(" + p.r + ", " + p.g + ", " + p.b + ", 0)"); + surface.fillStyle = gradient; + surface.arc(p.location.x, p.location.y, radius, Math.PI * 2, false); + surface.fill(); + p.death--; + if (type == "recover") { + p.radius += 0.5; + } + else if (type == "coin" || type == "dust") { + p.radius += 0.7; + } + else if (type == "legend" || type == "rare" || type == "epic") { + p.radius += 0.5; + } + else { + p.radius++; + } + p.location.x += (p.speed.x); + p.location.y += (p.speed.y); + + if (p.death < 0 || p.radius < 0) { + if (typeof duration == "number" && time + 500 >= duration) { + particles.splice(i--, 1); + } + else { + particles[i] = new particle(); + } + } + } + if (particles.length == 0) { + return false; + } + }); + } + } + /** + * @type {Player[]} + */ + static players = []; + /** + * @type {Player[]} + */ + static dead = []; + static imported = []; + static playerMap = {}; + static phaseNumber = 0; + static roundNumber = 0; + static shuffleNumber = 0; + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + // Stratagem + // 谋攻 + static setStratagemBuffCost(cardName, cost) { + game.broadcastAll((clientCardName, clientCost) => lib.stratagemBuff.cost.set(clientCardName, clientCost), cardName, cost); + } + static setStratagemBuffEffect(cardName, effect) { + game.broadcastAll((clientCardName, clientEffect) => lib.stratagemBuff.cost.set(clientCardName, clientEffect), cardName, effect); + } + static setStratagemBuffPrompt(cardName, prompt) { + game.broadcastAll((clientCardName, clientPrompt) => lib.stratagemBuff.cost.set(clientCardName, clientPrompt), cardName, prompt); + } + /** + * 添加新的属性杀 + */ + static addNature(nature, translation, config) { + if (!nature) throw new TypeError(); + if (translation && translation.length) lib.translate["nature_" + nature] = translation; + game.callHook("addNature", [nature, translation, config]); + return nature; + } + /** + * 判断卡牌信息/事件是否有某个属性 + */ + static hasNature(item, nature, player) { + var natures = get.natureList(item, player); + if (!nature) return natures.length > 0; + if (nature == "linked") return natures.some(n => lib.linked.includes(n)); + return get.is.sameNature(natures, nature); + } + /** + * 设置卡牌信息/事件的属性 + */ + static setNature(item, nature, addNature) { + if (!nature) nature = []; + if (!addNature) { + item.nature = get.nature(nature); + if (!item.nature.length) delete item.nature; + } + else { + let natures = Array.isArray(nature) ? nature : nature.split(lib.natureSeparator); + let _nature = get.natureList(item, false); + _nature.addArray(natures); + item.nature = _nature.join(lib.natureSeparator); + } + return item.nature; + } + /** + * 洗牌 + */ + static washCard() { + if (!ui.cardPile.hasChildNodes() && !ui.discardPile.hasChildNodes()) return false; + if (_status.maxShuffle != undefined) { + if (_status.maxShuffle == 0) { + if (_status.maxShuffleCheck) { + game.over(_status.maxShuffleCheck()); + } + else { + game.over("平局"); + } + return []; + } + _status.maxShuffle--; + } + game.shuffleNumber++; + const cards = Array.from(ui.cardPile.childNodes); + if (_status.discarded) { + _status.discarded.length = 0; + } + for (let i = 0; i < ui.discardPile.childNodes.length; i++) { + var currentcard = ui.discardPile.childNodes[i]; + currentcard.vanishtag.length = 0; + currentcard.clearKnowers(); + if (get.info(currentcard).vanish || currentcard.storage.vanish) { + currentcard.remove(); + continue; + } + cards.push(currentcard); + } + cards.randomSort(); + return game.cardsGotoPile(cards, "triggeronly", "washCard", ["shuffleNumber", game.shuffleNumber]) + } + + /** + * addGroup + * + * 基于钩子的添加势力方法 + */ + static addGroup(id, short, name, config) { + if (!id) throw new TypeError(); + if (lib.comparator.typeEquals(short, "object")) { + config = short; + short = null; + } + if (lib.comparator.typeEquals(name, "object")) { + config = name; + name = null; + } + if (!lib.comparator.typeEquals(short, "string") && short) { + name = short; + } + lib.group.add(id); + if (short) lib.translate[id] = short; + if (name) lib.translate[`${id}2`] = name; + game.callHook("addGroup", [id, short, name, config]); + return id; + } + /** + * 通用的调用钩子函数 + */ + static callHook(name, args) { + const callHook = () => { + for (const hook of lib.hooks[name]) { + if (hook != null && typeof hook == "function") { + hook(...args); + } + } + } + if ("onload" in lib) lib.onload.add(callHook); + else callHook(); + } + // Yingbian + // 应变 + static yingbianEffect(event, content) { + const yingbianEffect = game.createEvent("yingbianEffect"); + yingbianEffect.player = event.player; + yingbianEffect.card = event.card; + yingbianEffect._trigger = event; + yingbianEffect.setContent(content); + yingbianEffect._args = Array.from(arguments); + return yingbianEffect; + } + static setYingbianConditionColor(yingbianCondition, color) { + game.broadcastAll((yingbianCondition, color) => lib.yingbian.condition.color.set(yingbianCondition, color), yingbianCondition, color); + } + static setComplexYingbianCondition(yingbianCondition, condition) { + game.broadcastAll((yingbianCondition, condition) => lib.yingbian.condition.complex.set(yingbianCondition, condition), yingbianCondition, condition); + } + static setSimpleYingbianCondition(yingbianCondition, condition) { + game.broadcastAll((yingbianCondition, condition) => lib.yingbian.condition.simple.set(yingbianCondition, condition), yingbianCondition, condition); + } + static setYingbianEffect(yingbianEffect, effect) { + game.broadcastAll((yingbianEffect, effect) => lib.yingbian.effect.set(yingbianEffect, effect), yingbianEffect, effect); + } + static setYingbianPrompt(yingbian, prompt) { + game.broadcastAll((yingbian, prompt) => lib.yingbian.prompt.set(yingbian, prompt), yingbian, prompt); + } + + /** + * Add a background music to the config option + * 在设置选项中添加一首背景音乐 + */ + static addBackgroundMusic(link, musicName, aozhan) { + const backgroundMusicSetting = ui[aozhan ? "aozhan_bgm" : "background_music_setting"], menu = backgroundMusicSetting._link.menu, config = backgroundMusicSetting._link.config; + if (typeof musicName != "string") musicName = link; + if (aozhan) lib.mode.guozhan.config.aozhan_bgm.item[link] = musicName; + else lib.config.all.background_music.add(link); + config.item[link] = musicName; + const textMenu = ui.create.div("", musicName, menu, function () { + const node = this.parentNode._link, config = node._link.config; + node._link.current = this.link; + const tmpName = node.lastChild.innerHTML; + node.lastChild.innerHTML = config.item[this._link]; + if (config.onclick && config.onclick.call(node, this._link, this) === false) node.lastChild.innerHTML = tmpName; + if (config.update) config.update(); + }, menu.childElementCount - 2); + textMenu._link = link; + config.updatex.call(backgroundMusicSetting, []); + } + + /** + * Remove a background music from the config option + * 从设置选项中移除一首背景音乐 + */ + static removeBackgroundMusic(link, aozhan) { + if (aozhan) { + if (["disabled", "random"].includes(link)) return; + delete lib.mode.guozhan.config.aozhan_bgm.item[link]; + if (!Array.isArray(_status.aozhanBGMToRemove)) _status.aozhanBGMToRemove = []; + _status.aozhanBGMToRemove.add(link); + } + else { + if (["music_off", "music_custom", "music_random"].includes(link)) return; + lib.config.all.background_music.remove(link); + } + const backgroundMusicSetting = ui[aozhan ? "aozhan_bgm" : "background_music_setting"], config = backgroundMusicSetting._link.config; + config.updatex.call(backgroundMusicSetting, []); + } + static updateBackground() { + const background = _status.tempBackground || lib.config.image_background; + ui.background.delete(); + const uiBackground = ui.background = ui.create.div(".background"), style = uiBackground.style; + if (lib.config.image_background_blur) { + style.filter = "blur(8px)"; + style.webkitFilter = "blur(8px)"; + style.transform = "scale(1.05)"; + } + document.body.insertBefore(uiBackground, document.body.firstChild); + if (background.startsWith("db:")) uiBackground.setBackgroundDB(background.slice(3)); + else if (background.startsWith("ext:")) uiBackground.setBackgroundImage(`extension/${background.slice(4)}`); + else if (background == "default") { + uiBackground.animate("start"); + style.backgroundImage = "none"; + } + else if (background.startsWith("custom_")) { + style.backgroundImage = "none"; + game.getDB("image", background).then(fileToLoad => { + if (!fileToLoad) return; + const fileReader = new FileReader(); + fileReader.onload = fileLoadedEvent => style.backgroundImage = `url(${fileLoadedEvent.target.result})`; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else uiBackground.setBackgroundImage(`image/background/${background}.jpg`); + style.backgroundSize = "cover"; + style.backgroundPosition = "50% 50%"; + } + + /** + * Generate a beatmap using the given BPM, beats, and offset + * 用给定的BPM、节拍和偏移生成谱面 + */ + static generateBeatmapTimeleap(bpm, beats, offset) { + return beats.map(value => Math.round(value * 60000 / bpm + (offset || 0))); + } + static updateRenku() { + game.broadcast(function (renku) { + _status.renku = renku; + }, _status.renku); + for (var i of game.players) { + if (i.storage.renku) i.markSkill("renku"); + } + } + /** + * 为牌添加知情者。 + */ + static addCardKnower(cards, players) { + if (get.itemtype(cards) == "card") { + cards = [cards]; + } + cards.forEach(card => card.addKnower(players)); + } + /** + * 移除牌的所有知情者。 + */ + static clearCardKnowers(cards) { + if (get.itemtype(cards) == "card") { + cards = [cards]; + } + cards.forEach(card => card.clearKnowers()); + } + static loseAsync(arg) { + var next = game.createEvent("loseAsync"); + next.forceDie = true; + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + var cards = [], event = this; + game.checkGlobalHistory("cardMove", function (evt) { + if (evt.name != "lose" || evt.position != position || evt.getParent() != event) return; + if (player && player != evt.player) return; + cards.addArray(evt[key]); + }); + return cards; + }; + next.getl = function (player) { + const that = this; + const map = { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + player.checkHistory("lose", function (evt) { + if (evt.parent == that) { + map.hs.addArray(evt.hs); + map.es.addArray(evt.es); + map.js.addArray(evt.js); + map.ss.addArray(evt.ss); + map.xs.addArray(evt.xs); + map.cards.addArray(evt.cards); + map.cards2.addArray(evt.cards2); + for (let key in evt.gaintag_map) { + if (!map.gaintag_map[key]) map.gaintag_map[key] = []; + map.gaintag_map[key].addArray(evt.gaintag_map[key]); + } + } + }); + return map; + }; + next.getg = function (player) { + var that = this; + var cards = []; + player.checkHistory("gain", function (evt) { + if (evt.parent == that) { + cards.addArray(evt.cards); + } + }); + return cards; + }; + if (arg && get.is.object(arg)) { + for (var i in arg) next[i] = arg[i]; + } + return next; + } + static callFuncUseStepCache(prefix, func, params) { + if (typeof func != "function") return; + if (_status.closeStepCache || !_status.event) return func.apply(null, params); + var cacheKey = "[" + prefix + "]" + get.paramToCacheKey.apply(null, params); + var ret = _status.event.getStepCache(cacheKey); + if (ret === undefined || ret === null) { + ret = func.apply(null, params); + _status.event.putStepCache(cacheKey, ret); + } + return ret; + } + static getRarity(name) { + var rank = lib.rank.rarity; + if (rank.legend.contains(name)) return "legend"; + if (rank.epic.contains(name)) return "epic"; + if (rank.rare.contains(name)) return "rare"; + if (get.mode() != "chess" && rank.junk.contains(name)) return "junk"; + return "common"; + } + static hasGlobalHistory(key, filter, last) { + if (!key) return _status.globalHistory[_status.globalHistory.length - 1]; + if (!filter) return _status.globalHistory[_status.globalHistory.length - 1][key]; + else { + const history = game.getGlobalHistory(key); + if (last) { + const lastIndex = history.indexOf(last); + return history.some((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }); + } + else { + return history.some(filter); + } + } + } + static checkGlobalHistory(key, filter, last) { + if (!key) return _status.globalHistory[_status.globalHistory.length - 1]; + if (!filter) return _status.globalHistory[_status.globalHistory.length - 1][key]; + else { + const history = game.getGlobalHistory(key); + if (last) { + const lastIndex = history.indexOf(last); + history.forEach((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }); + } + else { + history.forEach(filter); + } + } + } + static getGlobalHistory(key, filter, last) { + if (!key) return _status.globalHistory[_status.globalHistory.length - 1]; + if (!filter) return _status.globalHistory[_status.globalHistory.length - 1][key]; + else { + const history = game.getGlobalHistory(key); + if (last) { + const lastIndex = history.indexOf(last); + return history.filter((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }) + } + return history.filter(filter); + } + } + static hasAllGlobalHistory(key, filter, last) { + if (!key || !filter) return; + let stopped = false; + _status.globalHistory.forEach(value => { + if (value[key]) { + if (last && value[key].includes(last) && !stopped) { + stopped = true; + const lastIndex = value[key].indexOf(last); + if (value[key].some((event, index) => { + if (index > lastIndex) return false; + return filter(event); + })) return true; + } + else { + if (value[key].some(filter)) return true; + } + } + }) + } + static checkAllGlobalHistory(key, filter, last) { + if (!key || !filter) return; + let stopped = false; + _status.globalHistory.forEach(value => { + if (value[key]) { + if (last && value[key].includes(last) && !stopped) { + stopped = true; + const lastIndex = value[key].indexOf(last); + value[key].forEach((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }); + } + else { + value[key].forEach(filter); + } + } + }) + } + static getAllGlobalHistory(key, filter, last) { + const history = []; + _status.globalHistory.forEach(value => { + if (!key || !value[key]) { + history.push(value); + } + else { + history.push(...value[key]); + } + }) + if (filter) { + if (last) { + const lastIndex = history.indexOf(last); + return history.filter(function (event, index) { + if (index > lastIndex) return false; + return filter(event); + }); + } + return history.filter(filter); + } + return history; + } + static cardsDiscard(cards) { + var type = get.itemtype(cards); + if (type != "cards" && type != "card") return; + var next = game.createEvent("cardsDiscard"); + next.cards = type == "cards" ? cards.slice(0) : [cards]; + next.setContent("cardsDiscard"); + next.getd = function (player, key, position) { + return this.cards.slice(0); + }; + return next; + } + static cardsGotoOrdering(cards) { + var type = get.itemtype(cards); + if (type != "cards" && type != "card") return; + var next = game.createEvent("cardsGotoOrdering"); + next.cards = type == "cards" ? cards.slice(0) : [cards]; + next.setContent("cardsGotoOrdering"); + return next; + } + static cardsGotoSpecial(cards, bool) { + var type = get.itemtype(cards); + if (type != "cards" && type != "card") return; + var next = game.createEvent("cardsGotoSpecial"); + next.cards = type == "cards" ? cards.slice(0) : [cards]; + if (bool == "toRenku") next.toRenku = true; + else if (bool === false) next.notrigger = true; + next.setContent("cardsGotoSpecial"); + return next; + } + static cardsGotoPile() { + const cards = []; + const next = game.createEvent("cardsGotoPile"); + next.cards = cards; + for (let i = 0; i < arguments.length; i++) { + let arg = arguments[i], itemtype = get.itemtype(arg); + if (itemtype == "cards") { + cards.addArray(arg); + } + else if (itemtype == "card") { + cards.add(arg); + } + else if (typeof arg == "function") { + next.insert_index = arg; + } + else if (typeof arg == "string") { + if (arg == "insert") next.insert_card = true; + else if (arg == "washCard") next.washCard = true; + else if (arg == "triggeronly") next._triggeronly = true; + } + else if (Array.isArray(arg) && arg.length == 2 && typeof arg[0] == "string") { + next.set(arg[0], arg[1]); + } + } + if (!cards.length) { + _status.event.next.remove(next); + } + else { + next.setContent("cardsGotoPile"); + if (next._triggeronly) game.$cardsGotoPile(next); + } + return next; + } + static $cardsGotoPile(event) { + const cards = event.cards; + const pile = ui.cardPile; + for (let i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("cardPile", null, event)) { + cards[i].selfDestroy(event); + continue; + } + if (event.insert_index) { + cards[i].fix(); + pile.insertBefore(cards[i], event.insert_index(event, cards[i])); + } + else if (event.insert_card) { + cards[i].fix(); + pile.insertBefore(cards[i], pile.firstChild); + } + else { + cards[i].fix(); + pile.appendChild(cards[i]); + } + } + game.updateRoundNumber(); + } + static showHistory(pause) { + if (lib.config.show_history == "left") { + ui.window.classList.add("leftbar"); + } + else if (lib.config.show_history == "right") { + ui.window.classList.add("rightbar"); + } + if (pause != false && ui.pause) { + ui.pause.show(); + } + } + static createBackground(src, blur) { + var current = document.body.querySelector(".background.upper"); + if (current) { + current.delete(); + } + var node = ui.create.div(".background.blurbg", document.body); + node.setBackgroundImage(src); + node.style.backgroundSize = "cover"; + if (blur) { + node.classList.add("paused") + } + return node; + } + static changeLand(url, player) { + game.addVideo("changeLand", player, url); + const parsedPath = lib.path.parse(url); + delete parsedPath.base; + if (!parsedPath.dir) parsedPath.dir = "image/card/"; + if (!parsedPath.ext) parsedPath.ext = ".jpg"; + const fileName = parsedPath.name; + game.broadcastAll((formattedPath, name, skill, player) => { + const node = ui.create.div(".background.upper.land"); + node.setBackgroundImage(formattedPath); + node.destroy = () => { + if (node.skill) { + game.removeGlobalSkill(node.skill); + if (node.system) node.system.remove(); + } + node.classList.add("hidden"); + setTimeout(() => node.remove(), 3000); + if (ui.land == node) ui.land = null; + } + if (ui.land) { + document.body.insertBefore(node, ui.land); + ui.land.destroy(); + } + else { + node.classList.add("hidden"); + document.body.insertBefore(node, ui.window); + ui.refresh(node); + node.classList.remove("hidden"); + } + ui.land = node; + if (!name) return; + node.name = name; + node.skill = skill; + if (player) { + node.player = player; + player.addTempSkill("land_used"); + } + lib.setPopped(node.system = ui.create.system(lib.translate[skill], null, true, true), () => { + const uiIntro = ui.create.dialog("hidden"); + uiIntro.addText(player ? `来源:${get.translation(player)}` : "地图").style.margin = "0"; + uiIntro._place_text = uiIntro.add(ui.create.div(".text", lib.translate[`${skill}_info`])); + uiIntro.add(ui.create.div(".placeholder.slim")); + return uiIntro; + }, 200); + game.addGlobalSkill(skill); + }, lib.path.format(parsedPath), fileName, `${fileName}_skill`, player); + } + static checkFileList(updates, proceed) { + var n = updates.length; + if (!n) { + proceed(n); + } + for (var i = 0; i < updates.length; i++) { + if (lib.node && lib.node.fs) { + lib.node.fs.access(__dirname + "/" + updates[i], (function (entry) { + return function (err) { + if (!err) { + var stat = lib.node.fs.statSync(__dirname + "/" + entry); + if (stat.size == 0) { + err = true; + } + } + if (err) { + n--; + if (n == 0) { + proceed(); + } + } + else { + n--; + updates.remove(entry); + if (n == 0) { + proceed(); + } + } + } + }(updates[i]))); + } + else { + resolveLocalFileSystemURL(lib.assetURL + updates[i], (function (name) { + return function (entry) { + n--; + updates.remove(name); + if (n == 0) { + proceed(); + } + } + }(updates[i])), function () { + n--; + if (n == 0) { + proceed(); + } + }); + } + } + } + static replaceHandcards() { + var next = game.createEvent("replaceHandcards"); + if (Array.isArray(arguments[0])) { + next.players = arguments[0]; + } + else { + next.players = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.players.push(arguments[i]); + } + } + } + if (_status.connectMode) { + next.setContent("replaceHandcardsOL"); + } + else { + next.setContent("replaceHandcards"); + } + } + static removeCard(name) { + for (var i = 0; i < lib.card.list.length; i++) { + if (lib.card.list[i][2] == name) { + lib.card.list.splice(i--, 1); + } + } + var list = []; + for (var i = 0; i < ui.cardPile.childElementCount; i++) { + if (ui.cardPile.childNodes[i].name == name) { + list.push(ui.cardPile.childNodes[i]); + } + } + for (var i = 0; i < list.length; i++) { + list[i].remove(); + } + } + static randomMapOL(type) { + if (type == "hidden") { + ui.arena.classList.add("playerhidden"); + } + game.prepareArena(); + if (window.isNonameServer) { + game.me = ui.create.player(); + } + var list = []; + for (var i = 0; i < game.players.length; i++) { + if (game.players[i] != game.me) { + list.push(game.players[i]); + } + } + var map = []; + for (var i = 0; i < lib.node.clients.length; i++) { + if (!list.length) break; + var current = list.randomRemove(); + current.ws = lib.node.clients[i]; + current.playerid = current.ws.id; + current.nickname = current.ws.nickname; + current.setNickname(); + } + if (!window.isNonameServer) { + game.me.playerid = get.id(); + game.me.nickname = get.connectNickname(); + game.me.setNickname(); + } + for (var i = 0; i < game.players.length; i++) { + if (!game.players[i].playerid) { + game.players[i].playerid = get.id(); + } + map.push([game.players[i].playerid, game.players[i].nickname]); + lib.playerOL[game.players[i].playerid] = game.players[i]; + } + game.broadcast(function (map, config, hidden) { + if (hidden) { + ui.arena.classList.add("playerhidden"); + } + lib.configOL = config; + ui.create.players(); + ui.create.me(); + game.me.playerid = game.onlineID; + game.me.nickname = get.connectNickname(); + for (var i = 0; i < map.length; i++) { + if (map[i][0] == game.me.playerid) { + map = map.concat(map.splice(0, i)); + break; + } + } + for (var i = 0; i < game.players.length; i++) { + game.players[i].playerid = map[i][0]; + game.players[i].nickname = map[i][1]; + game.players[i].setNickname(); + lib.playerOL[game.players[i].playerid] = game.players[i]; + } + _status.mode = lib.configOL[lib.configOL.mode + "_mode"]; + }, map, lib.configOL, type == "hidden"); + _status.mode = lib.configOL[lib.configOL.mode + "_mode"]; + game.chooseCharacterOL(); + } + static closeMenu() { + if (ui.menuContainer && !ui.menuContainer.classList.contains("hidden")) { + ui.click.configMenu(); + } + } + static closeConnectMenu() { + if (ui.connectMenuContainer && !ui.connectMenuContainer.classList.contains("hidden")) { + ui.click.connectMenu(); + } + } + static closePopped() { + if (ui.currentpopped) { + if (ui.currentpopped._uiintro) { + ui.currentpopped._uiintro.delete(); + delete ui.currentpopped._uiintro; + } + delete ui.currentpopped; + } + } + /** + * @type {{ + * (func: T, ...args: Parameters) => void; + * (func: (...args: T) => void, ...args: T) => void; + * }} + */ + static broadcast() { + if (!lib.node || !lib.node.clients || game.online) return; + for (var i = 0; i < lib.node.clients.length; i++) { + if (lib.node.clients[i].inited) { + lib.node.clients[i].send.apply(lib.node.clients[i], arguments); + } + } + } + /** + * @type {{ + * (func: T, ...args: Parameters) => void; + * (func: (...args: T) => void, ...args: T) => void; + * }} + */ + static broadcastAll() { + if (game.online) return; + var argc = arguments.length; + var args = new Array(argc); + for (var i = 0; i < argc; i++) { + args[i] = arguments[i]; + } + game.broadcast.apply(this, args); + var func = args.shift(); + if (typeof func == "string") { + func = lib.message.client[func]; + } + if (typeof func == "function") { + func.apply(this, args); + } + } + static syncState() { + var state = null; + if (game.getState) { + state = game.getState(); + } + game.broadcast(function (state, current, number) { + if (game.updateState && state) game.updateState(state); + _status.currentPhase = current; + game.phaseNumber = number; + }, state, _status.currentPhase, game.phaseNumber); + } + static updateWaiting() { + var map = []; + for (var i = 0; i < game.connectPlayers.length; i++) { + var player = game.connectPlayers[i]; + if (player.playerid) { + if (!game.onlinezhu) { + game.onlinezhu = player.playerid; + game.send("server", "changeAvatar", player.nickname, player.avatar); + _status.onlinenickname = player.nickname; + _status.onlineavatar = player.avatar; + } + map[i] = [player.nickname, player.avatar, player.playerid]; + if (player.playerid == game.onlinezhu) { + map[i].push("zhu"); + } + } + else if (player.classList.contains("unselectable2")) { + map[i] = "disabled"; + } + else { + map[i] = null; + } + } + game.broadcast("updateWaiting", map); + } + static waitForPlayer(func) { + var next = game.createEvent("waitForPlayer", false); + next.func = func; + next.setContent("waitForPlayer"); + } + static countDown(time, onEnd) { + time = parseInt(time); + if (!time) return; + if (time <= 0) return; + var current = time; + ui.timer.set(current, 1); + _status.countDown = setInterval(function () { + if (--current) { + ui.timer.set(current, current / time); + } + else { + ui.timer.set(0, 0); + clearInterval(_status.countDown); + delete _status.countDown; + if (onEnd) onEnd(); + } + }, 1000); + } + static countChoose(clear) { + if (_status.imchoosing) { + return; + } + _status.imchoosing = true; + if (_status.connectMode && !_status.countDown) { + ui.timer.show(); + var num; + //这么一大行都是为了祢衡 + if (_status.event && _status.event.name == "chooseToUse" && _status.event.type == "phase" && + _status.event.player && _status.event.player.forceCountChoose && + typeof _status.event.player.forceCountChoose.phaseUse == "number") { + num = _status.event.player.forceCountChoose.phaseUse; + } + else if (_status.connectMode) { + num = lib.configOL.choose_timeout; + } + else { + num = get.config("choose_timeout"); + } + game.countDown(parseInt(num), function () { + ui.click.auto(); + ui.timer.hide(); + }); + if (!game.online && game.me) { + if (_status.event.getParent().skillHidden) { + for (var i = 0; i < game.players.length; i++) { + game.players[i].showTimer(); + } + game.me._hide_all_timer = true; + } + else if (!_status.event._global_waiting) { + game.me.showTimer(); + } + } + } + else if (_status.event.player.forceCountChoose && _status.event.isMine() && !_status.countDown) { + var info = _status.event.player.forceCountChoose; + var num; + if (_status.event.name == "chooseToUse" && _status.event.type == "phase" && typeof info.phaseUse == "number") { + num = info.phaseUse; + } + else if (typeof info[_status.event.name] == "number") { + num = info[_status.event.name] + } + else if (info.default) { + num = info.default; + } + else return; + var finish = function () { + if (_status.event.endButton) { + if (_status.event.skill) { + ui.click.cancel(); + } + ui.click.cancel(); + } + else { + if (ui.confirm && ui.confirm.str) { + if (ui.confirm.str.includes("c")) { + ui.click.cancel(); + } + else if (ui.confirm.str.includes("o")) { + ui.click.ok(); + } + } + else if (["chooseControl", "chooseBool"].contains(_status.event.name) && _status.paused) { + _status.event.result = "ai"; + game.resume(); + } + else { + ui.click.auto("forced"); + setTimeout(function () { + ui.click.auto("forced"); + }, 200); + } + } + ui.timer.hide(); + }; + if (!num) { + ui.timer.hide(); + game.uncheck(); + setTimeout(finish, 200); + } + else { + ui.timer.show(); + game.countDown(num, finish); + } + } + } + static stopCountChoose() { + if (_status.countDown) { + clearInterval(_status.countDown); + delete _status.countDown; + ui.timer.hide(); + } + if (_status.connectMode && !game.online && game.me) { + if (game.me._hide_all_timer) { + delete game.me._hide_all_timer; + for (var i = 0; i < game.players.length; i++) { + game.players[i].hideTimer(); + } + } + else if (!_status.event._global_waiting) { + game.me.hideTimer(); + } + } + } + static connect(ip, callback) { + if (game.online) return; + var withport = false; + var index = ip.lastIndexOf(":"); + if (index != -1) { + index = parseFloat(ip.slice(index + 1)); + if (index && Math.floor(index) == index) { + withport = true; + } + } + if (!withport) { + ip = ip + ":8080"; + } + _status.connectCallback = callback; + try { + if (game.ws) { + game.ws._nocallback = true; + game.ws.close(); + delete game.ws; + } + var str = ""; + if (!ip.startsWith("wss://") && !ip.startsWith("ws://")) str = (get.config("wss_mode", "connect") ? "wss://" : "ws://"); + game.ws = new WebSocket(str + ip + ""); + } + catch (e) { + alert("错误:无效联机地址"); + if (callback) { + callback(false); + } + return; + } + game.ws.onopen = lib.element.ws.onopen; + game.ws.onmessage = lib.element.ws.onmessage; + game.ws.onerror = lib.element.ws.onerror; + game.ws.onclose = lib.element.ws.onclose; + _status.ip = ip; + } + static send() { + if (game.observe && arguments[0] != "reinited") return; + if (game.ws) { + var args = Array.from(arguments); + if (typeof args[0] == "function") { + args.unshift("exec"); + } + game.ws.send(JSON.stringify(get.stringifiedResult(args))); + } + } + static sendTo(id, message) { + return new lib.element.Client(new lib.element.NodeWS(id)).send(message); + } + static createServer() { + lib.node.clients = []; + lib.node.banned = []; + lib.node.observing = []; + lib.node.torespond = {}; + lib.node.torespondtimeout = {}; + lib.playerOL = {}; + lib.cardOL = {}; + lib.wsOL = {}; + ui.create.roomInfo(); + ui.create.chat(); + + if (game.onlineroom) { + void 0; + } + else { + var WebSocketServer = require("ws").Server; + var wss = new WebSocketServer({ port: 8080 }); + + game.ip = get.ip(); + + wss.on("connection", lib.init.connection); + } + } + static playAudio() { + let path = "", emptyPath = true, notCheckDBPath = true, onError = null; + if (_status.video) { + if (arguments[1] != "video") return; + path = arguments[0]; + } + else { + for (const argument of arguments) { + if (typeof argument === "string" || typeof argument == "number") { + if (emptyPath) emptyPath = false; + else if (notCheckDBPath) { + notCheckDBPath = false; + if (/^db:extension-[^:]*$/.test(path)) path += ":"; + else path += "/"; + } + else path += "/"; + path += argument; + } + else if (typeof argument == "function") onError = argument; + if (_status.video) break; + } + if (path.startsWith("ext:")) path = path.replace(/^ext:/, "extension/"); + else if (!path.startsWith("db:")) path = `audio/${path}`; + if (!lib.config.repeat_audio && _status.skillaudio.contains(path)) return; + } + _status.skillaudio.add(path); + game.addVideo("playAudio", null, path); + setTimeout(() => _status.skillaudio.remove(path), 1000); + const audio = document.createElement("audio"); + audio.autoplay = true; + audio.volume = lib.config.volumn_audio / 8; + audio.addEventListener("ended", () => audio.remove()); + audio.onerror = event => { + audio.remove(); + if (onError) onError(event); + }; + //Some browsers do not support "autoplay", so "oncanplay" listening has been added + audio.oncanplay = () => Promise.resolve(audio.play()).catch(() => void 0); + new Promise((resolve, reject) => { + if (path.startsWith("db:")) game.getDB("image", path.slice(3)).then(octetStream => resolve(get.objectURL(octetStream)), reject); + else if (lib.path.extname(path)) resolve(`${lib.assetURL}${path}`); + else resolve(`${lib.assetURL}${path}.mp3`); + }).then(resolvedPath => { + audio.src = resolvedPath; + ui.window.appendChild(audio); + }); + return audio; + } + /** + * 根据skill中的audio,audioname,audioname2和player来获取音频地址列表 + * @param {String} skill 技能名 + * @param {Player|String} player 角色/角色名 + * @returns {Array} 分析完的语音地址列表 + */ + static parseSkillAudio(skill, player) { + if (typeof player == "string") player = { name: player }; + else if (get.itemtype(player) != "player") player = {}; + + /** + * 处理 audioInfo 外的参数 + * @param {String} skill 技能名 + * @param {Player|{name:string}} player 角色 + * @param {Array} audioname audioname历史 + * @param {Array} history 判断deadlock + * @param {Number} fixedNum [audioname, number] 中的第二个参数,用来限制语音数 + * @returns {Array} 音频地址数组(有需要playSkillAudio的为[skillname]) + */ + function getAudioList(skill, player, audioname, history, fixedNum) { + let info = lib.skill[skill]; + if (!info) return []; + if (!history) history = []; + if (history.includes(skill)) {//判断deadlock + console.trace(`${skill} in ${history} forms a deadlock`); + if (info.audio !== false) return [[skill]]; + return []; + } + history.push(skill); + + let audioInfo = info.audio; + if (info.audioname2) { + if (info.audioname2[player.name]) audioInfo = info.audioname2[player.name]; + else if (info.audioname2[player.name1]) audioInfo = info.audioname2[player.name1]; + else if (info.audioname2[player.name2]) audioInfo = info.audioname2[player.name2]; + else if (player.tempname) { + const name = player.tempname.find(i => info.audioname2[i]); + if (name) audioInfo = info.audioname2[name]; + } + } + if (typeof audioInfo == "function") audioInfo = audioInfo(player); + + if (!audioname) audioname = []; + if (Array.isArray(info.audioname)) audioname.addArray(info.audioname); + + let audioList = parseAudio(skill, audioInfo, audioname, player, history, fixedNum); + if (fixedNum && fixedNum < audioList.length) audioList.length = fixedNum; + if (audioList.length) return audioList; + if (info.audio !== false) return [[skill]]; + return []; + } + + /** + * 分析 audioInfo 获取音频地址数组 + * @param {String} skill 技能名 + * @param {any} audioInfo info.audio + * @param {Array} audioname 要判断的audioname + * @param {Player|{name:string}} player 角色 + * @param {Array} history 判断deadlock + * @param {Number} fixedNum [audioname, number] 中的第二个参数,用来限制语音数 + * @returns {Array} 音频地址数组(有需要playSkillAudio的为[skillname]) + */ + function parseAudio(skill, audioInfo, audioname, player, history, fixedNum) { + if (Array.isArray(audioInfo)) { + if (typeof audioInfo[0] == "string" && typeof audioInfo[1] == "number") {// [audioname, number] + if (lib.skill[audioInfo[0]]) return getAudioList(audioInfo[0], player, audioname, history, fixedNum || audioInfo[1]); + return parseAudio(audioInfo[0], audioInfo[1], audioname, player, history, fixedNum || audioInfo[1]); + } + return audioInfo.reduce((total, i) => total.addArray(parseAudio(skill, i, audioname, player, history, fixedNum)), []); + } + + if (!["string", "number", "boolean"].includes(typeof audioInfo)) return []; + if (audioInfo === false) return []; + if (typeof audioInfo == "string" && lib.skill[audioInfo]) return getAudioList(audioInfo, player, audioname, history, fixedNum); + + let audioList = []; + audioInfo = String(audioInfo); + let list = audioInfo.match(/(?:(.*):|^)(true|\d+)(?::(.*)|$)/); + if (list && list[2]) { + let _audioname = ""; + if (audioname.includes(player.name)) _audioname = `_${player.name}`; + else if (audioname.includes(player.name1)) _audioname = `_${player.name1}`; + else if (audioname.includes(player.name2)) _audioname = `_${player.name2}`; + else if (player.tempname) { + const name = player.tempname.find(i => audioname.includes(i)); + if (name) _audioname = `_${name}`; + } + + list = list.slice(1);//[路径,number/true,格式] + if (list[1] == "true") audioList.add(`${list[0] || "skill"}/${skill}${_audioname}.${list[2] || "mp3"}`); + else { + list[1] = parseInt(list[1]); + for (let i = 1; i <= list[1]; i++) { + audioList.add(`${list[0] || "skill"}/${skill}${_audioname}${i}.${list[2] || "mp3"}`); + } + } + } + else audioList.add(`${/(?:^db:|^ext:|\/)/.test(audioInfo) ? "" : "skill/"}${audioInfo}`); + return audioList; + } + + return getAudioList(skill, player); + } + static trySkillAudio(skill, player, directaudio, nobroadcast/*,index*/) { + if (!nobroadcast) game.broadcast(game.trySkillAudio, skill, player, directaudio, nobroadcast/*,index*/); + var info = get.info(skill); + if (!info) return; + if (!lib.config.background_speak) return; + if (info.direct && !directaudio) return; + if (lib.skill.global.includes(skill) && !lib.skill[skill].forceaudio) return; + + let list = game.parseSkillAudio(skill, player); + if (!list.length) return; + // if(index) index=index%list.length||list.length; + // let audio=list[index?index-1:Math.floor(Math.random()*list.length)]; + let audio = list[Math.floor(Math.random() * list.length)]; + if (Array.isArray(audio)) return game.playSkillAudio(audio[0]); + return game.playAudio(audio); + } + static playSkillAudio(name, index) { + if (_status.video && arguments[1] != "video") return; + if (!lib.config.repeat_audio && _status.skillaudio.includes(name)) return; + game.addVideo("playSkillAudio", null, name); + if (name.indexOf("|") < name.lastIndexOf("|")) { + name = name.slice(name.lastIndexOf("|") + 1); + } + _status.skillaudio.add(name); + setTimeout(function () { + _status.skillaudio.remove(name); + }, 1000); + var str = "audio/skill/"; + var audio = document.createElement("audio"); + audio.autoplay = true; + audio.volume = lib.config.volumn_audio / 8; + audio.src = lib.assetURL + str + name + ".mp3"; + audio.addEventListener("ended", function () { + this.remove(); + }); + if (typeof index != "number") { + index = Math.ceil(Math.random() * 2); + } + audio._changed = 1; + audio.onerror = function () { + switch (this._changed) { + case 1: { + audio.src = lib.assetURL + str + name + ".ogg"; + this._changed = 2; + break; + } + case 2: { + audio.src = lib.assetURL + str + name + index + ".mp3"; + this._changed = 3; + break; + } + case 3: { + audio.src = lib.assetURL + str + name + index + ".ogg"; + this._changed = 4; + break; + } + default: { + this.remove(); + } + } + }; + //Some browsers do not support "autoplay", so "oncanplay" listening has been added + audio.oncanplay = function () { + Promise.resolve(this.play()).catch(() => void 0); + }; + ui.window.appendChild(audio); + } + static playCardAudio(card, sex) { + if (typeof card === "string") { + card = { name: card }; + } + if (get.itemtype(sex) === "player") { + sex = (sex.sex == "female" ? "female" : "male"); + } else if (typeof sex == "string") { + sex = (sex == "female" ? "female" : "male"); + } + if (!lib.config.background_audio || get.type(card) == "equip" && !lib.config.equip_audio) return; + var nature = get.natureList(card)[0]; + if (lib.natureAudio[card.name]) { + let useAudio = lib.natureAudio[card.name][nature]; + if (useAudio === "default") { + game.playAudio("card", sex, `${card.name}_${nature}`); + return; + } else if (useAudio && useAudio[sex]) { + game.playAudio(useAudio[sex]); + return; + } + } + const audio = lib.card[card.name].audio; + if (typeof audio == "string") { + const audioInfo = audio.split(":"); + if (audio.startsWith("db:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`, audioInfo[2], `${card.name}_${sex}.${audioInfo[3] || "mp3"}`); + else if (audio.startsWith("ext:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`, `${card.name}_${sex}.${audioInfo[2] || "mp3"}`); + else game.playAudio("card", sex, `${audioInfo[0]}.${audioInfo[1] || "mp3"}`); + } + else game.playAudio("card", sex, card.name); + } + static playBackgroundMusic() { + if (lib.config.background_music == "music_off") { + ui.backgroundMusic.src = ""; + return; + } + if (_status._aozhan) { + const aozhanBGMConfiguration = lib.config.mode_config.guozhan.aozhan_bgm; + if (aozhanBGMConfiguration == "disabled") return; + let aozhan = _status.tempAozhan || aozhanBGMConfiguration; + if (Array.isArray(aozhan)) aozhan = aozhan.randomGet("disabled", _status.currentAozhan) || aozhanBGMConfiguration; + if (aozhan == "random") aozhan = Object.keys(lib.mode.guozhan.config.aozhan_bgm.item).randomGet("disabled", "random", _status.currentAozhan); + _status.currentAozhan = aozhan; + if (aozhan.startsWith("db:")) game.getDB("image", aozhan.slice(3)).then(result => ui.backgroundMusic.src = result); + else if (aozhan.startsWith("ext:")) ui.backgroundMusic.src = `${lib.assetURL}extension/${aozhan.slice(4)}`; + else ui.backgroundMusic.src = `${lib.assetURL}audio/background/aozhan_${aozhan}.mp3`; + return; + } + let music = _status.tempMusic || lib.config.background_music; + if (Array.isArray(music)) music = music.randomGet("music_off", _status.currentMusic) || lib.config.background_music; + if (music == "music_random") music = lib.config.all.background_music.randomGet("music_off", "music_random", _status.currentMusic); + _status.currentMusic = music; + if (music == "music_custom") { + const backgroundMusicSourceConfiguration = lib.config.background_music_src; + if (backgroundMusicSourceConfiguration) ui.backgroundMusic.src = backgroundMusicSourceConfiguration; + return; + } + if (music.startsWith("db:")) game.getDB("image", music.slice(3)).then(result => ui.backgroundMusic.src = result); + else if (music.startsWith("ext:")) ui.backgroundMusic.src = `${lib.assetURL}extension/${music.slice(4)}`; + else ui.backgroundMusic.src = `${lib.assetURL}audio/background/${music}.mp3`; + } + static import(type, content, url) { + if (type == "extension") { + const promise = game.loadExtension(content).then((name) => { + if (typeof _status.extensionLoaded == "undefined") + _status.extensionLoaded = []; + _status.extensionLoaded.add(name); + return name; + }); + if (typeof _status.extensionLoading == "undefined") _status.extensionLoading = []; + _status.extensionLoading.add(promise); + return promise; + } + else { + if (!lib.imported[type]) lib.imported[type] = {}; + const promise = Promise.resolve((gnc.is.generator(content) ? gnc.of(content) : content)(lib, game, ui, get, ai, _status)).then(content2 => { + if (content2.name) { + lib.imported[type][content2.name] = content2; + delete content2.name; + } + }); + if (typeof _status.importing == "undefined") _status.importing = {}; + if (!_status.importing[type]) _status.importing[type] = []; + _status.importing[type].add(promise); + return promise; + } + } + static loadExtension = gnc.of(function* (object) { + let noEval = false; + if (typeof object == "function") { + object = yield (gnc.is.generatorFunc(object) ? gnc.of(object) : object)(lib, game, ui, get, ai, _status); + noEval = true; + } + const name = object.name, extensionName = `extension_${name}`, extensionMenu = lib.extensionMenu[extensionName] = { + enable: { + name: "开启", + init: true + } + }, objectPackage = object.package; + if (objectPackage) { + const author = Object.getOwnPropertyDescriptor(objectPackage, "author"); + if (author) Object.defineProperty(extensionMenu.author = { + get name() { + return `作者:${this.author}`; + }, + clear: true, + nopointer: true, + }, "author", author); + const intro = Object.getOwnPropertyDescriptor(objectPackage, "intro"); + if (intro) Object.defineProperty(extensionMenu.intro = { + clear: true, + nopointer: true, + }, "name", intro); + } + const objectConfig = object.config; + if (objectConfig) Object.defineProperties(extensionMenu, Object.keys(objectConfig).reduce((propertyDescriptorMap, key) => { + propertyDescriptorMap[key] = Object.getOwnPropertyDescriptor(objectConfig, key); + return propertyDescriptorMap; + }, {})); + const help = object.help; + if (help) Object.defineProperties(lib.help, Object.keys(help).reduce((propertyDescriptorMap, key) => { + propertyDescriptorMap[key] = Object.getOwnPropertyDescriptor(help, key); + return propertyDescriptorMap; + }, {})); + if (object.editable !== false && lib.config.show_extensionmaker) extensionMenu.edit = { + name: "编辑此扩展", + clear: true, + onclick: () => { + if (game.editExtension && lib.extensionPack && lib.extensionPack[name]) game.editExtension(name); + else alert("无法编辑未启用的扩展,请启用此扩展并重启后重试"); + } + }; + extensionMenu.delete = { + name: "删除此扩展", + clear: true, + onclick: function () { + if (this.innerHTML != "确认删除") { + this.innerHTML = "确认删除"; + new Promise(resolve => setTimeout(resolve, 1000)).then(() => this.innerHTML = "删除此扩展"); + return; + } + const page = this.parentNode, start = page.parentNode.previousSibling; + page.remove(); + if (start) { + const pageInStart = Array.from(start.childNodes).find(childNode => childNode.link == page); + if (pageInStart) { + let active = false; + if (pageInStart.classList.contains("active")) active = true; + pageInStart.remove(); + if (active) { + start.firstChild.classList.add("active"); + start.nextSibling.appendChild(start.firstChild.link); + } + } + } + game.removeExtension(name); + if (typeof object.onremove == "function") object.onremove(); + } + } + + if (_status.importingExtension) { + game.importedPack = object; + return; + } + const libConfig = lib.config; + if (!object || !libConfig[`${extensionName}_enable`]) return; + if (!noEval) lib.init.eval(object); + const config = Object.keys(libConfig).reduce((constructingConfig, key) => { + if (key != extensionName && key.startsWith(extensionName)) constructingConfig[key.slice(11 + name.length)] = libConfig[key]; + return constructingConfig; + }, {}); + try { + let extensionPack = lib.extensionPack[name]; + if (objectPackage) { + extensionPack = lib.extensionPack[name] = objectPackage; + objectPackage.files = object.files || {}; + const extensionPackFiles = objectPackage.files; + if (!extensionPackFiles.character) extensionPackFiles.character = []; + if (!extensionPackFiles.card) extensionPackFiles.card = []; + if (!extensionPackFiles.skill) extensionPackFiles.skill = []; + } + else extensionPack = lib.extensionPack[name] = {}; + const content = object.content, precontent = object.precontent; + extensionPack.code = { + content: content, + precontent: precontent, + help: help, + config: objectConfig + } + if (precontent) { + _status.extension = name; + yield (gnc.is.generatorFunc(precontent) ? gnc.of(precontent) : precontent).call(object, config); + delete _status.extension; + } + if (content) lib.extensions.push([name, content, config, _status.evaluatingExtension, objectPackage || {}]); + } + catch (e) { + console.log(e); + } + + return name; + }); + static createDir(directory, successCallback, errorCallback) { + const paths = directory.split("/").reverse(); + if (window.resolveLocalFileSystemURL) return new Promise((resolve, reject) => window.resolveLocalFileSystemURL(lib.assetURL, resolve, reject)).then(directoryEntry => { + const redo = entry => new Promise((resolve, reject) => entry.getDirectory(paths.pop(), { + create: true + }, resolve, reject)).then(resolvedDirectoryEntry => { + if (paths.length) return redo(resolvedDirectoryEntry); + if (typeof successCallback == "function") successCallback(); + }); + return redo(directoryEntry); + }, reason => { + if (typeof errorCallback != "function") return Promise.reject(reason); + errorCallback(reason); + }); + const fs = require("fs"); + let path = __dirname; + const redo = () => { + path += `/${paths.pop()}`; + return new Promise(resolve => fs.exists(path, resolve)).then(exists => { + //不存在此目录 + if (!exists) return new Promise(resolve => fs.mkdir(path, resolve)); + }).then(() => { + if (paths.length) return redo(); + if (typeof successCallback == "function") successCallback(); + }); + }; + return redo(); + } + static importExtension = gnc.of(function* (data, finishLoad, exportExtension, extensionPackage) { + //by 来瓶可乐加冰、Rintim、Tipx-L + if (!window.JSZip) + yield new Promise((resolve, reject) => lib.init.js(`${lib.assetURL}game`, "jszip", resolve, reject)); + + const zip = new JSZip(); + if (get.objtype(data) == "object") { + //导出 + const _filelist = data._filelist, filelist2 = _filelist || []; + if (_filelist) delete data._filelist; + const filelist = Object.keys(data); + filelist.forEach(value => zip.file(value, data[value])); + game.print(filelist); + game.print(filelist2); + const generate = zip.generate({ + type: "arraybuffer" + }); + if (!exportExtension) { + game.importExtension.apply(this, [generate, finishLoad]); + return; + } + if (extensionPackage) { + extensionPackage.files = filelist.concat(filelist2).filter(value => value != "extension.js"); + const size = generate.byteLength; + if (size < 1000) extensionPackage.size = `${size}B`; + else if (size < 1000000) extensionPackage.size = `${Math.round(size / 1000)}KB`; + else extensionPackage.size = `${Math.round(size / 100000) / 10}MB`; + zip.file("package.js", Object.keys(extensionPackage).reduce((constructingData, key, currentIndex, keys) => `${constructingData}\t${key}:${JSON.stringify(extensionPackage[key])}${currentIndex < keys.length - 1 ? ",\n" : "\n};"}`, `extension["${exportExtension}"]={\n`)); + } + const blob = zip.generate({ + type: "blob" + }), fileNameToSaveAs = `${exportExtension.replace(/\\|\/|:|\?|"|\*|<|>|\|/g, "-")}.zip`; + + if (lib.device) { + const directory = lib.device == "android" ? cordova.file.externalDataDirectory : cordova.file.documentsDirectory; + new Promise((resolve, reject) => window.resolveLocalFileSystemURL(directory, resolve, reject)).then(directoryEntry => new Promise((resolve, reject) => directoryEntry.getFile(fileNameToSaveAs, { + create: true + }, resolve, reject))).then(fileEntry => new Promise((resolve, reject) => fileEntry.createWriter(resolve, reject))).then(fileWriter => new Promise((resolve, reject) => { + fileWriter.onerror = reject; + fileWriter.onwriteend = resolve; + fileWriter.write(blob); + })).then(() => alert(`文件已导出至${directory}${fileNameToSaveAs}`)); + } + else { + const downloadLink = document.createElement("a"); + downloadLink.download = fileNameToSaveAs; + downloadLink.innerHTML = "Download File"; + downloadLink.href = window.URL.createObjectURL(blob); + downloadLink.click(); + } + + if (typeof finishLoad == "function") finishLoad(); + return; + } + //导入 + const UHP = error => alert(`导入失败:\n${JSON.stringify(error, null, "\t")}`); + try { + zip.load(data); + // alert(zip.file("文件夹/加扩展.js").asText()) + const str = zip.file("extension.js").asText(); + if (str === "" || undefined) throw ("你导入的不是扩展!请选择正确的文件"); + _status.importingExtension = true; + eval(str); + yield Promise.allSettled(_status.extensionLoading); + delete _status.extensionLoading; + _status.importingExtension = false; + if (!game.importedPack) throw ("err"); + const extensionName = game.importedPack.name; + if (lib.config.all.plays.contains(extensionName)) throw ("禁止安装游戏原生扩展"); + const extensions = lib.config.extensions; + if (extensions.contains(extensionName)) game.removeExtension(extensionName, true); + extensions.add(extensionName); + game.saveConfigValue("extensions"); + game.saveConfig(`extension_${extensionName}_enable`, true); + const config = game.importedPack.config; + Object.keys(config).forEach(value => { + const configObject = config[value]; + if (configObject && Object.prototype.hasOwnProperty.call(configObject, "init")) game.saveConfig(`extension_${extensionName}_${value}`, configObject.init); + }); + if (game.download) { + const files = zip.files, hiddenFileFlags = [".", "_"], fileList = Object.keys(files).filter(key => !files[key].dir && !hiddenFileFlags.includes(key[0])).reverse(); + //alert(filelist) + //电脑端 + //具备nodeJS环境 + if (lib.node && lib.node.fs) { + const writeFile = errnoException => { + if (errnoException) { + finishLoad(); + UHP(errnoException); + return; + } + if (fileList.length) { + //filename 数组 ...dir+/+file + //这里需要个创文件夹的函数 + const zipDir = fileList.pop(), fileName = zipDir.split("/"), name = fileName.pop(), letGo = name => new Promise(resolve => lib.node.fs.writeFile(`${__dirname}/extension/${extensionName}/${name}`, zip.file(zipDir).asNodeBuffer(), null, resolve)).then(writeFile); + return (fileName.length ? game.createDir(`extension/${extensionName}/${fileName.join("/")}`).then(() => letGo(`${fileName.join("/")}/${name}`)) : letGo(name)); + } + finishLoad(); + } + game.ensureDirectory(`extension/${extensionName}`).then(writeFile).catch(UHP); + } + else new Promise((resolve, reject) => window.resolveLocalFileSystemURL(lib.assetURL, resolve, reject)).then(directoryEntry => new Promise((resolve, reject) => directoryEntry.getDirectory(`extension/${extensionName}`, { + create: true + }, resolve, reject))).then(directoryEntry => { + //扩展文件夹 + const writeFile = () => { + if (!fileList.length) { + finishLoad(); + return; + } + //filename 数组 ...dir+/+file + const zipDirectory = fileList.shift(), fileName = zipDirectory.split("/"), name = fileName.pop(), letGo = name => new Promise((resolve, reject) => directoryEntry.getFile(name, { + create: true + }, resolve, reject)).then(fileEntry => new Promise((resolve, reject) => fileEntry.createWriter(resolve, reject))).then(fileWriter => new Promise((resolve, reject) => { + fileWriter.onerror = reject; + fileWriter.onwriteend = resolve; + fileWriter.write(zip.file(zipDirectory).asArrayBuffer()); + })).then(writeFile); + return (fileName.length ? game.createDir(`extension/${extensionName}/${fileName.join("/")}`).then(() => letGo(`${fileName.join("/")}/${name}`)) : letGo(name)); + }; + return writeFile(); + }).catch(UHP); + } + else { + localStorage.setItem(`${lib.configprefix}extension_${extensionName}`, str); + const hiddenFileFlags = [".", "_"], fileList = Object.keys(zip.files).filter(filePath => !hiddenFileFlags.includes(filePath[0]) && filePath[filePath.length - 1] != "/"); + if (fileList.length && lib.db) { + lib.config.extensionInfo[extensionName] = { + file: fileList + }; + game.saveConfigValue("extensionInfo"); + fileList.forEach(filePath => { + const arrayBuffer = zip.file(filePath).asArrayBuffer(); + if (!arrayBuffer) return; + const blob = new Blob([arrayBuffer]); + new Promise((resolve, reject) => { + const fileReader = new FileReader(); + fileReader.onerror = reject; + fileReader.onload = resolve; + fileReader.readAsDataURL(blob, "UTF-8"); + }).then(fileLoadedEvent => game.putDB("image", `extension-${extensionName}:${filePath}`, fileLoadedEvent.target.result)); + }); + } + finishLoad(); + } + delete game.importedPack; + } + catch (error) { + UHP(error); + return false; + } + }); + static export(textToWrite, name) { + var textFileAsBlob = new Blob([textToWrite], { type: "text/plain" }); + var fileNameToSaveAs = name || "noname"; + fileNameToSaveAs = fileNameToSaveAs.replace(/\\|\/|:|\?|"|\*|<|>|\|/g, "."); + + if (lib.device) { + var directory; + if (lib.device == "android") { + directory = cordova.file.externalDataDirectory; + } + else { + directory = cordova.file.documentsDirectory; + } + window.resolveLocalFileSystemURL(directory, function (entry) { + entry.getFile(fileNameToSaveAs, { create: true }, function (fileEntry) { + fileEntry.createWriter(function (fileWriter) { + fileWriter.onwriteend = function () { + alert("文件已导出至" + directory + fileNameToSaveAs); + } + fileWriter.write(textFileAsBlob) + }); + }); + }); + } + else { + var downloadLink = document.createElement("a"); + downloadLink.download = fileNameToSaveAs; + downloadLink.innerHTML = "Download File"; + downloadLink.href = window.URL.createObjectURL(textFileAsBlob); + downloadLink.click(); + } + } + static multiDownload2(list, onsuccess, onerror, onfinish, process, dev) { + list = list.slice(0); + var download = function () { + if (list.length) { + var current = list.shift(); + var current2; + if (typeof process == "function") { + current2 = process(current); + } + else { + current2 = current; + } + if (current.startsWith("theme")) { + game.print(current.slice(6)); + } + else if (current.startsWith("image/skin")) { + game.print(current.slice(11)); + } + else { + game.print(current.slice(current.lastIndexOf("/") + 1)); + } + game.download(current, current2, function () { + if (onsuccess) onsuccess(list.length); + download(); + }, function () { + if (onerror) onerror(list.length); + download(); + }, dev); + } + else { + if (onfinish) onfinish(); + } + } + download(); + } + static multiDownload(list, onsuccess, onerror, onfinish, process, dev) { + if (lib.config.dev) game.print(get.url()); + var args = Array.from(arguments); + if (list.length <= 3) { + game.multiDownload2.apply(this, args); + } + else { + var num = Math.round(list.length / 3); + var left = 3; + args[3] = function () { + left--; + if (left == 0) { + onfinish(); + } + }; + setTimeout(function () { + args[0] = list.slice(0, num); game.multiDownload2.apply(game, args); + }); + setTimeout(function () { + args[0] = list.slice(num, 2 * num); game.multiDownload2.apply(this, args); + }, 200); + setTimeout(function () { + args[0] = list.slice(2 * num); game.multiDownload2.apply(this, args); + }, 400); + } + } + static fetch(url, onload, onerror, onprogress) { + var tmpName = "~tmp" + get.id(); + game.download(encodeURI(url), tmpName, function () { + game.readFile(tmpName, function (data) { + onload(data); + game.removeFile(tmpName); + }, onerror); + }, onerror, null, onprogress); + } + static playVideo(time, mode) { + if (!_status.replayvideo) { + localStorage.setItem(lib.configprefix + "playbackmode", lib.config.mode); + } + game.saveConfig("mode", mode); + localStorage.setItem(lib.configprefix + "playback", time); + game.reload(); + } + static playVideoContent(video) { + var next = game.createEvent("video", false); + next.video = video; + ui.system.style.display = "none"; + ui.system.hide(); + ui.arena.style.display = "none"; + ui.arena.hide(); + ui.window.classList.remove("leftbar"); + ui.window.classList.remove("rightbar"); + ui.historybar.style.display = "none"; + _status.event = next; + _status.paused = false; + _status.paused2 = false; + _status.over = false; + _status.video = true; + clearTimeout(_status.timeout); + + for (var i in lib.characterPack) { + for (var j in lib.characterPack[i]) { + lib.character[j] = lib.character[j] || lib.characterPack[i][j]; + } + } + next.setContent("playVideoContent"); + game.loop(); + } + static reload() { + if (_status) { + if (_status.reloading) return; + _status.reloading = true; + } + if (_status.video && !_status.replayvideo) { + localStorage.removeItem(lib.configprefix + "playbackmode"); + } + localStorage.setItem("show_splash_off", true); + if (lib.status.reload) { + _status.waitingToReload = true; + } + else { + window.location.reload(); + } + } + static reload2() { + lib.status.reload--; + if (lib.status.reload == 0 && lib.ondb2.length) { + const command = lib.ondb2.shift(); + game[command[0]](...command[1]); + } + if (lib.status.reload == 0 && lib.ondb.length) { + const command = lib.ondb.shift(); + game[command[0]](...command[1]); + } + if (lib.status.reload || !_status.waitingToReload) return; + window.location.reload(); + delete _status.waitingToReload; + } + static exit() { + var ua = userAgent; + var ios = ua.includes("iphone") || ua.includes("ipad") || ua.includes("macintosh"); + //electron + if (typeof window.process == "object" && typeof window.require == "function") { + var versions = window.process.versions; + var electronVersion = parseFloat(versions.electron); + var remote; + if (electronVersion >= 14) { + remote = require("@electron/remote"); + } else { + remote = require("electron").remote; + } + var thisWindow = remote.getCurrentWindow(); + thisWindow.destroy(); + window.process.exit(); + } + // android-cordova环境 + else if (lib.device === "android") { + if (navigator.app && navigator.app.exitApp) { + navigator.app.exitApp(); + } + } + //ios-cordova环境或ios浏览器环境 + else if (lib.device === "ios" || !lib.device && ios) { + game.saveConfig("mode"); + if (_status) { + if (_status.reloading) return; + _status.reloading = true; + } + if (_status.video && !_status.replayvideo) { + localStorage.removeItem(lib.configprefix + "playbackmode"); + } + window.location.reload(); + } + //非ios的网页版 + else if (!ios) { + window.onbeforeunload = null; + window.close(); + } + } + static open(url) { + if (lib.device) { + if (cordova.InAppBrowser) { + cordova.InAppBrowser.open(url, "_system"); + } + else { + ui.create.iframe(url); + } + } + else { + window.open(url); + } + } + static reloadCurrent() { + game.saveConfig("continue_name", [game.me.name1 || game.me.name, game.me.name2]); + game.saveConfig("mode", lib.config.mode); + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + } + static update(func) { + lib.updates.push(func); + if (lib.updates.length === 1) { + game.run(); + } + return func; + } + static unupdate(func) { + lib.updates.remove(func); + } + static stop() { + cancelAnimationFrame(lib.status.frameId); + } + static run() { + if (lib.updates.length) { + cancelAnimationFrame(lib.status.frameId); + lib.status.frameId = requestAnimationFrame(function (time) { + if (lib.status.time !== 0) { + lib.status.delayed += time - lib.status.time; + } + lib.status.frameId = requestAnimationFrame(lib.run); + }); + } + } + static addVideo(type, player, content) { + if (_status.video || game.online) return; + if (!_status.videoInited) { + if (type == "arrangeLib") { + lib.video.push({ + type: type, + player: player, + content: content, + delay: 0 + }); + } + return; + } + if (type == "storage" && player && player.updateMarks) { + player.updateMarks(); + } + if (game.getVideoName) { + var time = get.time(); + if (!_status.lastVideoLog) { + _status.lastVideoLog = time; + } + if (get.itemtype(player) == "player") { + player = player.dataset.position; + } + lib.video.push({ + type: type, + player: player, + content: content, + delay: time - _status.lastVideoLog + }); + _status.lastVideoLog = time; + } + } + static draw(func) { + lib.canvasUpdates.push(func); + if (!lib.status.canvas) { + lib.status.canvas = true; + game.update(lib.updateCanvas); + } + } + static vibrate(time) { + if (typeof navigator.vibrate == "function") { + navigator.vibrate(time || 500); + } + } + static prompt() { + var str, forced, callback, noinput = false, str2 = ""; + for (var i = 0; i < arguments.length; i++) { + if (arguments[i] == "alert") { + forced = true; + noinput = true; + } + else if (typeof arguments[i] == "string") { + if (arguments[i].startsWith("###")) { + var list = arguments[i].slice(3).split("###"); + str = list[0]; + str2 = list[1]; + } + else str = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + forced = arguments[i]; + } + else if (typeof arguments[i] == "function") { + callback = arguments[i]; + } + } + if (!callback) { + callback = () => void 0; + } + var promptContainer = ui.create.div(".popup-container", ui.window, function () { + if (this.clicked) { + this.clicked = false; + } + else { + clickCancel(); + } + }); + var dialogContainer = ui.create.div(".prompt-container", promptContainer); + var dialog = ui.create.div(".menubg", ui.create.div(dialogContainer), function () { + promptContainer.clicked = true; + }); + var strnode = ui.create.div("", str || "", dialog); + var input = ui.create.node("input", ui.create.div(dialog)); + input.value = str2; + if (noinput) { + input.style.display = "none"; + } + var controls = ui.create.div(dialog); + var clickConfirm = function () { + if (noinput) { + // 给一个返回值使promise化正常使用 + callback(true); + promptContainer.remove(); + } + else { + callback(input.value); + promptContainer.remove(); + } + } + var clickCancel = function () { + callback(false); + if (!forced) { + promptContainer.remove(); + } + } + var confirmNode = ui.create.div(".menubutton.large.disabled", "确定", controls, clickConfirm); + if (!forced) { + ui.create.div(".menubutton.large", "取消", controls, clickCancel); + } + if (noinput || (str2 && str2.length > 0)) { + confirmNode.classList.remove("disabled"); + } + else { + input.onkeydown = function (e) { + if (e.keyCode == 13) { + clickConfirm(); + } + else if (e.keyCode == 27) { + clickCancel(); + } + e.stopPropagation(); + } + input.onkeyup = function (e) { + if (input.value) { + confirmNode.classList.remove("disabled"); + } + else { + confirmNode.classList.remove("disabled"); + } + e.stopPropagation(); + } + input.focus(); + } + } + static alert(str) { + game.prompt(str, "alert"); + } + static print() { + if (!_status.toprint) { + _status.toprint = []; + } + _status.toprint.push(Array.from(arguments)); + } + static linexy(path) { + const from = [path[0], path[1]], to = [path[2], path[3]]; + let total = typeof arguments[1] === "number" ? arguments[1] : lib.config.duration * 2, opacity = 1, color = [255, 255, 255], dashed = false, drag = false; + if (arguments[1] && typeof arguments[1] == "object") Object.keys(arguments[1]).forEach(value => { + switch (value) { + case "opacity": + opacity = arguments[1][value]; + break; + case "color": + color = arguments[1][value]; + break; + case "dashed": + dashed = arguments[1][value]; + break; + case "duration": total = arguments[1][value]; + } + }); + else if (typeof arguments[1] == "string") color = arguments[1]; + if (typeof color == "string") color = lib.lineColor.get(color) || [255, 255, 255]; + let node; + if (arguments[1] == "drag") { + color = [236, 201, 71]; + drag = true; + if (arguments[2]) node = arguments[2]; + else { + node = ui.create.div(".linexy.drag"); + node.style.left = `${from[0]}px`; + node.style.top = `${from[1]}px`; + node.style.background = `linear-gradient(transparent,rgba(${color.toString()},${opacity}),rgba(${color.toString()},${opacity}))`; + if (game.chess) ui.chess.appendChild(node); + else ui.arena.appendChild(node); + } + } + else { + node = ui.create.div(".linexy.hidden"); + node.style.left = `${from[0]}px`; + node.style.top = `${from[1]}px`; + node.style.background = `linear-gradient(transparent,rgba(${color.toString()},${opacity}),rgba(${color.toString()},${opacity}))`; + node.style.transitionDuration = `${total / 3000}s`; + } + const dy = to[1] - from[1], dx = to[0] - from[0]; + let deg = Math.atan(Math.abs(dy) / Math.abs(dx)) / Math.PI * 180; + if (dx >= 0) if (dy <= 0) deg += 90; + else deg = 90 - deg; + else if (dy <= 0) deg = 270 - deg; + else deg += 270; + if (drag) { + node.style.transform = `rotate(${(-deg)}deg)`; + node.style.height = `${get.xyDistance(from, to)}px`; + } + else { + node.style.transform = `rotate(${(-deg)}deg) scaleY(0)`; + node.style.height = `${get.xyDistance(from, to)}px`; + if (get.objtype(arguments[1]) == "div") arguments[1].appendChild(node); + else if (game.chess) ui.chess.appendChild(node); + else ui.arena.appendChild(node); + ui.refresh(node); + node.show(); + node.style.transform = `rotate(${(-deg)}deg) scaleY(1)`; + node.listenTransition(() => setTimeout(() => { + if (!node.classList.contains("removing")) node.delete(); + }, total / 3)); + } + return node; + } + static _linexy(path) { + var from = [path[0], path[1]]; + var to = [path[2], path[3]]; + var total = typeof arguments[1] === "number" ? arguments[1] : lib.config.duration * 2; + var opacity = 1; + var color = [255, 255, 255]; + var dashed = false; + if (typeof arguments[1] == "object") { + for (var i in arguments[1]) { + switch (i) { + case "opacity": opacity = arguments[1][i]; break; + case "color": color = arguments[1][i]; break; + case "dashed": dashed = arguments[1][i]; break; + case "duration": total = arguments[1][i]; break; + } + } + } + else if (arguments[1] == "fire" || arguments[1] == "thunder" || arguments[1] == "green") { + color = arguments[1]; + } + if (color == "fire") { + color = [255, 146, 68]; + } + else if (color == "thunder") { + color = [141, 216, 255]; + } + else if (color == "green") { + color = [141, 255, 216]; + } + var drawfunc = function (time, ctx) { + var current; + if (time < total / 3) { + ctx.strokeStyle = "rgba(" + color.toString() + "," + opacity * (time / (total / 3)) + ")"; + current = [from[0] + (to[0] - from[0]) * time / (total / 3), + from[1] + (to[1] - from[1]) * time / (total / 3)]; + } + else if (time <= total) { + current = to; + if (time > total / 1.5) { + ctx.strokeStyle = "rgba(" + color.toString() + "," + opacity * (1 - (time - total / 1.5) / (total - total / 1.5)) + ")"; + } + else { + ctx.strokeStyle = "rgba(" + color.toString() + "," + opacity + ")"; + } + } + else { + return false; + } + ctx.beginPath(); + if (dashed) { + ctx.lineCap = "butt"; + ctx.setLineDash([8, 2]); + } + else { + ctx.lineCap = "round"; + } + ctx.moveTo(from[0], from[1]); + ctx.lineTo(current[0], current[1]); + ctx.stroke(); + }; + if (arguments[2] && game.chess) { + game.draw2(drawfunc); + } + else { + game.draw(drawfunc); + } + } + static createTrigger(name, skill, player, event) { + var info = get.info(skill); + if (!info) return false; + if ((player.isOut() || player.removed) && !info.forceOut) return; + if (player.isDead() && !info.forceDie) return; + var next = game.createEvent("trigger", false); + next.skill = skill; + next.player = player; + next.triggername = name; + next.forceDie = true; + next.includeOut = true; + next._trigger = event; + next.setContent("createTrigger"); + } + /** + * @legacy Use {@link lib.element.GameEvent.constructor} instead. + */ + static createEvent(name, trigger, triggerEvent) { + const next = new lib.element.GameEvent(name, trigger); + (triggerEvent || _status.event).next.push(next); + return next; + } + static addCharacter(name, information) { + const extensionName = _status.extension || information.extension, character = [ + information.sex, + information.group, + information.hp, + information.skills || [], + [ + _status.evaluatingExtension ? `db:extension-${extensionName}:${name}.jpg` : `ext:${extensionName}/${name}.jpg`, + `die:ext:${extensionName}/${name}.mp3` + ] + ]; + if (information.tags) character[4] = character[4].concat(information.tags); + lib.character[name] = character; + const packName = `mode_extension_${extensionName}`; + if (!lib.characterPack[packName]) lib.characterPack[packName] = {}; + lib.translate[name] = information.translate; + lib.characterPack[packName][name] = character; + lib.translate[`${packName}_character_config`] = extensionName; + } + static addCharacterPack(pack, packagename) { + var extname = _status.extension || "扩展"; + let gzFlag = false; + packagename = packagename || extname; + for (var i in pack) { + if (i == "mode") { + if (pack[i] == "guozhan") gzFlag = true; + continue; + } + if (i == "forbid") continue; + for (var j in pack[i]) { + if (i == "character") { + if (!pack[i][j][4]) { + pack[i][j][4] = []; + } + var imgsrc; + if (_status.evaluatingExtension) { + imgsrc = "db:extension-" + extname + ":" + j + ".jpg"; + } + else { + imgsrc = "ext:" + extname + "/" + j + ".jpg"; + } + const audiosrc = "die:ext:" + extname + "/" + j + ".mp3"; + if (!pack[i][j][4].some(str => typeof str == "string" && /^(?:db:extension-|ext:):(?:.+)/.test(str))) pack[i][j][4].add(imgsrc); + if (!pack[i][j][4].some(str => typeof str == "string" && /^die:(?:.+)/.test(str))) pack[i][j][4].add(audiosrc); + if (pack[i][j][4].contains("boss") || + pack[i][j][4].contains("hiddenboss")) { + lib.config.forbidai.add(j); + } + if (lib.config.forbidai_user && lib.config.forbidai_user.contains(j)) { + lib.config.forbidai.add(j); + } + for (var l = 0; l < pack[i][j][3].length; l++) { + lib.skilllist.add(pack[i][j][3][l]); + } + } + else if (i == "skill") { + if (typeof pack[i][j].audio == "number" || typeof pack[i][j].audio == "boolean") { + pack[i][j].audio = "ext:" + extname + ":" + pack[i][j].audio; + } + } + if (lib[i][j] == undefined) { + lib[i][j] = pack[i][j]; + } + } + } + var packname = "mode_extension_" + packagename; + lib.characterPack[packname] = pack.character; + lib.translate[packname + "_character_config"] = packagename; + if (gzFlag) lib.characterGuozhanFilter.add(packname); + } + static addCard(name, info, info2) { + var extname = (_status.extension || info2.extension); + if (info.audio == true) { + info.audio = "ext:" + extname; + } + if (info.fullskin) { + if (_status.evaluatingExtension) { + info.image = "db:extension-" + extname + ":" + name + ".png"; + } + else { + info.image = "ext:" + extname + "/" + name + ".png"; + } + } + else if (info.fullimage) { + if (_status.evaluatingExtension) { + info.image = "db:extension-" + extname + ":" + name + ".jpg"; + } + else { + info.image = "ext:" + extname + "/" + name + ".jpg"; + } + } + lib.card[name] = info; + lib.translate[name] = info2.translate; + lib.translate[name + "_info"] = info2.description; + if (typeof info2.number == "number") { + var suits = ["heart", "spade", "diamond", "club"]; + if (info2.color == "red") { + suits = ["heart", "diamond"]; + } + else if (info2.color == "black") { + suits = ["club", "spade"]; + } + for (var i = 0; i < info2.number; i++) { + lib.card.list.push([suits[Math.floor(Math.random() * suits.length)], Math.ceil(Math.random() * 13), name]); + } + } + var packname = "mode_extension_" + extname; + if (!lib.cardPack[packname]) { + lib.cardPack[packname] = []; + lib.translate[packname + "_card_config"] = extname; + } + lib.cardPack[packname].push(name); + } + static addCardPack(pack, packagename) { + var extname = _status.extension || "扩展"; + packagename = packagename || extname; + var packname = "mode_extension_" + packagename; + lib.cardPack[packname] = []; + lib.translate[packname + "_card_config"] = packagename; + for (var i in pack) { + if (i == "mode" || i == "forbid") continue; + if (i == "list") { + for (var j = 0; j < pack[i].length; j++) { + lib.card.list.push(pack[i][j]); + } + continue; + } + for (var j in pack[i]) { + if (i == "card") { + if (pack[i][j].audio == true) { + pack[i][j].audio = "ext:" + extname; + } + if (pack[i][j].fullskin) { + if (_status.evaluatingExtension) { + pack[i][j].image = "db:extension-" + extname + ":" + j + ".png"; + } + else { + pack[i][j].image = "ext:" + extname + "/" + j + ".png"; + } + } + else if (pack[i][j].fullimage) { + if (_status.evaluatingExtension) { + pack[i][j].image = "db:extension-" + extname + ":" + j + ".jpg"; + } + else { + pack[i][j].image = "ext:" + extname + "/" + j + ".jpg"; + } + } + lib.cardPack[packname].push(j); + } + else if (i == "skill") { + if (typeof pack[i][j].audio == "number" || typeof pack[i][j].audio == "boolean") { + pack[i][j].audio = "ext:" + extname + ":" + pack[i][j].audio; + } + } + if (lib[i][j] == undefined) lib[i][j] = pack[i][j]; + } + } + } + static addSkill(name, info, translate, description, appendInfo, abInfo) { + if (lib.skill[name]) { + return false; + } + if (typeof info.audio == "number" || typeof info.audio == "boolean") { + info.audio = "ext:" + _status.extension + ":" + info.audio; + } + lib.skill[name] = info; + lib.translate[name] = translate; + lib.translate[name + "_info"] = description; + lib.translate[name + "_append"] = appendInfo; + lib.translate[`${name}_ab`] = abInfo; + return true; + } + static addMode(name, info, info2) { + lib.config.all.mode.push(name); + lib.translate[name] = info2.translate; + var imgsrc; + var extname = _status.extension || info2.extension; + if (_status.evaluatingExtension) { + imgsrc = "extension-" + extname + ":" + name + ".jpg"; + } + else { + imgsrc = "ext:" + extname + "/" + name + ".jpg"; + } + lib.mode[name] = { + name: info2.translate, + config: info2.config, + splash: imgsrc, + fromextension: true + } + lib.init["setMode_" + name] = gnc.of(function* () { + yield game.import("mode", function (lib, game, ui, get, ai, _status) { + info.name = name; + return info; + }); + }); + if (!lib.config.extensionInfo[extname]) { + lib.config.extensionInfo[extname] = {}; + } + if (!lib.config.extensionInfo[extname].mode) { + lib.config.extensionInfo[extname].mode = []; + } + if (lib.config.extensionInfo[extname].mode.indexOf(name) == -1) { + lib.config.extensionInfo[extname].mode.push(name); + } + game.saveConfig("extensionMode", lib.config.extensionInfo); + } + static addGlobalSkill(skill, player) { + var info = lib.skill[skill]; + if (!info) return false; + lib.skill.global.add(skill); + if (player) { + if (!lib.skill.globalmap[skill]) { + lib.skill.globalmap[skill] = []; + } + lib.skill.globalmap[skill].add(player); + } + if (info.trigger) { + var setTrigger = function (i, evt) { + var name = i + "_" + evt; + if (!lib.hook.globalskill[name]) { + lib.hook.globalskill[name] = []; + } + lib.hook.globalskill[name].add(skill); + lib.hookmap[evt] = true; + } + for (var i in info.trigger) { + if (typeof info.trigger[i] == "string") { + setTrigger(i, info.trigger[i]); + } + else if (Array.isArray(info.trigger[i])) { + for (var j = 0; j < info.trigger[i].length; j++) { + setTrigger(i, info.trigger[i][j]); + } + } + } + } + return true; + } + static removeGlobalSkill(skill) { + lib.skill.global.remove(skill); + delete lib.skill.globalmap[skill]; + for (var i in lib.hook.globalskill) { + lib.hook.globalskill[i].remove(skill); + } + } + static resetSkills() { + for (var i = 0; i < game.players.length; i++) { + for (var j in game.players[i].tempSkills) { + game.players[i].removeSkill(j); + } + var skills = game.players[i].getSkills(); + for (var j = 0; j < skills.length; j++) { + if (lib.skill[skills[j]].vanish) { + game.players[i].removeSkill(skills[j]); + } + } + game.players[i].in(true); + } + ui.clear(); + } + + /** + * @param {string} extensionName + */ + static hasExtension(extensionName) { + return this.hasExtensionInstalled(extensionName) && lib.config[`extension_${extensionName}_enable`]; + } + + /** + * @param {string} extensionName + */ + static hasExtensionInstalled(extensionName) { + return lib.config.extensions.includes(extensionName); + } + + /** + * @param {string} extensionName + */ + static hasExtensionLoaded(extensionName) { + return extensionName !== void 0 && _status.extensionLoaded.includes(extensionName); + } + + static runAfterExtensionLoaded(extensionName, runnable) { + if (game.hasExtensionLoaded(extensionName)) { + runnable(); + } else { + let eventName = `Noname.Init.Extension.${extensionName}.onLoad`; + let callback = () => { + lib.announce.unsubscribe(eventName, callback); + runnable(); + }; + lib.announce.subscribe(eventName, callback); + } + } + + static removeExtension(extensionName, keepFile) { + const prefix = `extension_${extensionName}`; + Object.keys(lib.config).forEach(key => { + if (key.startsWith(prefix)) game.saveConfig(key); + }); + localStorage.removeItem(`${lib.configprefix}${prefix}`); + game.deleteDB("data", prefix); + lib.config.extensions.remove(extensionName); + game.saveConfig("extensions", lib.config.extensions); + const modeList = lib.config.extensionInfo[extensionName]; + if (modeList) { + if (modeList.file) Object.values(modeList.file).forEach(filePath => game.deleteDB("image", `extension-${extensionName}:${filePath}`)); + if (modeList.mode) Object.values(modeList.mode).forEach(game.clearModeConfig); + delete lib.config.extensionInfo[extensionName]; + game.saveConfigValue("extensionInfo"); + } + if (!game.download || keepFile) return; + if (lib.node && lib.node.fs) try { + const deleteFolderRecursive = path => { + if (!lib.node.fs.existsSync(path)) return; + lib.node.fs.readdirSync(path).forEach((file, index) => { + const currentPath = `${path}/${file}`; + if (lib.node.fs.lstatSync(currentPath).isDirectory()) deleteFolderRecursive(currentPath); + else lib.node.fs.unlinkSync(currentPath); + }); + lib.node.fs.rmdirSync(path); + }; + deleteFolderRecursive(`${__dirname}/extension/${extensionName}`); + } + catch (error) { + console.log(error); + } + else new Promise((resolve, reject) => window.resolveLocalFileSystemURL(`${lib.assetURL}extension/${extensionName}`, resolve, reject)).then(directoryEntry => directoryEntry.removeRecursively()); + } + + static addRecentCharacter() { + var list = get.config("recentCharacter") || []; + for (var i = 0; i < arguments.length; i++) { + if (lib.character[arguments[i]]) { + list.remove(arguments[i]); + list.unshift(arguments[i]); + } + } + var num = parseInt(lib.config.recent_character_number); + if (list.length > num) { + list.splice(num); + } + game.saveConfig("recentCharacter", list, true); + } + static createCard(name, suit, number, nature) { + if (typeof name == "object") { + nature = name.nature; + number = name.number; + suit = name.suit; + name = name.name; + } + if (typeof name != "string") { + name = "sha"; + } + var noclick = false; + if (suit == "noclick") { + noclick = true; + suit = null; + } + if (!suit && lib.card[name].cardcolor) { + suit = lib.card[name].cardcolor; + } + if (!nature && lib.card[name].cardnature) { + nature = lib.card[name].cardnature; + } + if (typeof suit != "string") { + suit = ["heart", "diamond", "club", "spade"].randomGet(); + } + else if (suit == "black") { + suit = Math.random() < 0.5 ? "club" : "spade"; + } + else if (suit == "red") { + suit = Math.random() < 0.5 ? "diamond" : "heart"; + } + if (typeof number != "number" && typeof number != "string") { + number = Math.ceil(Math.random() * 13); + } + var card; + if (noclick) { + card = ui.create.card(ui.special, "noclick", true); + } + else { + card = ui.create.card(ui.special); + } + card.storage.vanish = true; + return card.init([suit, number, name, nature]); + } + static createCard2() { + var card = game.createCard.apply(this, arguments); + delete card.storage.vanish; + return card; + } + static forceOver(bool, callback) { + _status.event.next.length = 0; + var next = game.createEvent("finish_game"); + next.bool = bool; + next.callback = callback; + next.setContent("forceOver"); + if (_status.paused) { + game.uncheck(); + game.resume(); + } + } + static over(result) { + if (_status.over) return; + if (game.me._trueMe) game.swapPlayer(game.me._trueMe); + var i, j, k, num, table, tr, td, dialog; + _status.over = true; + ui.control.show(); + ui.clear(); + game.stopCountChoose(); + if (ui.time3) { + clearInterval(ui.time3.interval); + } + if ((game.layout == "long2" || game.layout == "nova") && !game.chess) { + ui.arena.classList.add("choose-character"); + ui.me.hide(); + ui.mebg.hide() + ui.autonode.hide(); + if (lib.config.radius_size != "off") { + ui.historybar.style.borderRadius = "0 0 0 4px"; + } + } + if (game.online) { + var dialog = ui.create.dialog(); + dialog.noforcebutton = true; + dialog.content.innerHTML = result; + dialog.forcebutton = true; + var result2 = arguments[1]; + if (result2 == true) { + dialog.content.firstChild.innerHTML = "战斗胜利"; + } + else if (result2 == false) { + dialog.content.firstChild.innerHTML = "战斗失败"; + } + ui.update(); + dialog.add(ui.create.div(".placeholder")); + for (var i = 0; i < game.players.length; i++) { + var hs = game.players[i].getCards("h"); + if (hs.length) { + dialog.add(`
${get.translation(game.players[i])}
`); + dialog.addSmall(hs); + } + } + + for (var j = 0; j < game.dead.length; j++) { + var hs = game.dead[j].getCards("h"); + if (hs.length) { + dialog.add(`
${get.translation(game.dead[j])}
`); + dialog.addSmall(hs); + } + } + + dialog.add(ui.create.div(".placeholder.slim")); + if (lib.config.background_audio) { + if (result2 === true) { + game.playAudio("effect", "win"); + } + else if (result2 === false) { + game.playAudio("effect", "lose"); + } + else { + game.playAudio("effect", "tie"); + } + } + if (!ui.exit) { + ui.create.exit(); + } + if (ui.giveup) { + ui.giveup.remove(); + delete ui.giveup; + } + if (game.servermode) { + ui.exit.firstChild.innerHTML = "返回房间"; + setTimeout(function () { + ui.exit.firstChild.innerHTML = "退出房间"; + _status.roomtimeout = true; + lib.config.reconnect_info[2] = null; + game.saveConfig("reconnect_info", lib.config.reconnect_info); + }, 10000); + } + if (ui.tempnowuxie) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + if (ui.auto) ui.auto.hide(); + if (ui.wuxie) ui.wuxie.hide(); + if (game.getIdentityList) { + for (var i = 0; i < game.players.length; i++) { + game.players[i].setIdentity(); + } + } + return; + } + if (lib.config.background_audio) { + if (result === true) { + game.playAudio("effect", "win"); + } + else if (result === false) { + game.playAudio("effect", "lose"); + } + else { + game.playAudio("effect", "tie"); + } + } + var resultbool = result; + if (typeof resultbool !== "boolean") { + resultbool = null; + } + if (result === true) result = "战斗胜利"; + if (result === false) result = "战斗失败"; + if (result == undefined) result = "战斗结束"; + dialog = ui.create.dialog(result); + dialog.noforcebutton = true; + dialog.forcebutton = true; + if (game.addOverDialog) { + game.addOverDialog(dialog, result); + } + if (typeof _status.coin == "number" && !_status.connectMode) { + var coeff = Math.random() * 0.4 + 0.8; + var added = 0; + var betWin = false; + if (result == "战斗胜利") { + if (_status.betWin) { + betWin = true; + _status.coin += 10; + } + _status.coin += 20; + if (_status.additionalReward) { + _status.coin += _status.additionalReward(); + } + switch (lib.config.mode) { + case "identity": { + switch (game.me.identity) { + case "zhu": case "zhong": case "mingzhong": + if (get.config("enhance_zhu")) { + added = 10; + } + else { + added = 20; + } + break; + case "fan": + if (get.config("enhance_zhu")) { + added = 16; + } + else { + added = 8; + } + break; + case "nei": + added = 40; + break; + } + added = added * (game.players.length + game.dead.length) / 8; + break; + } + case "guozhan": + if (game.me.identity == "ye") { + added = 8; + } + else { + added = 5 / get.totalPopulation(game.me.identity); + } + added = added * (game.players.length + game.dead.length); + break; + case "versus": + if (_status.friend) { + added = 5 * (game.players.length + _status.friend.length); + } + break; + default: + added = 10; + } + } + else { + added = 10; + } + if (lib.config.mode == "chess" && _status.mode == "combat" && get.config("additional_player")) { + added = 2; + } + _status.coin += added * coeff; + if (_status.coinCoeff) { + _status.coin *= _status.coinCoeff; + } + _status.coin = Math.ceil(_status.coin); + dialog.add(ui.create.div("", "获得" + _status.coin + "金")); + if (betWin) { + game.changeCoin(20); + dialog.content.appendChild(document.createElement("br")); + dialog.add(ui.create.div("", "(下注赢得10金)")); + } + game.changeCoin(_status.coin); + } + if (get.mode() == "versus" && _status.ladder) { + var mmr = _status.ladder_mmr; + mmr += 10 - get.rank(game.me.name, true) * 2; + if (result == "战斗胜利") { + mmr = 20 + Math.round(mmr); + if (mmr > 40) { + mmr = 40; + } + else if (mmr < 10) { + mmr = 10; + } + dialog.add(ui.create.div("", "获得 " + mmr + " 积分")); + } + else { + mmr = -30 + Math.round(mmr / 2); + if (mmr > -20) { + mmr = -20; + } + else if (mmr < -35) { + mmr = -35; + } + if (lib.storage.ladder.current < 900) { + mmr = Math.round(mmr / 4); + } + else if (lib.storage.ladder.current < 1400) { + mmr = Math.round(mmr / 2); + } + else if (lib.storage.ladder.current < 2000) { + mmr = Math.round(mmr / 1.5); + } + else if (lib.storage.ladder.current > 2500) { + mmr = Math.round(mmr * 1.5); + } + dialog.add(ui.create.div("", "失去 " + (-mmr) + " 积分")); + } + if (_status.ladder_tmp) { + lib.storage.ladder.current += 40; + delete _status.ladder_tmp; + } + lib.storage.ladder.current += mmr; + if (lib.storage.ladder.top < lib.storage.ladder.current) { + lib.storage.ladder.top = lib.storage.ladder.current; + } + game.save("ladder", lib.storage.ladder); + if (ui.ladder && game.getLadderName) { + ui.ladder.innerHTML = game.getLadderName(lib.storage.ladder.current); + } + } + if (game.players.length) { + table = document.createElement("table"); + tr = document.createElement("tr"); + tr.appendChild(document.createElement("td")); + td = document.createElement("td"); + td.innerHTML = "伤害"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "受伤"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "摸牌"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "出牌"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "杀敌"; + tr.appendChild(td); + table.appendChild(tr); + for (i = 0; i < game.players.length; i++) { + tr = document.createElement("tr"); + td = document.createElement("td"); + td.innerHTML = get.translation(game.players[i]) + (game.players[i].ai.stratagem_camouflage ? "(被伪装)" : ""); + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.players[i].stat.length; j++) { + if (game.players[i].stat[j].damage != undefined) num += game.players[i].stat[j].damage; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.players[i].stat.length; j++) { + if (game.players[i].stat[j].damaged != undefined) num += game.players[i].stat[j].damaged; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.players[i].stat.length; j++) { + if (game.players[i].stat[j].gain != undefined) num += game.players[i].stat[j].gain; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.players[i].stat.length; j++) { + for (k in game.players[i].stat[j].card) { + num += game.players[i].stat[j].card[k]; + } + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.players[i].stat.length; j++) { + if (game.players[i].stat[j].kill != undefined) num += game.players[i].stat[j].kill; + } + td.innerHTML = num; + tr.appendChild(td); + table.appendChild(tr); + } + dialog.add(ui.create.div(".placeholder")); + dialog.content.appendChild(table); + } + if (game.dead.length) { + table = document.createElement("table"); + table.style.opacity = "0.5"; + if (game.players.length == 0) { + tr = document.createElement("tr"); + tr.appendChild(document.createElement("td")); + td = document.createElement("td"); + td.innerHTML = "伤害"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "受伤"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "摸牌"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "出牌"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "杀敌"; + tr.appendChild(td); + table.appendChild(tr); + } + for (i = 0; i < game.dead.length; i++) { + tr = document.createElement("tr"); + td = document.createElement("td"); + td.innerHTML = get.translation(game.dead[i]) + (game.dead[i].ai.stratagem_camouflage ? "(被伪装)" : ""); + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.dead[i].stat.length; j++) { + if (game.dead[i].stat[j].damage != undefined) num += game.dead[i].stat[j].damage; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.dead[i].stat.length; j++) { + if (game.dead[i].stat[j].damaged != undefined) num += game.dead[i].stat[j].damaged; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.dead[i].stat.length; j++) { + if (game.dead[i].stat[j].gain != undefined) num += game.dead[i].stat[j].gain; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.dead[i].stat.length; j++) { + for (k in game.dead[i].stat[j].card) { + num += game.dead[i].stat[j].card[k]; + } + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.dead[i].stat.length; j++) { + if (game.dead[i].stat[j].kill != undefined) num += game.dead[i].stat[j].kill; + } + td.innerHTML = num; + tr.appendChild(td); + table.appendChild(tr); + } + dialog.add(ui.create.div(".placeholder")); + dialog.content.appendChild(table); + } + if (game.additionaldead && game.additionaldead.length) { + table = document.createElement("table"); + table.style.opacity = "0.5"; + for (i = 0; i < game.additionaldead.length; i++) { + tr = document.createElement("tr"); + td = document.createElement("td"); + td.innerHTML = get.translation(game.additionaldead[i]); + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.additionaldead[i].stat.length; j++) { + if (game.additionaldead[i].stat[j].damage != undefined) num += game.additionaldead[i].stat[j].damage; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.additionaldead[i].stat.length; j++) { + if (game.additionaldead[i].stat[j].damaged != undefined) num += game.additionaldead[i].stat[j].damaged; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.additionaldead[i].stat.length; j++) { + if (game.additionaldead[i].stat[j].gain != undefined) num += game.additionaldead[i].stat[j].gain; + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.additionaldead[i].stat.length; j++) { + for (k in game.additionaldead[i].stat[j].card) { + num += game.additionaldead[i].stat[j].card[k]; + } + } + td.innerHTML = num; + tr.appendChild(td); + td = document.createElement("td"); + num = 0; + for (j = 0; j < game.additionaldead[i].stat.length; j++) { + if (game.additionaldead[i].stat[j].kill != undefined) num += game.additionaldead[i].stat[j].kill; + } + td.innerHTML = num; + tr.appendChild(td); + table.appendChild(tr); + } + dialog.add(ui.create.div(".placeholder")); + dialog.content.appendChild(table); + } + dialog.add(ui.create.div(".placeholder")); + + var clients = game.players.concat(game.dead); + for (var i = 0; i < clients.length; i++) { + if (clients[i].isOnline2()) { + clients[i].send(game.over, dialog.content.innerHTML, game.checkOnlineResult(clients[i])); + } + } + + dialog.add(ui.create.div(".placeholder")); + + for (var i = 0; i < game.players.length; i++) { + if (!_status.connectMode && game.players[i].isUnderControl(true) && game.layout != "long2") continue; + var hs = game.players[i].getCards("h"); + if (hs.length) { + dialog.add(`
${get.translation(game.players[i])}
`); + dialog.addSmall(hs); + } + } + for (var i = 0; i < game.dead.length; i++) { + if (!_status.connectMode && game.dead[i].isUnderControl(true) && game.layout != "long2") continue; + var hs = game.dead[i].getCards("h"); + if (hs.length) { + dialog.add(`
${get.translation(game.dead[i])}
`); + dialog.addSmall(hs); + } + } + dialog.add(ui.create.div(".placeholder.slim")); + game.addVideo("over", null, dialog.content.innerHTML); + var vinum = parseInt(lib.config.video); + if (!_status.video && vinum && game.getVideoName && window.indexedDB && _status.videoInited) { + var store = lib.db.transaction(["video"], "readwrite").objectStore("video"); + var videos = lib.videos.slice(0); + for (var i = 0; i < videos.length; i++) { + if (videos[i].starred) { + videos.splice(i--, 1); + } + } + for (var deletei = 0; deletei < 5; deletei++) { + if (videos.length >= vinum) { + var toremove = videos.pop(); + lib.videos.remove(toremove); + store.delete(toremove.time); + } + else { + break; + } + } + var me = game.me || game.players[0]; + if (!me) return; + var newvid = { + name: game.getVideoName(), + mode: lib.config.mode, + video: lib.video, + win: result == "战斗胜利", + name1: me.name1 || me.name, + name2: me.name2, + time: lib.getUTC(new Date()) + }; + var modecharacters = lib.characterPack["mode_" + get.mode()]; + if (modecharacters) { + if (get.mode() == "guozhan") { + if (modecharacters[newvid.name1]) { + if (newvid.name1.startsWith("gz_shibing")) { + newvid.name1 = newvid.name1.slice(3, 11); + } + else { + newvid.name1 = newvid.name1.slice(3); + } + } + if (modecharacters[newvid.name2]) { + if (newvid.name2.startsWith("gz_shibing")) { + newvid.name2 = newvid.name2.slice(3, 11); + } + else { + newvid.name2 = newvid.name2.slice(3); + } + } + } + else { + if (modecharacters[newvid.name1]) { + newvid.name1 = get.mode() + "::" + newvid.name1; + } + if (modecharacters[newvid.name2]) { + newvid.name2 = get.mode() + "::" + newvid.name2; + } + } + } + if (newvid.name1 && newvid.name1.startsWith("subplayer_")) { + newvid.name1 = newvid.name1.slice(10, newvid.name1.lastIndexOf("_")); + } + if (newvid.name2 && newvid.name2.startsWith("subplayer_")) { + newvid.name1 = newvid.name2.slice(10, newvid.name1.lastIndexOf("_")); + } + lib.videos.unshift(newvid); + store.put(newvid); + ui.create.videoNode(newvid, true); + } + if (ui.auto) { + ui.auto.hide(); + } + if (ui.wuxie) ui.wuxie.hide(); + if (ui.giveup) { + ui.giveup.remove(); + delete ui.giveup; + } + + if (lib.config.test_game && !_status.connectMode) { + if (typeof lib.config.test_game !== "string") { + switch (lib.config.mode) { + case "identity": game.saveConfig("mode", "guozhan"); break; + case "guozhan": game.saveConfig("mode", "versus"); break; + case "versus": game.saveConfig("mode", "boss"); break; + case "boss": game.saveConfig("mode", "chess"); break; + case "chess": game.saveConfig("mode", "stone"); break; + case "stone": game.saveConfig("mode", "identity"); break; + } + } + setTimeout(game.reload, 500); + } + if (game.controlOver) { + game.controlOver(); return; + } + if (!_status.brawl) { + if (lib.config.mode == "boss") { + ui.create.control("再战", function () { + var pointer = game.boss; + var map = { boss: game.me == game.boss, links: [] }; + for (var iwhile = 0; iwhile < 10; iwhile++) { + pointer = pointer.nextSeat; + if (pointer == game.boss) { + break; + } + if (!pointer.side) { + map.links.push(pointer.name); + } + } + game.saveConfig("continue_name_boss", map); + game.saveConfig("mode", lib.config.mode); + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + }); + } + else if (lib.config.mode == "versus") { + if (_status.mode == "standard" || _status.mode == "three") { + ui.create.control("再战", function () { + game.saveConfig("continue_name_versus" + (_status.mode == "three" ? "_three" : ""), { + friend: _status.friendBackup, + enemy: _status.enemyBackup, + color: _status.color + }); + game.saveConfig("mode", lib.config.mode); + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + }); + } + } + else if (!_status.connectMode && get.config("continue_game") && !ui.continue_game && !_status.brawl && !game.no_continue_game) { + ui.continue_game = ui.create.control("再战", game.reloadCurrent); + } + } + if (!ui.restart) { + if (game.onlineroom && typeof game.roomId == "string") { + ui.restart = ui.create.control("restart", function () { + game.broadcastAll(function () { + if (ui.exit) { + ui.exit.stay = true; + ui.exit.firstChild.innerHTML = "返回房间"; + } + }); + game.saveConfig("tmp_owner_roomId", game.roomId); + setTimeout(game.reload, 100); + }); + } + else { + ui.restart = ui.create.control("restart", game.reload); + } + } + if (ui.tempnowuxie) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + + if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + if (ui.swap) { + ui.swap.close(); + delete ui.swap; + } + for (var i = 0; i < lib.onover.length; i++) { + lib.onover[i](resultbool); + } + if (game.addRecord) { + game.addRecord(resultbool); + } + if (window.isNonameServer) { + lib.configOL.gameStarted = false; + game.saveConfig("pagecfg" + window.isNonameServer, [lib.configOL, game.roomId, _status.onlinenickname, _status.onlineavatar]); + game.reload(); + } + else if (_status.connectMode && !game.online) { + setTimeout(game.reload, 15000) + } + } + /** + * @param { GameEvent } [belongAsyncEvent] + */ + static async loop(belongAsyncEvent) { + if (belongAsyncEvent) { + game.belongAsyncEvent = belongAsyncEvent; + } else if (game.belongAsyncEvent) { + return game.loop(game.belongAsyncEvent); + } + while (true) { + let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; + let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; + const _resolve = () => { + if (event.async) { + if (typeof event.resolve == "function") { + event.resolve(event); + } else { + throw new TypeError("异步事件的event.resolve未赋值,使用await时将会被永久等待"); + } + } + }; + if (_status.paused2 || _status.imchoosing) { + if (!lib.status.dateDelaying) { + lib.status.dateDelaying = new Date(); + } + } + if (_status.paused || _status.paused2 || _status.over) { + return; + } + if (_status.paused3) { + _status.paused3 = "paused"; + return; + } + if (lib.status.dateDelaying) { + lib.status.dateDelayed += lib.getUTC(new Date()) - lib.getUTC(lib.status.dateDelaying); + delete lib.status.dateDelaying; + } + if (event.next.length > 0) { + var next = event.next.shift(); + if (next.player && next.player.skipList.contains(next.name)) { + event.trigger(next.name + "Skipped"); + next.player.skipList.remove(next.name); + if (lib.phaseName.contains(next.name)) next.player.getHistory("skipped").add(next.name); + } + else { + next.parent = event; + _status.event = next; + game.getGlobalHistory("everything").push(next); + } + } + else if (event.finished) { + if (event._triggered == 1) { + if (event.type == "card") event.trigger("useCardToOmitted"); + event.trigger(event.name + "Omitted"); + event._triggered = 4; + } + else if (event._triggered == 2) { + if (event.type == "card") event.trigger("useCardToEnd"); + event.trigger(event.name + "End"); + event._triggered = 3; + } + else if (event._triggered == 3) { + if (event.type == "card") event.trigger("useCardToAfter"); + event.trigger(event.name + "After"); + event._triggered++; + } + else if (event.after && event.after.length) { + var next = event.after.shift(); + if (next.player && next.player.skipList.contains(next.name)) { + event.trigger(next.name + "Skipped"); + next.player.skipList.remove(next.name); + if (lib.phaseName.contains(next.name)) next.player.getHistory("skipped").add(next.name) + } + else { + next.parent = event; + _status.event = next; + } + } + else { + if (event.parent) { + if (event.result) { + event.parent._result = event.result; + } + _status.event = event.parent; + if (game.belongAsyncEvent == event) { + delete game.belongAsyncEvent; + //resolve(); + } + _resolve(); + // 此时应该退出了 + if (belongAsyncEvent && belongAsyncEvent.parent == _status.event) { + return; + } + } + else { + if (game.belongAsyncEvent == event) { + delete game.belongAsyncEvent; + //resolve(); + } + return _resolve(); + } + } + } + else { + if (event._triggered == 0) { + if (event.type == "card") event.trigger("useCardToBefore"); + event.trigger(event.name + "Before"); + event._triggered++; + } + else if (event._triggered == 1) { + if (event.type == "card") event.trigger("useCardToBegin"); + event.trigger(event.name + "Begin"); + event._triggered++; + } + else { + event.callHandler(event.getDefaultHandlerType(), event, { + state: "begin" + }); + const after = () => { + event.clearStepCache(); + event.callHandler(event.getDefaultHandlerType(), event, { + state: "end" + }); + if (typeof event.step == "number") ++event.step; + }; + if (player && player.classList.contains("dead") && !event.forceDie && event.name != "phaseLoop") { + game.broadcastAll(function () { + while (_status.dieClose.length) { + _status.dieClose.shift().close(); + } + }); + if (event._oncancel) { + event._oncancel(); + } + event.finish(); + after(); + } + else if (player && player.removed && event.name != "phaseLoop") { + event.finish(); + after(); + } + else if (player && player.isOut() && event.name != "phaseLoop" && !event.includeOut) { + if (event.name == "phase" && player == _status.roundStart && !event.skill) { + _status.roundSkipped = true; + } + event.finish(); + after(); + } + else { + await game.runContent(belongAsyncEvent).catch(e => { + if (_status.withError || lib.config.compatiblemode || (_status.connectMode && !lib.config.debug)) { + game.print("游戏出错:" + event.name); + game.print(e.toString()); + console.log(e); + } + else throw e; + }).then(after); + } + } + } + } + } + static runContent(belongAsyncEvent) { + return new Promise(resolve => { + let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; + let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; + if (event.content instanceof GeneratorFunction) { + if (!event.debugging) { + if (event.generatorContent) event.generatorContent.return(); + event.generatorContent = event.content(event, step, source, player, target, targets, + card, cards, skill, forced, num, trigger, result, + _status, lib, game, ui, get, ai); + } else { + delete event.debugging; + } + var next = event.generatorContent.next(); + if (typeof next.value == "function" && next.value.toString() == "code=>eval(code)") { + //触发debugger + var inputCallback = inputResult => { + if (inputResult === false) { + event.debugging = true; + game.resume2(); + } else { + alert(get.stringify(next.value(inputResult))); + game.prompt("", "debugger调试", inputCallback); + } + } + game.prompt("", "debugger调试", inputCallback); + return game.pause2(); + } + if (event.finished) event.generatorContent.return(); + resolve(); + } + else if (event.content instanceof AsyncFunction) { + // _status,lib,game,ui,get,ai六个变量由game.import提供 + event.content(event, trigger, player).then(() => { + event.finish(); + resolve(); + }); + } + else { + event.content(event, step, source, player, target, targets, + card, cards, skill, forced, num, trigger, result, + _status, lib, game, ui, get, ai); + resolve(); + } + }); + } + static pause() { + clearTimeout(_status.timeout); + _status.paused = true; + } + static pause2() { + if (_status.connectMode) return; + _status.paused2 = true; + } + static resume() { + if (_status.paused) { + if (!_status.noclearcountdown) { + game.stopCountChoose(); + } + _status.paused = false; + delete _status.waitingForTransition; + game.loop(); + } + } + static resume2() { + if (_status.connectMode) return; + if (_status.paused2) { + _status.paused2 = false; + game.loop(); + } + } + static delaye() { + var next = game.createEvent("delay", false); + next.setContent("delay"); + next._args = Array.from(arguments); + return next; + } + static delayex() { + var next = game.createEvent("delayx", false); + next.setContent("delay"); + next._args = Array.from(arguments); + return next; + } + static delay(time, time2) { + if (_status.paused) return; + game.pause(); + if (typeof time != "number") time = 1; + if (typeof time2 != "number") time2 = 0; + time = time * lib.config.duration + time2; + if (lib.config.speed == "vvfast") time /= 3; + _status.timeout = setTimeout(game.resume, time); + } + static delayx(time, time2) { + if (typeof time != "number") time = 1; + switch (lib.config.game_speed) { + case "vslow": time *= 2.5; break; + case "slow": time *= 1.5; break; + case "fast": time *= 0.7; break; + case "vfast": time *= 0.4; break; + case "vvfast": time *= 0.2; break; + } + return game.delay(time, time2); + } + static check(event) { + var i, j, range; + if (event == undefined) event = _status.event; + event._checked = true; + var custom = event.custom || {}; + var ok = true, auto = true; + var player = event.player; + var auto_confirm = lib.config.auto_confirm; + var players = game.players.slice(0); + if (event.deadTarget) players.addArray(game.dead); + if (!event.filterButton && !event.filterCard && !event.filterTarget && (!event.skill || !event._backup)) { + if (event.choosing) { + _status.imchoosing = true; + } + return; + } + player.node.equips.classList.remove("popequip"); + if (event.filterButton) { + var dialog = event.dialog; + range = get.select(event.selectButton); + var selectableButtons = false; + if (event.forceAuto && ui.selected.buttons.length == range[1]) auto = true; + else if (range[0] != range[1] || range[0] > 1) auto = false; + for (i = 0; i < dialog.buttons.length; i++) { + if (dialog.buttons[i].classList.contains("unselectable")) continue; + if (event.filterButton(dialog.buttons[i], player) && lib.filter.buttonIncluded(dialog.buttons[i])) { + if (ui.selected.buttons.length < range[1]) { + dialog.buttons[i].classList.add("selectable"); + } + else if (range[1] <= -1) { + dialog.buttons[i].classList.add("selected"); + ui.selected.buttons.add(dialog.buttons[i]); + } + else { + dialog.buttons[i].classList.remove("selectable"); + } + } + else { + dialog.buttons[i].classList.remove("selectable"); + if (range[1] <= -1) { + dialog.buttons[i].classList.remove("selected"); + ui.selected.buttons.remove(dialog.buttons[i]); + } + } + if (dialog.buttons[i].classList.contains("selected")) { + dialog.buttons[i].classList.add("selectable"); + } + else if (!selectableButtons && dialog.buttons[i].classList.contains("selectable")) { + selectableButtons = true; + } + } + if (ui.selected.buttons.length < range[0]) { + if (!event.forced || selectableButtons) { + ok = false; + } + if (event.complexSelect || event.getParent().name == "chooseCharacter" || event.getParent().name == "chooseButtonOL") { + ok = false; + } + } + if (custom.add.button) { + custom.add.button(); + } + } + if (event.filterCard) { + if (ok == false) { + game.uncheck("card"); + } + else { + var cards = player.getCards(event.position); + var firstCheck = false; + range = get.select(event.selectCard); + if (!event._cardChoice && typeof event.selectCard != "function" && + !event.complexCard && range[1] > -1 && !lib.config.compatiblemode) { + event._cardChoice = []; + firstCheck = true; + } + if (event.isMine() && event.name == "chooseToUse" && event.parent.name == "phaseUse" && !event.skill && + !event._targetChoice && !firstCheck && window.Map && !lib.config.compatiblemode) { + event._targetChoice = new Map(); + for (var i = 0; i < event._cardChoice.length; i++) { + if (!lib.card[event._cardChoice[i].name].complexTarget) { + var targets = []; + for (var j = 0; j < players.length; j++) { + if (event.filterTarget(event._cardChoice[i], player, players[j])) { + targets.push(players[j]); + } + } + event._targetChoice.set(event._cardChoice[i], targets); + } + } + } + var selectableCards = false; + if (range[0] != range[1] || range[0] > 1) auto = false; + for (i = 0; i < cards.length; i++) { + if (lib.config.cardtempname != "off") { + var cardname = get.name(cards[i]); + if (cards[i].name != cardname || !get.is.sameNature(get.nature(cards[i]), cards[i].nature, true)) { + var node = ui.create.cardTempName(cards[i]); + var cardtempnameConfig = lib.config.cardtempname; + if (cardtempnameConfig !== "default") node.classList.remove("vertical"); + } + } + var nochess = true; + if (!lib.filter.cardAiIncluded(cards[i])) { + nochess = false; + } + else if (event._cardChoice && !firstCheck) { + if (!event._cardChoice.contains(cards[i])) { + nochess = false; + } + } + else { + if (player.isOut() || !lib.filter.cardRespondable(cards[i], player) || + cards[i].classList.contains("uncheck") || + !event.filterCard(cards[i], player)) { + nochess = false; + } + } + if (nochess) { + if (ui.selected.cards.length < range[1]) { + cards[i].classList.add("selectable"); + if (event._cardChoice && firstCheck) { + event._cardChoice.push(cards[i]); + } + } + else if (range[1] <= -1) { + cards[i].classList.add("selected"); + cards[i].updateTransform(true); + ui.selected.cards.add(cards[i]); + } + else { + cards[i].classList.remove("selectable"); + } + } + else { + cards[i].classList.remove("selectable"); + if (range[1] <= -1) { + cards[i].classList.remove("selected"); + cards[i].updateTransform(); + ui.selected.cards.remove(cards[i]); + } + } + if (cards[i].classList.contains("selected")) { + cards[i].classList.add("selectable"); + } + else if (!selectableCards && cards[i].classList.contains("selectable")) { + selectableCards = true; + } + } + if (ui.selected.cards.length < range[0]) { + if (!event.forced || selectableCards || event.complexSelect) { + ok = false; + } + } + + if (lib.config.popequip && get.is.phoneLayout() && + typeof event.position == "string" && event.position.includes("e") && + player.node.equips.querySelector(".card.selectable")) { + player.node.equips.classList.add("popequip"); + auto_confirm = false; + } + } + if (custom.add.card) { + custom.add.card(); + } + } + if (event.filterTarget) { + if (ok == false) { + game.uncheck("target"); + } + else { + var card = get.card(); + var firstCheck = false; + range = get.select(event.selectTarget); + var selectableTargets = false; + if (range[0] != range[1] || range[0] > 1) auto = false; + for (i = 0; i < players.length; i++) { + var nochess = true; + if (game.chess && !event.chessForceAll && player && get.distance(player, players[i], "pure") > 7) { + nochess = false; + } + else if (players[i].isOut()) { + nochess = false; + } + else if (event._targetChoice && event._targetChoice.has(card)) { + var targetChoice = event._targetChoice.get(card); + if (!Array.isArray(targetChoice) || !targetChoice.contains(players[i])) { + nochess = false; + } + } + else if (!event.filterTarget(card, player, players[i])) { + nochess = false; + } + if (nochess) { + if (ui.selected.targets.length < range[1]) { + players[i].classList.add("selectable"); + if (Array.isArray(event._targetChoice)) { + event._targetChoice.push(players[i]); + } + } + else if (range[1] <= -1) { + players[i].classList.add("selected"); + ui.selected.targets.add(players[i]); + } + else { + players[i].classList.remove("selectable"); + } + } + else { + players[i].classList.remove("selectable"); + if (range[1] <= -1) { + players[i].classList.remove("selected"); + ui.selected.targets.remove(players[i]); + } + } + if (players[i].classList.contains("selected")) { + players[i].classList.add("selectable"); + } + else if (!selectableTargets && players[i].classList.contains("selectable")) { + selectableTargets = true; + } + if (players[i].instance) { + if (players[i].classList.contains("selected")) { + players[i].instance.classList.add("selected"); + } + else { + players[i].instance.classList.remove("selected"); + } + if (players[i].classList.contains("selectable")) { + players[i].instance.classList.add("selectable"); + } + else { + players[i].instance.classList.remove("selectable"); + } + } + } + if (ui.selected.targets.length < range[0]) { + if (!event.forced || selectableTargets || event.complexSelect) { + ok = false; + } + } + if (range[1] <= -1 && ui.selected.targets.length == 0 && event.targetRequired) { + ok = false; + } + } + if (custom.add.target) { + custom.add.target(); + } + } + if (!event.skill && get.noSelected() && !_status.noconfirm) { + var skills = [], enable, info; + var skills2; + if (event._skillChoice) { + skills2 = event._skillChoice; + for (var i = 0; i < skills2.length; i++) { + if (event.isMine() || !event._aiexclude.contains(skills2[i])) { + skills.push(skills2[i]); + } + } + } + else { + var skills2; + if (get.mode() == "guozhan" && player.hasSkillTag("nomingzhi", false, null, true)) { + skills2 = player.getSkills(false, true, false); + } + else { + skills2 = player.getSkills("invisible", true, false); + } + skills2 = game.filterSkills(skills2.concat(lib.skill.global), player, player.getSkills("e").concat(lib.skill.global)); + event._skillChoice = []; + game.expandSkills(skills2); + for (i = 0; i < skills2.length; i++) { + info = get.info(skills2[i]); + enable = false; + if (typeof info.enable == "function") enable = info.enable(event); + else if (Array.isArray(info.enable)) enable = info.enable.contains(event.name); + else if (info.enable == "phaseUse") enable = (event.type == "phase"); + else if (typeof info.enable == "string") enable = (info.enable == event.name); + if (enable) { + if (!game.expandSkills(player.getSkills(false).concat(lib.skill.global)).contains(skills2[i]) && (info.noHidden || get.mode() != "guozhan" || player.hasSkillTag("nomingzhi", false, null, true))) enable = false; + if (info.filter && !info.filter(event, player)) enable = false; + if (info.viewAs && typeof info.viewAs != "function" && event.filterCard && !event.filterCard(info.viewAs, player, event)) enable = false; + if (info.viewAs && typeof info.viewAs != "function" && info.viewAsFilter && info.viewAsFilter(player) == false) enable = false; + if (info.usable && get.skillCount(skills2[i]) >= info.usable) enable = false; + if (info.chooseButton && _status.event.noButton) enable = false; + if (info.round && (info.round - (game.roundNumber - player.storage[skills2[i] + "_roundcount"]) > 0)) enable = false; + if (player.storage[`temp_ban_${skills2[i]}`] === true) enable = false; + } + if (enable) { + if (event.isMine() || !event._aiexclude.contains(skills2[i])) { + skills.add(skills2[i]); + } + event._skillChoice.add(skills2[i]); + } + } + } + + var globalskills = []; + var globallist = lib.skill.global.slice(0); + game.expandSkills(globallist); + for (var i = 0; i < skills.length; i++) { + if (globallist.contains(skills[i])) { + globalskills.push(skills.splice(i--, 1)[0]); + } + } + var equipskills = []; + var ownedskills = player.getSkills("invisible", false); + game.expandSkills(ownedskills); + for (var i = 0; i < skills.length; i++) { + if (!ownedskills.contains(skills[i])) { + equipskills.push(skills.splice(i--, 1)[0]); + } + } + if (equipskills.length) { + ui.create.skills3(equipskills); + } + else if (ui.skills3) { + ui.skills3.close(); + } + if (skills.length) { + ui.create.skills(skills); + } + else if (ui.skills) { + ui.skills.close(); + } + if (globalskills.length) { + ui.create.skills2(globalskills); + } + else if (ui.skills2) { + ui.skills2.close(); + } + } + else { + if (ui.skills) { + ui.skills.close() + } + if (ui.skills2) { + ui.skills2.close() + } + if (ui.skills3) { + ui.skills3.close() + } + } + _status.multitarget = false; + var skillinfo = get.info(_status.event.skill); + if (_status.event.name == "chooseToUse") { + if (skillinfo && skillinfo.multitarget && !skillinfo.multiline) { + _status.multitarget = true; + } + if ((skillinfo && skillinfo.viewAs && typeof skillinfo.viewAs != "function") || !_status.event.skill) { + var cardinfo = get.info(get.card()); + if (cardinfo && (cardinfo.multitarget || cardinfo.complexSelect) && !cardinfo.multiline) { + _status.multitarget = true; + } + } + } + else if (_status.event.multitarget) { + _status.multitarget = true; + } + if (event.isMine()) { + if (game.chess && game.me && get.config("show_distance")) { + for (var i = 0; i < players.length; i++) { + if (players[i] == game.me) { + players[i].node.action.hide(); + } + else { + players[i].node.action.show(); + var dist = get.distance(game.me, players[i], "pure"); + var dist2 = get.distance(game.me, players[i]); + players[i].node.action.innerHTML = "距离:" + dist2 + "/" + dist; + if (dist > 7) { + players[i].node.action.classList.add("thunder"); + } + else { + players[i].node.action.classList.remove("thunder"); + } + } + } + } + if (ok && (!event.filterOk || event.filterOk()) && auto && (auto_confirm || (skillinfo && skillinfo.direct)) && (!_status.mousedragging || !_status.mouseleft) && + !_status.mousedown && !_status.touchnocheck) { + if (ui.confirm) { + if (!skillinfo || !skillinfo.preservecancel) { + ui.confirm.close(); + } + } + if (skillinfo && skillinfo.preservecancel && !ui.confirm) { + ui.create.confirm("c"); + } + if (event.skillDialog == true) event.skillDialog = false; + ui.click.ok(); + _status.mousedragging = null; + } + else { + ui.arena.classList.add("selecting"); + if (event.filterTarget && (!event.filterCard || !event.position || (typeof event.position == "string" && event.position.indexOf("e") == -1))) { + ui.arena.classList.add("tempnoe"); + } + game.countChoose(); + if (!_status.noconfirm && !_status.event.noconfirm) { + if (!_status.mousedown || _status.mouseleft) { + var str = ""; + if (ok && (!event.filterOk || event.filterOk())) str += "o"; + if (!event.forced && !event.fakeforce && get.noSelected()) str += "c"; + ui.create.confirm(str); + } + } + } + if (ui.confirm && ui.confirm.lastChild.link == "cancel") { + if (_status.event.type == "phase" && !_status.event.skill) { + ui.confirm.lastChild.innerHTML = "结束"; + } + else { + ui.confirm.lastChild.innerHTML = "取消"; + } + } + } + return ok; + } + static uncheck() { + var i, j; + if (game.chess) { + var shadows = ui.chessContainer.getElementsByClassName("playergrid temp"); + while (shadows.length) { + shadows[0].remove(); + } + } + var argc = arguments.length; + var args = new Array(argc); + for (var i = 0; i < argc; i++) { + args[i] = arguments[i]; + } + if ((args.length == 0 || args.contains("card")) && _status.event.player) { + var cards = _status.event.player.getCards("hejsx"); + for (j = 0; j < cards.length; j++) { + cards[j].classList.remove("selected"); + cards[j].classList.remove("selectable"); + if (cards[j]._tempName) { + cards[j]._tempName.delete(); + delete cards[j]._tempName; + } + cards[j].updateTransform(); + } + ui.selected.cards.length = 0; + _status.event.player.node.equips.classList.remove("popequip"); + } + var players = game.players.slice(0); + if (_status.event.deadTarget) players.addArray(game.dead); + if ((args.length == 0 || args.contains("target"))) { + for (j = 0; j < players.length; j++) { + players[j].classList.remove("selected"); + players[j].classList.remove("selectable"); + if (players[j].instance) { + players[j].instance.classList.remove("selected"); + players[j].instance.classList.remove("selectable"); + } + } + ui.selected.targets.length = 0; + } + if ((args.length == 0 || args.contains("button")) && _status.event.dialog && _status.event.dialog.buttons) { + for (var j = 0; j < _status.event.dialog.buttons.length; j++) { + _status.event.dialog.buttons[j].classList.remove("selectable"); + _status.event.dialog.buttons[j].classList.remove("selected"); + } + ui.selected.buttons.length = 0; + } + if (args.length == 0) { + ui.arena.classList.remove("selecting"); + ui.arena.classList.remove("tempnoe"); + _status.imchoosing = false; + _status.lastdragchange.length = 0; + _status.mousedragging = null; + _status.mousedragorigin = null; + + while (ui.touchlines.length) { + ui.touchlines.shift().delete(); + } + } + ui.canvas.width = ui.arena.offsetWidth; + ui.canvas.height = ui.arena.offsetHeight; + for (var i = 0; i < players.length; i++) { + players[i].unprompt(); + } + for (var i = 0; i < _status.dragline.length; i++) { + if (_status.dragline[i]) _status.dragline[i].remove(); + } + ui.arena.classList.remove("dragging"); + _status.dragline.length = 0; + } + static swapSeat(player1, player2, prompt, behind, noanimate) { + if (noanimate) { + player1.style.transition = "all 0s"; + player2.style.transition = "all 0s"; + ui.refresh(player1); + ui.refresh(player2); + } + if (behind) { + var totalPopulation = game.players.length + game.dead.length + 1; + for (var iwhile = 0; iwhile < totalPopulation; iwhile++) { + if (player1.next != player2) { + game.swapSeat(player1, player1.next, false, false); + } + else { + break; + } + } + if (prompt != false) { + game.log(player1, "将座位移至", player2, "后"); + } + } + else { + game.addVideo("swapSeat", null, [player1.dataset.position, player2.dataset.position]); + var seat1 = player1.seatNum; + var seat2 = player2.seatNum; + player2.seatNum = seat1; + player1.seatNum = seat2; + var temp1, pos, i, num; + temp1 = player1.dataset.position; + player1.dataset.position = player2.dataset.position; + player2.dataset.position = temp1; + game.arrangePlayers(); + if (!game.chess) { + if (player1.dataset.position == "0" || player2.dataset.position == "0") { + pos = parseInt(player1.dataset.position); + if (pos == 0) pos = parseInt(player2.dataset.position); + num = game.players.length + game.dead.length; + for (i = 0; i < game.players.length; i++) { + temp1 = parseInt(game.players[i].dataset.position) - pos; + if (temp1 < 0) temp1 += num; + game.players[i].dataset.position = temp1; + } + for (i = 0; i < game.dead.length; i++) { + temp1 = parseInt(game.dead[i].dataset.position) - pos; + if (temp1 < 0) temp1 += num; + game.dead[i].dataset.position = temp1; + } + } + } + if (prompt != false) { + game.log(player1, "和", player2, "交换了座位"); + } + } + if (noanimate) { + setTimeout(function () { + player1.style.transition = ""; + player2.style.transition = ""; + }, 200); + } + } + static swapPlayer(player, player2) { + if (player2) { + if (player == game.me) game.swapPlayer(player2); + else if (player2 == game.me) game.swapPlayer(player); + } + else { + if (player == game.me) return; + var players = game.players.concat(game.dead); + for (var i = 0; i < players.length; i++) { + players[i].style.transition = "all 0s"; + } + game.addVideo("swapPlayer", player, get.cardsInfo(player.getCards("h"))); + if (!game.chess) { + var pos = parseInt(player.dataset.position); + var num = game.players.length + game.dead.length; + var players = game.players.concat(game.dead); + var temp; + for (var i = 0; i < players.length; i++) { + temp = parseInt(players[i].dataset.position) - pos; + if (temp < 0) temp += num; + players[i].dataset.position = temp; + } + } + game.me.node.handcards1.remove(); + game.me.node.handcards2.remove(); + var current = game.me; + game.me = player; + if (current.isDead()) { + current.$die(); + } + ui.handcards1 = player.node.handcards1.animate("start").fix(); + ui.handcards2 = player.node.handcards2.animate("start").fix(); + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + + ui.updatehl(); + } + if (game.me.isAlive()) { + if (ui.auto) ui.auto.show(); + if (ui.wuxie) ui.wuxie.show(); + if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + if (ui.swap) { + ui.swap.close(); + delete ui.swap; + } + if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + } + if (lib.config.mode == "identity") { + game.me.setIdentity(game.me.identity); + } + setTimeout(function () { + for (var i = 0; i < players.length; i++) { + players[i].style.transition = ""; + } + }, 100); + } + static swapControl(player) { + if (player == game.me) return; + + game.me.node.handcards1.remove(); + game.me.node.handcards2.remove(); + + game.me = player; + ui.handcards1 = player.node.handcards1.animate("start").fix(); + ui.handcards2 = player.node.handcards2.animate("start").fix(); + ui.handcards1Container.insertBefore(ui.handcards1, ui.handcards1Container.firstChild); + ui.handcards2Container.insertBefore(ui.handcards2, ui.handcards2Container.firstChild); + ui.updatehl(); + game.addVideo("swapControl", player, get.cardsInfo(player.getCards("h"))); + + if (game.me.isAlive()) { + if (ui.auto) ui.auto.show(); + if (ui.wuxie) ui.wuxie.show(); + if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + if (ui.swap) { + ui.swap.close(); + delete ui.swap; + } + if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + } + } + static swapPlayerAuto(player) { + if (game.modeSwapPlayer) { + game.modeSwapPlayer(player); + } + else { + game.swapPlayer(player); + } + } + static findNext(player) { + var players = get.players(lib.sort.position); + var position = parseInt(player.dataset.position); + for (var i = 0; i < players.length; i++) { + if (parseInt(players[i].dataset.position) >= position) { + return players[i]; + } + } + return players[0]; + } + static loadModeAsync(name, callback) { + window.game = game; + var script = lib.init.js(lib.assetURL + "mode", name, gnc.of(function* () { + yield Promise.allSettled(_status.importing.mode); + if (!lib.config.dev) delete window.game; + script.remove(); + var content = lib.imported.mode[name]; + delete lib.imported.mode[name]; + if (get.is.empty(lib.imported.mode)) { + delete lib.imported.mode; + } + callback(content); + })); + } + static switchMode(name, configx) { + if (!lib.layoutfixed.contains(name)) { + if (lib.config.layout != game.layout) { + lib.init.layout(lib.config.layout); + } + else if (lib.config.mode == "brawl") { + if (lib.config.player_border == "normal" && (game.layout == "long" || game.layout == "long2")) { + ui.arena.classList.add("lslim_player"); + } + } + } + window.game = game; + var script = lib.init.js(lib.assetURL + "mode", name, gnc.of(function* () { + yield Promise.allSettled(_status.importing.mode); + if (!lib.config.dev) delete window.game; + script.remove(); + var mode = lib.imported.mode; + _status.sourcemode = lib.config.mode; + lib.config.mode = name; + + var i, j, k; + for (i in mode[lib.config.mode].element) { + if (!lib.element[i]) lib.element[i] = []; + for (j in mode[lib.config.mode].element[i]) { + if (j == "init") { + if (!lib.element[i].inits) lib.element[i].inits = []; + lib.element[i].inits.push(mode[lib.config.mode].element[i][j]); + } + else { + lib.element[i][j] = mode[lib.config.mode].element[i][j]; + } + } + } + for (i in mode[lib.config.mode].ai) { + if (typeof mode[lib.config.mode].ai[i] == "object") { + if (ai[i] == undefined) ai[i] = {}; + for (j in mode[lib.config.mode].ai[i]) { + ai[i][j] = mode[lib.config.mode].ai[i][j]; + } + } + else { + ai[i] = mode[lib.config.mode].ai[i]; + } + } + for (i in mode[lib.config.mode].ui) { + if (typeof mode[lib.config.mode].ui[i] == "object") { + if (ui[i] == undefined) ui[i] = {}; + for (j in mode[lib.config.mode].ui[i]) { + ui[i][j] = mode[lib.config.mode].ui[i][j]; + } + } + else { + ui[i] = mode[lib.config.mode].ui[i]; + } + } + for (i in mode[lib.config.mode].game) { + game[i] = mode[lib.config.mode].game[i]; + } + for (i in mode[lib.config.mode].get) { + get[i] = mode[lib.config.mode].get[i]; + } + if (game.onwash) { + lib.onwash.push(game.onwash); + delete game.onwash; + } + if (game.onover) { + lib.onover.push(game.onover); + delete game.onover; + } + lib.config.banned = lib.config[lib.config.mode + "_banned"] || []; + lib.config.bannedcards = lib.config[lib.config.mode + "_bannedcards"] || []; + + for (i in mode[lib.config.mode]) { + if (i == "element") continue; + if (i == "game") continue; + if (i == "ai") continue; + if (i == "ui") continue; + if (i == "get") continue; + if (i == "config") continue; + if (i == "start") continue; + if (i == "startBefore") continue; + if (lib[i] == undefined) lib[i] = (Array.isArray(mode[lib.config.mode][i])) ? [] : {}; + for (j in mode[lib.config.mode][i]) { + lib[i][j] = mode[lib.config.mode][i][j]; + } + } + + // var pilecfg=lib.config.customcardpile[get.config("cardpilename")]; + // if(pilecfg){ + // lib.config.bannedpile=pilecfg[0]||{}; + // lib.config.addedpile=pilecfg[1]||{}; + // } + + _status.event = lib.element.GameEvent.initialGameEvent(); + _status.paused = false; + + if (_status.connectMode && lib.mode[name].connect) { + game.saveConfig("connect_mode", name); + game.clearConnect(); + lib.configOL.mode = name; + if (configx) { + for (var i in configx) { + lib.configOL[i] = configx[i]; + } + } + else { + for (var i in lib.mode[name].connect) { + if (i == "update") continue; + lib.configOL[i.slice(8)] = get.config(i); + } + lib.configOL.zhinang_tricks = lib.config.connect_zhinang_tricks; + lib.configOL.characterPack = lib.connectCharacterPack.slice(0); + lib.configOL.cardPack = lib.connectCardPack.slice(0); + for (var i = 0; i < lib.config.connect_characters.length; i++) { + lib.configOL.characterPack.remove(lib.config.connect_characters[i]); + } + for (var i = 0; i < lib.config.connect_cards.length; i++) { + lib.configOL.cardPack.remove(lib.config.connect_cards[i]); + } + lib.configOL.banned = lib.config["connect_" + name + "_banned"]; + lib.configOL.bannedcards = lib.config["connect_" + name + "_bannedcards"]; + } + lib.configOL.version = lib.versionOL; + for (var i in lib.cardPackList) { + if (lib.configOL.cardPack.contains(i)) { + lib.card.list = lib.card.list.concat(lib.cardPackList[i]); + } + } + for (i = 0; i < lib.card.list.length; i++) { + if (lib.card.list[i][2] == "huosha") { + lib.card.list[i] = lib.card.list[i].slice(0); + lib.card.list[i][2] = "sha"; + lib.card.list[i][3] = "fire"; + } + else if (lib.card.list[i][2] == "leisha") { + lib.card.list[i] = lib.card.list[i].slice(0); + lib.card.list[i][2] = "sha"; + lib.card.list[i][3] = "thunder"; + } + if (!lib.card[lib.card.list[i][2]]) { + lib.card.list.splice(i, 1); i--; + } + else if (lib.card[lib.card.list[i][2]].mode && + lib.card[lib.card.list[i][2]].mode.contains(lib.config.mode) == false) { + lib.card.list.splice(i, 1); i--; + } + } + } + + if (!lib.config.show_playerids || !game.showIdentity) { + ui.playerids.style.display = "none"; + } + else { + ui.playerids.style.display = ""; + } + + if (mode[lib.config.mode].startBefore) mode[lib.config.mode].startBefore(); + game.createEvent("game", false).setContent(mode[lib.config.mode].start); + if (lib.mode[lib.config.mode] && lib.mode[lib.config.mode].fromextension) { + var startstr = mode[lib.config.mode].start.toString(); + if (startstr.indexOf("onfree") == -1) { + setTimeout(lib.init.onfree, 500); + } + } + delete lib.imported.mode[name]; + + if (!lib.db) { + try { + lib.storage = JSON.parse(localStorage.getItem(lib.configprefix + lib.config.mode)); + if (typeof lib.storage != "object") throw ("err"); + if (lib.storage == null) throw ("err"); + } + catch (err) { + lib.storage = {}; + localStorage.setItem(lib.configprefix + lib.config.mode, "{}"); + } + game.loop(); + } + else { + game.getDB("data", lib.config.mode, function (obj) { + lib.storage = obj || {}; + game.loop(); + }); + } + })); + } + static loadMode(mode) { + var next = game.createEvent("loadMode", false); + next.mode = mode; + next.setContent("loadMode"); + } + static loadPackage() { + var next = game.createEvent("loadPackage"); + next.packages = []; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + next.packages.push(arguments[i]); + } + } + next.setContent("loadPackage"); + } + static phaseLoop(player) { + var next = game.createEvent("phaseLoop"); + next.player = player; + next._isStandardLoop = true; + next.setContent("phaseLoop"); + } + static gameDraw(player, num) { + var next = game.createEvent("gameDraw"); + next.player = player || game.me; + if (num == undefined) next.num = 4; + else next.num = num; + next.setContent("gameDraw"); + return next; + } + static chooseCharacterDouble() { + var next = game.createEvent("chooseCharacter"); + var config, width, num, ratio, func, update, list, first; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + if (!width) { + width = arguments[i]; + } + else if (!num) { + num = arguments[i]; + } + else { + ratio = arguments[i]; + } + } + else if (typeof arguments[i] == "function") { + if (!func) { + func = arguments[i]; + } + else { + update = arguments[i]; + } + } + else if (Array.isArray(arguments[i])) { + list = arguments[i]; + } + else if (get.objtype(arguments[i]) == "object") { + config = arguments[i]; + } + } + if (!config) { + list = config; + config = {}; + } + config.width = config.width || width || 8; + config.height = 4; + config.size = config.width * config.height; + config.num = config.num || num || 3; + config.ratio = config.ratio || ratio || 1.2; + config.update = config.update || update; + if (!Object.prototype.hasOwnProperty.call(config, "first")) { + if (typeof first == "boolean") { + config.first = first; + } + else { + config.first = "rand"; + } + } + if (!list) { + list = []; + for (var i in lib.character) { + if (typeof func == "function") { + if (!func(i)) continue; + } + else { + if (lib.filter.characterDisabled(i)) continue; + } + list.push(i); + } + } + next.config = config; + next.list = list; + next.setContent(function () { + "step 0" + event.nodes = []; + event.avatars = []; + event.friend = []; + event.enemy = []; + event.blank = []; + for (var i = 0; i < event.config.size; i++) { + event.nodes.push(ui.create.div(".shadowed.reduce_radius.choosedouble")); + } + event.moveAvatar = function (node, i) { + if (!node.classList.contains("moved")) { + event.blank.push(node.index); + } + event.nodes[node.index].style.display = ""; + event.nodes[node.index].show(); + clearTimeout(event.nodes[node.index].choosetimeout); + event.moveNode(node, i); + var nodex = event.nodes[node.index]; + nodex.choosetimeout = setTimeout(function () { + nodex.hide(); + nodex.choosetimeout = setTimeout(function () { + nodex.show(); + nodex.style.display = "none"; + }, 300); + }, 400); + }; + event.aiMove = function (friend) { + var list = []; + for (var i = 0; i < event.avatars.length; i++) { + if (!event.avatars[i].classList.contains("moved")) { + list.push(event.avatars[i]); + } + } + for (var i = 0; i < list.length; i++) { + if (Math.random() < 0.7 || i == list.length - 1) { + if (friend) { + event.moveAvatar(list[i], event.friend.length + event.config.width * (event.config.height - 1)); + event.friend.push(list[i]); + } + else { + event.moveAvatar(list[i], event.enemy.length); + event.enemy.push(list[i]); + } + list[i].classList.add("moved"); + break; + } + } + }; + event.promptbar = ui.create.div(".hidden", ui.window); + event.promptbar.style.width = "100%"; + event.promptbar.style.left = 0; + if (get.is.phoneLayout()) { + event.promptbar.style.top = "20px"; + } + else { + event.promptbar.style.top = "58px"; + } + event.promptbar.style.pointerEvents = "none"; + event.promptbar.style.textAlign = "center"; + event.promptbar.style.zIndex = "2"; + ui.create.div(".shadowed.reduce_radius", event.promptbar); + event.promptbar.firstChild.style.fontSize = "18px"; + event.promptbar.firstChild.style.padding = "6px 10px"; + event.promptbar.firstChild.style.position = "relative"; + event.prompt = function (str) { + event.promptbar.firstChild.innerHTML = str; + event.promptbar.show(); + }; + event.moveNode = function (node, i) { + var width = event.width, height = event.height, margin = event.margin; + var left = -(width + 10) * event.config.width / 2 + 5 + (i % event.config.width) * (width + 10); + var top = -(height + 10) * event.config.height / 2 + 5 + Math.floor(i / event.config.width) * (height + 10) + margin / 2; + node.style.transform = "translate(" + left + "px," + top + "px)"; + node.index = i; + }; + event.resize = function () { + var margin = 0; + if (!get.is.phoneLayout()) { + margin = 38; + } + var height = (ui.window.offsetHeight - 10 * (event.config.height + 1) - margin) / event.config.height; + var width = (ui.window.offsetWidth - 10 * (event.config.width + 1)) / event.config.width; + if (width * event.config.ratio < height) { + height = width * event.config.ratio; + } + else { + width = height / event.config.ratio; + } + event.width = width; + event.height = height; + event.margin = margin; + for (var i = 0; i < event.config.size; i++) { + event.moveNode(event.nodes[i], i); + event.nodes[i].style.width = width + "px"; + event.nodes[i].style.height = height + "px"; + if (event.avatars[i]) { + event.moveNode(event.avatars[i], event.avatars[i].index); + event.avatars[i].style.width = width + "px"; + event.avatars[i].style.height = height + "px"; + event.avatars[i].nodename.style.fontSize = Math.max(14, Math.round(width / 5.6)) + "px"; + } + } + if (event.deciding) { + var str = "px," + (event.margin / 2 - event.height * 0.5) + "px)"; + for (var i = 0; i < event.friendlist.length; i++) { + event.friendlist[i].style.transform = "scale(1.2) translate(" + (-(event.width + 14) * event.friendlist.length / 2 + 7 + i * (event.width + 14)) + str; + } + } + }; + lib.onresize.push(event.resize); + event.clickAvatar = function () { + if (event.deciding) { + if (this.index < event.config.width) return; + if (event.friendlist.contains(this)) { + event.friendlist.remove(this); + event.moveNode(this, this.index); + this.nodename.innerHTML = get.slimName(this.link); + } + else { + event.friendlist.push(this); + } + if (event.friendlist.length == event.config.num) { + event.deciding = false; + event.prompt("比赛即将开始"); + setTimeout(game.resume, 1000); + } + if (event.config.update) { + for (var i = 0; i < event.friendlist.length; i++) { + event.friendlist[i].nodename.innerHTML = event.config.update(i, event.friendlist.length) || event.friendlist[i].nodename.innerHTML; + } + } + var str = "px," + (event.margin / 2 - event.height * 0.5) + "px)"; + for (var i = 0; i < event.friendlist.length; i++) { + event.friendlist[i].style.transform = "scale(1.2) translate(" + (-(event.width + 14) * event.friendlist.length / 2 + 7 + i * (event.width + 14)) + str; + } + } + else { + if (!event.imchoosing) return; + if (event.replacing) { + this.link = event.replacing; + this.setBackground(event.replacing, "character"); + + this.nodename.innerHTML = get.slimName(event.replacing); + this.nodename.dataset.nature = get.groupnature(lib.character[event.replacing][1]); + + delete event.replacing; + if (this.classList.contains("moved")) { + event.custom.add.window(); + } + } + if (this.classList.contains("moved")) return; + event.moveAvatar(this, event.friend.length + event.config.width * (event.config.height - 1)); + event.friend.push(this.link); + this.classList.add("moved"); + game.resume(); + } + }; + event.skipnode = ui.create.system("跳过", function () { + this.remove(); + event._skiprest = true; + if (event.imchoosing) { + game.resume(); + } + }); + if (get.config("change_choice")) { + event.replacenode = ui.create.system("换将", function () { + event.promptbar.hide(); + while (event.avatars.length) { + event.avatars.shift().remove(); + } + for (var i = 0; i < event.config.size; i++) { + event.nodes[i].show(); + event.nodes[i].style.display = ""; + clearTimeout(event.nodes[i].choosetimeout); + } + delete event.list2; + event.friend.length = 0; + event.enemy.length = 0; + event.blank.length = 0; + event.redoing = true; + if (event.imchoosing) { + game.resume(); + } + }, true); + } + if (get.config("change_choice")) { + event.reselectnode = ui.create.system("重选", function () { + event.promptbar.hide(); + event.list2 = event.list2.concat(event.friend).concat(event.enemy); + event.friend.length = 0; + event.enemy.length = 0; + for (var i = 0; i < event.avatars.length; i++) { + if (event.avatars[i].classList.contains("moved")) { + event.moveAvatar(event.avatars[i], event.blank.randomRemove()); + event.avatars[i].classList.remove("moved"); + } + } + event.redoing = true; + if (event.imchoosing) { + game.resume(); + } + }, true); + } + if (get.config("free_choose")) { + var createCharacterDialog = function () { + event.freechoosedialog = ui.create.characterDialog(); + event.freechoosedialog.style.height = "80%"; + event.freechoosedialog.style.top = "10%"; + event.freechoosedialog.style.transform = "scale(0.8)"; + event.freechoosedialog.style.transition = "all 0.3s"; + event.freechoosedialog.listen(function (e) { + if (!event.replacing) { + event.dialoglayer.clicked = true; + } + }); + event.freechoosedialog.classList.add("pointerdialog"); + event.dialoglayer = ui.create.div(".popup-container.hidden", function (e) { + if (this.classList.contains("removing")) return; + if (this.clicked) { + this.clicked = false; + return; + } + ui.window.classList.remove("modepaused"); + this.delete(); + e.stopPropagation(); + event.freechoosedialog.style.transform = "scale(0.8)"; + if (event.replacing) { + event.prompt("用" + get.translation(event.replacing) + "替换一名武将"); + } + else { + if (event.side == 0) { + event.prompt("请选择两名武将"); + } + else { + event.prompt("请选择一名武将"); + } + } + }); + event.dialoglayer.classList.add("modenopause"); + event.dialoglayer.appendChild(event.freechoosedialog); + event.freechoosenode.classList.remove("hidden"); + } + + event.custom.replace.button = function (button) { + event.replacing = button.link; + }; + event.custom.add.window = function () { + if (event.replacing) { + delete event.replacing; + if (event.side == 0) { + event.prompt("请选择两名武将"); + } + else { + event.prompt("请选择一名武将"); + } + } + }; + event.freechoosenode = ui.create.system("自由选将", function () { + if (this.classList.contains("hidden")) return; + if (!event.imchoosing) { + event.prompt("请等待敌方选将"); + return; + } + delete event.replacing; + ui.window.classList.add("modepaused"); + ui.window.appendChild(event.dialoglayer); + ui.refresh(event.dialoglayer); + event.dialoglayer.show(); + event.freechoosedialog.style.transform = "scale(1)"; + event.promptbar.hide(); + }, true); + if (lib.onfree) { + event.freechoosenode.classList.add("hidden"); + lib.onfree.push(createCharacterDialog); + } + else { + createCharacterDialog(); + } + } + event.checkredo = function () { + if (event.redoing) { + event.goto(1); + delete event.redoing; + return true; + } + }; + // if(ui.cardPileButton) ui.cardPileButton.style.display="none"; + ui.auto.hide(); + ui.wuxie.hide(); + event.resize(); + for (var i = 0; i < event.config.size; i++) { + ui.window.appendChild(event.nodes[i]); + } + "step 1" + var rand = event.config.first; + if (rand == "rand") { + rand = (Math.random() < 0.5); + } + if (rand) { + _status.color = true; + event.side = 1; + } + else { + _status.color = false; + event.side = 3; + } + if (!event.list2) { + event.list2 = event.list.randomGets(event.config.width * 2); + for (var i = 0; i < event.config.width * 2; i++) { + event.avatars.push(ui.create.div(".shadowed.shadowed2.reduce_radius.character.choosedouble", event.clickAvatar)); + var name = event.list2[i]; + event.avatars[i].setBackground(name, "character"); + event.avatars[i].link = name; + event.avatars[i].nodename = ui.create.div(".name", event.avatars[i], get.slimName(name)); + event.avatars[i].nodename.style.fontFamily = lib.config.name_font; + event.avatars[i].index = i + event.config.width; + event.avatars[i].animate("start"); + event.nodes[event.avatars[i].index].style.display = "none"; + event.avatars[i].nodename.dataset.nature = get.groupnature(lib.character[name][1]); + lib.setIntro(event.avatars[i]); + } + event.resize(); + for (var i = 0; i < event.avatars.length; i++) { + ui.window.appendChild(event.avatars[i]); + } + event.avatars.sort(function (a, b) { + return get.rank(b.link, true) - get.rank(a.link, true); + }) + } + game.delay(); + lib.init.onfree(); + "step 2" + if (event.checkredo()) return; + if (event._skiprest) return; + if (event.side < 2) { + event.imchoosing = true; + if (event.side == 0) { + event.prompt("请选择两名武将"); + } + else { + event.prompt("请选择一名武将"); + event.fast = get.time(); + } + game.pause(); + } + else { + event.aiMove(); + game.delay(); + } + "step 3" + if (typeof event.fast == "number" && get.time() - event.fast <= 1000) { + event.fast = true; + } + else { + event.fast = false; + } + delete event.imchoosing; + if (event.checkredo()) return; + if (event._skiprest) { + while (event.enemy.length < event.config.width) { + event.aiMove(); + } + while (event.friend.length < event.config.width) { + event.aiMove(true); + } + } + else if (event.friend.length + event.enemy.length < event.config.width * 2 - 1) { + if (event.side == 1) { + game.delay(event.fast ? 1 : 2); + event.promptbar.hide(); + } + event.side++; + if (event.side > 3) { + event.side = 0; + } + event.goto(2); + } + else { + event.promptbar.hide(); + event.side++; + if (event.side > 3) { + event.side = 0; + } + if (event.side >= 2) { + game.delay() + } + } + "step 4" + if (event.checkredo()) return; + if (event.skipnode) event.skipnode.delete(); + if (event.replacenode) event.replacenode.delete(); + if (event.reselectnode) event.reselectnode.delete(); + if (event.freechoosenode) event.freechoosenode.delete(); + for (var i = 0; i < event.avatars.length; i++) { + if (!event.avatars[i].classList.contains("moved")) { + if (event.side < 2) { + event.moveAvatar(event.avatars[i], event.friend.length + event.config.width * (event.config.height - 1)); + event.friend.push(event.avatars[i]); + } + else { + event.moveAvatar(event.avatars[i], event.enemy.length); + event.enemy.push(event.avatars[i]); + } + event.avatars[i].classList.add("moved"); + } + } + game.delay(); + "step 5" + event.prompt("选择" + get.cnNumber(event.config.num) + "名出场武将"); + event.enemylist = []; + for (var i = 0; i < event.avatars.length; i++) { + if (event.avatars[i].index > event.config.width) { + event.avatars[i].classList.add("selecting"); + } + } + var rand = []; + for (var i = 0; i < event.config.width; i++) { + for (var j = 0; j < event.config.width - i; j++) { + rand.push(i); + } + } + for (var i = 0; i < event.config.num; i++) { + var rand2 = rand.randomGet(); + for (var j = 0; j < rand.length; j++) { + if (rand[j] == rand2) { + rand.splice(j--, 1); + } + } + event.enemylist.push(event.enemy[rand2]); + } + event.enemylist.randomSort(); + event.friendlist = []; + event.deciding = true; + for (var i = 0; i < event.config.size; i++) { + event.nodes[i].hide(); + } + game.pause(); + "step 6" + event.promptbar.delete(); + if (ui.cardPileButton) ui.cardPileButton.style.display = ""; + lib.onresize.remove(event.resize); + ui.wuxie.show(); + ui.auto.show(); + for (var i = 0; i < event.avatars.length; i++) { + event.avatars[i].delete(); + } + for (var i = 0; i < event.nodes.length; i++) { + event.nodes[i].delete(); + } + event.result = { friend: [], enemy: [] }; + for (var i = 0; i < event.config.num; i++) { + event.result.friend[i] = event.friendlist[i].link; + event.result.enemy[i] = event.enemylist[i].link; + } + }); + } + static updateRoundNumber() { + game.broadcastAll((roundNumber, pileTop, pileNumber) => { + if (game.roundNumber != roundNumber) game.roundNumber = roundNumber; + if (_status.pileTop != pileTop) _status.pileTop = pileTop; + ui.updateRoundNumber(roundNumber, pileNumber); + }, game.roundNumber, ui.cardPile.firstChild, ui.cardPile.childElementCount); + } + static asyncDraw(players, num, drawDeck, bottom) { + players.forEach((value, index) => { + let num2 = 1; + if (typeof num == "number") num2 = num; + else if (Array.isArray(num)) num2 = num[index]; + else if (typeof num == "function") num2 = num(value); + if (drawDeck && drawDeck.drawDeck) value.draw(num2, false, drawDeck); + else if (bottom) value.draw(num2, "nodelay", "bottom"); + else value.draw(num2, "nodelay"); + }); + } + static asyncDrawAuto(players, num, drawDeck) { + if (players.length > 1) { + game.asyncDraw.apply(this, arguments); + return; + } + let num2 = 1; + if (typeof num == "number") num2 = num; + else if (Array.isArray(num)) num2 = num[0]; + else if (typeof num == "function") num2 = num(players[0]); + if (drawDeck && drawDeck.drawDeck) players[0].draw(num2, drawDeck); + else players[0].draw(num2); + } + static finishSkill(i, sub) { + const mode = get.mode(), info = lib.skill[i], iInfo = `${i}_info`; + if (info.alter) { + lib.translate[`${iInfo}_origin`] = lib.translate[iInfo]; + if (!lib.config.vintageSkills.contains(i)) lib.translate[iInfo] = lib.translate[`${iInfo}_alter`]; + } + else if (_status.mode && lib.translate[iInfo + "_" + mode + "_" + _status.mode]) lib.translate[iInfo] = lib.translate[iInfo + "_" + mode + "_" + _status.mode]; + else if (lib.translate[`${iInfo}_${mode}`]) lib.translate[iInfo] = lib.translate[`${iInfo}_${mode}`]; + else if (lib.translate[`${iInfo}_zhu`] && (mode == "identity" || mode == "guozhan" && _status.mode == "four")) lib.translate[iInfo] = lib.translate[`${iInfo}_zhu`]; + else if (lib.translate[`${iInfo}_combat`] && get.is.versus()) lib.translate[iInfo] = lib.translate[`${iInfo}_combat`]; + var deleteSkill = function (skill, iInfo) { + var skillx = {}, info = get.info(skill); + if (info) { + ["audio", "audioname", "audioname2"].forEach(name => { + if (info[name]) skillx[name] = info[name]; + }); + } + lib.skill[skill] = skillx; + if (lib.translate[iInfo]) lib.translate[iInfo] = "此模式下不可用"; + if (lib.dynamicTranslate[skill]) lib.dynamicTranslate[skill] = () => "此模式下不可用"; + }; + if ((info.forbid && info.forbid.contains(mode)) || (info.mode && info.mode.contains(mode) == false) || (info.available && info.available(mode) == false)) { + deleteSkill(i, iInfo); + return; + } + if (info.viewAs && typeof info.viewAs != "function") { + if (typeof info.viewAs == "string") info.viewAs = { + name: info.viewAs + }; + if (!lib.card[info.viewAs.name]) { + deleteSkill(i, iInfo); + return; + } + if (info.ai == undefined) info.ai = {}; + const skill = info.ai, card = lib.card[info.viewAs.name].ai; + if (card) Object.keys(card).forEach(value => { + if (skill[value] == undefined) skill[value] = card[value]; + else if (typeof skill[value] == "object") Object.keys(card[value]).forEach(element => { + if (skill[value][element] == undefined) skill[value][element] = card[value][element]; + }); + }); + } + if (info.inherit) { + const skill = lib.skill[info.inherit]; + if (skill) Object.keys(skill).forEach(value => { + if (info[value] != undefined) return; + if (value == "audio" && (typeof info[value] == "number" || typeof info[value] == "boolean")) info[value] = info.inherit; + else info[value] = skill[value]; + }); + if (lib.translate[i] == undefined) lib.translate[i] = lib.translate[info.inherit]; + if (lib.translate[iInfo] == undefined) lib.translate[iInfo] = lib.translate[`${info.inherit}_info`]; + } + if (info.limited) { + if (info.mark === undefined) info.mark = true; + if (!info.intro) info.intro = {}; + if (info.intro.content === undefined) info.intro.content = "limited"; + if (info.skillAnimation === undefined) info.skillAnimation = true; + if (info.init === undefined) info.init = (player, skill) => player.storage[skill] = false; + } + if (info.subSkill && !sub) Object.keys(info.subSkill).forEach(value => { + const iValue = `${i}_${value}`; + lib.skill[iValue] = info.subSkill[value]; + lib.skill[iValue].sub = true; + if (info.subSkill[value].name) lib.translate[iValue] = info.subSkill[value].name; + else lib.translate[iValue] = lib.translate[iValue] || lib.translate[i]; + if (info.subSkill[value].description) lib.translate[`${iValue}_info`] = info.subSkill[value].description; + if (info.subSkill[value].marktext) lib.translate[`${iValue}_bg`] = info.subSkill[value].marktext; + game.finishSkill(iValue, true); + }); + if (info.round) { + const k = `${i}_roundcount`; + if (typeof info.group == "string") info.group = [info.group, k]; + else if (Array.isArray(info.group)) info.group.add(k); + else info.group = [k]; + lib.skill[k] = ((round, name) => ({ + init: player => { + if (typeof player.storage[name] !== "number") player.storage[name] = 1 - round; + }, + intro: { + content: (storage, player) => { + let str = ""; + const info = get.info(name.slice(0, name.indexOf("_roundcount"))); + if (info && info.addintro) str += info.addintro(storage, player); + const num = round - (game.roundNumber - storage); + if (num > 0) str += `${get.cnNumber(num)}轮后${info.roundtext || "技能重置"}`; + else str += "技能可发动"; + return str; + }, + markcount: (storage, player) => Math.max(round - (game.roundNumber - storage), 0) + }, + trigger: { global: "roundStart" }, + forced: true, + popup: false, + silent: true, + content: () => { + if (lib.skill[event.name.slice(0, event.name.indexOf("_roundcount"))].round - (game.roundNumber - player.storage[event.name]) > 0) player.updateMarks(); + else player.unmarkSkill(event.name); + } + }))(info.round, k); + lib.translate[k] = lib.translate[i] || ""; + lib.translate[`${k}_bg`] = lib.translate[`${i}_bg`] || lib.translate[k][0]; + } + if (info.marktext) lib.translate[`${i}_bg`] = info.marktext; + if (info.silent) { + if (!Object.prototype.hasOwnProperty.call(info, "forced")) info.forced = true; + if (!Object.prototype.hasOwnProperty.call(info, "popup")) info.popup = false; + } + if (!Object.prototype.hasOwnProperty.call(info, "_priority")) { + let priority = 0; + if (info.priority) { + priority = info.priority * 100; + } + if (info.silent) { + priority++; + } + if (info.equipSkill) priority -= 25; + if (info.cardSkill) priority -= 50; + if (info.ruleSkill) priority -= 75; + info._priority = priority; + } + if (i[0] == "_") game.addGlobalSkill(i); + } + static finishCards() { + _status.cardsFinished = true; + const mode = get.mode(), filterTarget = (card, player, target) => player == target && target.canEquip(card, true), aiBasicOrder = (card, player) => { + const equipValue = get.equipValue(card, player) / 20; + return player && player.hasSkillTag("reverseEquip") ? 8.5 - equipValue : 8 + equipValue; + }, aiBasicValue = (card, player, index, method) => { + if (!player.getCards("e").contains(card) && !player.canEquip(card, true)) return 0.01; + const info = get.info(card), current = player.getEquip(info.subtype), value = current && card != current && get.value(current, player); + let equipValue = info.ai.equipValue || info.ai.basic.equipValue; + if (typeof equipValue == "function") { + if (method == "raw") return equipValue(card, player); + if (method == "raw2") return equipValue(card, player) - value; + return Math.max(0.1, equipValue(card, player) - value); + } + if (typeof equipValue != "number") equipValue = 0; + if (method == "raw") return equipValue; + if (method == "raw2") return equipValue - value; + return Math.max(0.1, equipValue - value); + }, aiResultTarget = (player, target, card) => get.equipResult(player, target, card.name); + Object.keys(lib.card).forEach(libCardKey => { + const info = `${libCardKey}_info`; + if (lib.translate[`${info}_${mode}`]) lib.translate[info] = lib.translate[`${info}_${mode}`]; + else if (lib.translate[`${info}_zhu`] && (mode == "identity" || mode == "guozhan" && _status.mode == "four")) lib.translate[info] = lib.translate[`${info}_zhu`]; + else if (lib.translate[`${info}_combat`] && get.is.versus()) lib.translate[info] = lib.translate[`${info}_combat`]; + const card = lib.card[libCardKey]; + if (card.filterTarget && card.selectTarget == undefined) card.selectTarget = 1; + if (card.autoViewAs) { + if (!card.ai) card.ai = {}; + if (!card.ai.order) { + card.ai.order = lib.card[card.autoViewAs].ai.order; + if (!card.ai.order && lib.card[card.autoViewAs].ai.basic) card.ai.order = lib.card[card.autoViewAs].ai.basic.order; + } + } + if (card.type == "equip") { + if (card.enable == undefined) card.enable = true; + if (card.selectTarget == undefined) card.selectTarget = -1; + if (card.filterTarget == undefined) card.filterTarget = filterTarget; + if (card.modTarget == undefined) card.modTarget = true; + if (card.allowMultiple == undefined) card.allowMultiple = false; + if (card.content == undefined) card.content = lib.element.content.equipCard; + if (card.toself == undefined) card.toself = true; + if (card.ai == undefined) card.ai = { + basic: {} + }; + if (card.ai.basic == undefined) card.ai.basic = {}; + if (card.ai.result == undefined) card.ai.result = { + target: 1.5 + }; + if (card.ai.basic.order == undefined) card.ai.basic.order = aiBasicOrder; + if (card.ai.basic.useful == undefined) card.ai.basic.useful = 2; + if (card.subtype == "equip3") { + if (card.ai.basic.equipValue == undefined) card.ai.basic.equipValue = 7; + } + else if (card.subtype == "equip4") { + if (card.ai.basic.equipValue == undefined) card.ai.basic.equipValue = 4; + } + else if (card.ai.basic.equipValue == undefined) card.ai.basic.equipValue = 1; + if (card.ai.basic.value == undefined) card.ai.basic.value = aiBasicValue; + if (!card.ai.result.keepAI) card.ai.result.target = aiResultTarget; + } + else if (card.type == "delay") { + if (card.enable == undefined) card.enable = true; + if (card.filterTarget == undefined) card.filterTarget = lib.filter.judge; + if (card.content == undefined) card.content = lib.element.content.addJudgeCard; + if (card.allowMultiple == undefined) card.allowMultiple = false; + } + }); + Object.keys(lib.skill).forEach(value => game.finishSkill(value)); + } + static checkMod() { + const argumentArray = Array.from(arguments), name = argumentArray[argumentArray.length - 2]; + let skills = argumentArray[argumentArray.length - 1]; + if (typeof skills.getModableSkills == "function") { + skills = skills.getModableSkills(_status.event.useCache === true); + } else if (typeof skills.getSkills == "function") { + skills = skills.getSkills().concat(lib.skill.global); + game.expandSkills(skills); + skills = skills.filter(function (skill) { + var info = get.info(skill); + return info && info.mod; + }); + skills.sort((a, b) => get.priority(a) - get.priority(b)); + } + const arg = argumentArray.slice(0, -2); + skills.forEach(value => { + var mod = get.info(value).mod[name]; + if (!mod) return; + const result = mod.apply(this, arg); + if (typeof arg[arg.length - 1] != "object" && result != undefined) arg[arg.length - 1] = result; + }); + return arg[arg.length - 1]; + } + static prepareArena(num) { + _status.prepareArena = true; + game.showHistory(false); + ui.create.players(num); + ui.create.me(); + ui.create.cardsAsync(); + game.finishCards(); + } + static clearArena() { + ui.control.innerHTML = ""; + ui.arenalog.innerHTML = ""; + Array.from(ui.arena.childNodes).forEach(value => { + if (value == ui.canvas) return; + if (value == ui.control) return; + if (value == ui.arenalog) return; + if (value == ui.roundmenu) return; + if (value == ui.timer) return; + if (value == ui.autonode) return; + value.remove(); + }); + ui.sidebar.innerHTML = ""; + ui.cardPile.innerHTML = ""; + ui.discardPile.innerHTML = ""; + ui.special.innerHTML = ""; + ui.ordering.innerHTML = ""; + ui.playerids.remove(); + game.players.length = 0; + game.dead.length = 0; + game.me = null; + } + static clearConnect() { + if (ui.ipnode) { + ui.ipnode.remove(); + delete ui.ipnode; + } + if (ui.iptext) { + ui.iptext.remove(); + delete ui.iptext; + } + if (ui.ipbutton) { + ui.ipbutton.remove(); + delete ui.ipbutton; + } + if (ui.recentIP) { + ui.recentIP.remove(); + delete ui.recentIP; + } + if (ui.hall_button) { + ui.hall_button.remove(); + delete ui.hall_button; + } + if (ui.startServer) { + ui.startServer.remove(); + delete ui.startServer; + } + if (ui.rooms) { + ui.rooms.forEach(value => value.remove()); + delete ui.rooms; + } + if (ui.roombase) { + ui.roombase.remove(); + delete ui.roombase; + } + if (!ui.connectEvents) return; + ui.connectEvents.remove(); + ui.connectEventsCount.remove(); + ui.connectClients.remove(); + ui.connectClientsCount.remove(); + ui.createRoomButton.remove(); + delete ui.connectEvents; + delete ui.connectEventsCount; + delete ui.connectClients; + delete ui.connectClientsCount; + delete ui.createRoomButton; + } + static log() { + let str = "", str2 = "", logvid = null; + const color = new Map([ + ["r", "fire"], + ["y", "yellow"], + ["g", "green"], + ["b", "blue"] + ]); + Array.from(arguments).forEach(value => { + const itemtype = get.itemtype(value); + if (itemtype == "player" || itemtype == "players") { + str += `${get.translation(value)}`; + str2 += get.translation(value); + } + else if (itemtype == "cards" || itemtype == "card" || (typeof value == "object" && value && value.name)) { + str += `${get.translation(value)}`; + str2 += get.translation(value); + } + else if (typeof value == "object") { + if (value.parentNode == ui.historybar) logvid = value.logvid; + else { + str += get.translation(value); + str2 += get.translation(value); + } + } + else if (typeof value == "string") { + if (value[0] == "【" && value[value.length - 1] == "】") { + str += `${get.translation(value)}`; + str2 += get.translation(value); + } + else if (value[0] == "#") { + str += `${get.translation(value.slice(2))}`; + str2 += get.translation(value.slice(2)); + } + else { + str += get.translation(value); + str2 += get.translation(value); + } + } + else { + str += value; + str2 += value; + } + }); + const node = ui.create.div(); + node.innerHTML = lib.config.log_highlight ? str : str2; + ui.sidebar.insertBefore(node, ui.sidebar.firstChild); + game.addVideo("log", null, lib.config.log_highlight ? str : str2); + game.broadcast((str, str2) => game.log(lib.config.log_highlight ? str : str2), str, str2); + if (!_status.video && !game.online) { + if (logvid) game.logv(logvid, `
${lib.config.log_highlight ? str : str2}
`); + else logvid = _status.event.getLogv(); + } + if (lib.config.show_log == "off" || game.chess) return; + const nodeentry = node.cloneNode(true); + ui.arenalog.insertBefore(nodeentry, ui.arenalog.firstChild); + if (!lib.config.clear_log) while (ui.arenalog.childNodes.length && ui.arenalog.scrollHeight > ui.arenalog.offsetHeight) { + ui.arenalog.lastChild.remove(); + } + if (!lib.config.low_performance) { + nodeentry.style.transition = "all 0s"; + nodeentry.style.marginBottom = `-${nodeentry.offsetHeight}px`; + ui.refresh(nodeentry); + nodeentry.style.transition = ""; + nodeentry.style.marginBottom = ""; + } + if (!lib.config.clear_log) return; + nodeentry.timeout = setTimeout(() => nodeentry.delete(), 1000); + Array.from(ui.arenalog.childNodes).forEach(value => { + if (!value.timeout) value.remove(); + }); + } + static logv(player, card, targets, event, forced, logvid) { + if (!player) { + player = _status.event.getParent().logvid; + if (!player) return; + } + const node = ui.create.div(".hidden"); + node.node = {}; + logvid = logvid || get.id(); + game.broadcast(game.logv, player, card, targets, event, forced, logvid); + if (typeof player == "string") { + const childNode = Array.from(ui.historybar.childNodes).find(value => value.logvid == player); + if (childNode) childNode.added.push(card); + return; + } + if (typeof card == "string") { + if (card != "die") { + if (lib.skill[card] && lib.skill[card].logv === false && !forced) return; + if (!lib.translate[card]) return; + } + let avatar; + if (!player.isUnseen(0)) avatar = player.node.avatar.cloneNode(); + else if (!player.isUnseen(1)) avatar = player.node.avatar2.cloneNode(); + else return; + node.node.avatar = avatar; + avatar.style.transform = ""; + avatar.className = "avatar"; + if (card == "die") { + node.dead = true; + node.player = player; + const avatar2 = avatar.cloneNode(); + avatar2.className = "avatarbg grayscale1"; + avatar.appendChild(avatar2); + avatar.style.opacity = 0.6; + } + else { + node.node.text = ui.create.div("", get.translation(card, "skill"), avatar); + node.node.text.dataset.nature = "water"; + node.skill = card; + } + node.appendChild(avatar); + if (card == "die" && targets && targets != player) { + node.source = targets; + player = targets; + if (!player.isUnseen(0)) avatar = player.node.avatar.cloneNode(); + else if (!player.isUnseen(1)) avatar = player.node.avatar2.cloneNode(); + else if (get.mode() == "guozhan" && player.node && player.node.name_seat) { + avatar = ui.create.div(".avatar.cardbg"); + avatar.innerHTML = player.node.name_seat.innerHTML[0]; + } + else return; + avatar.style.transform = ""; + node.node.avatar2 = avatar; + avatar.classList.add("avatar2"); + node.appendChild(avatar); + } + } + else if (Array.isArray(card)) { + node.cards = card[1].slice(0) + card = card[0]; + const info = [card.suit || "", card.number || "", card.name || "", card.nature || ""]; + if (!Array.isArray(node.cards) || !node.cards.length) node.cards = [ui.create.card(node, "noclick", true).init(info)]; + if (card.name == "wuxie") { + if (ui.historybar.firstChild && ui.historybar.firstChild.type == "wuxie") { + ui.historybar.firstChild.players.push(player); + ui.historybar.firstChild.cards.addArray(node.cards); + return; + } + node.type = "wuxie"; + node.players = [player]; + } + if (card.copy) card.copy(node, false); + else { + card = ui.create.card(node, "noclick", true); + card.init(info); + } + let avatar; + if (!player.isUnseen(0)) avatar = player.node.avatar.cloneNode(); + else if (!player.isUnseen(1)) avatar = player.node.avatar2.cloneNode(); + else if (get.mode() == "guozhan" && player.node && player.node.name_seat) { + avatar = ui.create.div(".avatar.cardbg"); + avatar.innerHTML = player.node.name_seat.innerHTML[0]; + } + else return; + node.node.avatar = avatar; + avatar.style.transform = ""; + avatar.classList.add("avatar2"); + node.appendChild(avatar); + if (targets && targets.length == 1 && targets[0] != player && get.itemtype(targets[0]) == "player") (() => { + let avatar2; + const target = targets[0]; + if (!target.isUnseen(0)) avatar2 = target.node.avatar.cloneNode(); + else if (!player.isUnseen(1)) avatar2 = target.node.avatar2.cloneNode(); + else if (get.mode() == "guozhan" && target.node && target.node.name_seat) { + avatar2 = ui.create.div(".avatar.cardbg"); + avatar2.innerHTML = target.node.name_seat.innerHTML[0]; + } + else return; + node.node.avatar2 = avatar2; + avatar2.style.transform = ""; + avatar2.classList.add("avatar2"); + avatar2.classList.add("avatar3"); + node.insertBefore(avatar2, avatar); + })(); + } + if (targets && targets.length) { + if (targets.length == 1 && targets[0] == player) { + node.targets = []; + } + else { + node.targets = targets; + } + } + const fullheight = ui.historybar.offsetHeight, num = Math.round((fullheight - 8) / 50), margin = (fullheight - 42 * num) / (num + 1); + node.style.transform = "scale(0.8)"; + ui.historybar.insertBefore(node, ui.historybar.firstChild); + ui.refresh(node); + node.classList.remove("hidden"); + Array.from(ui.historybar.childNodes).forEach((value, index) => { + if (index < num) { + value.style.transform = `scale(1) translateY(${margin + index * (42 + margin) - 4}px)`; + return; + } + if (value.removetimeout) return; + value.style.opacity = 0; + value.style.transform = `scale(1) translateY(${fullheight}px)`; + value.removetimeout = setTimeout((current => () => current.remove())(value), 500); + }); + if (lib.config.touchscreen) node.addEventListener("touchstart", ui.click.intro); + else { + node.addEventListener(lib.config.pop_logv ? "mousemove" : "click", ui.click.logv); + node.addEventListener("mouseleave", ui.click.logvleave); + } + node.logvid = logvid; + node.added = []; + if (!game.online) { + event = event || _status.event; + event.logvid = node.logvid; + } + return node; + } + static putDB(storeName, idbValidKey, value, onSuccess, onError) { + if (!lib.db) return Promise.resolve(value); + if (lib.status.reload) return new Promise((resolve, reject) => lib[_status.dburgent ? "ondb2" : "ondb"].push(["putDB", [storeName, idbValidKey, value, event => { + if (typeof onSuccess == "function") onSuccess(event); + resolve(event); + }, event => { + if (typeof onError == "function") { + onError(event); + resolve(); + } + else reject(event); + }]])); + lib.status.reload++; + return new Promise((resolve, reject) => { + const record = lib.db.transaction([storeName], "readwrite").objectStore(storeName).put(value, idbValidKey); + record.onerror = event => { + if (typeof onError == "function") { + onError(event); + game.reload2(); + resolve(); + } + else { + game.reload2(); + reject(event); + } + }; + record.onsuccess = event => { + if (typeof onSuccess == "function") { + _status.dburgent = true; + onSuccess(event); + delete _status.dburgent; + } + game.reload2(); + resolve(event); + }; + }); + } + static getDB(storeName, query, onSuccess, onError) { + if (!lib.db) return new Promise(resolve => { + if (typeof onSuccess == "function") onSuccess(null); + resolve(null); + }); + if (lib.status.reload) return new Promise((resolve, reject) => lib[_status.dburgent ? "ondb2" : "ondb"].push(["getDB", [storeName, query, result => { + if (typeof onSuccess == "function") onSuccess(result); + resolve(result); + }, event => { + if (typeof onError == "function") { + onError(event); + resolve(); + } + else reject(event); + }]])); + return new Promise(query ? (resolve, reject) => { + lib.status.reload++; + const idbRequest = lib.db.transaction([storeName], "readwrite").objectStore(storeName).get(query); + idbRequest.onerror = event => { + if (typeof onError == "function") { + onError(event); + game.reload2(); + resolve(); + } + else { + game.reload2(); + reject(event); + } + }; + idbRequest.onsuccess = event => { + const result = event.target.result; + if (typeof onSuccess == "function") { + _status.dburgent = true; + onSuccess(result); + delete _status.dburgent; + } + game.reload2(); + resolve(result); + }; + } : (resolve, reject) => { + lib.status.reload++; + const idbRequest = lib.db.transaction([storeName], "readwrite").objectStore(storeName).openCursor(), object = {}; + idbRequest.onerror = event => { + if (typeof onError == "function") { + onError(event); + game.reload2(); + resolve(); + } + else { + game.reload2(); + reject(event); + } + }; + idbRequest.onsuccess = event => { + const result = event.target.result; + if (result) { + object[result.key] = result.value; + result.continue(); + return; + } + if (typeof onSuccess == "function") { + _status.dburgent = true; + onSuccess(object); + delete _status.dburgent; + } + game.reload2(); + resolve(object); + }; + }); + } + static deleteDB(storeName, query, onSuccess, onError) { + if (!lib.db) return new Promise(resolve => { + if (typeof onSuccess == "function") onSuccess(false); + resolve(false); + }); + if (lib.status.reload) return new Promise((resolve, reject) => lib[_status.dburgent ? "ondb2" : "ondb"].push(["deleteDB", [storeName, query, event => { + if (typeof onSuccess == "function") onSuccess(event); + resolve(event); + }, event => { + if (typeof onError == "function") { + onError(event); + resolve(); + } + else reject(event); + }]])); + return query ? new Promise((resolve, reject) => { + lib.status.reload++; + const record = lib.db.transaction([storeName], "readwrite").objectStore(storeName).delete(query); + record.onerror = event => { + if (typeof onError == "function") { + onError(event); + game.reload2(); + resolve(); + } + else { + game.reload2(); + reject(event); + } + }; + record.onsuccess = event => { + if (typeof onSuccess == "function") onSuccess(event); + game.reload2(); + resolve(event); + }; + }) : game.getDB(storeName).then(object => { + const keys = Object.keys(object); + lib.status.reload += keys.length; + const store = lib.db.transaction([storeName], "readwrite").objectStore(storeName); + return Promise.allSettled(keys.map(key => new Promise((resolve, reject) => { + const request = store.delete(key); + request.onerror = event => { + game.reload2(); + reject(event); + }; + request.onsuccess = event => { + game.reload2(); + resolve(event); + }; + }))); + }); + } + static save(key, value, mode) { + if (_status.reloading) return; + mode = mode || lib.config.mode; + if (lib.db) { + if (!key) { + game.putDB("data", mode, get.copy(lib.storage)); + return; + } + if (mode == lib.config.mode) { + if (value == undefined) delete lib.storage[key]; + else lib.storage[key] = value; + lib.storage.version = lib.version; + game.putDB("data", mode, lib.storage); + } + else game.getDB("data", mode, config => { + if (!config) config = {}; + if (value == undefined) delete config[key]; + else config[key] = value; + config.version = lib.version; + game.putDB("data", mode, config); + }); + return; + } + if (!key) { + localStorage.setItem(`${lib.configprefix}${mode}`, JSON.stringify(lib.storage)); + return; + } + let config; + try { + config = JSON.parse(localStorage.getItem(`${lib.configprefix}${mode}`)); + if (typeof config != "object") throw "err"; + } + catch (err) { + config = {}; + } + if (value == undefined) { + delete config[key]; + if (mode == lib.config.mode) delete lib.storage[key]; + } + else { + config[key] = value; + if (mode == lib.config.mode) lib.storage[key] = value; + } + config.version = lib.version; + localStorage.setItem(`${lib.configprefix}${mode}`, JSON.stringify(config)); + } + static showChangeLog() { + if (lib.version == lib.config.version && !_status.extensionChangeLog) return; + const ul = document.createElement("ul"); + ul.style.textAlign = "left"; + const caption = lib.version == lib.config.version ? "扩展更新" : `${lib.version}更新内容`; + let players = null, cards = null; + if (lib.version != lib.config.version) lib.changeLog.forEach(value => { + if (value.startsWith("players://")) try { + players = JSON.parse(value.slice(10)).filter(value => lib.character[value]); + } + catch (e) { + players = null; + } + else if (value.startsWith("cards://")) try { + cards = JSON.parse(value.slice(8)).filter(value => lib.card[value]); + } + catch (e) { + cards = null; + } + else { + const li = document.createElement("li"); + li.innerHTML = value; + ul.appendChild(li); + } + }); + game.saveConfig("version", lib.version); + if (_status.extensionChangeLog) Object.keys(_status.extensionChangeLog).forEach(value => { + const li = document.createElement("li"); + li.innerHTML = `${value}:${_status.extensionChangeLog[value]}`; + ul.appendChild(li); + }); + const dialog = ui.create.dialog(caption, "hidden"), lic = ui.create.div(dialog.content); + lic.style.display = "block"; + ul.style.display = "inline-block"; + ul.style.marginLeft = "-40px"; + lic.appendChild(ul); + if (players && players.length) { + dialog.addSmall([players, "character"]); + dialog.classList.add("forcebutton"); + dialog.classList.add("withbg"); + } + if (cards && cards.length) { + dialog.addSmall([cards.map(value => [get.translation(get.type(value)), "", value]), "vcard"]); + dialog.classList.add("forcebutton"); + dialog.classList.add("withbg"); + } + dialog.open(); + let hidden = false; + if (!ui.auto.classList.contains("hidden")) { + ui.auto.hide(); + hidden = true; + } + game.pause(); + const control = ui.create.control("确定", () => { + dialog.close(); + control.close(); + if (hidden) ui.auto.show(); + game.resume(); + }); + lib.init.onfree(); + } + static showExtensionChangeLog(str, extname) { + extname = extname || _status.extension; + const cfg = `extension_${extname}_changelog`; + if (!lib.extensionPack[extname] || lib.extensionPack[extname].version == lib.config[cfg]) return; + game.saveConfig(cfg, lib.extensionPack[extname].version); + if (_status.extensionChangeLog) return; + _status.extensionChangeLog = {}; + _status.extensionChangeLog[extname] = str; + } + static saveConfig(key, value, local, callback) { + if (_status.reloading) return; + if (local) { + const localmode = typeof local == "string" ? local : lib.config.mode; + if (!lib.config.mode_config[localmode]) lib.config.mode_config[localmode] = {}; + if (value == undefined) delete lib.config.mode_config[localmode][key]; + else lib.config.mode_config[localmode][key] = value; + key += `_mode_config_${localmode}`; + } + else if (value == undefined) delete lib.config[key]; + else lib.config[key] = value; + if (lib.db) { + if (value == undefined) game.deleteDB("config", key, callback); + else game.putDB("config", key, value, callback); + return; + } + let config; + try { + config = JSON.parse(localStorage.getItem(`${lib.configprefix}config`)); + if (!config || typeof config != "object") throw "err"; + } + catch (err) { + config = {}; + } + if (value === undefined) delete config[key]; + else config[key] = value; + localStorage.setItem(`${lib.configprefix}config`, JSON.stringify(config)); + if (callback) callback(); + } + static saveConfigValue(key) { + game.saveConfig(key, lib.config[key]); + } + static saveExtensionConfig(extension, key, value) { + game.saveConfig(`extension_${extension}_${key}`, value); + } + static saveExtensionConfigValue(extension, key) { + game.saveExtensionConfig(extension, key, game.getExtensionConfig(extension, key)); + } + static getExtensionConfig(extension, key) { + return lib.config[`extension_${extension}_${key}`]; + } + static clearModeConfig(mode) { + if (_status.reloading) return; + if (lib.db) { + game.getDB("config", null, config => Object.keys(config).forEach(value => { + if (value.substr(value.indexOf("_mode_config") + 13) == mode) game.saveConfig(value); + })); + return; + } + let config; + try { + config = JSON.parse(localStorage.getItem(`${lib.configprefix}config`)); + if (!config || typeof config != "object") throw "err"; + } + catch (err) { + config = {}; + } + Object.keys(config).forEach(value => { + if (value.substr(value.indexOf("_mode_config") + 13) == mode) delete config[value]; + }); + localStorage.setItem(`${lib.configprefix}config`, JSON.stringify(config)); + localStorage.removeItem(`${lib.configprefix}${mode}`); + } + static addPlayer(position, character, character2) { + if (position < 0 || position > game.players.length + game.dead.length || position == undefined) position = Math.ceil(Math.random() * (game.players.length + game.dead.length)); + const players = game.players.concat(game.dead); + ui.arena.setNumber(players.length + 1); + players.forEach(value => { + if (parseInt(value.dataset.position) >= position) value.dataset.position = parseInt(value.dataset.position) + 1; + }); + const player = ui.create.player(ui.arena).animate("start"); + if (character) player.init(character, character2); + game.players.push(player); + player.dataset.position = position; + game.arrangePlayers(); + return player; + } + static addFellow(position, character, animation) { + game.addVideo("addFellow", null, [position, character, animation]); + const player = ui.create.player(ui.arena).animate(animation || "start"); + player.dataset.position = position || game.players.length + game.dead.length; + player.getId(); + if (character) player.init(character); + game.players.push(player); + game.arrangePlayers(); + return player; + } + static triggerEnter(player) { + const next = game.createEvent("enterGame", false); + next.player = player; + next.setContent(() => { + event.trigger("enterGame"); + }); + return next; + } + static restorePlayer(player) { + if (game.players.contains(player) || game.dead.contains(player)) return; + let position = parseInt(player.dataset.position); + if (position < 0 || position > game.players.length + game.dead.length || position == undefined) position = Math.ceil(Math.random() * (game.players.length + game.dead.length)); + const players = game.players.concat(game.dead); + ui.arena.setNumber(players.length + 1); + players.forEach(value => { + if (parseInt(value.dataset.position) >= position) value.dataset.position = parseInt(value.dataset.position) + 1; + }); + game.players.push(player); + delete player.removed; + player.removeAttribute("style"); + player.animate("start"); + ui.arena.appendChild(player); + game.arrangePlayers(); + return player; + } + static removePlayer(player) { + if (_status.roundStart == player) _status.roundStart = player.next || player.getNext() || game.players[0]; + const players = game.players.concat(game.dead); + player.style.left = `${player.getLeft()}px`; + player.style.top = `${player.getTop()}px`; + if (player == undefined) player = game.dead[0] || game.me.next; + const position = parseInt(player.dataset.position); + players.forEach(value => { + if (parseInt(value.dataset.position) > position) value.dataset.position = parseInt(value.dataset.position) - 1; + }); + if (player.isAlive()) { + player.next.previous = player.previous; + player.previous.next = player.next; + } + player.nextSeat.previousSeat = player.previousSeat; + player.previousSeat.nextSeat = player.nextSeat; + player.delete(); + game.players.remove(player); + game.dead.remove(player); + ui.arena.setNumber(players.length - 1); + player.removed = true; + if (player == game.me) { + ui.me.hide(); + ui.auto.hide(); + ui.wuxie.hide(); + } + setTimeout(() => player.removeAttribute("style"), 500); + return player; + } + static replacePlayer(player, character, character2) { + player.removed = true; + const position = parseInt(player.dataset.position); + game.players.remove(player); + game.dead.remove(player); + player.delete(); + const player2 = ui.create.player(ui.arena).animate("start"); + if (character) player2.init(character, character2); + game.players.push(player2); + player2.dataset.position = position; + player2.nextSeat = player.nextSeat; + player2.previousSeat = player.previousSeat; + player2.nextSeat.previousSeat = player2; + player2.previousSeat.nextSeat = player2; + let player3 = player2.nextSeat; + while (player3.isDead()) { + player3 = player3.nextSeat; + } + player3.previous = player2; + player2.next = player3; + let player4 = player2.previousSeat; + while (player4.isDead()) { + player4 = player4.previousSeat; + } + player4.next = player2; + player2.previous = player4; + if (_status.roundStart == player) _status.roundStart = player2; + return player2; + } + static arrangePlayers() { + if (game.chess && game.me) { + let friendCount = 0, enemyCount = 0; + const rand = Math.random() < 0.5, sortCount = new Map(); + game.players.forEach(value => { + if (value.side == game.me.side) { + if (rand) if (value == game.friendZhu) sortCount.set(value, -2); + else sortCount.set(value, 2 * friendCount); + else if (value == game.friendZhu) sortCount.set(value, -1); + else sortCount.set(value, 2 * friendCount + 1); + friendCount++; + return; + } + if (rand) if (value == game.enemyZhu) sortCount.set(value, -1); + else sortCount.set(value, 2 * enemyCount + 1); + else if (value == game.enemyZhu) sortCount.set(value, -2); + else sortCount.set(value, 2 * enemyCount); + enemyCount++; + }); + game.players.sort((a, b) => sortCount.get(a) - sortCount.get(b)); + } + else game.players.sort(lib.sort.position); + game.players.concat(game.dead).sort(lib.sort.position).forEach((value, index, array) => { + if (index == 0) value.previousSeat = array[array.length - 1]; + else value.previousSeat = array[index - 1]; + if (index == array.length - 1) value.nextSeat = array[0]; + else value.nextSeat = array[index + 1]; + }); + game.players.forEach((value, index, array) => { + if (index == 0) value.previous = array[array.length - 1]; + else value.previous = array[index - 1]; + if (index == array.length - 1) value.next = array[0]; + else value.next = array[index + 1]; + }); + } + static filterSkills(skills, player, exclude) { + const out = skills.slice().removeArray(Object.keys(player.disabledSkills)); + if (!player.storage.skill_blocker || !player.storage.skill_blocker.length) return out; + return out.filter(value => exclude && exclude.includes(value) || !get.is.blocked(value, player)); + } + static expandSkills(skills) { + skills.addArray(skills.reduce((previousValue, currentValue) => { + const info = get.info(currentValue); + if (info) { + if (Array.isArray(info.group)) previousValue.push(...info.group); + else if (info.group) previousValue.push(info.group); + } + else console.log(currentValue); + return previousValue; + }, [])); + } + static css(style) { + Object.keys(style).forEach(value => { + let uiStyle = ui.style[value]; + if (!uiStyle) { + uiStyle = ui.style[value] = document.createElement("style"); + document.head.appendChild(uiStyle); + } + uiStyle.innerHTML = `${value}${JSON.stringify(style[value]).replace(/"/g, "")}`; + }); + } + static hasPlayer(func, includeOut) { + return game.players.some(value => (includeOut || !value.isOut()) && func(value)); + } + static hasPlayer2(func, includeOut) { + return game.players.concat(game.dead).some(value => (includeOut || !value.isOut()) && func(value)); + } + static countPlayer(func, includeOut) { + if (typeof func != "function") func = lib.filter.all; + return game.players.reduce((previousValue, currentValue) => { + if (!includeOut && currentValue.isOut()) return previousValue; + const result = func(currentValue); + if (typeof result == "number") previousValue += result; + else if (result) previousValue++; + return previousValue; + }, 0); + } + static countPlayer2(func, includeOut) { + if (typeof func != "function") func = lib.filter.all; + return game.players.concat(game.dead).reduce((previousValue, currentValue) => { + if (!includeOut && currentValue.isOut()) return previousValue; + const result = func(currentValue); + if (typeof result == "number") previousValue += result; + else if (result) previousValue++; + return previousValue; + }, 0); + } + static filterPlayer(func, list, includeOut) { + if (!Array.isArray(list)) list = []; + if (typeof func != "function") func = lib.filter.all; + return list.addArray(game.players.filter(value => (includeOut || !value.isOut()) && func(value))); + } + static filterPlayer2(func, list, includeOut) { + if (!Array.isArray(list)) list = []; + if (typeof func != "function") func = lib.filter.all; + return list.addArray(game.players.concat(game.dead).filter(value => (includeOut || !value.isOut()) && func(value))); + } + static findPlayer(func, includeOut) { + return game.players.find(value => (includeOut || !value.isOut()) && func(value)) || null; + } + static findPlayer2(func, includeOut) { + return game.players.concat(game.dead).find(value => (includeOut || !value.isOut()) && func(value)) || null; + } + static findCards(func, all) { + return Object.keys(lib.card).filter(value => { + if (!lib.translate[`${value}_info`]) return false; + if (lib.card[value].mode && lib.card[value].mode.includes(lib.config.mode) == false) return false; + if (!all && !lib.inpile.includes(value)) return false; + return func(value, lib.card[value]); + }); + } + static countGroup() { + const list = lib.group.slice(0); + return game.countPlayer(current => { + if (!list.includes(current.group)) return false; + list.remove(current.group); + return true; + }); + } +} diff --git a/noname/get.js b/noname/get.js new file mode 100644 index 000000000..085c7312b --- /dev/null +++ b/noname/get.js @@ -0,0 +1,4435 @@ +import { Is } from "./get/is.js"; +import { Library } from "./library.js"; +import { status } from "./status.js"; + +export class Get { + static is = Is; + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + /** + * 获取当前内核版本信息 + * + * 目前仅考虑`chrome`, `firefox`和`safari`三种浏览器的信息,其余均归于其他范畴 + * + * > 其他后续或许会增加,但`IE`永无可能 + * + * @returns {["firefox" | "chrome" | "safari" | "other", number]} + */ + static coreInfo() { + const regex = /(firefox|chrome|safari)\/([\d.]+)/; + let result; + if (!(result = userAgent.match(regex))) return ["other", NaN]; + if (result[1] != "safari") return [result[1], parseInt(result[2])]; + result = userAgent.match(/version\/([\d.]+).*safari/); + return ["safari", parseInt(result[1])]; + } + /** + * 返回 VCard[] 形式的所有牌,用于印卡将遍历 + * @param {Function} filter + * @returns {string[][]} + */ + static inpileVCardList(filter) { + let list = []; + for (const name of lib.inpile) { + const type = get.type(name); + const info = [type, "", name]; + if (!filter || filter(info)) list.push(info); + if (name == "sha") { + for (const nature of lib.inpile_nature) { + const info = [type, "", name, nature]; + if (!filter || filter(info)) list.push(info); + } + } + } + return list; + } + /** + * 根据座次数n(从0开始)获取对应的“n+1号位”翻译 + * @param {number} seat + */ + static seatTranslation(seat) { + return `${get.cnNumber(seat + 1, true)}号位`; + } + /** + * @param {number} numberOfPlayers + * @returns {string[]} + */ + static identityList(numberOfPlayers) { + const modeConfig = lib.config.mode_config; + if (modeConfig) { + const identityConfig = modeConfig.identity; + if (identityConfig) { + const identityLists = identityConfig.identity; + if (identityLists) { + const identityList = identityLists[numberOfPlayers - 2]; + if (Array.isArray(identityList)) return identityList.slice(); + } + } + } + const numberOfPlayersExceptLord = numberOfPlayers - 1, numberOfLoyalists = Math.round(numberOfPlayersExceptLord * 3 / 9), numberOfSpys = Math.round(numberOfPlayersExceptLord * 2 / 9); + return ["zhu"].concat(Array.from({ + length: numberOfLoyalists + }, () => "zhong"), Array.from({ + length: numberOfSpys + }, () => "nei"), Array.from({ + length: numberOfPlayersExceptLord - numberOfLoyalists - numberOfSpys + }, () => "fan")); + } + + /** + * Generate an object URL from the Base64-encoded octet stream + * + * 从Base64编码的八位字节流生成对象URL + */ + static objectURL(octetStream) { + const objectURLMap = lib.objectURL; + if (objectURLMap.has(octetStream)) return objectURLMap.get(octetStream); + const objectURL = URL.createObjectURL(new Blob([Uint8Array.from(atob(octetStream.replace(/^data:[\s\S]*\/[\s\S]*;base64,/, "")), character => character.charCodeAt())])); + objectURLMap.set(octetStream, objectURL); + return objectURL; + } + + /** + * Get the card name length + * + * 获取此牌的字数 + */ + static cardNameLength(card, player) { + const actualCardName = lib.actualCardName, name = get.translation(typeof card == "string" ? card : get.name(card, player)); + return (actualCardName.has(name) ? actualCardName.get(name) : name).length; + } + + // Yingbian + // 应变 + /** + * Get the Yingbian conditions (of the card) + * + * 获取(此牌的)应变条件 + */ + static yingbianConditions(card) { + return get.complexYingbianConditions(card).concat(get.simpleYingbianConditions(card)); + } + static complexYingbianConditions(card) { + const complexYingbianConditions = Array.from(lib.yingbian.condition.complex.keys()); + return card ? complexYingbianConditions.filter(value => get.cardtag(card, `yingbian_${value}`)) : complexYingbianConditions; + } + static simpleYingbianConditions(card) { + const simpleYingbianConditions = Array.from(lib.yingbian.condition.simple.keys()) + return card ? simpleYingbianConditions.filter(value => get.cardtag(card, `yingbian_${value}`)) : simpleYingbianConditions; + } + + /** + * Get the Yingbian effects (of the card) + * + * 获取(此牌的)应变效果 + */ + static yingbianEffects(card) { + const yingbianEffects = Array.from(lib.yingbian.effect.keys()); + return card ? yingbianEffects.filter(value => get.cardtag(card, `yingbian_${value}`)) : yingbianEffects; + } + + /** + * Get the default Yingbian effect of the card + * + * 获取此牌的默认应变效果 + */ + static defaultYingbianEffect(card) { + const info = get.info(card); + return info && info.defaultYingbianEffect || null; + } + /** + * 优先度判断 + */ + static priority(skill) { + const info = get.info(skill); + if (!info) return 0; + if (Object.prototype.hasOwnProperty.call(info, "_priority")) return info._priority; + let priority = 0; + if (info.priority) { + priority = info.priority * 100; + } + if (info.silent) { + priority++; + } + if (info.equipSkill) priority -= 25; + if (info.cardSkill) priority -= 50; + if (info.ruleSkill) priority -= 75; + info._priority = priority; + return priority; + } + + // 新装备栏相关 + /** + * 获取一张装备牌实际占用的装备栏(君曹操六龙) + * + * 用法同get.subtype,返回数组 + */ + static subtypes(obj, player) { + if (typeof obj == "string") obj = { name: obj }; + if (typeof obj != "object") return; + var name = get.name(obj, player); + if (!lib.card[name]) return []; + if (lib.card[name].subtypes) { + const subtypes = get.copy(lib.card[name].subtypes); + return subtypes; + } + else if (lib.card[name].subtype) { + const subtype = lib.card[name].subtype; + return [subtype]; + } + return []; + } + // 装备栏 END + static pinyin(chinese, withTone) { + const pinyinUtilx = window.pinyinUtilx; + if (!pinyinUtilx) return []; + const pinyins = lib.pinyins; + if (pinyins) { + const pinyin = pinyins[chinese]; + if (Array.isArray(pinyin)) return withTone === false ? pinyin.map(pinyinUtilx.removeTone) : pinyin.slice(); + } + return pinyinUtilx.getPinyin(chinese, null, withTone, true); + } + static yunmu(str) { + //部分整体认读音节特化处理 + const util = window.pinyinUtilx; + if (util && lib.pinyins._metadata.zhengtirendu.contains(util.removeTone(str))) { + return "-" + str[str.length - 1]; + } + //排除声母 + for (let i of lib.pinyins._metadata.shengmu) { + if (str.startsWith(i)) { + str = str.slice(i.length); + if (str[0] == "u" && lib.pinyins._metadata.special_shengmu.contains(i)) str = "ü" + str.slice(1); + break; + } + } + //排除介母 + if (str.length > 0) { + for (let i in lib.pinyins._metadata.feijiemu) { + if (str[0] == i) { + let goon = false; + for (let j of lib.pinyins._metadata.feijiemu[i]) { + if (str.startsWith(j)) goon = true; + } + if (!goon) str = str.slice(1); + break; + } + } + } + return str; + } + /** + * 用于将参数转换为字符串,作为缓存的key。 + */ + static paramToCacheKey() { + var str = ""; + for (var arg of arguments) { + if (arg === null || arg === undefined) { + str += (arg + "-"); + continue; + } + if (arg.playerid) { + str += "p:" + arg.playerid; + } else if (arg.cardid) { + str += "c:" + arg.cardid; + } else if (arg.name) { + str += "n:" + arg.name; + } else { + str += "s:" + arg; + } + str += "-"; + } + return str; + } + static yunjiao(str) { + const util = window.pinyinUtilx; + if (util) str = util.removeTone(str) + if (lib.pinyins._metadata.zhengtirendu.contains(str)) { + str = ("-" + str[str.length - 1]); + } + else { + for (let i of lib.pinyins._metadata.shengmu) { + if (str.startsWith(i)) { + str = str.slice(i.length); + if (str[0] == "u" && lib.pinyins._metadata.special_shengmu.contains(i)) str = "ü" + str.slice(1); + break; + } + } + } + for (let i in lib.pinyins._metadata.yunjiao) { + if (lib.pinyins._metadata.yunjiao[i].contains(str)) return i; + } + return null; + } + static skillCategoriesOf(skill, player) { + var list = [], info = get.info(skill); + if (!info) return list; + if (get.is.locked(skill, player)) list.add("锁定技"); + if (info.zhuSkill) list.add("主公技"); + if (info.limited) list.add("限定技"); + if (info.juexingji) list.add("觉醒技"); + if (info.zhuanhuanji) list.add("转换技"); + if (info.hiddenSkill) list.add("隐匿技"); + if (info.clanSkill) list.add("宗族技"); + if (info.groupSkill) list.add("势力技"); + if (info.dutySkill) list.add("使命技"); + if (info.chargeSkill) list.add("蓄力技"); + if (info.zhenfa) list.add("阵法技"); + if (info.mainSkill) list.add("主将技"); + if (info.viceSkill) list.add("副将技"); + if (info.lordSkill) list.add("君主技"); + if (info.chargingSkill) list.add("蓄能技"); + if (info.charlotte) list.add("Charlotte"); + if (info.sunbenSkill) list.add("昂扬技"); + if (info.categories) list.addArray(info.categories(skill, player)); + return list; + } + static numOf(obj, item) { + return obj.filter(element => element == item).length; + } + static connectNickname() { + return typeof lib.config.connect_nickname == "string" ? (lib.config.connect_nickname.slice(0, 12)) : "无名玩家"; + } + static zhinangs(filter) { + var list = (_status.connectMode ? lib.configOL : lib.config).zhinang_tricks; + if (!list || !list.filter || !list.length) return get.inpile("trick", "trick").randomGets(3); + if (filter === false) return list.slice(0); + list = list.filter(card => lib.inpile.includes(card)); + if (list.length) return list; + return get.inpile("trick", "trick").randomGets(3); + } + static sourceCharacter(str) { + if (str) { + for (var i in lib.characterReplace) { + if (lib.characterReplace[i].includes(str)) return i; + } + } + return str; + } + static isLuckyStar(player) { + if (player && player.hasSkillTag("luckyStar")) return true; + if (_status.connectMode) return false; + return (!player || player == game.me || player.isUnderControl()) && lib.config.lucky_star == true; + } + static infoHp(hp) { + if (typeof hp == "number") return hp; + else if (typeof hp == "string" && hp.includes("/")) { + return parseInt(hp.split("/")[0]); + } + return 0; + } + static infoMaxHp(hp) { + if (typeof hp == "number") return hp; + else if (typeof hp == "string" && hp.includes("/")) { + return parseInt(hp.split("/")[1]); + } + return 0; + } + static infoHujia(hp) { + if (typeof hp == "string" && hp.includes("/")) { + var splited = hp.split("/"); + if (splited.length > 2) return parseInt(splited[2]); + } + return 0; + } + static bottomCards(num, putBack) { + if (_status.waitingForCards) { + ui.create.cards.apply(ui.create, _status.waitingForCards); + delete _status.waitingForCards; + } + var list = []; + var card = false; + if (typeof num != "number") num = 1; + if (num == 0) { card = true; num = 1; } + if (num < 0) num = 1; + while (num--) { + if (ui.cardPile.hasChildNodes() == false) { + game.washCard(); + } + if (ui.cardPile.hasChildNodes() == false) { + game.over("平局"); + return []; + } + var cardx = ui.cardPile.removeChild(ui.cardPile.lastChild); + cardx.original = "c"; + list.push(cardx); + } + if (putBack) { + for (let i = list.length - 1; i >= 0; i--) { + ui.cardPile.appendChild(list[i]); + } + } + game.updateRoundNumber(); + if (card) return list[0]; + return list; + } + static discarded() { + return _status.discarded.filter(item => item.parentNode == ui.discardPile); + } + static cardOffset() { + var x = ui.arena.getBoundingClientRect(); + var y = ui.window.getBoundingClientRect(); + return -y.width / 2 + (x.left + x.width / 2); + } + static colorspan(str) { + if (str[0] == "#") { + var color; + switch (str[1]) { + case "r": color = "fire"; break; + case "p": color = "legend"; break; + case "b": color = "blue"; break; + case "g": color = "green"; break; + default: return str.slice(2); + } + return `${str.slice(2)}`; + } + return str; + } + static evtprompt(next, str) { + if (next.prompt) { + next.set("prompt2", str); + } + else { + if (str.startsWith("###")) { + var prompts = str.slice(3).split("###"); + if (prompts[0]) next.set("prompt", prompts[0]); + if (prompts[1]) next.set("prompt2", prompts[1]); + } + else { + next.set("prompt", str); + } + } + } + static autoViewAs(card, cards) { + return new lib.element.VCard(card, cards); + } + /** + * @deprecated + */ + static _autoViewAs(card, cards) { + var info = get.info(card); + if (info.autoViewAs) { + if (cards === false) { + return { + name: info.autoViewAs, + }; + } + else if (Array.isArray(cards)) { + return { + name: info.autoViewAs, + cards: cards.slice(0), + }; + } + else if (get.itemtype(card) == "card") { + return { + name: info.autoViewAs, + cards: [card], + }; + } + else { + return { + name: info.autoViewAs, + suit: card.suit, + number: card.number, + nature: card.nature, + }; + } + } + else { + if (card.isCard || get.itemtype(card) == "card") { + var next = { + name: get.name(card), + suit: get.suit(card), + number: get.number(card), + nature: get.nature(card), + isCard: true, + cardid: card.cardid, + wunature: card.wunature, + storage: get.copy(card.storage), + cards: get.copy(card.cards), + }; + if (get.itemtype(cards) == "cards" && !card.cards) next.cards = cards.slice(0); + else if (get.itemtype(card) == "card") next.cards = [card]; + return next; + } + else if (get.is.object(card) && get.itemtype(cards) == "cards" && !card.cards) { + card = get.copy(card); + card.cards = cards.slice(0); + } + return card; + } + } + static max(list, func, type) { + list = list.slice(0); + if (typeof func == "string") { + var key = func; + func = function (item) { + return item[key]; + } + } + list.sort(function (a, b) { + return func(b) - func(a); + }); + if (type == "list") { + var list2 = []; + for (var i = 0; i < list.length; i++) { + if (func(list[i]) == func(list[0])) { + list2.push(list[i]); + } + } + return list2; + } + else if (type == "item") { + return list[0]; + } + else { + return func(list[0]); + } + } + static min(list, func, type) { + list = list.slice(0); + if (typeof func == "string") { + var key = func; + func = function (item) { + return item[key]; + } + } + list.sort(function (a, b) { + return func(a) - func(b); + }); + if (type == "list") { + var list2 = []; + for (var i = 0; i < list.length; i++) { + if (func(list[i]) == func(list[0])) { + list2.push(list[i]); + } + } + return list2; + } + else if (type == "item") { + return list[0]; + } + else { + return func(list[0]); + } + } + static character(name, num) { + let info = lib.character[name]; + if (!info) { + const pack = Object.keys(lib.characterPack).find(pack => Object.prototype.hasOwnProperty.call(lib.characterPack[pack], name)); + if (pack) info = lib.characterPack[pack][name]; + } + if (info) { + if (typeof num == "number") { + return info[num]; + } + return info; + } + return null; + } + static characterIntro(name) { + if (lib.characterIntro[name]) return lib.characterIntro[name]; + var tags = get.character(name, 4); + if (tags) { + for (var i = 0; i < tags.length; i++) { + if (tags[i].startsWith("des:")) { + return tags[i].slice(4); + } + } + } + while (name.includes("_") && !lib.characterIntro[name]) { + name = name.slice(name.indexOf("_") + 1); + } + if (lib.characterIntro[name]) return lib.characterIntro[name]; + return "暂无武将介绍"; + } + static bordergroup(info, raw) { + if (!Array.isArray(info)) { + info = lib.character[info]; + if (!info) return ""; + } + if (Array.isArray(info[4])) for (const str of info[4]) { + if (typeof str == "string" && str.startsWith("border:")) return str.slice(7); + } + return raw ? "" : info[1] || ""; + } + static groupnature(group, method) { + var nature = lib.groupnature[group]; + if (!nature) return ""; + if (method == "raw") { + return nature; + } + return nature + "mm"; + } + static sgn(num) { + if (num > 0) return 1; + if (num < 0) return -1; + return 0; + } + static rand(num, num2) { + if (typeof num2 == "number") { + return num + Math.floor(Math.random() * (num2 - num + 1)); + } + else { + return Math.floor(Math.random() * num); + } + } + static sort(arr, method, arg) { + if (method == "seat") return arr.sortBySeat(arg); + } + static sortSeat(arr, target) { + return arr.sortBySeat(target); + } + static zip(callback) { + if (!window.JSZip) { + lib.init.js(lib.assetURL + "game", "jszip", function () { + callback(new JSZip()); + }); + } + else { + callback(new JSZip()); + } + } + static delayx(num, max) { + if (typeof num != "number") num = 1; + if (typeof max != "number") max = Infinity; + switch (lib.config.game_speed) { + case "vslow": return Math.min(max, 2.5 * num); + case "slow": return Math.min(max, 1.5 * num); + case "fast": return Math.min(max, 0.7 * num); + case "vfast": return Math.min(max, 0.4 * num); + case "vvfast": return Math.min(max, 0.2 * num); + default: return Math.min(max, num); + } + } + static prompt(skill, target, player) { + player = player || _status.event.player; + if (target) { + var str = get.translation(target); + if (target == player) { + str += "(你)" + } + return "是否对" + str + "发动【" + get.skillTranslation(skill, player) + "】?"; + } + else { + return "是否发动【" + get.skillTranslation(skill, player) + "】?"; + } + } + static prompt2(skill, target, player) { + var str = get.prompt.apply(this, arguments); + if (!lib.translate[skill + "_info"]) return str; + return "###" + str + "###" + lib.translate[skill + "_info"]; + } + static url(master) { + var url = lib.config.updateURL || lib.updateURL; + if (url[url.length - 1] != "/") { + url += "/"; + } + if (master != "nodev") { + return url + "master/"; + } + else { + return url + "v" + lib.version + "/"; + } + } + static round(num, f) { + var round = Math.pow(10, f); + return Math.round(num * round) / round; + } + static playerNumber() { + var num; + if (_status.brawl && _status.brawl.playerNumber) { + num = _status.brawl.playerNumber + } + else { + num = get.config("player_number"); + } + return parseInt(num) || 2; + } + static benchmark(func1, func2, iteration, arg) { + var tic, toc; + var key1, key2; + if (!arg) arg = []; + if (Array.isArray(func2)) { + key1 = func2[0]; + key2 = func2[1]; + } + else if (typeof func2 == "string") { + key1 = func2; + func2 = iteration || 100; + } + else if (typeof func2 == "number") { + arg = iteration || arg; + iteration = func2; + } + tic = get.utc(); + for (var i = 0; i < iteration; i++) { + if (key1) { + func1[key1](arg.randomGet()); + } + else { + func1(arg.randomGet()); + } + } + toc = get.utc(); + if (typeof func2 == "number") { + return toc - tic; + } + console.log("time1: " + (toc - tic)); + tic = get.utc(); + for (var i = 0; i < iteration; i++) { + if (key2) { + func1[key2](arg.randomGet()); + } + else { + func2(arg.randomGet()); + } + } + toc = get.utc(); + console.log("time2: " + (toc - tic)); + } + static stringify(obj, level) { + level = level || 0; + var indent = ""; + var str; + for (var i = 0; i < level; i++) { + indent += " "; + } + if (get.objtype(obj) == "object") { + str = "{\n"; + for (var i in obj) { + if (/[^a-zA-Z]/.test(i)) { + str += `${indent} "${i}":${get.stringify(obj[i], level + 1)},\n`; + } + else { + str += indent + " " + i + ":" + get.stringify(obj[i], level + 1) + ",\n"; + } + } + str += indent + "}"; + return str; + } + else { + if (typeof obj == "function") { + str = obj.toString(); + str = str.replace(/\t/g, " "); + var i = str.lastIndexOf("\n"); + var num = 0; + for (var j = i + 1; j < str.length && str[j] == " "; j++) { + num++; + } + num = Math.floor(num / 4); + for (i = 0; i < num - level; i++) { + str = str.replace(/\n {4}/g, "\n"); + } + } + else { + try { + if (Array.isArray(obj) && obj.contains(Infinity)) { + obj = obj.slice(0); + var rand = get.id(); + for (var i = 0; i < obj.length; i++) { + if (obj[i] === Infinity) { + obj[i] = parseInt(rand); + } + } + str = JSON.stringify(obj).replace(new RegExp(rand, "g"), "Infinity"); + } + else { + str = JSON.stringify(obj) || ""; + } + } + catch (e) { + str = ""; + } + } + return str; + } + } + /** + * @template T + * @param {T} obj + * @returns {T} + */ + static copy(obj) { + if (get.objtype(obj) == "object") { + var copy = {}; + for (var i in obj) { + copy[i] = get.copy(obj[i]); + } + return copy; + } + else if (Array.isArray(obj)) { + var copy = []; + for (var i = 0; i < obj.length; i++) { + copy.push(get.copy(obj[i])); + } + return copy; + } + else { + return obj; + } + } + static inpilefull(type) { + var list = []; + for (var i in lib.cardPile) { + for (var j = 0; j < lib.cardPile[i].length; j++) { + var info = lib.cardPile[i][j]; + if (lib.inpile.contains(info[2]) && get.type(info[2]) == type) { + list.push({ + name: info[2], + suit: info[0], + number: info[1], + nature: info[3] + }); + } + } + } + return list; + } + static inpile(type, filter) { + var list = []; + if (filter == "trick") { + for (var i = 0; i < lib.inpile.length; i++) { + if (get.type(lib.inpile[i], "trick") == type) list.push(lib.inpile[i]); + } + } + else { + for (var i = 0; i < lib.inpile.length; i++) { + if (typeof type == "function") { + if (type(lib.inpile[i])) { + list.push(lib.inpile[i]); + } + } + else { + if (typeof filter == "function" && !filter(lib.inpile[i])) continue; + if (type.startsWith("equip") && type.length == 6) { + if (get.subtype(lib.inpile[i]) == type) list.push(lib.inpile[i]); + } + else { + if (get.type(lib.inpile[i]) == type) list.push(lib.inpile[i]); + } + } + } + } + return list; + } + static inpile2(type) { + return get.inpile(type, "trick"); + } + static typeCard(type, filter) { + var list = []; + for (var i in lib.card) { + if (lib.card[i].mode && lib.card[i].mode.contains(get.mode()) == false) continue; + // if(lib.card[i].vanish||lib.card[i].destroy) continue; + if (lib.card[i].destroy) continue; + if (typeof filter == "function" && !filter(i)) continue; + if (lib.config.bannedcards.contains(i)) continue; + if (!lib.translate[i + "_info"]) continue; + if ((type.startsWith("equip") && type.length == 6) || + (type.startsWith("hslingjian") && type.length == 11) || + (type.startsWith("spell_"))) { + if (get.subtype(i) == type) list.push(i); + } + else { + if (get.type(i) == type) list.push(i); + } + } + return list; + } + static libCard(filter) { + var list = []; + for (var i in lib.card) { + if (lib.card[i].mode && lib.card[i].mode.contains(get.mode()) == false) continue; + // if(lib.card[i].vanish||lib.card[i].destroy) continue; + if (lib.card[i].destroy) continue; + if (lib.config.bannedcards.contains(i)) continue; + if (!lib.translate[i + "_info"]) continue; + if (filter(lib.card[i], i)) { + list.push(i); + } + } + return list; + } + static ip() { + if (!require) return ""; + var interfaces = require("os").networkInterfaces(); + for (var devName in interfaces) { + var iface = interfaces[devName]; + for (var i = 0; i < iface.length; i++) { + var alias = iface[i]; + if (alias.family === "IPv4" && alias.address !== "127.0.0.1" && !alias.internal) { + return alias.address; + } + } + } + } + static modetrans(config, server) { + if (config.mode == "doudizhu") { + switch (config.doudizhu_mode) { + case "kaihei": return "开黑斗地主"; + case "huanle": return "欢乐斗地主"; + case "binglin": return "兵临城下"; + case "online": return "智斗三国"; + default: return "休闲" + (config.double_character ? "双将" : "") + "斗地主"; + } + } + if (config.mode == "versus") { + switch (config.versus_mode) { + case "1v1": return "单人对决"; + case "2v2": return "欢乐成双"; + case "3v3": return "血战到底"; + case "4v4": return "四人对决"; + case "guandu": return "官渡之战"; + } + } + if (config.mode == "single") { + switch (config.single_mode) { + case "normal": return "新1v1"; + case "changban": return "血战长坂坡"; + case "dianjiang": return "点将单挑"; + } + } + if (config.mode == "identity") { + switch (config.identity_mode) { + case "purple": return "三对三对二"; + case "zhong": return (config.double_character ? "双将" : "") + "忠胆英杰"; + case "stratagem": return get.cnNumber(parseInt(config.number)) + "人" + (config.double_character ? "双将" : "") + "谋攻"; + default: return `${get.cnNumber(parseInt(config.number))}人${config.double_nei ? "双内" : ""}${config.enable_commoner ? "带民" : ""}${config.double_character ? "双将" : ""}身份`; + } + } + if (config.mode == "guozhan") { + if (config.separatism) return "群雄割据"; + if (config.guozhan_mode != "normal") switch (config.guozhan_mode) { + case "yingbian": return "应变国战"; + case "old": return "怀旧国战"; + } + } + if (server) { + return get.translation(config.mode) + "模式"; + } + else { + return get.cnNumber(parseInt(config.number)) + "人" + get.translation(config.mode); + } + } + static charactersOL(func) { + var list = []; + var libCharacter = {}; + for (var i = 0; i < lib.configOL.characterPack.length; i++) { + var pack = lib.characterPack[lib.configOL.characterPack[i]]; + for (var j in pack) { + if (typeof func == "function" && func(j)) continue; + if (lib.connectBanned.contains(j)) continue; + if (lib.character[j]) libCharacter[j] = pack[j]; + } + } + for (i in libCharacter) { + if (lib.filter.characterDisabled(i, libCharacter)) continue; + list.push(i); + } + return list; + } + static trimip(str) { + var len = str.length - 5; + if (str.lastIndexOf(":8080") == len) { + str = str.slice(0, len); + } + return str; + } + static mode() { + return lib[_status.connectMode ? "configOL" : "config"].mode; + } + static idDialog(id) { + return ui.dialogs.find(dialog => dialog.videoId == id) || null; + } + static arenaState() { + var state = { + number: ui.arena.dataset.number, + players: {}, + mode: _status.mode, + dying: _status.dying, + servermode: window.isNonameServer, + roomId: game.roomId, + over: _status.over, + inpile: lib.inpile, + inpile_nature: lib.inpile_nature, + renku: _status.renku, + }; + for (var i in lib.playerOL) { + state.players[i] = lib.playerOL[i].getState(); + } + return state; + } + static skillState(player) { + var skills = { + global: lib.skill.global + }; + var skillinfo = {}; + for (var i in lib.playerOL) { + skills[i] = { + skills: lib.playerOL[i].skills, + hiddenSkills: lib.playerOL[i].hiddenSkills, + invisibleSkills: lib.playerOL[i].invisibleSkills, + additionalSkills: lib.playerOL[i].additionalSkills, + disabledSkills: lib.playerOL[i].disabledSkills, + tempSkills: lib.playerOL[i].tempSkills, + storage: lib.playerOL[i].storage, + } + } + //for(var i in lib.skill){ + // if(lib.skill[i].chooseButton&&lib.skill[i].enable){ + // skillinfo[i]=lib.skill[i].chooseButton; + // } + //} + skills.skillinfo = skillinfo; + if (player) { + skills.stat = player.getStat(); + } + return skills; + } + static id() { + return `${Math.floor(1000000 + 9000000 * Math.random())}${10 + lib.status.globalId++}`; + } + static zhu(player, skill, group) { + if (typeof player == "string") { + skill = player; + player = null; + } + var mode = get.mode(); + if (mode == "identity") { + if (_status.mode == "purple") { + if (!player) return null; + var zhu = game[player.identity.slice(0, 1) + "Zhu"]; + if (!zhu) return null; + if (skill && !zhu.hasSkill(skill)) return null; + return zhu; + } + if (!game.zhu) return null; + if (skill && !game.zhu.hasSkill(skill)) return null; + if (game.zhu.isZhu) return game.zhu; + } + else if (mode == "versus" && (_status.mode == "four" || _status.mode == "guandu")) { + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isZhu) { + if (skill && !(game.players[i].hasSkill(skill))) continue; + if (!player) return game.players[i]; + if (player.side == game.players[i].side) { + return game.players[i]; + } + } + } + } + else if (mode == "guozhan") { + for (var i = 0; i < game.players.length; i++) { + if (get.is.jun(game.players[i]) && !game.players[i].isUnseen()) { + if (skill && !game.players[i].hasSkill(skill)) continue; + if (!player) return game.players[i]; + if (player.identity == game.players[i].identity) { + return game.players[i]; + } + else if (group && group == game.players[i].identity) { + return game.players[i]; + } + } + } + } + return null; + } + static config(item, mode) { + mode = mode || lib.config.mode; + if (!lib.config.mode_config[mode]) return; + return lib.config.mode_config[mode][item]; + } + static coinCoeff(list) { + var num = 0; + for (var i = 0; i < list.length; i++) { + var rank = get.rank(list[i]); + switch (rank) { + case "sp": return 0.1; + case "s": num += 0.4; break; + case "ap": num += 0.6; break; + case "a": num += 0.8; break; + case "am": num += 0.95; break; + case "bp": num += 1.05; break; + case "b": num += 1.2; break; + case "bm": num += 1.4; break; + case "c": num += 1.6; break; + case "d": num += 1.8; break; + } + } + return num / list.length; + } + static rank(name, num) { + if (typeof name == "object" && name.name) { + name = name.name; + } + if (num == true) num = 9; + if (typeof num != "number") num = false; + if (name == _status.lord) return num ? Math.round(7 * (num - 1) / 8 + 1) : "ap"; + var rank = lib.rank; + if (lib.characterPack.standard[name] || lib.characterPack.shenhua[name]) { + var skills; + if (lib.character[name]) { + skills = lib.character[name][3]; + } + else { + var tmpinfo = get.character(name); + if (tmpinfo) { + skills = tmpinfo[3]; + } + else { + skills = []; + } + } + for (var i = 0; i < skills.length; i++) { + if (skills[i].alter && !lib.config.vintageSkills.contains(skills[i])) { + name = lib.rank.a[0]; break; + } + } + } + if (rank.s.contains(name)) return num ? Math.round(8 * (num - 1) / 8 + 1) : "s"; + if (rank.ap.contains(name)) return num ? Math.round(7 * (num - 1) / 8 + 1) : "ap"; + if (rank.a.contains(name)) return num ? Math.round(6 * (num - 1) / 8 + 1) : "a"; + if (rank.am.contains(name)) return num ? Math.round(5 * (num - 1) / 8 + 1) : "am"; + if (rank.bp.contains(name)) return num ? Math.round(4 * (num - 1) / 8 + 1) : "bp"; + if (rank.b.contains(name)) return num ? Math.round(3 * (num - 1) / 8 + 1) : "b"; + if (rank.bm.contains(name)) return num ? Math.round(2 * (num - 1) / 8 + 1) : "bm"; + if (rank.c.contains(name)) return num ? Math.round(1 * (num - 1) / 8 + 1) : "c"; + if (rank.d.contains(name)) return num ? Math.round(0 * (num - 1) / 8 + 1) : "d"; + if (lib.character[name] && lib.character[name][4]) { + if (lib.character[name][4].contains("boss") || + lib.character[name][4].contains("bossallowed") || + lib.character[name][4].contains("hiddenboss")) { + return num ? Math.round(9 * (num - 1) / 8 + 1) : "sp"; + } + } + return num ? Math.round(9 * (num - 1) / 8 + 1) : "x"; + } + static skillRank(skill, type, grouped) { + var info = lib.skill[skill]; + var player = _status.event.skillRankPlayer || _status.event.player; + if (!info) return 0; + if (info.ai) { + if (info.ai.halfneg) return 0; + if (typeof info.ai.combo == "string" && player && !player.hasSkill(info.ai.combo)) { + return 0; + } + if (info.ai.neg) return -1; + } + var num = 1; + var threaten = 1; + if (info.ai && info.ai.threaten) { + if (typeof info.ai.threaten == "number") { + threaten = info.ai.threaten; + } + else if (typeof info.ai.threaten == "function" && player) { + threaten = info.ai.threaten(player, player); + } + } + if (type && type.includes("in")) { + if (info.enable == "phaseUse") num += 0.5; + if (info.trigger && info.trigger.player) { + var list = Array.isArray(info.trigger.player) ? info.trigger.player : [info.trigger.player]; + var add = false; + for (var i of list) { + if (i.startsWith("phase")) { + num += 0.5; + add = true; + } + else { + for (var j of lib.phaseName) { + if (i.indexOf[j] == 0) { + num += 0.5; + add = true; + break; + } + } + } + if (add) break; + } + } + if (info.trigger && ((typeof info.trigger.player == "string" && info.trigger.player.startsWith("use")) || info.trigger.source)) { + num += 0.3; + } + if (num > 1 && threaten > 1) { + num += Math.sqrt(threaten) - 1; + } + } + if (type && type.includes("out")) { + if (threaten < 1) { + num *= 1 / Math.sqrt(threaten); + } + if (info.trigger) { + if (info.trigger.global) { + var list = Array.isArray(info.trigger.global) ? info.trigger.global : [info.trigger.global]; + num += Math.min(3, list.length) / 10; + for (var i of list) { + if (i.startsWith("lose") || i.startsWith("use")) num += 0.3; + if (i.startsWith("cardsDiscard")) num += 0.4; + } + } + if (info.trigger.target || (typeof info.trigger.player == "string" && + (info.trigger.player.startsWith("damage") || info.trigger.player.startsWith("lose")))) num += 0.1; + } + if (info.ai) { + if (info.ai.maixie || info.ai.maixie_hp || info.ai.maixie_defend) { + num += 0.5; + } + if (info.ai.nolose || info.ai.noh || info.ai.noe || info.ai.nodiscard) { + num += 0.3; + } + } + } + if (!grouped) { + var groups = game.expandSkills([skill]); + groups.remove(skill); + var ggt = []; + for (var i = 0; i < groups.length; i++) { + var gi = get.skillRank(groups[i], type, true); + if (gi < 0) { + num -= 0.5; + } + else if (gi > 1) { + ggt.push(gi); + } + } + if (ggt.length) { + num += Math.max.apply(this, ggt) - 1 + ggt.length / 20; + } + } + return num; + } + static targetsInfo(targets) { + var info = []; + for (var i = 0; i < targets.length; i++) { + info.push(targets[i].dataset.position); + } + return info; + } + static infoTargets(infos) { + return Array.from(infos || [], info => game.playerMap[info]); + } + static cardInfo(card) { + return [card.suit, card.number, card.name, card.nature]; + } + static cardsInfo(cards) { + return Array.from(cards || [], get.cardInfo); + } + static infoCard(info) { + var card = ui.create.card(); + if (info[0]) { + card.init(info); + } + return card; + } + static infoCards(infos) { + return Array.from(infos || [], get.infoCard); + } + static cardInfoOL(card) { + return "_noname_card:" + JSON.stringify([card.cardid, card.suit, card.number, card.name, card.nature]); + } + static infoCardOL(info) { + if (!lib.cardOL) return info; + var card; + try { + var info = JSON.parse(info.slice(13)); + var id = info.shift(); + if (!id) { + card = ui.create.card(); + if (info && info[2]) card.init(info); + } + else if (lib.cardOL[id]) { + if (lib.cardOL[id].name != info[2]) { + if (info && info[2]) lib.cardOL[id].init(info); + } + card = lib.cardOL[id]; + } + else if (game.online) { + card = ui.create.card(); + card.cardid = id; + if (info && info[2]) card.init(info); + lib.cardOL[id] = card; + } + } + catch (e) { + console.log(e); + } + return card || info; + } + static cardsInfoOL(cards) { + return Array.from(cards || [], get.cardInfoOL); + } + static infoCardsOL(infos) { + return Array.from(infos || [], get.infoCardOL); + } + static playerInfoOL(player) { + return "_noname_player:" + player.playerid; + } + static infoPlayerOL(info) { + return lib.playerOL ? (lib.playerOL[info.slice(15)] || info) : info; + } + static playersInfoOL(players) { + return Array.from(players || [], get.playerInfoOL); + } + static infoPlayersOL(infos) { + return Array.from(infos || [], get.infoPlayerOL); + } + static funcInfoOL(func) { + if (typeof func == "function") { + if (func._filter_args) { + return "_noname_func:" + JSON.stringify(get.stringifiedResult(func._filter_args, 3)); + } + return "_noname_func:" + func.toString(); + } + return ""; + } + static infoFuncOL(info) { + var func; + try { + eval("func=(" + info.slice(13) + ");"); + } + catch (e) { + return function () { }; + } + if (Array.isArray(func)) { + func = get.filter.apply(this, get.parsedResult(func)); + } + return func; + } + static eventInfoOL(item, level, noMore) { + return get.itemtype(item) == "event" ? `_noname_event:${JSON.stringify(Object.entries(item).reduce((stringifying, entry) => { + const key = entry[0]; + if (key == "_trigger") { + if (noMore !== false) stringifying[key] = get.eventInfoOL(entry[1], null, false); + } + else if (!lib.element.GameEvent.prototype[key] && key != "content" && get.itemtype(entry[1]) != "event") stringifying[key] = get.stringifiedResult(entry[1], null, false); + return stringifying; + }, {}))}` : ""; + } + /** + * @param {string} item + */ + static infoEventOL(item) { + const evt = new lib.element.GameEvent(); + try { + Object.entries(JSON.parse(item.slice(14))).forEach(entry => { + const key = entry[0]; + if (typeof evt[key] != "function") evt[key] = get.parsedResult(entry[1]); + }); + } + catch (error) { + console.log(error); + } + return evt || item; + } + static stringifiedResult(item, level, nomore) { + if (!item) return item; + if (typeof item == "function") { + return get.funcInfoOL(item); + } + else if (typeof item == "object") { + switch (get.itemtype(item)) { + case "card": return get.cardInfoOL(item); + case "cards": return get.cardsInfoOL(item); + case "player": return get.playerInfoOL(item); + case "players": return get.playersInfoOL(item); + case "event": + if (nomore === false) return ""; + return get.eventInfoOL(item); + default: + if (typeof level != "number") { + level = 8; + } + if (Array.isArray(item)) { + if (level == 0) { + return []; + } + var item2 = []; + for (var i = 0; i < item.length; i++) { + item2.push(get.stringifiedResult(item[i], level - 1, nomore)); + } + return item2; + } + else if (Object.prototype.toString.call(item) == "[object Object]") { + if (level == 0) { + return {}; + } + var item2 = {}; + for (var i in item) { + item2[i] = get.stringifiedResult(item[i], level - 1, nomore); + } + return item2; + } + else { + return {}; + } + } + } + else if (item === Infinity) { + return "_noname_infinity"; + } + else { + return item; + } + } + static parsedResult(item) { + if (!item) return item; + if (typeof item == "string") { + if (item.startsWith("_noname_func:")) { + return get.infoFuncOL(item); + } + else if (item.startsWith("_noname_card:")) { + return get.infoCardOL(item); + } + else if (item.startsWith("_noname_player:")) { + return get.infoPlayerOL(item); + } + else if (item.startsWith("_noname_event:")) { + return get.infoEventOL(item); + } + else if (item == "_noname_infinity") { + return Infinity; + } + else { + return item; + } + } + else if (Array.isArray(item)) { + var item2 = []; + for (var i = 0; i < item.length; i++) { + item2.push(get.parsedResult(item[i])); + } + return item2; + } + else if (typeof item == "object") { + var item2 = {}; + for (var i in item) { + item2[i] = get.parsedResult(item[i]); + } + return item2; + } + else { + return item; + } + } + static verticalStr(str, sp) { + if (typeof str != "string") return ""; + return Array.from(str).filter(value => value != "`").join(""); + } + static numStr(num, method) { + if (num == Infinity) { + if (method == "card") return get.selectableCards().length + ui.selected.cards.length; + if (method == "target") return get.selectableTargets().length + ui.selected.targets.length; + return "∞"; + } + return num.toString(); + } + static rawName(str) { + let str2 = lib.translate[str]; + if (lib.translate[str + "_ab"]) str2 = lib.translate[str + "_ab"]; + if (!str2) return ""; + if (lib.translate[str + "_prefix"] && str2.startsWith(lib.translate[str + "_prefix"])) { + return str2.slice(lib.translate[str + "_prefix"].length); + } + return str2; + } + /** + * 作用修改:只读前缀 不读_ab + */ + static rawName2(str) { + let str2 = lib.translate[str]; + if (!str2) return ""; + if (lib.translate[str + "_prefix"] && str2.startsWith(lib.translate[str + "_prefix"])) { + return str2.slice(lib.translate[str + "_prefix"].length); + } + return str2; + } + static slimNameHorizontal(str) { + const slimName = lib.translate[`${str}_ab`] || lib.translate[str]; + if (!slimName) return ""; + const prefix = lib.translate[`${str}_prefix`]; + if (prefix && slimName.startsWith(prefix)) { + //兼容版特化处理 + if (lib.compatibleEdition) return `${get.prefixSpan(prefix, str)}${slimName.slice(prefix.length)} `; + return `${get.prefixSpan(prefix, str)}${slimName.slice(prefix.length)}`; + } + return slimName; + } + /** + * @param {string} prefix + * @param {string} name + * @returns {string} + */ + static prefixSpan(prefix, name) { + const config = lib.config.buttoncharacter_prefix; + if (config == "off") return ""; + if (config == "simple") { + const span = document.createElement("span"); + span.innerHTML = prefix; + return span.outerHTML; + } + const namePrefix = lib.namePrefix.get(prefix), exists = Boolean(namePrefix); + if (exists && "getSpan" in namePrefix) return namePrefix.getSpan(prefix, name); + const span = document.createElement("span"); + if (exists) { + if ("color" in namePrefix) span.style.color = namePrefix.color; + if ("nature" in namePrefix) span.dataset.nature = namePrefix.nature; + if ("showName" in namePrefix) prefix = namePrefix.showName; + } + else span.style.color = "#ffffff"; + span.innerHTML = prefix; + return span.outerHTML; + } + static slimName(str) { + return get.verticalStr(get.slimNameHorizontal(str), true); + } + static time() { + if (lib.status.dateDelaying) { + return lib.getUTC(lib.status.dateDelaying) - lib.getUTC(lib.status.date) - lib.status.dateDelayed; + } + else { + return lib.getUTC(new Date()) - lib.getUTC(lib.status.date) - lib.status.dateDelayed; + } + } + static utc() { + return new Date().getTime(); + } + static evtDistance(e1, e2) { + var dx = (e1.clientX - e2.clientX) / game.documentZoom; + var dy = (e1.clientY - e2.clientY) / game.documentZoom; + return Math.sqrt(dx * dx + dy * dy); + } + static xyDistance(from, to) { + return Math.sqrt((from[0] - to[0]) * (from[0] - to[0]) + (from[1] - to[1]) * (from[1] - to[1])); + } + static itemtype(obj) { + var i, j; + if (typeof obj == "string") { + if (obj.length <= 5) { + var bool = true; + for (i = 0; i < obj.length; i++) { + if (/h|e|j|s|x/.test(obj[i]) == false) { + bool = false; break; + } + } + if (bool) return "position"; + } + if (obj.includes(lib.natureSeparator) && obj.split(lib.natureSeparator).every(n => lib.nature.has(n))) return "natures"; + if (lib.nature.has(obj)) return "nature"; + } + if (Array.isArray(obj) && obj.length) { + var isPlayers = true; + for (i = 0; i < obj.length; i++) { + if (get.itemtype(obj[i]) != "player") { isPlayers = false; break; } + } + if (isPlayers) return "players"; + + var isCards = true; + for (i = 0; i < obj.length; i++) { + if (get.itemtype(obj[i]) != "card") { isCards = false; break; } + } + if (isCards) return "cards"; + + if (obj.length == 2) { + if (typeof obj[0] == "number" && typeof obj[1] == "number") { + if (obj[0] <= obj[1] || obj[1] <= -1) return "select"; + } + } + + if (obj.length == 4) { + var isPosition = true; + for (i = 0; i < obj.length; i++) { + if (typeof obj[i] != "number") { isPosition = false; break; } + } + if (isPosition) return "divposition"; + } + } + if (get.objtype(obj) == "div") { + if (obj.classList.contains("button")) return "button"; + if (obj.classList.contains("card")) return "card"; + if (obj.classList.contains("player")) return "player"; + if (obj.classList.contains("dialog")) return "dialog"; + } + if (get.is.object(obj)) { + if (obj.isMine == lib.element.GameEvent.prototype.isMine) return "event"; + } + } + static equipNum(card) { + if (get.type(card) == "equip") { + return parseInt(get.subtype(card)[5]); + } + return 0; + } + static objtype(obj) { + if (Object.prototype.toString.call(obj) === "[object Array]") return "array"; + if (Object.prototype.toString.call(obj) === "[object Object]") return "object"; + if (Object.prototype.toString.call(obj) === "[object HTMLDivElement]") return "div"; + if (Object.prototype.toString.call(obj) === "[object HTMLTableElement]") return "table"; + if (Object.prototype.toString.call(obj) === "[object HTMLTableRowElement]") return "tr"; + if (Object.prototype.toString.call(obj) === "[object HTMLTableCellElement]") return "td"; + if (Object.prototype.toString.call(obj) === "[object HTMLBodyElement]") return "td"; + } + static type(obj, method, player) { + if (typeof obj == "string") obj = { name: obj }; + if (typeof obj != "object") return; + var name = get.name(obj, player); + if (!lib.card[name]) { + if (!name.startsWith("sha_")) return; + if (name.slice(4).split("_").every(n => lib.nature.has(n))) return lib.card["sha"].type; + } + if (method == "trick" && lib.card[name].type == "delay") return "trick"; + return lib.card[name].type; + } + static type2(card, player) { + return get.type(card, "trick", player); + } + static subtype(obj, player) { + if (typeof obj == "string") obj = { name: obj }; + if (typeof obj != "object") return; + const name = get.name(obj, player); + if (!lib.card[name]) return; + let subtype = lib.card[name].subtype; + return subtype; + } + static equiptype(card, player) { + var subtype = get.subtype(card, player); + if (subtype.startsWith("equip")) return parseInt(subtype[5]); + return 0; + } + /** + * @param {Card | VCard} card + * @param {false | Player} [player] + * @returns {string} + */ + static name(card, player) { + if (get.itemtype(player) == "player" || (player !== false && get.position(card) == "h")) { + var owner = player || get.owner(card); + if (owner) { + return game.checkMod(card, owner, card.name, "cardname", owner); + } + } + return card.name; + } + /** + * @param {Card | VCard | Card[] | VCard[]} card + * @param {false | Player} [player] + * @returns {string} + */ + static suit(card, player) { + if (!card) return; + if (Array.isArray(card)) { + if (card.length == 1) return get.suit(card[0], player); + return "none"; + } + else if (!Object.prototype.hasOwnProperty.call(card, "suit") && Array.isArray(card.cards)) { + return get.suit(card.cards, player); + } + else { + if (player !== false) { + const owner = player || get.owner(card); + if (owner) { + return game.checkMod(card, owner, game.checkMod(card, card.suit, "suit", owner), "cardsuit", owner); + } + } + if (lib.suits.contains(card.suit)) return card.suit; + return "none"; + } + } + /** + * @param {Card | VCard | Card[] | VCard[]} card + * @param {false | Player} [player] + * @returns {string} + */ + static color(card, player) { + if (!card) return; + if (Array.isArray(card)) { + if (!card.length) return "none"; + const cards = card.slice(), color = get.color(cards.shift(), player); + for (const anotherCard of cards) { + if (get.color(anotherCard, player) != color) return "none"; + } + return color; + } + else if (Object.keys(lib.color).includes(card.color)) { + return card.color; + } + else if (Array.isArray(card.cards) && !lib.suit.includes(card.suit)) { + return get.color(card.cards, player); + } + else { + const suit = get.suit(card, player); + for (const entry of Object.entries(lib.color)) { + if (entry[1].includes(suit)) return entry[0]; + } + return "none"; + } + } + /** + * @param {Card | VCard} card + * @param {false | Player} [player] + * @returns {number} + */ + static number(card, player) { + if (!card) return; + //狗卡你是真敢出啊 + var number = null; + if (Object.prototype.hasOwnProperty.call(card, "number")) { + number = card.number; + if (typeof number != "number") number = null; + } + else { + if (card.cards && card.cards.length == 1) number = get.number(card.cards[0], false); + } + if (player !== false) { + var owner = player || get.owner(card); + if (owner) { + return game.checkMod(card, owner, number, "cardnumber", owner); + } + } + return number; + } + /** + * 返回一张杀的属性。如有多种属性则用`lib.natureSeparator`分割开来。例:火雷【杀】的返回值为`fire|thunder` + * @param {string | string[] | Card | VCard} card + * @param {false | Player} [player] + * @returns {string} + */ + static nature(card, player) { + if (typeof card == "string") return card.split(lib.natureSeparator).sort(lib.sort.nature).join(lib.natureSeparator); + if (Array.isArray(card)) return card.sort(lib.sort.nature).join(lib.natureSeparator); + var nature = card.nature; + if (get.itemtype(player) == "player" || player !== false) { + var owner = get.owner(card); + if (owner) { + return game.checkMod(card, owner, nature, "cardnature", owner); + } + } + return nature; + } + /** + * 返回包含所有属性的数组 + * @param {string[] | string} card + * @param {false | Player} [player] + * @returns {string[]} + */ + static natureList(card, player) { + if (!card) return []; + if (get.itemtype(card) == "natures") return card.split(lib.natureSeparator); + if (get.itemtype(card) == "nature") return [card]; + const natures = get.nature(card, player); + if (typeof natures != "string") return []; + return natures.split(lib.natureSeparator); + } + static cards(num, putBack) { + if (_status.waitingForCards) { + ui.create.cards.apply(ui.create, _status.waitingForCards); + delete _status.waitingForCards; + } + var list = []; + var card = false; + if (typeof num != "number") num = 1; + if (num == 0) { card = true; num = 1; } + if (num < 0) num = 1; + while (num--) { + if (ui.cardPile.hasChildNodes() == false) { + game.washCard(); + } + if (ui.cardPile.hasChildNodes() == false) { + game.over("平局"); + return []; + } + var cardx = ui.cardPile.removeChild(ui.cardPile.firstChild); + cardx.original = "c"; + list.push(cardx); + } + if (putBack) { + for (let i = list.length - 1; i >= 0; i--) { + ui.cardPile.insertBefore(list[i], ui.cardPile.firstChild); + } + } + game.updateRoundNumber(); + if (card) return list[0]; + return list; + } + static judge(card) { + return card.viewAs ? lib.card[card.viewAs].judge : get.info(card).judge; + } + static judge2(card) { + return card.viewAs ? lib.card[card.viewAs].judge2 : get.info(card).judge2; + } + static distance(from, to, method) { + if (from == to) return 0; + if (!game.players.contains(from) && !game.dead.contains(from)) return Infinity; + if (!game.players.contains(to) && !game.dead.contains(to)) return Infinity; + let n = 1; + if (game.chess) { + let fxy = from.getXY(), txy = to.getXY(); + n = Math.abs(fxy[0] - txy[0]) + Math.abs(fxy[1] - txy[1]); + if (method == "raw" || method == "pure" || method == "absolute") return n; + } + else if (to.isMin(true) || from.isMin(true)) { + if (method == "raw" || method == "pure" || method == "absolute") return n; + } + else { + let player = from, length = game.players.length; + const totalPopulation = game.players.length + game.dead.length + 1; + for (let iwhile = 0; iwhile < totalPopulation; iwhile++) { + if (player.nextSeat != to) { + player = player.nextSeat; + if (player.isAlive() && !player.isOut() && !player.hasSkill("undist") && !player.isMin(true)) n++; + } + else { + break; + } + } + for (let i = 0; i < game.players.length; i++) { + if (game.players[i].isOut() || game.players[i].hasSkill("undist") || game.players[i].isMin(true)) length--; + } + if (method == "absolute") return n; + if (from.isDead()) length++; + if (to.isDead()) length++; + const left = from.hasSkillTag("left_hand"), right = from.hasSkillTag("right_hand"); + if (left === right) n = Math.min(n, length - n); + else if (left == true) n = length - n; + if (method == "raw" || method == "pure") return n; + } + n = game.checkMod(from, to, n, "globalFrom", from); + n = game.checkMod(from, to, n, "globalTo", to); + const equips1 = from.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }), equips2 = to.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + for (let i = 0; i < equips1.length; i++) { + let info = get.info(equips1[i]).distance; + if (!info) continue; + if (info.globalFrom) { + n += info.globalFrom; + } + } + for (let i = 0; i < equips2.length; i++) { + let info = get.info(equips2[i]).distance; + if (!info) continue; + if (info.globalTo) { + n += info.globalTo; + } + if (info.attaclTo) { + m += info.attaclTo; + } + } + if (method == "attack") { + let m = n; + m = game.checkMod(from, to, m, "attackFrom", from); + m = game.checkMod(from, to, m, "attackTo", to); + return m; + // const attakRange=from.getEquipRange(); + // m+=(1-attakRange); + // for(let i=0;i !current.isOut()); + return players; + } + static position(card, ordering) { + if (get.itemtype(card) == "player") return parseInt(card.dataset.position); + if (card.timeout && card.destiny && card.destiny.classList) { + if (card.destiny.classList.contains("equips")) return "e"; + if (card.destiny.classList.contains("judges")) return "j"; + if (card.destiny.classList.contains("expansions")) return "x"; + if (card.destiny.classList.contains("handcards")) return card.classList.contains("glows") ? "s" : "h"; + if (card.destiny.id == "cardPile") return "c"; + if (card.destiny.id == "discardPile") return "d"; + if (card.destiny.id == "special") return "s"; + if (card.destiny.id == "ordering") return ordering ? "o" : "d"; + return null; + } + if (!card.parentNode || !card.parentNode.classList) return; + if (card.parentNode.classList.contains("equips")) return "e"; + if (card.parentNode.classList.contains("judges")) return "j"; + if (card.parentNode.classList.contains("expansions")) return "x"; + if (card.parentNode.classList.contains("handcards")) return card.classList.contains("glows") ? "s" : "h"; + if (card.parentNode.id == "cardPile") return "c"; + if (card.parentNode.id == "discardPile") return "d"; + if (card.parentNode.id == "special") return "s"; + if (card.parentNode.id == "ordering") return ordering ? "o" : "d"; + return null; + } + static skillTranslation(str, player) { + var str2; + if (str.startsWith("re")) { + str2 = str.slice(2); + if (str2) { + if (lib.translate[str] == lib.translate[str2]) { + if (player.hasSkill(str2)) { + return "界" + lib.translate[str]; + } + } + } + } + else if (str.startsWith("xin")) { + str2 = str.slice(3); + if (str2) { + if (lib.translate[str] == lib.translate[str2]) { + if (player.hasSkill(str2)) { + return "新" + lib.translate[str]; + } + } + } + } + return get.translation(str); + } + static skillInfoTranslation(name, player) { + if (player && lib.dynamicTranslate[name]) return lib.dynamicTranslate[name](player, name); + var str = lib.translate[name + "_info"]; + if (!str) return ""; + return str; + } + + /** + * @returns {string} + */ + static translation(str, arg) { + if (str && typeof str == "object" && (str.name || str._tempTranslate)) { + if (str._tempTranslate) return str._tempTranslate; + var str2; + if (arg == "viewAs" && str.viewAs) { + str2 = this.translation(str.viewAs); + } + else { + str2 = this.translation(str.name); + } + if (str2 == "杀") { + str2 = ""; + if (typeof str.nature == "string") { + let natures = str.nature.split(Library.natureSeparator).sort(Library.sort.nature); + for (let nature of natures) { + str2 += Library.translate["nature_" + nature] || Library.translate[nature] || ""; + } + } + str2 += "杀"; + } + if (this.itemtype(str) == "card" || str.isCard) { + if (status.cardtag && str.cardid) { + var tagstr = ""; + for (var i in status.cardtag) { + if (status.cardtag[i].contains(str.cardid)) { + tagstr += Library.translate[i + "_tag"]; + } + } + if (tagstr) { + str2 += "·" + tagstr; + } + } + if (str.suit && str.number || str.isCard) { + var cardnum = this.number(str, false) || ""; + if ([1, 11, 12, 13].contains(cardnum)) { + cardnum = { "1": "A", "11": "J", "12": "Q", "13": "K" }[cardnum] + } + if (arg == "viewAs" && str.viewAs != str.name && str.viewAs) { + str2 += "(" + this.translation(str) + ")"; + } + else { + str2 += "【" + this.translation(this.suit(str, false)) + cardnum + "】"; + } + } + } + return str2; + } + if (Array.isArray(str)) { + var str2 = this.translation(str[0], arg); + for (var i = 1; i < str.length; i++) { + str2 += "、" + this.translation(str[i], arg); + } + return str2; + } + if (this.itemtype(str) == "natures") { + let natures = str.split(Library.natureSeparator).sort(Library.sort.nature); + var str2 = ""; + for (var nature of natures) { + str2 += Library.translate["nature_" + nature] || Library.translate[nature] || ""; + } + return str2; + } + if (arg == "skill") { + if (Library.translate[str + "_ab"]) return Library.translate[str + "_ab"]; + if (Library.translate[str]) return Library.translate[str].slice(0, 2); + return str; + } + else if (arg == "info") { + if (Library.translate[str + "_info"]) return Library.translate[str + "_info"]; + var str2 = str.slice(0, str.length - 1); + if (Library.translate[str2 + "_info"]) return Library.translate[str2 + "_info"]; + if (str.lastIndexOf("_") > 0) { + str2 = str.slice(0, str.lastIndexOf("_")); + if (Library.translate[str2 + "_info"]) return Library.translate[str2 + "_info"]; + } + str2 = str.slice(0, str.length - 2); + if (Library.translate[str2 + "_info"]) return Library.translate[str2 + "_info"]; + if (Library.skill[str] && Library.skill[str].prompt) return Library.skill[str].prompt; + } + if (Library.translate[str]) { + return Library.translate[str]; + } + if (typeof str == "string") { + if (Library.translate["nature_" + str]) return Library.translate["nature_" + str]; + return str; + } + if (typeof str == "number" || typeof str == "boolean") { + return str.toString(); + } + if (str && str.toString) { + return str.toString(); + } + return ""; + } + static strNumber(num) { + switch (num) { + case 1: return "A"; + case 11: return "J"; + case 12: return "Q"; + case 13: return "K"; + default: return num.toString(); + } + } + static cnNumber(num, two) { + if (num == Infinity) return "∞"; + if (typeof num != "number" && typeof num != "string") return num; + if (isNaN(num)) return ""; + let numStr = num.toString(); + if (!/^\d+$/.test(numStr)) return num; + + const chars = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]; + const units = ["", "十", "百", "千"]; + + if (numStr.length <= 2) {//两位数以下单独处理保证效率 + if (numStr.length == 1) return !two && num == 2 ? "两" : chars[num]; + return (numStr[0] == "1" ? "" : chars[numStr[0]]) + "十" + (numStr[1] == "0" ? "" : chars[numStr[1]]); + } + + numStr = numStr.replace(/(?=(\d{4})+$)/g, ",").split(",").filter(Boolean); + const handleZero = str => str.replace(/零{2,}/g, "零").replace(/零+$/g, ""); + const _transform = str => { + if (str === "0000") return "零"; + if (!two && str === "2") return "两"; + let result = ""; + for (let i = 0; i < str.length; i++) { + let char = chars[+str[i]]; + const unitIndex = str.length - 1 - i; + let unit = units[unitIndex]; + if (!two && char === "二" && unitIndex > 1) char = "两"; + if (char === "零") unit = ""; + result += char + unit; + } + result = handleZero(result); + return result; + } + let result = ""; + for (let i = 0; i < numStr.length; i++) { + const part = numStr[i]; + let char = _transform(part); + const unitIndex = numStr.length - 1 - i; + let unit = unitIndex % 2 ? "万" : "亿".repeat(unitIndex / 2); + if (char === "零") unit = ""; + result += char + unit; + } + result = handleZero(result); + return result; + } + static selectableButtons(sort) { + if (!_status.event.player) return []; + var buttons = _status.event.dialog.buttons; + var selectable = []; + for (var i = 0; i < buttons.length; i++) { + if (buttons[i].classList.contains("selectable") && + buttons[i].classList.contains("selected") == false) { + selectable.push(buttons[i]); + } + } + if (sort) { + selectable.sort(sort); + } + return selectable; + } + static selectableCards(sort) { + if (!_status.event.player) return []; + var cards = _status.event.player.getCards("hes"); + var selectable = []; + for (var i = 0; i < cards.length; i++) { + if (cards[i].classList.contains("selectable") && + cards[i].classList.contains("selected") == false) { + selectable.push(cards[i]); + } + } + if (sort) { + selectable.sort(sort); + } + return selectable; + } + static skills() { + var skills = []; + if (ui.skills) { + skills = skills.concat(ui.skills.skills); + } + if (ui.skills2) { + skills = skills.concat(ui.skills2.skills); + } + if (ui.skills3) { + skills = skills.concat(ui.skills3.skills); + } + return skills; + } + static gainableSkills(func, player) { + var list = []; + for (var i in lib.character) { + if (lib.filter.characterDisabled(i)) continue; + if (lib.filter.characterDisabled2(i)) continue; + if (lib.character[i][4]) { + if (lib.character[i][4].contains("boss")) continue; + if (lib.character[i][4].contains("hiddenboss")) continue; + if (lib.character[i][4].contains("minskin")) continue; + if (lib.character[i][4].contains("unseen")) continue; + } + for (var j = 0; j < lib.character[i][3].length; j++) { + var skill = lib.character[i][3][j]; + var info = lib.skill[skill]; + if (lib.filter.skillDisabled(skill)) continue; + if (func && !func(info, skill, i)) continue; + if (player && player.hasSkill && info.ai && info.ai.combo && !player.hasSkill(info.ai.combo)) continue; + list.add(skill); + } + } + return list; + } + static gainableSkillsName(name, func) { + var list = []; + if (name && lib.character[name]) { + if (lib.character[name][4]) { + if (lib.character[name][4].contains("boss")) return list; + if (lib.character[name][4].contains("hiddenboss")) return list; + if (lib.character[name][4].contains("minskin")) return list; + if (lib.character[name][4].contains("unseen")) return list; + } + for (var j = 0; j < lib.character[name][3].length; j++) { + var skill = lib.character[name][3][j]; + var info = lib.skill[skill]; + if (lib.filter.skillDisabled(skill)) continue; + if (func && !func(info, skill, name)) continue; + list.add(skill); + } + } + return list; + } + static gainableCharacters(func) { + var list = []; + for (var i in lib.character) { + var info = lib.character[i]; + if (!info) continue; + if (typeof func == "function" && !func(info, i)) continue; + if (lib.filter.characterDisabled(i)) continue; + if (lib.filter.characterDisabled2(i)) continue; + list.push(i); + } + if (func === true) { + var players = game.players.concat(game.dead); + for (var i = 0; i < players.length; i++) { + list.remove(players[i].name); + list.remove(players[i].name1); + list.remove(players[i].name2); + } + } + return list; + } + static selectableTargets(sort) { + var selectable = []; + var players = game.players.slice(0); + if (_status.event.deadTarget) players.addArray(game.dead); + for (var i = 0; i < players.length; i++) { + if (players[i].classList.contains("selectable") && + players[i].classList.contains("selected") == false) { + selectable.push(players[i]); + } + } + selectable.randomSort(); + if (sort) { + selectable.sort(sort); + } + return selectable; + } + static filter(filter, i) { + if (typeof filter == "function") return filter; + if (i == undefined) i = 0; + var result = function () { + if (filter == arguments[i]) return true; + for (var j in filter) { + if (Object.prototype.hasOwnProperty.call(filter, j)) { + if (get.itemtype(arguments[i]) == "card") { + if (j == "name") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.name(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.name(arguments[i]) != filter[j]) return false; + } + } + else if (j == "type") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.type(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.type(arguments[i]) != filter[j]) return false; + } + } + else if (j == "subtype") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.subtype(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.subtype(arguments[i]) != filter[j]) return false; + } + } + else if (j == "color") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.color(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.color(arguments[i]) != filter[j]) return false; + } + } + else if (j == "suit") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.suit(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.suit(arguments[i]) != filter[j]) return false; + } + } + else if (j == "number") { + if (Array.isArray(filter[j])) { + if (filter[j].contains(get.number(arguments[i])) == false) return false; + } + else if (typeof filter[j] == "string") { + if (get.number(arguments[i]) != filter[j]) return false; + } + } + else if (Array.isArray(filter[j])) { + if (filter[j].contains(arguments[i][j]) == false) return false; + } + else if (typeof filter[j] == "string") { + if (arguments[i][j] != filter[j]) return false; + } + } + else { + if (arguments[i][j] != filter[j]) return false; + } + } + } + return true; + } + result._filter_args = [filter, i]; + return result; + } + static cardCount(card, player) { + var num; + if (player == undefined) player = _status.event.player; + if (card == true) { + num = 0; + var stat = player.getStat("card"); + for (var i in stat) { + if (typeof stat[i] == "number") num += stat[i]; + } + return num; + } + if (typeof card == "object") { + card = card.name; + } + num = player.getStat("card")[card]; + if (num == undefined) return 0; + return num; + } + static skillCount(skill, player) { + if (player == undefined) player = _status.event.player; + var num = player.getStat("skill")[skill]; + if (num == undefined) return 0; + return num; + } + static owner(card, method) { + return game.players.concat(game.dead).find(current => current.getCards("hejsx").includes(card) || (current.judging[0] == card && method != "judge")); + } + static noSelected() { + return ui.selected.buttons.length + ui.selected.cards.length + ui.selected.targets.length == 0; + } + static population(identity) { + return identity == undefined ? game.players.length + game.dead.length : game.players.filter(current => current.identity == identity).length; + } + static totalPopulation(identity) { + return identity == undefined ? game.players.length + game.dead.length : game.players.concat(game.dead).filter(current => current.identity == identity).length; + } + static cardtag(item, tag) { + return (item.cardid && (get.itemtype(item) == "card" || !item.cards || !item.cards.length || item.name == item.cards[0].name) && _status.cardtag && _status.cardtag[tag] && _status.cardtag[tag].contains(item.cardid)) || (item.cardtags && item.cardtags.contains(tag)); + } + static tag(item, tag, item2, bool) { + var result; + if (get.info(item, bool) && get.info(item, bool).ai && get.info(item, bool).ai.tag) { + result = get.info(item, bool).ai.tag[tag]; + } + if (typeof result == "function") return result(item, item2); + return result; + } + static sortCard(sort) { + var func; + if (sort == "type_sort") { + func = function (card) { + var type = get.type(card, null, false); + var subtype = get.subtype(card, false); + if (lib.cardType[subtype]) { + return lib.cardType[subtype]; + } + if (lib.cardType[type]) { + return lib.cardType[type]; + } + switch (type) { + case "basic": return 2; + case "chess": return 1.5; + case "trick": return -1; + case "delay": return -2; + case "equip": return -3; + default: return -4; + } + } + } + else if (sort == "suit_sort") { + func = function (card) { + if (get.suit(card) == "heart") return 2; + if (get.suit(card) == "diamond") return 1; + if (get.suit(card) == "spade") return -1; + if (get.suit(card) == "club") return -2; + } + } + else if (sort == "number_sort") { + func = function (card) { + return get.number(card) - 7 + 0.5; + } + } + return func; + } + static difficulty() { + switch (get.config("difficulty")) { + case "easy": return 1; + case "normal": return 2; + case "hard": return 3; + default: return 1; + } + } + static cardPile(name, create) { + var filter = function (card) { + if (typeof name == "string") { + if (card.name == name) { + return true; + } + } + else if (typeof name == "function") { + if (name(card)) { + return true; + } + } + return false; + }; + if (create != "discardPile") { + var num = get.rand(0, ui.cardPile.childNodes.length - 1); + for (var i = 0; i < ui.cardPile.childNodes.length; i++) { + var j = i; + if (j >= ui.cardPile.childNodes.length) j -= ui.cardPile.childNodes.length; + if (filter(ui.cardPile.childNodes[j])) { + return ui.cardPile.childNodes[j]; + } + } + } + if (create != "cardPile") { + for (var i = 0; i < ui.discardPile.childNodes.length; i++) { + var j = i; + if (j >= ui.discardPile.childNodes.length) j -= ui.discardPile.childNodes.length; + if (filter(ui.discardPile.childNodes[j])) { + return ui.discardPile.childNodes[j]; + } + } + } + if (create == "field") { + var found = null; + game.findPlayer(function (current) { + var ej = current.getCards("ej"); + for (var i = 0; i < ej.length; i++) { + if (filter(ej[i])) { + found = ej[i]; + return true; + } + } + }); + return found; + } + if (create && !["cardPile", "discardPile", "field"].contains(create)) { + return game.createCard(name); + } + return null; + } + static cardPile2(name) { + return get.cardPile(name, "cardPile"); + } + static discardPile(name) { + return get.cardPile(name, "discardPile"); + } + static aiStrategy() { + switch (get.config("ai_strategy")) { + case "ai_strategy_1": return 1; + case "ai_strategy_2": return 2; + case "ai_strategy_3": return 3; + case "ai_strategy_4": return 4; + case "ai_strategy_5": return 5; + case "ai_strategy_6": return 6; + default: return 1; + } + } + static skillintro(name, learn, learn2) { + var str = ""; + var infoitem = lib.character[name]; + if (!infoitem) { + for (var itemx in lib.characterPack) { + if (lib.characterPack[itemx][name]) { + infoitem = lib.characterPack[itemx][name]; break; + } + } + } + var skills = infoitem[3]; + var opacity; + for (var i = 0; i < skills.length; i++) { + if (lib.translate[skills[i]] && lib.translate[skills[i] + "_info"] && lib.skill[skills[i]]) { + if (learn && lib.skill[skills[i]].unique && (learn2 || !lib.skill[skills[i]].gainable)) { + opacity = "opacity:0.5"; + } + else { + opacity = ""; + } + var skilltrans = get.translation(skills[i]).slice(0, 2); + str += `
【${skilltrans}】
${get.skillInfoTranslation(skills[i])}
`; + } + } + return str; + } + static intro(name) { + var info = lib.character[name]; + var str = "性别:" + get.translation(info[0]) + "
"; + str += "势力:" + get.translation(info[1]) + "
"; + str += "体力:" + get.translation(info[2]) + "
"; + str += "技能:"; + if (info[3].length) { + str += get.translation(info[3][0]); + for (var i = 1; i < info[3].length; i++) { + str += "、" + get.translation(info[3][i]); + } + } + return str; + } + static storageintro(type, content, player, dialog, skill) { + switch (type) { + case "mark": { + if (content > 0) { + return "共有" + content + "个标记"; + } + return false; + } + case "turn": { + if (content > 0) { + return "剩余" + content + "个回合"; + } + return false; + } + case "time": { + if (content > 0) { + return "剩余" + content + "次"; + } + return false; + } + case "limited": { + if (content) { + return "已发动"; + } + return "未发动"; + } + case "info": { + return lib.translate[skill + "_info"]; + } + case "cardCount": { + if (Array.isArray(content)) { + return "共有" + get.cnNumber(content.length) + "张牌"; + } + return false; + } + case "expansion": { + content = player.getCards("x", function (card) { + return card.hasGaintag(skill); + }); + if (dialog && content.length) { + dialog.addAuto(content); + } + else { + return "没有卡牌"; + } + return false; + } + case "card": case "cards": { + if (get.itemtype(content) == "card") { + content = [content]; + } + if (dialog && get.itemtype(content) == "cards") { + dialog.addAuto(content); + } + else { + if (content && content.length) { + return get.translation(content); + } + } + if (Array.isArray(content) && !content.length) { + return "没有卡牌"; + } + return false; + } + case "player": case "players": { + if (get.itemtype(content) == "player") { + content = [content]; + } + if (dialog && get.itemtype(content) == "players") { + dialog.addAuto(content); + return false; + } + else { + if (content && content.length) { + return get.translation(content); + } + return false; + } + } + case "character": case "characters": { + if (typeof content == "string") { + content = [content]; + } + if (dialog && Array.isArray(content)) { + dialog.addAuto([content, "character"]); + return false; + } + else { + if (content && content.length) { + return get.translation(content); + } + return false; + } + } + default: { + if (typeof type == "string") { + type = type.replace(/#/g, content); + type = type.replace(/&/g, get.cnNumber(content)); + type = type.replace(/\$/g, get.translation(content)); + return type; + } + else if (typeof type == "function") { + return type(content, player, skill); + } + return false; + } + } + } + static nodeintro(node, simple, evt) { + var uiintro = ui.create.dialog("hidden", "notouchscroll"); + if (node.classList.contains("player") && !node.name) { + return uiintro; + } + var i, translation, intro, str; + if (node._nointro) return; + if (typeof node._customintro == "function") { + if (node._customintro(uiintro, evt) === false) return; + if (evt) lib.placePoppedDialog(uiintro, evt); + } + else if (Array.isArray(node._customintro)) { + var caption = node._customintro[0]; + var content = node._customintro[1]; + if (typeof caption == "function") { + caption = caption(node); + } + if (typeof content == "function") { + content = content(node); + } + uiintro.add(caption); + uiintro.add(`
${content}
`); + } + else if (node.classList.contains("player") || node.linkplayer) { + if (node.linkplayer) { + node = node.link; + } + let capt = get.translation(node.name); + const characterInfo = get.character(node.name), sex = node.sex || characterInfo[0]; + if (sex && sex != "unknown" && lib.config.show_sex) capt += `  ${sex == "none" ? "无" : get.translation(sex)}`; + const group = node.group; + if (group && group != "unknown" && lib.config.show_group) capt += `  ${get.translation(group)}`; + uiintro.add(capt); + + if (lib.characterTitle[node.name]) { + uiintro.addText(get.colorspan(lib.characterTitle[node.name])); + } + + if (!node.noclick) { + const allShown = (node.isUnderControl() || (!game.observe && game.me && game.me.hasSkillTag("viewHandcard", null, node, true))); + const shownHs = node.getShownCards(); + if (shownHs.length) { + uiintro.add(`
明置的手牌
`); + uiintro.addSmall(shownHs); + if (allShown) { + var hs = node.getCards("h"); + hs.removeArray(shownHs) + if (hs.length) { + uiintro.add(`
其他手牌
`); + uiintro.addSmall(hs); + } + } + } + else if (allShown) { + var hs = node.getCards("h"); + if (hs.length) { + uiintro.add(`
手牌
`); + uiintro.addSmall(hs); + } + } + } + + var skills = node.getSkills(null, false, false).slice(0); + var skills2 = game.filterSkills(skills, node); + if (node == game.me && node.hiddenSkills.length) { + skills.addArray(node.hiddenSkills); + } + for (var i in node.disabledSkills) { + if (node.disabledSkills[i].length == 1 && + node.disabledSkills[i][0] == i + "_awake" && + !node.hiddenSkills.contains(i)) { + skills.add(i); + } + } + for (i = 0; i < skills.length; i++) { + if (lib.skill[skills[i]] && (lib.skill[skills[i]].nopop || lib.skill[skills[i]].equipSkill)) continue; + if (lib.translate[skills[i] + "_info"]) { + if (lib.translate[skills[i] + "_ab"]) translation = lib.translate[skills[i] + "_ab"]; + else { + translation = get.translation(skills[i]); + if (!lib.skill[skills[i]].nobracket) translation = translation.slice(0, 2); + } + + if (node.forbiddenSkills[skills[i]]) { + var forbidstr = `
【${translation}】
`; + if (node.forbiddenSkills[skills[i]].length) { + forbidstr += "(与" + get.translation(node.forbiddenSkills[skills[i]]) + "冲突)
"; + } + else { + forbidstr += "(双将禁用)
"; + } + forbidstr += get.skillInfoTranslation(skills[i], node) + "
" + uiintro.add(forbidstr); + } + else if (!skills2.contains(skills[i])) { + if (lib.skill[skills[i]].preHidden && get.mode() == "guozhan") { + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
预亮技能
`); + var underlinenode = uiintro.content.lastChild.querySelector(".underlinenode"); + if (_status.prehidden_skills.contains(skills[i])) { + underlinenode.classList.remove("on"); + } + underlinenode.link = skills[i]; + underlinenode.listen(ui.click.hiddenskill); + } + else uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
`); + } + else if (lib.skill[skills[i]].temp || !node.skills.contains(skills[i]) || lib.skill[skills[i]].thundertext) { + if (lib.skill[skills[i]].frequent || lib.skill[skills[i]].subfrequent) { + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
自动发动
`); + var underlinenode = uiintro.content.lastChild.querySelector(".underlinenode"); + if (lib.skill[skills[i]].frequent) { + if (lib.config.autoskilllist.contains(skills[i])) { + underlinenode.classList.remove("on"); + } + } + if (lib.skill[skills[i]].subfrequent) { + for (var j = 0; j < lib.skill[skills[i]].subfrequent.length; j++) { + if (lib.config.autoskilllist.contains(skills[i] + "_" + lib.skill[skills[i]].subfrequent[j])) { + underlinenode.classList.remove("on"); + } + } + } + if (lib.config.autoskilllist.contains(skills[i])) { + underlinenode.classList.remove("on"); + } + underlinenode.link = skills[i]; + underlinenode.listen(ui.click.autoskill2); + } + else { + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
`); + } + } + else if (lib.skill[skills[i]].frequent || lib.skill[skills[i]].subfrequent) { + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
自动发动
`); + var underlinenode = uiintro.content.lastChild.querySelector(".underlinenode"); + if (lib.skill[skills[i]].frequent) { + if (lib.config.autoskilllist.contains(skills[i])) { + underlinenode.classList.remove("on"); + } + } + if (lib.skill[skills[i]].subfrequent) { + for (var j = 0; j < lib.skill[skills[i]].subfrequent.length; j++) { + if (lib.config.autoskilllist.contains(skills[i] + "_" + lib.skill[skills[i]].subfrequent[j])) { + underlinenode.classList.remove("on"); + } + } + } + if (lib.config.autoskilllist.contains(skills[i])) { + underlinenode.classList.remove("on"); + } + underlinenode.link = skills[i]; + underlinenode.listen(ui.click.autoskill2); + } + else if (lib.skill[skills[i]].clickable && node.isIn() && node.isUnderControl(true)) { + var intronode = uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
`).querySelector(".skillbutton"); + if (!_status.gameStarted || (lib.skill[skills[i]].clickableFilter && !lib.skill[skills[i]].clickableFilter(node))) { + intronode.classList.add("disabled"); + intronode.style.opacity = 0.5; + } + else { + intronode.link = node; + intronode.func = lib.skill[skills[i]].clickable; + intronode.classList.add("pointerdiv"); + intronode.listen(ui.click.skillbutton); + } + } + else { + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i], node)}
`); + } + if (lib.translate[skills[i] + "_append"]) { + uiintro._place_text = uiintro.add(`
${lib.translate[`${skills[i]}_append`]}
`) + } + } + } + // if(get.is.phoneLayout()){ + // var storage=node.storage; + // for(i in storage){ + // if(get.info(i)&&get.info(i).intro){ + // intro=get.info(i).intro; + // if(node.getSkills().concat(lib.skill.global).contains(i)==false&&!intro.show) continue; + // var name=intro.name?intro.name:get.translation(i); + // if(typeof name=="function"){ + // name=name(storage[i],node); + // } + // translation="
『"+name.slice(0,2)+"』
"; + // var stint=get.storageintro(intro.content,storage[i],node,null,i); + // if(stint){ + // translation+=stint+"
"; + // uiintro.add(translation); + // } + // } + // } + // } + + if (lib.config.right_range && _status.gameStarted) { + uiintro.add(ui.create.div(".placeholder")); + var table, tr, td; + table = document.createElement("table"); + tr = document.createElement("tr"); + table.appendChild(tr); + td = document.createElement("td"); + td.innerHTML = "距离"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "手牌"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "行动"; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = "伤害"; + tr.appendChild(td); + + tr = document.createElement("tr"); + table.appendChild(tr); + td = document.createElement("td"); + if (node == game.me || !game.me || !game.me.isIn()) { + td.innerHTML = "-"; + } + else { + var dist1 = get.numStr(Math.max(1, game.me.distanceTo(node))); + var dist2 = get.numStr(Math.max(1, node.distanceTo(game.me))); + if (dist1 == dist2) { + td.innerHTML = dist1; + } + else { + td.innerHTML = dist1 + "/" + dist2; + } + } + tr.appendChild(td); + td = document.createElement("td"); + let handcardLimit = node.getHandcardLimit(); + td.innerHTML = `${node.countCards("h")}/${handcardLimit >= 114514 ? "∞" : handcardLimit}`; + tr.appendChild(td); + td = document.createElement("td"); + td.innerHTML = node.phaseNumber; + tr.appendChild(td); + td = document.createElement("td"); + + (function () { + num = 0; + for (var j = 0; j < node.stat.length; j++) { + if (typeof node.stat[j].damage == "number") num += node.stat[j].damage; + } + td.innerHTML = num; + }()); + tr.appendChild(td); + table.style.width = "calc(100% - 20px)"; + table.style.marginLeft = "10px"; + + uiintro.content.appendChild(table); + if (!lib.config.show_favourite) { + table.style.paddingBottom = "5px" + } + } + if (!simple || get.is.phoneLayout()) { + var es = node.getCards("e"); + for (var i = 0; i < es.length; i++) { + var cardinfo = lib.card[es[i].name]; + if (cardinfo && cardinfo.cardPrompt) uiintro.add(`
${es[i].outerHTML}
${cardinfo.cardPrompt(es[i])}
`); + else uiintro.add(`
${es[i].outerHTML}
${lib.translate[`${es[i].name}_info`]}
`); + uiintro.content.lastChild.querySelector(".skill>.card").style.transform = ""; + + if (lib.translate[es[i].name + "_append"]) { + uiintro.add(`
${lib.translate[`${es[i].name}_append`]}
`); + } + } + var js = node.getCards("j"); + for (var i = 0; i < js.length; i++) { + if (js[i].viewAs && js[i].viewAs != js[i].name) { + uiintro.add(`
${js[i].outerHTML}
${lib.translate[js[i].viewAs]}:${lib.translate[`${js[i].viewAs}_info`]}
`); + } + else { + uiintro.add(`
${js[i].outerHTML}
${lib.translate[`${js[i].name}_info`]}
`); + } + uiintro.content.lastChild.querySelector(".skill>.card").style.transform = ""; + } + if (get.is.phoneLayout()) { + var markCoutainer = ui.create.div(".mark-container.marks"); + for (var i in node.marks) { + var nodemark = node.marks[i].cloneNode(true); + nodemark.classList.add("pointerdiv"); + nodemark.link = node.marks[i]; + nodemark.style.transform = ""; + markCoutainer.appendChild(nodemark); + nodemark.listen(function () { + uiintro.noresume = true; + var rect = this.link.getBoundingClientRect(); + ui.click.intro.call(this.link, { + clientX: rect.left + rect.width, + clientY: rect.top + rect.height / 2, + }); + if (lib.config.touchscreen) { + uiintro._close(); + } + }); + } + if (markCoutainer.childElementCount) { + uiintro.addText("标记"); + uiintro.add(markCoutainer); + } + } + } + if (!game.observe && _status.gameStarted && game.me && node != game.me) { + ui.throwEmotion = []; + uiintro.addText("发送交互表情"); + var click = function () { + if (_status.dragged) return; + if (_status.justdragged) return; + if (_status.throwEmotionWait) return; + var emotion = this.link; + if (game.online) { + game.send("throwEmotion", node, emotion); + } + else game.me.throwEmotion(node, emotion); + uiintro._close(); + _status.throwEmotionWait = true; + setTimeout(function () { + _status.throwEmotionWait = false; + if (ui.throwEmotion) { + for (var i of ui.throwEmotion) i.classList.remove("exclude"); + } + }, (emotion == "flower" || emotion == "egg") ? 500 : 5000) + }; + var td; + var table = document.createElement("div"); + table.classList.add("add-setting"); + table.style.margin = "0"; + table.style.width = "100%"; + table.style.position = "relative"; + var listi = ["flower", "egg"]; + for (var i = 0; i < listi.length; i++) { + td = ui.create.div(".menubutton.reduce_radius.pointerdiv.tdnode"); + ui.throwEmotion.add(td); + if (_status.throwEmotionWait) td.classList.add("exclude"); + td.link = listi[i]; + table.appendChild(td); + td.innerHTML = "" + get.translation(listi[i]) + ""; + td.addEventListener(lib.config.touchscreen ? "touchend" : "click", click); + } + uiintro.content.appendChild(table); + table = document.createElement("div"); + table.classList.add("add-setting"); + table.style.margin = "0"; + table.style.width = "100%"; + table.style.position = "relative"; + var listi = ["wine", "shoe"]; + if (game.me.storage.zhuSkill_shanli) listi = ["yuxisx", "jiasuo"]; + for (var i = 0; i < listi.length; i++) { + td = ui.create.div(".menubutton.reduce_radius.pointerdiv.tdnode"); + ui.throwEmotion.add(td); + if (_status.throwEmotionWait) td.classList.add("exclude"); + td.link = listi[i]; + table.appendChild(td); + td.innerHTML = "" + get.translation(listi[i]) + ""; + td.addEventListener(lib.config.touchscreen ? "touchend" : "click", click); + } + uiintro.content.appendChild(table); + } + var modepack = lib.characterPack["mode_" + get.mode()]; + if (lib.config.show_favourite && lib.character[node.name] && game.players.contains(node) && + (!modepack || !modepack[node.name]) && (!simple || get.is.phoneLayout())) { + var addFavourite = ui.create.div(".text.center.pointerdiv"); + addFavourite.link = node.name; + if (lib.config.favouriteCharacter.contains(node.name)) { + addFavourite.innerHTML = "移除收藏"; + } + else { + addFavourite.innerHTML = "添加收藏"; + } + addFavourite.listen(ui.click.favouriteCharacter) + uiintro.add(addFavourite); + } + if (!simple || get.is.phoneLayout()) { + if ((lib.config.change_skin || lib.skin) && !node.isUnseen()) { + var num = 1; + var introadded = false; + var createButtons = function (num, avatar2) { + if (!introadded) { + introadded = true; + uiintro.add(`
更改皮肤
`); + } + var buttons = ui.create.div(".buttons.smallzoom.scrollbuttons"); + lib.setMousewheel(buttons); + var nameskin = (avatar2 ? node.name2 : node.name1); + var nameskin2 = nameskin; + var gzbool = false; + if (nameskin.startsWith("gz_shibing")) { + nameskin = nameskin.slice(3, 11); + } + else if (nameskin.startsWith("gz_")) { + nameskin = nameskin.slice(3); + gzbool = true; + } + for (var i = 0; i <= num; i++) { + var button = ui.create.div(".button.character.pointerdiv", buttons, function () { + if (this._link) { + if (avatar2) { + lib.config.skin[nameskin] = this._link; + node.node.avatar2.style.backgroundImage = this.style.backgroundImage; + } + else { + lib.config.skin[nameskin] = this._link; + node.node.avatar.style.backgroundImage = this.style.backgroundImage; + } + } + else { + delete lib.config.skin[nameskin]; + if (avatar2) { + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) node.node.avatar2.setBackground(nameskin2, "character"); + else node.node.avatar2.setBackground(nameskin, "character"); + } + else { + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) node.node.avatar.setBackground(nameskin2, "character"); + else node.node.avatar.setBackground(nameskin, "character"); + } + } + game.saveConfig("skin", lib.config.skin); + }); + button._link = i; + if (i) { + button.setBackgroundImage("image/skin/" + nameskin + "/" + i + ".jpg"); + } + else { + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) button.setBackground(nameskin2, "character", "noskin"); + else button.setBackground(nameskin, "character", "noskin"); + } + } + uiintro.add(buttons); + }; + var loadImage = function (avatar2) { + var img = new Image(); + img.onload = function () { + num++; + loadImage(avatar2); + } + img.onerror = function () { + num--; + if (num) { + createButtons(num, avatar2); + } + if (!avatar2) { + if (!node.classList.contains("unseen2") && node.name2) { + num = 1; + loadImage(true); + } + } + } + var nameskin = (avatar2 ? node.name2 : node.name1); + var nameskin2 = nameskin; + var gzbool = false; + if (nameskin.startsWith("gz_shibing")) { + nameskin = nameskin.slice(3, 11); + } + else if (nameskin.startsWith("gz_")) { + nameskin = nameskin.slice(3); + gzbool = true; + } + img.src = lib.assetURL + "image/skin/" + nameskin + "/" + num + ".jpg"; + } + if (lib.config.change_skin) { + if (!node.isUnseen(0)) { + loadImage(); + } + else if (node.name2) { + loadImage(true); + } + } + else { + setTimeout(function () { + var nameskin1 = node.name1; + var nameskin2 = node.name2; + if (nameskin1 && nameskin1.startsWith("gz_")) { + nameskin1 = nameskin1.slice(3); + } + if (nameskin2 && nameskin2.startsWith("gz_")) { + nameskin2 = nameskin2.slice(3); + } + if (!node.isUnseen(0) && lib.skin[nameskin1]) { + createButtons(lib.skin[nameskin1]); + } + if (!node.isUnseen(1) && lib.skin[nameskin2]) { + createButtons(lib.skin[nameskin2], true); + } + }); + } + } + } + + uiintro.add(ui.create.div(".placeholder.slim")); + } + else if (node.classList.contains("mark") && node.info && + node.parentNode && node.parentNode.parentNode && node.parentNode.parentNode.classList.contains("player")) { + var info = node.info; + var player = node.parentNode.parentNode; + if (info.name) { + if (typeof info.name == "function") { + var named = info.name(player.storage[node.skill], player); + if (named) { + uiintro.add(named); + } + } + else { + uiintro.add(info.name); + } + } + else if (info.name !== false) { + uiintro.add(get.translation(node.skill)); + } + if (typeof info.id == "string" && info.id.startsWith("subplayer") && + player.isUnderControl(true) && player.storage[info.id] && !_status.video) { + var storage = player.storage[info.id]; + uiintro.addText("当前体力:" + storage.hp + "/" + storage.maxHp); + if (storage.hs.length) { + uiintro.addText("手牌区"); + uiintro.addSmall(storage.hs); + } + if (storage.es.length) { + uiintro.addText("装备区"); + uiintro.addSmall(storage.es); + } + } + if (typeof info.mark == "function") { + var stint = info.mark(uiintro, player.storage[node.skill], player); + if (stint) { + var placetext = uiintro.add(`
${stint}
`); + if (!stint.startsWith(`
"+stint+"
"); + // } + // else{ + // uiintro.add("
"+stint+"
"); + // } + } + } + else { + var stint = get.storageintro(info.content, player.storage[node.skill], player, uiintro, node.skill); + if (stint) { + if (stint[0] == "@") { + uiintro.add(`
${stint.slice(1)}
`); + } + else { + var placetext = uiintro.add(`
${stint}
`); + if (!stint.startsWith(`
"+stint+"
"); + // } + // else{ + // uiintro.add("
"+stint+"
"); + // } + } + } + uiintro.add(ui.create.div(".placeholder.slim")); + } + else if (node.classList.contains("card")) { + //卡牌长按介绍 + if (ui.arena.classList.contains("observe") && node.parentNode.classList.contains("handcards")) { + return; + } + var name = node.name; + if (node.parentNode.cardMod) { + var moded = false; + for (var i in node.parentNode.cardMod) { + var item = node.parentNode.cardMod[i](node); + if (Array.isArray(item)) { + moded = true; + uiintro.add(item[0]); + uiintro._place_text = uiintro.add(`
${item[1]}
`); + } + } + if (moded) return uiintro; + } + if (node.link && node.link.name && lib.card[node.link.name]) { + name = node.link.name; + } + if (get.position(node) == "j" && node.viewAs && node.viewAs != name) { + uiintro.add(get.translation(node.viewAs)); + uiintro.add(`
(${get.translation(get.translation(node))})
`); + uiintro.nosub = true; + name = node.viewAs; + } + else { + uiintro.add(get.translation(node)); + } + if (node._banning) { + var clickBanned = function () { + var banned = lib.config[this.bannedname] || []; + if (banned.contains(name)) { + banned.remove(name); + } + else { + banned.push(name); + } + game.saveConfig(this.bannedname, banned); + this.classList.toggle("on"); + if (node.updateBanned) { + node.updateBanned(); + } + }; + var modeorder = lib.config.modeorder || []; + for (var i in lib.mode) { + modeorder.add(i); + } + var list = []; + uiintro.contentContainer.listen(function (e) { + ui.click.touchpop(); + e.stopPropagation(); + }); + for (var i = 0; i < modeorder.length; i++) { + if (node._banning == "online") { + if (!lib.mode[modeorder[i]].connect) continue; + } + else if (modeorder[i] == "connect" || modeorder[i] == "brawl") { + continue; + } + if (lib.config.all.mode.contains(modeorder[i])) { + list.push(modeorder[i]); + } + } + if (lib.card[name] && lib.card[name].type == "trick") list.push("zhinang_tricks"); + var page = ui.create.div(".menu-buttons.configpopped", uiintro.content); + var banall = false; + for (var i = 0; i < list.length; i++) { + var cfg = ui.create.div(".config", list[i] == "zhinang_tricks" ? "设为智囊" : (lib.translate[list[i]] + "模式"), page); + cfg.classList.add("toggle"); + if (list[i] == "zhinang_tricks") { + cfg.bannedname = ((node._banning == "offline") ? "" : "connect_") + "zhinang_tricks"; + } + else if (node._banning == "offline") { + cfg.bannedname = list[i] + "_bannedcards"; + } + else { + cfg.bannedname = "connect_" + list[i] + "_bannedcards"; + } + cfg.listen(clickBanned); + ui.create.div(ui.create.div(cfg)); + var banned = lib.config[cfg.bannedname] || []; + if (banned.contains(name) == (list[i] == "zhinang_tricks")) { + cfg.classList.add("on"); + banall = true; + } + } + ui.create.div(".menubutton.pointerdiv", banall ? "全部禁用" : "全部启用", uiintro.content, function () { + if (this.innerHTML == "全部禁用") { + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].bannedname.indexOf("zhinang_tricks") == -1 && page.childNodes[i].bannedname && page.childNodes[i].classList.contains("on")) { + clickBanned.call(page.childNodes[i]); + } + } + this.innerHTML = "全部启用"; + } + else { + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].bannedname.indexOf("zhinang_tricks") == -1 && page.childNodes[i].bannedname && !page.childNodes[i].classList.contains("on")) { + clickBanned.call(page.childNodes[i]); + } + } + this.innerHTML = "全部禁用"; + } + }).style.marginTop = "-10px"; + ui.create.div(".placeholder.slim", uiintro.content); + } + else { + if (lib.translate[name + "_info"]) { + if (!uiintro.nosub) { + if (lib.card[name] && lib.card[name].derivation) { + if (typeof lib.card[name].derivation == "string") { + uiintro.add(`
来源:${get.translation(lib.card[name].derivation)}
`); + } + else if (lib.card[name].derivationpack) { + uiintro.add(`
来源:${get.translation(`${lib.card[name].derivationpack}_card_config`)}包
`); + } + } + let typeinfo = ""; + if (lib.card[name].unique) { + typeinfo += ("特殊" + get.translation(lib.card[name].type) + "牌"); + } + else if (lib.card[name].type && lib.translate[lib.card[name].type]) { + typeinfo += (get.translation(lib.card[name].type) + "牌"); + } + if (get.subtype(name, false)) { + typeinfo += ("-" + get.translation(get.subtype(name, false))); + } + if (typeinfo) { + uiintro.add(`
${typeinfo}
`); + } + if (lib.card[name].unique && lib.card[name].type == "equip") { + if (lib.cardPile.guozhan && lib.cardPack.guozhan.contains(name)) { + uiintro.add(`
专属装备
`).style.marginTop = "-5px"; + } + else { + uiintro.add(`
特殊装备
`).style.marginTop = "-5px"; + } + } + if (lib.card[name] && lib.card[name].addinfomenu) { + uiintro.add(`
${lib.card[name].addinfomenu}
`); + } + if (get.subtype(name, false) == "equip1") { + var added = false; + if (lib.card[node.name] && lib.card[node.name].distance) { + var dist = lib.card[node.name].distance; + if (dist.attackFrom) { + added = true; + uiintro.add(`
攻击范围:${-dist.attackFrom + 1}
`); + } + } + if (!added) { + uiintro.add(`
攻击范围:1
`); + } + } + } + if (lib.card[name].cardPrompt) { + var str = lib.card[name].cardPrompt(node.link || node), placetext = uiintro.add(`
${str}
`); + if (!str.startsWith(`
${lib.translate[`${name}_info`]}
`); + if (!lib.translate[name + "_info"].startsWith(`
应变:${yingbianEffects.map(value => lib.yingbian.prompt.get(value)).join(";")}
`); + } + if (lib.translate[name + "_append"]) { + uiintro.add(`
${lib.translate[`${name}_append`]}
`); + } + } + uiintro.add(ui.create.div(".placeholder.slim")); + } + } + else if (node.classList.contains("character")) { + const character = node.link, characterInfo = get.character(node.link); + let capt = get.translation(character); + if (characterInfo) { + const infoSex = characterInfo[0]; + if (infoSex && lib.config.show_sex) capt += `  ${infoSex == "none" ? "无" : lib.translate[infoSex]}`; + const infoGroup = characterInfo[1]; + if (infoGroup && lib.config.show_group) { + const group = get.is.double(character, true); + if (group) capt += `  ${group.map(value => get.translation(value)).join("/")}`; + else capt += `  ${lib.translate[infoGroup]}`; + } + } + uiintro.add(capt); + + if (lib.characterTitle[node.link]) { + uiintro.addText(get.colorspan(lib.characterTitle[node.link])); + } + + if (node._banning) { + var clickBanned = function () { + var banned = lib.config[this.bannedname] || []; + if (banned.contains(character)) { + banned.remove(character); + } + else { + banned.push(character); + } + game.saveConfig(this.bannedname, banned); + this.classList.toggle("on"); + if (node.updateBanned) { + node.updateBanned(); + } + }; + var modeorder = lib.config.modeorder || []; + for (var i in lib.mode) { + modeorder.add(i); + } + var list = []; + uiintro.contentContainer.listen(function (e) { + ui.click.touchpop(); + e.stopPropagation(); + }); + for (var i = 0; i < modeorder.length; i++) { + if (node._banning == "online") { + if (!lib.mode[modeorder[i]].connect) continue; + if (!lib.config["connect_" + modeorder[i] + "_banned"]) { + lib.config["connect_" + modeorder[i] + "_banned"] = []; + } + } + else if (modeorder[i] == "connect" || modeorder[i] == "brawl") { + continue; + } + if (lib.config.all.mode.contains(modeorder[i])) { + list.push(modeorder[i]); + } + } + var page = ui.create.div(".menu-buttons.configpopped", uiintro.content); + var banall = false; + for (var i = 0; i < list.length; i++) { + var cfg = ui.create.div(".config", lib.translate[list[i]] + "模式", page); + cfg.classList.add("toggle"); + if (node._banning == "offline") { + cfg.bannedname = list[i] + "_banned"; + } + else { + cfg.bannedname = "connect_" + list[i] + "_banned"; + } + cfg.listen(clickBanned); + ui.create.div(ui.create.div(cfg)); + var banned = lib.config[cfg.bannedname] || []; + if (!banned.contains(character)) { + cfg.classList.add("on"); + banall = true; + } + } + if (node._banning == "offline") { + var cfg = ui.create.div(".config", "随机选将可用", page); + cfg.classList.add("toggle"); + cfg.listen(function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + lib.config.forbidai_user.remove(character); + } + else { + lib.config.forbidai_user.add(character); + } + game.saveConfig("forbidai_user", lib.config.forbidai_user); + }); + ui.create.div(ui.create.div(cfg)); + if (!lib.config.forbidai_user.contains(character)) { + cfg.classList.add("on"); + } + } + ui.create.div(".menubutton.pointerdiv", banall ? "全部禁用" : "全部启用", uiintro.content, function () { + if (this.innerHTML == "全部禁用") { + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].bannedname && page.childNodes[i].classList.contains("on")) { + clickBanned.call(page.childNodes[i]); + } + } + this.innerHTML = "全部启用"; + } + else { + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].bannedname && !page.childNodes[i].classList.contains("on")) { + clickBanned.call(page.childNodes[i]); + } + } + this.innerHTML = "全部禁用"; + } + }).style.marginTop = "-10px"; + ui.create.div(".placeholder.slim", uiintro.content); + } + else { + var infoitem = get.character(character); + var skills = infoitem[3]; + for (i = 0; i < skills.length; i++) { + if (lib.translate[skills[i] + "_info"]) { + if (lib.translate[skills[i] + "_ab"]) translation = lib.translate[skills[i] + "_ab"]; + else { + translation = get.translation(skills[i]); + if (!lib.skill[skills[i]].nobracket) translation = translation.slice(0, 2); + } + + uiintro.add(`
【${translation}】
${get.skillInfoTranslation(skills[i])}
`); + + if (lib.translate[skills[i] + "_append"]) { + uiintro._place_text = uiintro.add(`
${lib.translate[`${skills[i]}_append`]}
`) + } + } + } + var modepack = lib.characterPack["mode_" + get.mode()]; + if (lib.config.show_favourite && + lib.character[node.link] && (!modepack || !modepack[node.link]) && (!simple || get.is.phoneLayout())) { + var addFavourite = ui.create.div(".text.center.pointerdiv"); + addFavourite.link = node.link; + addFavourite.style.marginBottom = "15px"; + if (lib.config.favouriteCharacter.contains(node.link)) { + addFavourite.innerHTML = "移除收藏"; + } + else { + addFavourite.innerHTML = "添加收藏"; + } + addFavourite.listen(ui.click.favouriteCharacter) + uiintro.add(addFavourite); + } + else { + uiintro.add(ui.create.div(".placeholder.slim")); + } + var addskin = false; + if (node.parentNode.classList.contains("menu-buttons")) { + addskin = !lib.config.show_charactercard; + } + else { + addskin = lib.config.change_skin || lib.skin; + } + if (addskin && (!simple || get.is.phoneLayout())) { + var num = 1; + var introadded = false; + var nameskin = node.link; + var nameskin2 = nameskin; + var gzbool = false; + if (nameskin.startsWith("gz_shibing")) { + nameskin = nameskin.slice(3, 11); + } + else if (nameskin.startsWith("gz_")) { + nameskin = nameskin.slice(3); + gzbool = true; + } + var createButtons = function (num) { + if (!num) return; + if (!introadded) { + introadded = true; + uiintro.add(`
更改皮肤
`); + } + var buttons = ui.create.div(".buttons.smallzoom.scrollbuttons"); + lib.setMousewheel(buttons); + for (var i = 0; i <= num; i++) { + var button = ui.create.div(".button.character.pointerdiv", buttons, function () { + if (this._link) { + lib.config.skin[nameskin] = this._link; + node.style.backgroundImage = this.style.backgroundImage; + game.saveConfig("skin", lib.config.skin); + } + else { + delete lib.config.skin[nameskin]; + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) node.setBackground(nameskin2, "character"); + else node.setBackground(nameskin, "character"); + game.saveConfig("skin", lib.config.skin); + } + }); + button._link = i; + if (i) { + button.setBackgroundImage("image/skin/" + nameskin + "/" + i + ".jpg"); + } + else { + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) button.setBackground(nameskin2, "character", "noskin"); + else button.setBackground(nameskin, "character", "noskin"); + } + } + uiintro.add(buttons); + }; + var loadImage = function () { + var img = new Image(); + img.onload = function () { + num++; + loadImage(); + } + img.onerror = function () { + num--; + createButtons(num); + } + img.src = lib.assetURL + "image/skin/" + nameskin + "/" + num + ".jpg"; + } + if (lib.config.change_skin) { + loadImage(); + } + else { + setTimeout(function () { + createButtons(lib.skin[nameskin]); + }); + } + } + } + } + else if (node.classList.contains("equips") && ui.arena.classList.contains("selecting")) { + (function () { + uiintro.add("选择装备"); + uiintro.addSmall(Array.from(node.childNodes).filter(node => !node.classList.contains("feichu")), true); + uiintro.clickintro = true; + ui.control.hide(); + uiintro._onclose = function () { + ui.control.show(); + } + var confirmbutton; + for (var i = 0; i < uiintro.buttons.length; i++) { + var button = uiintro.buttons[i]; + button.classList.add("pointerdiv"); + if (button.link.classList.contains("selected")) { + button.classList.add("selected"); + } + button.listen(function (e) { + ui.click.card.call(this.link, "popequip"); + ui.click.window.call(ui.window, e); + if (this.link.classList.contains("selected")) { + this.classList.add("selected"); + } + else { + this.classList.remove("selected"); + } + if (ui.confirm && ui.confirm.str && ui.confirm.str.includes("o")) { + confirmbutton.classList.remove("disabled"); + } + else { + confirmbutton.classList.add("disabled"); + } + }); + } + var buttoncontainer = uiintro.add(ui.create.div()); + buttoncontainer.style.display = "block"; + confirmbutton = ui.create.div(".menubutton.large.pointerdiv", "确定", function () { + if (ui.confirm && ui.confirm.str && ui.confirm.str.includes("o")) { + uiintro._clickintro(); + ui.click.ok(ui.confirm.firstChild); + } + }, buttoncontainer); + confirmbutton.style.position = "relative"; + setTimeout(function () { + if (ui.confirm && ui.confirm.str && ui.confirm.str.includes("o")) { + confirmbutton.classList.remove("disabled"); + } + else { + confirmbutton.classList.add("disabled"); + } + }, 300); + }()); + } + else if (node.classList.contains("identity") && node.dataset.career) { + var career = node.dataset.career; + uiintro.add(get.translation(career)); + uiintro.add(`
${lib.translate[`_${career}_skill_info`]}
`); + } + else if (node.classList.contains("skillbar")) { + if (node == ui.friendBar) { + uiintro.add("友方怒气值"); + uiintro.add(`
${_status.friendRage}/100
`); + } + else if (node == ui.enemyBar) { + uiintro.add("敌方怒气值"); + uiintro.add(`
${_status.enemyRage}/100
`); + } + } + else if (node.parentNode == ui.historybar) { + if (node.dead) { + if (!node.source || node.source == node.player) { + uiintro.add(`
${get.translation(node.player)}阵亡
`); + uiintro.addSmall([node.player]); + } + else { + uiintro.add(`
${get.translation(node.player)}被${get.translation(node.source)}杀害
`); + uiintro.addSmall([node.source]); + } + } + if (node.skill) { + uiintro.add(`
${get.translation(node.skill, "skill")}
`); + uiintro._place_text = uiintro.add(`
${get.translation(node.skill, "info")}
`); + } + if (node.targets && get.itemtype(node.targets) == "players") { + uiintro.add(`
目标
`); + uiintro.addSmall(node.targets); + } + if (node.players && node.players.length > 1) { + uiintro.add(`
使用者
`); + uiintro.addSmall(node.players); + } + if (node.cards && node.cards.length) { + uiintro.add(`
卡牌
`); + uiintro.addSmall(node.cards); + } + for (var i = 0; i < node.added.length; i++) { + uiintro.add(node.added[i]); + } + if (node.added.length) { + uiintro.add(ui.create.div(".placeholder.slim")); + } + if (uiintro.content.firstChild) { + uiintro.content.firstChild.style.paddingTop = "3px"; + } + } + if (lib.config.touchscreen) { + lib.setScroll(uiintro.contentContainer); + } + return uiintro; + } + static linkintro(dialog, content, player) { + dialog.content.firstChild.remove(); + dialog.add(`
已横置
`); + var list = []; + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isLinked() && game.players[i].name && !game.players[i].name.startsWith("unknown")) { + list.push(game.players[i]); + } + } + if (list.length) { + dialog.add(list, true, true); + } + } + static groups() { + return ["wei", "shu", "wu", "qun", "jin", "western", "key"]; + } + static types() { + var types = []; + for (var i in lib.card) { + if (lib.card[i].mode && lib.card[i].mode.contains(lib.config.mode) == false) continue; + if (lib.card[i].forbid && lib.card[i].forbid.contains(lib.config.mode)) continue; + if (lib.card[i].type) { + if (lib.card[i].type == "delay") types.add("trick"); + else types.add(lib.card[i].type); + } + } + return types; + } + static links(buttons) { + var links = []; + for (var i = 0; i < buttons.length; i++) { + if (buttons[i].link != undefined) links.push(buttons[i].link); + } + return links; + } + static threaten(target, player, hp) { + var threaten = 1; + var skills = target.getSkills(); + if (!player && player !== false) { + player = _status.event.player; + } + for (var i = 0; i < skills.length; i++) { + var info = get.info(skills[i]); + if (info && info.ai && info.ai.threaten) { + if (typeof info.ai.threaten == "function" && player) { + var tmp = info.ai.threaten(player, target); + if (typeof tmp == "number") { + threaten *= tmp; + } + } + else if (typeof info.ai.threaten == "number") { + threaten *= info.ai.threaten; + } + } + } + if (hp) { + switch (target.hp) { + case 0: threaten *= 1.5; break; + case 1: threaten *= 1.2; break; + } + switch (target.countCards("h")) { + case 0: threaten *= 1.5; break; + case 1: threaten *= 1.2; break; + } + } + return threaten; + } + static condition(player) { + var num = player.hp; + if (num > 4) { + num = 4 + Math.sqrt(num - 4); + } + else { + if (player.isHealthy()) { + if (player.hp == 3) { + num += 0.5; + } + else if (player.hp < 3) { + num++; + } + } + } + num += player.countCards("h") / 2; + var es = player.getCards("e"); + for (var i = 0; i < es.length; i++) { + var val = get.equipValueNumber(es[i]); + if (val >= 7) num += 0.8; + if (val >= 5) num += 0.5; + if (val >= 3) num += 0.2; + } + return num; + } + static attitude(from, to) { + if (!from || !to) return 0; + from = from._trueMe || from; + arguments[0] = from; + var att = get.rawAttitude.apply(this, arguments); + if (from.isMad()) att = -att; + if (to.isMad() && att > 0) { + if (to.identity == "zhu") { + att = 1; + } + else { + att = 0; + } + } + if (!_status.tempnofake) { + _status.tempnofake = true; + if (from.ai.modAttitudeFrom) { + att = from.ai.modAttitudeFrom(from, to, att); + } + if (to.ai.modAttitudeTo) { + att = to.ai.modAttitudeTo(from, to, att); + } + delete _status.tempnofake; + } + return att; + } + static sgnAttitude() { + return get.sgn(get.attitude.apply(this, arguments)); + } + static useful_raw(card, player) { + if (get.position(card) == "j") return -1; + if (get.position(card) == "e") return get.equipValue(card); + if (card._modUseful) { + return card._modUseful(); + } + var i = 0; + if (!player) player = _status.event.player; + if (player) { + if (_status.event.useCache) { + i = game.callFuncUseStepCache("player.getCardsInUseful", function (player, position, cardname) { + return player.getCards(position, cardname); + }, [player, "h", card.name]).indexOf(card); + } else { + i = player.getCards("h", card.name).indexOf(card); + } + if (i < 0) i = 0; + } + var aii = get.info(card).ai; + var useful; + if (aii && aii.useful) useful = aii.useful; + else if (aii && aii.basic) useful = aii.basic.useful; + var result; + if (useful == undefined) result = -1; + else if (typeof useful == "function") { + result = useful(card, i); + } + else if (typeof useful == "number") result = useful; + else if (i < useful.length) { + result = useful[i]; + } + else result = useful[useful.length - 1]; + result = game.checkMod(player, card, result, "aiUseful", player); + return result; + } + static useful(card, player) { + if (_status.event.useCache) { + return game.callFuncUseStepCache("get.useful_raw", get.useful_raw, [card, player]); + } + return get.useful_raw(card, player); + } + static unuseful(card) { + return -get.useful(card); + } + static unuseful2(card) { + return 10 - get.useful(card); + } + static unuseful3(card) { + if (card.name == "du") return 20; + return 10 - get.useful(card); + } + static value(card, player, method) { + var result = 0; + var value; + if (Array.isArray(card)) { + if (!card.length) return 0; + value = 0; + for (var i = 0; i < card.length; i++) { + value += get.value(card[i], player, method); + } + return value / Math.sqrt(card.length); + } + if (card._modValue) { + return card._modValue(player, method); + } + var aii = get.info(card).ai; + if (aii && aii.value) value = aii.value; + else if (aii && aii.basic) value = aii.basic.value; + if (player == undefined || get.itemtype(player) != "player") player = _status.event.player; + var geti = function () { + var num = 0, i; + var cards = player.getCards("hs", card.name); + if (cards.contains(card)) { + return cards.indexOf(card); + } + return cards.length; + }; + if (typeof value == "function") { + result = value(card, player, geti(), method); + } + if (typeof value == "number") result = value; + if (Array.isArray(value)) { + if (method == "raw") result = value[0]; + var num = geti(); + if (num < value.length) result = value[num]; + else result = value[value.length - 1]; + } + result = game.checkMod(player, card, result, "aiValue", player); + return result; + } + static equipResult(player, target, name) { + var card = get.card(); + if (!card || card.name != name) { + card = { name: name }; + } + var value1 = get.equipValue(card, target); + var value2 = 0; + if (!player.canEquip(card)) { + if (!player.canEquip(card, true)) return 0; + var current = target.getEquip(card); + if (current && current != card) { + value2 = get.equipValue(current, target); + if (value2 > 0 && !target.needsToDiscard() && !get.tag(card, "valueswap")) { + return 0; + } + } + } + return Math.max(0, value1 - value2) / 5; + } + static equipValue(card, player) { + if (player == undefined || get.itemtype(player) != "player") player = get.owner(card); + if (player == undefined || get.itemtype(player) != "player") player = _status.event.player; + var info = get.info(card); + if (!info.ai) return 0; + var value = info.ai.equipValue; + if (value == undefined) { + if (info.ai.basic && info.ai.basic.equipValue != undefined) { + value = info.ai.basic.equipValue; + } + else return 0; + } + if (typeof value == "number") return value; + if (typeof value == "function") return value(card, player, null, "raw2"); + return 0; + } + static equipValueNumber(card) { + var info = get.info(card); + if (info.ai) { + if (typeof info.ai.equipValue == "number") return info.ai.equipValue; + if (info.ai.basic && typeof info.ai.basic.equipValue == "number") return info.ai.basic.equipValue; + } + return 0; + } + static disvalue(card, player) { + return -get.value(card, player); + } + static disvalue2(card, player) { + return -get.value(card, player, "raw"); + } + static skillthreaten(skill, player, target) { + if (!lib.skill[skill]) return 1; + if (!lib.skill[skill].ai) return 1; + var threaten = lib.skill[skill].ai.threaten; + if (typeof threaten == "number") return threaten; + if (typeof threaten == "function") { + player = player || _status.event.player; + target = target || player; + return threaten(player, target); + } + return 1; + } + static order(item) { + var info = get.info(item); + if (!info) return -1; + var aii = info.ai; + var order; + if (aii && aii.order) order = aii.order; + else if (aii && aii.basic) order = aii.basic.order; + if (order == undefined) return -1; + var num = order; + if (typeof (order) == "function") { + num = order(item, _status.event.player); + } + if (typeof item == "object" && _status.event.player) { + var player = _status.event.player; + num = game.checkMod(player, item, num, "aiOrder", player); + } + return num; + } + static result(item, skill) { + var result; + var info = get.info(item); + if (info.ai) result = get.copy(info.ai.result); + if (typeof (result) == "function") result = result(item); + if (!result) result = {}; + if (skill) { + var info2 = get.info(skill); + if (info2.ai) { + info2 = info2.ai.result; + for (var i in info2) { + result[i] = info2[i]; + } + } + } + return result; + } + static effect_use(target, card, player, player2, isLink) { + var event = _status.event; + var eventskill = null; + if (player == undefined) player = _status.event.player; + if (card && typeof card == "object" && "name" in card) card = get.autoViewAs(card); + if (typeof card != "string" && (typeof card != "object" || !card.name)) { + var skillinfo = get.info(event.skill); + if (event.skill && skillinfo.viewAs == undefined) card = _status.event.skill; + else { + card = get.card(); + if (skillinfo && skillinfo.viewAs && card.name === skillinfo.viewAs.name) { + eventskill = event.skill; + } + } + } + var info = get.info(card); + if (typeof card == "object" && info && info.changeTarget) { + var targets = [target]; + info.changeTarget(player, targets); + var eff = 0; + for (var i of targets) { + eff += get.effect(i, card, player, player2, isLink); + } + return eff; + } + var result = get.result(card, eventskill); + var result1 = result.player_use || result.player, result2 = result.target_use || result.target; + if (typeof result1 == "function") result1 = result1(player, target, card, isLink); + if (typeof result2 == "function") result2 = result2(player, target, card, isLink); + + if (typeof result1 != "number") result1 = 0; + if (typeof result2 != "number") result2 = 0; + var temp1, temp2, temp3, temp01 = 0, temp02 = 0, threaten = 1; + var skills1 = player.getSkills().concat(lib.skill.global); + game.expandSkills(skills1); + var zerotarget = false, zeroplayer = false; + for (var i = 0; i < skills1.length; i++) { + temp1 = get.info(skills1[i]).ai; + if (temp1 && typeof temp1.effect == "object" && typeof temp1.effect.player_use == "function") { + temp1 = temp1.effect.player_use(card, player, target, result1, isLink); + } + else if (temp1 && typeof temp1.effect == "object" && typeof temp1.effect.player == "function") { + temp1 = temp1.effect.player(card, player, target, result1, isLink); + } + else temp1 = undefined; + if (typeof temp1 == "object") { + if (temp1.length == 2 || temp1.length == 4) { + result1 *= temp1[0]; + temp01 += temp1[1]; + } + if (temp1.length == 4) { + result2 *= temp1[2]; + temp02 += temp1[3]; + } + } + else if (typeof temp1 == "number") { + result1 *= temp1; + } + else if (temp1 == "zeroplayer") { + zeroplayer = true; + } + else if (temp1 == "zerotarget") { + zerotarget = true; + } + else if (temp1 == "zeroplayertarget") { + zeroplayer = true; + zerotarget = true; + } + } + if (target) { + var skills2 = target.getSkills().concat(lib.skill.global); + game.expandSkills(skills2); + for (var i = 0; i < skills2.length; i++) { + temp2 = get.info(skills2[i]).ai; + if (temp2 && temp2.threaten) temp3 = temp2.threaten; + else temp3 = undefined; + if (temp2 && typeof temp2.effect == "function") { + if (!player.hasSkillTag("ignoreSkill", true, { + card: card, + target: target, + skill: skills2[i], + isLink: isLink, + })) temp2 = temp2.effect(card, player, target, result2, isLink); + else temp2 = undefined; + } + else if (temp2 && typeof temp2.effect == "object" && typeof temp2.effect.target_use == "function") { + if (!player.hasSkillTag("ignoreSkill", true, { + card: card, + target: target, + skill: skills2[i], + isLink: isLink, + })) temp2 = temp2.effect.target_use(card, player, target, result2, isLink); + else temp2 = undefined; + } + else if (temp2 && typeof temp2.effect == "object" && typeof temp2.effect.target == "function") { + if (!player.hasSkillTag("ignoreSkill", true, { + card: card, + target: target, + skill: skills2[i], + isLink: isLink, + })) temp2 = temp2.effect.target(card, player, target, result2, isLink); + else temp2 = undefined; + } + else temp2 = undefined; + if (typeof temp2 == "object") { + if (temp2.length == 2 || temp2.length == 4) { + result2 *= temp2[0]; + temp02 += temp2[1]; + } + if (temp2.length == 4) { + result1 *= temp2[2]; + temp01 += temp2[3]; + } + } + else if (typeof temp2 == "number") { + result2 *= temp2; + } + else if (temp2 == "zeroplayer") { + zeroplayer = true; + } + else if (temp2 == "zerotarget") { + zerotarget = true; + } + else if (temp2 == "zeroplayertarget") { + zeroplayer = true; + zerotarget = true; + } + if (typeof temp3 == "function" && temp3(player, target) != undefined) { + threaten *= temp3(player, target); + } + else if (typeof temp3 == "object") { + if (typeof temp3.target == "number") { + threaten *= temp3; + } + else if (typeof temp3.target == "function" && temp3(player, target) != undefined) { + threaten *= temp3(player, target); + } + } + else if (typeof temp3 == "number") { + threaten *= temp3; + } + } + result2 += temp02; + result1 += temp01; + if (typeof card == "object" && !result.ignoreStatus) { + if (get.attitude(player, target) < 0) { + result2 *= Math.sqrt(threaten); + } + else { + result2 *= Math.sqrt(Math.sqrt(threaten)); + } + if (target.hp == 1) result2 *= 2.5; + if (target.hp == 2) result2 *= 1.8; + if (target.countCards("h") == 0) { + if (get.tag(card, "respondSha") || get.tag(card, "respondShan")) { + result2 *= 1.7; + } + else { + result2 *= 1.5; + } + } + if (target.countCards("h") == 1) result2 *= 1.3; + if (target.countCards("h") == 2) result2 *= 1.1; + if (target.countCards("h") > 3) result2 *= 0.5; + if (target.hp == 4) result2 *= 0.9; + if (target.hp == 5) result2 *= 0.8; + if (target.hp > 5) result2 *= 0.6; + } + } + else { + result2 += temp02; + result1 += temp01; + } + if (zeroplayer) result1 = 0; + if (zerotarget) result2 = 0; + var final = 0; + if (player2) { + final = (result1 * get.attitude(player2, player) + (target ? result2 * get.attitude(player2, target) : 0)); + } + else final = (result1 * get.attitude(player, player) + (target ? result2 * get.attitude(player, target) : 0)); + if (!isLink && get.tag(card, "natureDamage") && !zerotarget) { + var info = get.info(card); + if (!info || !info.ai || !info.ai.canLink) { + if (target.isLinked()) game.countPlayer(function (current) { + if (current != target && current.isLinked()) final += get.effect(current, card, player, player2, true); + }); + } + else if (info.ai.canLink(player, target, card)) { + game.countPlayer(function (current) { + if (current != target && current.isLinked()) final += get.effect(current, card, player, player2, true); + }); + } + } + return final; + } + static effect(target, card, player, player2, isLink) { + var event = _status.event; + var eventskill = null; + if (player == undefined) player = _status.event.player; + if (card && typeof card == "object" && "name" in card) card = get.autoViewAs(card); + if (typeof card != "string" && (typeof card != "object" || !card.name)) { + var skillinfo = get.info(event.skill); + if (event.skill && skillinfo.viewAs == undefined) card = _status.event.skill; + else { + card = get.card(); + if (skillinfo && skillinfo.viewAs && card.name === skillinfo.viewAs.name) { + eventskill = event.skill; + } + } + } + var result = get.result(card, eventskill); + var result1 = result.player, result2 = result.target; + if (typeof result1 == "function") result1 = result1(player, target, card, isLink); + if (typeof result2 == "function") result2 = result2(player, target, card, isLink); + + if (typeof result1 != "number") result1 = 0; + if (typeof result2 != "number") result2 = 0; + var temp1, temp2, temp3, temp01 = 0, temp02 = 0, threaten = 1; + var skills1 = player.getSkills().concat(lib.skill.global); + game.expandSkills(skills1); + var zerotarget = false, zeroplayer = false; + for (var i = 0; i < skills1.length; i++) { + temp1 = get.info(skills1[i]).ai; + if (temp1 && typeof temp1.effect == "object" && typeof temp1.effect.player == "function") { + temp1 = temp1.effect.player(card, player, target, result1, isLink); + } + else temp1 = undefined; + if (typeof temp1 == "object") { + if (temp1.length == 2 || temp1.length == 4) { + result1 *= temp1[0]; + temp01 += temp1[1]; + } + if (temp1.length == 4) { + result2 *= temp1[2]; + temp02 += temp1[3]; + } + } + else if (typeof temp1 == "number") { + result1 *= temp1; + } + else if (temp1 == "zeroplayer") { + zeroplayer = true; + } + else if (temp1 == "zerotarget") { + zerotarget = true; + } + else if (temp1 == "zeroplayertarget") { + zeroplayer = true; + zerotarget = true; + } + } + if (target) { + var skills2 = target.getSkills().concat(lib.skill.global); + game.expandSkills(skills2); + for (var i = 0; i < skills2.length; i++) { + temp2 = get.info(skills2[i]).ai; + if (temp2 && temp2.threaten) temp3 = temp2.threaten; + else temp3 = undefined; + if (temp2 && typeof temp2.effect == "function") { + if (!player.hasSkillTag("ignoreSkill", true, { + card: card, + target: target, + skill: skills2[i], + isLink: isLink, + })) temp2 = temp2.effect(card, player, target, result2, isLink); + else temp2 = undefined; + } + else if (temp2 && typeof temp2.effect == "object" && typeof temp2.effect.target == "function") { + if (!player.hasSkillTag("ignoreSkill", true, { + card: card, + target: target, + skill: skills2[i], + isLink: isLink, + })) temp2 = temp2.effect.target(card, player, target, result2, isLink); + else temp2 = undefined; + } + else temp2 = undefined; + if (typeof temp2 == "object") { + if (temp2.length == 2 || temp2.length == 4) { + result2 *= temp2[0]; + temp02 += temp2[1]; + } + if (temp2.length == 4) { + result1 *= temp2[2]; + temp01 += temp2[3]; + } + } + else if (typeof temp2 == "number") { + result2 *= temp2; + } + else if (temp2 == "zeroplayer") { + zeroplayer = true; + } + else if (temp2 == "zerotarget") { + zerotarget = true; + } + else if (temp2 == "zeroplayertarget") { + zeroplayer = true; + zerotarget = true; + } + if (typeof temp3 == "function" && temp3(player, target) != undefined) { + threaten *= temp3(player, target); + } + else if (typeof temp3 == "object") { + if (typeof temp3.target == "number") { + threaten *= temp3; + } + else if (typeof temp3.target == "function" && temp3(player, target) != undefined) { + threaten *= temp3(player, target); + } + } + else if (typeof temp3 == "number") { + threaten *= temp3; + } + } + result2 += temp02; + result1 += temp01; + if (typeof card == "object" && !result.ignoreStatus) { + if (get.attitude(player, target) < 0) { + result2 *= Math.sqrt(threaten); + } + else { + result2 *= Math.sqrt(Math.sqrt(threaten)); + } + // *** continue here *** + if (target.hp == 1) result2 *= 2.5; + if (target.hp == 2) result2 *= 1.8; + if (target.countCards("h") == 0) { + if (get.tag(card, "respondSha") || get.tag(card, "respondShan")) { + result2 *= 1.7; + } + else { + result2 *= 1.5; + } + } + if (target.countCards("h") == 1) result2 *= 1.3; + if (target.countCards("h") == 2) result2 *= 1.1; + if (target.countCards("h") > 3) result2 *= 0.5; + if (target.hp == 4) result2 *= 0.9; + if (target.hp == 5) result2 *= 0.8; + if (target.hp > 5) result2 *= 0.6; + } + } + else { + result2 += temp02; + result1 += temp01; + } + if (zeroplayer) result1 = 0; + if (zerotarget) result2 = 0; + var final = 0; + if (player2) { + final = (result1 * get.attitude(player2, player) + (target ? result2 * get.attitude(player2, target) : 0)); + } + else final = (result1 * get.attitude(player, player) + (target ? result2 * get.attitude(player, target) : 0)); + if (!isLink && get.tag(card, "natureDamage") && !zerotarget) { + var info = get.info(card); + if (!info || !info.ai || !info.ai.canLink) { + if (target.isLinked()) game.countPlayer(function (current) { + if (current != target && current.isLinked()) final += get.effect(current, card, player, player2, true); + }); + } + else if (info.ai.canLink(player, target, card)) { + game.countPlayer(function (current) { + if (current != target && current.isLinked()) final += get.effect(current, card, player, player2, true); + }); + } + } + return final; + } + static damageEffect(target, player, viewer, nature) { + if (get.itemtype(nature) == "natures") { + var natures = get.natureList(nature); + return natures.map(n => get.damageEffect(target, player, viewer, n)).reduce((p, c) => p + c, 0) / (natures.length || 1); + } + if (!player) { + player = target; + } + if (!viewer) { + viewer = target; + } + var name = "damage"; + if (nature == "fire") { + name = "firedamage"; + } + else if (nature == "thunder") { + name = "thunderdamage"; + } + else if (nature == "ice") { + name = "icedamage"; + } + var eff = get.effect(target, { name: name }, player, viewer); + if (eff > 0 && target.hujia > 0) return eff / 1.3; + return eff; + } + static recoverEffect(target, player, viewer) { + if (target.hp == target.maxHp) return 0; + if (!player) { + player = target; + } + if (!viewer) { + viewer = target; + } + return get.effect(target, { name: "recover" }, player, viewer); + } + static buttonValue(button) { + var card = button.link; + var player = get.owner(card); + if (!player) player = _status.event.player; + if (player.getCards("j").contains(card)) { + var efff = get.effect(player, { + name: card.viewAs || card.name, + cards: [card], + }, player, player); + if (efff > 0) return 0.5; + if (efff == 0) return 0; + return -1.5; + } + if (player.getCards("e").contains(card)) { + var evalue = get.value(card, player); + if (player.hasSkillTag("noe")) { + if (evalue >= 7) { + return evalue / 6; + } + return evalue / 10; + } + return evalue / 3; + } + if (player.hasSkillTag("noh")) return 0.1; + var nh = player.countCards("h"); + switch (nh) { + case 1: return 2; + case 2: return 1.6; + case 3: return 1; + case 4: return 0.8; + case 5: return 0.6; + default: return 0.4; + } + } + static attitude2(to) { + return get.attitude(_status.event.player, to); + } +} diff --git a/noname/get/is.js b/noname/get/is.js new file mode 100644 index 000000000..e3e58fbcf --- /dev/null +++ b/noname/get/is.js @@ -0,0 +1,378 @@ +export class Is { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + /** + * 判断是否为进攻坐骑 + * @param {Card | VCard} card + * @param {false | Player} [player] + * @returns {boolean} + */ + static attackingMount(card, player) { + const subtype = get.subtype(card, player); + if (subtype == "equip4") return true; + else if (subtype == "equip6") { + const info = get.info(card, player), distance = info.distance; + if (!distance) return false; + if (distance.globalFrom && !info.notMount) return true; + } + return false; + } + /** + * 判断是否为防御坐骑 + * @param {Card | VCard} card + * @param {false | Player} [player] + * @returns {boolean} + */ + static defendingMount(card, player) { + const subtype = get.subtype(card, player); + if (subtype == "equip3") return true; + else if (subtype == "equip6") { + const info = get.info(card, player), distance = info.distance; + if (!distance) return false; + if (distance.globalTo && !info.notMount) return true; + } + return false; + } + /** + * 判断坐骑栏是否被合并 + */ + static mountCombined() { + if (lib.configOL) { + return lib.configOL.mount_combine; + } + else if (typeof _status.mountCombined != "boolean") { + _status.mountCombined = lib.config.mount_combine; + } + return _status.mountCombined; + } + /** + * 判断传入的参数的属性是否相同(参数可以为卡牌、卡牌信息、属性等) + * @param {...} infos 要判断的属性列表 + * @param {boolean} every 是否判断每一个传入的属性是否完全相同而不是存在部分相同 + */ + static sameNature() { + let processedArguments = [], every = false; + Array.from(arguments).forEach(argument => { + if (typeof argument == "boolean") every = argument; + else if (argument) processedArguments.push(argument); + }); + if (!processedArguments.length) return true; + if (processedArguments.length == 1) { + const argument = processedArguments[0]; + if (!Array.isArray(argument)) return false; + if (!argument.length) return true; + if (argument.length == 1) return false; + processedArguments = argument; + } + const naturesList = processedArguments.map(card => { + if (typeof card == "string") return card.split(lib.natureSeparator); + else if (Array.isArray(card)) return card; + return get.natureList(card || {}); + }); + const testingNaturesList = naturesList.slice(0, naturesList.length - 1); + if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.length == natures.length && testingNatures.every(nature => natures.includes(nature)))); + return testingNaturesList.every((natures, index) => { + const comparingNaturesList = naturesList.slice(index + 1); + if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => testingNatures.includes(nature))); + return comparingNaturesList.every(testingNatures => !testingNatures.length); + }); + } + /** + * 判断传入的参数的属性是否不同(参数可以为卡牌、卡牌信息、属性等) + * @param ...infos 要判断的属性列表 + * @param every {boolean} 是否判断每一个传入的属性是否完全不同而不是存在部分不同 + */ + static differentNature() { + let processedArguments = [], every = false; + Array.from(arguments).forEach(argument => { + if (typeof argument == "boolean") every = argument; + else if (argument) processedArguments.push(argument); + }); + if (!processedArguments.length) return false; + if (processedArguments.length == 1) { + const argument = processedArguments[0]; + if (!Array.isArray(argument)) return true; + if (!argument.length) return false; + if (argument.length == 1) return true; + processedArguments = argument; + } + const naturesList = processedArguments.map(card => { + if (typeof card == "string") return card.split(lib.natureSeparator); + else if (Array.isArray(card)) return card; + return get.natureList(card || {}); + }); + const testingNaturesList = naturesList.slice(0, naturesList.length - 1); + if (every) return testingNaturesList.every((natures, index) => naturesList.slice(index + 1).every(testingNatures => testingNatures.every(nature => !natures.includes(nature)))); + return testingNaturesList.every((natures, index) => { + const comparingNaturesList = naturesList.slice(index + 1); + if (natures.length) return natures.some(nature => comparingNaturesList.every(testingNatures => !testingNatures.length || testingNatures.some(testingNature => testingNature != nature))); + return comparingNaturesList.every(testingNatures => testingNatures.length); + }); + } + /** + * 判断一张牌是否为明置手牌 + */ + static shownCard(card) { + if (!card) return false; + const gaintag = card.gaintag; + return Array.isArray(gaintag) && gaintag.some(tag => tag.startsWith("visible_")); + } + /** + * 是否是虚拟牌 + */ + static vituralCard(card) { + return card.isCard || (!("cards" in card) || !Array.isArray(card.cards) || card.cards.length == 0); + } + /** + * 是否是转化牌 + */ + static convertedCard(card) { + return !card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length > 0; + } + /** + * 是否是实体牌 + */ + static ordinaryCard(card) { + return card.isCard && ("cards" in card) && Array.isArray(card.cards) && card.cards.length == 1; + } + /** + * 押韵判断 + */ + static yayun(str1, str2) { + if (str1 == str2) return true; + var pinyin1 = get.pinyin(str1, false), pinyin2 = get.pinyin(str2, false); + if (!pinyin1.length || !pinyin2.length) return false; + var pron1 = pinyin1[pinyin1.length - 1], pron2 = pinyin2[pinyin2.length - 1]; + if (pron1 == pron2) return true; + return get.yunjiao(pron1) == get.yunjiao(pron2); + } + static blocked(skill, player) { + if (!player.storage.skill_blocker || !player.storage.skill_blocker.length) return false; + for (var i of player.storage.skill_blocker) { + if (lib.skill[i] && lib.skill[i].skillBlocker && lib.skill[i].skillBlocker(skill, player)) return true; + } + return false; + } + static double(name, array) { + const extraInformations = get.character(name, 4); + if (!extraInformations) return false; + for (const extraInformation of extraInformations) { + if (!extraInformation.startsWith("doublegroup:")) continue; + return array ? extraInformation.split(":").slice(1) : true; + } + return false; + } + + /** + * Check if the card has a Yingbian condition + * + * 检测此牌是否具有应变条件 + */ + static yingbianConditional(card) { + return get.is.complexlyYingbianConditional(card) || get.is.simplyYingbianConditional(card); + } + static complexlyYingbianConditional(card) { + for (const key of lib.yingbian.condition.complex.keys()) { + if (get.cardtag(card, `yingbian_${key}`)) return true; + } + return false; + } + static simplyYingbianConditional(card) { + for (const key of lib.yingbian.condition.simple.keys()) { + if (get.cardtag(card, `yingbian_${key}`)) return true; + } + return false; + } + + /** + * Check if the card has a Yingbian effect + * + * 检测此牌是否具有应变效果 + */ + static yingbianEffective(card) { + for (const key of lib.yingbian.effect.keys()) { + if (get.cardtag(card, `yingbian_${key}`)) return true; + } + return false; + } + static yingbian(card) { + return get.is.yingbianConditional(card) || get.is.yingbianEffective(card); + } + static emoji(substring) { + if (substring) { + var reg = new RegExp("[~#^$@%&!?%*]", "g"); + if (substring.match(reg)) { + return true; + } + for (var i = 0; i < substring.length; i++) { + var hs = substring.charCodeAt(i); + if (0xd800 <= hs && hs <= 0xdbff) { + if (substring.length > 1) { + var ls = substring.charCodeAt(i + 1); + var uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; + if (0x1d000 <= uc && uc <= 0x1f77f) { + return true; + } + } + } + else if (substring.length > 1) { + var ls = substring.charCodeAt(i + 1); + if (ls == 0x20e3) { + return true; + } + } + else { + if (0x2100 <= hs && hs <= 0x27ff) { + return true; + } + else if (0x2B05 <= hs && hs <= 0x2b07) { + return true; + } + else if (0x2934 <= hs && hs <= 0x2935) { + return true; + } + else if (0x3297 <= hs && hs <= 0x3299) { + return true; + } + else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 + || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b + || hs == 0x2b50) { + return true; + } + } + } + } + return false; + } + static banWords(str) { + return get.is.emoji(str) || window.bannedKeyWords.some(item => str.includes(item)); + } + static converted(event) { + return !(event.card && event.card.isCard); + } + static safari() { + return userAgent.indexOf("safari" != -1) && userAgent.indexOf("chrome") == -1; + } + static freePosition(cards) { + return !cards.some(card => !card.hasPosition || card.hasPosition()); + } + static nomenu(name, item) { + var menus = ["system", "menu"]; + var configs = { + show_round_menu: lib.config.show_round_menu, + round_menu_func: lib.config.round_menu_func, + touchscreen: lib.config.touchscreen, + swipe_up: lib.config.swipe_up, + swipe_down: lib.config.swipe_down, + swipe_left: lib.config.swipe_left, + swipe_right: lib.config.swipe_right, + right_click: lib.config.right_click, + phonelayout: lib.config.phonelayout + }; + configs[name] = item; + if (!configs.phonelayout) return false; + if (configs.show_round_menu && menus.contains(configs.round_menu_func)) { + return false; + } + if (configs.touchscreen) { + if (menus.contains(configs.swipe_up)) return false; + if (menus.contains(configs.swipe_down)) return false; + if (menus.contains(configs.swipe_left)) return false; + if (menus.contains(configs.swipe_right)) return false; + } + else { + if (configs.right_click == "config") return false; + } + if (name) { + setTimeout(function () { + alert("请将至少一个操作绑定为显示按钮或打开菜单,否则将永远无法打开菜单"); + }); + } + return true; + } + static altered() { + return false; + } + static node(obj) { + var str = Object.prototype.toString.call(obj); + if (str && str.indexOf("[object HTML")) return true; + return false; + } + static div(obj) { + return Object.prototype.toString.call(obj) === "[object HTMLDivElement]"; + } + static map(obj) { + return Object.prototype.toString.call(obj) === "[object Map]"; + } + static set(obj) { + return Object.prototype.toString.call(obj) === "[object Set]"; + } + static object(obj) { + return Object.prototype.toString.call(obj) === "[object Object]"; + } + static singleSelect(func) { + if (typeof func == "function") return false; + var select = get.select(func); + return select[0] == 1 && select[1] == 1; + } + static jun(name) { + if (get.mode() == "guozhan") { + if (name && typeof name == "object") { + if (name.isUnseen && name.isUnseen(0)) return false; + name = name.name1; + } + if (typeof name == "string" && name.startsWith("gz_jun_")) { + return true; + } + } + return false; + } + static versus() { + return !_status.connectMode && get.mode() == "versus" && _status.mode == "three"; + } + static changban() { + return get.mode() == "single" && _status.mode == "changban"; + } + static single() { + return get.mode() == "single" && _status.mode == "normal"; + } + static mobileMe(player) { + return (game.layout == "mobile" || game.layout == "long") && !game.chess && player.dataset.position == 0; + } + static newLayout() { + return game.layout != "default"; + } + static phoneLayout() { + if (!lib.config.phonelayout) return false; + return (game.layout == "mobile" || game.layout == "long" || game.layout == "long2" || game.layout == "nova"); + } + static singleHandcard() { + return game.singleHandcard || game.layout == "mobile" || game.layout == "long" || game.layout == "long2" || game.layout == "nova"; + } + static linked2(player) { + if (game.chess) return true; + if (lib.config.link_style2 != "rotate") return true; + // if(game.chess) return false; + if (game.layout == "long" || game.layout == "long2" || game.layout == "nova") return true; + if (player.dataset.position == "0") { + return ui.arena.classList.contains("oblongcard"); + } + return false; + } + static empty(obj) { + return Object.keys(obj).length == 0; + } + static pos(str) { + return str == "h" || str == "e" || str == "j" || str == "he" || str == "hj" || str == "ej" || str == "hej"; + } + static locked(skill, player) { + var info = lib.skill[skill]; + if (typeof info.locked == "function") return info.locked(skill, player); + if (info.locked == false) return false; + if (info.trigger && info.forced) return true; + if (info.mod) return true; + if (info.locked) return true; + return false; + } +} diff --git a/noname/gnc.js b/noname/gnc.js new file mode 100644 index 000000000..6e55587ea --- /dev/null +++ b/noname/gnc.js @@ -0,0 +1,57 @@ +const GeneratorFunction = (function* () { +}).constructor; + +export class GNC { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static of(fn) { + return this.isGeneratorFunc(fn) ? function genCoroutine() { + let gen = fn.apply(this, arguments); + gen.status = "next"; + gen.state = undefined; + const callback = (resolve, reject) => { + let result, + nexts = resolve, + throws = reject; + try { + result = gen[gen.status](gen.state); + } catch (error) { + reject(error); + return; + } + if (!result.done) { + nexts = (item) => { + gen.state = item; + gen.status = "next"; + callback(resolve, reject); + } + throws = (err) => { + gen.state = err; + gen.status = "throw"; + callback(resolve, reject); + } + } + result = result.value; + Promise.resolve(result).then(nexts, throws); + } + return new Promise(callback); + } : (() => { throw new TypeError("gnc.of needs a GeneratorFunction.") })(); + } + + static isCoroutine(item) { + return typeof item == "function" && item.name == "genCoroutine"; + } + + /** + * @returns {item is GeneratorFunction} + */ + static isGeneratorFunc(item) { + return item instanceof GeneratorFunction; + } + + static isGenerator(item) { + return typeof item == "object" && "constructor" in item && item.constructor && "constructor" in item.constructor && item.constructor.constructor === GeneratorFunction; + } +} diff --git a/noname/internal.js b/noname/internal.js new file mode 100644 index 000000000..89a82766d --- /dev/null +++ b/noname/internal.js @@ -0,0 +1 @@ +export { Library as InternalLibrary } from "./library.js"; diff --git a/noname/library.js b/noname/library.js new file mode 100644 index 000000000..4b2ec1635 --- /dev/null +++ b/noname/library.js @@ -0,0 +1,1034 @@ +import { Game } from "./game.js"; +import { Get } from "./get.js"; +import { GNC } from "./gnc.js"; +import { InternalLibrary } from "./internal.js"; +import { animate } from "./library/animate.js"; +import { announce } from "./library/announce.js"; +import { cardPack } from "./library/card-pack.js"; +import { cardPile } from "./library/card-pile.js"; +import { cardType } from "./library/card-type.js"; +import { card } from "./library/card.js"; +import { Channel } from "./library/channel.js"; +import { CharacterDialogGroup } from "./library/character-dialog-group.js"; +import { characterFilter } from "./library/character-filter.js"; +import { characterIntro } from "./library/character-intro.js"; +import { characterPack } from "./library/character-pack.js"; +import { characterReplace } from "./library/character-replace.js"; +import { characterSort } from "./library/character-sort.js"; +import { characterTitle } from "./library/character-title.js"; +import { character } from "./library/character.js"; +import { Cheat } from "./library/cheat.js"; +import { color } from "./library/color.js"; +import { Comparator } from "./library/comparator.js"; +import { CONFIGURATION_MENU } from "./library/configuration-menu.js"; +import { configuration } from "./library/configuration.js"; +import { Creation } from "./library/creation.js"; +import { dynamicTranslate } from "./library/dynamic-translate.js"; +import { element } from "./library/element.js"; +import { emotionList } from "./library/emotion-list.js"; +import { extensionMenu } from "./library/extension-menu.js"; +import { extensionPack } from "./library/extension-pack.js"; +import { Filter } from "./library/filter.js"; +import { groupNature } from "./library/group-nature.js"; +import { HELP } from "./library/help.js"; +import { hookMap } from "./library/hook-map.js"; +import { hook } from "./library/hook.js"; +import { hooks } from "./library/hooks.js"; +import { imported } from "./library/imported.js"; +import { Initialization } from "./library/initialization.js"; +import { internalStatus } from "./library/internal-status.js"; +import { linq } from "./library/linq.js"; +import { message } from "./library/message.js"; +import { MODE } from "./library/mode.js"; +import { natureAudio } from "./library/nature-audio.js"; +import { Other } from "./library/other.js"; +import { perfectPair } from "./library/perfect-pair.js"; +import { pinyins } from "./library/pinyins.js"; +import { skill } from "./library/skill.js"; +import { skin } from "./library/skin.js"; +import { Sort } from "./library/sort.js"; +import { stratagemBuff } from "./library/stratagem-buff.js"; +import { translate } from "./library/translate.js"; +import { updateURLs } from "./library/update-urls.js"; +import { yingbian } from "./library/yingbian.js"; +import { status } from "./status.js"; +import { UI } from "./ui.js"; +import { Click } from "./ui/click.js"; +import { Create } from "./ui/create.js"; + +const nonameInitialized = localStorage.getItem("noname_inited"); + +export class Library { + static configprefix = "noname_0.9_"; + static versionOL = 27; + static updateURLS = updateURLs; + static updateURL = updateURLs.github; + static mirrorURL = updateURLs.coding; + static hallURL = "47.99.105.222"; + static assetURL = typeof nonameInitialized != "string" || nonameInitialized == "nodejs" ? "" : nonameInitialized; + static userAgent = navigator.userAgent.toLowerCase(); + static compatibleEdition = Boolean(typeof nonameInitialized == "string" && nonameInitialized.match(/\/(?:com\.widget|yuri\.nakamura)\.noname\//)); + static changeLog = []; + static updates = []; + static canvasUpdates = []; + static video = []; + static skilllist = []; + static connectBanned = []; + static characterIntro = characterIntro; + static characterTitle = characterTitle; + static characterPack = characterPack; + static characterFilter = characterFilter; + static characterSort = characterSort; + static characterReplace = characterReplace; + static characterGuozhanFilter = ["mode_guozhan"]; + static dynamicTranslate = dynamicTranslate; + static cardPack = cardPack; + static skin = skin; + static onresize = []; + static onphase = []; + static onwash = []; + static onover = []; + static ondb = []; + static ondb2 = []; + static chatHistory = []; + static emotionList = emotionList; + static animate = animate; + static onload = []; + static onload2 = []; + static onprepare = []; + static arenaReady = []; + static onfree = []; + static inpile = []; + static inpile_nature = []; + static extensions = []; + static extensionPack = extensionPack; + static cardType = cardType; + static hook = hook; + static hooks = hooks; + static Channel = Channel; + /** + * @todo Waiting for [Rintim](https://github.com/Rintim)’s pull request. + */ + static announce = announce; + /** + * @type {Map} + */ + static objectURL = new Map(); + static hookmap = hookMap; + static imported = imported; + static layoutfixed = ["chess", "tafang", "stone"]; + static pinyins = pinyins; + static yingbian = yingbian; + static stratagemBuff = stratagemBuff; + /** + * The actual card name + * + * 实际的卡牌名称 + */ + static actualCardName = new Map([ + ["挟令", "挟天子以令诸侯"], + ["霹雳投石车", "霹雳车"] + ]) + static characterDialogGroup = CharacterDialogGroup; + static configMenu = CONFIGURATION_MENU; + static extensionMenu = extensionMenu; + static mode = MODE; + static status = internalStatus; + static help = HELP; + /** + * @type {import("path")} + */ + // @ts-ignore + static path = {}; + static gnc = GNC; + static comparator = Comparator; + static creation = Creation; + static linq = linq; + static init = Initialization; + static cheat = Cheat; + static translate = translate; + static element = element; + static card = card; + static filter = Filter; + static sort = Sort; + static skill = skill; + static character = character; + static perfectPair = perfectPair; + static cardPile = cardPile; + static message = message; + static suit = ["club", "spade", "diamond", "heart"]; + static suits = ["club", "spade", "diamond", "heart", "none"]; + static color = color; + static group = ["wei", "shu", "wu", "qun", "jin", "shen"]; + /** + * 数值代表各元素在名称中排列的先后顺序 + */ + static nature = new Map([ + ["fire", 20], + ["thunder", 30], + ["kami", 60], + ["ice", 40], + ["stab", 10], + ["poison", 50] + ]); + static natureAudio = natureAudio; + static linked = ["fire", "thunder", "kami", "ice"]; + static natureBg = new Map([ + ["stab", "image/card/cisha.png"] + ]); + static natureSeparator = "|"; + static namePrefix = new Map([ + ["界", { + color: "#fdd559", + nature: "soilmm", + }], + ["谋", { + color: "#def7ca", + nature: "woodmm", + }], + ["武", { + color: "#fd8359", + nature: "soilmm", + }], + ["乐", { + color: "#f7f4fc", + nature: "keymm", + }], + ["神", { + color: "#faecd1", + nature: "orangemm", + }], + ["族", { + color: "#ee9ac7", + nature: "firemm", + }], + ["晋", { + color: "#f3c5ff", + nature: "blackmm", + }], + ["侠", { + color: "#eeeeee", + nature: "qunmm", + }], + ["起", { + color: "#c3f9ff", + nature: "thundermm", + }], + ["承", { + color: "#c3f9ff", + nature: "thundermm", + }], + ["转", { + color: "#c3f9ff", + nature: "thundermm", + }], + ["梦", { + color: "#6affe2", + nature: "watermm", + }], + ["用间", { + color: "#c3f9ff", + nature: "thundermm", + }], + ["战役篇", { + color: "#c3f9ff", + nature: "thundermm", + showName: "战", + }], + ["武将传", { + color: "#c3f9ff", + nature: "thundermm", + showName: "传", + }], + ["将", { + nature: "firemm", + }], + ["新杀", { + color: "#fefedc", + nature: "metalmm", + showName: "新", + }], + ["旧", { + color: "#a4a4a4", + nature: "black", + }], + ["旧界", { + color: "#a4a4a4", + nature: "black", + }], + ["节钺", { + color: "#a4a4a4", + nature: "black", + }], + ["毅重", { + color: "#a4a4a4", + nature: "black", + }], + ["★SP", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("SP")}` + }], + ["☆SP", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("SP")}` + }], + ["J.SP", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("SP")}` + }], + ["K系列", { + showName: "K", + }], + ["经典", { + showName: "典", + }], + ["君", { + color: "#fefedc", + nature: "shenmm", + }], + ["骰子", { + getSpan: () => { + const span = document.createElement("span"); + span.style.fontFamily = "NonameSuits"; + span.textContent = "🎲"; + return span.outerHTML; + } + }], + ["SP", { + getSpan: () => { + const span = document.createElement("span"), style = span.style; + style.writingMode = style.webkitWritingMode = "horizontal-tb"; + style.fontFamily = "MotoyaLMaru"; + style.transform = "scaleY(0.85)"; + span.textContent = "SP"; + return span.outerHTML; + }, + }], + ["OL", { + getSpan: () => { + const span = document.createElement("span"), style = span.style; + style.writingMode = style.webkitWritingMode = "horizontal-tb"; + style.fontFamily = "MotoyaLMaru"; + style.transform = "scaleY(0.85)"; + span.textContent = "OL"; + return span.outerHTML; + }, + }], + ["RE", { + getSpan: () => { + const span = document.createElement("span"), style = span.style; + style.writingMode = style.webkitWritingMode = "horizontal-tb"; + style.fontFamily = "MotoyaLMaru"; + style.transform = "scaleY(0.85)"; + span.textContent = "RE"; + return span.outerHTML; + }, + }], + ["手杀", { + getSpan: (prefix, name) => { + const simple = configuration.buttoncharacter_prefix == "simple", span = document.createElement("span"); + if (characterPack.shiji && name in characterPack.shiji) { + for (const entry of Object.entries(characterSort.shiji)) { + if (!entry[1].includes(name)) continue; + prefix = Get.translation(entry[0]).slice(-1); + break; + } + if (!simple) { + span.style.color = "#def7ca"; + span.dataset.nature = "watermm"; + } + span.innerHTML = prefix; + } + else if (simple) span.textContent = "手杀"; + else { + span.style.fontFamily = "NonameSuits"; + span.textContent = "📱"; + } + return span.outerHTML; + }, + }], + ["TW", { + getSpan: () => { + const span = document.createElement("span"), style = span.style; + style.writingMode = style.webkitWritingMode = "horizontal-tb"; + style.fontFamily = "MotoyaLMaru"; + style.transform = "scaleY(0.85)"; + span.textContent = "TW"; + return span.outerHTML; + }, + }], + ["TW神", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("TW")}${Get.prefixSpan("神")}` + }], + ["TW将", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("TW")}${Get.prefixSpan("将")}` + }], + ["OL神", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("OL")}${Get.prefixSpan("神")}` + }], + ["旧神", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("旧")}${Get.prefixSpan("神")}` + }], + ["旧晋", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("旧")}${Get.prefixSpan("晋")}` + }], + ["新杀SP", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("新杀")}${Get.prefixSpan("SP")}` + }], + ["界SP", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("界")}${Get.prefixSpan("SP")}` + }], + ["S特神", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("★")}${Get.prefixSpan("神")}` + }], + ["手杀界", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("手杀")}${Get.prefixSpan("界")}` + }], + ["战役篇神", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("战役篇")}${Get.prefixSpan("神")}` + }], + ["星", { + color: "#ffd700", + nature: "glodenmm", + }], + ["OL界", { + /** + * @returns {string} + */ + getSpan: () => `${Get.prefixSpan("OL")}${Get.prefixSpan("界")}` + }] + ]); + static groupnature = groupNature; + static lineColor = new Map([ + ["fire", [255, 146, 68]], + ["yellow", [255, 255, 122]], + ["blue", [150, 202, 255]], + ["green", [141, 255, 216]], + ["ice", [59, 98, 115]], + ["thunder", [141, 216, 255]], + ["kami", [90, 118, 99]], + ["white", [255, 255, 255]], + ["poison", [104, 221, 127]], + ["brown", [195, 161, 223]], + ["legend", [233, 131, 255]] + ]); + static phaseName = ["phaseZhunbei", "phaseJudge", "phaseDraw", "phaseUse", "phaseDiscard", "phaseJieshu"]; + static quickVoice = [ + "我从未见过如此厚颜无耻之人!", + "这波不亏", + "请收下我的膝盖", + "你咋不上天呢", + "放开我的队友,冲我来", + "你随便杀,闪不了算我输", + "见证奇迹的时刻到了", + "能不能快一点啊,兵贵神速啊", + "主公,别开枪,自己人", + "小内再不跳,后面还怎么玩儿啊", + "你们忍心,就这么让我酱油了?", + "我,我惹你们了吗", + "姑娘,你真是条汉子", + "三十六计,走为上,容我去去便回", + "人心散了,队伍不好带啊", + "昏君,昏君啊!", + "风吹鸡蛋壳,牌去人安乐", + "小内啊,您老悠着点儿", + "不好意思,刚才卡了", + "你可以打得再烂一点吗", + "哥们,给力点儿行嘛", + "哥哥,交个朋友吧", + "妹子,交个朋友吧", + ]; + static other = Other; + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static listenEnd(node) { + if (!node._listeningEnd) { + node._listeningEnd = true; + node.listenTransition(function () { + delete node._listeningEnd; + if (node._onEndMoveDelete) { + node.moveDelete(node._onEndMoveDelete); + } + else if (node._onEndDelete) { + node.delete(); + } + node._transitionEnded = true; + }); + } + } + + static getErrorTip(msg) { + if (typeof msg != "string") { + try { + msg = msg.toString(); + if (typeof msg != "string") throw "err"; + } catch (_) { + throw `传参错误:${msg}`; + } + } + if (msg.startsWith("Uncaught ")) msg = msg.slice(9); + let newMessage = msg; + if (/RangeError/.test(newMessage)) { + if (newMessage.includes("Maximum call stack size exceeded")) { + newMessage = "堆栈溢出"; + } else if (/argument must be between 0 and 20/.test(newMessage)) { + let funName = newMessage.slice(newMessage.indexOf("RangeError: ") + 12, newMessage.indexOf(")") + 1); + newMessage = funName + "参数必须在0和20之间"; + } else { + newMessage = "传递错误值到数值计算方法"; + } + } else if (/ReferenceError/.test(newMessage)) { + let messageName; + if (newMessage.includes("is not defined")) { + messageName = newMessage.replace("ReferenceError: ", "").replace(" is not defined", ""); + newMessage = "引用了一个未定义的变量:" + messageName; + } else if (newMessage.includes("invalid assignment left-hand side")) { + newMessage = "赋值运算符或比较运算符不匹配"; + } else if (newMessage.includes("Octal literals are not allowed in strict mode")) { + newMessage = "八进制字面量与八进制转义序列语法已经被废弃"; + } else if (newMessage.includes("Illegal \x27use strict\x27 directive in function with non-simple parameter list")) { + newMessage = "\x27use strict\x27指令不能使用在带有‘非简单参数’列表的函数"; + } else if (newMessage.includes("Invalid left-hand side in assignment")) { + newMessage = "赋值中的左侧无效,即number,string等不可赋值的非变量数据"; + } + } else if (/SyntaxError/.test(newMessage)) { + let messageName; + if (newMessage.includes("Unexpected token ")) { + messageName = newMessage.replace("SyntaxError: Unexpected token ", ""); + newMessage = "使用了未定义或错误的语法 : (" + messageName + ")"; + } else if (newMessage.includes( + "Block-scoped declarations (let, const, function, class) not yet supported outside strict mode")) { + newMessage = "请在严格模式下运行let,const,class"; + } else if (newMessage.includes("for-of loop variable declaration may not have an initializer.")) { + newMessage = "for...of 循环的头部包含有初始化表达式"; + } else if (newMessage.includes("for-in loop variable declaration may not have an initializer.")) { + newMessage = "for...in 循环的头部包含有初始化表达式"; + } else if (newMessage.includes("Delete of an unqualified identifier in strict mode.")) { + newMessage = "普通变量不能通过 delete 操作符来删除"; + } else if (newMessage.includes("Unexpected identifier")) { + newMessage = "不合法的标识符或错误的语法"; + } else if (newMessage.includes("Invalid or unexpected token")) { + newMessage = "非法的或者不期望出现的标记符号出现在不该出现的位置"; + } else if (newMessage.includes("Invalid regular expression flags")) { + newMessage = "无效的正则表达式的标记"; + } else if (newMessage.includes("missing ) after argument list")) { + newMessage = "参数列表后面缺少“)” (丢失运算符或者转义字符等)"; + } else if (newMessage.includes("Invalid shorthand property initializer")) { + newMessage = "在定义一个{}对象时,应该使用“:”而不是“=”"; + } else if (newMessage.includes("Missing initializer in const declaration")) { + newMessage = "在使用const定义一个对象时,必须指定初始值"; + } else if (newMessage.includes("Unexpected number") || newMessage.includes("Unexpected string")) { + newMessage = "在定义函数时,函数参数必须为合法标记符"; + } else if (newMessage.includes("Unexpected end of input")) { + newMessage = "遗漏了符号或符号顺序不对(小括号,花括号等)"; + } else if (newMessage.includes("has already been declared")) { + messageName = newMessage.replace("SyntaxError: Identifier ", "").replace(" has already been declared", ""); + newMessage = messageName + "变量已经被声明过,不能被重新声明"; + } else if (newMessage.includes("Duplicate parameter name not allowed in this context")) { + newMessage = "参数名不允许重复"; + } else if (newMessage.includes("Unexpected reserved word") || newMessage.includes( + "Unexpected strict mode reserved word")) { + newMessage = "保留字被用作标记符"; + } + } else if (/TypeError/.test(newMessage)) { + let messageName; + if (newMessage.includes(" is not a function")) { + messageName = newMessage.replace("TypeError: ", "").replace(" is not a function", ""); + newMessage = messageName + "不是一个函数"; + } else if (newMessage.includes(" is not a constructor")) { + messageName = newMessage.replace("TypeError: ", "").replace(" is not a constructor", ""); + newMessage = messageName + "不是一个构造函数"; + } else if (newMessage.includes("Cannot read property")) { + messageName = newMessage.replace("TypeError: Cannot read property ", "").replace(" of null", "").replace(" of undefined", ""); + let ofName = newMessage.slice(newMessage.indexOf(" of ") + 4); + newMessage = `无法读取“${ofName}”的属性值${messageName}`; + } else if (newMessage.includes("Cannot read properties")) { + messageName = newMessage.slice(newMessage.indexOf("reading \x27") + 9, -2); + let ofName = newMessage.slice(newMessage.indexOf(" of ") + 4, newMessage.indexOf("(") - 1); + newMessage = `无法读取“${ofName}”的属性值${messageName}`; + } else if (newMessage.includes("Property description must be an object")) { + messageName = newMessage.replace("TypeError: Property description must be an object: ", ""); + newMessage = messageName + "是非对象类型的值"; + } else if (newMessage.includes("Cannot assign to read only property ")) { + messageName = newMessage.slice(47, newMessage.lastIndexOf(" of ") + 1); + newMessage = messageName + "属性禁止写入"; + } else if (newMessage.includes("Object prototype may only be an Object or null")) { + newMessage = messageName + "对象原型只能是对象或null"; + } else if (newMessage.includes("Cannot create property")) { + messageName = newMessage.slice(newMessage.indexOf("\x27") + 1); + messageName = messageName.slice(0, messageName.indexOf("\x27")); + let obj = newMessage.slice(newMessage.indexOf(messageName) + 16); + newMessage = `${obj}不能添加或修改“${messageName}”属性,任何 Primitive 值都不允许有property`; + } else if (newMessage.includes("Can\x27t add property") && newMessage.includes("is not extensible")) { + newMessage = "对象不可添加属性(不可扩展)"; + } else if (newMessage.includes("Cannot redefine property")) { + messageName = newMessage.slice(37); + newMessage = messageName + "不可配置"; + } else if (newMessage.includes("Converting circular structure to JSON")) { + messageName = newMessage.slice(37); + newMessage = "JSON.stringify() 方法处理循环引用结构的JSON会失败"; + } else if (newMessage.includes("Cannot use \x27in\x27 operator to search for ")) { + newMessage = "in不能用来在字符串、数字或者其他基本类型的数据中进行检索"; + } else if (newMessage.includes("Right-hand side of \x27instanceof\x27 is not an object")) { + newMessage = "instanceof 操作符 希望右边的操作数为一个构造对象,即一个有 prototype 属性且可以调用的对象"; + } else if (newMessage.includes("Assignment to constant variable")) { + newMessage = "const定义的变量不可修改"; + } else if (newMessage.includes("Cannot delete property")) { + newMessage = "不可配置的属性不能删除"; + } else if (newMessage.includes("which has only a getter")) { + newMessage = "仅设置了getter特性的属性不可被赋值"; + } else if (newMessage.includes("called on incompatible receiver undefined")) { + newMessage = "this提供的绑定对象与预期的不匹配"; + } + } else if (/URIError/.test(newMessage)) { + newMessage = "一个不合法的URI"; + } else if (/EvalError/.test(newMessage)) { + newMessage = "非法调用 eval()"; + } else if (/InternalError/.test(newMessage)) { + if (newMessage.includes("too many switch cases")) { + newMessage = "过多case子句"; + } else if (newMessage.includes("too many parentheses in regular expression")) { + newMessage = "正则表达式中括号过多"; + } else if (newMessage.includes("array initializer too large")) { + newMessage = "超出数组大小的限制"; + } else if (newMessage.includes("too much recursion")) { + newMessage = "递归过深"; + } + } + if (newMessage != msg) { + return newMessage; + } + } + + static codeMirrorReady(node, editor) { + UI.window.appendChild(node); + node.style.fontSize = `${20 / Game.documentZoom}px`; + const mirror = window.CodeMirror(editor, { + value: node.code, + mode: "javascript", + lineWrapping: !configuration.touchscreen && configuration.mousewheel, + lineNumbers: true, + indentUnit: 4, + autoCloseBrackets: true, + fixedGutter: false, + hintOptions: { completeSingle: false }, + theme: configuration.codeMirror_theme || "mdn-like", + extraKeys: { + "Ctrl-Z": "undo",//撤销 + "Ctrl-Y": "redo",//恢复撤销 + //"Ctrl-A":"selectAll",//全选 + }, + }); + InternalLibrary.setScroll(editor.querySelector(".CodeMirror-scroll")); + node.aced = true; + node.editor = mirror; + setTimeout(() => mirror.refresh(), 0); + node.editor.on("change", (e, change) => { + let code; + if (node.editor) { + code = node.editor.getValue(); + } else if (node.textarea) { + code = node.textarea.value; + } + //动态绑定文本 + if (code.length && change.origin == "+input" && + /{|}|\s|=|;|:|,|,|。|?|!|!|\?|&|#|%|@|‘|’|;/.test(change.text[0]) == false && + change.text.length == 1) { + //输入了代码,并且不包括空格,{},=, ; , : , 逗号等,才可以自动提示 + node.editor.showHint(); + } + }); + //防止每次输出字符都创建以下元素 + const event = status.event; + const trigger = status.event; + const player = Create.player().init("sunce"); + const target = player; + const targets = [player]; + const source = player; + const card = Game.createCard(); + const cards = [card]; + const result = { bool: true }; + function forEach(arr, f) { + Array.from(arr).forEach(v => f(v)); + } + function forAllProps(obj, callback) { + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (let name in obj) callback(name); + } else { + for (let o = obj; o; o = Object.getPrototypeOf(o)) Object.getOwnPropertyNames(o).forEach(callback); + } + } + function scriptHint(editor, keywords, getToken, options) { + //Find the token at the cursor + let cur = editor.getCursor(), token = editor.getTokenAt(cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + const innerMode = CodeMirror.innerMode(editor.getMode(), token.state); + if (innerMode.mode.helperType === "json") return; + token.state = innerMode.state; + //If it’s not a “word-style” token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = { + start: cur.ch, + end: cur.ch, + string: "", + state: token.state, + type: token.string == "." ? "property" : null + }; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + let tprop = token, context; + //If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = editor.getTokenAt(CodeMirror.Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = editor.getTokenAt(CodeMirror.Pos(cur.line, tprop.start)); + if (!context) context = []; + context.push(tprop); + } + const list = []; + let obj; + if (Array.isArray(context)) { + try { + const code = context.length == 1 ? context[0].string : context.reduceRight((pre, cur) => `${pre.string || pre}.${cur.string}`); + obj = eval(code); + if (![null, undefined].includes(obj)) { + const keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(obj))).filter(key => key.startsWith(token.string)); + list.addArray(keys); + } + } catch (_) { return; } + } else if (token && typeof token.string == "string") { + //非开发者模式下,提示这些单词 + list.addArray(["player", "card", "cards", "result", "trigger", "source", "target", "targets", "lib", "game", "ui", "get", "ai", "_status"]); + } + return { + list: [...new Set(getCompletions(token, context, keywords, options).concat(list))] + .filter(key => key.startsWith(token.string)) + .sort((a, b) => `${a}`.localeCompare(`${b}`)) + .map(text => { + return { + render(elt, data, cur) { + var icon = document.createElement("span"); + var className = "cm-completionIcon cm-completionIcon-"; + if (obj) { + const type = typeof obj[text]; + if (type == "function") { + className += "function"; + } + else if (type == "string") { + className += "text"; + } + else if (type == "boolean") { + className += "variable"; + } + else { + className += "namespace"; + } + } else { + if (javascriptKeywords.includes(text)) { + className += "keyword"; + } + else if (window[text]) { + const type = typeof window[text]; + if (type == "function") { + className += "function"; + } + else if (type == "string") { + className += "text"; + } + else if (text == "window" || type == "boolean") { + className += "variable"; + } + else { + className += "namespace"; + } + } else { + className += "namespace"; + } + } + icon.className = className; + elt.appendChild(icon); + elt.appendChild(document.createTextNode(text)); + }, + displayText: text, + text: text, + } + }), + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + } + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, function (e, cur) { return e.getTokenAt(cur); }, options); + } + //覆盖原本的javascript提示 + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + const stringProps = Object.getOwnPropertyNames(String.prototype); + const arrayProps = Object.getOwnPropertyNames(Array.prototype); + const funcProps = Object.getOwnPropertyNames(Array.prototype); + const javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends from false finally for function " + + "if in import instanceof let new null return super switch this throw true try typeof var void while with yield").split(" "); + function getCompletions(token, context, keywords, options) { + let found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !found.includes(str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd); + } + if (context && context.length) { + //If this is a property, see if it belongs to some object we can + //find in the current environment. + let obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == "$" || obj.string == "jQuery") && (typeof global.jQuery == "function")) + base = global.jQuery(); + else if (global._ != null && (obj.string == "_") && (typeof global._ == "function")) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + //If not, just look in the global object, any local scope, and optional additional-context + //(reading into JS mode internals to get at the local and global variables) + for (let v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (let c = token.state.context; c; c = c.prev) for (let v = c.vars; v; v = v.next) maybeAdd(v.name) + for (let v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (options && options.additionalContext != null) for (let key in options.additionalContext) maybeAdd(key); + if (!options || options.useGlobalScope !== false) gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found.sort((a, b) => `${a}`.localeCompare(`${b}`)); + } + } + + static setIntro(node, func, left) { + if (configuration.touchscreen) { + if (left) { + node.listen(Click.touchintro); + } + else { + InternalLibrary.setLongPress(node, Click.intro); + } + } + else { + if (left) { + node.listen(Click.intro); + } + if (configuration.hover_all && !InternalLibrary.device) { + InternalLibrary.setHover(node, Click.hoverplayer); + } + if (configuration.right_info) { + node.oncontextmenu = Click.rightplayer; + } + } + if (func) { + node._customintro = func; + } + } + + static setPopped(node, func, width, height, forceclick, paused2) { + node._poppedfunc = func; + node._poppedwidth = width; + node._poppedheight = height; + if (forceclick) { + node.forceclick = true; + } + if (configuration.touchscreen || forceclick) { + node.listen(Click.hoverpopped); + } + else { + node.addEventListener("mouseenter", Click.hoverpopped); + } + if (paused2) { + node._paused2 = true; + } + } + + static placePoppedDialog(dialog, e) { + if (dialog._place_text) { + if (dialog._place_text.firstChild.offsetWidth >= 190 || dialog._place_text.firstChild.offsetHeight >= 30) { + dialog._place_text.style.marginLeft = "14px"; + dialog._place_text.style.marginRight = "14px"; + dialog._place_text.style.textAlign = "left"; + dialog._place_text.style.width = "calc(100% - 28px)"; + } + } + if (e.touches && e.touches[0]) { + e = e.touches[0]; + } + var height = Math.min(UI.window.offsetHeight - 20, dialog.content.scrollHeight); + if (dialog._mod_height) { + height += dialog._mod_height; + } + dialog.style.height = `${height}px`; + if (e.clientX / Game.documentZoom < UI.window.offsetWidth / 2) { + dialog.style.left = `${e.clientX / Game.documentZoom + 10}px`; + } + else { + dialog.style.left = `${e.clientX / Game.documentZoom - dialog.offsetWidth - 10}px`; + } + var idealtop = (e.clientY || 0) / Game.documentZoom - dialog.offsetHeight / 2; + if (typeof idealtop != "number" || isNaN(idealtop) || idealtop <= 5) { + idealtop = 5; + } + else if (idealtop + dialog.offsetHeight + 10 > UI.window.offsetHeight) { + idealtop = UI.window.offsetHeight - 10 - dialog.offsetHeight; + } + dialog.style.top = `${idealtop}px`; + } + + static setHover(node, func, hoveration, width) { + node._hoverfunc = func; + if (typeof hoveration == "number") { + node._hoveration = hoveration; + } + if (typeof width == "number") { + node._hoverwidth = width + } + node.addEventListener("mouseenter", Click.mouseenter); + node.addEventListener("mouseleave", Click.mouseleave); + node.addEventListener("mousedown", Click.mousedown); + node.addEventListener("mousemove", Click.mousemove); + return node; + } + + static setScroll(node) { + node.ontouchstart = Click.touchStart; + node.ontouchmove = Click.touchScroll; + node.style.webkitOverflowScrolling = "touch"; + return node; + } + + static setMousewheel(node) { + if (configuration.mousewheel) node.onmousewheel = Click.mousewheel; + } + + static setLongPress(node, func) { + node.addEventListener("touchstart", Click.longpressdown); + node.addEventListener("touchend", Click.longpresscancel); + node._longpresscallback = func; + return node; + } + + static updateCanvas(time) { + if (InternalLibrary.canvasUpdates.length === 0) { + internalStatus.canvas = false; + return false; + } + UI.canvas.width = UI.arena.offsetWidth; + UI.canvas.height = UI.arena.offsetHeight; + var ctx = UI.ctx; + ctx.shadowBlur = 5; + ctx.shadowColor = "rgba(0,0,0,0.3)"; + ctx.strokeStyle = "white"; + ctx.lineWidth = 3; + ctx.save(); + for (var i = 0; i < InternalLibrary.canvasUpdates.length; i++) { + ctx.restore(); + ctx.save(); + var update = InternalLibrary.canvasUpdates[i]; + if (!update.starttime) { + update.starttime = time; + } + if (update(time - update.starttime, ctx) === false) { + InternalLibrary.canvasUpdates.splice(i--, 1); + } + } + } + + static run(time) { + internalStatus.time = time; + for (var i = 0; i < InternalLibrary.updates.length; i++) { + if (!Object.prototype.hasOwnProperty.call(InternalLibrary.updates[i], "_time")) { + InternalLibrary.updates[i]._time = time; + } + if (InternalLibrary.updates[i](time - InternalLibrary.updates[i]._time - internalStatus.delayed) === false) { + InternalLibrary.updates.splice(i--, 1); + } + } + if (InternalLibrary.updates.length) { + internalStatus.frameId = requestAnimationFrame(InternalLibrary.run); + } + else { + internalStatus.time = 0; + internalStatus.delayed = 0; + } + } + + static getUTC(date) { + return date.getTime(); + } + + static saveVideo() { + if (status.videoToSave) { + Game.export(Initialization.encode(JSON.stringify(status.videoToSave)), + `无名杀 - 录像 - ${status.videoToSave.name[0]} - ${status.videoToSave.name[1]}`); + } + } + + static genAsync(fn) { + return GNC.of(fn); + } + + static genAwait(item) { + return GNC.isGenerator(item) ? GNC.of(function* () { + for (const content of item) { + yield content; + } + })() : Promise.resolve(item); + } +} diff --git a/noname/library/animate.js b/noname/library/animate.js new file mode 100644 index 000000000..7da77889e --- /dev/null +++ b/noname/library/animate.js @@ -0,0 +1,7 @@ +import { card } from "./animate/card.js"; +import { skill } from "./animate/skill.js"; + +export const animate = { + skill, + card +}; diff --git a/noname/library/animate/card.d.ts b/noname/library/animate/card.d.ts new file mode 100644 index 000000000..9ecf38bc7 --- /dev/null +++ b/noname/library/animate/card.d.ts @@ -0,0 +1,4 @@ +interface Card extends Record { +} + +export const card: Card; diff --git a/noname/library/animate/card.js b/noname/library/animate/card.js new file mode 100644 index 000000000..9dd692f57 --- /dev/null +++ b/noname/library/animate/card.js @@ -0,0 +1 @@ +export const card = {}; diff --git a/noname/library/animate/skill.d.ts b/noname/library/animate/skill.d.ts new file mode 100644 index 000000000..32ba7e50b --- /dev/null +++ b/noname/library/animate/skill.d.ts @@ -0,0 +1,4 @@ +interface Skill extends Record { +} + +export const skill: Skill; diff --git a/noname/library/animate/skill.js b/noname/library/animate/skill.js new file mode 100644 index 000000000..b5128ac48 --- /dev/null +++ b/noname/library/animate/skill.js @@ -0,0 +1 @@ +export const skill = {}; diff --git a/noname/library/announce.js b/noname/library/announce.js new file mode 100644 index 000000000..1e1c7c091 --- /dev/null +++ b/noname/library/announce.js @@ -0,0 +1,101 @@ + +/** + * **无名杀消息推送库** + * + * 通过`EventTarget`机制,实现消息推送和接收的解耦, + * 从而使消息接收方无需依赖发布方,发布方也无需考虑接收方 + * + * > `lib.announce`不是`actor`模型,若不存在订阅者,则消息发送将无意义 + * + * @example + * // 甲扩展(如《千幻聆音》)在角色皮肤切换后,调用: + * lib.announce.publish("skinChange", { + * player, + * playerName: "zhangfei", + * originSkin: "image/xxx.jpg", + * currentSkin: "image/yyy.jpg" + * }); + * + * // 乙扩展监听此`skinChange`事件,并修改自己扩展相关界面的图片: + * const method = lib.announce.subscribe("skinChange", (e) => { + * div.setBackgroundImage(e.currentSkin); + * }); + * + * // 若此时乙扩展不想继续订阅`skinChange`事件,可以通过`unsubscribe`解除订阅 + * lib.announce.unsubscribe("skinChange", method); + */ +export const announce = { + _announce: document.createElement("Announce"), + /** + * @type {Map<(values: T) => void, Map void>>} + */ + _announce_cache: new Map(), + /** + * 推送任意数据给所有监听了指定事件的订阅者,并返回给定的数据 + * + * 若不存在订阅指定事件的订阅者,则推送的数据将无意义 + * + * @template T + * @param {string} name - 要推送事件的名称 + * @param {T} values - 要推送的数据 + * @returns {T} + */ + publish(name, values) { + if (this._announce) this._announce.dispatchEvent(new CustomEvent(name, { + detail: values + })); + return values; + }, + /** + * 订阅给定名字的事件,并返回给定的函数 + * + * 在事件触发时执行给定的函数 + * + * 给定的函数将被存储至当前实例中,用于取消订阅时获取 + * + * @template T + * @param {string} name - 要订阅事件的名称 + * @param {(values: T) => void} method - 事件触发时执行的函数 + * @returns {(values: T) => void} + */ + subscribe(name, method) { + if (this._announce && this._announce_cache) { + let subscribeFunction; + if (this._announce_cache.has(method)) { + let records = this._announce_cache.get(method); + subscribeFunction = records.get("Listener"); + records.get("EventTargets").add(name); + } + else { + subscribeFunction = event => method(event.detail); + let records = new Map(); + records.set("Listener", subscribeFunction); + records.set("EventTargets", [name]); + this._announce_cache.set(method, records); + } + this._announce.addEventListener(name, subscribeFunction); + } + return method; + }, + /** + * 取消指定事件某一函数的订阅,并返回该函数 + * + * 给定的函数将不再于事件触发时执行,其余同事件需触发的函数不受限制 + * + * @template T + * @param {string} name - 要取消订阅事件的名称 + * @param {(values: T) => void} method - 订阅指定事件的函数 + * @returns {(values: T) => void} + */ + unsubscribe(name, method) { + if (this._announce && this._announce_cache && this._announce_cache.has(method)) { + let records = this._announce_cache.get(method); + const listener = records.get("Listener"); + let eventTargets = records.get("EventTargets"); + eventTargets.remove(name); + if (eventTargets.length <= 0) this._announce_cache.remove(method); + this._announce.removeEventListener(name, listener); + } + return method; + } +}; diff --git a/noname/library/card-pack.d.ts b/noname/library/card-pack.d.ts new file mode 100644 index 000000000..509a0f895 --- /dev/null +++ b/noname/library/card-pack.d.ts @@ -0,0 +1,4 @@ +interface CardPack extends Record { +} + +export const cardPack: CardPack; diff --git a/noname/library/card-pack.js b/noname/library/card-pack.js new file mode 100644 index 000000000..1ca34c63a --- /dev/null +++ b/noname/library/card-pack.js @@ -0,0 +1 @@ +export const cardPack = {}; diff --git a/noname/library/card-pile.js b/noname/library/card-pile.js new file mode 100644 index 000000000..f0ba7bfca --- /dev/null +++ b/noname/library/card-pile.js @@ -0,0 +1 @@ +export const cardPile = {}; diff --git a/noname/library/card-type.d.ts b/noname/library/card-type.d.ts new file mode 100644 index 000000000..3de15d929 --- /dev/null +++ b/noname/library/card-type.d.ts @@ -0,0 +1,4 @@ +interface CardType extends Record { +} + +export const cardType: CardType; diff --git a/noname/library/card-type.js b/noname/library/card-type.js new file mode 100644 index 000000000..b38a1eb64 --- /dev/null +++ b/noname/library/card-type.js @@ -0,0 +1 @@ +export const cardType = {}; diff --git a/noname/library/card.js b/noname/library/card.js new file mode 100644 index 000000000..06163d873 --- /dev/null +++ b/noname/library/card.js @@ -0,0 +1,93 @@ +export const card = { + list: [], + cooperation_damage: { + fullskin: true + }, + cooperation_draw: { + fullskin: true, + cardimage: "cooperation_damage" + }, + cooperation_discard: { + fullskin: true, + cardimage: "cooperation_damage" + }, + cooperation_use: { + fullskin: true, + cardimage: "cooperation_damage" + }, + pss_paper: { + type: "pss", + fullskin: true + }, + pss_scissor: { + type: "pss", + fullskin: true, + }, + pss_stone: { + type: "pss", + fullskin: true + }, + feichu_equip1: { + type: "equip", + subtype: "equip1" + }, + feichu_equip2: { + type: "equip", + subtype: "equip2" + }, + feichu_equip3: { + type: "equip", + subtype: "equip3" + }, + feichu_equip4: { + type: "equip", + subtype: "equip4" + }, + feichu_equip5: { + type: "equip", + subtype: "equip5" + }, + feichu_equip6: { + type: "equip", + subtype: "equip6" + }, + zhengsu_leijin: {}, + zhengsu_mingzhi: {}, + zhengsu_bianzhen: {}, + disable_judge: {}, + group_wei: { + fullskin: true + }, + group_shu: { + fullskin: true + }, + group_wu: { + fullskin: true + }, + group_qun: { + fullskin: true + }, + group_key: { + fullskin: true + }, + group_jin: { + fullskin: true + }, + + db_atk1: { + type: "db_atk", + fullimage: true + }, + db_atk2: { + type: "db_atk", + fullimage: true + }, + db_def1: { + type: "db_def", + fullimage: true + }, + db_def2: { + type: "db_def", + fullimage: true + } +}; diff --git a/noname/library/channel.js b/noname/library/channel.js new file mode 100644 index 000000000..3927f87ed --- /dev/null +++ b/noname/library/channel.js @@ -0,0 +1,98 @@ +/** + * **无名杀频道推送机制** + * + * 鉴于`Javascript`的特性及自身对所需功能的思考,这是一个参考`Golang`的`channel`设计的、完全和`go channel`不一样的异步消息传递对象 + * + * 当且仅当接收方和发送方均存在时进行消息传递,完全保证信息传递的单一性(发送方/接收方一旦确定则无法更改)和准确性(发送方必然将消息发送给接收方) + * + * 若存在发送方/接收方时调用`send`/`receive`,将报错 + * + * 若需要异步/不报错发送信息,请等待`lib.actor` + * + * @template T + * @example + * // 创建一个频道 + * const channel = new lib.channel(); + * + * // 从某个角落接收channel发出的消息,若无消息则等待 + * const message = await channel.receive(); + * + * // 从某个角落向channel发消息,若无消息接收则等待 + * await channel.send(item); + */ +export class Channel { + constructor() { + /** + * @type {"active" | "receiving" | "sending"} + */ + this.status = "active"; + + /** + * @type {import("./promise-resolve").PromiseResolve | [T, import("./promise-resolve").PromiseResolve] | null} + */ + this._buffer = null; + } + + /** + * 向该频道发送消息,在消息未被接受前将等待 + * + * @param {T} value - 要发送的消息 + * @returns {Promise} + */ + send(value) { + return new Promise((resolve, reject) => { + switch (this.status) { + case "sending": + // TODO: handle the error. + reject(new Error()); + break; + case "receiving": { + /** + * @type {import("./promise-resolve").PromiseResolve} + */ + const buffer = this._buffer; + this._buffer = null; + buffer(value); + this.status = "active"; + resolve(); + break; + } + case "active": + this.status = "sending"; + this._buffer = [value, resolve]; + break; + } + }); + } + + /** + * 接收频道所发送的消息,若无消息发送则等待 + * + * @returns {Promise} 接收到的消息 + */ + receive() { + return new Promise((resolve, reject) => { + switch (this.status) { + case "receiving": + // TODO: handle the error. + reject(new Error()); + break; + case "sending": { + /** + * @type {[T, import("./promise-resolve").PromiseResolve]} + */ + const buffer = this._buffer; + this._buffer = null; + resolve(buffer[0]); + this.status = "active"; + buffer[1](); + break; + } + case "active": + this.status = "receiving"; + this._buffer = resolve; + break; + } + }); + } +} diff --git a/noname/library/character-dialog-group.js b/noname/library/character-dialog-group.js new file mode 100644 index 000000000..a4ed6040a --- /dev/null +++ b/noname/library/character-dialog-group.js @@ -0,0 +1,17 @@ +import { Get } from "../get.js"; +import { configuration } from "./configuration.js"; + +export class CharacterDialogGroup { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static 收藏(name, capt) { + return configuration.favouriteCharacter.includes(name) ? capt : null; + } + + static 最近(name, capt) { + var list = Get.config("recentCharacter") || []; + return list.includes(name) ? capt : null; + } +} diff --git a/noname/library/character-filter.d.ts b/noname/library/character-filter.d.ts new file mode 100644 index 000000000..8385e0654 --- /dev/null +++ b/noname/library/character-filter.d.ts @@ -0,0 +1,4 @@ +interface CharacterFilter extends Record boolean> { +} + +export const characterFilter: CharacterFilter; diff --git a/noname/library/character-filter.js b/noname/library/character-filter.js new file mode 100644 index 000000000..c83393b66 --- /dev/null +++ b/noname/library/character-filter.js @@ -0,0 +1 @@ +export const characterFilter = {}; diff --git a/noname/library/character-information.ts b/noname/library/character-information.ts new file mode 100644 index 000000000..5457cce90 --- /dev/null +++ b/noname/library/character-information.ts @@ -0,0 +1,4 @@ +type CharacterSex = "double" | "female" | "male" | "none" | "unknown" | string & {}; +type CharacterGroup = "wei" | "shu" | "wu" | "qun" | "jin"; +type CharacterHP = number | `${number}/${number}` | `${number}/${number}/${number}`; +export type CharacterInformation = [CharacterSex, CharacterGroup, CharacterHP, string[], string[]?]; diff --git a/noname/library/character-intro.d.ts b/noname/library/character-intro.d.ts new file mode 100644 index 000000000..1240bf057 --- /dev/null +++ b/noname/library/character-intro.d.ts @@ -0,0 +1,4 @@ +interface CharacterIntro extends Record { +} + +export const characterIntro: CharacterIntro; diff --git a/noname/library/character-intro.js b/noname/library/character-intro.js new file mode 100644 index 000000000..5e82988b8 --- /dev/null +++ b/noname/library/character-intro.js @@ -0,0 +1 @@ +export const characterIntro = {}; diff --git a/noname/library/character-pack.d.ts b/noname/library/character-pack.d.ts new file mode 100644 index 000000000..42ef4b35f --- /dev/null +++ b/noname/library/character-pack.d.ts @@ -0,0 +1,6 @@ +import { CharacterInformation } from "./character-information.js"; + +interface CharacterPack extends Record> { +} + +export const characterPack: CharacterPack; diff --git a/noname/library/character-pack.js b/noname/library/character-pack.js new file mode 100644 index 000000000..5c62945fc --- /dev/null +++ b/noname/library/character-pack.js @@ -0,0 +1 @@ +export const characterPack = {}; diff --git a/noname/library/character-replace.d.ts b/noname/library/character-replace.d.ts new file mode 100644 index 000000000..9877858a6 --- /dev/null +++ b/noname/library/character-replace.d.ts @@ -0,0 +1,4 @@ +interface CharacterReplace extends Record { +} + +export const characterReplace: CharacterReplace; diff --git a/noname/library/character-replace.js b/noname/library/character-replace.js new file mode 100644 index 000000000..0b94a222e --- /dev/null +++ b/noname/library/character-replace.js @@ -0,0 +1 @@ +export const characterReplace = {}; diff --git a/noname/library/character-sort.d.ts b/noname/library/character-sort.d.ts new file mode 100644 index 000000000..efe385632 --- /dev/null +++ b/noname/library/character-sort.d.ts @@ -0,0 +1,4 @@ +interface CharacterSort extends Record> { +} + +export const characterSort: CharacterSort; diff --git a/noname/library/character-sort.js b/noname/library/character-sort.js new file mode 100644 index 000000000..4728ab53a --- /dev/null +++ b/noname/library/character-sort.js @@ -0,0 +1 @@ +export const characterSort = {}; diff --git a/noname/library/character-title.d.ts b/noname/library/character-title.d.ts new file mode 100644 index 000000000..3942841b9 --- /dev/null +++ b/noname/library/character-title.d.ts @@ -0,0 +1,4 @@ +interface CharacterTitle extends Record { +} + +export const characterTitle: CharacterTitle; diff --git a/noname/library/character-title.js b/noname/library/character-title.js new file mode 100644 index 000000000..12e7faed4 --- /dev/null +++ b/noname/library/character-title.js @@ -0,0 +1 @@ +export const characterTitle = {}; diff --git a/noname/library/character.js b/noname/library/character.js new file mode 100644 index 000000000..111324fc9 --- /dev/null +++ b/noname/library/character.js @@ -0,0 +1 @@ +export const character = {}; diff --git a/noname/library/cheat.js b/noname/library/cheat.js new file mode 100644 index 000000000..8ac06961d --- /dev/null +++ b/noname/library/cheat.js @@ -0,0 +1,693 @@ +export class Cheat { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static i() { + window.cheat = lib.cheat; + window.game = game; + window.ui = ui; + window.get = get; + window.ai = ai; + window.lib = lib; + window._status = _status; + } + + static dy() { + var next = game.me.next; + for (var i = 0; i < 10; i++) { + if (next.identity != "zhu") { + break; + } + next = next.next; + } + next.die(); + } + + static x() { + var gl = function (dir, callback) { + var files = [], folders = []; + dir = "/Users/widget/Documents/extension/" + dir; + lib.node.fs.readdir(dir, function (err, filelist) { + for (var i = 0; i < filelist.length; i++) { + if (filelist[i][0] != "." && filelist[i][0] != "_") { + if (lib.node.fs.statSync(dir + "/" + filelist[i]).isDirectory()) { + folders.push(filelist[i]); + } + else { + files.push(filelist[i]); + } + } + } + callback(folders, files); + }); + } + var args = Array.from(arguments); + for (var i = 0; i < args.length; i++) { + args[i] = args[i][0]; + } + gl("", function (list) { + if (args.length) { + for (var i = 0; i < list.length; i++) { + if (!args.contains(list[i][0])) { + list.splice(i--, 1); + } + } + } + if (list.length) { + for (var i = 0; i < list.length; i++) { + (function (str) { + gl(str, function (folders, files) { + if (files.length > 1) { + for (var i = 0; i < files.length; i++) { + if (files[i].includes("extension.js")) { + files.splice(i--, 1); + } + else { + if (i % 5 == 0) { + str += "\n\t\t\t"; + } + str += `"${files[i]}",`; + } + } + console.log(str.slice(0, str.length - 1)); + } + }); + }(list[i])); + } + } + }); + } + + static cfg() { + var mode = lib.config.all.mode.slice(0); + mode.remove("connect"); + mode.remove("brawl"); + var banned = ["shen_guanyu", "shen_caocao", "caopi", "re_daqiao", "caorui", + "daqiao", "lingcao", "liuzan", "lusu", "luxun", "yanwen", "zhouyu", "ns_wangyue", "gw_yenaifa", + "old_caozhen", "swd_jiangziya", "xuhuang", "maliang", "guojia", "simayi", "swd_kangnalishi", "hs_siwangzhiyi", "hs_nozdormu", "old_zhuzhi"]; + var bannedcards = ["zengbin"]; + var favs = ["hs_tuoqi", "hs_siwangxianzhi", "hs_xukongzhiying", "hs_hsjiasha", "gjqt_xieyi", "gjqt_yunwuyue", "gjqt_beiluo", + "gjqt_cenying", "shen_lvmeng", "shen_zhaoyun", "shen_zhugeliang", "ow_ana", "chenlin", "ns_guanlu", "hs_guldan", "swd_guyue", + "pal_jiangyunfan", "mtg_jiesi", "swd_lanyin", "pal_liumengli", "swd_muyun", "pal_nangonghuang", "swd_muyue", "pal_murongziying", + "swd_qiner", "pal_shenqishuang", "hs_taisi", "wangji", "pal_xingxuan", "xunyou", "hs_yelise", "pal_yuejinzhao", "pal_yueqi", + "gjqt_yuewuyi", "swd_yuxiaoxue", "ow_zhaliya", "zhangchunhua", "hs_zhihuanhua", "swd_zhiyin", "old_zhonghui", "gjqt_bailitusu", + "hs_barnes", "ow_dva", "swd_hengai", "pal_jushifang", "hs_kazhakusi", "hs_lafamu", "ow_liekong", "hs_lreno", "pal_mingxiu", + "swd_murongshi", "gw_oudimu", "gjqt_ouyangshaogong", "hs_pyros", "qinmi", "gw_sanhanya", "hs_selajin", "swd_shuwaner", + "swd_situqiang", "hs_xialikeer", "pal_xuejian", "swd_yuchiyanhong", "swd_yuwentuo", "swd_zhaoyun", "zhugeliang", "gw_aigeleisi", + "gw_aimin", "gjqt_aruan", "hs_aya", "swd_cheyun", "swd_chenjingchou", "gw_diandian", "swd_huzhongxian", "hs_jinglinglong", + "hs_kaituozhe", "hs_kalimosi", "gw_linjing", "ow_luxiao", "re_luxun", "hs_morgl", "swd_sikongyu", "hs_sthrall", "sunquan", + "sunshangxiang", "gw_yioufeisisp", "gw_yisilinni", "hs_yogg", "hs_ysera", "pal_yuntianhe", "zhugejin", "zhugeke", "gw_zhuoertan", + "hs_anduin", "swd_anka", "ow_banzang", "ow_chanyata", "diaochan", "swd_duguningke", "sp_diaochan", "hetaihou", "ns_huamulan", + "swd_huanglei", "swd_huanyuanzhi", "re_huatuo", "gw_huoge", "pal_jiangcheng", "yj_jushou", "swd_kendi", "yxs_libai", + "mtg_lilianna", "xin_liru", "liuxie", "pal_lixiaoyao", "pal_longkui", "ns_nanhua", "swd_qi", "swd_septem", "gw_shasixiwusi", + "ow_tianshi", "swd_weida", "gjqt_xiayize", "swd_xiyan", "hs_xsylvanas", "hs_yelinlonghou", "ow_yuanshi", "zuoci"]; + var vintage = ["tianjian", "shuiyun", "zhuyue", "zhimeng", "poyun", "qianfang", "xfenxin", "danqing", "ywuhun", "tianwu", "xuelu", + "shahun", "yuling", "duhun", "liaoyuan", "touxi", "wangchen", "poyue", "kunlunjing", "huanhun", "yunchou", "tuzhen", "cyqiaoxie", + "mufeng", "duanyi", "guozao", "yaotong", "pozhen", "tanlin", "susheng", "jikong", "shouyin", "jilve", "hxunzhi", "huodan", "shanxian", + "ziyu", "kuoyin", "feiren", "zihui", "jidong", "baoxue", "aqianghua", "maoding", "bfengshi", "zhongdun", "pingzhang", "maichong", + "guozai", "jingxiang", "yuelu", "liechao", "fengnu", "hanshuang", "enze", "malymowang", "xshixin", "qingzun"]; + var favmodes = ["versus|three", "versus|four", "versus|two", "chess|combat"]; + for (var i = 0; i < mode.length; i++) { + game.saveConfig(mode[i] + "_banned", banned); + game.saveConfig(mode[i] + "_bannedcards", bannedcards); + } + var characters = lib.config.all.characters.slice(0); + characters.remove("standard"); + characters.remove("old"); + game.saveConfig("vintageSkills", vintage); + game.saveConfig("favouriteCharacter", favs); + game.saveConfig("favouriteMode", favmodes); + game.saveConfig("theme", "simple"); + game.saveConfig("player_border", "slim"); + game.saveConfig("cards", lib.config.all.cards); + game.saveConfig("characters", characters); + game.saveConfig("change_skin", false); + game.saveConfig("show_splash", "off"); + game.saveConfig("show_favourite", false); + game.saveConfig("animation", false); + game.saveConfig("hover_all", false); + game.saveConfig("asset_version", "v1.9"); + // game.saveConfig("characters",lib.config.all.characters); + // game.saveConfig("cards",lib.config.all.cards); + game.saveConfig("plays", ["cardpile"]); + game.saveConfig("skip_shan", false); + game.saveConfig("tao_enemy", true); + game.saveConfig("layout", "long2"); + game.saveConfig("hp_style", "ol"); + game.saveConfig("background_music", "music_off"); + game.saveConfig("background_audio", false); + game.saveConfig("background_speak", false); + game.saveConfig("show_volumn", false); + game.saveConfig("show_replay", true); + game.saveConfig("autostyle", true); + game.saveConfig("debug", true); + game.saveConfig("dev", true); + if (!lib.device) { + game.saveConfig("sync_speed", false); + } + game.reload(); + } + + static o() { + ui.arena.classList.remove("observe"); + } + + static pt() { + var list = Array.from(arguments); + while (list.length) { + var card = cheat.gn(list.pop()); + if (card) ui.cardPile.insertBefore(card, ui.cardPile.firstChild); + } + } + + static q() { + if (arguments.length == 0) { + var style = ui.css.card_style; + if (lib.config.card_style != "simple") { + lib.config.card_style = "simple"; + ui.css.card_style = lib.init.css(lib.assetURL + "theme/style/card", "simple"); + } + else { + lib.config.card_style = "default"; + ui.css.card_style = lib.init.css(lib.assetURL + "theme/style/card", "default"); + } + style.remove(); + } + else { + for (var i = 0; i < arguments.length; i++) { + cheat.g(arguments[i]); + } + } + ui.arena.classList.remove("selecting"); + ui.arena.classList.remove("tempnoe"); + } + + static p(name, i, skin) { + var list = ["swd", "hs", "pal", "gjqt", "ow", "gw"]; + if (!lib.character[name]) { + for (var j = 0; j < list.length; j++) { + if (lib.character[list[j] + "_" + name]) { + name = list[j] + "_" + name; break; + } + } + } + if (skin) { + lib.config.skin[name] = skin + } + var target; + if (typeof i == "number") { + target = game.players[i]; + } + else { + target = game.me.next; + } + if (!lib.character[name]) { + target.node.avatar.setBackground(name, "character"); + target.node.avatar.show(); + } + else { + target.init(name); + } + if (i === true) { + if (lib.config.layout == "long2") { + lib.init.layout("mobile"); + } + else { + lib.init.layout("long2"); + } + } + } + + static e() { + var cards = [], target; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + target = arguments[i]; + } + else { + cards.push(game.createCard(arguments[i])); + } + } + if (!cards.length) { + cards.push(game.createCard("qilin")); + cards.push(game.createCard("bagua")); + cards.push(game.createCard("dilu")); + cards.push(game.createCard("chitu")); + cards.push(game.createCard("muniu")); + } + target = target || game.me; + for (var i = 0; i < cards.length; i++) { + var card = target.getEquip(cards[i]); + if (card) { + card.discard(); + target.removeEquipTrigger(card); + } + target.$equip(cards[i]); + } + } + + static c() { + (function () { + var a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0; + var sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0; + for (var i in lib.character) { + switch (lib.character[i][1]) { + case "wei": a++; if (lib.config.banned.contains(i)) sa++; break; + case "shu": b++; if (lib.config.banned.contains(i)) sb++; break; + case "wu": c++; if (lib.config.banned.contains(i)) sc++; break; + case "qun": d++; if (lib.config.banned.contains(i)) sd++; break; + case "jin": g++; if (lib.config.banned.contains(i)) sg++; break; + case "western": e++; if (lib.config.banned.contains(i)) se++; break; + case "key": f++; if (lib.config.banned.contains(i)) sf++; break; + } + } + console.log("魏:" + (a - sa) + "/" + a); + console.log("蜀:" + (b - sb) + "/" + b); + console.log("吴:" + (c - sc) + "/" + c); + console.log("群:" + (d - sd) + "/" + d); + console.log("晋:" + (g - sg) + "/" + g); + console.log("西:" + (e - se) + "/" + e); + console.log("键:" + (f - sf) + "/" + f); + console.log("已启用:" + ((a + b + c + d + e + f) - (sa + sb + sc + sd + se + sf)) + "/" + (a + b + c + d + e + f)); + }()); + (function () { + var a = 0, b = 0, c = 0, d = 0; + var aa = 0, bb = 0, cc = 0, dd = 0; + var sa = 0, sb = 0, sc = 0, sd = 0; + var sha = 0, shan = 0, tao = 0, jiu = 0, wuxie = 0, heisha = 0, hongsha = 0; + var num = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 }; + for (var i in lib.card) { + if (get.objtype(lib.card[i]) == "object" && lib.translate[i + "_info"]) { + switch (lib.card[i].type) { + case "basic": a++; break; + case "trick": b++; break; + case "equip": c++; break; + default: d++; break; + } + } + } + for (var i = 0; i < lib.card.list.length; i++) { + if (typeof lib.card[lib.card.list[i][2]] == "object") { + switch (lib.card[lib.card.list[i][2]].type) { + case "basic": aa++; break; + case "trick": case "delay": bb++; break; + case "equip": cc++; break; + default: dd++; break; + } + switch (lib.card.list[i][0]) { + case "heart": sa++; break; + case "diamond": sb++; break; + case "club": sc++; break; + case "spade": sd++; break; + } + if (lib.card.list[i][2] == "sha") { + sha++; + if (lib.card.list[i][0] == "club" || lib.card.list[i][0] == "spade") { + heisha++; + } + else { + hongsha++; + } + } + if (lib.card.list[i][2] == "shan") { + shan++; + } + if (lib.card.list[i][2] == "tao") { + tao++; + } + if (lib.card.list[i][2] == "jiu") { + jiu++; + } + if (lib.card.list[i][2] == "wuxie") { + wuxie++; + } + num[lib.card.list[i][1]]++; + } + } + var str = "基本牌" + aa + "; " + "锦囊牌" + bb + "; " + "装备牌" + cc + "; " + "其它牌" + dd + console.log(str); + str = "红桃牌" + sa + "; " + "方片牌" + sb + "; " + "梅花牌" + sc + "; " + "黑桃牌" + sd + console.log(str); + str = "杀" + sha + "; " + "黑杀" + heisha + "; " + "红杀" + hongsha + "; " + "闪" + shan + "; " + "桃" + tao + "; " + "酒" + jiu + "; " + "无懈" + wuxie + console.log(str); + if (arguments[1]) { + for (var i = 1; i <= 13; i++) { + if (i < 10) { + console.log(i + " ", num[i]); + } + else { + console.log(i, num[i]); + } + } + } + var arr = []; + for (var i = 1; i <= 13; i++) { + arr.push(num[i]); + } + console.log((a + b + c + d) + "/" + (aa + bb + cc + dd), ...arr) + }()); + } + + static id() { + game.showIdentity(); + } + + static b() { + if (!ui.dialog || !ui.dialog.buttons) return; + for (var i = 0; i < Math.min(arguments.length, ui.dialog.buttons.length); i++) { + ui.dialog.buttons[i].link = arguments[i]; + } + } + + static uy(me) { + if (me) { + game.me.useCard({ name: "spell_yexinglanghun" }, game.me); + } + else { + var enemy = game.me.getEnemy(); + enemy.useCard({ name: "spell_yexinglanghun" }, enemy); + } + } + + static gs(name, act) { + var card = game.createCard("spell_" + (name || "yexinglanghun")); + game.me.node.handcards1.appendChild(card); + if (!act) { + game.me.actused = -99; + } + ui.updatehl(); + delete _status.event._cardChoice; + delete _status.event._targetChoice; + delete _status.event._skillChoice; + setTimeout(game.check, 300); + } + + static gc(name, act) { + var card = game.createCard("stone_" + (name || "falifulong") + "_stonecharacter"); + game.me.node.handcards1.appendChild(card); + if (!act) { + game.me.actused = -99; + } + ui.updatehl(); + delete _status.event._cardChoice; + delete _status.event._targetChoice; + delete _status.event._skillChoice; + setTimeout(game.check, 300); + } + + static a(bool) { + if (lib.config.test_game) { + game.saveConfig("test_game"); + } + else { + if (bool) { + if (typeof bool === "string") { + game.saveConfig("test_game", bool); + } + else { + game.saveConfig("test_game", "_"); + } + } + else { + game.saveConfig("test_game", true); + } + } + game.reload(); + } + + static as() { + ui.window.classList.remove("testing"); + var bg = ui.window.querySelector(".pausedbg"); + if (bg) { + bg.remove(); + } + } + + static uj() { + cheat.e("qilin"); + game.me.next.useCard({ name: "jiedao" }, [game.me, game.me.previous]); + } + + static u() { + var card = { name: "sha" }, source = game.me.next, targets = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + source = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + targets = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + card = arguments[i]; + } + else if (typeof arguments[i] == "string") { + card = { name: arguments[i] } + } + } + if (!targets.length) targets.push(game.me); + source.useCard(game.createCard(card.name, card.suit, card.number, card.nature), targets); + } + + static r(bool) { + var list = ["s", "ap", "a", "am", "bp", "b", "bm", "c", "d"]; + var str = ""; + for (var i = 0; i < list.length; i++) { + if (str) str += " 、 "; + str += list[i] + "-" + lib.rank[list[i]].length; + } + console.log(str); + for (var i in lib.characterPack) { + if (!bool && lib.config.all.sgscharacters.contains(i)) continue; + var map = {}; + var str = ""; + for (var j in lib.characterPack[i]) { + var rank = get.rank(j); + if (!map[rank]) { + map[rank] = 1; + } + else { + map[rank]++; + } + } + for (var j = 0; j < list.length; j++) { + if (map[list[j]]) { + if (str) str += " 、 "; + str += list[j] + "-" + map[list[j]]; + } + } + if (str) { + console.log(lib.translate[i + "_character_config"] + ":" + str); + } + } + + var list = lib.rank.s.concat(lib.rank.ap).concat(lib.rank.a).concat(lib.rank.am). + concat(lib.rank.bp).concat(lib.rank.b).concat(lib.rank.bm).concat(lib.rank.c).concat(lib.rank.d); + Object.keys(lib.character).forEach(key => { + if (!lib.config.forbidai.includes(key) && !key.startsWith("boss_") && !key.startsWith("tafang_") && !list.includes(key)) console.log(get.translation(key), key); + }); + } + + static h(player) { + console.log(get.translation(player.getCards("h"))); + } + + static g() { + for (var i = 0; i < arguments.length; i++) { + if (i > 0 && typeof arguments[i] == "number") { + for (var j = 0; j < arguments[i] - 1; j++) { + cheat.gx(arguments[i - 1]); + } + } + else { + cheat.gx(arguments[i]); + } + } + } + + static ga(type) { + for (var i in lib.card) { + if (lib.card[i].type == type || lib.card[i].subtype == type) { + cheat.g(i); + } + } + } + + static gg() { + for (var i = 0; i < game.players.length; i++) { + for (var j = 0; j < arguments.length; j++) { + cheat.gx(arguments[j], game.players[i]); + } + } + } + + static gx(name, target) { + target = target || game.me; + var card = cheat.gn(name); + if (!card) return; + target.node.handcards1.appendChild(card); + delete _status.event._cardChoice; + delete _status.event._targetChoice; + delete _status.event._skillChoice; + game.check(); + target.update(); + ui.updatehl(); + } + + static gn(name) { + var nature = null; + var suit = null; + var suits = ["club", "spade", "diamond", "heart"]; + for (var i = 0; i < suits.length; i++) { + if (name.startsWith(suits[i])) { + suit = suits[i]; + name = name.slice(suits[i].length); + break; + } + } + if (name.startsWith("red")) { + name = name.slice(3); + suit = ["diamond", "heart"].randomGet(); + } + if (name.startsWith("black")) { + name = name.slice(5); + suit = ["spade", "club"].randomGet(); + } + + if (name == "huosha") { + name = "sha"; + nature = "fire"; + } + else if (name == "leisha") { + name = "sha"; + nature = "thunder"; + } + if (!lib.card[name]) { + return null; + } + return game.createCard(name, suit, null, nature); + } + + static ge(target) { + if (target) { + cheat.gx("zhuge", target); + cheat.gx("qinglong", target); + cheat.gx("bagua", target); + cheat.gx("dilu", target); + cheat.gx("chitu", target); + cheat.gx("muniu", target); + } + else { + cheat.g("zhuge"); + cheat.g("qinglong"); + cheat.g("bagua"); + cheat.g("dilu"); + cheat.g("chitu"); + cheat.g("muniu"); + } + } + + static gj() { + cheat.g("shandian"); + cheat.g("huoshan"); + cheat.g("hongshui"); + cheat.g("lebu"); + cheat.g("bingliang"); + cheat.g("guiyoujie"); + } + + static gf() { + for (var i in lib.card) { + if (lib.card[i].type == "food") { + cheat.g(i); + } + } + } + + static d(num, target) { + if (num == undefined) num = 1; + var cards = get.cards(num); + for (var i = 0; i < num; i++) { + var card = cards[i]; + game.me.node.handcards1.appendChild(card); + delete _status.event._cardChoice; + delete _status.event._targetChoice; + delete _status.event._skillChoice; + game.check(); + game.me.update(); + ui.updatehl(); + } + } + + static s() { + for (var i = 0; i < arguments.length; i++) { + game.me.addSkill(arguments[i], true); + } + delete _status.event._cardChoice; + delete _status.event._targetChoice; + delete _status.event._skillChoice; + game.check(); + } + + static t(num) { + if (game.players.contains(num)) { + num = game.players.indexOf(num); + } + if (num == undefined) { + for (var i = 0; i < game.players.length; i++) cheat.t(i); + return; + } + var player = game.players[num]; + var cards = player.getCards("hej"); + for (var i = 0; i < cards.length; i++) { + cards[i].discard(); + } + player.removeEquipTrigger(); + player.update(); + } + + static to() { + for (var i = 0; i < game.players.length; i++) { + if (game.players[i] != game.me) { + cheat.t(i); + } + } + } + + static tm() { + for (var i = 0; i < game.players.length; i++) { + if (game.players[i] == game.me) { + cheat.t(i); + } + } + } + + static k(i) { + if (i == undefined) i = 1; + game.players[i].hp = 1; + cheat.t(i); + cheat.g("juedou"); + } + + static z(name) { + switch (name) { + case "cc": name = "re_caocao"; break; + case "lb": name = "re_liubei"; break; + case "sq": name = "sunquan"; break; + case "dz": name = "dongzhuo"; break; + case "ys": name = "re_yuanshao"; break; + case "zj": name = "sp_zhangjiao"; break; + case "ls": name = "liushan"; break; + case "sc": name = "sunce"; break; + case "cp": name = "caopi"; break; + case "cr": name = "caorui"; break; + case "sx": name = "sunxiu"; break; + case "lc": name = "liuchen"; break; + case "sh": name = "sunhao"; break; + } + game.zhu.init(name); + game.zhu.maxHp++; + game.zhu.hp++; + game.zhu.update(); + } +} diff --git a/noname/library/color.js b/noname/library/color.js new file mode 100644 index 000000000..09d92642e --- /dev/null +++ b/noname/library/color.js @@ -0,0 +1,5 @@ +export const color = { + black: ["club", "spade"], + red: ["diamond", "heart"], + none: ["none"] +}; diff --git a/noname/library/comparator.js b/noname/library/comparator.js new file mode 100644 index 000000000..9d73cea8b --- /dev/null +++ b/noname/library/comparator.js @@ -0,0 +1,41 @@ +export class Comparator { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static equals() { + if (arguments.length == 0) return false; + if (arguments.length == 1) return true; + for (let i = 1; i < arguments.length; ++i) if (arguments[i] !== arguments[0]) return false; + return true; + } + + static equalAny() { + if (arguments.length == 0) return false; + if (arguments.length == 1) return true; + for (let i = 1; i < arguments.length; ++i) if (arguments[i] === arguments[0]) return true; + return false; + } + + static notEquals() { + if (arguments.length == 0) return false; + if (arguments.length == 1) return true; + for (let i = 1; i < arguments.length; ++i) if (arguments[i] === arguments[0]) return false; + return true; + } + + static notEqualAny() { + if (arguments.length == 0) return false; + if (arguments.length == 1) return true; + for (let i = 1; i < arguments.length; ++i) if (arguments[i] !== arguments[0]) return true; + return false; + } + + static typeEquals() { + if (arguments.length == 0) return false; + if (arguments.length == 1) return arguments[0] !== null; + const type = typeof arguments[0]; + for (let i = 1; i < arguments.length; ++i) if (type !== arguments[i]) return false; + return true; + } +} diff --git a/noname/library/configuration-menu.js b/noname/library/configuration-menu.js new file mode 100644 index 000000000..5f5bcc431 --- /dev/null +++ b/noname/library/configuration-menu.js @@ -0,0 +1,15 @@ +import { APPEARANCE } from "./configuration-menu/appearance.js"; +import { AUDIO } from "./configuration-menu/audio.js"; +import { GENERAL } from "./configuration-menu/general.js"; +import { OTHERS } from "./configuration-menu/others.js"; +import { SKILL } from "./configuration-menu/skill.js"; +import { VIEW } from "./configuration-menu/view.js"; + +export const CONFIGURATION_MENU = { + general: GENERAL, + appearence: APPEARANCE, + view: VIEW, + audio: AUDIO, + skill: SKILL, + others: OTHERS +}; diff --git a/noname/library/configuration-menu/appearance.js b/noname/library/configuration-menu/appearance.js new file mode 100644 index 000000000..56f8d0e33 --- /dev/null +++ b/noname/library/configuration-menu/appearance.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./appearance/configuration.js"; + +export const APPEARANCE = { + name: "外观", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/appearance/configuration.js b/noname/library/configuration-menu/appearance/configuration.js new file mode 100644 index 000000000..d71b7d1b6 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration.js @@ -0,0 +1,187 @@ +import { ANIMATION } from "./configuration/animation.js"; +import { AUTOMATIC_BORDER_COUNT } from "./configuration/automatic-border-count.js"; +import { AUTOMATIC_BORDER_START } from "./configuration/automatic-border-start.js"; +import { BLUR_UI } from "./configuration/blur-ui.js"; +import { BORDER_STYLE } from "./configuration/border-style.js"; +import { BUTTON_CHARACTER_PREFIX } from "./configuration/button-character-prefix.js"; +import { BUTTON_CHARACTER_STYLE } from "./configuration/button-character-style.js"; +import { BUTTON_PRESS } from "./configuration/button-press.js"; +import { CARD_BACK_STYLE } from "./configuration/card-back-style.js"; +import { CARD_SHAPE } from "./configuration/card-shape.js"; +import { CARD_STYLE } from "./configuration/card-style.js"; +import { CARD_TEMPORARY_NAME } from "./configuration/card-temporary-name.js"; +import { CARD_TEXT_FONT } from "./configuration/card-text-font.js"; +import { CHANGE_SKIN_AUTOMATICALLY } from "./configuration/change-skin-automatically.js"; +import { CHANGE_SKIN } from "./configuration/change-skin.js"; +import { CONTROL_STYLE } from "./configuration/control-style.js"; +import { CURSOR_STYLE } from "./configuration/cursor-style.js"; +import { CUSTOM_BUTTON_CONTROL_BOTTOM } from "./configuration/custom-button-control-bottom.js"; +import { CUSTOM_BUTTON_CONTROL_TOP } from "./configuration/custom-button-control-top.js"; +import { CUSTOM_BUTTON_SYSTEM_BOTTOM } from "./configuration/custom-button-system-bottom.js"; +import { CUSTOM_BUTTON_SYSTEM_TOP } from "./configuration/custom-button-system-top.js"; +import { CUSTOM_BUTTON } from "./configuration/custom-button.js"; +import { DAMAGE_SHAKE } from "./configuration/damage-shake.js"; +import { DIE_MOVE } from "./configuration/die-move.js"; +import { FOLD_CARD } from "./configuration/fold-card.js"; +import { FOLD_MODE } from "./configuration/fold-mode.js"; +import { GLASS_UI } from "./configuration/glass-ui.js"; +import { GLOBAL_FONT } from "./configuration/global-font.js"; +import { GLOW_PHASE } from "./configuration/glow-phase.js"; +import { HP_STYLE } from "./configuration/hp-style.js"; +import { IDENTITY_FONT } from "./configuration/identity-font.js"; +import { IMAGE_BACKGROUND_BLUR } from "./configuration/image-background-blur.js"; +import { IMAGE_BACKGROUND_RANDOM } from "./configuration/image-background-random.js"; +import { IMAGE_BACKGROUND } from "./configuration/image-background.js"; +import { JIU_EFFECT } from "./configuration/jiu-effect.js"; +import { LAYOUT } from "./configuration/layout.js"; +import { LINK_STYLE_2 } from "./configuration/link-style-2.js"; +import { MENU_STYLE } from "./configuration/menu-style.js"; +import { NAME_FONT } from "./configuration/name-font.js"; +import { PHONE_LAYOUT } from "./configuration/phone-layout.js"; +import { PLAYER_BORDER } from "./configuration/player-border.js"; +import { PLAYER_HEIGHT_NOVA } from "./configuration/player-height-nova.js"; +import { PLAYER_HEIGHT } from "./configuration/player-height.js"; +import { PLAYER_STYLE } from "./configuration/player-style.js"; +import { RADIUS_SIZE } from "./configuration/radius-size.js"; +import { SEPARATE_CONTROL } from "./configuration/separate-control.js"; +import { SKILL_ANIMATION_TYPE } from "./configuration/skill-animation-type.js"; +import { SPLASH_STYLE } from "./configuration/splash-style.js"; +import { SUITS_FONT } from "./configuration/suits-font.js"; +import { TARGET_SHAKE } from "./configuration/target-shake.js"; +import { THEME } from "./configuration/theme.js"; +import { TURNED_STYLE } from "./configuration/turned-style.js"; +import { UI_ZOOM } from "./configuration/ui-zoom.js"; + +export const CONFIGURATION = { + theme: THEME, + layout: LAYOUT, + splash_style: SPLASH_STYLE, + player_height: PLAYER_HEIGHT, + player_height_nova: PLAYER_HEIGHT_NOVA, + ui_zoom: UI_ZOOM, + image_background: IMAGE_BACKGROUND, + image_background_random: IMAGE_BACKGROUND_RANDOM, + image_background_blur: IMAGE_BACKGROUND_BLUR, + phonelayout: PHONE_LAYOUT, + change_skin: CHANGE_SKIN, + change_skin_auto: CHANGE_SKIN_AUTOMATICALLY, + card_style: CARD_STYLE, + cardback_style: CARD_BACK_STYLE, + hp_style: HP_STYLE, + player_style: PLAYER_STYLE, + border_style: BORDER_STYLE, + autoborder_count: AUTOMATIC_BORDER_COUNT, + autoborder_start: AUTOMATIC_BORDER_START, + player_border: PLAYER_BORDER, + menu_style: MENU_STYLE, + control_style: CONTROL_STYLE, + custom_button: CUSTOM_BUTTON, + custom_button_system_top: CUSTOM_BUTTON_SYSTEM_TOP, + custom_button_system_bottom: CUSTOM_BUTTON_SYSTEM_BOTTOM, + custom_button_control_top: CUSTOM_BUTTON_CONTROL_TOP, + custom_button_control_bottom: CUSTOM_BUTTON_CONTROL_BOTTOM, + radius_size: RADIUS_SIZE, + glow_phase: GLOW_PHASE, + fold_card: FOLD_CARD, + fold_mode: FOLD_MODE, + seperate_control: SEPARATE_CONTROL, + blur_ui: BLUR_UI, + glass_ui: GLASS_UI, + damage_shake: DAMAGE_SHAKE, + button_press: BUTTON_PRESS, + jiu_effect: JIU_EFFECT, + animation: ANIMATION, + skill_animation_type: SKILL_ANIMATION_TYPE, + die_move: DIE_MOVE, + target_shake: TARGET_SHAKE, + turned_style: TURNED_STYLE, + link_style2: LINK_STYLE_2, + cardshape: CARD_SHAPE, + cardtempname: CARD_TEMPORARY_NAME, + buttoncharacter_style: BUTTON_CHARACTER_STYLE, + buttoncharacter_prefix: BUTTON_CHARACTER_PREFIX, + cursor_style: CURSOR_STYLE, + name_font: NAME_FONT, + identity_font: IDENTITY_FONT, + cardtext_font: CARD_TEXT_FONT, + global_font: GLOBAL_FONT, + suits_font: SUITS_FONT, + update(config, map) { + if (config.custom_button) { + map.custom_button_system_top.show(); + map.custom_button_system_bottom.show(); + map.custom_button_control_top.show(); + map.custom_button_control_bottom.show(); + } + else { + map.custom_button_system_top.hide(); + map.custom_button_system_bottom.hide(); + map.custom_button_control_top.hide(); + map.custom_button_control_bottom.hide(); + } + if (config.change_skin) { + map.change_skin_auto.show(); + } + else { + map.change_skin_auto.hide(); + } + if (config.image_background_random) { + map.image_background_blur.show(); + map.image_background.hide(); + } + else { + map.image_background.show(); + if (config.image_background == "default") { + map.image_background_blur.hide(); + } + else { + map.image_background_blur.show(); + } + } + if (config.layout == "long" || config.layout == "mobile") { + map.cardshape.show(); + map.phonelayout.show(); + } + else { + if (config.layout == "long2" || config.layout == "nova") { + map.phonelayout.show(); + map.cardshape.show(); + } + else { + map.phonelayout.hide(); + map.cardshape.hide(); + } + } + if (config.layout == "long") { + map.player_height.show(); + } + else { + if (config.layout == "long2") { + map.player_height.show(); + } + else { + map.player_height.hide(); + } + } + if (config.layout == "nova") { + map.player_height_nova.show(); + } + else { + map.player_height_nova.hide(); + } + if (config.touchscreen) { + map.cursor_style.hide(); + } + else { + map.cursor_style.show(); + } + if (config.border_style == "auto") { + map.autoborder_count.show(); + map.autoborder_start.show(); + } + else { + map.autoborder_count.hide(); + map.autoborder_start.hide(); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/animation.js b/noname/library/configuration-menu/appearance/configuration/animation.js new file mode 100644 index 000000000..5b66b618b --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/animation.js @@ -0,0 +1,6 @@ +export const ANIMATION = { + name: "游戏特效", + intro: "开启后出现属性伤害、回复体力等情况时会显示动画", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/automatic-border-count.js b/noname/library/configuration-menu/appearance/configuration/automatic-border-count.js new file mode 100644 index 000000000..f4d1bbcac --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/automatic-border-count.js @@ -0,0 +1,20 @@ +import { ITEM } from "./automatic-border-count/item.js"; + +const introduction = document.createElement("body"); +const kill = document.createElement("strong"); +kill.append("击杀"); +introduction.append(kill, " 每击杀一人,边框提升两级", document.createElement("br")); +const damage = document.createElement("strong"); +damage.append("伤害"); +introduction.append(damage, " 每造成两点伤害,边框提升一级", document.createElement("br")); +const mix = document.createElement("strong"); +mix.append("混合"); +introduction.append(mix, " 击杀量决定边框颜色,伤害量决定边框装饰"); + +export const AUTOMATIC_BORDER_COUNT = { + name: "边框升级方式", + intro: introduction.innerHTML, + init: "kill", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/automatic-border-count/item.js b/noname/library/configuration-menu/appearance/configuration/automatic-border-count/item.js new file mode 100644 index 000000000..f9ec4eb19 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/automatic-border-count/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + kill: "击杀", + damage: "伤害", + mix: "混合" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/automatic-border-start.js b/noname/library/configuration-menu/appearance/configuration/automatic-border-start.js new file mode 100644 index 000000000..f473e7262 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/automatic-border-start.js @@ -0,0 +1,8 @@ +import { ITEM } from "./automatic-border-start/item.js"; + +export const AUTOMATIC_BORDER_START = { + name: "基础边框颜色", + init: "bronze", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/automatic-border-start/item.js b/noname/library/configuration-menu/appearance/configuration/automatic-border-start/item.js new file mode 100644 index 000000000..4b8f3ff94 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/automatic-border-start/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + bronze: "铜", + silver: "银", + gold: "金" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/blur-ui.js b/noname/library/configuration-menu/appearance/configuration/blur-ui.js new file mode 100644 index 000000000..9f1db757d --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/blur-ui.js @@ -0,0 +1,15 @@ +export const BLUR_UI = { + name: "模糊效果", + intro: "在暂停或打开菜单时开启模糊效果", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("blur_ui", bool); + if (bool) { + ui.window.classList.add("blur_ui"); + } + else { + ui.window.classList.remove("blur_ui"); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/border-style.js b/noname/library/configuration-menu/appearance/configuration/border-style.js new file mode 100644 index 000000000..2cab0544d --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/border-style.js @@ -0,0 +1,125 @@ +import { ITEM } from "./border-style/item.js"; + +export const BORDER_STYLE = { + name: "角色边框", + init: "default", + intro: "设置角色边框的样式,当设为自动时,样式将随着一局游戏中伤害或击杀的数量自动改变", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "border_style", file, function () { + game.getDB("image", "border_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = "url(" + data + ")"; + button.className = "button character"; + button.style.backgroundSize = "100% 100%"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "border_style"); + button.style.backgroundImage = "none"; + button.className = "button character dashedmenubutton"; + node.classList.remove("showdelete"); + if (lib.config.border_style == "custom") { + lib.configMenu.appearence.config.border_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button character"; + node.style.backgroundSize = ""; + node.style.height = "108px"; + node.dataset.decoration = ""; + if (link == "default" || link == "custom" || link == "auto") { + node.style.backgroundImage = "none"; + node.className = "button character dashedmenubutton"; + } + else { + if (link.startsWith("dragon_")) { + link = link.slice(7); + node.dataset.decoration = link; + } + node.setBackgroundImage("theme/style/player/" + link + "1.png"); + node.style.backgroundSize = "100% 100%"; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "border_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.className = "button character"; + node.parentNode.lastChild.classList.add("showdelete"); + node.style.backgroundSize = "100% 100%"; + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("border_style", layout); + if (ui.css.border_stylesheet) { + ui.css.border_stylesheet.remove(); + delete ui.css.border_stylesheet; + } + if (layout == "custom") { + game.getDB("image", "border_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.border_stylesheet) { + ui.css.border_stylesheet.remove(); + } + ui.css.border_stylesheet = lib.init.sheet(); + ui.css.border_stylesheet.id = "ui.css.border"; + ui.css.border_stylesheet.sheet.insertRule(`#window .player>.framebg{display:block;background-image:url("${fileLoadedEvent.target.result}")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(".player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}", 0); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else if (layout != "default" && layout != "auto") { + ui.css.border_stylesheet = lib.init.sheet(); + if (layout.startsWith("dragon_")) { + layout = layout.slice(7); + ui.arena.dataset.framedecoration = layout; + } + else { + ui.arena.dataset.framedecoration = ""; + } + ui.css.border_stylesheet.sheet.insertRule(`#window .player>.framebg,#window #arena.long.mobile:not(.fewplayer) .player[data-position="0"]>.framebg{display:block;background-image:url("${lib.assetURL}theme/style/player/${layout}1.png")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(`#window #arena.long:not(.fewplayer) .player>.framebg, #arena.oldlayout .player>.framebg{background-image:url("${lib.assetURL}theme/style/player/${layout}3.png")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(".player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}", 0); + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/border-style/item.js b/noname/library/configuration-menu/appearance/configuration/border-style/item.js new file mode 100644 index 000000000..4c23e0ecc --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/border-style/item.js @@ -0,0 +1,11 @@ +export const ITEM = { + gold: "金框", + silver: "银框", + bronze: "铜框", + dragon_gold: "金龙", + dragon_silver: "银龙", + dragon_bronze: "玉龙", + custom: "自定", + auto: "自动", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/button-character-prefix.js b/noname/library/configuration-menu/appearance/configuration/button-character-prefix.js new file mode 100644 index 000000000..f75a8aece --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/button-character-prefix.js @@ -0,0 +1,8 @@ +import { ITEM } from "./button-character-prefix/item.js"; + +export const BUTTON_CHARACTER_PREFIX = { + name: "武将前缀", + init: "default", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/button-character-prefix/item.js b/noname/library/configuration-menu/appearance/configuration/button-character-prefix/item.js new file mode 100644 index 000000000..941d1a567 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/button-character-prefix/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + default: "默认", + simple: "不显示颜色", + off: "不显示前缀" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/button-character-style.js b/noname/library/configuration-menu/appearance/configuration/button-character-style.js new file mode 100644 index 000000000..b20618757 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/button-character-style.js @@ -0,0 +1,8 @@ +import { ITEM } from "./button-character-style/item.js"; + +export const BUTTON_CHARACTER_STYLE = { + name: "选将样式", + init: "default", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/button-character-style/item.js b/noname/library/configuration-menu/appearance/configuration/button-character-style/item.js new file mode 100644 index 000000000..1d8569f82 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/button-character-style/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + default: "默认", + simple: "精简", + old: "旧版" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/button-press.js b/noname/library/configuration-menu/appearance/configuration/button-press.js new file mode 100644 index 000000000..9ea96bb1d --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/button-press.js @@ -0,0 +1,6 @@ +export const BUTTON_PRESS = { + name: "按钮效果", + intro: "选项条被按下时将有按下效果", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-back-style.js b/noname/library/configuration-menu/appearance/configuration/card-back-style.js new file mode 100644 index 000000000..cb6696124 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-back-style.js @@ -0,0 +1,138 @@ +import { ITEM } from "./card-back-style/item.js"; + +export const CARD_BACK_STYLE = { + name: "卡背样式", + intro: "设置背面朝上的卡牌的样式", + init: "default", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "cardback_style", file, function () { + game.getDB("image", "cardback_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = "url(" + data + ")"; + button.className = "button character"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + ui.create.filediv(".menubutton.deletebutton.addbutton", "添加翻转图片", node, function (file) { + if (file) { + game.putDB("image", "cardback_style2", file, function () { + node.classList.add("hideadd"); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "cardback_style"); + game.deleteDB("image", "cardback_style2"); + button.style.backgroundImage = "none"; + button.className = "button character dashedmenubutton"; + node.classList.remove("showdelete"); + node.classList.remove("hideadd"); + if (lib.config.cardback_style == "custom") { + lib.configMenu.appearence.config.cardback_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.style.backgroundSize = "100% 100%"; + switch (link) { + case "default": case "custom": { + node.style.backgroundImage = "none"; + node.className = "button character dashedmenubutton"; + break; + } + case "new": node.className = "button character"; node.setBackgroundImage("theme/style/cardback/image/new.png"); break; + case "feicheng": node.className = "button character"; node.setBackgroundImage("theme/style/cardback/image/feicheng.png"); break; + case "official": node.className = "button character"; node.setBackgroundImage("theme/style/cardback/image/official.png"); break; + case "liusha": node.className = "button character"; node.setBackgroundImage("theme/style/cardback/image/liusha.png"); break; + case "ol": node.className = "button character"; node.setBackgroundImage("theme/style/cardback/image/ol.png"); break; + case "wood": node.className = "button card fullskin"; node.setBackgroundImage("theme/woodden/wood.jpg"); node.style.backgroundSize = "initial"; break; + case "music": node.className = "button card fullskin"; node.setBackgroundImage("theme/music/wood3.png"); break; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "cardback_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.className = "button character"; + node.parentNode.lastChild.classList.add("showdelete"); + game.getDB("image", "cardback_style2", function (file) { + if (file) { + node.parentNode.lastChild.classList.add("hideadd"); + } + }); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("cardback_style", layout); + var style = ui.css.cardback_style; + ui.css.cardback_style = lib.init.css(lib.assetURL + "theme/style/cardback", lib.config.cardback_style); + style.remove(); + if (ui.css.cardback_stylesheet) { + ui.css.cardback_stylesheet.remove(); + delete ui.css.cardback_stylesheet; + } + if (ui.css.cardback_stylesheet2) { + ui.css.cardback_stylesheet2.remove(); + delete ui.css.cardback_stylesheet2; + } + if (layout == "custom") { + game.getDB("image", "cardback_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.cardback_stylesheet) { + ui.css.cardback_stylesheet.remove(); + } + ui.css.cardback_stylesheet = lib.init.sheet(".card:empty,.card.infohidden{background-image:url(" + fileLoadedEvent.target.result + ")}"); + game.getDB("image", "cardback_style2", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.cardback_stylesheet2) { + ui.css.cardback_stylesheet2.remove(); + } + ui.css.cardback_stylesheet2 = lib.init.sheet(".card.infohidden:not(.infoflip){background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-back-style/item.js b/noname/library/configuration-menu/appearance/configuration/card-back-style/item.js new file mode 100644 index 000000000..14ac8f52a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-back-style/item.js @@ -0,0 +1,8 @@ +export const ITEM = { + official: "原版", + feicheng: "废城", + liusha: "流沙", + ol: "手杀", + custom: "自定", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-shape.js b/noname/library/configuration-menu/appearance/configuration/card-shape.js new file mode 100644 index 000000000..691d628e3 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-shape.js @@ -0,0 +1,34 @@ +import { ITEM } from "./card-shape/item.js"; + +export const CARD_SHAPE = { + name: "手牌显示", + intro: "将手牌设置为正方形或长方形", + init: "default", + unfrequent: true, + item: ITEM, + onclick(item) { + var linked = false; + if (game.me && game.me.isLinked()) { + linked = true; + } + game.saveConfig("cardshape", item); + if (item == "oblong" && (game.layout == "long" || game.layout == "mobile" || game.layout == "long2" || game.layout == "nova")) { + ui.arena.classList.add("oblongcard"); + ui.window.classList.add("oblongcard"); + } + else { + ui.arena.classList.remove("oblongcard"); + ui.window.classList.remove("oblongcard"); + } + if (linked) { + if (get.is.linked2(game.me)) { + game.me.classList.remove("linked"); + game.me.classList.add("linked2"); + } + else { + game.me.classList.add("linked"); + game.me.classList.remove("linked2"); + } + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-shape/item.js b/noname/library/configuration-menu/appearance/configuration/card-shape/item.js new file mode 100644 index 000000000..b778bf649 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-shape/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + default: "默认", + oblong: "长方" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-style.js b/noname/library/configuration-menu/appearance/configuration/card-style.js new file mode 100644 index 000000000..1cb3110ff --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-style.js @@ -0,0 +1,114 @@ +import { ITEM } from "./card-style/item.js"; + +export const CARD_STYLE = { + name: "卡牌样式", + init: "default", + intro: "设置正面朝上的卡牌的样式", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "card_style", file, function () { + game.getDB("image", "card_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = "url(" + data + ")"; + button.className = "button card fullskin"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "card_style"); + button.style.backgroundImage = "none"; + button.className = "button character dashedmenubutton"; + node.classList.remove("showdelete"); + if (lib.config.card_style == "custom") { + lib.configMenu.appearence.config.card_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button card fullskin"; + node.style.backgroundSize = "100% 100%"; + switch (link) { + case "default": case "custom": { + if (lib.config.theme == "simple") { + node.style.backgroundImage = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; + node.className = "button character"; + } + else { + node.style.backgroundImage = "none"; + node.className = "button character dashedmenubutton"; + } + break; + } + case "new": node.setBackgroundImage("theme/style/card/image/new.png"); break; + case "ol": node.setBackgroundImage("theme/style/card/image/ol.png"); break; + case "wood": node.setBackgroundImage("theme/woodden/wood.jpg"); node.style.backgroundSize = "initial"; break; + case "music": node.setBackgroundImage("theme/music/wood3.png"); break; + case "simple": node.setBackgroundImage("theme/simple/card.png"); break; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "card_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.className = "button card fullskin"; + node.parentNode.lastChild.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("card_style", layout); + var style = ui.css.card_style; + ui.css.card_style = lib.init.css(lib.assetURL + "theme/style/card", lib.config.card_style); + style.remove(); + if (ui.css.card_stylesheet) { + ui.css.card_stylesheet.remove(); + delete ui.css.card_stylesheet; + } + if (layout == "custom") { + game.getDB("image", "card_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.card_stylesheet) { + ui.css.card_stylesheet.remove(); + } + ui.css.card_stylesheet = lib.init.sheet(".card:not(*:empty){background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-style/item.js b/noname/library/configuration-menu/appearance/configuration/card-style/item.js new file mode 100644 index 000000000..d6b45d906 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-style/item.js @@ -0,0 +1,8 @@ +export const ITEM = { + wood: "木纹", + music: "音乐", + simple: "原版", + ol: "手杀", + custom: "自定", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-temporary-name.js b/noname/library/configuration-menu/appearance/configuration/card-temporary-name.js new file mode 100644 index 000000000..f5598d07e --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-temporary-name.js @@ -0,0 +1,28 @@ +import { ITEM } from "./card-temporary-name/item.js"; + +export const CARD_TEMPORARY_NAME = { + name: "视为卡牌名称显示", + intro: "显示强制视为类卡牌(如武魂),包括拆顺对话框内的判定牌(国色)转换等名称的显示方式", + init: "image", + unfrequent: true, + item: ITEM, + onclick(item) { + game.saveConfig("cardtempname", item); + if (!game.me || !game.me.getCards) return; + var hs = game.me.getCards("h"); + for (var i = 0; i < hs.length; i++) { + if (hs[i]._tempName) { + switch (item) { + case "default": + case "horizon": + case "image": + ui.create.cardTempName(hs[i]); + break; + default: + hs[i]._tempName.delete(); + delete hs[i]._tempName; + } + } + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-temporary-name/item.js b/noname/library/configuration-menu/appearance/configuration/card-temporary-name/item.js new file mode 100644 index 000000000..827633983 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-temporary-name/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + default: "纵向", + horizon: "横向", + image: "图片", + off: "禁用" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-text-font.js b/noname/library/configuration-menu/appearance/configuration/card-text-font.js new file mode 100644 index 000000000..cb7f93318 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-text-font.js @@ -0,0 +1,18 @@ +import { ITEM } from "./card-text-font/item.js"; + +export const CARD_TEXT_FONT = { + name: "卡牌字体", + init: "default", + unfrequent: true, + item: ITEM, + textMenu(node, link) { + if (link != "default") { + node.style.fontFamily = link; + } + node.style.fontSize = "20px"; + }, + onclick(font) { + game.saveConfig("cardtext_font", font); + lib.init.cssstyles(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/card-text-font/item.js b/noname/library/configuration-menu/appearance/configuration/card-text-font/item.js new file mode 100644 index 000000000..34bd11ce8 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/card-text-font/item.js @@ -0,0 +1 @@ +export const ITEM = {}; \ No newline at end of file diff --git a/noname/library/configuration-menu/appearance/configuration/change-skin-automatically.js b/noname/library/configuration-menu/appearance/configuration/change-skin-automatically.js new file mode 100644 index 000000000..d808c1a0c --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/change-skin-automatically.js @@ -0,0 +1,18 @@ +import { Game } from "../../../../game.js"; +import { status } from "../../../../status.js"; +import { Click } from "../../../../ui/click.js"; +import { ITEM } from "./change-skin-automatically/item.js"; + +export const CHANGE_SKIN_AUTOMATICALLY = { + name: "自动换肤", + init: "off", + item: ITEM, + intro: "游戏每进行一段时间自动为一个随机角色更换皮肤", + onclick(item) { + Game.saveConfig("change_skin_auto", item); + clearTimeout(status.skintimeout); + if (item != "off") { + status.skintimeout = setTimeout(Click.autoskin, parseInt(item)); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/change-skin-automatically/item.js b/noname/library/configuration-menu/appearance/configuration/change-skin-automatically/item.js new file mode 100644 index 000000000..6a9ec12fa --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/change-skin-automatically/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + off: "关闭", + "30000": "半分钟", + "60000": "一分钟", + "120000": "两分钟", + "300000": "五分钟" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/change-skin.js b/noname/library/configuration-menu/appearance/configuration/change-skin.js new file mode 100644 index 000000000..a88d82463 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/change-skin.js @@ -0,0 +1,5 @@ +export const CHANGE_SKIN = { + name: "开启换肤", + init: true, + intro: "在武将的右键菜单中换肤,皮肤可在选项-文件-图片文件-皮肤图片中添加" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/control-style.js b/noname/library/configuration-menu/appearance/configuration/control-style.js new file mode 100644 index 000000000..8b35cc9d4 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/control-style.js @@ -0,0 +1,116 @@ +import { ITEM } from "./control-style/item.js"; + +export const CONTROL_STYLE = { + name: "按钮背景", + init: "default", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "control_style", file, function () { + game.getDB("image", "control_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = "url(" + data + ")"; + button.className = "button character controlbutton"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "control_style"); + button.style.backgroundImage = "none"; + button.className = "button character controlbutton dashedmenubutton"; + node.classList.remove("showdelete"); + if (lib.config.control_style == "custom") { + lib.configMenu.appearence.config.control_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button character controlbutton"; + node.style.backgroundSize = ""; + switch (link) { + case "default": case "custom": { + node.style.backgroundImage = "none"; + node.classList.add("dashedmenubutton"); + break; + } + case "wood": node.setBackgroundImage("theme/woodden/wood.jpg"); break; + case "music": node.style.backgroundImage = "linear-gradient(#4b4b4b, #464646)"; break; + case "simple": node.style.backgroundImage = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; break; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "control_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.className = "button character controlbutton"; + node.parentNode.lastChild.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("control_style", layout); + if (ui.css.control_stylesheet) { + ui.css.control_stylesheet.remove(); + delete ui.css.control_stylesheet; + } + if (layout == "custom") { + game.getDB("image", "control_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.control_stylesheet) { + ui.css.control_stylesheet.remove(); + } + ui.css.control_stylesheet = lib.init.sheet(`#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:url("${fileLoadedEvent.target.result}")}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else if (layout != "default") { + var str = ""; + switch (layout) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood.jpg")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px"; break; + } + if (layout == "wood") { + ui.css.control_stylesheet = lib.init.sheet("#window .control,#window .menubutton,#window #system>div>div,#window #system>div>.pressdown2{background-image:" + str + "}"); + } + else { + ui.css.control_stylesheet = lib.init.sheet("#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:" + str + "}"); + } + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/control-style/item.js b/noname/library/configuration-menu/appearance/configuration/control-style/item.js new file mode 100644 index 000000000..d24a30c12 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/control-style/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + wood: "木纹", + music: "音乐", + simple: "简约", + custom: "自定", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/cursor-style.js b/noname/library/configuration-menu/appearance/configuration/cursor-style.js new file mode 100644 index 000000000..939a7589f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/cursor-style.js @@ -0,0 +1,18 @@ +import { ITEM } from "./cursor-style/item.js"; + +export const CURSOR_STYLE = { + name: "鼠标指针", + init: "auto", + intro: "设置为固定后鼠标指针将不随移动到的区域而变化", + unfrequent: true, + item: ITEM, + onclick(item) { + game.saveConfig("cursor_style", item); + if (item == "pointer") { + ui.window.classList.add("nopointer"); + } + else { + ui.window.classList.remove("nopointer"); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/cursor-style/item.js b/noname/library/configuration-menu/appearance/configuration/cursor-style/item.js new file mode 100644 index 000000000..4def114e0 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/cursor-style/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + auto: "自动", + pointer: "固定" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button-control-bottom.js b/noname/library/configuration-menu/appearance/configuration/custom-button-control-bottom.js new file mode 100644 index 000000000..72c0e0956 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button-control-bottom.js @@ -0,0 +1,12 @@ +import { CUSTOM_BUTTON_ITEM } from "./custom-button-item.js"; + +export const CUSTOM_BUTTON_CONTROL_BOTTOM = { + name: "技能下部高度", + init: "0x", + item: CUSTOM_BUTTON_ITEM, + unfrequent: true, + onclick(item) { + game.saveConfig("custom_button_control_bottom", item); + lib.configMenu.appearence.config.custom_button.onclick("skip"); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button-control-top.js b/noname/library/configuration-menu/appearance/configuration/custom-button-control-top.js new file mode 100644 index 000000000..c265d9a71 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button-control-top.js @@ -0,0 +1,12 @@ +import { CUSTOM_BUTTON_ITEM } from "./custom-button-item.js"; + +export const CUSTOM_BUTTON_CONTROL_TOP = { + name: "技能上部高度", + init: "0x", + item: CUSTOM_BUTTON_ITEM, + unfrequent: true, + onclick(item) { + game.saveConfig("custom_button_control_top", item); + lib.configMenu.appearence.config.custom_button.onclick("skip"); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button-item.js b/noname/library/configuration-menu/appearance/configuration/custom-button-item.js new file mode 100644 index 000000000..0799dc9a6 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button-item.js @@ -0,0 +1,13 @@ +export const CUSTOM_BUTTON_ITEM = { + "-5x": "-5px", + "-4x": "-4px", + "-3x": "-3px", + "-2x": "-2px", + "-1x": "-1px", + "0x": "默认", + "1x": "1px", + "2x": "2px", + "3x": "3px", + "4x": "4px", + "5x": "5px" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button-system-bottom.js b/noname/library/configuration-menu/appearance/configuration/custom-button-system-bottom.js new file mode 100644 index 000000000..5b68ab220 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button-system-bottom.js @@ -0,0 +1,12 @@ +import { CUSTOM_BUTTON_ITEM } from "./custom-button-item.js"; + +export const CUSTOM_BUTTON_SYSTEM_BOTTOM = { + name: "菜单下部高度", + init: "0x", + item: CUSTOM_BUTTON_ITEM, + unfrequent: true, + onclick(item) { + game.saveConfig("custom_button_system_bottom", item); + lib.configMenu.appearence.config.custom_button.onclick("skip"); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button-system-top.js b/noname/library/configuration-menu/appearance/configuration/custom-button-system-top.js new file mode 100644 index 000000000..42010d5a9 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button-system-top.js @@ -0,0 +1,12 @@ +import { CUSTOM_BUTTON_ITEM } from "./custom-button-item.js"; + +export const CUSTOM_BUTTON_SYSTEM_TOP = { + name: "菜单上部高度", + init: "0x", + item: CUSTOM_BUTTON_ITEM, + unfrequent: true, + onclick(item) { + game.saveConfig("custom_button_system_top", item); + lib.configMenu.appearence.config.custom_button.onclick("skip"); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/custom-button.js b/noname/library/configuration-menu/appearance/configuration/custom-button.js new file mode 100644 index 000000000..cb40ae74d --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/custom-button.js @@ -0,0 +1,34 @@ +export const CUSTOM_BUTTON = { + name: "自定义按钮高度", + init: false, + unfrequent: true, + onclick(bool) { + if (bool !== "skip") { + game.saveConfig("custom_button", bool); + } + if (ui.css.buttonsheet) { + ui.css.buttonsheet.remove(); + } + if (lib.config.custom_button) { + var cbnum1 = 6 + (parseInt(lib.config.custom_button_system_top) || 0); + var cbnum2 = 6 + (parseInt(lib.config.custom_button_system_bottom) || 0); + var cbnum3 = 3 + (parseInt(lib.config.custom_button_control_top) || 0); + var cbnum4 = 3 + (parseInt(lib.config.custom_button_control_bottom) || 0); + var cbnum5 = 2; + var cbnum6 = 2; + if (cbnum3 < 0) { + cbnum5 += cbnum3; + cbnum3 = 0; + } + if (cbnum4 < 0) { + cbnum6 += cbnum4; + cbnum4 = 0; + } + ui.css.buttonsheet = lib.init.sheet( + "#system>div>div, .caption>div>.tdnode{padding-top:" + cbnum1 + "px !important;padding-bottom:" + cbnum2 + "px !important}", + "#control>.control>div{padding-top:" + cbnum3 + "px;padding-bottom:" + cbnum4 + "px}", + "#control>.control{padding-top:" + cbnum5 + "px;padding-bottom:" + cbnum6 + "px}" + ); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/damage-shake.js b/noname/library/configuration-menu/appearance/configuration/damage-shake.js new file mode 100644 index 000000000..c86dc762f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/damage-shake.js @@ -0,0 +1,6 @@ +export const DAMAGE_SHAKE = { + name: "伤害抖动", + intro: "角色受到伤害时的抖动效果", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/die-move.js b/noname/library/configuration-menu/appearance/configuration/die-move.js new file mode 100644 index 000000000..e81c239ed --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/die-move.js @@ -0,0 +1,9 @@ +import { ITEM } from "./die-move/item.js"; + +export const DIE_MOVE = { + name: "阵亡效果", + intro: "阵亡后武将的显示效果", + init: "flip", + unfrequent: true, + item: ITEM +}; diff --git a/noname/library/configuration-menu/appearance/configuration/die-move/item.js b/noname/library/configuration-menu/appearance/configuration/die-move/item.js new file mode 100644 index 000000000..6e94766b2 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/die-move/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + off: "关闭", + move: "移动", + flip: "翻面" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/fold-card.js b/noname/library/configuration-menu/appearance/configuration/fold-card.js new file mode 100644 index 000000000..6c6971b6a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/fold-card.js @@ -0,0 +1,5 @@ +export const FOLD_CARD = { + name: "折叠手牌", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/fold-mode.js b/noname/library/configuration-menu/appearance/configuration/fold-mode.js new file mode 100644 index 000000000..493bfc1ec --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/fold-mode.js @@ -0,0 +1,6 @@ +export const FOLD_MODE = { + name: "折叠模式菜单", + intro: "关闭后模式菜单中“更多”内的项目将直接展开", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/glass-ui.js b/noname/library/configuration-menu/appearance/configuration/glass-ui.js new file mode 100644 index 000000000..d4224263e --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/glass-ui.js @@ -0,0 +1,15 @@ +export const GLASS_UI = { + name: "玻璃主题", + intro: "为游戏主题打开玻璃效果(手机暂不支持)", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("glass_ui", bool); + if (bool) { + ui.window.classList.add("glass_ui"); + } + else { + ui.window.classList.remove("glass_ui"); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/global-font.js b/noname/library/configuration-menu/appearance/configuration/global-font.js new file mode 100644 index 000000000..98b29cd24 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/global-font.js @@ -0,0 +1,21 @@ +import { ITEM } from "./global-font/item.js"; + +export const GLOBAL_FONT = { + name: "界面字体", + init: "default", + unfrequent: true, + item: ITEM, + textMenu(node, link) { + if (link != "default") { + node.style.fontFamily = link; + } + else { + node.style.fontFamily = `"STHeiti","SimHei","Microsoft JhengHei","Microsoft YaHei","WenQuanYi Micro Hei","Suits",Helvetica,Arial,sans-serif`; + } + node.style.fontSize = "20px"; + }, + onclick(font) { + game.saveConfig("global_font", font); + lib.init.cssstyles(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/global-font/item.js b/noname/library/configuration-menu/appearance/configuration/global-font/item.js new file mode 100644 index 000000000..69a1c7a1a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/global-font/item.js @@ -0,0 +1 @@ +export const ITEM = {}; diff --git a/noname/library/configuration-menu/appearance/configuration/glow-phase.js b/noname/library/configuration-menu/appearance/configuration/glow-phase.js new file mode 100644 index 000000000..9c89d28bd --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/glow-phase.js @@ -0,0 +1,13 @@ +import { ITEM } from "./glow-phase/item.js"; + +export const GLOW_PHASE = { + name: "当前回合角色高亮", + unfrequent: true, + init: "yellow", + intro: "设置当前回合角色的边框颜色", + item: ITEM, + onclick(bool) { + game.saveConfig("glow_phase", bool); + lib.init.cssstyles(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/glow-phase/item.js b/noname/library/configuration-menu/appearance/configuration/glow-phase/item.js new file mode 100644 index 000000000..58949f7d8 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/glow-phase/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + none: "无", + yellow: "黄色", + green: "绿色", + purple: "紫色" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/hp-style.js b/noname/library/configuration-menu/appearance/configuration/hp-style.js new file mode 100644 index 000000000..47da26b82 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/hp-style.js @@ -0,0 +1,177 @@ +import { ITEM } from "./hp-style/item.js"; + +export const HP_STYLE = { + name: "体力条样式", + init: "ol", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton.addbutton", "添加图片", node, function (file) { + if (file && node.currentDB) { + game.putDB("image", "hp_style" + node.currentDB, file, function () { + game.getDB("image", "hp_style" + node.currentDB, function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.childNodes[node.currentDB - 1].style.backgroundImage = "url(" + data + ")"; + button.classList.add("shown"); + node.classList.add("showdelete"); + node.currentDB++; + if (node.currentDB > 4) { + node.classList.add("hideadd"); + button.classList.remove("transparent"); + delete node.currentDB; + } + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "hp_style1"); + game.deleteDB("image", "hp_style2"); + game.deleteDB("image", "hp_style3"); + game.deleteDB("image", "hp_style4"); + for (var i = 0; i < button.childElementCount; i++) { + button.childNodes[i].style.backgroundImage = "none"; + } + node.classList.remove("showdelete"); + node.classList.remove("hideadd"); + if (lib.config.hp_style == "custom") { + lib.configMenu.appearence.config.hp_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + button.classList.remove("shown"); + node.currentDB = 1; + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button hpbutton dashedmenubutton"; + node.innerHTML = ""; + for (var i = 1; i <= 4; i++) { + var div = ui.create.div(node); + if (link == "default") { + ui.create.div(div); + } + else if (link != "custom") { + div.setBackgroundImage("theme/style/hp/image/" + link + i + ".png"); + } + if (i == 4) { + div.style.webkitFilter = "grayscale(1)"; + } + } + if (link == "custom") { + node.classList.add("transparent"); + var getDB = function (num) { + node.parentNode.lastChild.currentDB = num; + game.getDB("image", "hp_style" + num, function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.childNodes[num - 1].style.backgroundImage = "url(" + data + ")"; + node.classList.add("shown"); + node.parentNode.lastChild.classList.add("showdelete"); + if (num < 4) { + getDB(num + 1); + } + else { + node.parentNode.lastChild.classList.add("hideadd"); + node.classList.remove("transparent"); + delete node.parentNode.firstChild.currentDB; + } + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + getDB(1); + } + }, + onclick(layout) { + game.saveConfig("hp_style", layout); + var style = ui.css.hp_style; + ui.css.hp_style = lib.init.css(lib.assetURL + "theme/style/hp", lib.config.hp_style); + style.remove(); + if (ui.css.hp_stylesheet1) { + ui.css.hp_stylesheet1.remove(); + delete ui.css.hp_stylesheet1; + } + if (ui.css.hp_stylesheet2) { + ui.css.hp_stylesheet2.remove(); + delete ui.css.hp_stylesheet2; + } + if (ui.css.hp_stylesheet3) { + ui.css.hp_stylesheet3.remove(); + delete ui.css.hp_stylesheet3; + } + if (ui.css.hp_stylesheet4) { + ui.css.hp_stylesheet4.remove(); + delete ui.css.hp_stylesheet4; + } + if (layout == "custom") { + game.getDB("image", "hp_style1", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet1) { + ui.css.hp_stylesheet1.remove(); + } + ui.css.hp_stylesheet1 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="high"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style2", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet2) { + ui.css.hp_stylesheet2.remove(); + } + ui.css.hp_stylesheet2 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="mid"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style3", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet3) { + ui.css.hp_stylesheet3.remove(); + } + ui.css.hp_stylesheet3 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="low"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style4", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet4) { + ui.css.hp_stylesheet4.remove(); + } + ui.css.hp_stylesheet4 = lib.init.sheet(`.hp:not(.text):not(.actcount)>.lost{background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/hp-style/item.js b/noname/library/configuration-menu/appearance/configuration/hp-style/item.js new file mode 100644 index 000000000..5b5db306d --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/hp-style/item.js @@ -0,0 +1,10 @@ +export const ITEM = { + default: "默认", + emotion: "表情", + glass: "勾玉", + round: "国战", + ol: "手杀", + xinglass: "双鱼", + xinround: "OL", + custom: "自定" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/identity-font.js b/noname/library/configuration-menu/appearance/configuration/identity-font.js new file mode 100644 index 000000000..7b2a7968c --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/identity-font.js @@ -0,0 +1,18 @@ +import { ITEM } from "./identity-font/item.js"; + +export const IDENTITY_FONT = { + name: "身份字体", + init: "huangcao", + unfrequent: true, + item: ITEM, + textMenu(node, link) { + if (link != "default") { + node.style.fontFamily = link; + } + node.style.fontSize = "20px"; + }, + onclick(font) { + game.saveConfig("identity_font", font); + lib.init.cssstyles(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/identity-font/item.js b/noname/library/configuration-menu/appearance/configuration/identity-font/item.js new file mode 100644 index 000000000..69a1c7a1a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/identity-font/item.js @@ -0,0 +1 @@ +export const ITEM = {}; diff --git a/noname/library/configuration-menu/appearance/configuration/image-background-blur.js b/noname/library/configuration-menu/appearance/configuration/image-background-blur.js new file mode 100644 index 000000000..818ac2423 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/image-background-blur.js @@ -0,0 +1,21 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { configuration } from "../../../configuration.js"; + +export const IMAGE_BACKGROUND_BLUR = { + name: "背景模糊", + init: false, + onclick(bool) { + Game.saveConfig("image_background_blur", bool); + if (configuration.image_background_blur) { + UI.background.style.filter = "blur(8px)"; + UI.background.style.webkitFilter = "blur(8px)"; + UI.background.style.transform = "scale(1.05)"; + } + else { + UI.background.style.filter = ""; + UI.background.style.webkitFilter = ""; + UI.background.style.transform = ""; + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/image-background-random.js b/noname/library/configuration-menu/appearance/configuration/image-background-random.js new file mode 100644 index 000000000..1340ddf8e --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/image-background-random.js @@ -0,0 +1,11 @@ +import { Game } from "../../../../game.js"; +import { Initialization } from "../../../initialization.js"; + +export const IMAGE_BACKGROUND_RANDOM = { + name: "随机背景", + init: false, + onclick(bool) { + Game.saveConfig("image_background_random", bool); + Initialization.background(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/image-background.js b/noname/library/configuration-menu/appearance/configuration/image-background.js new file mode 100644 index 000000000..8994d42bc --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/image-background.js @@ -0,0 +1,159 @@ +import { Game } from "../../../../game.js"; +import { Create } from "../../../../ui/create.js"; +import { configuration } from "../../../configuration.js"; +import { Initialization } from "../../../initialization.js"; +import { ITEM } from "./image-background/item.js"; + +export const IMAGE_BACKGROUND = { + name: "游戏背景", + init: "default", + item: ITEM, + visualBar(node, item, create) { + if (node.created) { + node.lastChild.classList.remove("active"); + return; + } + node.created = true; + Create.filediv(".menubutton", "添加背景", node, function (file) { + if (file) { + var name = file.name; + if (name.includes(".")) { + name = name.slice(0, name.indexOf(".")); + } + var link = `${Game.writeFile ? "cdv_" : "custom_"}${name}`; + if (item[link]) { + for (var i = 1; i < 1000; i++) { + if (!item[`${link}_${i}`]) { + link = `${link}_${i}`; break; + } + } + } + item[link] = name; + var callback = function () { + create(link, node.parentNode.defaultNode); + node.parentNode.updateBr(); + configuration.customBackgroundPack.add(link); + Game.saveConfig("customBackgroundPack", configuration.customBackgroundPack); + }; + if (Game.writeFile) { + Game.writeFile(file, "image/background", `${link}.jpg`, callback); + } + else { + Game.putDB("image", link, file, callback); + } + if (node.lastChild.classList.contains("active")) { + editbg.call(node.lastChild); + } + } + }).inputNode.accept = "image/*"; + var editbg = function () { + this.classList.toggle("active"); + var page = this.parentNode.parentNode; + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].classList.contains("button")) { + var link = page.childNodes[i]._link; + if (link && link != "default") { + var str; + if (this.classList.contains("active")) { + if (link.startsWith("custom_") || link.startsWith("cdv_")) { + str = "删除"; + } + else { + str = "隐藏"; + } + } + else { + str = item[link]; + } + page.childNodes[i].firstChild.innerHTML = get.verticalStr(str); + } + } + } + }; + Create.div(".menubutton", "编辑背景", node, editbg); + }, + visualMenu(node, link, name, config) { + node.className = "button character"; + node.style.backgroundImage = ""; + node.style.backgroundSize = ""; + if (node.firstChild) { + node.firstChild.innerHTML = get.verticalStr(name); + } + if (link == "default" || link.startsWith("custom_")) { + node.style.backgroundImage = "none"; + node.classList.add("dashedmenubutton"); + if (link.startsWith("custom_")) { + Game.getDB("image", link, function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = `url(${data})`; + node.style.backgroundSize = "cover"; + node.classList.remove("dashedmenubutton"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else { + node.parentNode.defaultNode = node; + } + } + else { + node.setBackgroundImage(`image/background/${link}.jpg`); + node.style.backgroundSize = "cover"; + } + }, + onclick(background, node) { + if (node && node.firstChild) { + var menu = node.parentNode; + if (node.firstChild.innerHTML == get.verticalStr("隐藏")) { + menu.parentNode.noclose = true; + node.remove(); + menu.updateBr(); + if (!configuration.prompt_hidebg) { + alert("隐藏的背景可通过选项-其它-重置隐藏内容恢复"); + Game.saveConfig("prompt_hidebg", true); + } + configuration.hiddenBackgroundPack.add(background); + Game.saveConfig("hiddenBackgroundPack", configuration.hiddenBackgroundPack); + delete ITEM[background]; + if (configuration.image_background == background) { + background = "default"; + this.lastChild.innerHTML = "默认"; + } + else { + this.lastChild.innerHTML = ITEM[configuration.image_background]; + return; + } + } + else if (node.firstChild.innerHTML == get.verticalStr("删除")) { + menu.parentNode.noclose = true; + if (confirm("是否删除此背景?(此操作不可撤销)")) { + node.remove(); + menu.updateBr(); + configuration.customBackgroundPack.remove(background); + Game.saveConfig("customBackgroundPack", configuration.customBackgroundPack); + if (background.startsWith("cdv_")) { + Game.removeFile(`image/background/${background}.jpg`); + } + else { + Game.deleteDB("image", background); + } + delete ITEM[background]; + if (configuration.image_background == background) { + background = "default"; + this.lastChild.innerHTML = "默认"; + } + else { + this.lastChild.innerHTML = ITEM[configuration.image_background]; + return; + } + } + } + } + Game.saveConfig("image_background", background); + Initialization.background(); + Game.updateBackground(); + }, +}; diff --git a/noname/library/configuration-menu/appearance/configuration/image-background/item.js b/noname/library/configuration-menu/appearance/configuration/image-background/item.js new file mode 100644 index 000000000..69a1c7a1a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/image-background/item.js @@ -0,0 +1 @@ +export const ITEM = {}; diff --git a/noname/library/configuration-menu/appearance/configuration/jiu-effect.js b/noname/library/configuration-menu/appearance/configuration/jiu-effect.js new file mode 100644 index 000000000..694c9d3fb --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/jiu-effect.js @@ -0,0 +1,5 @@ +export const JIU_EFFECT = { + name: "喝酒效果", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/layout.js b/noname/library/configuration-menu/appearance/configuration/layout.js new file mode 100644 index 000000000..ac22ad375 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/layout.js @@ -0,0 +1,158 @@ +import { Game } from "../../../../game.js"; +import { Library } from "../../../../library.js"; +import { Create } from "../../../../ui/create.js"; +import { configuration } from "../../../configuration.js"; +import { Initialization } from "../../../initialization.js"; +import { ITEM } from "./layout/item.js"; + +export const LAYOUT = { + name: "布局", + init: "mobile", + item: ITEM, + visualMenu(node, link) { + node.className = `button character themebutton ${configuration.theme}`; + if (!node.created) { + node.created = true; + node.style.overflow = "hidden"; + node.firstChild.style.display = "none"; + var me = Create.div(node); + me.style.top = "auto"; + if (link == "default" || link == "newlayout") { + me.style.width = "calc(100% - 6px)"; + me.style.left = "3px"; + me.style.bottom = "3px"; + me.style.height = "25px"; + if (link == "newlayout") { + me.style.height = "23px"; + me.style.bottom = "4px"; + } + } + else if (link == "long2" || link == "nova") { + me.style.display = "none"; + } + else { + me.style.width = "120%"; + me.style.left = "-10%"; + me.style.bottom = "0"; + me.style.height = "22px"; + } + me.style.borderRadius = "2px"; + var list = ["re_caocao", "re_liubei", "sp_zhangjiao", "sunquan"]; + for (var i = 0; i < 4; i++) { + var player = Create.div(".fakeplayer", node); + Create.div(".avatar", player).setBackground(list.randomRemove(), "character"); + player.style.borderRadius = "2px"; + if (i != 3) { + player.style.top = "auto"; + } + if (link == "default") { + player.style.height = "19px"; + player.style.width = "38px"; + player.classList.add("oldlayout") + } + else if (link == "mobile" || link == "newlayout") { + player.style.width = "24px"; + player.style.height = "29px"; + } + else if (link == "nova") { + player.style.width = "20px"; + player.style.height = "24px"; + } + else { + player.style.width = "20px"; + player.style.height = "34px"; + } + if (i == 1) { + player.style.left = "3px"; + } + if (i == 2) { + player.style.left = "auto"; + player.style.right = "3px"; + } + if (i == 3) { + player.style.top = "3px"; + } + if (link == "default") { + if (i == 0) { + player.style.bottom = "6px"; + } + if (i == 0 || i == 3) { + player.style.left = "calc(50% - 18px)"; + } + if (i == 1 || i == 2) { + player.style.bottom = "36px"; + } + } + else if (link == "newlayout") { + if (i == 0) { + player.style.bottom = "1px"; + } + if (i == 0 || i == 3) { + player.style.left = "calc(50% - 12px)"; + } + if (i == 1 || i == 2) { + player.style.bottom = "32px"; + } + } + else if (link == "mobile") { + if (i == 0 || i == 3) { + player.style.left = "calc(50% - 12px)"; + } + if (i == 1 || i == 2) { + player.style.bottom = "30px"; + } + } + else if (link == "long") { + if (i == 0 || i == 3) { + player.style.left = "calc(50% - 10px)"; + } + if (i == 1 || i == 2) { + player.style.bottom = "45px"; + } + } + else if (link == "long2") { + if (i == 0) { + player.style.bottom = "2px"; + player.style.left = "3px"; + } + if (i == 3) { + player.style.left = "calc(50% - 10px)"; + } + if (i == 1 || i == 2) { + player.style.bottom = "45px"; + } + } + else if (link == "nova") { + if (i == 0) { + player.style.bottom = "2px"; + player.style.left = "3px"; + } + if (i == 3) { + player.style.left = "calc(50% - 10px)"; + } + if (i == 1 || i == 2) { + player.style.left = "3px"; + player.style.bottom = (i * 30) + "px"; + } + } + + if (i == 0 && (link == "mobile" || link == "long")) { + player.classList.add("me"); + player.style.borderRadius = "0px"; + player.style.width = "25px"; + player.style.height = "25px"; + player.style.bottom = "-3px"; + player.style.left = "-3px"; + } + } + } + }, + onclick(layout) { + if (Library.layoutfixed.includes(configuration.mode)) { + Game.saveConfig("layout", layout); + } + else { + Initialization.layout(layout); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/layout/item.js b/noname/library/configuration-menu/appearance/configuration/layout/item.js new file mode 100644 index 000000000..c4e69294f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/layout/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + newlayout: "对称", + mobile: "默认", + long: "宽屏", + long2: "手杀", + nova: "新版" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/link-style-2.js b/noname/library/configuration-menu/appearance/configuration/link-style-2.js new file mode 100644 index 000000000..2042baca2 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/link-style-2.js @@ -0,0 +1,35 @@ +import { ITEM } from "./link-style-2/item.js"; + +export const LINK_STYLE_2 = { + name: "横置样式", + intro: "设置角色被横置时的样式", + init: "chain", + unfrequent: true, + item: ITEM, + onclick(style) { + var list = []; + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isLinked()) { + list.push(game.players[i]); + } + } + game.saveConfig("link_style2", style); + for (var i = 0; i < list.length; i++) { + if (get.is.linked2(list[i])) { + list[i].classList.add("linked2"); + list[i].classList.remove("linked"); + } + else { + list[i].classList.add("linked"); + list[i].classList.remove("linked2"); + } + } + if (style == "chain") { + ui.arena.classList.remove("nolink"); + } + else { + ui.arena.classList.add("nolink"); + } + ui.updatem(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/link-style-2/item.js b/noname/library/configuration-menu/appearance/configuration/link-style-2/item.js new file mode 100644 index 000000000..de0ffc37c --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/link-style-2/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + chain: "铁索", + rotate: "横置", + mark: "标记" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/menu-style.js b/noname/library/configuration-menu/appearance/configuration/menu-style.js new file mode 100644 index 000000000..d2db6a1da --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/menu-style.js @@ -0,0 +1,114 @@ +import { ITEM } from "./menu-style/item.js"; + +export const MENU_STYLE = { + name: "菜单背景", + init: "default", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "menu_style", file, function () { + game.getDB("image", "menu_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = `url(${data})`; + button.style.backgroundSize = "cover"; + button.className = "button character"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "menu_style"); + button.style.backgroundImage = "none"; + button.style.backgroundSize = "auto"; + button.className = "button character dashedmenubutton"; + node.classList.remove("showdelete"); + if (lib.config.menu_style == "custom") { + lib.configMenu.appearence.config.menu_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button character"; + node.style.backgroundSize = "auto"; + switch (link) { + case "default": case "custom": { + node.style.backgroundImage = "none"; + node.classList.add("dashedmenubutton"); + break; + } + case "wood": node.setBackgroundImage("theme/woodden/wood2.png"); break; + case "music": node.style.backgroundImage = "linear-gradient(#4b4b4b, #464646)"; break; + case "simple": node.style.backgroundImage = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; break; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "menu_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.style.backgroundSize = "cover"; + node.className = "button character"; + node.parentNode.lastChild.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("menu_style", layout); + if (ui.css.menu_stylesheet) { + ui.css.menu_stylesheet.remove(); + delete ui.css.menu_stylesheet; + } + if (layout == "custom") { + game.getDB("image", "menu_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.menu_stylesheet) { + ui.css.menu_stylesheet.remove(); + } + ui.css.menu_stylesheet = lib.init.sheet(`html #window>.dialog.popped,html .menu,html .menubg{background-image:url("${fileLoadedEvent.target.result}");background-size:cover}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else if (layout != "default") { + var str = ""; + switch (layout) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood2.png")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px"; break; + } + ui.css.menu_stylesheet = lib.init.sheet(`html #window>.dialog.popped,html .menu,html .menubg{background-image:${str}}`); + } + }, + unfrequent: true, +}; diff --git a/noname/library/configuration-menu/appearance/configuration/menu-style/item.js b/noname/library/configuration-menu/appearance/configuration/menu-style/item.js new file mode 100644 index 000000000..d24a30c12 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/menu-style/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + wood: "木纹", + music: "音乐", + simple: "简约", + custom: "自定", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/name-font.js b/noname/library/configuration-menu/appearance/configuration/name-font.js new file mode 100644 index 000000000..5fa4950a2 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/name-font.js @@ -0,0 +1,18 @@ +import { ITEM } from "./name-font/item.js"; + +export const NAME_FONT = { + name: "人名字体", + init: "xingkai", + unfrequent: true, + item: ITEM, + textMenu(node, link) { + if (link != "default") { + node.style.fontFamily = link; + } + node.style.fontSize = "20px"; + }, + onclick(font) { + game.saveConfig("name_font", font); + lib.init.cssstyles(); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/name-font/item.js b/noname/library/configuration-menu/appearance/configuration/name-font/item.js new file mode 100644 index 000000000..69a1c7a1a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/name-font/item.js @@ -0,0 +1 @@ +export const ITEM = {}; diff --git a/noname/library/configuration-menu/appearance/configuration/phone-layout.js b/noname/library/configuration-menu/appearance/configuration/phone-layout.js new file mode 100644 index 000000000..1097352e7 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/phone-layout.js @@ -0,0 +1,22 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { Library } from "../../../../library.js"; +import { UI } from "../../../../ui.js"; +import { css } from "../../../../ui/css.js"; + +export const PHONE_LAYOUT = { + name: "触屏布局", + init: false, + onclick(bool) { + if (Is.nomenu("phonelayout", bool)) return false; + Game.saveConfig("phonelayout", bool); + if (Is.phoneLayout()) { + css.phone.href = `${Library.assetURL}layout/default/phone.css`; + UI.arena.classList.add("phone"); + } + else { + css.phone.href = ""; + UI.arena.classList.remove("phone"); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-border.js b/noname/library/configuration-menu/appearance/configuration/player-border.js new file mode 100644 index 000000000..ecf365a34 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-border.js @@ -0,0 +1,37 @@ +import { ITEM } from "./player-border/item.js"; + +export const PLAYER_BORDER = { + name: "边框宽度", + init: "normal", + intro: "设置角色的边框宽度", + unfrequent: true, + item: ITEM, + onclick(item) { + game.saveConfig("player_border", item); + if (item != "wide" || game.layout == "long" || game.layout == "long2") { + ui.arena.classList.add("slim_player"); + } + else { + ui.arena.classList.remove("slim_player"); + } + if (item == "slim") { + ui.arena.classList.add("uslim_player"); + } + else { + ui.arena.classList.remove("uslim_player"); + } + if (item == "narrow") { + ui.arena.classList.add("mslim_player"); + } + else { + ui.arena.classList.remove("mslim_player"); + } + if (item == "normal" && lib.config.mode != "brawl" && (game.layout == "long" || game.layout == "long2")) { + ui.arena.classList.add("lslim_player"); + } + else { + ui.arena.classList.remove("lslim_player"); + } + ui.window.dataset.player_border = item; + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-border/item.js b/noname/library/configuration-menu/appearance/configuration/player-border/item.js new file mode 100644 index 000000000..fe4b10145 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-border/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + slim: "细", + narrow: "窄", + normal: "中", + wide: "宽" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-height-item.js b/noname/library/configuration-menu/appearance/configuration/player-height-item.js new file mode 100644 index 000000000..339f0e038 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-height-item.js @@ -0,0 +1,5 @@ +export const PLAYER_HEIGHT_ITEM = { + short: "矮", + default: "中", + long: "高" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-height-nova.js b/noname/library/configuration-menu/appearance/configuration/player-height-nova.js new file mode 100644 index 000000000..93a2c13a9 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-height-nova.js @@ -0,0 +1,13 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { PLAYER_HEIGHT_ITEM } from "./player-height-item.js"; + +export const PLAYER_HEIGHT_NOVA = { + name: "角色高度", + init: "short", + item: PLAYER_HEIGHT_ITEM, + onclick(item) { + Game.saveConfig("player_height_nova", item); + UI.arena.dataset.player_height_nova = item; + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-height.js b/noname/library/configuration-menu/appearance/configuration/player-height.js new file mode 100644 index 000000000..ee2fd0d4f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-height.js @@ -0,0 +1,13 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { PLAYER_HEIGHT_ITEM } from "./player-height-item.js"; + +export const PLAYER_HEIGHT = { + name: "角色高度", + init: "long", + item: PLAYER_HEIGHT_ITEM, + onclick(item) { + Game.saveConfig("player_height", item); + UI.arena.dataset.player_height = item; + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-style.js b/noname/library/configuration-menu/appearance/configuration/player-style.js new file mode 100644 index 000000000..97a75bce8 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-style.js @@ -0,0 +1,115 @@ +import { ITEM } from "./player-style/item.js"; + +export const PLAYER_STYLE = { + name: "角色背景", + init: "default", + intro: "设置角色的背景图片", + item: ITEM, + visualBar(node, item, create, switcher) { + if (node.created) { + return; + } + var button; + for (var i = 0; i < node.parentNode.childElementCount; i++) { + if (node.parentNode.childNodes[i]._link == "custom") { + button = node.parentNode.childNodes[i]; + } + } + if (!button) { + return; + } + node.created = true; + var deletepic; + ui.create.filediv(".menubutton", "添加图片", node, function (file) { + if (file) { + game.putDB("image", "player_style", file, function () { + game.getDB("image", "player_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + button.style.backgroundImage = "url(" + data + ")"; + button.className = "button character"; + button.style.backgroundSize = "100% 100%"; + node.classList.add("showdelete"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + }); + } + }).inputNode.accept = "image/*"; + deletepic = ui.create.div(".menubutton.deletebutton", "删除图片", node, function () { + if (confirm("确定删除自定义图片?(此操作不可撤销)")) { + game.deleteDB("image", "player_style"); + button.style.backgroundImage = "none"; + button.className = "button character dashedmenubutton"; + node.classList.remove("showdelete"); + if (lib.config.player_style == "custom") { + lib.configMenu.appearence.config.player_style.onclick("default"); + switcher.lastChild.innerHTML = "默认"; + } + button.classList.add("transparent"); + } + }); + }, + visualMenu(node, link, name, config) { + node.className = "button character"; + node.style.backgroundSize = ""; + node.style.height = "108px"; + switch (link) { + case "default": case "custom": { + node.style.backgroundImage = "none"; + node.className = "button character dashedmenubutton"; + break; + } + case "wood": node.setBackgroundImage("theme/woodden/wood.jpg"); break; + case "music": node.style.backgroundImage = "linear-gradient(#4b4b4b, #464646)"; break; + case "simple": node.style.backgroundImage = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; break; + } + if (link == "custom") { + node.classList.add("transparent"); + game.getDB("image", "player_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + node.style.backgroundImage = "url(" + data + ")"; + node.className = "button character"; + node.parentNode.lastChild.classList.add("showdelete"); + node.style.backgroundSize = "100% 100%"; + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + }, + onclick(layout) { + game.saveConfig("player_style", layout); + if (ui.css.player_stylesheet) { + ui.css.player_stylesheet.remove(); + delete ui.css.player_stylesheet; + } + if (layout == "custom") { + game.getDB("image", "player_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.player_stylesheet) { + ui.css.player_stylesheet.remove(); + } + ui.css.player_stylesheet = lib.init.sheet(`#window .player{background-image:url("${fileLoadedEvent.target.result}");background-size:100% 100%;}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + else if (layout != "default") { + var str = ""; + switch (layout) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood.jpg")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646)"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; break; + } + ui.css.player_stylesheet = lib.init.sheet(`#window .player{background-image:${str}}`); + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/appearance/configuration/player-style/item.js b/noname/library/configuration-menu/appearance/configuration/player-style/item.js new file mode 100644 index 000000000..d24a30c12 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/player-style/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + wood: "木纹", + music: "音乐", + simple: "简约", + custom: "自定", + default: "默认" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/radius-size.js b/noname/library/configuration-menu/appearance/configuration/radius-size.js new file mode 100644 index 000000000..6b5bc027f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/radius-size.js @@ -0,0 +1,12 @@ +import { ITEM } from "./radius-size/item.js"; + +export const RADIUS_SIZE = { + name: "圆角大小", + init: "default", + item: ITEM, + unfrequent: true, + onclick(item) { + game.saveConfig("radius_size", item); + ui.window.dataset.radius_size = item; + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/radius-size/item.js b/noname/library/configuration-menu/appearance/configuration/radius-size/item.js new file mode 100644 index 000000000..3839d7906 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/radius-size/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + off: "关闭", + reduce: "减小", + default: "默认", + increase: "增大" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/separate-control.js b/noname/library/configuration-menu/appearance/configuration/separate-control.js new file mode 100644 index 000000000..f2598cfe2 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/separate-control.js @@ -0,0 +1,6 @@ +export const SEPARATE_CONTROL = { + name: "分离选项条", + init: true, + unfrequent: true, + intro: "开启后玩家在进行选择时不同的选项将分开,而不是连在一起" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/skill-animation-type.js b/noname/library/configuration-menu/appearance/configuration/skill-animation-type.js new file mode 100644 index 000000000..4a0a9bd0c --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/skill-animation-type.js @@ -0,0 +1,9 @@ +import { ITEM } from "./skill-animation-type/item.js"; + +export const SKILL_ANIMATION_TYPE = { + name: "技能特效", + intro: "开启后觉醒技、限定技将显示全屏文字", + init: "default", + unfrequent: true, + item: ITEM +}; diff --git a/noname/library/configuration-menu/appearance/configuration/skill-animation-type/item.js b/noname/library/configuration-menu/appearance/configuration/skill-animation-type/item.js new file mode 100644 index 000000000..46ba99fe0 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/skill-animation-type/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + default: "默认", + old: "旧版", + off: "关闭" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/splash-style.js b/noname/library/configuration-menu/appearance/configuration/splash-style.js new file mode 100644 index 000000000..bf230e5db --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/splash-style.js @@ -0,0 +1,16 @@ +import { ITEM } from "./splash-style/item.js"; + +export const SPLASH_STYLE = { + name: "启动页", + item: ITEM, + visualMenu(node, link) { + node.className = "button character"; + node.style.width = "200px"; + node.style.height = `${node.offsetWidth * 1080 / 2400}px`; + node.style.display = "flex"; + node.style.flexDirection = "column"; + node.style.alignItems = "center"; + node.style.backgroundSize = "100% 100%"; + node.setBackgroundImage(`image/splash/${link}.jpg`); + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/splash-style/item.js b/noname/library/configuration-menu/appearance/configuration/splash-style/item.js new file mode 100644 index 000000000..8ea88f873 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/splash-style/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + style1: "样式一", + style2: "样式二" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/suits-font.js b/noname/library/configuration-menu/appearance/configuration/suits-font.js new file mode 100644 index 000000000..4a1d7a4a6 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/suits-font.js @@ -0,0 +1,6 @@ +export const SUITS_FONT = { + name: "替换花色字体", + init: true, + unfrequent: true, + intro: "使用全角字符的花色替代系统自带的花色(重启游戏后生效)" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/target-shake.js b/noname/library/configuration-menu/appearance/configuration/target-shake.js new file mode 100644 index 000000000..9e0fddd55 --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/target-shake.js @@ -0,0 +1,13 @@ +import { ITEM } from "./target-shake/item.js"; + +export const TARGET_SHAKE = { + name: "目标效果", + intro: "一名玩家成为卡牌或技能的目标时的显示效果", + init: "off", + item: ITEM, + unfrequent: true, + onclick(bool) { + game.saveConfig("target_shake", bool); + ui.arena.dataset.target_shake = bool; + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/target-shake/item.js b/noname/library/configuration-menu/appearance/configuration/target-shake/item.js new file mode 100644 index 000000000..64663612b --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/target-shake/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + off: "关闭", + zoom: "缩放", + shake: "抖动" +}; diff --git a/noname/library/configuration-menu/appearance/configuration/theme.js b/noname/library/configuration-menu/appearance/configuration/theme.js new file mode 100644 index 000000000..2d8c0be8e --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/theme.js @@ -0,0 +1,46 @@ +import { Game } from "../../../../game.js"; +import { GNC } from "../../../../gnc.js"; +import { Library } from "../../../../library.js"; +import { UI } from "../../../../ui.js"; +import { Create } from "../../../../ui/create.js"; +import { css } from "../../../../ui/css.js"; +import { announce } from "../../../announce.js"; +import { configuration } from "../../../configuration.js"; +import { Initialization } from "../../../initialization.js"; +import { ITEM } from "./theme/item.js"; + +export const THEME = { + name: "主题", + init: "woodden", + item: ITEM, + visualMenu(node, link) { + if (!node.menu) { + node.className = `button character themebutton ${link}`; + node.menu = Create.div(node, "", "
"); + } + }, + onclick: GNC.of(function* (theme) { + Game.saveConfig("theme", theme); + UI.arena.hide(); + Initialization.background(); + if (configuration.autostyle) { + if (theme === "simple") { + Library.configMenu.appearence.config.player_border.onclick("slim"); + } + else { + Library.configMenu.appearence.config.player_border.onclick("normal"); + } + } + announce.publish("Noname.Apperaence.Theme.onChanging", theme); + yield new Promise(resolve => setTimeout(resolve, 500)); + + const deletingTheme = css.theme; + css.theme = Initialization.css(`${Library.assetURL}theme/${configuration.theme}`, "style"); + deletingTheme.remove(); + announce.publish("Noname.Apperaence.Theme.onChanged", theme); + yield new Promise(resolve => setTimeout(resolve, 100)); + + UI.arena.show(); + announce.publish("Noname.Apperaence.Theme.onChangeFinished", theme); + }) +}; diff --git a/noname/library/configuration-menu/appearance/configuration/theme/item.js b/noname/library/configuration-menu/appearance/configuration/theme/item.js new file mode 100644 index 000000000..69a1c7a1a --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/theme/item.js @@ -0,0 +1 @@ +export const ITEM = {}; diff --git a/noname/library/configuration-menu/appearance/configuration/turned-style.js b/noname/library/configuration-menu/appearance/configuration/turned-style.js new file mode 100644 index 000000000..9d156ed1e --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/turned-style.js @@ -0,0 +1,15 @@ +export const TURNED_STYLE = { + name: "翻面文字", + intro: "角色被翻面时显示“翻面”", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("turned_style", bool); + if (bool) { + ui.arena.classList.remove("hide_turned"); + } + else { + ui.arena.classList.add("hide_turned"); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/ui-zoom.js b/noname/library/configuration-menu/appearance/configuration/ui-zoom.js new file mode 100644 index 000000000..242a8f34f --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/ui-zoom.js @@ -0,0 +1,33 @@ +import { Game } from "../../../../game.js"; +import { Library } from "../../../../library.js"; +import { UI } from "../../../../ui.js"; +import { ITEM } from "./ui-zoom/item.js"; + +export const UI_ZOOM = { + name: "界面缩放", + unfrequent: true, + init: "normal", + item: ITEM, + onclick(zoom) { + Game.saveConfig("ui_zoom", zoom); + switch (zoom) { + case "esmall": zoom = 0.8; break; + case "vsmall": zoom = 0.9; break; + case "small": zoom = 0.93; break; + case "big": zoom = 1.05; break; + case "vbig": zoom = 1.1; break; + case "ebig": zoom = 1.2; break; + case "eebig": zoom = 1.5; break; + case "eeebig": zoom = 1.8; break; + case "eeeebig": zoom = 2; break; + default: zoom = 1; + } + Game.documentZoom = Game.deviceZoom * zoom; + UI.updatez(); + if (Array.isArray(Library.onresize)) { + Library.onresize.forEach(fun => { + if (typeof fun == "function") fun(); + }); + } + } +}; diff --git a/noname/library/configuration-menu/appearance/configuration/ui-zoom/item.js b/noname/library/configuration-menu/appearance/configuration/ui-zoom/item.js new file mode 100644 index 000000000..ac58ff7dc --- /dev/null +++ b/noname/library/configuration-menu/appearance/configuration/ui-zoom/item.js @@ -0,0 +1,12 @@ +export const ITEM = { + esmall: "80%", + vsmall: "90%", + small: "95%", + normal: "100%", + big: "105%", + vbig: "110%", + ebig: "120%", + eebig: "150%", + eeebig: "180%", + eeeebig: "200%" +}; diff --git a/noname/library/configuration-menu/audio.js b/noname/library/configuration-menu/audio.js new file mode 100644 index 000000000..c799d0a27 --- /dev/null +++ b/noname/library/configuration-menu/audio.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./audio/configuration.js"; + +export const AUDIO = { + name: "音效", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/audio/configuration.js b/noname/library/configuration-menu/audio/configuration.js new file mode 100644 index 000000000..1885f4ecc --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration.js @@ -0,0 +1,32 @@ +import { BACKGROUND_AUDIO } from "./configuration/background-audio.js"; +import { BACKGROUND_MUSIC } from "./configuration/background-music.js"; +import { BACKGROUND_SPEAK } from "./configuration/background-speak.js"; +import { CLEAR_BACKGROUND_MUSIC } from "./configuration/clear-background-music.js"; +import { EQUIP_AUDIO } from "./configuration/equip-audio.js"; +import { IMPORT_MUSIC } from "./configuration/import-music.js"; +import { REPEAT_AUDIO } from "./configuration/repeat-audio.js"; +import { VOLUME_AUDIO } from "./configuration/volume-audio.js"; +import { VOLUME_BACKGROUND } from "./configuration/volume-background.js"; + +export const CONFIGURATION = { + update(config, map) { + if (config.background_music == "music_custom" && (lib.device || lib.node)) { + map.import_music.show(); + } + else { + map.import_music.hide(); + } + map.clear_background_music[get.is.object(config.customBackgroundMusic) ? "show" : "hide"](); + ui.background_music_setting = map.background_music; + map.background_music._link.config.updatex.call(map.background_music, []); + }, + background_music: BACKGROUND_MUSIC, + import_music: IMPORT_MUSIC, + background_audio: BACKGROUND_AUDIO, + background_speak: BACKGROUND_SPEAK, + equip_audio: EQUIP_AUDIO, + repeat_audio: REPEAT_AUDIO, + volumn_audio: VOLUME_AUDIO, + volumn_background: VOLUME_BACKGROUND, + clear_background_music: CLEAR_BACKGROUND_MUSIC +}; diff --git a/noname/library/configuration-menu/audio/configuration/background-audio.js b/noname/library/configuration-menu/audio/configuration/background-audio.js new file mode 100644 index 000000000..f627a8219 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/background-audio.js @@ -0,0 +1,4 @@ +export const BACKGROUND_AUDIO = { + name: "游戏音效", + init: true +}; diff --git a/noname/library/configuration-menu/audio/configuration/background-music.js b/noname/library/configuration-menu/audio/configuration/background-music.js new file mode 100644 index 000000000..4be23a96c --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/background-music.js @@ -0,0 +1,18 @@ +import { ITEM } from "./background-music/item.js"; + +export const BACKGROUND_MUSIC = { + updatex() { + this.lastChild.innerHTML = this._link.config.item[lib.config.background_music]; + var menu = this._link.menu; + for (var i = 0; i < menu.childElementCount; i++) { + if (!["music_off", "music_custom", "music_random"].concat(lib.config.all.background_music).includes(menu.childNodes[i]._link)) menu.childNodes[i].delete(); + } + }, + name: "背景音乐", + init: true, + item: ITEM, + onclick(item) { + game.saveConfig("background_music", item); + game.playBackgroundMusic(); + } +}; diff --git a/noname/library/configuration-menu/audio/configuration/background-music/item.js b/noname/library/configuration-menu/audio/configuration/background-music/item.js new file mode 100644 index 000000000..fd62bea33 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/background-music/item.js @@ -0,0 +1,3 @@ +export const ITEM = { + music_default: "默认" +}; diff --git a/noname/library/configuration-menu/audio/configuration/background-speak.js b/noname/library/configuration-menu/audio/configuration/background-speak.js new file mode 100644 index 000000000..434cb80e7 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/background-speak.js @@ -0,0 +1,4 @@ +export const BACKGROUND_SPEAK = { + name: "人物配音", + init: true +}; diff --git a/noname/library/configuration-menu/audio/configuration/clear-background-music.js b/noname/library/configuration-menu/audio/configuration/clear-background-music.js new file mode 100644 index 000000000..77344c6bf --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/clear-background-music.js @@ -0,0 +1,21 @@ +export const CLEAR_BACKGROUND_MUSIC = { + name: "清除自定义背景音乐", + clear: true, + onclick() { + if (confirm("是否清除已导入的所有自定义背景音乐?(该操作不可撤销!)")) { + for (var i in lib.config.customBackgroundMusic) { + lib.config.all.background_music.remove(i); + if (i.startsWith("cdv_")) { + game.removeFile("audio/background/" + i + ".mp3"); + } + else { + game.deleteDB("audio", i); + } + } + lib.config.customBackgroundMusic = null; + game.saveConfig("customBackgroundMusic", null); + game.saveConfig("background_music", "music_off"); + if (!_status._aozhan) game.playBackgroundMusic(); + } + } +}; diff --git a/noname/library/configuration-menu/audio/configuration/equip-audio.js b/noname/library/configuration-menu/audio/configuration/equip-audio.js new file mode 100644 index 000000000..8601de4f7 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/equip-audio.js @@ -0,0 +1,4 @@ +export const EQUIP_AUDIO = { + name: "装备配音", + init: false +}; diff --git a/noname/library/configuration-menu/audio/configuration/import-music.js b/noname/library/configuration-menu/audio/configuration/import-music.js new file mode 100644 index 000000000..77e806ea9 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/import-music.js @@ -0,0 +1,18 @@ +const div = document.createElement("div"); +const style = div.style; +style.whiteSpace = "nowrap"; +style.width = "calc(100% - 5px)"; +const input = document.createElement("input"); +input.accept = "audio/*"; +input.style.width = "calc(100% - 40px)"; +input.type = "file"; +div.append(input); +const button = document.createElement("button"); +button.style.width = "40px"; +button.append("确定"); +div.append(button); + +export const IMPORT_MUSIC = { + name: div.outerHTML, + clear: true +} diff --git a/noname/library/configuration-menu/audio/configuration/repeat-audio.js b/noname/library/configuration-menu/audio/configuration/repeat-audio.js new file mode 100644 index 000000000..84bbaf69b --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/repeat-audio.js @@ -0,0 +1,4 @@ +export const REPEAT_AUDIO = { + name: "播放重复语音", + init: false +}; diff --git a/noname/library/configuration-menu/audio/configuration/volume-audio.js b/noname/library/configuration-menu/audio/configuration/volume-audio.js new file mode 100644 index 000000000..e18726bab --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/volume-audio.js @@ -0,0 +1,10 @@ +import { VOLUME_ITEM } from "./volume-item.js"; + +export const VOLUME_AUDIO = { + name: "音效音量", + init: 8, + item: VOLUME_ITEM, + onclick(volume) { + game.saveConfig("volumn_audio", parseInt(volume)); + } +}; diff --git a/noname/library/configuration-menu/audio/configuration/volume-background.js b/noname/library/configuration-menu/audio/configuration/volume-background.js new file mode 100644 index 000000000..ef52f0a34 --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/volume-background.js @@ -0,0 +1,11 @@ +import { VOLUME_ITEM } from "./volume-item.js"; + +export const VOLUME_BACKGROUND = { + name: "音乐音量", + init: 8, + item: VOLUME_ITEM, + onclick(volume) { + game.saveConfig("volumn_background", parseInt(volume)); + ui.backgroundMusic.volume = volume / 8; + } +}; diff --git a/noname/library/configuration-menu/audio/configuration/volume-item.js b/noname/library/configuration-menu/audio/configuration/volume-item.js new file mode 100644 index 000000000..99f1fb27d --- /dev/null +++ b/noname/library/configuration-menu/audio/configuration/volume-item.js @@ -0,0 +1,11 @@ +export const VOLUME_ITEM = { + "0": "〇", + "1": "一", + "2": "二", + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "7": "七", + "8": "八" +}; diff --git a/noname/library/configuration-menu/general.js b/noname/library/configuration-menu/general.js new file mode 100644 index 000000000..c7112b78a --- /dev/null +++ b/noname/library/configuration-menu/general.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./general/configuration.js"; + +export const GENERAL = { + name: "通用", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/general/configuration.js b/noname/library/configuration-menu/general/configuration.js new file mode 100644 index 000000000..449cde010 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration.js @@ -0,0 +1,187 @@ +import { Is } from "../../../get/is.js"; +import { Library } from "../../../library.js"; +import { AUTOMATICALLY_CHECK_UPDATE } from "./configuration/automatically-check-update.js"; +import { AUTOMATICALLY_CONFIRM } from "./configuration/automatically-confirm.js"; +import { COMPATIBLE_MODE } from "./configuration/compatible-mode.js"; +import { CONFIRM_EXIT } from "./configuration/confirm-exit.js"; +import { DEVELOPER } from "./configuration/developer.js"; +import { DOUBLE_CLICK_INTRODUCTION } from "./configuration/double-click-introduction.js"; +import { ENABLE_DRAG_LINE } from "./configuration/enable-drag-line.js"; +import { ENABLE_DRAG } from "./configuration/enable-drag.js"; +import { ENABLE_TOUCH_DRAG_LINE } from "./configuration/enable-touch-drag-line.js"; +import { ENABLE_VIBRATE } from "./configuration/enable-vibrate.js"; +import { ERROR_STOP } from "./configuration/error-stop.js"; +import { EXTENSION_CREATE } from "./configuration/extension-create.js"; +import { EXTENSION_DELETE } from "./configuration/extension-delete.js"; +import { EXTENSION_SOURCE } from "./configuration/extension-source.js"; +import { FUCK_SO_JSON } from "./configuration/fuck-so-json.js"; +import { GAME_SPEED } from "./configuration/game-speed.js"; +import { HOVER_ALL } from "./configuration/hover-all.js"; +import { HOVER_HAND_CARD } from "./configuration/hover-hand-card.js"; +import { HOVERATION } from "./configuration/hoveration.js"; +import { KEEP_AWAKE } from "./configuration/keep-awake.js"; +import { LONG_PRESS_INFORMATION } from "./configuration/long-press-information.js"; +import { LOW_PERFORMANCE } from "./configuration/low-performance.js"; +import { LUCKY_STAR } from "./configuration/lucky-star.js"; +import { MAXIMUM_LOAD_TIME } from "./configuration/maximum-load-time.js"; +import { MOUNT_COMBINE } from "./configuration/mount-combine.js"; +import { MOUSE_WHEEL } from "./configuration/mouse-wheel.js"; +import { RIGHT_CLICK } from "./configuration/right-click.js"; +import { RIGHT_INFORMATION } from "./configuration/right-information.js"; +import { ROUND_MENU_FUNCTION } from "./configuration/round-menu-function.js"; +import { SHOW_SPLASH } from "./configuration/show-splash.js"; +import { SKIP_SHAN } from "./configuration/skip-shan.js"; +import { SWIPE_DOWN } from "./configuration/swipe-down.js"; +import { SWIPE_LEFT } from "./configuration/swipe-left.js"; +import { SWIPE_RIGHT } from "./configuration/swipe-right.js"; +import { SWIPE_UP } from "./configuration/swipe-up.js"; +import { SWIPE } from "./configuration/swipe.js"; +import { SYNCHRONIZE_SPEED } from "./configuration/synchronize-speed.js"; +import { TAO_ENEMY } from "./configuration/tao-enemy.js"; +import { TOUCHSCREEN } from "./configuration/touchscreen.js"; +import { UN_AUTOMATICALLY_CHOOSE } from "./configuration/un-automatically-choose.js"; +import { UPDATE_LINK } from "./configuration/update-link.js"; +import { VIDEO } from "./configuration/video.js"; +import { WUXIE_SELF } from "./configuration/wuxie-self.js"; + +export const CONFIGURATION = { + mount_combine: MOUNT_COMBINE, + low_performance: LOW_PERFORMANCE, + compatiblemode: COMPATIBLE_MODE, + confirm_exit: CONFIRM_EXIT, + keep_awake: KEEP_AWAKE, + auto_confirm: AUTOMATICALLY_CONFIRM, + skip_shan: SKIP_SHAN, + unauto_choose: UN_AUTOMATICALLY_CHOOSE, + wuxie_self: WUXIE_SELF, + tao_enemy: TAO_ENEMY, + enable_drag: ENABLE_DRAG, + enable_dragline: ENABLE_DRAG_LINE, + enable_touchdragline: ENABLE_TOUCH_DRAG_LINE, + touchscreen: TOUCHSCREEN, + swipe: SWIPE, + swipe_down: SWIPE_DOWN, + swipe_up: SWIPE_UP, + swipe_left: SWIPE_LEFT, + swipe_right: SWIPE_RIGHT, + round_menu_func: ROUND_MENU_FUNCTION, + show_splash: SHOW_SPLASH, + game_speed: GAME_SPEED, + sync_speed: SYNCHRONIZE_SPEED, + enable_vibrate: ENABLE_VIBRATE, + right_click: RIGHT_CLICK, + longpress_info: LONG_PRESS_INFORMATION, + right_info: RIGHT_INFORMATION, + hover_all: HOVER_ALL, + hover_handcard: HOVER_HAND_CARD, + hoveration: HOVERATION, + doubleclick_intro: DOUBLE_CLICK_INTRODUCTION, + video: VIDEO, + max_loadtime: MAXIMUM_LOAD_TIME, + mousewheel: MOUSE_WHEEL, + auto_check_update: AUTOMATICALLY_CHECK_UPDATE, + lucky_star: LUCKY_STAR, + dev: DEVELOPER, + fuck_sojson: FUCK_SO_JSON, + errstop: ERROR_STOP, + update_link: UPDATE_LINK, + extension_source: EXTENSION_SOURCE, + extension_create: EXTENSION_CREATE, + extension_delete: EXTENSION_DELETE, + update(config, map) { + if ("ontouchstart" in document) { + map.touchscreen.show(); + } + else { + map.touchscreen.hide(); + } + if (Library.device || Library.node) { + map.auto_check_update.show(); + } + else { + map.auto_check_update.hide(); + } + if (Library.device) { + map.enable_vibrate.show(); + map.keep_awake.show(); + } + else { + map.enable_vibrate.hide(); + map.keep_awake.hide(); + } + if (config.touchscreen) { + map.mousewheel.hide(); + map.hover_all.hide(); + map.hover_handcard.hide(); + map.hoveration.hide(); + map.right_info.hide(); + map.right_click.hide(); + map.longpress_info.show(); + map.swipe.show(); + if (config.swipe) { + map.swipe_up.show(); + map.swipe_down.show(); + map.swipe_left.show(); + map.swipe_right.show(); + } + else { + map.swipe_up.hide(); + map.swipe_down.hide(); + map.swipe_left.hide(); + map.swipe_right.hide(); + } + } + else { + map.mousewheel.show(); + map.hover_all.show(); + map.right_info.show(); + map.right_click.show(); + map.longpress_info.hide(); + if (!config.hover_all) { + map.hover_handcard.hide(); + map.hoveration.hide(); + } + else { + map.hover_handcard.show(); + map.hoveration.show(); + } + map.swipe.hide(); + map.swipe_up.hide(); + map.swipe_down.hide(); + map.swipe_left.hide(); + map.swipe_right.hide(); + } + if (config.enable_drag) { + if (config.touchscreen) { + map.enable_dragline.hide(); + map.enable_touchdragline.show(); + } + else { + map.enable_dragline.show(); + map.enable_touchdragline.hide(); + } + } + else { + map.enable_dragline.hide(); + map.enable_touchdragline.hide(); + } + if (!Is.phoneLayout()) { + map.round_menu_func.hide(); + } + else { + map.round_menu_func.show(); + } + if (!Library.node && Library.device != "ios") { + map.confirm_exit.show(); + } + else { + map.confirm_exit.hide(); + } + if (config.dev) { + map.errstop.show(); + } + else { + map.errstop.hide(); + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/automatically-check-update.js b/noname/library/configuration-menu/general/configuration/automatically-check-update.js new file mode 100644 index 000000000..ef554d1a5 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/automatically-check-update.js @@ -0,0 +1,6 @@ +export const AUTOMATICALLY_CHECK_UPDATE = { + name: "自动检查游戏更新", + intro: "进入游戏时检查更新", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/automatically-confirm.js b/noname/library/configuration-menu/general/configuration/automatically-confirm.js new file mode 100644 index 000000000..93b54b8e7 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/automatically-confirm.js @@ -0,0 +1,6 @@ +export const AUTOMATICALLY_CONFIRM = { + name: "自动确认", + init: true, + unfrequent: true, + intro: "当候选目标只有1个时,点击目标后无需再点击确认" +}; diff --git a/noname/library/configuration-menu/general/configuration/compatible-mode.js b/noname/library/configuration-menu/general/configuration/compatible-mode.js new file mode 100644 index 000000000..3eceacf21 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/compatible-mode.js @@ -0,0 +1,17 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; + +export const COMPATIBLE_MODE = { + name: "兼容模式", + init: false, + intro: "开启兼容模式可防止扩展使游戏卡死并提高对旧扩展的兼容性,但对游戏速度有一定影响,若无不稳定或不兼容的扩展建议关闭", + onclick(bool) { + Game.saveConfig("compatiblemode", bool); + if (bool) { + UI.window.classList.add("compatiblemode"); + } + else { + UI.window.classList.remove("compatiblemode"); + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/confirm-exit.js b/noname/library/configuration-menu/general/configuration/confirm-exit.js new file mode 100644 index 000000000..6b41ac4b3 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/confirm-exit.js @@ -0,0 +1,6 @@ +export const CONFIRM_EXIT = { + name: "确认退出", + init: false, + unfrequent: true, + intro: "离开游戏前弹出确认对话框" +}; diff --git a/noname/library/configuration-menu/general/configuration/developer.js b/noname/library/configuration-menu/general/configuration/developer.js new file mode 100644 index 000000000..8c4d0e25f --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/developer.js @@ -0,0 +1,26 @@ +import { Game } from "../../../../game.js"; +import { status } from "../../../../status.js"; +import { Cheat } from "../../../cheat.js"; + +export const DEVELOPER = { + name: "开发者模式", + intro: "开启后可使用浏览器控制台控制游戏,同时可更新到开发版", + init: false, + onclick(bool) { + Game.saveConfig("dev", bool); + if (status.connectMode) return; + if (bool) { + Cheat.i(); + } + else { + delete window.cheat; + delete window.game; + delete window.ui; + delete window.get; + delete window.ai; + delete window.lib; + delete window._status; + } + }, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/double-click-introduction.js b/noname/library/configuration-menu/general/configuration/double-click-introduction.js new file mode 100644 index 000000000..8fc08de74 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/double-click-introduction.js @@ -0,0 +1,6 @@ +export const DOUBLE_CLICK_INTRODUCTION = { + name: "双击显示武将资料", + init: true, + unfrequent: true, + intro: "双击武将头像后显示其资料卡" +}; diff --git a/noname/library/configuration-menu/general/configuration/enable-drag-line.js b/noname/library/configuration-menu/general/configuration/enable-drag-line.js new file mode 100644 index 000000000..5b12bc7a6 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/enable-drag-line.js @@ -0,0 +1,6 @@ +export const ENABLE_DRAG_LINE = { + name: "拖拽指示线", + init: true, + unfrequent: true, + intro: "拖拽时显示虚线,可能降低游戏速度" +}; diff --git a/noname/library/configuration-menu/general/configuration/enable-drag.js b/noname/library/configuration-menu/general/configuration/enable-drag.js new file mode 100644 index 000000000..e8295f14f --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/enable-drag.js @@ -0,0 +1,6 @@ +export const ENABLE_DRAG = { + name: "启用拖拽", + init: true, + intro: "按住卡牌后可将卡牌拖至目标", + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/enable-touch-drag-line.js b/noname/library/configuration-menu/general/configuration/enable-touch-drag-line.js new file mode 100644 index 000000000..25a13e11d --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/enable-touch-drag-line.js @@ -0,0 +1,6 @@ +export const ENABLE_TOUCH_DRAG_LINE = { + name: "拖拽指示线", + init: false, + unfrequent: true, + intro: "拖拽时显示虚线,可能降低游戏速度" +}; diff --git a/noname/library/configuration-menu/general/configuration/enable-vibrate.js b/noname/library/configuration-menu/general/configuration/enable-vibrate.js new file mode 100644 index 000000000..51aae6869 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/enable-vibrate.js @@ -0,0 +1,5 @@ +export const ENABLE_VIBRATE = { + name: "开启震动", + intro: "回合开始时使手机震动", + init: false +}; diff --git a/noname/library/configuration-menu/general/configuration/error-stop.js b/noname/library/configuration-menu/general/configuration/error-stop.js new file mode 100644 index 000000000..a94d4edae --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/error-stop.js @@ -0,0 +1,5 @@ +export const ERROR_STOP = { + name: "出错时停止游戏", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/extension-create.js b/noname/library/configuration-menu/general/configuration/extension-create.js new file mode 100644 index 000000000..cbc60ef29 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/extension-create.js @@ -0,0 +1,51 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { Create } from "../../../../ui/create.js"; +import { configuration } from "../../../configuration.js"; + +export const EXTENSION_CREATE = { + name: "添加获取扩展地址", + clear: true, + unfrequent: true, + onclick() { + Game.prompt("请输入地址名称", str => { + if (!str) return; + + var map = configuration.extension_sources; + Game.prompt(`请输入${str}的地址`, str2 => { + if (!str2) return; + + delete map[str]; + map[str] = str2; + Game.saveConfig("extension_sources", map); + Game.saveConfig("extension_source", str); + var nodexx = UI.extension_source; + nodexx.updateInner(); + var nodeyy = nodexx._link.menu; + var nodezz = nodexx._link.config; + for (var i = 0; i < nodeyy.childElementCount; i++) { + if (nodeyy.childNodes[i]._link != str) continue; + + nodeyy.childNodes[i].remove(); + break; + } + var textMenu = Create.div("", str, nodeyy, function () { + var node = this.parentNode._link; + var config = node._link.config; + node._link.current = this.link; + var tmpName = node.lastChild.innerHTML; + node.lastChild.innerHTML = config.item[this._link]; + if (config.onclick && config.onclick.call(node, this._link, this) === false) { + node.lastChild.innerHTML = tmpName; + } + if (config.update) { + config.update(); + } + }); + textMenu._link = str; + nodezz.item[name] = str; + alert(`已添加扩展地址:${str}`); + }); + }); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/extension-delete.js b/noname/library/configuration-menu/general/configuration/extension-delete.js new file mode 100644 index 000000000..9ddec9cdb --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/extension-delete.js @@ -0,0 +1,38 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { configuration } from "../../../configuration.js"; + +export const EXTENSION_DELETE = { + name: "删除当前扩展地址", + clear: true, + unfrequent: true, + onclick() { + var bool = false, map = configuration.extension_sources; + for (var i in map) { + if (i != configuration.extension_source) { + bool = true; + break; + } + } + if (!bool) { + alert("不能删除最后一个扩展地址!"); + return; + } + var name = configuration.extension_source; + Game.saveConfig("extension_source", i); + delete map[name]; + Game.saveConfig("extension_sources", map); + var nodexx = UI.extension_source; + nodexx.updateInner(); + var nodeyy = nodexx._link.menu; + var nodezz = nodexx._link.config; + for (var i = 0; i < nodeyy.childElementCount; i++) { + if (nodeyy.childNodes[i]._link == name) { + nodeyy.childNodes[i].remove(); + break; + } + } + delete nodezz.item[name]; + alert(`已删除扩展地址:${name}`); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/extension-source.js b/noname/library/configuration-menu/general/configuration/extension-source.js new file mode 100644 index 000000000..3498dec4e --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/extension-source.js @@ -0,0 +1,16 @@ +import { configuration } from "../../../configuration.js"; + +export const EXTENSION_SOURCE = { + name: "获取扩展地址", + init: "GitHub Proxy", + unfrequent: true, + get item() { + return configuration.extension_sources; + }, + intro() { + const introduction = document.createElement("body"); + introduction.append("获取在线扩展时的地址。当前地址:", document.createElement("br")); + introduction.append(configuration.extension_sources[configuration.extension_source]); + return introduction.innerHTML; + } +}; diff --git a/noname/library/configuration-menu/general/configuration/fuck-so-json.js b/noname/library/configuration-menu/general/configuration/fuck-so-json.js new file mode 100644 index 000000000..2ce8b8b2a --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/fuck-so-json.js @@ -0,0 +1,4 @@ +export const FUCK_SO_JSON = { + name: "检测加密扩展", + init: false +}; diff --git a/noname/library/configuration-menu/general/configuration/game-speed.js b/noname/library/configuration-menu/general/configuration/game-speed.js new file mode 100644 index 000000000..ff6d197c7 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/game-speed.js @@ -0,0 +1,8 @@ +import { ITEM } from "./game-speed/item.js"; + +export const GAME_SPEED = { + name: "游戏速度", + init: "mid", + item: ITEM, + intro: "设置不同游戏操作间的时间间隔" +}; diff --git a/noname/library/configuration-menu/general/configuration/game-speed/item.js b/noname/library/configuration-menu/general/configuration/game-speed/item.js new file mode 100644 index 000000000..7b1214f9c --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/game-speed/item.js @@ -0,0 +1,8 @@ +export const ITEM = { + vslow: "慢", + slow: "较慢", + mid: "中", + fast: "较快", + vfast: "快", + vvfast: "很快" +}; diff --git a/noname/library/configuration-menu/general/configuration/hover-all.js b/noname/library/configuration-menu/general/configuration/hover-all.js new file mode 100644 index 000000000..931dd5db2 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/hover-all.js @@ -0,0 +1,7 @@ +export const HOVER_ALL = { + name: "悬停显示信息", + init: true, + unfrequent: true, + restart: true, + intro: "悬停后弹出菜单" +}; diff --git a/noname/library/configuration-menu/general/configuration/hover-hand-card.js b/noname/library/configuration-menu/general/configuration/hover-hand-card.js new file mode 100644 index 000000000..12e6df9aa --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/hover-hand-card.js @@ -0,0 +1,6 @@ +export const HOVER_HAND_CARD = { + name: "悬停手牌显示信息", + init: true, + unfrequent: true, + intro: "悬停手牌后弹出菜单" +}; diff --git a/noname/library/configuration-menu/general/configuration/hoveration.js b/noname/library/configuration-menu/general/configuration/hoveration.js new file mode 100644 index 000000000..8017f172a --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/hoveration.js @@ -0,0 +1,9 @@ +import { ITEM } from "./hoveration/item.js"; + +export const HOVERATION = { + name: "悬停菜单弹出时间", + unfrequent: true, + intro: "鼠标移至目标到弹出菜单的时间间隔", + init: "1000", + item: ITEM +}; diff --git a/noname/library/configuration-menu/general/configuration/hoveration/item.js b/noname/library/configuration-menu/general/configuration/hoveration/item.js new file mode 100644 index 000000000..b850049b8 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/hoveration/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + "500": "0.5秒", + "700": "0.7秒", + "1000": "1秒", + "1500": "1.5秒", + "2500": "2.5秒" +}; diff --git a/noname/library/configuration-menu/general/configuration/keep-awake.js b/noname/library/configuration-menu/general/configuration/keep-awake.js new file mode 100644 index 000000000..da83738b1 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/keep-awake.js @@ -0,0 +1,28 @@ +import { Game } from "../../../../game.js"; + +const introduction = document.createElement("body"); +introduction.append("防止屏幕自动关闭", document.createElement("br")); +introduction.append("注:旧版本通过NoSleep.js实现的屏幕常亮可能会影响外置音频的音量"); + +export const KEEP_AWAKE = { + name: "屏幕常亮", + init: false, + unfrequent: true, + intro: introduction.innerHTML, + onclick(bool) { + Game.saveConfig("keep_awake", bool); + if (bool) { + if (window.plugins && window.plugins.insomnia) window.plugins.insomnia.keepAwake(); + else if (window.noSleep) { + document.addEventListener(lib.config.touchscreen ? "touchend" : "click", function enableNoSleepX() { + document.removeEventListener(lib.config.touchscreen ? "touchend" : "click", enableNoSleepX, false); + window.noSleep.enable(); + }, false); + } + } + else { + if (window.plugins && window.plugins.insomnia) window.plugins.insomnia.allowSleepAgain(); + else if (window.noSleep) window.noSleep.disable(); + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/long-press-information.js b/noname/library/configuration-menu/general/configuration/long-press-information.js new file mode 100644 index 000000000..ea5a75b8a --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/long-press-information.js @@ -0,0 +1,7 @@ +export const LONG_PRESS_INFORMATION = { + name: "长按显示信息", + init: true, + unfrequent: true, + restart: true, + intro: "长按后弹出菜单" +}; diff --git a/noname/library/configuration-menu/general/configuration/low-performance.js b/noname/library/configuration-menu/general/configuration/low-performance.js new file mode 100644 index 000000000..e05c2b2dd --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/low-performance.js @@ -0,0 +1,17 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; + +export const LOW_PERFORMANCE = { + name: "流畅模式", + init: false, + intro: "减少部分游戏特效,提高游戏速度", + onclick(bool) { + Game.saveConfig("low_performance", bool); + if (bool) { + UI.window.classList.add("low_performance"); + } + else { + UI.window.classList.remove("low_performance"); + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/lucky-star.js b/noname/library/configuration-menu/general/configuration/lucky-star.js new file mode 100644 index 000000000..cb57ad1b7 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/lucky-star.js @@ -0,0 +1,6 @@ +export const LUCKY_STAR = { + name: "幸运星模式", + intro: "在涉及随机数等的技能中,必定得到效果最好的结果。(联机模式无效)", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/maximum-load-time.js b/noname/library/configuration-menu/general/configuration/maximum-load-time.js new file mode 100644 index 000000000..5e8968b13 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/maximum-load-time.js @@ -0,0 +1,20 @@ +import { Game } from "../../../../game.js"; +import { Library } from "../../../../library.js"; +import { ITEM } from "./maximum-load-time/item.js"; + +export const MAXIMUM_LOAD_TIME = { + name: "最长载入时间", + intro: "设置游戏从启动到完成载入所需的最长时间,超过此时间未完成载入会报错,若设备较慢或安装了较多扩展可适当延长此时间", + init: "5000", + unfrequent: true, + item: ITEM, + onclick(item) { + Game.saveConfig("max_loadtime", item); + if (item == "5000") { + localStorage.removeItem(`${Library.configprefix}loadtime`); + } + else { + localStorage.setItem(`${Library.configprefix}loadtime`, item); + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/maximum-load-time/item.js b/noname/library/configuration-menu/general/configuration/maximum-load-time/item.js new file mode 100644 index 000000000..ab901e30c --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/maximum-load-time/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + 5000: "5秒", + 10000: "10秒", + 20000: "20秒", + 60000: "60秒" +}; diff --git a/noname/library/configuration-menu/general/configuration/mount-combine.js b/noname/library/configuration-menu/general/configuration/mount-combine.js new file mode 100644 index 000000000..317a47b81 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/mount-combine.js @@ -0,0 +1,9 @@ +const listItem = document.createElement("li"); +listItem.textContent = "将进攻坐骑栏和防御坐骑栏合并为同一个位置(重启后生效)。"; + +export const MOUNT_COMBINE = { + name: "合并坐骑栏", + init: false, + intro: listItem.outerHTML, + restart: true +}; diff --git a/noname/library/configuration-menu/general/configuration/mouse-wheel.js b/noname/library/configuration-menu/general/configuration/mouse-wheel.js new file mode 100644 index 000000000..5e15c1670 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/mouse-wheel.js @@ -0,0 +1,23 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; +import { Click } from "../../../../ui/click.js"; +import { configuration } from "../../../configuration.js"; + +export const MOUSE_WHEEL = { + name: "滚轮控制手牌", + init: true, + unfrequent: true, + intro: "开启后滚轮可使手牌横向滚动,在mac等可横向滚动的设备上建议关闭", + onclick(bool) { + Game.saveConfig("mousewheel", bool); + if (configuration.touchscreen) return; + if (configuration.mousewheel) { + UI.handcards1Container.onmousewheel = Click.mousewheel; + UI.handcards2Container.onmousewheel = Click.mousewheel; + } + else { + UI.handcards1Container.onmousewheel = null; + UI.handcards2Container.onmousewheel = null; + } + } +}; diff --git a/noname/library/configuration-menu/general/configuration/right-click.js b/noname/library/configuration-menu/general/configuration/right-click.js new file mode 100644 index 000000000..3893168f8 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/right-click.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { ITEM } from "./right-click/item.js"; + +export const RIGHT_CLICK = { + name: "右键操作", + init: "pause", + intro: "在空白区域点击右键时的操作", + unfrequent: true, + item: ITEM, + onclick(item) { + if (Is.nomenu("right_click", item)) return false; + Game.saveConfig("right_click", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/right-click/item.js b/noname/library/configuration-menu/general/configuration/right-click/item.js new file mode 100644 index 000000000..884ca8e36 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/right-click/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + pause: "暂停", + shortcut: "工具", + config: "选项", + auto: "托管" +}; diff --git a/noname/library/configuration-menu/general/configuration/right-information.js b/noname/library/configuration-menu/general/configuration/right-information.js new file mode 100644 index 000000000..6f2bb9710 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/right-information.js @@ -0,0 +1,7 @@ +export const RIGHT_INFORMATION = { + name: "右键显示信息", + init: true, + unfrequent: true, + restart: true, + intro: "右键点击后弹出菜单" +}; diff --git a/noname/library/configuration-menu/general/configuration/round-menu-function.js b/noname/library/configuration-menu/general/configuration/round-menu-function.js new file mode 100644 index 000000000..3ff6e4eed --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/round-menu-function.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { ITEM } from "./round-menu-function/item.js"; + +export const ROUND_MENU_FUNCTION = { + name: "触屏按钮操作", + intro: "点击屏幕中圆形按钮时执行的操作", + init: "system", + unfrequent: true, + item: ITEM, + onclick(item) { + if (Is.nomenu("round_menu_func", item)) return false; + Game.saveConfig("round_menu_func", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/round-menu-function/item.js b/noname/library/configuration-menu/general/configuration/round-menu-function/item.js new file mode 100644 index 000000000..c47a2c3f1 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/round-menu-function/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + system: "显示按钮", + menu: "打开菜单", + pause: "切换暂停", + auto: "切换托管" +}; diff --git a/noname/library/configuration-menu/general/configuration/show-splash.js b/noname/library/configuration-menu/general/configuration/show-splash.js new file mode 100644 index 000000000..2a8387eed --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/show-splash.js @@ -0,0 +1,8 @@ +import { ITEM } from "./show-splash/item.js"; + +export const SHOW_SPLASH = { + name: "显示开始界面", + intro: "游戏开始前进入模式选择画面", + init: "init", + item: ITEM +}; diff --git a/noname/library/configuration-menu/general/configuration/show-splash/item.js b/noname/library/configuration-menu/general/configuration/show-splash/item.js new file mode 100644 index 000000000..15e80da89 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/show-splash/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + off: "关闭", + init: "首次启动", + always: "保持开启" +}; diff --git a/noname/library/configuration-menu/general/configuration/skip-shan.js b/noname/library/configuration-menu/general/configuration/skip-shan.js new file mode 100644 index 000000000..ccb494e23 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/skip-shan.js @@ -0,0 +1,6 @@ +export const SKIP_SHAN = { + name: "无闪自动取消", + init: false, + unfrequent: true, + intro: "当自己需要使用或打出【闪】时,若自己没有【闪】,则跳过该步骤" +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe-down.js b/noname/library/configuration-menu/general/configuration/swipe-down.js new file mode 100644 index 000000000..3d1af3144 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe-down.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { SWIPE_ITEM } from "./swipe-item.js"; + +export const SWIPE_DOWN = { + name: "下划操作", + init: "menu", + unfrequent: true, + intro: "向下滑动时执行的操作", + item: SWIPE_ITEM, + onclick(item) { + if (Is.nomenu("swipe_down", item)) return false; + Game.saveConfig("swipe_down", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe-item.js b/noname/library/configuration-menu/general/configuration/swipe-item.js new file mode 100644 index 000000000..5992db082 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe-item.js @@ -0,0 +1,8 @@ +export const SWIPE_ITEM = { + system: "显示按钮", + menu: "打开菜单", + pause: "切换暂停", + auto: "切换托管", + chat: "显示聊天", + off: "关闭" +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe-left.js b/noname/library/configuration-menu/general/configuration/swipe-left.js new file mode 100644 index 000000000..9ef49fd47 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe-left.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { SWIPE_ITEM } from "./swipe-item.js"; + +export const SWIPE_LEFT = { + name: "左划操作", + intro: "向左滑动时执行的操作", + init: "system", + unfrequent: true, + item: SWIPE_ITEM, + onclick(item) { + if (Is.nomenu("swipe_left", item)) return false; + Game.saveConfig("swipe_left", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe-right.js b/noname/library/configuration-menu/general/configuration/swipe-right.js new file mode 100644 index 000000000..807af7e7d --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe-right.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { SWIPE_ITEM } from "./swipe-item.js"; + +export const SWIPE_RIGHT = { + name: "右划操作", + intro: "向右滑动时执行的操作", + init: "system", + unfrequent: true, + item: SWIPE_ITEM, + onclick(item) { + if (Is.nomenu("swipe_right", item)) return false; + Game.saveConfig("swipe_right", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe-up.js b/noname/library/configuration-menu/general/configuration/swipe-up.js new file mode 100644 index 000000000..d6c85db8f --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe-up.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; +import { SWIPE_ITEM } from "./swipe-item.js"; + +export const SWIPE_UP = { + name: "上划操作", + intro: "向上滑动时执行的操作", + init: "auto", + unfrequent: true, + item: SWIPE_ITEM, + onclick(item) { + if (Is.nomenu("swipe_up", item)) return false; + Game.saveConfig("swipe_up", item); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/swipe.js b/noname/library/configuration-menu/general/configuration/swipe.js new file mode 100644 index 000000000..026eb62cd --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/swipe.js @@ -0,0 +1,6 @@ +export const SWIPE = { + name: "滑动手势", + init: true, + unfrequent: true, + intro: "在非滚动区域向四个方向滑动可执行对应操作" +}; diff --git a/noname/library/configuration-menu/general/configuration/synchronize-speed.js b/noname/library/configuration-menu/general/configuration/synchronize-speed.js new file mode 100644 index 000000000..f89dceeec --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/synchronize-speed.js @@ -0,0 +1,5 @@ +export const SYNCHRONIZE_SPEED = { + name: "限制结算速度", + intro: "在动画结算完成前不执行下一步操作,开启后游戏操作的间隔更长但画面更浏畅,在游戏较卡时建议开启", + init: true +}; diff --git a/noname/library/configuration-menu/general/configuration/tao-enemy.js b/noname/library/configuration-menu/general/configuration/tao-enemy.js new file mode 100644 index 000000000..1dfc9d7f0 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/tao-enemy.js @@ -0,0 +1,6 @@ +export const TAO_ENEMY = { + name: "不对敌方出桃", + init: false, + intro: "双方阵营明确的模式中(如对决),敌方角色濒死时不询问出桃", + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/touchscreen.js b/noname/library/configuration-menu/general/configuration/touchscreen.js new file mode 100644 index 000000000..f20c99056 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/touchscreen.js @@ -0,0 +1,14 @@ +import { Game } from "../../../../game.js"; +import { Is } from "../../../../get/is.js"; + +export const TOUCHSCREEN = { + name: "触屏模式", + init: false, + restart: true, + unfrequent: true, + intro: "开启后可使触屏设备反应更快,但无法使用鼠标操作", + onclick(bool) { + if (Is.nomenu("touchscreen", bool)) return false; + Game.saveConfig("touchscreen", bool); + } +}; diff --git a/noname/library/configuration-menu/general/configuration/un-automatically-choose.js b/noname/library/configuration-menu/general/configuration/un-automatically-choose.js new file mode 100644 index 000000000..e8943c263 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/un-automatically-choose.js @@ -0,0 +1,6 @@ +export const UN_AUTOMATICALLY_CHOOSE = { + name: "拆顺手牌选择", + init: false, + unfrequent: true, + intro: "拆牌或者顺牌时,就算只能选择对方的手牌依然手动选择" +}; diff --git a/noname/library/configuration-menu/general/configuration/update-link.js b/noname/library/configuration-menu/general/configuration/update-link.js new file mode 100644 index 000000000..d539377cb --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/update-link.js @@ -0,0 +1,15 @@ +import { Game } from "../../../../game.js"; +import { Library } from "../../../../library.js"; +import { updateURLs } from "../../../update-urls.js"; +import { ITEM } from "./update-link/item.js"; + +export const UPDATE_LINK = { + name: "更新地址", + init: "coding", + unfrequent: true, + item: ITEM, + onclick(item) { + Game.saveConfig("update_link", item); + Library.updateURL = updateURLs[item] || updateURLs.coding; + } +}; diff --git a/noname/library/configuration-menu/general/configuration/update-link/item.js b/noname/library/configuration-menu/general/configuration/update-link/item.js new file mode 100644 index 000000000..a5667de4c --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/update-link/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + coding: "CSDN", + github: "GitHub" +}; diff --git a/noname/library/configuration-menu/general/configuration/video.js b/noname/library/configuration-menu/general/configuration/video.js new file mode 100644 index 000000000..59a7fb4c9 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/video.js @@ -0,0 +1,9 @@ +import { ITEM } from "./video/item.js"; + +export const VIDEO = { + name: "保存录像", + init: "20", + intro: "游戏结束后保存录像在最大条数,超过后将从最早的录像开始删除(已收藏的录像不计入条数)", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/general/configuration/video/item.js b/noname/library/configuration-menu/general/configuration/video/item.js new file mode 100644 index 000000000..51f4b1320 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/video/item.js @@ -0,0 +1,8 @@ +export const ITEM = { + "0": "关闭", + "5": "五局", + "10": "十局", + "20": "二十局", + "50": "五十局", + "10000": "无限" +}; diff --git a/noname/library/configuration-menu/general/configuration/wuxie-self.js b/noname/library/configuration-menu/general/configuration/wuxie-self.js new file mode 100644 index 000000000..2a7e28ba3 --- /dev/null +++ b/noname/library/configuration-menu/general/configuration/wuxie-self.js @@ -0,0 +1,6 @@ +export const WUXIE_SELF = { + name: "不无懈自己", + init: true, + unfrequent: true, + intro: "自己使用的单目标普通锦囊即将生效时,不询问无懈" +}; diff --git a/noname/library/configuration-menu/others.js b/noname/library/configuration-menu/others.js new file mode 100644 index 000000000..ffc19f967 --- /dev/null +++ b/noname/library/configuration-menu/others.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./others/configuration.js"; + +export const OTHERS = { + name: "其它", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/others/configuration.js b/noname/library/configuration-menu/others/configuration.js new file mode 100644 index 000000000..491a070c2 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration.js @@ -0,0 +1,25 @@ +import { EXPORT_DATA } from "./configuration/export-data.js"; +import { IMPORT_DATA_BUTTON } from "./configuration/import-data-button.js"; +import { IMPORT_DATA } from "./configuration/import-data.js"; +import { REDOWNLOAD_GAME } from "./configuration/redownload-game.js"; +import { RESET_GAME } from "./configuration/reset-game.js"; +import { RESET_HIDDEN_PACK } from "./configuration/reset-hidden-pack.js"; +import { RESET_TUTORIAL } from "./configuration/reset-tutorial.js"; + +export const CONFIGURATION = { + reset_game: RESET_GAME, + reset_hiddenpack: RESET_HIDDEN_PACK, + reset_tutorial: RESET_TUTORIAL, + import_data: IMPORT_DATA, + import_data_button: IMPORT_DATA_BUTTON, + export_data: EXPORT_DATA, + redownload_game: REDOWNLOAD_GAME, + update(config, map) { + if (lib.device || lib.node) { + map.redownload_game.show(); + } + else { + map.redownload_game.hide(); + } + } +}; diff --git a/noname/library/configuration-menu/others/configuration/export-data.js b/noname/library/configuration-menu/others/configuration/export-data.js new file mode 100644 index 000000000..ecf0522e9 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/export-data.js @@ -0,0 +1,30 @@ +export const EXPORT_DATA = { + name: "导出游戏设置", + onclick() { + var data; + var export_data = function (data) { + game.export(lib.init.encode(JSON.stringify(data)), "无名杀 - 数据 - " + (new Date()).toLocaleString()); + } + if (!lib.db) { + data = {}; + for (var i in localStorage) { + if (i.startsWith(lib.configprefix)) { + data[i] = localStorage[i]; + } + } + export_data(data); + } + else { + game.getDB("config", null, function (data1) { + game.getDB("data", null, function (data2) { + export_data({ + config: data1, + data: data2 + }); + }); + }); + } + + }, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/import-data-button.js b/noname/library/configuration-menu/others/configuration/import-data-button.js new file mode 100644 index 000000000..e310cc600 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/import-data-button.js @@ -0,0 +1,18 @@ +const div = document.createElement("div"); +const style = div.style; +style.whiteSpace = "nowrap"; +style.width = "calc(100% - 10px)"; +const input = document.createElement("input"); +input.accept = "*/*"; +input.style.width = "calc(100% - 40px)"; +input.type = "file"; +div.append(input); +const button = document.createElement("button"); +button.style.width = "40px"; +button.append("确定"); +div.append(button); + +export const IMPORT_DATA_BUTTON = { + name: div.outerHTML, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/import-data.js b/noname/library/configuration-menu/others/configuration/import-data.js new file mode 100644 index 000000000..0db98e92d --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/import-data.js @@ -0,0 +1,7 @@ +export const IMPORT_DATA = { + name: "导入游戏设置", + onclick() { + ui.import_data_button.classList.toggle("hidden"); + }, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/redownload-game.js b/noname/library/configuration-menu/others/configuration/redownload-game.js new file mode 100644 index 000000000..61de58616 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/redownload-game.js @@ -0,0 +1,24 @@ +export const REDOWNLOAD_GAME = { + name: "重新下载游戏", + onclick() { + var node = this; + if (node._clearing) { + localStorage.removeItem("noname_inited"); + game.reload(); + return; + } + node._clearing = true; + node.firstChild.innerHTML = "单击以确认 (3)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (2)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (1)"; + setTimeout(function () { + node.firstChild.innerHTML = "重新下载游戏"; + delete node._clearing; + }, 1000); + }, 1000); + }, 1000); + }, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/reset-game.js b/noname/library/configuration-menu/others/configuration/reset-game.js new file mode 100644 index 000000000..ec6b047be --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/reset-game.js @@ -0,0 +1,34 @@ +export const RESET_GAME = { + name: "重置游戏设置", + onclick() { + var node = this; + if (node._clearing) { + var noname_inited = localStorage.getItem("noname_inited"); + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem("noname_inited", noname_inited); + } + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + game.deleteDB("config"); + game.deleteDB("data"); + game.reload(); + return; + } + node._clearing = true; + node.firstChild.innerHTML = "单击以确认 (3)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (2)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (1)"; + setTimeout(function () { + node.firstChild.innerHTML = "重置游戏设置"; + delete node._clearing; + }, 1000); + }, 1000); + }, 1000); + }, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/reset-hidden-pack.js b/noname/library/configuration-menu/others/configuration/reset-hidden-pack.js new file mode 100644 index 000000000..005e33471 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/reset-hidden-pack.js @@ -0,0 +1,23 @@ +export const RESET_HIDDEN_PACK = { + name: "重置隐藏内容", + onclick() { + if (this.firstChild.innerHTML != "已重置") { + this.firstChild.innerHTML = "已重置" + game.saveConfig("hiddenModePack", []); + game.saveConfig("hiddenCharacterPack", []); + game.saveConfig("hiddenCardPack", []); + game.saveConfig("hiddenPlayPack", []); + game.saveConfig("hiddenBackgroundPack", []); + var that = this; + setTimeout(function () { + that.firstChild.innerHTML = "重置隐藏内容"; + setTimeout(function () { + if (confirm("是否重新启动使改变生效?")) { + game.reload(); + } + }); + }, 500); + } + }, + clear: true +}; diff --git a/noname/library/configuration-menu/others/configuration/reset-tutorial.js b/noname/library/configuration-menu/others/configuration/reset-tutorial.js new file mode 100644 index 000000000..58ffa1907 --- /dev/null +++ b/noname/library/configuration-menu/others/configuration/reset-tutorial.js @@ -0,0 +1,16 @@ +export const RESET_TUTORIAL = { + name: "重置新手向导", + onclick() { + if (this.firstChild.innerHTML != "已重置") { + this.firstChild.innerHTML = "已重置" + game.saveConfig("new_tutorial", false); + game.saveConfig("prompt_hidebg"); + game.saveConfig("prompt_hidepack"); + var that = this; + setTimeout(function () { + that.firstChild.innerHTML = "重置新手向导"; + }, 500); + } + }, + clear: true +}; diff --git a/noname/library/configuration-menu/skill.js b/noname/library/configuration-menu/skill.js new file mode 100644 index 000000000..03ffa67c6 --- /dev/null +++ b/noname/library/configuration-menu/skill.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./skill/configuration.js"; + +export const SKILL = { + name: "技能", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/skill/configuration.js b/noname/library/configuration-menu/skill/configuration.js new file mode 100644 index 000000000..c57a0eac5 --- /dev/null +++ b/noname/library/configuration-menu/skill/configuration.js @@ -0,0 +1,22 @@ +export const CONFIGURATION = { + update(config, map) { + for (var i in map) { + if (map[i]._link.config.type == "autoskill") { + if (!config.autoskilllist.contains(i)) { + map[i].classList.add("on"); + } + else { + map[i].classList.remove("on"); + } + } + else if (map[i]._link.config.type == "banskill") { + if (!config.forbidlist.contains(i)) { + map[i].classList.add("on"); + } + else { + map[i].classList.remove("on"); + } + } + } + } +}; diff --git a/noname/library/configuration-menu/view.js b/noname/library/configuration-menu/view.js new file mode 100644 index 000000000..5533fc0a4 --- /dev/null +++ b/noname/library/configuration-menu/view.js @@ -0,0 +1,6 @@ +import { CONFIGURATION } from "./view/configuration.js"; + +export const VIEW = { + name: "显示", + config: CONFIGURATION +}; diff --git a/noname/library/configuration-menu/view/configuration.js b/noname/library/configuration-menu/view/configuration.js new file mode 100644 index 000000000..372fdca52 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration.js @@ -0,0 +1,199 @@ +import { AUTOMATICALLY_POPPED_CONFIGURATION } from "./configuration/automatically-popped-configuration.js"; +import { AUTOMATICALLY_POPPED_HISTORY } from "./configuration/automatically-popped-history.js"; +import { CHARACTER_DIALOG_TOOL } from "./configuration/character-dialog-tool.js"; +import { CLEAR_LOG } from "./configuration/clear-log.js"; +import { HIDE_CARD_IMAGE } from "./configuration/hide-card-image.js"; +import { HIDE_CARD_PROMPT_BASIC } from "./configuration/hide-card-prompt-basic.js"; +import { HIDE_CARD_PROMPT_EQUIP } from "./configuration/hide-card-prompt-equip.js"; +import { LOG_HIGHLIGHT } from "./configuration/log-highlight.js"; +import { MARK_IDENTITY_STYLE } from "./configuration/mark-identity-style.js"; +import { POP_EQUIP } from "./configuration/pop-equip.js"; +import { POP_LOGV } from "./configuration/pop-logv.js"; +import { RECENT_CHARACTER_NUMBER } from "./configuration/recent-character-number.js"; +import { REMEMBER_DIALOG } from "./configuration/remember-dialog.js"; +import { REMEMBER_ROUND_BUTTON } from "./configuration/remember-round-button.js"; +import { RIGHT_RANGE } from "./configuration/right-range.js"; +import { SHOW_AUTOMATIC } from "./configuration/show-automatic.js"; +import { SHOW_BAN_MENU } from "./configuration/show-ban-menu.js"; +import { SHOW_CARD_PILE_NUMBER } from "./configuration/show-card-pile-number.js"; +import { SHOW_CARD_PILE } from "./configuration/show-card-pile.js"; +import { SHOW_CARD_PROMPT } from "./configuration/show-card-prompt.js"; +import { SHOW_CHARACTER_CARD } from "./configuration/show-character-card.js"; +import { SHOW_CHARACTER_NAME_PINYIN } from "./configuration/show-character-name-pinyin.js"; +import { SHOW_DISCARD_PILE } from "./configuration/show-discard-pile.js"; +import { SHOW_EXTENSION_MAKER } from "./configuration/show-extension-maker.js"; +import { SHOW_EXTENSION_SHARE } from "./configuration/show-extension-share.js"; +import { SHOW_FAVORITE_MENU } from "./configuration/show-favorite-menu.js"; +import { SHOW_FAVORITE_MODE } from "./configuration/show-favorite-mode.js"; +import { SHOW_FAVORITE } from "./configuration/show-favorite.js"; +import { SHOW_GIVE_UP } from "./configuration/show-give-up.js"; +import { SHOW_GROUP } from "./configuration/show-group.js"; +import { SHOW_HAND_CARD_BUTTON } from "./configuration/show-hand-card-button.js"; +import { SHOW_HISTORY } from "./configuration/show-history.js"; +import { SHOW_LOG } from "./configuration/show-log.js"; +import { SHOW_NAME } from "./configuration/show-name.js"; +import { SHOW_PAUSE } from "./configuration/show-pause.js"; +import { SHOW_PHASE_PROMPT } from "./configuration/show-phase-prompt.js"; +import { SHOW_PHASE_USE_PROMPT } from "./configuration/show-phase-use-prompt.js"; +import { SHOW_PLAYER_IDS } from "./configuration/show-player-ids.js"; +import { SHOW_RARITY } from "./configuration/show-rarity.js"; +import { SHOW_REPLAY } from "./configuration/show-replay.js"; +import { SHOW_ROUND_MENU } from "./configuration/show-round-menu.js"; +import { SHOW_SEX } from "./configuration/show-sex.js"; +import { SHOW_SKILL_NAME_PINYIN } from "./configuration/show-skill-name-pinyin.js"; +import { SHOW_SORT_CARD } from "./configuration/show-sort-card.js"; +import { SHOW_STATUS_BAR_ANDROID } from "./configuration/show-status-bar-android.js"; +import { SHOW_STATUS_BAR_IOS } from "./configuration/show-status-bar-ios.js"; +import { SHOW_TIME_2 } from "./configuration/show-time-2.js"; +import { SHOW_TIME_3 } from "./configuration/show-time-3.js"; +import { SHOW_TIME } from "./configuration/show-time.js"; +import { SHOW_VOLUME } from "./configuration/show-volume.js"; +import { SHOW_WUXIE } from "./configuration/show-wuxie.js"; +import { TRANSPARENT_DIALOG } from "./configuration/transparent-dialog.js"; +import { WATCH_FACE } from "./configuration/watch-face.js"; +import { WUXIE_RIGHT } from "./configuration/wuxie-right.js"; + +export const CONFIGURATION = { + update(config, map) { + if (config.mode == "versus" || config.mode == "chess" || config.mode == "tafang" || config.mode == "boss") { + map.show_handcardbutton.show(); + } + else { + map.show_handcardbutton.hide(); + } + if (config.touchscreen) { + map.pop_logv.hide(); + } + else { + map.pop_logv.show(); + } + if (device) { + if (device == "android") { + map.show_statusbar_android.show(); + map.show_statusbar_ios.hide(); + } + else if (device == "ios") { + map.show_statusbar_ios.show(); + map.show_statusbar_android.hide(); + } + if (!game.download) { + setTimeout(function () { + if (!window.StatusBar) { + map.show_statusbar.hide(); + } + }, 5000); + } + } + else { + map.show_statusbar_ios.hide(); + map.show_statusbar_android.hide(); + } + if (get.is.phoneLayout()) { + map.remember_round_button.show(); + map.popequip.show(); + map.filternode_button.show(); + map.show_pause.hide(); + map.show_auto.hide(); + map.show_replay.hide(); + map.show_round_menu.show(); + } + else { + map.show_pause.show(); + map.show_auto.show(); + map.show_replay.show(); + map.show_round_menu.hide(); + map.remember_round_button.hide(); + map.popequip.hide(); + map.filternode_button.hide(); + } + if (config.show_card_prompt) { + map.hide_card_prompt_basic.show(); + map.hide_card_prompt_equip.show(); + } + else { + map.hide_card_prompt_basic.hide(); + map.hide_card_prompt_equip.hide(); + } + if (config.show_log != "off") { + map.clear_log.show(); + } + else { + map.clear_log.hide(); + } + if (get.is.phoneLayout()) { + map.show_time2.show(); + map.show_time.hide(); + if (config.show_time2) { + map.watchface.show(); + } + else { + map.watchface.hide(); + } + } + else { + map.show_time2.hide(); + map.show_time.show(); + map.watchface.hide(); + } + if (config.show_extensionmaker) { + map.show_extensionshare.show(); + } + else { + map.show_extensionshare.hide(); + } + }, + show_history: SHOW_HISTORY, + pop_logv: POP_LOGV, + show_log: SHOW_LOG, + clear_log: CLEAR_LOG, + log_highlight: LOG_HIGHLIGHT, + show_time: SHOW_TIME, + show_time2: SHOW_TIME_2, + watchface: WATCH_FACE, + show_time3: SHOW_TIME_3, + show_statusbar_android: SHOW_STATUS_BAR_ANDROID, + show_statusbar_ios: SHOW_STATUS_BAR_IOS, + show_card_prompt: SHOW_CARD_PROMPT, + hide_card_prompt_basic: HIDE_CARD_PROMPT_BASIC, + hide_card_prompt_equip: HIDE_CARD_PROMPT_EQUIP, + show_phase_prompt: SHOW_PHASE_PROMPT, + show_phaseuse_prompt: SHOW_PHASE_USE_PROMPT, + auto_popped_config: AUTOMATICALLY_POPPED_CONFIGURATION, + auto_popped_history: AUTOMATICALLY_POPPED_HISTORY, + show_round_menu: SHOW_ROUND_MENU, + remember_round_button: REMEMBER_ROUND_BUTTON, + remember_dialog: REMEMBER_DIALOG, + transparent_dialog: TRANSPARENT_DIALOG, + show_rarity: SHOW_RARITY, + mark_identity_style: MARK_IDENTITY_STYLE, + character_dialog_tool: CHARACTER_DIALOG_TOOL, + recent_character_number: RECENT_CHARACTER_NUMBER, + popequip: POP_EQUIP, + show_charactercard: SHOW_CHARACTER_CARD, + show_favourite: SHOW_FAVORITE, + show_favmode: SHOW_FAVORITE_MODE, + show_favourite_menu: SHOW_FAVORITE_MENU, + show_ban_menu: SHOW_BAN_MENU, + right_range: RIGHT_RANGE, + hide_card_image: HIDE_CARD_IMAGE, + show_name: SHOW_NAME, + show_sex: SHOW_SEX, + show_group: SHOW_GROUP, + show_replay: SHOW_REPLAY, + show_playerids: SHOW_PLAYER_IDS, + show_sortcard: SHOW_SORT_CARD, + show_pause: SHOW_PAUSE, + show_auto: SHOW_AUTOMATIC, + show_volumn: SHOW_VOLUME, + show_cardpile: SHOW_CARD_PILE, + show_cardpile_number: SHOW_CARD_PILE_NUMBER, + show_handcardbutton: SHOW_HAND_CARD_BUTTON, + show_giveup: SHOW_GIVE_UP, + show_wuxie: SHOW_WUXIE, + wuxie_right: WUXIE_RIGHT, + show_discardpile: SHOW_DISCARD_PILE, + show_extensionmaker: SHOW_EXTENSION_MAKER, + show_extensionshare: SHOW_EXTENSION_SHARE, + show_characternamepinyin: SHOW_CHARACTER_NAME_PINYIN, + show_skillnamepinyin: SHOW_SKILL_NAME_PINYIN +}; diff --git a/noname/library/configuration-menu/view/configuration/automatically-popped-configuration.js b/noname/library/configuration-menu/view/configuration/automatically-popped-configuration.js new file mode 100644 index 000000000..c75e38a03 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/automatically-popped-configuration.js @@ -0,0 +1,6 @@ +export const AUTOMATICALLY_POPPED_CONFIGURATION = { + name: "自动弹出选项", + intro: "鼠标移至选项按钮时弹出模式选择菜单", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/automatically-popped-history.js b/noname/library/configuration-menu/view/configuration/automatically-popped-history.js new file mode 100644 index 000000000..c0e863c32 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/automatically-popped-history.js @@ -0,0 +1,6 @@ +export const AUTOMATICALLY_POPPED_HISTORY = { + name: "自动弹出历史", + intro: "鼠标移至暂停按钮时弹出历史记录菜单", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/character-dialog-tool.js b/noname/library/configuration-menu/view/configuration/character-dialog-tool.js new file mode 100644 index 000000000..bc1eeb0f8 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/character-dialog-tool.js @@ -0,0 +1,9 @@ +import { ITEM } from "./character-dialog-tool/item.js"; + +export const CHARACTER_DIALOG_TOOL = { + name: "自由选将显示", + intro: "点击自由选将时默认显示的条目", + init: "最近", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/character-dialog-tool/item.js b/noname/library/configuration-menu/view/configuration/character-dialog-tool/item.js new file mode 100644 index 000000000..27b23013b --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/character-dialog-tool/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + 收藏: "收藏", + 最近: "最近", + all: "全部" +}; diff --git a/noname/library/configuration-menu/view/configuration/clear-log.js b/noname/library/configuration-menu/view/configuration/clear-log.js new file mode 100644 index 000000000..739d65577 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/clear-log.js @@ -0,0 +1,6 @@ +export const CLEAR_LOG = { + name: "自动清除历史记录", + init: false, + unfrequent: true, + intro: "开启后将定时清除历史记录栏的条目(而不是等记录栏满后再清除)" +}; diff --git a/noname/library/configuration-menu/view/configuration/hide-card-image.js b/noname/library/configuration-menu/view/configuration/hide-card-image.js new file mode 100644 index 000000000..d4554a9ec --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/hide-card-image.js @@ -0,0 +1,7 @@ +export const HIDE_CARD_IMAGE = { + name: "隐藏卡牌背景", + intro: "所有卡牌将使用文字作为背景", + init: false, + unfrequent: true, + restart: true +}; diff --git a/noname/library/configuration-menu/view/configuration/hide-card-prompt-basic.js b/noname/library/configuration-menu/view/configuration/hide-card-prompt-basic.js new file mode 100644 index 000000000..f91980fe9 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/hide-card-prompt-basic.js @@ -0,0 +1,6 @@ +export const HIDE_CARD_PROMPT_BASIC = { + name: "隐藏基本牌信息", + intro: "不显示基本牌名称", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/hide-card-prompt-equip.js b/noname/library/configuration-menu/view/configuration/hide-card-prompt-equip.js new file mode 100644 index 000000000..3a2deba6c --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/hide-card-prompt-equip.js @@ -0,0 +1,6 @@ +export const HIDE_CARD_PROMPT_EQUIP = { + name: "隐藏装备牌信息", + intro: "不显示装备牌名称", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/log-highlight.js b/noname/library/configuration-menu/view/configuration/log-highlight.js new file mode 100644 index 000000000..a5ed3b301 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/log-highlight.js @@ -0,0 +1,6 @@ +export const LOG_HIGHLIGHT = { + name: "历史记录高亮", + init: true, + unfrequent: true, + intro: "开启后历史记录不同类别的信息将以不同颜色显示" +}; diff --git a/noname/library/configuration-menu/view/configuration/mark-identity-style.js b/noname/library/configuration-menu/view/configuration/mark-identity-style.js new file mode 100644 index 000000000..7dfff2d09 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/mark-identity-style.js @@ -0,0 +1,9 @@ +import { ITEM } from "./mark-identity-style/item.js"; + +export const MARK_IDENTITY_STYLE = { + name: "标记身份操作", + intro: "设置单击身份按钮时的操作", + unfrequent: true, + init: "menu", + item: ITEM +}; diff --git a/noname/library/configuration-menu/view/configuration/mark-identity-style/item.js b/noname/library/configuration-menu/view/configuration/mark-identity-style/item.js new file mode 100644 index 000000000..e91a17cf0 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/mark-identity-style/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + menu: "菜单", + click: "单击" +}; diff --git a/noname/library/configuration-menu/view/configuration/pop-equip.js b/noname/library/configuration-menu/view/configuration/pop-equip.js new file mode 100644 index 000000000..333fe2cb4 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/pop-equip.js @@ -0,0 +1,6 @@ +export const POP_EQUIP = { + name: "触屏装备选择", + intro: "设置触屏布局中选择装备的方式", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/pop-logv.js b/noname/library/configuration-menu/view/configuration/pop-logv.js new file mode 100644 index 000000000..cbcf07965 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/pop-logv.js @@ -0,0 +1,5 @@ +export const POP_LOGV = { + name: "自动弹出记录", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/recent-character-number.js b/noname/library/configuration-menu/view/configuration/recent-character-number.js new file mode 100644 index 000000000..b7fbb19b0 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/recent-character-number.js @@ -0,0 +1,9 @@ +import { ITEM } from "./recent-character-number/item.js"; + +export const RECENT_CHARACTER_NUMBER = { + name: "最近使用武将", + intro: "自由选将对话框中最近使用武将的数量", + init: "12", + item: ITEM, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/recent-character-number/item.js b/noname/library/configuration-menu/view/configuration/recent-character-number/item.js new file mode 100644 index 000000000..e4206404a --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/recent-character-number/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + "6": "6", + "12": "12", + "20": "24", + "30": "36", +}; diff --git a/noname/library/configuration-menu/view/configuration/remember-dialog.js b/noname/library/configuration-menu/view/configuration/remember-dialog.js new file mode 100644 index 000000000..83ff5d6f1 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/remember-dialog.js @@ -0,0 +1,24 @@ +export const REMEMBER_DIALOG = { + name: "记住对话框位置", + intro: "移动对话框后新的对话框也将在移动后的位置显示", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("remember_dialog", bool); + if (!bool) { + if (ui.dialog) { + var dialog = ui.dialog; + dialog.style.transform = ""; + dialog._dragtransform = [0, 0]; + dialog.style.transition = "all 0.3s"; + dialog._dragtouches; + dialog._dragorigin; + dialog._dragorigintransform; + setTimeout(function () { + dialog.style.transition = ""; + }, 500); + } + game.saveConfig("dialog_transform", [0, 0]); + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/remember-round-button.js b/noname/library/configuration-menu/view/configuration/remember-round-button.js new file mode 100644 index 000000000..a80d04dd4 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/remember-round-button.js @@ -0,0 +1,12 @@ +export const REMEMBER_ROUND_BUTTON = { + name: "记住按钮位置", + intro: "重新开始后触屏按钮将保存的上一局的位置", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("remember_round_button", bool); + if (!bool) { + ui.click.resetround(); + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/right-range.js b/noname/library/configuration-menu/view/configuration/right-range.js new file mode 100644 index 000000000..606bcc138 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/right-range.js @@ -0,0 +1,6 @@ +export const RIGHT_RANGE = { + name: "显示距离信息", + intro: "在角色的右键菜单中显示距离等信息", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-automatic.js b/noname/library/configuration-menu/view/configuration/show-automatic.js new file mode 100644 index 000000000..f331465f8 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-automatic.js @@ -0,0 +1,14 @@ +export const SHOW_AUTOMATIC = { + name: "显示托管按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_auto", bool); + if (lib.config.show_auto) { + ui.auto.style.display = ""; + } + else { + ui.auto.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-ban-menu.js b/noname/library/configuration-menu/view/configuration/show-ban-menu.js new file mode 100644 index 000000000..b1bb00afd --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-ban-menu.js @@ -0,0 +1,6 @@ +export const SHOW_BAN_MENU = { + name: "显示禁将菜单", + intro: "在选项-武将中显示禁将一栏", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-card-pile-number.js b/noname/library/configuration-menu/view/configuration/show-card-pile-number.js new file mode 100644 index 000000000..9398b0c2d --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-card-pile-number.js @@ -0,0 +1,14 @@ +export const SHOW_CARD_PILE_NUMBER = { + name: "显示剩余牌数", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_cardpile_number", bool); + if (bool) { + ui.cardPileNumber.style.display = ""; + } + else { + ui.cardPileNumber.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-card-pile.js b/noname/library/configuration-menu/view/configuration/show-card-pile.js new file mode 100644 index 000000000..9551e4201 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-card-pile.js @@ -0,0 +1,14 @@ +export const SHOW_CARD_PILE = { + name: "显示牌堆按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_cardpile", bool); + if (bool) { + ui.cardPileButton.style.display = ""; + } + else { + ui.cardPileButton.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-card-prompt.js b/noname/library/configuration-menu/view/configuration/show-card-prompt.js new file mode 100644 index 000000000..d4c002b0f --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-card-prompt.js @@ -0,0 +1,6 @@ +export const SHOW_CARD_PROMPT = { + name: "显示出牌信息", + intro: "出牌时在使用者上显示卡牌名称", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-character-card.js b/noname/library/configuration-menu/view/configuration/show-character-card.js new file mode 100644 index 000000000..b86346998 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-character-card.js @@ -0,0 +1,6 @@ +export const SHOW_CHARACTER_CARD = { + name: "显示武将资料", + intro: "在武将界面单击时弹出武将资料卡", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-character-name-pinyin.js b/noname/library/configuration-menu/view/configuration/show-character-name-pinyin.js new file mode 100644 index 000000000..b2b41c931 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-character-name-pinyin.js @@ -0,0 +1,43 @@ +import { ITEM } from "./show-character-name-pinyin/item.js"; + +export const SHOW_CHARACTER_NAME_PINYIN = { + name: "显示武将名注解", + intro: "在武将资料卡显示武将名及其注解、性别、势力、体力等信息", + init: "showPinyin", + unfrequent: true, + item: ITEM, + visualMenu(node, link, name) { + node.classList.add("button", "character"); + const style = node.style; + style.alignItems = "center"; + style.animation = "background-position-left-center-right-center-left-center 15s ease infinite"; + style.background = "linear-gradient(-45deg, #EE7752, #E73C7E, #23A6D5, #23D5AB)"; + style.backgroundSize = "400% 400%"; + style.display = "flex"; + style.height = "60px"; + style.justifyContent = "center"; + style.width = "180px"; + const firstChild = node.firstChild; + firstChild.removeAttribute("class"); + firstChild.style.position = "initial"; + if (link == "doNotShow") return; + const ruby = document.createElement("ruby"); + ruby.textContent = name; + const rt = document.createElement("rt"); + rt.style.fontSize = "smaller"; + if (link == "showPinyin2" || link == "showCodeIdentifier2") { + rt.textContent = link == "showCodeIdentifier2" ? "[" + link + "]" : "[" + get.pinyin(name) + "]"; + ruby.appendChild(rt); + } else { + const leftParenthesisRP = document.createElement("rp"); + leftParenthesisRP.textContent = "("; + ruby.appendChild(leftParenthesisRP); + rt.textContent = link == "showCodeIdentifier" ? link : get.pinyin(name).join(" "); + ruby.appendChild(rt); + const rightParenthesisRP = document.createElement("rp"); + rightParenthesisRP.textContent = ")"; + ruby.appendChild(rightParenthesisRP); + } + firstChild.innerHTML = ruby.outerHTML; + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-character-name-pinyin/item.js b/noname/library/configuration-menu/view/configuration/show-character-name-pinyin/item.js new file mode 100644 index 000000000..2b32bfc28 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-character-name-pinyin/item.js @@ -0,0 +1,7 @@ +export const ITEM = { + doNotShow: "不显示", + showPinyin: "拼音(样式一)", + showCodeIdentifier: "代码ID(样式一)", + showPinyin2: "拼音(样式二)", + showCodeIdentifier2: "代码ID(样式二)" +}; diff --git a/noname/library/configuration-menu/view/configuration/show-discard-pile.js b/noname/library/configuration-menu/view/configuration/show-discard-pile.js new file mode 100644 index 000000000..9cbd388ff --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-discard-pile.js @@ -0,0 +1,5 @@ +export const SHOW_DISCARD_PILE = { + name: "暂停时显示弃牌堆", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-extension-maker.js b/noname/library/configuration-menu/view/configuration/show-extension-maker.js new file mode 100644 index 000000000..bca3a3c9d --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-extension-maker.js @@ -0,0 +1,5 @@ +export const SHOW_EXTENSION_MAKER = { + name: "显示制作扩展", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-extension-share.js b/noname/library/configuration-menu/view/configuration/show-extension-share.js new file mode 100644 index 000000000..47010482f --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-extension-share.js @@ -0,0 +1,5 @@ +export const SHOW_EXTENSION_SHARE = { + name: "显示分享扩展", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-favorite-menu.js b/noname/library/configuration-menu/view/configuration/show-favorite-menu.js new file mode 100644 index 000000000..dab7508a6 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-favorite-menu.js @@ -0,0 +1,6 @@ +export const SHOW_FAVORITE_MENU = { + name: "显示收藏菜单", + intro: "在选项-武将中显示收藏一栏", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-favorite-mode.js b/noname/library/configuration-menu/view/configuration/show-favorite-mode.js new file mode 100644 index 000000000..20ddfb310 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-favorite-mode.js @@ -0,0 +1,6 @@ +export const SHOW_FAVORITE_MODE = { + name: "显示模式收藏", + intro: "快捷菜单中显示收藏模式", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-favorite.js b/noname/library/configuration-menu/view/configuration/show-favorite.js new file mode 100644 index 000000000..bd0d85b0d --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-favorite.js @@ -0,0 +1,6 @@ +export const SHOW_FAVORITE = { + name: "显示添加收藏", + intro: "在角色的右键菜单中显示添加收藏", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-give-up.js b/noname/library/configuration-menu/view/configuration/show-give-up.js new file mode 100644 index 000000000..b2ce71cc7 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-give-up.js @@ -0,0 +1,8 @@ +export const SHOW_GIVE_UP = { + name: "显示投降按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_giveup", bool); + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-group.js b/noname/library/configuration-menu/view/configuration/show-group.js new file mode 100644 index 000000000..348a09feb --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-group.js @@ -0,0 +1,6 @@ +export const SHOW_GROUP = { + name: "显示角色势力", + intro: "在角色的右键菜单中显示角色势力", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-hand-card-button.js b/noname/library/configuration-menu/view/configuration/show-hand-card-button.js new file mode 100644 index 000000000..bdc71d71d --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-hand-card-button.js @@ -0,0 +1,8 @@ +export const SHOW_HAND_CARD_BUTTON = { + name: '显示手牌按钮', + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig('show_handcardbutton', bool); + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-history.js b/noname/library/configuration-menu/view/configuration/show-history.js new file mode 100644 index 000000000..f9eae643f --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-history.js @@ -0,0 +1,26 @@ +import { ITEM } from "./show-history/item.js"; + +export const SHOW_HISTORY = { + name: "出牌记录栏", + init: "off", + intro: "在屏幕左侧或右侧显示出牌记录", + unfrequent: true, + item: ITEM, + onclick(bool) { + if (lib.config.show_history == "right") ui.window.animate("rightbar2"); + game.saveConfig("show_history", bool); + if (_status.video || !_status.prepareArena) return; + if (bool == "left") { + ui.window.classList.add("leftbar"); + ui.window.classList.remove("rightbar"); + } + else if (bool == "right") { + ui.window.classList.remove("leftbar"); + ui.window.classList.add("rightbar"); + } + else { + ui.window.classList.remove("leftbar"); + ui.window.classList.remove("rightbar"); + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-history/item.js b/noname/library/configuration-menu/view/configuration/show-history/item.js new file mode 100644 index 000000000..592e12857 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-history/item.js @@ -0,0 +1,5 @@ +export const ITEM = { + off: "关闭", + left: "靠左", + right: "靠右" +}; diff --git a/noname/library/configuration-menu/view/configuration/show-log.js b/noname/library/configuration-menu/view/configuration/show-log.js new file mode 100644 index 000000000..7f8abd10d --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-log.js @@ -0,0 +1,20 @@ +import { ITEM } from "./show-log/item.js"; + +export const SHOW_LOG = { + name: "历史记录栏", + init: "off", + intro: "在屏幕中部显示出牌文字记录", + unfrequent: true, + item: ITEM, + onclick(bool) { + game.saveConfig("show_log", bool); + if (lib.config.show_log != "off") { + ui.arenalog.style.display = ""; + ui.arenalog.dataset.position = bool; + } + else { + ui.arenalog.style.display = "none"; + ui.arenalog.innerHTML = ""; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-log/item.js b/noname/library/configuration-menu/view/configuration/show-log/item.js new file mode 100644 index 000000000..a894c1df3 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-log/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + off: "关闭", + left: "靠左", + center: "居中", + right: "靠右" +}; diff --git a/noname/library/configuration-menu/view/configuration/show-name.js b/noname/library/configuration-menu/view/configuration/show-name.js new file mode 100644 index 000000000..093da972b --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-name.js @@ -0,0 +1,14 @@ +export const SHOW_NAME = { + name: "显示角色名称", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_name", bool); + if (bool) { + ui.arena.classList.remove("hide_name"); + } + else { + ui.arena.classList.add("hide_name"); + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-pause.js b/noname/library/configuration-menu/view/configuration/show-pause.js new file mode 100644 index 000000000..9d89516a1 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-pause.js @@ -0,0 +1,14 @@ +export const SHOW_PAUSE = { + name: "显示暂停按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_pause", bool); + if (lib.config.show_pause) { + ui.pause.style.display = ""; + } + else { + ui.pause.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-phase-prompt.js b/noname/library/configuration-menu/view/configuration/show-phase-prompt.js new file mode 100644 index 000000000..b15d399af --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-phase-prompt.js @@ -0,0 +1,6 @@ +export const SHOW_PHASE_PROMPT = { + name: "显示阶段信息", + intro: "在当前回合不同阶段开始时显示阶段名称", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-phase-use-prompt.js b/noname/library/configuration-menu/view/configuration/show-phase-use-prompt.js new file mode 100644 index 000000000..f30730d98 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-phase-use-prompt.js @@ -0,0 +1,6 @@ +export const SHOW_PHASE_USE_PROMPT = { + name: "出牌阶段提示", + intro: "在你出牌时显示提示文字", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-player-ids.js b/noname/library/configuration-menu/view/configuration/show-player-ids.js new file mode 100644 index 000000000..14251c7ef --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-player-ids.js @@ -0,0 +1,14 @@ +export const SHOW_PLAYER_IDS = { + name: "显示身份按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_playerids", bool); + if (lib.config.show_playerids) { + ui.playerids.style.display = ""; + } + else { + ui.playerids.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-rarity.js b/noname/library/configuration-menu/view/configuration/show-rarity.js new file mode 100644 index 000000000..14f99724b --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-rarity.js @@ -0,0 +1,9 @@ +export const SHOW_RARITY = { + name: "显示武将评级", + init: false, + intro: "仅供娱乐,重启后生效", + unfrequent: true, + onclick(bool) { + game.saveConfig("show_rarity", bool); + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-replay.js b/noname/library/configuration-menu/view/configuration/show-replay.js new file mode 100644 index 000000000..5155d52e3 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-replay.js @@ -0,0 +1,14 @@ +export const SHOW_REPLAY = { + name: "显示重来按钮", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_replay", bool); + if (lib.config.show_replay) { + ui.replay.style.display = ""; + } + else { + ui.replay.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-round-menu.js b/noname/library/configuration-menu/view/configuration/show-round-menu.js new file mode 100644 index 000000000..45c4e285c --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-round-menu.js @@ -0,0 +1,16 @@ +export const SHOW_ROUND_MENU = { + name: "显示触屏按钮", + init: true, + unfrequent: true, + onclick(bool) { + if (get.is.nomenu("show_round_menu", bool)) return false; + game.saveConfig("show_round_menu", bool); + if (bool && ui.roundmenu) { + ui.roundmenu.style.display = ""; + } + else { + ui.roundmenu.style.display = "none"; + alert("关闭触屏按钮后可通过手势打开菜单(默认为下划)") + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-sex.js b/noname/library/configuration-menu/view/configuration/show-sex.js new file mode 100644 index 000000000..82da6d633 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-sex.js @@ -0,0 +1,6 @@ +export const SHOW_SEX = { + name: "显示角色性别", + intro: "在角色的右键菜单中显示角色性别", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-skill-name-pinyin.js b/noname/library/configuration-menu/view/configuration/show-skill-name-pinyin.js new file mode 100644 index 000000000..9c6d03a49 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-skill-name-pinyin.js @@ -0,0 +1,18 @@ +import { SHOW_CHARACTER_NAME_PINYIN } from "./show-character-name-pinyin.js"; + +export const SHOW_SKILL_NAME_PINYIN = { + name: "显示技能名注解", + intro: "在武将资料卡显示技能名注解", + get init() { + return SHOW_CHARACTER_NAME_PINYIN.init; + }, + get unfrequent() { + return SHOW_CHARACTER_NAME_PINYIN.unfrequent; + }, + get item() { + return SHOW_CHARACTER_NAME_PINYIN.item; + }, + get visualMenu() { + return SHOW_CHARACTER_NAME_PINYIN.visualMenu; + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-sort-card.js b/noname/library/configuration-menu/view/configuration/show-sort-card.js new file mode 100644 index 000000000..a869d022e --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-sort-card.js @@ -0,0 +1,14 @@ +export const SHOW_SORT_CARD = { + name: "显示整理手牌按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_sortcard", bool); + if (lib.config.show_sortcard) { + ui.sortCard.style.display = ""; + } + else { + ui.sortCard.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-status-bar-android.js b/noname/library/configuration-menu/view/configuration/show-status-bar-android.js new file mode 100644 index 000000000..0baf51bd1 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-status-bar-android.js @@ -0,0 +1,18 @@ +export const SHOW_STATUS_BAR_ANDROID = { + name: "显示状态栏", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_statusbar", bool); + if (window.StatusBar && lib.device == "android") { + if (bool) { + window.StatusBar.overlaysWebView(false); + window.StatusBar.backgroundColorByName("black"); + window.StatusBar.show(); + } + else { + window.StatusBar.hide(); + } + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-status-bar-ios.js b/noname/library/configuration-menu/view/configuration/show-status-bar-ios.js new file mode 100644 index 000000000..4c4cb231e --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-status-bar-ios.js @@ -0,0 +1,29 @@ +import { ITEM } from "./show-status-bar-ios/item.js"; + +export const SHOW_STATUS_BAR_IOS = { + name: "显示状态栏", + init: "off", + unfrequent: true, + item: ITEM, + onclick(bool) { + game.saveConfig("show_statusbar_ios", bool); + if (window.StatusBar && lib.device == "ios") { + if (bool != "off" && bool != "auto") { + if (lib.config.show_statusbar_ios == "default") { + window.StatusBar.overlaysWebView(false); + document.body.classList.remove("statusbar"); + } + else { + window.StatusBar.overlaysWebView(true); + document.body.classList.add("statusbar"); + } + window.StatusBar.backgroundColorByName("black"); + window.StatusBar.show(); + } + else { + document.body.classList.remove("statusbar"); + window.StatusBar.hide(); + } + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-status-bar-ios/item.js b/noname/library/configuration-menu/view/configuration/show-status-bar-ios/item.js new file mode 100644 index 000000000..fbff5ec7e --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-status-bar-ios/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + default: "默认", + overlay: "嵌入", + auto: "自动", + off: "关闭" +}; diff --git a/noname/library/configuration-menu/view/configuration/show-time-2.js b/noname/library/configuration-menu/view/configuration/show-time-2.js new file mode 100644 index 000000000..b66b41d04 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-time-2.js @@ -0,0 +1,15 @@ +export const SHOW_TIME_2 = { + name: "显示时间", + intro: "在触屏按钮处显示当前时间", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_time2", bool); + if (bool) { + ui.roundmenu.classList.add("clock"); + } + else { + ui.roundmenu.classList.remove("clock"); + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-time-3.js b/noname/library/configuration-menu/view/configuration/show-time-3.js new file mode 100644 index 000000000..bdf8d2c7b --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-time-3.js @@ -0,0 +1,5 @@ +export const SHOW_TIME_3 = { + name: "显示游戏时间", + init: false, + unfrequent: true +}; diff --git a/noname/library/configuration-menu/view/configuration/show-time.js b/noname/library/configuration-menu/view/configuration/show-time.js new file mode 100644 index 000000000..dff5d5d24 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-time.js @@ -0,0 +1,15 @@ +export const SHOW_TIME = { + name: "显示时间", + intro: "在屏幕顶部显示当前时间", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_time", bool); + if (bool) { + ui.time.style.display = ""; + } + else { + ui.time.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-volume.js b/noname/library/configuration-menu/view/configuration/show-volume.js new file mode 100644 index 000000000..1dd459e5b --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-volume.js @@ -0,0 +1,14 @@ +export const SHOW_VOLUME = { + name: "显示音量按钮", + init: true, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_volumn", bool); + if (lib.config.show_volumn) { + ui.volumn.style.display = ""; + } + else { + ui.volumn.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/show-wuxie.js b/noname/library/configuration-menu/view/configuration/show-wuxie.js new file mode 100644 index 000000000..2d5194874 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/show-wuxie.js @@ -0,0 +1,15 @@ +export const SHOW_WUXIE = { + name: "显示无懈按钮", + intro: "在右上角显示不询问无懈", + init: false, + unfrequent: true, + onclick(bool) { + game.saveConfig("show_wuxie", bool); + if (lib.config.show_wuxie) { + ui.wuxie.style.display = ""; + } + else { + ui.wuxie.style.display = "none"; + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/transparent-dialog.js b/noname/library/configuration-menu/view/configuration/transparent-dialog.js new file mode 100644 index 000000000..1dcc3f4b2 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/transparent-dialog.js @@ -0,0 +1,22 @@ +export const TRANSPARENT_DIALOG = { + name: "堆叠对话框虚化", + init: false, + intro: "当具有static属性的对话框堆叠(如五谷丰登对话框中提示无懈可击)时,将后方的对话框变为半透明", + onclick(bool) { + game.saveConfig("transparent_dialog", bool); + if (bool) { + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i] != ui.dialog && ui.dialogs[i].static) { + ui.dialogs[i].unfocus(); + } + } + } + else { + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i] != ui.dialog && ui.dialogs[i].static) { + ui.dialogs[i].refocus(); + } + } + } + } +}; diff --git a/noname/library/configuration-menu/view/configuration/watch-face.js b/noname/library/configuration-menu/view/configuration/watch-face.js new file mode 100644 index 000000000..5db60a6cf --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/watch-face.js @@ -0,0 +1,12 @@ +import { ITEM } from "./watch-face/item.js"; + +export const WATCH_FACE = { + name: "表盘样式", + init: "none", + unfrequent: true, + item: ITEM, + onclick(item) { + game.saveConfig("watchface", item); + ui.roundmenu.dataset.watchface = item; + } +}; diff --git a/noname/library/configuration-menu/view/configuration/watch-face/item.js b/noname/library/configuration-menu/view/configuration/watch-face/item.js new file mode 100644 index 000000000..373e84912 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/watch-face/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + none: "默认", + simple: "简约" +}; diff --git a/noname/library/configuration-menu/view/configuration/wuxie-right.js b/noname/library/configuration-menu/view/configuration/wuxie-right.js new file mode 100644 index 000000000..0c7e6f1e2 --- /dev/null +++ b/noname/library/configuration-menu/view/configuration/wuxie-right.js @@ -0,0 +1,5 @@ +export const WUXIE_RIGHT = { + name: "无懈按钮靠左", + init: true, + unfrequent: true +}; diff --git a/noname/library/configuration.d.ts b/noname/library/configuration.d.ts new file mode 100644 index 000000000..a4a9c8433 --- /dev/null +++ b/noname/library/configuration.d.ts @@ -0,0 +1,6 @@ +interface Configuration extends Record { + extension_sources: Record; + favouriteCharacter: string[]; +} + +export const configuration: Configuration; diff --git a/noname/library/configuration.js b/noname/library/configuration.js new file mode 100644 index 000000000..b067409b7 --- /dev/null +++ b/noname/library/configuration.js @@ -0,0 +1 @@ +export const configuration = {}; diff --git a/noname/library/creation.js b/noname/library/creation.js new file mode 100644 index 000000000..6b6f7a85a --- /dev/null +++ b/noname/library/creation.js @@ -0,0 +1,21 @@ +export class Creation { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static get array() { + return []; + } + + static get object() { + return {}; + } + + static get nullObject() { + return Object.create(null); + } + + static get string() { + return ""; + } +} diff --git a/noname/library/dynamic-translate.d.ts b/noname/library/dynamic-translate.d.ts new file mode 100644 index 000000000..ca315d8e6 --- /dev/null +++ b/noname/library/dynamic-translate.d.ts @@ -0,0 +1,6 @@ +import { Player } from "./element/player.js"; + +interface DynamicTranslate extends Record string> { +} + +export const dynamicTranslate: DynamicTranslate; diff --git a/noname/library/dynamic-translate.js b/noname/library/dynamic-translate.js new file mode 100644 index 000000000..d4ef217a6 --- /dev/null +++ b/noname/library/dynamic-translate.js @@ -0,0 +1 @@ +export const dynamicTranslate = {}; diff --git a/noname/library/element.js b/noname/library/element.js new file mode 100644 index 000000000..c9e360f4f --- /dev/null +++ b/noname/library/element.js @@ -0,0 +1,8212 @@ +import { Button } from "./element/button.js"; +import { Card } from "./element/card.js"; +import { Client } from "./element/client.js"; +import { Control } from "./element/control.js"; +import { Dialog } from "./element/dialog.js"; +import { GameEventPromise } from "./element/game-event-promise.js"; +import { GameEvent } from "./element/game-event.js"; +import { NodeWS } from "./element/node-ws.js"; +import { Player } from "./element/player.js"; +import { VCard } from "./element/v-card.js"; +import { WS } from "./element/ws.js"; + +export const element = { + content: { + emptyEvent: function () { + event.trigger(event.name); + }, + //增加明置手牌 + addShownCards: () => { + var hs = player.getCards("h"), showingCards = event._cards.filter(showingCard => hs.includes(showingCard)), shown = player.getShownCards(); + event.gaintag.forEach(tag => player.addGaintag(showingCards, tag)); + if (!(event.cards = showingCards.filter(showingCard => !shown.includes(showingCard))).length) return; + game.log(player, "明置了", event.cards); + if (event.animate != false) player.$give(event.cards, player, false); + event.trigger("addShownCardsAfter"); + }, + //隐藏明置手牌 + hideShownCards: () => { + var shown = player.getShownCards(), hidingCards = event._cards.filter(hidingCard => shown.includes(hidingCard)); + if (!hidingCards.length) return; + if (event.gaintag.length) event.gaintag.forEach(tag => player.removeGaintag(tag, hidingCards)); + else { + var map = hidingCards.reduce((constructingMap, hidingCard) => { + hidingCard.gaintag.forEach(tag => { + if (!tag.startsWith("visible_")) return; + if (!constructingMap[tag]) constructingMap[tag] = []; + constructingMap[tag].push(hidingCard); + }); + return constructingMap; + }, {}); + Object.keys(map).forEach(key => player.removeGaintag(key, map[key])); + } + hidingCards.removeArray(player.getShownCards()); + if (!hidingCards.length) return; + game.log(player, "取消明置了", event.cards = hidingCards); + if (event.animate != false) player.$give(hidingCards, player, false); + event.trigger("hideShownCardsAfter"); + }, + //Execute the delay card effect + //执行延时锦囊牌效果 + executeDelayCardEffect: () => { + "step 0" + target.$phaseJudge(card); + event.cancelled = false; + event.trigger("executeDelayCardEffect"); + event.cardName = card.viewAs || card.name; + target.popup(event.cardName, "thunder"); + if (!lib.card[event.cardName].effect) { + game.delay(); + event.finish(); + } + else if (!lib.card[event.cardName].judge) { + game.delay(); + event.nojudge = true; + } + "step 1" + if (event.cancelled || event.nojudge) return; + var next = player.judge(card), judge = event.judge; + if (typeof judge == "function") next.judge = judge; + var judge2 = event.judge2; + if (typeof judge2 == "function") next.judge2 = judge2; + "step 2" + if (event.excluded) delete event.excluded; + else { + var cardName = event.cardName; + if (event.cancelled && !event.direct) { + var cardCancel = lib.card[cardName].cancel; + if (cardCancel) { + var next = game.createEvent(`${cardName}Cancel`); + next.setContent(cardCancel); + next.cards = [card]; + if (!card.viewAs) { + var autoViewAs = next.card = get.autoViewAs(card); + autoViewAs.expired = card.expired; + } + else { + var autoViewAs = next.card = get.autoViewAs({ + name: cardName + }, next.cards); + autoViewAs.expired = card.expired; + } + next.player = player; + } + } + else { + var next = game.createEvent(cardName); + next.setContent(lib.card[cardName].effect); + next._result = result; + next.cards = [card]; + if (!card.viewAs) { + var autoViewAs = next.card = get.autoViewAs(card); + autoViewAs.expired = card.expired; + } + else { + var autoViewAs = next.card = get.autoViewAs({ + name: cardName + }, next.cards); + autoViewAs.expired = card.expired; + } + next.player = player; + } + } + ui.clear(); + card.delete(); + }, + //Gift + //赠予 + gift: () => { + "step 0" + event.num = 0; + "step 1" + if (num < cards.length) { + event.card = cards[num]; + event.trigger("gift"); + } + else { + game.delayx(); + event.finish(); + } + "step 2" + if (event.deniedGifts.includes(card)) { + game.log(target, "拒绝了", player, "赠予的", card); + event.trigger("giftDeny"); + player.loseToDiscardpile(card).log = false; + event.trigger("giftDenied"); + return; + } + game.log(player, "将", card, "赠予了", target); + player.$give(card, target, false); + game.delay(0.5); + event.trigger("giftAccept"); + if (get.type(card, false) == "equip") target.equip(card).log = false; + else target.gain(card, player).visible = true; + event.trigger("giftAccepted"); + "step 3" + event.num++; + event.goto(1); + }, + //Recast + //重铸 + recast: () => { + "step 0" + game.log(player, "重铸了", cards); + if (typeof event.recastingLose != "function") return; + event.trigger("recastingLose"); + event.recastingLose(player, cards); + event.trigger("recastingLost"); + event.recastingLosingEvents.push(...event.next.filter(value => value.name != "arrangeTrigger")); + "step 1" + event.trigger("recast"); + "step 2" + if (typeof event.recastingGain != "function") return; + event.trigger("recastingGain"); + event.recastingGain(player, cards); + event.trigger("recastingGained"); + event.recastingGainingEvents.push(...event.next.filter(value => value.name != "arrangeTrigger")); + }, + //装备栏相关 + disableEquip: function () { + "step 0" + event.cards = []; + event.num = 0; + event.slotsx = []; + if (get.is.mountCombined()) { + event.slots.forEach(type => { + if (type == "equip3" || type == "equip4") event.slotsx.add("equip3_4"); + else event.slotsx.add(type) + }); + } + else { + event.slotsx.addArray(event.slots); + } + event.slotsx.sort(); + if (!event.slots.length) event.finish(); + "step 1" + var slot = event.slotsx[event.num]; + var slot_key = slot; + var left = player.countEnabledSlot(slot), lose; + if (slot == "equip3_4") { + lose = Math.min(left, Math.max(get.numOf(event.slots, "equip3"), get.numOf(event.slots, "equip4"))); + slot_key = "equip3"; + } + else lose = Math.min(left, get.numOf(event.slots, slot)); + if (lose <= 0) event.goto(3); + else { + game.log(player, "废除了" + get.cnNumber(lose) + "个", "#g" + get.translation(slot) + "栏"); + if (!player.disabledSlots) player.disabledSlots = {}; + if (!player.disabledSlots[slot_key]) player.disabledSlots[slot_key] = 0; + player.disabledSlots[slot_key] += lose; + var cards = player.getEquips(slot).filter(card => !event.cards.contains(card)); + if (cards.length > 0) { + if (lose >= left) { + event._result = { bool: true, links: cards }; + } + else if (cards.length > (left - lose)) { + var source = event.source, num = (cards.length - (left - lose)); + if (!source || !source.isIn()) source = player; + source.chooseButton([ + "选择" + (player == source ? "你" : get.translation(player)) + "的" + get.cnNumber(num) + "张" + get.translation(slot) + "牌置入弃牌堆", + cards, + ], true, [1, num]).set("filterOk", function () { + var evt = _status.event; + return ui.selected.buttons.reduce(function (num, button) { + if (evt.slot == "equip3_4") return num + Math.max(get.numOf(get.subtypes(button.link, false), "equip3"), get.numOf(get.subtypes(button.link, false), "equip4")); + return num + get.numOf(get.subtypes(button.link, false), evt.slot) + }, 0) == evt.required; + }).set("required", num).set("slot", slot) + } + else event.goto(3); + } + else event.goto(3) + } + "step 2" + if (result.bool) event.cards.addArray(result.links); + "step 3" + event.num++; + if (event.num < event.slotsx.length) event.goto(1); + else { + player.$syncDisable(); + if (cards.length > 0) player.loseToDiscardpile(cards); + } + }, + enableEquip: function () { + if (!event.slots.length) return; + var slotsx = [...new Set(event.slots)].sort(); + for (var slot of slotsx) { + var lost = player.countDisabledSlot(slot), gain = Math.min(lost, get.numOf(event.slots, slot)); + if (lost <= 0) continue; + else { + game.log(player, "恢复了" + get.cnNumber(gain) + "个", "#g" + get.translation(slot) + "栏"); + if (!player.disabledSlots) player.disabledSlots = {}; + if (!player.disabledSlots[slot]) player.disabledSlots[slot] = 0; + player.disabledSlots[slot] -= gain; + } + } + player.$syncDisable(); + }, + expandEquip: function () { + if (!event.slots.length) return; + var slotsx = []; + if (get.is.mountCombined()) { + event.slots.forEach(type => { + if (type == "equip3" || type == "equip4") slotsx.add("equip3_4"); + else slotsx.add(type) + }); + } + else { + slotsx.addArray(event.slots); + } + slotsx.sort(); + for (var slot of slotsx) { + var expand = get.numOf(event.slots, slot), slot_key = slot; + if (slot == "equip3_4") { + expand = Math.max(get.numOf(event.slots, "equip3"), get.numOf(event.slots, "equip4")); + slot_key = "equip3"; + } + game.log(player, "获得了" + get.cnNumber(expand) + "个额外的", "#g" + get.translation(slot) + "栏"); + if (!player.expandedSlots) player.expandedSlots = {}; + if (!player.expandedSlots[slot_key]) player.expandedSlots[slot_key] = 0; + player.expandedSlots[slot_key] += expand; + } + player.$syncExpand(); + }, + //选择顶装备要顶的牌 + replaceEquip: function () { + "step 0" + event.cards = []; + var types = get.subtypes(card, false); + if (types.length) { + var info = get.info(card, false); + if (info.customSwap) { + event.cards.addArray(player.getCards("e", function (card) { + return info.customSwap(card); + })); + event.goto(4); + } + else { + event.num = 0; + event.slots = types; + event.slotsx = []; + if (get.is.mountCombined()) { + event.slots.forEach(type => { + if (type == "equip3" || type == "equip4") event.slotsx.add("equip3_4"); + else event.slotsx.add(type) + }); + } + else { + event.slotsx.addArray(event.slots); + } + event.slotsx.sort(); + } + } + else event.goto(4); + "step 1" + var slot = event.slotsx[event.num]; + var left = player.countEquipableSlot(slot), lose; + if (slot == "equip3_4") lose = Math.min(left, Math.max(get.numOf(event.slots, "equip3"), get.numOf(event.slots, "equip4"))); + else lose = Math.min(left, get.numOf(event.slots, slot)); + if (lose <= 0) event.goto(3); + else { + var cards = player.getEquips(slot).filter(card => { + return !event.cards.contains(card) && lib.filter.canBeReplaced(card, player); + }); + if (cards.length > 0) { + if (lose >= left) { + event._result = { bool: true, links: cards }; + } + else if (cards.length > (left - lose)) { + var source = event.source, num = (cards.length - (left - lose)); + if (!source || !source.isIn()) source = player; + source.chooseButton([ + "选择替换掉" + get.cnNumber(num) + "张" + get.translation(slot) + "牌", + cards, + ], true, [1, num]).set("filterOk", function () { + var evt = _status.event; + return ui.selected.buttons.reduce(function (num, button) { + if (evt.slot == "equip3_4") return num + Math.max(get.numOf(get.subtypes(button.link, false), "equip3"), get.numOf(get.subtypes(button.link, false), "equip4")); + return num + get.numOf(get.subtypes(button.link, false), evt.slot) + }, 0) == evt.required; + }).set("required", num).set("slot", slot) + } + else event.goto(3); + } + else event.goto(3) + } + "step 2" + if (result.bool) event.cards.addArray(result.links); + "step 3" + event.num++; + if (event.num < event.slotsx.length) event.goto(1); + "step 4" + event.result = cards; + }, + //装备牌 + equip: function () { + "step 0" + var owner = get.owner(card) + if (owner) { + event.owner = owner; + owner.lose(card, ui.special, "visible").set("type", "equip").set("getlx", false); + } + else if (get.position(card) == "c") event.updatePile = true; + "step 1" + if (event.cancelled) { + event.finish(); + return; + } + if (card.willBeDestroyed("equip", player, event)) { + card.selfDestroy(event); + event.finish(); + return; + } + else if (event.owner) { + if (event.owner.getCards("hejsx").contains(card)) { + event.finish(); + return; + } + } + if (event.draw) { + game.delay(0, 300); + player.$draw(card); + } + "step 2" + if (card.clone) { + game.broadcast(function (card, player) { + if (card.clone) { + card.clone.moveDelete(player); + } + }, card, player); + card.clone.moveDelete(player); + game.addVideo("gain2", player, get.cardsInfo([card.clone])); + } + player.equiping = true; + "step 3" + var info = get.info(card, false); + var next = game.createEvent("replaceEquip"); + next.player = player; + next.card = card; + next.setContent(info.replaceEquip || "replaceEquip"); + "step 4" + var info = get.info(card, false); + if (get.itemtype(result) == "cards") { + player.lose(result, "visible").set("type", "equip").set("getlx", false).swapEquip = true; + if (info.loseThrow) { + player.$throw(result, 1000); + } + event.swapped = true; + } + "step 5" + //if(player.isMin() || player.countCards("e",{subtype:get.subtype(card)})){ + if (player.isMin() || !player.canEquip(card)) { + event.finish(); + game.cardsDiscard(card); + delete player.equiping; + return; + } + var subtype = get.subtype(card); + if (subtype == "equip6") subtype = "equip3"; + game.broadcastAll(function (type) { + if (lib.config.background_audio) { + game.playAudio("effect", type); + } + }, subtype); + player.$equip(card); + game.addVideo("equip", player, get.cardInfo(card)); + if (event.log != false) game.log(player, "装备了", card); + if (event.updatePile) game.updateRoundNumber(); + "step 6" + var info = get.info(card, false); + if (info.onEquip && (!info.filterEquip || info.filterEquip(card, player))) { + if (Array.isArray(info.onEquip)) { + for (var i = 0; i < info.onEquip.length; i++) { + var next = game.createEvent("equip_" + card.name); + next.setContent(info.onEquip[i]); + next.player = player; + next.card = card; + } + } + else { + var next = game.createEvent("equip_" + card.name); + next.setContent(info.onEquip); + next.player = player; + next.card = card; + } + if (info.equipDelay != false) game.delayx(); + } + delete player.equiping; + if (event.delay) { + game.delayx(); + } + }, + //装备栏 END + changeGroup: function () { + "step 0" + event.originGroup = player.group; + if (!event.group) event.group = player.group; + var group = event.group; + player.getHistory("custom").push(event); + if (event.broadcast !== false) { + game.broadcast(function (player, group) { + player.group = group; + player.node.name.dataset.nature = get.groupnature(group); + }, player, group); + } + player.group = group; + player.node.name.dataset.nature = get.groupnature(group); + if (event.log !== false) game.log(player, "将势力变为了", "#y" + get.translation(group + 2)); + }, + chooseToDebate: function () { + "step 0" + event.targets = event.list.filter(function (i) { + return i.countCards("h") > 0; + }); + if (!event.targets.length) event.result = { bool: false }; + else { + var next = player.chooseCardOL(event.targets, get.translation(player) + "发起了议事,请选择展示的手牌", true).set("type", "debate").set("source", player).set("ai", event.ai || function (card) { + return Math.random(); + }).set("aiCard", event.aiCard || function (target) { + var hs = target.getCards("h"); + return { bool: true, cards: [hs.randomGet()] }; + }); + next._args.remove("glow_result"); + } + "step 1" + var red = [], black = []; + event.videoId = lib.status.videoId++; + for (var i = 0; i < event.targets.length; i++) { + var card = result[i].cards[0], target = event.targets[i]; + if (get.color(card, target) == "red") red.push([target, card]); + else black.push([target, card]); + } + event.red = red; event.black = black; + if (red.length) { + game.log(red.map(function (i) { + return i[0]; + }), `意见为红色,展示了`, red.map(function (i) { + return i[1]; + })); + } + else game.log("#b无人", `意见为红色`); + if (black.length) { + game.log(black.map(function (i) { + return i[0]; + }), "意见为", "#g黑色", ",展示了", black.map(function (i) { + return i[1]; + })); + } + else game.log("#b无人", "意见为", "#g黑色"); + game.broadcastAll(function (name, id, redArgs, blackArgs) { + var dialog = ui.create.dialog(name + "发起了议事", "hidden", "forcebutton"); + dialog.videoId = id; + dialog.classList.add("scroll1"); + dialog.classList.add("scroll2"); + dialog.classList.add("fullwidth"); + dialog.classList.add("fullheight"); + dialog.buttonss = []; + + var list = ["意见为红色的角色", "意见为黑色的角色"] + for (var i = 0; i < list.length; i++) { + dialog.add(`
${list[i]}
`); + var buttons = ui.create.div(".buttons", dialog.content); + dialog.buttonss.push(buttons); + buttons.classList.add("popup"); + buttons.classList.add("guanxing"); + } + var func = function (target) { + if (target._tempTranslate) return target._tempTranslate; + var name = target.name; + if (lib.translate[name + "_ab"]) return lib.translate[name + "_ab"]; + return get.translation(name); + }; + for (var i = 0; i < redArgs.length; i++) { + var list = redArgs[i]; + var button = ui.create.button(list[1], "card", dialog.buttonss[0]); + button.querySelector(".info").innerHTML = func(list[0]); + } + for (var i = 0; i < blackArgs.length; i++) { + var list = blackArgs[i]; + var button = ui.create.button(list[1], "card", dialog.buttonss[1]); + button.querySelector(".info").innerHTML = func(list[0]); + } + dialog.open(); + }, get.translation(player), event.videoId, red, black); + game.delay(4); + "step 2" + game.broadcastAll("closeDialog", event.videoId); + var opinion = null; + if (event.red.length > event.black.length) opinion = "red"; + else if (event.red.length < event.black.length) opinion = "black"; + if (opinion) game.log(player, "本次发起的议事结果为", opinion == "red" ? `红色` : "#g黑色"); + else game.log(player, "本次发起的议事无结果"); + event.result = { + bool: true, + opinion: opinion, + red: event.red, + black: event.black, + targets: event.targets + } + "step 3" + if (event.callback) { + var next = game.createEvent("debateCallback", false); + next.player = player; + next.debateResult = get.copy(event.result); + next.setContent(event.callback); + } + }, + delay: function () { + game[event.name].apply(game, event._args) + }, + chooseCooperationFor: function () { + "step 0" + var next = player.chooseButton([ + "选择和" + get.translation(target) + "的协力方式", + [event.cardlist, "vcard"], + ], true); + next.set("ai", event.ai || function () { + return Math.random(); + }); + "step 1" + if (result.bool) { + player.cooperationWith(target, result.links[0][2].slice(12), event.reason); + } + }, + chooseToPlayBeatmap: function () { + "step 0" + if (game.online) return; + if (_status.connectMode) event.time = lib.configOL.choose_timeout; + event.videoId = lib.status.videoId++; + //给其他角色看的演奏框 + game.broadcastAll(function (player, id, beatmap) { + if (_status.connectMode) lib.configOL.choose_timeout = (Math.ceil((beatmap.timeleap[beatmap.timeleap.length - 1] + beatmap.speed * 100 + (beatmap.current || 0)) / 1000) + 5).toString(); + if (player == game.me) return; + var str = get.translation(player) + "正在演奏《" + beatmap.name + "》..."; + if (!_status.connectMode) str += "
(点击屏幕可以跳过等待AI操作)"; + ui.create.dialog(str).videoId = id; + if (ui.backgroundMusic) ui.backgroundMusic.pause(); + if (lib.config.background_audio) { + if (beatmap.filename.startsWith("ext:")) game.playAudio(beatmap.filename); + else game.playAudio("effect", beatmap.filename); + } + }, player, event.videoId, event.beatmap); + "step 1" + var beatmap = event.beatmap; + if (event.isMine()) { + var timeleap = beatmap.timeleap.slice(0); + var current = beatmap.current; + //获取两个音符的时间间隔 + var getTimeout = function () { + var time = timeleap.shift(); + var out = time - current; + current = time; + return out; + }; + //初始化一堆变量 + var score = 0; + var added = timeleap.length; + var number_of_tracks = beatmap.number_of_tracks || 6; + var custom_mapping = Array.isArray(beatmap.mapping); + var mapping = custom_mapping ? beatmap.mapping.slice() : beatmap.mapping; + var hitsound = beatmap.hitsound || "hitsound.wav"; + if (hitsound.startsWith("ext:")) hitsound = lib.assetURL + "extension/" + hitsound.slice(4); + else hitsound = lib.assetURL + "audio/effect/" + hitsound; + var hitsound_audio = new Audio(hitsound); + hitsound_audio.volume = 0.25; + var abs = 1; + var node_pos = 0; + if (custom_mapping) { + node_pos = mapping.shift(); + } + else if (mapping == "random") { + abs = get.rand(number_of_tracks); + node_pos = abs; + } + var combo = 0; + var max_combo = 0; + var nodes = []; + var roundmenu = false; + //隐藏菜单按钮 + if (ui.roundmenu && ui.roundmenu.display != "none") { + roundmenu = true; + ui.roundmenu.style.display = "none"; + } + if (ui.backgroundMusic) ui.backgroundMusic.pause(); + var event = _status.event; + event.settleed = false; + //建个框框 + var dialog = ui.create.dialog("forcebutton", "hidden"); + event.dialog = dialog; + event.dialog.textPrompt = event.dialog.add(`
${beatmap.prompt || "在音符滑条和底部判定区重合时点击屏幕!"}
`); + event.switchToAuto = () => void 0; + event.dialog.classList.add("fixed"); + event.dialog.classList.add("scroll1"); + event.dialog.classList.add("scroll2"); + event.dialog.classList.add("fullwidth"); + event.dialog.classList.add("fullheight"); + event.dialog.classList.add("noupdate"); + event.dialog.style.overflow = "hidden"; + //结束后操作 + event.settle = function () { + if (event.settleed) return; + event.settleed = true; + //评分 + var acc = Math.floor(score / (added * 5) * 100); + if (!Array.isArray(lib.config.choose_to_play_beatmap_accuracies)) lib.config.choose_to_play_beatmap_accuracies = []; + lib.config.choose_to_play_beatmap_accuracies.push(acc); + if (lib.config.choose_to_play_beatmap_accuracies.length > 5) lib.config.choose_to_play_beatmap_accuracies.shift(); + game.saveConfigValue("choose_to_play_beatmap_accuracies"); + var rank; + if (acc == 100) rank = ["SS", "metal"]; + else if (acc >= 94) rank = ["S", "orange"]; + else if (acc >= 87) rank = ["A", "wood"]; + else if (acc >= 80) rank = ["B", "water"]; + else if (acc >= 65) rank = ["C", "thunder"]; + else rank = ["D", "fire"]; + event.dialog.textPrompt.innerHTML = `
演奏结束!
最大连击数:${max_combo} 精准度:${acc}%
`; + game.me.$fullscreenpop(`演奏评级:${rank[0]}`, null, null, false); + //返回结果并继续游戏 + setTimeout(function () { + event._result = { + bool: true, + accuracy: acc, + rank: rank, + }; + event.dialog.close(); + game.resume(); + _status.imchoosing = false; + if (roundmenu) ui.roundmenu.style.display = ""; + if (ui.backgroundMusic) ui.backgroundMusic.play(); + hitsound_audio.remove(); + }, 1000); + }; + event.dialog.open(); + //操作容差 + var height = event.dialog.offsetHeight; + var width = event.dialog.offsetWidth; + var range1 = (beatmap.range1 || [90, 110]); + var range2 = (beatmap.range2 || [93, 107]); + var range3 = (beatmap.range3 || [96, 104]); + var speed = (beatmap.speed || 25); + //初始化底部的条子 + var judger = ui.create.div(""); + judger.style["background-image"] = (beatmap.judgebar_color || "linear-gradient(rgba(240, 235, 3, 1), rgba(230, 225, 5, 1))"); + judger.style["border-radius"] = "3px"; + judger.style.position = "absolute"; + judger.style.opacity = "0.3"; + var heightj = Math.ceil(height * (beatmap.judgebar_height || 0.1)); + judger.style.height = heightj + "px"; + judger.style.width = width + "px"; + judger.style.left = "0px"; + judger.style.top = (height - heightj) + "px"; + event.dialog.appendChild(judger); + //生成每个音符 + var addNode = function () { + var node = ui.create.div(""); + nodes.push(node); + node.style["background-image"] = (beatmap.node_color || "linear-gradient(rgba(120, 120, 240, 1), rgba(100, 100, 230, 1))"); + node.style["border-radius"] = "3px"; + node.style.position = "absolute"; + node.style.height = Math.ceil(height / 10) + "px"; + node.style.width = Math.ceil(width / number_of_tracks) - 10 + "px"; + node._position = get.utc(); + event.dialog.appendChild(node); + + node.style.left = Math.ceil(width * node_pos / number_of_tracks + 5) + "px"; + node.style.top = "-" + (Math.ceil(height / 10)) + "px"; + ui.refresh(node); + node.style.transition = "all " + speed * 110 + "ms linear"; + node.style.transform = "translateY(" + Math.ceil(height * 1.1) + "px)"; + node.timeout = setTimeout(function () { + if (nodes.contains(node)) { + nodes.remove(node); + player.popup("Miss", "fire", false); + if (player.damagepopups.length) player.$damagepop(); + combo = 0; + } + }, speed * 110); + + if (custom_mapping) { + node_pos = mapping.shift(); + } + else if (mapping == "random") { + while (node_pos == abs) { + node_pos = get.rand(number_of_tracks); + } + abs = node_pos; + } + else { + node_pos += abs; + if (node_pos > number_of_tracks - 1) { + abs = -1; + node_pos = number_of_tracks - 2; + } + else if (node_pos < 0) { + abs = 1; + node_pos = 1; + } + } + if (timeleap.length) { + setTimeout(function () { + addNode(); + }, getTimeout()); + } + else { + setTimeout(function () { + event.settle(); + }, speed * 110 + 100) + } + } + //点击时的判断操作 + var click = function () { + if (!nodes.length) return; + for (var node of nodes) { + //用生成到点击的时间差来判断距离 + var time = get.utc(); + var top = (time - node._position) / speed; + if (top > range1[1]) continue; + else if (top < range1[0]) return; + nodes.remove(node); + clearTimeout(node.timeout); + node.style.transform = ""; + node.style.transition = "all 0s"; + node.style.top = (height * ((top - 10) / 100)) + "px"; + ui.refresh(node); + node.style.transition = "all 0.5s"; + node.style.transform = "scale(1.2)"; + node.delete(); + if (top >= range3[0] && top < range3[1]) { + score += 5; + player.popup("Perfect", "orange", false); + } + else if (top >= range2[0] && top < range2[1]) { + score += 3; + player.popup("Great", "wood", false); + } + else { + score += 1; + player.popup("Good", "soil", false); + } + if (player.damagepopups.length) player.$damagepop(); + combo++; + max_combo = Math.max(combo, max_combo); + hitsound_audio.currentTime = 0; + if (hitsound_audio.paused) Promise.resolve(hitsound_audio.play()).catch(() => void 0); + break; + } + }; + document.addEventListener(lib.config.touchscreen ? "touchstart" : "mousedown", click); + + game.pause(); + game.countChoose(); + setTimeout(() => { + if (!lib.config.background_audio) return; + if (beatmap.filename.startsWith("ext:")) game.playAudio(beatmap.filename); + else game.playAudio("effect", beatmap.filename); + }, Math.floor(speed * 100 * (0.9 + beatmap.judgebar_height)) + beatmap.current); + setTimeout(function () { + addNode(); + }, getTimeout()); + } + else if (event.isOnline()) { + event.send(); + } + else { + game.pause(); + game.countChoose(); + var settle = function () { + _status.imchoosing = false; + //Algorithm: Generate the random number range using the mean and the half standard deviation of accuracies of the player"s last 5 plays + //算法:用玩家的上5次游玩的准确率的平均数和半标准差生成随机数范围 + var choose_to_play_beatmap_accuracies = (lib.config.choose_to_play_beatmap_accuracies || []).concat(Array.from({ + length: 6 - (lib.config.choose_to_play_beatmap_accuracies || []).length + }, () => get.rand(70, 100))); + var mean = Math.round(choose_to_play_beatmap_accuracies.reduce((previousValue, currentValue) => previousValue + currentValue) / choose_to_play_beatmap_accuracies.length); + var half_standard_deviation = Math.round(Math.sqrt(choose_to_play_beatmap_accuracies.reduce((previousValue, currentValue) => previousValue + Math.pow(currentValue - mean, 2), 0)) / 2); + var acc = Math.min(Math.max(get.rand.apply(get, beatmap.aiAcc || [mean - half_standard_deviation - get.rand(0, half_standard_deviation), mean + half_standard_deviation + get.rand(0, half_standard_deviation)]), 0), 100); + var rank; + if (acc == 100) rank = ["SS", "metal"]; + else if (acc >= 94) rank = ["S", "orange"]; + else if (acc >= 87) rank = ["A", "green"]; + else if (acc >= 80) rank = ["B", "water"]; + else if (acc >= 65) rank = ["C", "thunder"]; + else rank = ["D", "fire"]; + event._result = { + bool: true, + accuracy: acc, + rank: rank, + }; + if (event.dialog) event.dialog.close(); + if (event.control) event.control.close(); + game.resume(); + }; + var song_duration = beatmap.timeleap[beatmap.timeleap.length - 1] + beatmap.speed * 100 + 1000 + (beatmap.current || 0); + var settle_timeout = setTimeout(settle, song_duration); + if (!_status.connectMode) { + var skip_timeout; + var skip = () => { + settle(); + Array.from(ui.window.getElementsByTagName("audio")).forEach(audio => { + if (audio.currentSrc.includes(beatmap.filename.startsWith("ext:") ? beatmap.name : beatmap.filename)) audio.remove(); + }); + document.removeEventListener(lib.config.touchscreen ? "touchend" : "click", skip); + clearTimeout(settle_timeout); + clearTimeout(skip_timeout); + }; + document.addEventListener(lib.config.touchscreen ? "touchend" : "click", skip); + skip_timeout = setTimeout(() => document.removeEventListener(lib.config.touchscreen ? "touchend" : "click", skip), song_duration); + } + } + "step 2" + game.broadcastAll(function (id, time) { + if (_status.connectMode) lib.configOL.choose_timeout = time; + var dialog = get.idDialog(id); + if (dialog) { + dialog.close(); + } + if (ui.backgroundMusic) ui.backgroundMusic.play(); + }, event.videoId, event.time); + var result = event.result || result; + event.result = result; + }, + chooseToMove: function () { + "step 0" + if (event.chooseTime && _status.connectMode && !game.online) { + event.time = lib.configOL.choose_timeout; + game.broadcastAll(function (time) { + lib.configOL.choose_timeout = time; + }, event.chooseTime); + } + if (event.isMine()) { + delete ui.selected.guanxing_button; + var list = event.list, filterMove = event.filterMove, filterOk = event.filterOk; + _status.imchoosing = true; + var event = _status.event; + event.settleed = false; + event.dialog = ui.create.dialog(event.prompt || "请选择要操作的牌", "hidden", "forcebutton"); + event.switchToAuto = function () { + if (!filterOk(event.moved)) { + if (!event.forced) event._result = { bool: false }; + else event._result = "ai"; + } + else { + event._result = { + bool: true, + moved: event.moved, + }; + } + event.dialog.close(); + if (ui.confirm) ui.confirm.close(); + game.resume(); + _status.imchoosing = false; + setTimeout(function () { + ui.arena.classList.remove("choose-to-move"); + }, 500); + }; + event.dialog.classList.add("scroll1"); + event.dialog.classList.add("scroll2"); + event.dialog.classList.add("fullwidth"); + if (list.length > 1) { + ui.arena.classList.add("choose-to-move"); + event.dialog.classList.add("fullheight"); + } + + event.moved = []; + var buttonss = []; + event.buttonss = buttonss; + var updateButtons = function () { + for (var i of buttonss) { + event.moved[i._link] = get.links(Array.from(i.childNodes)); + if (i.textPrompt) i.previousSibling.innerHTML = `
${i.textPrompt(event.moved[i._link])}
`; + } + if (filterOk(event.moved)) { + ui.create.confirm("o"); + } + else { + if (!event.forced) ui.create.confirm("c"); + else if (ui.confirm) ui.confirm.close(); + } + }; + var clickButtons = function () { + if (!ui.selected.guanxing_button) return; + if (ui.selected.guanxing_button.parentNode == this) return; + if (!filterMove(ui.selected.guanxing_button, this._link, event.moved)) return; + ui.selected.guanxing_button.classList.remove("glow2"); + this.appendChild(ui.selected.guanxing_button); + delete ui.selected.guanxing_button; + updateButtons(); + }; + + for (var i = 0; i < list.length; i++) { + var tex = event.dialog.add(`
${list[i][0]}
`); + tex.classList.add("choosetomove"); + var buttons = ui.create.div(".buttons", event.dialog.content, clickButtons); + buttonss.push(buttons); + buttons.classList.add("popup"); + buttons.classList.add("guanxing"); + buttons._link = i; + if (list[i][1]) { + if (get.itemtype(list[i][1]) == "cards") { + var cardsb = ui.create.buttons(list[i][1], "card", buttons); + if (list[i][2] && typeof list[i][2] == "string") { + for (var ij of cardsb) ij.node.gaintag.innerHTML = get.translation(list[i][2]); + } + } + else if (list[i][1].length == 2) { + ui.create.buttons(list[i][1][0], list[i][1][1], buttons); + } + } + if (list[i][2] && typeof list[i][2] == "function") buttons.textPrompt = list[i][2]; + } + var tex = event.dialog.add(`
点击两张牌以交换位置;点击一张牌并点击其他区域以移动卡牌
`); + tex.classList.add("choosetomove"); + + event.dialog.open(); + updateButtons(); + + event.custom.replace.button = function (button) { + var node = button.parentNode; + if (!buttonss.contains(node)) return; + if (!ui.selected.guanxing_button) { + ui.selected.guanxing_button = button; + button.classList.add("glow2"); + return; + } + if (ui.selected.guanxing_button == button) { + button.classList.remove("glow2"); + delete ui.selected.guanxing_button; + return; + } + if (!filterMove(button, ui.selected.guanxing_button, event.moved)) return; + var par1 = ui.selected.guanxing_button.parentNode, ind1 = ui.selected.guanxing_button.nextSibling, par2 = button.parentNode, ind2 = button.nextSibling; + ui.selected.guanxing_button.classList.remove("glow2"); + par1.insertBefore(button, ind1); + par2.insertBefore(ui.selected.guanxing_button, ind2); + delete ui.selected.guanxing_button; + updateButtons(); + } + event.custom.replace.confirm = function (bool) { + if (bool) event._result = { + bool: true, + moved: event.moved, + }; + else event._result = { bool: false }; + event.dialog.close(); + if (ui.confirm) ui.confirm.close(); + game.resume(); + _status.imchoosing = false; + setTimeout(function () { + ui.arena.classList.remove("choose-to-move"); + }, 500); + }; + + game.pause(); + game.countChoose(); + event.choosing = true; + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.time) game.broadcastAll(function (time) { + lib.configOL.choose_timeout = time; + }, event.time); + var result = event.result || result; + if ((!result || result == "ai" || (event.forced && !result.bool)) && event.processAI) { + var moved = event.processAI(event.list); + if (moved) result = { + bool: true, + moved: moved, + } + else result = { bool: false }; + } + event.result = result; + }, + showCharacter: function () { + "step 0" + event.trigger("showCharacterEnd"); + "step 1" + event.trigger("showCharacterAfter"); + if (get.mode() == "identity" && player.isZhu) event.trigger("zhuUpdate"); + }, + removeCharacter: function () { + player.$removeCharacter(event.num); + }, + chooseUseTarget: function () { + "step 0" + if (get.is.object(card) && !event.viewAs) card.isCard = true; + if (cards && get.itemtype(card) != "card") { + card = get.copy(card); + card.cards = cards.slice(0); + event.card = card; + } + if (!lib.filter.cardEnabled(card, player) || (event.addCount !== false && !lib.filter.cardUsable(card, player))) { + event.result = { bool: false }; + event.finish(); + return; + } + var info = get.info(card); + var range; + if (!info.notarget) { + var select = get.copy(info.selectTarget); + range = get.select(select); + if (event.selectTarget) range = get.select(event.selectTarget); + game.checkMod(card, player, range, "selectTarget", player); + } + if (info.notarget || range[1] <= -1) { + if (!info.notarget && range[1] <= -1) { + for (var i = 0; i < targets.length; i++) { + if (event.filterTarget) { + if (!event.filterTarget(card, player, targets[i])) { + targets.splice(i--, 1); + } + } + else if (!player.canUse(card, targets[i], event.nodistance ? false : null, event.addCount === false ? null : true)) { + targets.splice(i--, 1); + } + } + if (targets.length) { + event.targets2 = targets; + } + else { + event.finish(); + return; + } + } + else event.targets2 = []; + if (event.forced) { + event._result = { bool: true }; + return; + } + else { + var next = player.chooseBool(); + next.set("prompt", event.prompt || ("是否" + (event.targets2.length ? "对" : "") + get.translation(event.targets2) + "使用" + get.translation(card) + "?")); + if (event.hsskill) next.setHiddenSkill(event.hsskill); + if (event.prompt2) next.set("prompt2", event.prompt2); + next.ai = function () { + var eff = 0; + for (var i = 0; i < event.targets2.length; i++) { + eff += get.effect(event.targets2[i], card, player, player); + } + return eff > 0; + }; + } + } + else { + if (event.filterTarget) { + var targets = game.filterPlayer(function (current) { + return event.filterTarget(card, player, current); + }); + if (targets.length < range[0]) { + event._result = { bool: false }; + return; + } + else if (!info.complexTarget && targets.length == range[0] && range[0] == range[1]) { + event.targets2 = targets; + event._result = { bool: true }; + return; + } + } + var next = player.chooseTarget(); + next.set("_get_card", card); + next.set("filterTarget", event.filterTarget || function (card, player, target) { + if (!_status.event.targets.contains(target)) return false; + if (!_status.event.nodistance && !lib.filter.targetInRange(card, player, target)) return false; + return lib.filter.targetEnabledx(card, player, target); + }); + next.set("ai", event.ai || get.effect_use); + next.set("selectTarget", event.selectTarget || lib.filter.selectTarget); + if (event.nodistance) next.set("nodistance", true); + if (event.forced) next.set("forced", true); + if (event.addCount !== false) next.set("addCount_extra", true); + next.set("targets", targets); + next.set("prompt", event.prompt || ("选择" + get.translation(card) + "的目标")); + if (event.prompt2) next.set("prompt2", event.prompt2); + if (event.hsskill) next.setHiddenSkill(event.hsskill); + } + "step 1" + if (result.bool) { + event.result = { + bool: true, + targets: event.targets2 || result.targets, + }; + var args = [card, event.targets2 || result.targets]; + if (cards) args.push(cards.slice()); + var next = player.useCard(...args); + next.oncard = event.oncard; + if (cards) next.cards = cards.slice(0); + if (event.nopopup) next.nopopup = true; + if (event.animate === false) next.animate = false; + if (event.throw === false) next.throw = false; + if (event.addCount === false) next.addCount = false; + if (event.noTargetDelay) next.targetDelay = false; + if (event.nodelayx) next.delayx = false; + if (event.logSkill) { + if (typeof event.logSkill == "string") { + next.skill = event.logSkill; + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + } + else event.result = { bool: false }; + }, + chooseToDuiben: function () { + "step 0" + if (!event.namelist) event.namelist = ["全军出击", "分兵围城", "奇袭粮道", "开城诱敌"]; + game.broadcastAll(function (list) { + var list2 = ["db_atk1", "db_atk2", "db_def1", "db_def2"]; + for (var i = 0; i < 4; i++) { + lib.card[list2[i]].image = "card/" + list2[i] + (list[0] == "全军出击" ? "" : "_" + list[i]); + lib.translate[list2[i]] = list[i]; + } + }, event.namelist); + if (!event.title) event.title = "对策"; + game.log(player, "向", target, "发起了", "#y" + event.title); + if (!event.ai) event.ai = function () { return 1 + Math.random() }; + if (_status.connectMode) { + player.chooseButtonOL([ + [player, [event.title + ":请选择一种策略", [[["", "", "db_def2"], ["", "", "db_def1"]], "vcard"]], true], + [target, [event.title + ":请选择一种策略", [[["", "", "db_atk1"], ["", "", "db_atk2"]], "vcard"]], true] + ], () => void 0, event.ai).set("switchToAuto", function () { + _status.event.result = "ai"; + }).set("processAI", function () { + var buttons = _status.event.dialog.buttons; + return { + bool: true, + links: [buttons.randomGet().link], + } + }); + } + "step 1" + if (_status.connectMode) { + event.mes = result[player.playerid].links[0][2]; + event.tes = result[target.playerid].links[0][2]; + event.goto(4); + } + else { + player.chooseButton([event.title + ":请选择一种策略", [[["", "", "db_def2"], ["", "", "db_def1"]], "vcard"]], true).ai = event.ai; + } + "step 2" + event.mes = result.links[0][2]; + target.chooseButton([event.title + ":请选择一种策略", [[["", "", "db_atk1"], ["", "", "db_atk2"]], "vcard"]], true).ai = event.ai; + "step 3" + event.tes = result.links[0][2]; + "step 4" + game.broadcast(function () { + ui.arena.classList.add("thrownhighlight"); + }); + ui.arena.classList.add("thrownhighlight"); + game.addVideo("thrownhighlight1"); + target.$compare(game.createCard(event.tes, "", ""), player, game.createCard(event.mes, "", "")); + game.log(target, "选择的策略为", "#g" + get.translation(event.tes)); + game.log(player, "选择的策略为", "#g" + get.translation(event.mes)); + game.delay(0, 1500); + "step 5" + var mes = event.mes.slice(6); + var tes = event.tes.slice(6); + var str; + if (mes == tes) { + str = get.translation(player) + event.title + "成功"; + player.popup("胜", "wood"); + target.popup("负", "fire"); + game.log(player, "#g胜"); + event.result = { bool: true }; + } + else { + str = get.translation(player) + event.title + "失败"; + target.popup("胜", "wood"); + player.popup("负", "fire"); + game.log(target, "#g胜"); + event.result = { bool: false }; + } + event.result.player = event.mes; + event.result.target = event.tes; + game.broadcastAll(function (str) { + var dialog = ui.create.dialog(str); + dialog.classList.add("center"); + setTimeout(function () { + dialog.close(); + }, 1000); + }, str); + game.trySkillAudio(event.getParent().name + "_" + (event.result.bool ? "true" + mes : "false"), player); + game.delay(2); + "step 6" + game.broadcastAll(function () { + ui.arena.classList.remove("thrownhighlight"); + }); + game.addVideo("thrownhighlight2"); + if (event.clear !== false) { + game.broadcastAll(ui.clear); + } + }, + chooseToPSS: function () { + "step 0" + game.log(player, "对", target, "发起了猜拳"); + if (_status.connectMode) { + player.chooseButtonOL([ + [player, ["猜拳:请选择一种手势", [[["", "", "pss_stone"], ["", "", "pss_scissor"], ["", "", "pss_paper"]], "vcard"]], true], + [target, ["猜拳:请选择一种手势", [[["", "", "pss_stone"], ["", "", "pss_scissor"], ["", "", "pss_paper"]], "vcard"]], true] + ], () => void 0, function () { return 1 + Math.random() }).set("switchToAuto", function () { + _status.event.result = "ai"; + }).set("processAI", function () { + var buttons = _status.event.dialog.buttons; + return { + bool: true, + links: [buttons.randomGet().link], + } + }); + } + "step 1" + if (_status.connectMode) { + event.mes = result[player.playerid].links[0][2]; + event.tes = result[target.playerid].links[0][2]; + event.goto(4); + } + else { + player.chooseButton(["猜拳:请选择一种手势", [[["", "", "pss_stone"], ["", "", "pss_scissor"], ["", "", "pss_paper"]], "vcard"]], true).ai = function () { return 1 + Math.random() }; + } + "step 2" + event.mes = result.links[0][2]; + target.chooseButton(["猜拳:请选择一种手势", [[["", "", "pss_stone"], ["", "", "pss_scissor"], ["", "", "pss_paper"]], "vcard"]], true).ai = function () { return 1 + Math.random() }; + "step 3" + event.tes = result.links[0][2]; + "step 4" + game.broadcast(function () { + ui.arena.classList.add("thrownhighlight"); + }); + ui.arena.classList.add("thrownhighlight"); + game.addVideo("thrownhighlight1"); + player.$compare(game.createCard(event.mes, "", ""), target, game.createCard(event.tes, "", "")); + game.log(player, "选择的手势为", "#g" + get.translation(event.mes)); + game.log(target, "选择的手势为", "#g" + get.translation(event.tes)); + game.delay(0, 1500); + "step 5" + var mes = event.mes.slice(4); + var tes = event.tes.slice(4); + var str; + if (mes == tes) { + str = "二人平局"; + player.popup("平", "metal"); + target.popup("平", "metal"); + game.log("猜拳的结果为", "#g平局"); + event.result = { tie: true }; + } + else { + if ({ paper: "stone", scissor: "paper", stone: "scissor" }[mes] == tes) { + str = get.translation(player) + "胜利"; + player.popup("胜", "wood"); + target.popup("负", "fire"); + game.log(player, "#g胜"); + event.result = { bool: true }; + } + else { + str = get.translation(target) + "胜利"; + target.popup("胜", "wood"); + player.popup("负", "fire"); + game.log(target, "#g胜"); + event.result = { bool: false }; + } + } + game.broadcastAll(function (str) { + var dialog = ui.create.dialog(str); + dialog.classList.add("center"); + setTimeout(function () { + dialog.close(); + }, 1000); + }, str); + game.delay(2); + "step 6" + game.broadcastAll(function () { + ui.arena.classList.remove("thrownhighlight"); + }); + game.addVideo("thrownhighlight2"); + if (event.clear !== false) { + game.broadcastAll(ui.clear); + } + }, + cardsDiscard: function () { + game.getGlobalHistory().cardMove.push(event); + var withPile = false; + for (var i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("discardPile", null, event)) { + cards[i].selfDestroy(event); + continue; + } + if (get.position(cards[i], true) == "c") withPile = true; + cards[i].discard(); + } + if (withPile) game.updateRoundNumber(); + }, + orderingDiscard: function () { + var cards = event.relatedEvent.orderingCards.slice(0); + for (var i = 0; i < cards.length; i++) { + if (get.position(cards[i], true) != "o") cards.splice(i--, 1); + } + if (cards.length) game.cardsDiscard(cards); + }, + cardsGotoOrdering: function () { + game.getGlobalHistory().cardMove.push(event); + var withPile = false; + for (var i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("ordering", null, event)) { + cards[i].selfDestroy(event); + continue; + } + if (get.position(cards[i], true) == "c") withPile = true; + cards[i].fix(); + ui.ordering.appendChild(cards[i]); + } + if (withPile) game.updateRoundNumber(); + var evt = event.relatedEvent || event.getParent(); + if (!evt.orderingCards) evt.orderingCards = []; + if (!evt.noOrdering && !evt.cardsOrdered) { + evt.cardsOrdered = true; + var next = game.createEvent("orderingDiscard", false, evt.getParent()); + next.relatedEvent = evt; + next.setContent("orderingDiscard"); + } + if (!evt.noOrdering) evt.orderingCards.addArray(cards); + }, + cardsGotoSpecial: function () { + game.getGlobalHistory().cardMove.push(event); + var withPile = false; + for (var i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("special", null, event)) { + cards[i].selfDestroy(event); + continue; + } + if (get.position(cards[i], true) == "c") withPile = true; + cards[i].fix(); + ui.special.appendChild(cards[i]); + } + if (withPile) game.updateRoundNumber(); + if (event.toRenku) { + _status.renku.addArray(cards); + if (_status.renku.length > 6) { + var cards = _status.renku.splice(0, _status.renku.length - 6); + game.log(cards, "从仁库进入了弃牌堆"); + game.cardsDiscard(cards).set("outRange", true).fromRenku = true; + } + game.updateRenku(); + } + }, + cardsGotoPile: function () { + if (event.washCard) { + event.trigger("washCard") + for (var i = 0; i < lib.onwash.length; i++) { + if (lib.onwash[i]() == "remove") { + lib.onwash.splice(i--, 1); + } + } + } + game.getGlobalHistory().cardMove.push(event); + if (!event._triggeronly) game.$cardsGotoPile(event); + }, + chooseToEnable: function () { + "step 0" + var list = []; + for (var i = 1; i <= 5; i++) { + if (player.hasDisabledSlot(i)) list.push("equip" + i); + } + if (!list.length) event.finish(); + else if (list.length == 1) { + event.list = list; + event._result = { control: list[0] }; + } + else { + var next = player.chooseControl(list); + next.set("prompt", "请选择恢复一个装备栏"); + if (!event.ai) event.ai = function (event, player, list) { + return list.randomGet(); + } + event.ai = event.ai(event.getParent(), player, list); + next.ai = function () { + return event.ai; + }; + } + "step 1" + event.result = { control: result.control }; + player.enableEquip(result.control); + }, + chooseToDisable: function () { + "step 0" + var list = []; + for (var i = 1; i <= 5; i++) { + if (player.hasEnabledSlot(i)) list.push("equip" + i); + } + if (event.horse) { + if (list.contains("equip3") && (get.is.mountCombined() || list.contains("equip4"))) list.push("equip3_4"); + list.remove("equip3"); + list.remove("equip4"); + } + if (!list.length) event.finish(); + else if (list.length == 1) { + event.list = list; + event._result = { control: list[0] }; + } + else { + list.sort(); + event.list = list; + var next = player.chooseControl(list); + next.set("prompt", "请选择废除一个装备栏"); + if (!event.ai) event.ai = function (event, player, list) { + return list.randomGet(); + } + event.ai = event.ai(event.getParent(), player, list); + next.ai = function () { + return event.ai; + }; + } + "step 1" + event.result = { control: result.control }; + if (result.control == "equip3_4") { + player.disableEquip(3, 4); + } + else player.disableEquip(result.control); + }, + swapEquip: function () { + "step 0" + game.log(player, "和", target, "交换了装备区中的牌") + event.cards = [player.getCards("e"), target.getCards("e")]; + game.loseAsync({ + player: player, + target: target, + cards1: event.cards[0], + cards2: event.cards[1], + }).setContent("swapHandcardsx"); + "step 1" + for (var i = 0; i < event.cards[1].length; i++) { + if (get.position(event.cards[1][i], true) == "o") player.equip(event.cards[1][i]); + } + for (var i = 0; i < event.cards[0].length; i++) { + if (get.position(event.cards[0][i], true) == "o") target.equip(event.cards[0][i]); + } + }, + disableJudge: function () { + "step 0" + game.log(player, "废除了判定区"); + var js = player.getCards("j"); + if (js.length) player.discard(js); + player.storage._disableJudge = true; + //player.markSkill("_disableJudge"); + "step 1" + game.broadcastAll(function (player, card) { + player.$disableJudge(); + }, player); + }, + enableJudge: function () { + if (!player.storage._disableJudge) return; + game.log(player, "恢复了判定区"); + game.broadcastAll(function (player) { + player.$enableJudge(); + }, player); + }, + /*----分界线----*/ + phasing: function () { + "step 0" + while (ui.dialogs.length) { + ui.dialogs[0].close(); + } + game.phaseNumber++; + player.phaseNumber++; + game.broadcastAll(function (player, player2, num, popup) { + if (lib.config.glow_phase) { + if (player2) player2.classList.remove("glow_phase"); + player.classList.add("glow_phase"); + } + player.phaseNumber = num; + if (popup && lib.config.show_phase_prompt) player.popup("回合开始", null, false); + }, player, _status.currentPhase, player.phaseNumber, !player.noPhaseDelay); + _status.currentPhase = player; + _status.discarded = []; + game.syncState(); + game.addVideo("phaseChange", player); + if (game.phaseNumber == 1) { + delete player._start_cards; + if (lib.configOL.observe) { + lib.configOL.observeReady = true; + game.send("server", "config", lib.configOL); + } + } + game.log(); + game.log(player, "的回合开始"); + player._noVibrate = true; + if (get.config("identity_mode") != "zhong" && get.config("identity_mode") != "purple" && !_status.connectMode) { + var num; + switch (get.config("auto_identity")) { + case "one": num = 1; break; + case "two": num = 2; break; + case "three": num = 3; break; + case "always": num = -1; break; + default: num = 0; break; + } + if (num && !_status.identityShown && game.phaseNumber > game.players.length * num && game.showIdentity) { + if (!_status.video) player.popup("显示身份"); + _status.identityShown = true; + game.showIdentity(false); + } + } + player.ai.tempIgnore = []; + if (ui.land && ui.land.player == player) { + game.addVideo("destroyLand"); + ui.land.destroy(); + } + "step 1" + event.trigger("phaseBeginStart"); + }, + toggleSubPlayer: function () { + "step 0" + var list = event.list || player.storage.subplayer.skills.slice(0); + list.remove(player.storage.subplayer.name2); + event.list = list; + if (!event.directresult) { + if (list.length > 1) { + var dialog = ui.create.dialog("更换一个随从", "hidden"); + dialog.add([list, "character"]); + player.chooseButton(dialog, true); + } + else if (list.length == 1) { + event.directresult = list[0]; + } + else { + event.finish(); + } + } + else { + if (!list.contains(event.directresult)) { + event.finish(); + } + } + "step 1" + if (!event.directresult) { + if (result && result.bool && result.links[0]) { + event.directresult = result.links[0]; + } + else { + event.finish(); + return; + } + } + if (player.storage.subplayer) { + var current = player.storage.subplayer.name2; + if (event.directresult == current) { + event.finish(); + return; + } + player.storage[current].hp = player.hp; + player.storage[current].maxHp = player.maxHp; + player.storage[current].hs = player.getCards("h"); + player.storage[current].es = player.getCards("e"); + player.lose(player.getCards("he"), ui.special)._triggered = null; + + var cfg = player.storage[event.directresult]; + player.storage.subplayer.name2 = event.directresult; + player.reinit(current, event.directresult, [ + cfg.hp, + cfg.maxHp + ]); + if (cfg.hs.length) player.directgain(cfg.hs); + if (cfg.es.length) player.directequip(cfg.es); + } + }, + exitSubPlayer: function () { + "step 0" + if (player.storage.subplayer) { + var current = player.storage.subplayer.name2; + if (event.remove) { + player.lose(player.getCards("he"), ui.discardPile)._triggered = null; + } + else { + player.storage[current].hp = player.hp; + player.storage[current].maxHp = player.maxHp; + player.storage[current].hs = player.getCards("h"); + player.storage[current].es = player.getCards("e"); + player.lose(player.getCards("he"), ui.special)._triggered = null; + } + player.reinit(current, player.storage.subplayer.name, [ + player.storage.subplayer.hp, + player.storage.subplayer.maxHp + ]); + player.update(); + if (event.remove) { + if (player.storage[current].onremove) { + player.storage[current].onremove(player); + } + delete player.storage[current]; + player.storage.subplayer.skills.remove(current); + game.log(player, "牺牲了随从", "#g" + current); + } + else { + game.log(player, "收回了随从", "#g" + current); + } + player.addSkill(player.storage.subplayer.skills); + } + "step 1" + if (player.storage.subplayer) { + player.directgain(player.storage.subplayer.hs); + player.directequip(player.storage.subplayer.es); + } + player.removeSkill("subplayer"); + "step 2" + if (event.remove) { + event.trigger("subPlayerDie"); + } + }, + callSubPlayer: function () { + "step 0" + var list = player.getSubPlayers(event.tag); + event.list = list; + if (!event.directresult) { + if (list.length > 1) { + var dialog = ui.create.dialog("调遣一个随从", "hidden"); + dialog.add([list, "character"]); + player.chooseButton(dialog, true); + } + else if (list.length == 1) { + event.directresult = list[0]; + } + else { + event.finish(); + } + } + else { + if (!list.contains(event.directresult)) { + event.finish(); + } + } + "step 1" + if (!event.directresult) { + if (result && result.bool && result.links[0]) { + event.directresult = result.links[0]; + } + else { + event.finish(); + return; + } + } + if (event.directresult) { + var cfg = player.storage[event.directresult]; + var source = cfg.source || player.name; + var name = event.directresult; + game.log(player, "调遣了随从", "#g" + name); + player.storage.subplayer = { + name: source, + name2: event.directresult, + hp: player.hp, + maxHp: player.maxHp, + skills: event.list.slice(0), + hs: player.getCards("h"), + es: player.getCards("e"), + intro2: cfg.intro2 + } + player.removeSkill(event.list); + player.reinit(source, name, [cfg.hp, cfg.maxHp]); + player.addSkill("subplayer"); + player.lose(player.getCards("he"), ui.special)._triggered = null; + if (cfg.hs.length) player.directgain(cfg.hs); + if (cfg.es.length) player.directequip(cfg.es); + } + "step 2" + game.delay(); + }, + addExtraTarget: function () { + "step 0" + event.num = 0; + "step 1" + var target = targets[num], info = get.info(card); + if (target == event.target && event.addedTarget) { + event.addedTargets[num] = event.addedTarget; + event._result = { bool: false }; + } + else if (game.hasPlayer(function (current) { + return info.filterAddedTarget(card, player, current, target) + })) { + var next = player.chooseTarget(get.translation(event.card) + ":选择" + get.translation(targets[num]) + "对应的指向目标", function (card, player, target) { + var card = get.card(), info = get.info(card); + return info.filterAddedTarget(card, player, target, _status.event.preTarget) + }, true); + next.set("_get_card", card); + next.set("preTarget", targets[num]); + next.set("ai", target => get.effect(target, get.card(), player, _status.event.player)); + } + else { + event.addedTargets[num] = false; + event._result = { bool: false }; + } + "step 2" + if (result.bool) { + event.addedTargets[num] = result.targets[0]; + player.line2([targets[num], result.targets[0]]); + } + event.num++; + if (event.num < targets.length) event.goto(1); + }, + reverseOrder: function () { + "step 0" + game.delay(); + "step 1" + var choice; + if (get.tag(card, "multineg")) { + choice = (player.previous.side == player.side) ? "逆时针" : "顺时针"; + } + else { + choice = (player.next.side == player.side) ? "逆时针" : "顺时针"; + } + player.chooseControl("顺时针", "逆时针", function (event, player) { + return _status.event.choice || "逆时针"; + }).set("prompt", "选择" + get.translation(card) + "的结算方向").set("choice", choice).set("forceDie", true); + "step 2" + if (result && result.control == "顺时针") { + var evt = event.getParent(), sorter = (_status.currentPhase || player); + evt.fixedSeat = true; + evt.targets.sortBySeat(sorter); + evt.targets.reverse(); + if (evt.targets[evt.targets.length - 1] == sorter) { + evt.targets.unshift(evt.targets.pop()); + } + } + }, + addJudgeCard: function () { + if (lib.filter.judge(card, player, target) && cards.length && get.position(cards[0], true) == "o") target.addJudge(card, cards); + }, + equipCard: function () { + if (cards.length && get.position(cards[0], true) == "o") target.equip(cards[0]); + }, + gameDraw: function () { + "step 0" + if (_status.brawl && _status.brawl.noGameDraw) { + event.finish(); + return; + } + var end = player; + var numx = num; + do { + if (typeof num == "function") { + numx = num(player); + } + if (player.getTopCards) player.directgain(player.getTopCards(numx)); + else player.directgain(get.cards(numx)); + if (player.singleHp === true && get.mode() != "guozhan" && (lib.config.mode != "doudizhu" || _status.mode != "online")) { + player.doubleDraw(); + } + player._start_cards = player.getCards("h"); + player = player.next; + } + while (player != end); + event.changeCard = get.config("change_card"); + if (_status.connectMode || (lib.config.mode == "doudizhu" && _status.mode == "online") || lib.config.mode != "identity" && lib.config.mode != "guozhan" && lib.config.mode != "doudizhu") { + event.changeCard = "disabled"; + } + "step 1" + if (event.changeCard != "disabled" && !_status.auto) { + event.dialog = ui.create.dialog("是否使用手气卡?"); + ui.create.confirm("oc"); + event.custom.replace.confirm = function (bool) { + _status.event.bool = bool; + game.resume(); + } + } + else { + event.finish(); + } + "step 2" + if (event.changeCard == "once") { + event.changeCard = "disabled"; + } + else if (event.changeCard == "twice") { + event.changeCard = "once"; + } + else if (event.changeCard == "disabled") { + event.bool = false; + return; + } + _status.imchoosing = true; + event.switchToAuto = function () { + _status.event.bool = false; + game.resume(); + } + game.pause(); + "step 3" + _status.imchoosing = false; + if (event.bool) { + if (game.changeCoin) { + game.changeCoin(-3); + } + var hs = game.me.getCards("h"); + game.addVideo("lose", game.me, [get.cardsInfo(hs), [], [], []]); + for (var i = 0; i < hs.length; i++) { + hs[i].discard(false); + } + game.me.directgain(get.cards(hs.length)); + event.goto(2); + } + else { + if (event.dialog) event.dialog.close(); + if (ui.confirm) ui.confirm.close(); + game.me._start_cards = game.me.getCards("h"); + event.finish(); + } + }, + phaseLoop: function () { + "step 0" + var num = 1, current = player; + while (current.getSeatNum() == 0) { + current.setSeatNum(num); + current = current.next; + num++; + } + "step 1" + for (var i = 0; i < lib.onphase.length; i++) { + lib.onphase[i](); + } + player.phase(); + "step 2" + if (!game.players.contains(event.player.next)) { + event.player = game.findNext(event.player.next); + } + else { + event.player = event.player.next; + } + event.goto(1); + }, + loadPackage: function () { + "step 0" + if (event.packages.length) { + window.game = game; + var pack = event.packages.shift().split("/"); + lib.init.js(lib.assetURL + pack[0], pack[1], game.resume); + game.pause(); + } + else { + event.finish(); + } + "step 1" + if (!lib.config.dev) delete window.game; + var character = lib.imported.character; + var card = lib.imported.card; + var i, j, k; + for (i in character) { + if (character[i].character) { + var characterPack = lib.characterPack[i]; + if (characterPack) Object.assign(characterPack, character[i].character); + else lib.characterPack[i] = character[i].character; + } + if (character[i].forbid && character[i].forbid.contains(lib.config.mode)) continue; + if (character[i].mode && character[i].mode.contains(lib.config.mode) == false) continue; + + if (Array.isArray(lib[j]) && Array.isArray(character[i][j])) { + lib[j].addArray(character[i][j]); + continue; + } + for (j in character[i]) { + if (j == "mode" || j == "forbid" || j == "characterSort") continue; + for (k in character[i][j]) { + if (j == "character") { + if (!character[i][j][k][4]) { + character[i][j][k][4] = []; + } + if (character[i][j][k][4].contains("boss") || + character[i][j][k][4].contains("hiddenboss")) { + lib.config.forbidai.add(k); + } + if (lib.config.forbidai_user && lib.config.forbidai_user.contains(k)) { + lib.config.forbidai.add(k); + } + for (var l = 0; l < character[i][j][k][3].length; l++) { + lib.skilllist.add(character[i][j][k][3][l]); + } + } + if (j == "translate" && k == i) { + lib[j][k + "_character_config"] = character[i][j][k]; + } + else { + if (lib[j][k] == undefined) { + Object.defineProperty(lib[j], k, Object.getOwnPropertyDescriptor(character[i][j], k)); + } + else if (Array.isArray(lib[j][k]) && Array.isArray(character[i][j][k])) { + lib[j][k].addArray(character[i][j][k]); + } + else { + console.log( + `dublicate ${j} in character ${i}:\n${k}:\nlib.${j}.${k}`, + lib[j][k], + `\ncharacter.${i}.${j}.${k}`, + character[i][j][k] + ); + } + } + } + } + } + for (i in card) { + var cardPack = lib.cardPack[i] ? lib.cardPack[i] : lib.cardPack[i] = []; + if (card[i].card) { + for (var j in card[i].card) { + if (!card[i].card[j].hidden && card[i].translate[j + "_info"]) { + cardPack.push(j); + } + } + } + for (j in card[i]) { + if (j == "mode" || j == "forbid") continue; + if (j == "list") continue; + for (k in card[i][j]) { + if (j == "skill" && k[0] == "_" && !lib.config.cards.contains(i)) { + continue; + } + if (j == "translate" && k == i) { + lib[j][k + "_card_config"] = card[i][j][k]; + } + else { + if (lib[j][k] == undefined) Object.defineProperty(lib[j], k, Object.getOwnPropertyDescriptor(card[i][j], k)); + else { + console.log( + `dublicate ${j} in card ${i}:\n${k}\nlib.${j}.${k}`, + lib[j][k], + `\ncard.${i}.${j}.${k}`, + card[i][j][k] + ); + } + } + } + } + } + event.goto(0); + }, + loadMode: function () { + "step 0" + window.game = game; + lib.init.js(lib.assetURL + "mode", event.mode, game.resume); + game.pause(); + "step 1" + if (!lib.config.dev) delete window.game; + event.result = lib.imported.mode[event.mode]; + delete lib.imported.mode[event.mode]; + }, + forceOver: function () { + "step 0" + while (ui.controls.length) { + ui.controls[0].close(); + } + while (ui.dialogs.length) { + ui.dialogs[0].close(); + } + "step 1" + if (event.bool != "noover") { + game.over(event.bool); + } + if (event.callback) { + event.callback(); + } + }, + arrangeTrigger: function () { + "step 0" + event.noDirectUse = info => !lib.skill[info.skill].silent && lib.translate[info.skill];//是否触发同顺序选择 + "step 1" + if (event.doing && event.doing.todoList.length) return; + if (event.doingList.length) return event.doing = event.doingList.shift(); + event.finish(); + "step 2" + if (trigger.filterStop && trigger.filterStop()) return event.finish(); + const current = event.doing.todoList.find(info => lib.filter.filterTrigger(trigger, info.player, event.triggername, info.skill)); + if (!current) { + event.doing.todoList = []; + return event.goto(1); + } + event.doing.todoList = event.doing.todoList.filter(i => i.priority <= current.priority); + event.num = event.doing.todoList.indexOf(current); + if (!event.noDirectUse(current)) return event.goto(5); + event.choice = event.doing.todoList.filter(info => { + if (!lib.filter.filterTrigger(trigger, info.player, event.triggername, info.skill)) return false; + if (!event.noDirectUse(info)) return false; + if (current.skill != info.skill) return false; + if (current.player != info.player) return false; + return lib.skill.global.includes(info.skill) || current.player.hasSkill(info.skill, true); + }); + if (event.choice.length < 2) event.goto(5); + "step 3" + const next = event.choice[0].player.chooseControl(event.choice.map(i => i.skill)); + next.set("prompt", "选择下一个触发的技能"); + next.set("forceDie", true); + next.set("arrangeSkill", true); + next.set("includeOut", true); + "step 4" + if (result.control) event.num = event.doing.todoList.findIndex(info => info.skill == result.control && info.player == event.choice[0].player); + "step 5" + const info = event.doing.todoList[event.num]; + if (!info) return; + event.doing.doneList.push(info); + event.doing.todoList.splice(event.num, 1); + game.createTrigger(event.triggername, info.skill, info.player, trigger); + event.goto(1); + }, + createTrigger: function () { + "step 0" + // console.log("triggering: " + player.name+ " \"s skill: " + event.skill+" in " + event.triggername) + if (game.expandSkills(player.getSkills().concat(lib.skill.global)).includes(event.skill)) return; + var info = get.info(event.skill); + let hidden = player.hiddenSkills.slice(0); + let invisible = player.invisibleSkills.slice(0); + game.expandSkills(hidden); + game.expandSkills(invisible); + if (hidden.includes(event.skill)) { + if (!info.silent && player.hasSkillTag("nomingzhi", false, null, true)) event.finish(); + else if (!info.direct) event.trigger("triggerHidden"); + else event.skillHidden = true; + } + else if (invisible.includes(event.skill)) event.trigger("triggerInvisible"); + else if (Object.keys(player.additionalSkills).every(i => { + if (i.startsWith("hidden:")) return true; + return !game.expandSkills(player.additionalSkills[i]).includes(event.skill); + })) event.finish(); + "step 1" + if (event.cancelled) return event.finish(); + var info = get.info(event.skill); + if (event.revealed || info.forced) return; + const checkFrequent = function (info) { + if (player.hasSkillTag("nofrequent", false, event.skill)) return false; + if (typeof info.frequent == "boolean") return info.frequent; + if (typeof info.frequent == "function") return info.frequent(trigger, player); + if (info.frequent == "check" && typeof info.check == "function") return info.check(trigger, player); + return false; + } + if (info.direct) { + if (player.isUnderControl()) game.swapPlayerAuto(player); + if (player.isOnline()) void 0; + event._result = { bool: true }; + event._direct = true; + } + else { + if (checkFrequent(info)) event.frequentSkill = true; + var str; + var check = info.check; + if (info.prompt) str = info.prompt; + else if (typeof info.logTarget == "string") str = get.prompt(event.skill, trigger[info.logTarget], player); + else if (typeof info.logTarget == "function") { + const logTarget = info.logTarget(trigger, player); + if (get.itemtype(logTarget).startsWith("player")) str = get.prompt(event.skill, logTarget, player); + } + else str = get.prompt(event.skill, null, player); + if (typeof str == "function") str = str(trigger, player); + + var next = player.chooseBool(str); + if (event.frequentSkill) next.set("frequentSkill", event.skill); + next.set("forceDie", true); + next.set("includeOut", true); + next.ai = () => !check || check(trigger, player); + + if (typeof info.prompt2 == "function") next.set("prompt2", info.prompt2(trigger, player)); + else if (typeof info.prompt2 == "string") next.set("prompt2", info.prompt2); + else if (info.prompt2 != false) { + if (lib.dynamicTranslate[event.skill]) next.set("prompt2", lib.dynamicTranslate[event.skill](player, event.skill)); + else if (lib.translate[event.skill + "_info"]) next.set("prompt2", lib.translate[event.skill + "_info"]); + } + + if (trigger.skillwarn) { + if (next.prompt2) next.set("prompt2", `${trigger.skillwarn}。${next.prompt2}`); + else next.set("prompt2", trigger.skillwarn); + } + } + "step 2" + var info = get.info(event.skill); + if (!result || !result.bool) return; + var autodelay = info.autodelay; + if (typeof autodelay == "function") autodelay = autodelay(trigger, player); + if (autodelay && (info.forced || !event.isMine())) { + if (typeof autodelay == "number") game.delayx(autodelay); + else game.delayx(); + } + "step 3" + var info = get.info(event.skill); + if (result && result.bool == false) { + if (info.oncancel) info.oncancel(trigger, player); + return event.finish(); + } + if (info.popup != false && !info.direct) { + if (info.popup) { + player.popup(info.popup); + game.log(player, "发动了", "【" + get.skillTranslation(event.skill, player) + "】"); + } + else if (!info.logTarget || info.logLine === false) player.logSkill(event.skill, false, info.line); + else if (typeof info.logTarget == "string") player.logSkill(event.skill, trigger[info.logTarget], info.line); + else if (typeof info.logTarget == "function") player.logSkill(event.skill, info.logTarget(trigger, player), info.line); + } + var next = game.createEvent(event.skill); + if (typeof info.usable == "number") { + player.addSkill("counttrigger"); + if (!player.storage.counttrigger) player.storage.counttrigger = {}; + if (!player.storage.counttrigger[event.skill]) player.storage.counttrigger[event.skill] = 1; + else player.storage.counttrigger[event.skill]++; + } + next.player = player; + next._trigger = trigger; + next.triggername = event.triggername; + next.setContent(info.content); + next.skillHidden = event.skillHidden; + if (info.forceDie) next.forceDie = true; + if (info.forceOut) next.includeOut = true; + "step 4" + if (!player._hookTrigger) return; + if (player._hookTrigger.some(i => { + const info = lib.skill[i].hookTrigger; + return info && info.after && info.after(event, player, event.triggername); + })) event.trigger("triggerAfter"); + }, + playVideoContent: function () { + "step 0" + game.delay(0, 500); + "step 1" + if (!game.chess) { + ui.control.innerHTML = ""; + var nodes = []; + for (var i = 0; i < ui.arena.childNodes.length; i++) { + nodes.push(ui.arena.childNodes[i]); + } + for (var i = 0; i < nodes.length; i++) { + if (nodes[i] == ui.canvas) continue; + if (nodes[i] == ui.control) continue; + if (nodes[i] == ui.mebg) continue; + if (nodes[i] == ui.me) continue; + if (nodes[i] == ui.roundmenu) continue; + nodes[i].remove(); + } + ui.sidebar.innerHTML = ""; + ui.cardPile.innerHTML = ""; + ui.discardPile.innerHTML = ""; + ui.special.innerHTML = ""; + ui.ordering.innerHTML = ""; + } + ui.system.firstChild.innerHTML = ""; + ui.system.lastChild.innerHTML = ""; + ui.system.firstChild.appendChild(ui.config2); + if (ui.updateVideoMenu) { + ui.updateVideoMenu(); + } + _status.videoDuration = 1; + ui.create.system("返回", function () { + var mode = localStorage.getItem(lib.configprefix + "playbackmode"); + if (mode) { + game.saveConfig("mode", mode); + } + game.reload(); + }); + ui.create.system("重播", function () { + _status.replayvideo = true; + game.playVideo(_status.playback, lib.config.mode); + }); + ui.create.system("暂停", ui.click.pause, true).id = "pausebutton"; + var slow = ui.create.system("减速", function () { + _status.videoDuration *= 1.5; + updateDuration(); + }, true); + var fast = ui.create.system("加速", function () { + _status.videoDuration /= 1.5; + updateDuration(); + }, true); + var updateDuration = function () { + if (_status.videoDuration > 1) { + slow.classList.add("glow"); + } + else { + slow.classList.remove("glow"); + } + if (_status.videoDuration < 1) { + fast.classList.add("glow"); + } + else { + fast.classList.remove("glow"); + } + } + ui.system.style.display = ""; + ui.refresh(ui.system); + ui.system.show(); + ui.window.show(); + if (lib.config.mode != "versus" && lib.config.mode != "boss") { + ui.arena.style.display = ""; + ui.refresh(ui.arena); + ui.arena.show(); + } + if (!game.chess) { + game.playerMap = {}; + } + game.finishCards(); + "step 2" + if (event.video.length) { + var content = event.video.shift(); + // console.log(content); + if (content.type == "delay") { + game.delay(content.content); + } + else if (content.type == "play") { + window.play = {}; + if (!event.playtoload) { + event.playtoload = 1; + } + else { + event.playtoload++; + } + var script = lib.init.js(lib.assetURL + "play", content.name); + script.addEventListener("load", function () { + var play = window.play[content.name] + if (play && play.video) { + play.video(content.init); + } + event.playtoload--; + if (event.playtoload == 0) { + delete window.play; + } + }); + } + else if (typeof content.player == "string" && game.playerMap[content.player] && + game.playerMap[content.player].classList && + !game.playerMap[content.player].classList.contains("obstacle")) { + game.videoContent[content.type](game.playerMap[content.player], content.content); + } + else { + game.videoContent[content.type](content.content); + } + if (event.video.length) { + game.delay(0, _status.videoDuration * Math.min(2000, event.video[0].delay)); + } + event.redo(); + } + else { + _status.over = true; + ui.system.lastChild.hide(); + setTimeout(function () { + ui.system.lastChild.innerHTML = ""; + }, 500); + } + }, + waitForPlayer: function () { + "step 0" + ui.auto.hide(); + ui.pause.hide(); + + game.createServer(); + if (!lib.translate.zhu) { + lib.translate.zhu = "主"; + } + if (event.func) { + event.func(); + } + if (!lib.configOL.number) { + lib.configOL.number = parseInt(lib.configOL.player_number); + } + if (game.onlineroom) { + game.send("server", "config", lib.configOL); + } + + ui.create.connectPlayers(game.ip); + if (!window.isNonameServer) { + var me = game.connectPlayers[0]; + me.setIdentity("zhu"); + me.initOL(get.connectNickname(), lib.config.connect_avatar); + me.playerid = "1"; + game.onlinezhu = "1"; + } + _status.waitingForPlayer = true; + if (window.isNonameServer) { + document.querySelector("#server_status").innerHTML = "等待中"; + } + game.pause(); + "step 1" + _status.waitingForPlayer = false; + lib.configOL.gameStarted = true; + if (window.isNonameServer) { + document.querySelector("#server_status").innerHTML = "游戏中"; + } + if (game.onlineroom) { + game.send("server", "config", lib.configOL); + } + for (var i = 0; i < game.connectPlayers.length; i++) { + game.connectPlayers[i].delete(); + } + delete game.connectPlayers; + if (ui.roomInfo) { + ui.roomInfo.remove(); + delete ui.roomInfo; + } + if (ui.exitroom) { + ui.exitroom.remove(); + delete ui.exitroom; + } + game.broadcast("gameStart"); + game.delay(2); + ui.auto.show(); + ui.pause.show(); + if (lib.config.show_cardpile) { + ui.cardPileButton.style.display = ""; + } + }, + replaceHandcards: function () { + "step 0" + if (event.players.contains(game.me)) { + game.me.chooseBool("是否置换手牌?"); + } + else { + event.finish(); + } + "step 1" + if (result && result.bool) { + var hs = game.me.getCards("h") + for (var i = 0; i < hs.length; i++) { + hs[i].discard(false); + } + var cards = get.cards(hs.length); + game.me._start_cards = cards; + game.me.directgain(cards); + } + }, + replaceHandcardsOL: function () { + "step 0" + var send = function () { + game.me.chooseBool("是否置换手牌?"); + game.resume(); + }; + var sendback = function (result, player) { + if (result && result.bool) { + var hs = player.getCards("h") + game.broadcastAll(function (player, hs) { + game.addVideo("lose", player, [get.cardsInfo(hs), [], [], []]); + for (var i = 0; i < hs.length; i++) { + hs[i].discard(false); + } + }, player, hs); + var cards = get.cards(hs.length); + player.directgain(cards); + player._start_cards = cards; + } + }; + for (var i = 0; i < event.players.length; i++) { + if (event.players[i].isOnline()) { + event.withol = true; + event.players[i].send(send); + event.players[i].wait(sendback); + } + else if (event.players[i] == game.me) { + event.withme = true; + game.me.chooseBool("是否置换手牌?"); + game.me.wait(sendback); + } + } + "step 1" + if (event.withme) { + game.me.unwait(result); + } + "step 2" + if (event.withol && !event.resultOL) { + game.pause(); + } + }, + phase: function () { + "step 0" + //初始化阶段列表 + if (!event.phaseList) { + event.phaseList = ["phaseZhunbei", "phaseJudge", "phaseDraw", "phaseUse", "phaseDiscard", "phaseJieshu"]; + } + if (typeof event.num != "number") { + event.num = 0; + } + //规则集中的“回合开始后①”,更新游戏轮数,触发“一轮游戏开始时” + var isRound = false; + if (!event.skill) { + isRound = _status.roundSkipped; + if (_status.isRoundFilter) { + isRound = _status.isRoundFilter(event, player); + } + else if (_status.seatNumSettled) { + var seatNum = player.getSeatNum(); + if (seatNum != 0) { + if (get.itemtype(_status.lastPhasedPlayer) != "player" || seatNum < _status.lastPhasedPlayer.getSeatNum()) isRound = true; + _status.lastPhasedPlayer = player; + } + } + else if (player == _status.roundStart) isRound = true; + if (isRound) { + delete _status.roundSkipped; + game.roundNumber++; + event._roundStart = true; + game.updateRoundNumber(); + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isOut() && game.players[i].outCount > 0) { + game.players[i].outCount--; + if (game.players[i].outCount == 0 && !game.players[i].outSkills) { + game.players[i].in(); + } + } + } + event.trigger("roundStart"); + } + } + _status.globalHistory.push({ + cardMove: [], + custom: [], + useCard: [], + changeHp: [], + everything: [], + }); + var players = game.players.slice(0).concat(game.dead); + for (var i = 0; i < players.length; i++) { + var current = players[i]; + current.actionHistory.push({ useCard: [], respond: [], skipped: [], lose: [], gain: [], sourceDamage: [], damage: [], custom: [], useSkill: [] }); + current.stat.push({ card: {}, skill: {} }); + if (isRound) { + current.getHistory().isRound = true; + current.getStat().isRound = true; + } + } + if (isRound) { + game.getGlobalHistory().isRound = true; + } + "step 1" + //规则集中的“回合开始后②(1v1武将登场专用)” + event.trigger("phaseBeforeStart"); + "step 2" + //规则集中的“回合开始后③(处理“游戏开始时”的时机)” + event.trigger("phaseBefore"); + "step 3" + //规则集中的“回合开始后④(卑弥呼〖纵傀〗的时机)” + event.trigger("phaseBeforeEnd"); + "step 4" + //规则集中的“回合开始后⑤”,进行翻面检测 + if (player.isTurnedOver() && !event._noTurnOver) { + event.cancel(); + player.turnOver(); + player.phaseSkipped = true; + } + else { + player.phaseSkipped = false; + player.getHistory().isMe = true; + player.getStat().isMe = true; + } + "step 5" + //规则集中的“回合开始后⑥”,更新“当前回合角色” + while (ui.dialogs.length) { + ui.dialogs[0].close(); + } + game.phaseNumber++; + player.phaseNumber++; + game.broadcastAll(function (player, num, popup) { + if (lib.config.glow_phase) { + player.classList.add("glow_phase"); + } + player.phaseNumber = num; + _status.currentPhase = player; + if (popup && lib.config.show_phase_prompt) player.popup("回合开始", null, false); + }, player, player.phaseNumber, !player.noPhaseDelay); + _status.currentPhase = player; + _status.discarded = []; + game.syncState(); + game.addVideo("phaseChange", player); + if (game.phaseNumber == 1) { + delete player._start_cards; + if (lib.configOL.observe) { + lib.configOL.observeReady = true; + game.send("server", "config", lib.configOL); + } + } + game.log(); + game.log(player, "的回合开始"); + player._noVibrate = true; + if (get.config("identity_mode") != "zhong" && get.config("identity_mode") != "purple" && !_status.connectMode) { + var num; + switch (get.config("auto_identity")) { + case "one": num = 1; break; + case "two": num = 2; break; + case "three": num = 3; break; + case "always": num = -1; break; + default: num = 0; break; + } + if (num && !_status.identityShown && game.phaseNumber > game.players.length * num && game.showIdentity) { + if (!_status.video) player.popup("显示身份"); + _status.identityShown = true; + game.showIdentity(false); + } + } + player.ai.tempIgnore = []; + if (ui.land && ui.land.player == player) { + game.addVideo("destroyLand"); + ui.land.destroy(); + } + "step 6" + //规则集中的“回合开始后⑦”,国战武将明置武将牌 + event.trigger("phaseBeginStart"); + "step 7" + //规则集中的“回合开始后⑨”,进行当先,化身等操作 + //没有⑧ 因为⑧用不到 + event.trigger("phaseBegin"); + //阶段部分 + "step 8" + if (num < event.phaseList.length) { + //规则集中没有的新时机 可以用来插入额外阶段啥的 + if (player.isIn()) event.trigger("phaseChange") + } + else event.goto(11); + "step 9" + if (player.isIn() && num < event.phaseList.length) { + var phase = event.phaseList[num].split("|"); + event.currentPhase = phase[0]; + var next = player[event.currentPhase](); + next.phaseIndex = num; + if (phase.length > 1) { + next._extraPhaseReason = phase[1]; + } + if (event.currentPhase == "phaseDraw" || event.currentPhase == "phaseDiscard") { + if (!player.noPhaseDelay) { + if (player == game.me) { + game.delay(); + } + else { + game.delayx(); + } + } + } + } + "step 10" + if (event.currentPhase == "phaseUse") { + game.broadcastAll(function () { + if (ui.tempnowuxie) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + }); + delete player._noSkill; + } + event.num++; + "step 11" + if (event.num < event.phaseList.length) { + event.goto(8); + } + else if (!event._phaseEndTriggered) { + event._phaseEndTriggered = true; + event.trigger("phaseEnd"); + event.redo(); + } + "step 12" + event.trigger("phaseAfter"); + "step 13" + //删除当前回合角色 此时处于“不属于任何角色的回合”的阶段 + game.broadcastAll(function (player) { + player.classList.remove("glow_phase"); + delete _status.currentPhase; + }, player); + }, + /** + * @deprecated + */ + phase_old: function () { + "step 0" + player.phaseZhunbei(); + "step 1" + player.phaseJudge(); + "step 2" + player.phaseDraw(); + if (!player.noPhaseDelay) { + if (player == game.me) { + game.delay(); + } + else { + game.delayx(); + } + } + "step 3" + player.phaseUse(); + "step 4" + game.broadcastAll(function () { + if (ui.tempnowuxie) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + }); + player.phaseDiscard() + if (!player.noPhaseDelay) game.delayx(); + //delete player.using; + delete player._noSkill; + "step 5" + player.phaseJieshu(); + }, + phaseZhunbei: function () { + event.trigger(event.name); + game.log(player, "进入了准备阶段"); + }, + phaseJudge: function () { + "step 0" + game.log(player, "进入了判定阶段"); + event.cards = player.getCards("j"); + if (!event.cards.length) event.finish(); + "step 1" + if (cards.length && player.getCards("j").contains(cards[0])) { + event.card = cards.shift(); + if (event.card.classList.contains("removing")) { + event.card.remove(); + delete event.card; + event.redo(); + } + else if (event.card.classList.contains("feichu")) { + event.finish(); + return; + } + else { + player.lose(event.card, "visible", ui.ordering); + player.$phaseJudge(event.card); + event.cancelled = false; + event.trigger("phaseJudge"); + var name = event.card.viewAs || event.card.name; + player.popup(name, "thunder"); + if (!lib.card[name].effect) { + game.delay(); + event.redo(); + } + else if (!lib.card[name].judge) { + game.delay(); + event.nojudge = true; + } + } + } + else event.finish(); + "step 2" + if (!event.cancelled && !event.nojudge) player.judge(event.card).set("type", "phase"); + "step 3" + var name = event.card.viewAs || event.card.name; + if (event.excluded) { + delete event.excluded; + } + else if (event.cancelled && !event.direct) { + if (lib.card[name].cancel) { + var next = game.createEvent(name + "Cancel"); + next.setContent(lib.card[name].cancel); + next.cards = [event.card]; + if (!event.card.viewAs) next.card = get.autoViewAs(event.card); + else next.card = get.autoViewAs({ name: name }, next.cards); + next.player = player; + } + } + else { + var next = game.createEvent(name); + next.setContent(lib.card[name].effect); + next._result = result; + next.cards = [event.card]; + if (!event.card.viewAs) next.card = get.autoViewAs(event.card); + else next.card = get.autoViewAs({ name: name }, next.cards); + next.player = player; + } + ui.clear(); + event.goto(1); + }, + phaseDraw: function () { + "step 0" + game.log(player, "进入了摸牌阶段"); + event.trigger("phaseDrawBegin1"); + "step 1" + event.trigger("phaseDrawBegin2"); + "step 2" + if (game.modPhaseDraw) { + game.modPhaseDraw(player, event.num); + } + else { + if (event.num > 0) { + var num = event.num; + if (event.attachDraw) { + for (var i = 0; i < event.attachDraw.length; i++) { + ui.cardPile.insertBefore(event.attachDraw[i], ui.cardPile.firstChild); + } + num += event.attachDraw.length; + } + var next = player.draw(num); + if (event.attachDraw) { + next.minnum = event.attachDraw.length; + } + } + } + "step 3" + if (Array.isArray(result)) { + event.cards = result; + } + }, + phaseUse: function () { + "step 0" + if (!event.logged) { + game.log(player, "进入了出牌阶段"); + event.logged = true; + } + var next = player.chooseToUse(); + if (!lib.config.show_phaseuse_prompt) { + next.set("prompt", false); + } + next.set("type", "phase"); + "step 1" + if (result.bool && !event.skipped) { + event.goto(0); + } + game.broadcastAll(function () { + if (ui.tempnowuxie) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + }); + "step 2" + var stat = player.getStat(); + for (var i in stat.skill) { + var bool = false; + var info = lib.skill[i]; + if (!info) continue; + if (info.enable != undefined) { + if (typeof info.enable == "string" && info.enable == "phaseUse") bool = true; + else if (typeof info.enable == "object" && info.enable.contains("phaseUse")) bool = true; + } + if (bool) stat.skill[i] = 0; + } + for (var i in stat.card) { + var bool = false; + var info = lib.card[i]; + if (!info) continue; + if (info.updateUsable == "phaseUse") stat.card[i] = 0; + } + }, + phaseDiscard: function () { + "step 0" + game.log(player, "进入了弃牌阶段"); + event.num = player.needsToDiscard(); + if (event.num <= 0) event.finish(); + else { + game.broadcastAll(function (player) { + if (lib.config.show_phase_prompt) { + player.popup("弃牌阶段", null, false); + } + }, player); + } + event.trigger("phaseDiscard"); + "step 1" + player.chooseToDiscard(num, true) + .set("useCache", true); + "step 2" + event.cards = result.cards; + }, + phaseJieshu: function () { + event.trigger(event.name); + game.log(player, "进入了结束阶段"); + }, + chooseToUse: function () { + "step 0" + if (event.responded) return; + if (game.modeSwapPlayer && !_status.auto && player.isUnderControl() && !lib.filter.wuxieSwap(event)) { + game.modeSwapPlayer(player); + } + var skills = player.getSkills("invisible").concat(lib.skill.global); + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var info = lib.skill[skills[i]]; + if (info && info.onChooseToUse) { + info.onChooseToUse(event); + } + } + if (_status.noclearcountdown !== "direct") _status.noclearcountdown = true; + if (event.type == "phase") { + if (event.isMine()) { + event.endButton = ui.create.control("结束回合", "stayleft", function () { + var evt = _status.event; + if (evt.name != "chooseToUse" || evt.type != "phase") return; + if (evt.skill) { + ui.click.cancel(); + } + ui.click.cancel(); + }); + event.fakeforce = true; + } + else { + if (event.endButton) { + event.endButton.close(); + delete event.endButton; + } + event.fakeforce = false; + } + } + if (event.player.isUnderControl() && !_status.auto) { + event.result = { + bool: false + } + return; + } + else if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + if (event.type == "wuxie") { + if (ui.tempnowuxie) { + var triggerevent = event.getTrigger(); + if (triggerevent && triggerevent.targets && triggerevent.num == triggerevent.targets.length - 1) { + ui.tempnowuxie.close(); + } + } + if (lib.filter.wuxieSwap(event)) { + event.result = { + bool: false + } + return; + } + } + var ok = game.check(); + if (!ok || !lib.config.auto_confirm) { + game.pause(); + if (lib.config.enable_vibrate && player._noVibrate) { + delete player._noVibrate; + game.vibrate(); + } + if (typeof event.prompt == "string") { + if (event.openskilldialog) { + event.skillDialog = ui.create.dialog(event.openskilldialog); + delete event.openskilldialog; + event.dialog = event.prompt; + } + else { + event.dialog = ui.create.dialog(event.prompt); + if (event.prompt2) { + event.dialog.addText(event.prompt2); + } + } + } + else if (typeof event.prompt == "function") { + event.dialog = ui.create.dialog(event.prompt(event)); + } + else if (event.prompt == undefined) { + var str; + if (typeof event.filterCard == "object") { + var filter = event.filterCard; + str = "请使用" + get.cnNumber(event.selectCard[0]) + "张" + if (filter.name) { + str += get.translation(filter.name); + } + else { + str += "牌"; + } + } + else { + str = "请选择要使用的牌"; + } + if (event.openskilldialog) { + event.skillDialog = ui.create.dialog(event.openskilldialog); + delete event.openskilldialog; + event.dialog = str; + } + else if (typeof event.skillDialog != "string") { + event.dialog = ui.create.dialog(str); + } + else { + event.dialog = str; + } + } + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.result == "ai") { + var ok = game.check(); + if (ok) { + ui.click.ok(); + } + else if (ai.basic.chooseCard(event.ai1) || forced) { + if ((ai.basic.chooseTarget(event.ai2) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + event._aiexcludeclear = true; + } + else { + if (!event.norestore) { + if (event.skill) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + var info = get.info(skill); + if (info.sourceSkill) { + event._aiexclude.add(info.sourceSkill); + } + } + else { + get.card(true).aiexclude(); + game.uncheck(); + } + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + } + } + else if (event.skill && !event.norestore) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + var info = get.info(skill); + if (info.sourceSkill) { + event._aiexclude.add(info.sourceSkill); + } + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + if (event.aidelay && event.result && event.result.bool) { + game.delayx(); + } + } + "step 2" + if (event.endButton) { + event.endButton.close(); + delete event.endButton; + } + event.resume(); + if (event.result) { + if (event.result._sendskill) { + lib.skill[event.result._sendskill[0]] = event.result._sendskill[1]; + } + if (event.result.skill) { + var info = get.info(event.result.skill); + if (info && info.chooseButton) { + if (event.dialog && typeof event.dialog == "object") event.dialog.close(); + var dialog = info.chooseButton.dialog(event, player); + if (info.chooseButton.chooseControl) { + var next = player.chooseControl(info.chooseButton.chooseControl(event, player)); + if (dialog.direct) next.direct = true; + if (dialog.forceDirect) next.forceDirect = true; + next.dialog = dialog; + next.set("ai", info.chooseButton.check || function () { return 0; }); + if (event.id) next._parent_id = event.id; + next.type = "chooseToUse_button"; + } + else { + var next = player.chooseButton(dialog); + if (dialog.direct) next.direct = true; + if (dialog.forceDirect) next.forceDirect = true; + next.set("ai", info.chooseButton.check || function () { return 1; }); + next.set("filterButton", info.chooseButton.filter || function () { return true; }); + next.set("selectButton", info.chooseButton.select || 1); + next.set("filterOk", info.chooseButton.filterOk || (() => true)); + if (event.id) next._parent_id = event.id; + next.type = "chooseToUse_button"; + } + event.buttoned = event.result.skill; + } + else if (info && info.precontent && !game.online && !event.nouse) { + var next = game.createEvent("pre_" + event.result.skill); + next.setContent(info.precontent); + next.set("result", event.result); + next.set("player", player); + } + } + } + "step 3" + if (event.buttoned) { + if (result.bool || result.control && result.control != "cancel2") { + var info = get.info(event.buttoned).chooseButton; + lib.skill[event.buttoned + "_backup"] = info.backup(info.chooseControl ? result : result.links, player); + lib.skill[event.buttoned + "_backup"].sourceSkill = event.buttoned; + if (game.online) { + event._sendskill = [event.buttoned + "_backup", lib.skill[event.buttoned + "_backup"]]; + } + else { + game.broadcast((skill, audio) => { + if (!lib.skill[skill]) lib.skill[skill] = {}; + lib.skill[skill].audio = audio; + }, event.buttoned + "_backup", lib.skill[event.buttoned + "_backup"].audio); + } + event.backup(event.buttoned + "_backup"); + if (info.prompt) { + event.openskilldialog = info.prompt(info.chooseControl ? result : result.links, player); + } + } + else { + ui.control.animate("nozoom", 100); + event._aiexclude.add(event.buttoned); + } + event.goto(0); + delete event.buttoned; + } + "step 4" + if (event._aiexcludeclear) { + delete event._aiexcludeclear; + event._aiexclude.length = 0; + } + delete _status.noclearcountdown; + if (event.skillDialog && get.objtype(event.skillDialog) == "div") { + event.skillDialog.close(); + } + if (event.result && event.result.bool && !game.online && !event.nouse) { + player.useResult(event.result, event); + } + else if (event._sendskill) { + event.result._sendskill = event._sendskill; + } + if ((!event.result || !event.result.bool || event.result._noHidingTimer) && (event.result.skill || event.logSkill)) { + var info = get.info(event.result.skill || event.logSkill); + if (info.direct && !info.clearTime) { + _status.noclearcountdown = "direct"; + } + } + if (event.dialog && typeof event.dialog == "object") event.dialog.close(); + if (!_status.noclearcountdown) { + game.stopCountChoose(); + } + "step 5" + if (event._result && event.result) { + event.result.result = event._result; + } + }, + chooseToRespond: function () { + "step 0" + if (event.responded) { + delete event.dialog; + return; + } + var skills = player.getSkills("invisible").concat(lib.skill.global); + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var info = lib.skill[skills[i]]; + if (info && info.onChooseToRespond) { + info.onChooseToRespond(event); + } + } + if (_status.noclearcountdown !== "direct") _status.noclearcountdown = true; + if (!_status.connectMode && lib.config.skip_shan && event.autochoose && event.autochoose()) { + event.result = { bool: false }; + } + else { + if (game.modeSwapPlayer && !_status.auto && player.isUnderControl()) { + game.modeSwapPlayer(player); + } + if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + var ok = game.check(); + if (!ok || !lib.config.auto_confirm) { + game.pause(); + if (event.openskilldialog) { + event.skillDialog = ui.create.dialog(event.openskilldialog); + delete event.openskilldialog; + event.dialog = event.prompt; + } + else { + if (event.prompt) event.dialog = ui.create.dialog(event.prompt); + if (event.prompt2) event.dialog.addText(event.prompt2); + } + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + var ok = game.check(); + if (ok) { + ui.click.ok(); + } + else if (ai.basic.chooseCard(event.ai1 || event.ai) || forced) { + if ((ai.basic.chooseTarget(event.ai2) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + event._aiexcludeclear = true; + } + else { + if (!event.norestore) { + if (event.skill) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + var info = get.info(skill); + if (info.sourceSkill) { + event._aiexclude.add(info.sourceSkill); + } + } + else { + get.card(true).aiexclude(); + game.uncheck(); + } + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + } + } + else if (event.skill && !event.norestore) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + var info = get.info(skill); + if (info.sourceSkill) { + event._aiexclude.add(info.sourceSkill); + } + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + if (event.aidelay && event.result && event.result.bool) { + game.delayx(); + } + } + "step 2" + event.resume(); + if (event.result) { + if (event.result._sendskill) { + lib.skill[event.result._sendskill[0]] = event.result._sendskill[1]; + } + if (event.result.skill) { + var info = get.info(event.result.skill); + if (info && info.chooseButton) { + if (event.dialog && typeof event.dialog == "object") event.dialog.close(); + var dialog = info.chooseButton.dialog(event, player); + if (info.chooseButton.chooseControl) { + var next = player.chooseControl(info.chooseButton.chooseControl(event, player)); + if (dialog.direct) next.direct = true; + if (dialog.forceDirect) next.forceDirect = true; + next.dialog = dialog; + next.set("ai", info.chooseButton.check || function () { return 0; }); + } + else { + var next = player.chooseButton(dialog); + if (dialog.direct) next.direct = true; + if (dialog.forceDirect) next.forceDirect = true; + next.set("ai", info.chooseButton.check || function () { return 1; }); + next.set("filterButton", info.chooseButton.filter || function () { return true; }); + next.set("selectButton", info.chooseButton.select || 1); + next.set("filterOk", info.chooseButton.filterOk || (() => true)); + } + event.buttoned = event.result.skill; + } + else if (info && info.precontent && !game.online) { + var next = game.createEvent("pre_" + event.result.skill); + next.setContent(info.precontent); + next.set("result", event.result); + next.set("player", player); + } + } + } + "step 3" + if (event.buttoned) { + if (result.bool || result.control && result.control != "cancel2") { + var info = get.info(event.buttoned).chooseButton; + lib.skill[event.buttoned + "_backup"] = info.backup(info.chooseControl ? result : result.links, player); + lib.skill[event.buttoned + "_backup"].sourceSkill = event.buttoned; + if (game.online) { + event._sendskill = [event.buttoned + "_backup", lib.skill[event.buttoned + "_backup"]]; + } + else { + game.broadcast((skill, audio) => { + if (!lib.skill[skill]) lib.skill[skill] = {}; + lib.skill[skill].audio = audio; + }, event.buttoned + "_backup", lib.skill[event.buttoned + "_backup"].audio); + } + event.backup(event.buttoned + "_backup"); + if (info.prompt) { + event.openskilldialog = info.prompt(info.chooseControl ? result : result.links, player); + } + } + else { + ui.control.animate("nozoom", 100); + event._aiexclude.add(event.buttoned); + } + event.goto(0); + delete event.buttoned; + } + "step 4" + delete _status.noclearcountdown; + if (event.skillDialog && get.objtype(event.skillDialog) == "div") { + event.skillDialog.close(); + } + if (event.result.bool && !game.online) { + if (event.result._sendskill) { + lib.skill[event.result._sendskill[0]] = event.result._sendskill[1]; + } + var info = get.info(event.result.skill); + if (event.onresult) { + event.onresult(event.result); + } + if ((!event.result || !event.result.bool || event.result._noHidingTimer) && (event.result.skill || event.logSkill)) { + if (info.direct && !info.clearTime) { + _status.noclearcountdown = "direct"; + } + } + if (event.logSkill) { + if (typeof event.logSkill == "string") { + player.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + if (!event.result.card && event.result.skill) { + event.result.used = event.result.skill; + player.useSkill(event.result.skill, event.result.cards, event.result.targets); + } + else { + if (info && info.prerespond) { + info.prerespond(event.result, player); + } + var next = player.respond(event.result.cards, event.result.card, event.animate, event.result.skill, event.source); + if (event.result.noanimate) next.animate = false; + if (event.parent.card && event.parent.type == "card") { + next.set("respondTo", [event.parent.player, event.parent.card]); + } + if (event.noOrdering) next.noOrdering = true; + } + } + else if (event._sendskill) { + event.result._sendskill = event._sendskill; + } + if (event.dialog && event.dialog.close) event.dialog.close(); + if (!_status.noclearcountdown) { + game.stopCountChoose(); + } + }, + chooseToDiscard: function () { + "step 0" + if (event.autochoose()) { + event.result = { + bool: true, + autochoose: true, + cards: player.getCards(event.position), + rawcards: player.getCards(event.position), + } + for (var i = 0; i < event.result.cards.length; i++) { + if (!lib.filter.cardDiscardable(event.result.cards[i], player, event)) { + event.result.cards.splice(i--, 1); + } + } + } + else { + // &&!lib.filter.wuxieSwap(trigger) + if (game.modeSwapPlayer && !_status.auto && player.isUnderControl()) { + game.modeSwapPlayer(player); + } + event.rangecards = player.getCards(event.position); + for (var i = 0; i < event.rangecards.length; i++) { + if (lib.filter.cardDiscardable(event.rangecards[i], player, event)) { + event.rangecards.splice(i--, 1); + } + else { + event.rangecards[i].uncheck("chooseToDiscard"); + } + } + var range = get.select(event.selectCard); + if (event.isMine()) { + game.check(); + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + game.pause(); + if (range[1] > 1 && typeof event.selectCard != "function") { + event.promptdiscard = ui.create.control("AI代选", function () { + ai.basic.chooseCard(event.ai); + if (_status.event.custom && _status.event.custom.add.card) { + _status.event.custom.add.card(); + } + for (var i = 0; i < ui.selected.cards.length; i++) { + ui.selected.cards[i].updateTransform(true); + } + }); + } + if (Array.isArray(event.dialog)) { + event.dialog = ui.create.dialog.apply(this, event.dialog); + event.dialog.open(); + event.dialog.classList.add("noselect"); + } + else if (event.prompt != false) { + var str; + if (typeof (event.prompt) == "string") str = event.prompt; + else { + str = "请弃置"; + if (range[0] == range[1]) str += get.cnNumber(range[0]); + else if (range[1] == Infinity) str += "至少" + get.cnNumber(range[0]); + else str += get.cnNumber(range[0]) + "至" + get.cnNumber(range[1]); + str += "张"; + if (event.position == "h" || event.position == undefined) str += "手"; + if (event.position == "e") str += "装备"; + str += "牌"; + } + event.dialog = ui.create.dialog(str); + if (event.prompt2) { + event.dialog.addText(event.prompt2, event.prompt2.length <= 20); + } + if (Array.isArray(event.selectCard)) { + event.promptbar = event.dialog.add("0/" + get.numStr(event.selectCard[1], "card")); + event.custom.add.card = function () { + _status.event.promptbar.innerHTML = + ui.selected.cards.length + "/" + get.numStr(_status.event.selectCard[1], "card"); + } + } + } + else if (get.itemtype(event.dialog) == "dialog") { + event.dialog.style.display = ""; + event.dialog.open(); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseCard(event.ai) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + } + else if (event.skill) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + } + if (event.rangecards) { + for (var i = 0; i < event.rangecards.length; i++) { + event.rangecards[i].recheck("chooseToDiscard"); + } + } + "step 2" + event.resume(); + if (event.promptdiscard) { + event.promptdiscard.close(); + } + "step 3" + if (event.result.bool && event.result.cards && event.result.cards.length && + !game.online && event.autodelay && !event.isMine()) { + if (typeof event.autodelay == "number") { + game.delayx(event.autodelay); + } + else { + game.delayx(); + } + } + "step 4" + if (event.logSkill && event.result.bool && !game.online) { + if (typeof event.logSkill == "string") { + player.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + if (!game.online) { + if (typeof event.delay == "boolean") { + event.done = player.discard(event.result.cards).set("delay", event.delay); + } + else { + event.done = player.discard(event.result.cards); + } + event.done.discarder = player; + } + if (event.dialog && event.dialog.close) event.dialog.close(); + }, + gaincardMultiple: function () { + "step 0" + event.type = "gain"; + if (event.animate == "give" || event.animate == "gain2") event.visible = true; + if (player && cards) { + event._lose = true; + player.lose(cards, ui.special).set("type", "gain").set("forceDie", true).set("getlx", false); + } + "step 1" + switch (event.animate) { + case "draw": + game.delay(0, get.delayx(500, 500)); + for (var i of event.gain_list) { + if (get.itemtype(i[1]) == "card") i[1] = [i[1]]; + if (event._lose) { + i[1] = i[1].filter(card => { + return !cards.contains(card) || !player.getCards("hejsx").contains(card); + }) + } + if (i[1].length > 0) i[0].$draw(i[1].length); + } + break; + case "gain": + game.delay(0, get.delayx(700, 700)); + for (var i of event.gain_list) { + if (get.itemtype(i[1]) == "card") i[1] = [i[1]]; + if (event._lose) { + i[1] = i[1].filter(card => { + return !cards.contains(card) || !player.getCards("hejsx").contains(card); + }) + } + if (i[1].length > 0) i[0].$gain(i[1].length); + } + break; + case "gain2": case "draw2": + game.delay(0, get.delayx(500, 500)); + for (var i of event.gain_list) { + if (get.itemtype(i[1]) == "card") i[1] = [i[1]]; + if (event._lose) { + i[1] = i[1].filter(card => { + return !cards.contains(card) || !player.getCards("hejsx").contains(card); + }) + } + if (i[1].length > 0) i[0].$gain2(i[1]); + } + break; + case "give": case "giveAuto": + if (!player) break; + var evt = event.getl(player); + game.delay(0, get.delayx(500, 500)); + for (var i of event.gain_list) { + if (get.itemtype(i[1]) == "card") i[1] = [i[1]]; + if (event._lose) { + i[1] = i[1].filter(card => { + return !cards.contains(card) || !player.getCards("hejsx").contains(card); + }) + } + var shown = i[1].slice(0), hidden = []; + if (event.animate == "giveAuto") { + for (var card of i[1]) { + if (evt.hs.contains(card)) { + shown.remove(card); + hidden.push(card); + } + } + } + if (shown.length > 0) player.$give(shown, i[0]); + if (hidden.length > 0) player.$giveAuto(hidden, i[0]); + } + break; + default: + event.finish(); + } + for (var i of event.gain_list) { + if (i[1].length > 0) { + var next = i[0].gain(i[1]); + next.getlx = false; + if (event.visible) next.visible = true; + if (event.giver) next.giver = event.giver; + if (event.gaintag) next.gaintag.addArray(event.gaintag); + } + } + "step 2" + game.delayx(); + }, + discardMultiple: function () { + "step 0" + event.type = "discard"; + event.visible = true; + if (!event.position) event.position = ui.discardPile; + var cards = []; + event.cards = cards; + for (var i = 0; i < event.lose_list.length; i++) { + var next = event.lose_list[i][0].lose(event.lose_list[i][1], event.position); + game.log(event.lose_list[i][0], "弃置了", event.lose_list[i][1]); + next.type = "discard"; + next.animate = false; + next.delay = false; + cards.addArray(event.lose_list[i][1]); + next.getlx = false; + } + var evt = event; + if (evt.animate != false) { + evt.discardid = lib.status.videoId++; + game.broadcastAll(function (list, id, cards) { + for (var i of list) { + for (var j of i[1]) { + j.classList.remove("glow"); + j.classList.remove("glows"); + } + i[0].$throw(i[1], null, "nobroadcast"); + } + var cardnodes = []; + cardnodes._discardtime = get.time(); + for (var ix of list) { + var card = ix[1]; + for (var i = 0; i < cards.length; i++) { + if (cards[i].clone) { + cardnodes.push(cards[i].clone); + } + } + } + ui.todiscard[id] = cardnodes; + }, event.lose_list, evt.discardid, cards); + if (lib.config.sync_speed && cards[0] && cards[0].clone) { + if (evt.delay != false) { + var waitingForTransition = get.time(); + evt.waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete evt.waitingForTransition; + }); + } + else if (evt.getParent().discardTransition) { + delete evt.getParent().discardTransition; + var waitingForTransition = get.time(); + evt.getParent().waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete evt.getParent().waitingForTransition; + }); + } + } + } + "step 1" + if (event.delay != false) { + if (event.waitingForTransition) { + _status.waitingForTransition = event.waitingForTransition; + game.pause(); + } + else { + game.delayx(); + } + } + }, + chooseToCompareLose: function () { + for (var i = 0; i < event.lose_list.length; i++) { + var next = event.lose_list[i][0].lose(event.lose_list[i][1], ui.ordering); + next.relatedEvent = event.getParent(); + next.getlx = false; + } + }, + chooseToCompareMeanwhile: function () { + "step 0" + if (player.countCards("h") == 0) { + event.result = { cancelled: true, bool: false } + event.finish(); + return; + } + for (var i = 0; i < targets.length; i++) { + if (targets[i].countCards("h") == 0) { + event.result = { cancelled: true, bool: false } + event.finish(); + return; + } + } + if (!event.multitarget) { + targets.sort(lib.sort.seat); + } + game.log(player, "对", targets, "发起了共同拼点"); + event.compareMeanwhile = true; + "step 1" + event._result = []; + event.list = targets.filter(function (current) { + return !event.fixedResult || !event.fixedResult[current.playerid]; + }); + if (event.list.length || !event.fixedResult || !event.fixedResult[player.playerid]) { + if (!event.fixedResult || !event.fixedResult[player.playerid]) event.list.unshift(player); + player.chooseCardOL(event.list, "请选择拼点牌", true).set("type", "compare").set("ai", event.ai).set("source", player).aiCard = function (target) { + var hs = target.getCards("h"); + var event = _status.event; + event.player = target; + hs.sort(function (a, b) { + return event.ai(b) - event.ai(a); + }); + delete event.player; + return { bool: true, cards: [hs[0]] }; + }; + } + "step 2" + var cards = []; + var lose_list = []; + if (event.fixedResult && event.fixedResult[player.playerid]) { + event.list.unshift(player); + result.unshift({ bool: true, cards: [event.fixedResult[player.playerid]] }); + lose_list.push([player, [event.fixedResult[player.playerid]]]); + } + else { + if (result[0].skill && lib.skill[result[0].skill] && lib.skill[result[0].skill].onCompare) { + player.logSkill(result[0].skill); + result[0].cards = lib.skill[result[0].skill].onCompare(player) + } + else lose_list.push([player, result[0].cards]); + } + for (var j = 0; j < targets.length; j++) { + if (event.list.contains(targets[j])) { + var i = event.list.indexOf(targets[j]); + if (result[i].skill && lib.skill[result[i].skill] && lib.skill[result[i].skill].onCompare) { + event.list[i].logSkill(result[i].skill); + result[i].cards = lib.skill[result[i].skill].onCompare(event.list[i]); + } + else lose_list.push([targets[j], result[i].cards]); + cards.push(result[i].cards[0]); + } + else if (event.fixedResult && event.fixedResult[targets[j].playerid]) { + cards.push(event.fixedResult[targets[j].playerid]); + lose_list.push([targets[j], [event.fixedResult[targets[j].playerid]]]); + } + } + if (lose_list.length) { + game.loseAsync({ + lose_list: lose_list, + }).setContent("chooseToCompareLose"); + } + event.lose_list = lose_list; + event.getNum = function (card) { + for (var i of event.lose_list) { + if (i[1].contains && i[1].contains(card)) return get.number(card, i[0]); + } + return get.number(card, false); + } + event.cardlist = cards; + event.cards = cards; + event.card1 = result[0].cards[0]; + event.num1 = event.getNum(event.card1); + event.iwhile = 0; + event.winner = null; + event.maxNum = -1; + event.tempplayer = event.player; + event.result = { + winner: null, + player: event.card1, + targets: event.cardlist.slice(0), + num1: [], + num2: [], + }; + "step 3" + event.trigger("compareCardShowBefore"); + "step 4" + player.$compareMultiple(event.card1, targets, cards); + game.log(player, "的拼点牌为", event.card1); + event.cardlist.forEach((card, index) => { + game.log(targets[index], "的拼点牌为", card); + }); + player.animate("target"); + game.delay(0, 1000); + "step 5" + event.target = null; + event.trigger("compare"); + "step 6" + if (event.iwhile < targets.length) { + event.target = targets[event.iwhile]; + event.target.animate("target"); + event.card2 = event.cardlist[event.iwhile]; + event.num2 = event.getNum(event.card2); + //event.tempplayer.line(event.target); + delete event.player; + event.trigger("compare"); + } + else { + game.delay(0, 1000); + event.goto(9); + } + "step 7" + event.result.num1[event.iwhile] = event.num1; + event.result.num2[event.iwhile] = event.num2; + var list = [[event.tempplayer, event.num1], [event.target, event.num2]]; + for (var i of list) { + if (i[1] > event.maxNum) { + event.maxNum = i[1]; + event.winner = i[0]; + } + else if (event.winner && i[1] == event.maxNum && i[0] != event.winner) { + event.winner = null; + } + } + "step 8" + event.iwhile++; + event.goto(6); + "step 9" + var player = event.tempplayer; + event.player = player; + delete event.tempplayer; + var str = "无人拼点成功"; + if (event.winner) { + event.result.winner = event.winner; + str = get.translation(event.winner) + "拼点成功"; + game.log(event.winner, "拼点成功"); + event.winner.popup("胜"); + } else game.log("#b无人", "拼点成功"); + var list = [player].addArray(targets); + list.remove(event.winner); + for (var i of list) { + i.popup("负"); + } + if (str) { + game.broadcastAll(function (str) { + var dialog = ui.create.dialog(str); + dialog.classList.add("center"); + setTimeout(function () { + dialog.close(); + }, 1000); + }, str); + } + game.delay(3); + "step 10" + game.broadcastAll(ui.clear); + "step 11" + event.cards.add(event.card1); + }, + chooseToCompareMultiple: function () { + "step 0" + if (player.countCards("h") == 0) { + event.result = { cancelled: true, bool: false } + event.finish(); + return; + } + for (var i = 0; i < targets.length; i++) { + if (targets[i].countCards("h") == 0) { + event.result = { cancelled: true, bool: false } + event.finish(); + return; + } + } + if (!event.multitarget) { + targets.sort(lib.sort.seat); + } + game.log(player, "对", targets, "发起拼点"); + "step 1" + event._result = []; + event.list = targets.filter(function (current) { + return !event.fixedResult || !event.fixedResult[current.playerid]; + }); + if (event.list.length || !event.fixedResult || !event.fixedResult[player.playerid]) { + if (!event.fixedResult || !event.fixedResult[player.playerid]) event.list.unshift(player); + player.chooseCardOL(event.list, "请选择拼点牌", true).set("type", "compare").set("ai", event.ai).set("source", player).aiCard = function (target) { + var hs = target.getCards("h"); + var event = _status.event; + event.player = target; + hs.sort(function (a, b) { + return event.ai(b) - event.ai(a); + }); + delete event.player; + return { bool: true, cards: [hs[0]] }; + }; + } + "step 2" + var cards = []; + var lose_list = []; + if (event.fixedResult && event.fixedResult[player.playerid]) { + event.list.unshift(player); + result.unshift({ bool: true, cards: [event.fixedResult[player.playerid]] }); + lose_list.push([player, [event.fixedResult[player.playerid]]]); + } + else { + if (result[0].skill && lib.skill[result[0].skill] && lib.skill[result[0].skill].onCompare) { + player.logSkill(result[0].skill); + result[0].cards = lib.skill[result[0].skill].onCompare(player) + } + else lose_list.push([player, result[0].cards]); + } + for (var j = 0; j < targets.length; j++) { + if (event.list.contains(targets[j])) { + var i = event.list.indexOf(targets[j]); + if (result[i].skill && lib.skill[result[i].skill] && lib.skill[result[i].skill].onCompare) { + event.list[i].logSkill(result[i].skill); + result[i].cards = lib.skill[result[i].skill].onCompare(event.list[i]); + } + else lose_list.push([targets[j], result[i].cards]); + cards.push(result[i].cards[0]); + } + else if (event.fixedResult && event.fixedResult[targets[j].playerid]) { + cards.push(event.fixedResult[targets[j].playerid]); + lose_list.push([targets[j], [event.fixedResult[targets[j].playerid]]]); + } + } + if (lose_list.length) { + game.loseAsync({ + lose_list: lose_list, + }).setContent("chooseToCompareLose"); + } + event.lose_list = lose_list; + event.getNum = function (card) { + for (var i of event.lose_list) { + if (i[1].contains && i[1].contains(card)) return get.number(card, i[0]); + } + return get.number(card, false); + } + event.cardlist = cards; + event.cards = cards; + event.card1 = result[0].cards[0]; + event.num1 = event.getNum(event.card1); + event.iwhile = 0; + event.result = { + player: event.card1, + targets: event.cardlist.slice(0), + num1: [], + num2: [], + }; + "step 3" + event.trigger("compareCardShowBefore"); + "step 4" + game.log(player, "的拼点牌为", event.card1); + "step 5" + if (event.iwhile < targets.length) { + event.target = targets[event.iwhile]; + event.target.animate("target"); + player.animate("target"); + event.card2 = event.cardlist[event.iwhile]; + event.num2 = event.getNum(event.card2); + game.log(event.target, "的拼点牌为", event.card2); + player.line(event.target); + player.$compare(event.card1, event.target, event.card2); + event.trigger("compare"); + game.delay(0, 1500); + } + else { + event.goto(9); + } + "step 6" + event.result.num1[event.iwhile] = event.num1; + event.result.num2[event.iwhile] = event.num2; + var str; + if (event.num1 > event.num2) { + str = get.translation(player) + "拼点成功"; + player.popup("胜"); + target.popup("负"); + } + else { + str = get.translation(player) + "拼点失败"; + if (event.num1 == event.num2) { + player.popup("平"); + target.popup("平"); + } + else { + player.popup("负"); + target.popup("胜"); + } + } + game.broadcastAll(function (str) { + var dialog = ui.create.dialog(str); + dialog.classList.add("center"); + setTimeout(function () { + dialog.close(); + }, 1000); + }, str); + game.delay(2); + "step 7" + if (event.callback) { + game.broadcastAll(function (card1, card2) { + if (card1.clone) card1.clone.style.opacity = 0.5; + if (card2.clone) card2.clone.style.opacity = 0.5; + }, event.card1, event.card2); + var next = game.createEvent("compareMultiple"); + next.player = player; + next.target = event.target; + next.card1 = event.card1; + next.card2 = event.card2; + next.num1 = event.num1; + next.num2 = event.num2; + next.setContent(event.callback); + event.compareMultiple = true; + } + "step 8" + game.broadcastAll(ui.clear); + event.iwhile++; + event.goto(5); + "step 9" + event.cards.add(event.card1); + }, + chooseToCompare: function () { + "step 0" + if (((!event.fixedResult || !event.fixedResult[player.playerid]) && player.countCards("h") == 0) || ((!event.fixedResult || !event.fixedResult[target.playerid]) && target.countCards("h") == 0)) { + event.result = { cancelled: true, bool: false } + event.finish(); + return; + } + game.log(player, "对", target, "发起拼点"); + event.lose_list = []; + "step 1" + var sendback = function () { + if (_status.event != event) { + return function () { + event.resultOL = _status.event.resultOL; + }; + } + }; + if (event.fixedResult && event.fixedResult[player.playerid]) { + event.card1 = event.fixedResult[player.playerid]; + event.lose_list.push([player, event.card1]); + } + else if (player.isOnline()) { + player.wait(sendback); + event.ol = true; + player.send(function (ai) { + game.me.chooseCard("请选择拼点牌", true).set("type", "compare").set("glow_result", true).ai = ai; + game.resume(); + }, event.ai); + } + else { + event.localPlayer = true; + player.chooseCard("请选择拼点牌", true).set("type", "compare").set("glow_result", true).ai = event.ai; + } + if (event.fixedResult && event.fixedResult[target.playerid]) { + event.card2 = event.fixedResult[target.playerid]; + event.lose_list.push([target, event.card2]); + } + else if (target.isOnline()) { + target.wait(sendback); + event.ol = true; + target.send(function (ai) { + game.me.chooseCard("请选择拼点牌", true).set("type", "compare").set("glow_result", true).ai = ai; + game.resume(); + }, event.ai); + } + else { + event.localTarget = true; + } + "step 2" + if (event.localPlayer) { + if (result.skill && lib.skill[result.skill] && lib.skill[result.skill].onCompare) { + result.cards = lib.skill[result.skill].onCompare(player); + player.logSkill(result.skill); + } + else event.lose_list.push([player, result.cards[0]]); + event.card1 = result.cards[0]; + } + if (event.localTarget) { + target.chooseCard("请选择拼点牌", true).set("type", "compare").set("glow_result", true).ai = event.ai; + } + "step 3" + if (event.localTarget) { + if (result.skill && lib.skill[result.skill] && lib.skill[result.skill].onCompare) { + target.logSkill(result.skill); + result.cards = lib.skill[result.skill].onCompare(target); + } + else event.lose_list.push([target, result.cards[0]]); + event.card2 = result.cards[0]; + } + if (!event.resultOL && event.ol) { + game.pause(); + } + "step 4" + try { + if (!event.card1) { + if (event.resultOL[player.playerid].skill && lib.skill[event.resultOL[player.playerid].skill] && lib.skill[event.resultOL[player.playerid].skill].onCompare) { + player.logSkill(event.resultOL[player.playerid].skill); + event.resultOL[player.playerid].cards = lib.skill[event.resultOL[player.playerid].skill].onCompare(player); + } + else event.lose_list.push([player, event.resultOL[player.playerid].cards[0]]); + event.card1 = event.resultOL[player.playerid].cards[0]; + } + if (!event.card2) { + if (event.resultOL[target.playerid].skill && lib.skill[event.resultOL[target.playerid].skill] && lib.skill[event.resultOL[target.playerid].skill].onCompare) { + target.logSkill(event.resultOL[target.playerid].skill); + event.resultOL[target.playerid].cards = lib.skill[event.resultOL[target.playerid].skill].onCompare(player); + } + else event.lose_list.push([target, event.resultOL[target.playerid].cards[0]]); + event.card2 = event.resultOL[target.playerid].cards[0]; + } + if (!event.card1 || !event.card2) { + throw ("err"); + } + } + catch (e) { + console.log(e); + game.print(e); + event.finish(); + return; + } + if (event.card2.number >= 10 || event.card2.number <= 4) { + if (target.countCards("h") > 2) { + event.addToAI = true; + } + } + if (event.lose_list.length) { + game.loseAsync({ + lose_list: event.lose_list, + }).setContent("chooseToCompareLose"); + } + "step 5" + event.trigger("compareCardShowBefore"); + "step 6" + game.broadcast(function () { + ui.arena.classList.add("thrownhighlight"); + }); + ui.arena.classList.add("thrownhighlight"); + game.addVideo("thrownhighlight1"); + player.$compare(event.card1, target, event.card2); + game.log(player, "的拼点牌为", event.card1); + game.log(target, "的拼点牌为", event.card2); + var getNum = function (card) { + for (var i of event.lose_list) { + if (i[1] == card) return get.number(card, i[0]); + } + return get.number(card, false); + } + event.num1 = getNum(event.card1); + event.num2 = getNum(event.card2); + event.trigger("compare"); + game.delay(0, 1500); + "step 7" + event.result = { + player: event.card1, + target: event.card2, + num1: event.num1, + num2: event.num2 + } + var str; + if (event.num1 > event.num2) { + event.result.bool = true; + event.result.winner = player; + str = get.translation(player) + "拼点成功"; + player.popup("胜"); + target.popup("负"); + } + else { + event.result.bool = false; + str = get.translation(player) + "拼点失败"; + if (event.num1 == event.num2) { + event.result.tie = true; + player.popup("平"); + target.popup("平"); + } + else { + event.result.winner = target; + player.popup("负"); + target.popup("胜"); + } + } + game.broadcastAll(function (str) { + var dialog = ui.create.dialog(str); + dialog.classList.add("center"); + setTimeout(function () { + dialog.close(); + }, 1000); + }, str); + game.delay(2); + "step 8" + if (typeof event.target.ai.shown == "number" && event.target.ai.shown <= 0.85 && event.addToAI) { + event.target.ai.shown += 0.1; + } + game.broadcastAll(function () { + ui.arena.classList.remove("thrownhighlight"); + }); + game.addVideo("thrownhighlight2"); + if (event.clear !== false) { + game.broadcastAll(ui.clear); + } + if (typeof event.preserve == "function") { + event.preserve = event.preserve(event.result); + } + else if (event.preserve == "win") { + event.preserve = event.result.bool; + } + else if (event.preserve == "lose") { + event.preserve = !event.result.bool; + } + }, + chooseSkill: function () { + "step 0" + var list; + if (typeof event.target == "string") { + list = get.gainableSkillsName(event.target, event.func); + } + else { + list = event.target.getGainableSkills(event.func); + } + if (!list.length) { + event.finish(); + event.result = { bool: false }; + return; + } + event.skillai = function (list) { + return get.max(list, get.skillRank, "item"); + }; + if (event.isMine()) { + var dialog = ui.create.dialog("forcebutton"); + dialog.add(event.prompt || "选择获得一项技能"); + _status.event.list = list; + var clickItem = function () { + _status.event._result = this.link; + game.resume(); + }; + for (i = 0; i < list.length; i++) { + if (lib.translate[list[i] + "_info"]) { + var translation = get.translation(list[i]); + if (translation[0] == "新" && translation.length == 3) { + translation = translation.slice(1, 3); + } + else { + translation = translation.slice(0, 2); + } + var item = dialog.add(``); + item.firstChild.addEventListener("click", clickItem); + item.firstChild.link = list[i]; + } + } + dialog.add(ui.create.div(".placeholder")); + event.dialog = dialog; + event.switchToAuto = function () { + event._result = event.skillai(event.list); + game.resume(); + }; + _status.imchoosing = true; + game.pause(); + } + else { + event._result = event.skillai(list); + } + "step 1" + _status.imchoosing = false; + if (event.dialog) { + event.dialog.close(); + } + event.result = { bool: true, skill: result }; + }, + discoverCard: function () { + "step 0" + var num = event.num || 3; + var choice; + if (typeof event.list == "string" || typeof event.list == "function") { + choice = get.inpile(event.list).randomGets(num); + } + else if (Array.isArray(event.list)) { + choice = event.list.randomGets(num); + } + else { + choice = Array.from(event.list).randomGets(num); + } + if (choice.length) { + var prompt = event.prompt; + if (!prompt) { + prompt = "选择一张牌"; + if (event.use) { + prompt += "使用之"; + } + else if (!event.nogain) { + prompt += "获得之"; + } + } + if (typeof choice[0] === "string") { + var next = player.chooseVCardButton(choice, prompt, event.forced); + if (event.ai) { + next.set("ai", event.ai); + } + } + else if (get.itemtype(choice[0]) == "card") { + var next = player.chooseCardButton(choice, prompt, event.forced); + if (event.ai) { + next.set("ai", event.ai); + } + } + else { + event.finish(); + } + } + else { + event.finish(); + } + "step 1" + event.result = { + bool: result.bool, + card: null, + choice: null + }; + if (result.bool && result.links.length) { + var link = result.links[0]; + var togain = null; + if (get.itemtype(link) == "card") { + event.result.card = link; + togain = link; + } + else if (Array.isArray(link)) { + event.result.choice = link[2]; + togain = game.createCard(link[2]); + } + if (togain) { + if (event.use) { + player.chooseUseTarget(togain); + } + else if (!event.nogain) { + player.gain(togain, "draw"); + game.log(player, "获得了一张牌"); + } + } + } + }, + chooseButton: function () { + "step 0" + if (typeof event.dialog == "number") { + event.dialog = get.idDialog(event.dialog); + } + if (event.createDialog && !event.dialog) { + if (Array.isArray(event.createDialog)) { + event.createDialog.add("hidden"); + event.dialog = ui.create.dialog.apply(this, event.createDialog); + } + event.closeDialog = true; + } + if (event.dialog == undefined) event.dialog = ui.dialog; + if (event.isMine() || event.dialogdisplay) { + event.dialog.style.display = ""; + event.dialog.open(); + } + var filterButton = event.filterButton || function () { return true }; + var selectButton = get.select(event.selectButton); + var buttons = event.dialog.buttons; + var buttonsx = []; + var num = 0; + for (var i = 0; i < buttons.length; i++) { + var button = buttons[i]; + if (filterButton(button, player)) { + num++; + buttonsx.add(button); + } + } + if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + else if (event.direct && num == selectButton[0] || event.forceDirect) { + var buttons = buttonsx.slice(0, num); + event.result = { + bool: true, + button: [buttons], + links: get.links(buttons), + }; + event.dialog.close(); + } + else { + game.check(); + game.pause(); + } + } + else if (event.isOnline()) { + if (event.direct && num == 1 || event.forceDirect) { + var buttons = buttonsx.slice(0, num); + event.result = { + bool: true, + button: [buttons], + links: get.links(buttons), + }; + event.dialog.close(); + } + else { + event.send(); + } + delete event.callback; + } + else { + event.result = "ai"; + } + if (event.onfree) { + lib.init.onfree(); + } + "step 1" + if (event.result == "ai") { + if (event.processAI) { + event.result = event.processAI(); + } + else { + game.check(); + if ((ai.basic.chooseButton(event.ai) || forced) && (!event.filterOk || event.filterOk())) ui.click.ok(); + else ui.click.cancel(); + } + } + if (event.closeDialog) { + event.dialog.close(); + } + if (event.callback) { + event.callback(event.player, event.result); + } + event.resume(); + }, + chooseCardOL: function () { + "step 0" + event.targets = event.list.slice(0); + if (!_status.connectMode) { + event.result = []; + event.goto(7); + } + else { + for (var i = 0; i < event.list.length; i++) { + var target = event.list[i]; + target.wait(); + if (target.isOnline()) { + target.send(function (args, set) { + game.me.chooseCard.apply(game.me, args).set(set); + game.resume(); + }, event._args, event._set); + event.list.splice(i--, 1); + } + else if (target == game.me) { + event.withme = true; + event.list.splice(i--, 1); + } + } + } + "step 1" + if (event.list.length) { + event.target = event.list.shift(); + event.target.chooseCard.apply(event.target, event._args).set(event._set); + } + else { + event.goto(3); + } + "step 2" + event.target.unwait(result); + event.goto(1); + "step 3" + if (event.withme) { + game.me.chooseCard.apply(game.me, event._args).set(event._set); + } + else { + event.goto(5); + } + "step 4" + game.me.unwait(result); + "step 5" + if (!event.resultOL) { + game.pause(); + } + "step 6" + event.result = []; + for (var i = 0; i < event.targets.length; i++) { + event.result[i] = event.resultOL[event.targets[i].playerid] || {}; + if (event.result[i] == "ai" && event.aiCard) { + event.result[i] = event.aiCard(event.targets[i]); + } + } + event.finish(); + "step 7" + if (event.list.length) { + event.target = event.list.shift(); + event.target.chooseCard.apply(event.target, event._args).set(event._set); + } + else { + for (var i = 0; i < event.targets.length; i++) { + if (!event.result[i]) { + event.result[i] = {}; + } + } + event.finish(); + } + "step 8" + event.result[event.targets.indexOf(event.target)] = result; + event.goto(7); + }, + chooseButtonOL: function () { + "step 0" + //ui.arena.classList.add("markhidden"); + for (var i = 0; i < event.list.length; i++) { + var current = event.list[i]; + current[0].wait(); + if (current[0].isOnline()) { + var target = current.shift(); + target.send(function (args, callback, switchToAuto, processAI) { + //ui.arena.classList.add("markhidden"); + var next = game.me.chooseButton.apply(game.me, args); + next.callback = callback; + next.switchToAuto = switchToAuto; + next.processAI = processAI; + next.complexSelect = true; + game.resume(); + }, current, event.callback, event.switchToAuto, event.processAI); + target._choose_button_ol = current; + event.list.splice(i--, 1); + } + else if (current[0] == game.me) { + event.last = current; + event.last.shift(); + event.list.splice(i--, 1); + } + } + "step 1" + if (event.list.length) { + var current = event.list.shift(); + event.target = current.shift(); + var next = event.target.chooseButton.apply(event.target, current); + next.callback = event.callback; + next.switchToAuto = event.switchToAuto; + next.processAI = event.processAI; + } + else { + event.goto(3); + } + "step 2" + event.target.unwait(result); + event.goto(1); + "step 3" + if (event.last) { + var next = game.me.chooseButton.apply(game.me, event.last); + next.callback = event.callback; + next.switchToAuto = event.switchToAuto; + next.processAI = event.processAI; + } + else { + event.goto(5); + } + "step 4" + game.me.unwait(result); + "step 5" + if (!event.resultOL) { + game.pause(); + } + "step 6" + /*game.broadcastAll(function(){ + ui.arena.classList.remove("markhidden"); + });*/ + event.result = event.resultOL; + }, + chooseCard: function () { + "step 0" + if (event.directresult) { + event.result = { + buttons: [], + cards: event.directresult.slice(0), + targets: [], + confirm: "ok", + bool: true, + links: [] + }; + } + else { + if (event.isMine()) { + game.check(); + game.pause(); + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + if (event.prompt != false) { + var str; + if (typeof event.prompt == "string") str = event.prompt; + else { + str = "请选择" + var range = get.select(event.selectCard); + if (range[0] == range[1]) str += get.cnNumber(range[0]); + else if (range[1] == Infinity) str += "至少" + get.cnNumber(range[0]); + else str += get.cnNumber(range[0]) + "至" + get.cnNumber(range[1]); + str += "张"; + if (event.position == "h" || event.position == undefined) str += "手"; + if (event.position == "e") str += "装备"; + str += "牌"; + } + event.dialog = ui.create.dialog(str); + if (event.prompt2) { + event.dialog.addText(event.prompt2, event.prompt2.length <= 20); + } + if (Array.isArray(event.promptx)) { + for (var i = 0; i < event.promptx.length; i++) { + event.dialog.add(event.promptx[i]); + } + } + if (Array.isArray(event.selectCard)) { + event.promptbar = event.dialog.add("0/" + get.numStr(event.selectCard[1], "card")); + event.custom.add.card = function () { + _status.event.promptbar.innerHTML = + ui.selected.cards.length + "/" + get.numStr(_status.event.selectCard[1], "card"); + } + } + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseCard(event.ai) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + } + else if (event.skill) { + var skill = event.skill; + ui.click.cancel(); + event._aiexclude.add(skill); + event.redo(); + game.resume(); + } + else { + ui.click.cancel(); + } + } + "step 2" + event.resume(); + if (event.glow_result && event.result.cards && !event.directresult) { + for (var i = 0; i < event.result.cards.length; i++) { + event.result.cards[i].classList.add("glow"); + } + } + if (event.dialog) event.dialog.close(); + }, + chooseTarget: function () { + "step 0" + if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + game.check(); + game.pause(); + if (event.createDialog && !event.dialog && Array.isArray(event.createDialog)) { + event.dialog = ui.create.dialog.apply(this, event.createDialog); + } + else if (event.prompt != false) { + var str; + if (typeof event.prompt == "string") str = event.prompt; + else { + str = "请选择" + var range = get.select(event.selectTarget); + if (range[0] == range[1]) str += get.cnNumber(range[0]); + else if (range[1] == Infinity) str += "至少" + get.cnNumber(range[0]); + else str += get.cnNumber(range[0]) + "至" + get.cnNumber(range[1]); + str += "个目标"; + } + event.dialog = ui.create.dialog(str); + if (event.prompt2) { + event.dialog.addText(event.prompt2, event.prompt2.length <= 20); + } + if (event.promptbar != "none") { + event.promptbar = event.dialog.add("0/" + get.numStr(get.select(event.selectTarget)[1], "target")); + event.custom.add.target = function () { + _status.event.promptbar.innerHTML = + ui.selected.targets.length + "/" + get.numStr(get.select(event.selectTarget)[1], "target"); + } + } + } + else if (get.itemtype(event.dialog) == "dialog") { + event.dialog.open(); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseTarget(event.ai) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + } + else { + ui.click.cancel(); + } + } + if (event.result.bool && event.animate !== false) { + for (var i = 0; i < event.result.targets.length; i++) { + event.result.targets[i].animate("target"); + } + } + if (event.dialog) event.dialog.close(); + event.resume(); + "step 2" + if (event.onresult) { + event.onresult(event.result); + } + if (event.result.bool && event.autodelay && !event.isMine()) { + if (typeof event.autodelay == "number") { + game.delayx(event.autodelay); + } + else { + game.delayx(); + } + } + }, + chooseCardTarget: function () { + "step 0" + if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + game.check(); + game.pause(); + if (event.prompt != false) { + event.dialog = ui.create.dialog(event.prompt || "请选择卡牌和目标"); + if (event.prompt2) { + event.dialog.addText(event.prompt2, event.prompt2.length <= 20); + } + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.result == "ai") { + game.check(); + if (ai.basic.chooseCard(event.ai1) || forced) { + if ((ai.basic.chooseTarget(event.ai2) || forced) && (!event.filterOk || event.filterOk())) { + ui.click.ok(); + _status.event._aiexclude.length = 0; + } + else { + ui.click.cancel(); + } + } + else { + ui.click.cancel(); + } + } + "step 2" + event.resume(); + if (event.result.bool && event.animate !== false) { + for (var i = 0; i < event.result.targets.length; i++) { + event.result.targets[i].animate("target"); + } + } + if (event.dialog) event.dialog.close(); + }, + chooseControl: function () { + "step 0" + if (event.controls.length == 0) { + if (event.sortcard) { + var sortnum = 2; + if (event.sorttop) { + sortnum = 1; + } + for (var i = 0; i < event.sortcard.length + sortnum; i++) { + event.controls.push(get.cnNumber(i, true)); + } + } + else if (event.choiceList) { + for (var i = 0; i < event.choiceList.length; i++) { + event.controls.push("选项" + get.cnNumber(i + 1, true)); + } + } + else { + event.finish(); + return; + } + } + else if (event.choiceList && event.controls.length == 1 && event.controls[0] == "cancel2") { + event.controls.shift(); + for (var i = 0; i < event.choiceList.length; i++) { + event.controls.push("选项" + get.cnNumber(i + 1, true)); + } + event.controls.push("cancel2"); + } + if (event.isMine()) { + if (event.arrangeSkill) { + var hidden = player.hiddenSkills.slice(0); + game.expandSkills(hidden); + if (hidden.length) { + for (var i of event.controls) { + if (_status.prehidden_skills.contains(i) && hidden.contains(i)) { + event.result = { + bool: true, + control: i, + } + return; + } + } + } + } + else if (event.hsskill && _status.prehidden_skills.contains(event.hsskill) && event.controls.contains("cancel2")) { + event.result = { + bool: true, + control: "cancel2", + } + return; + } + if (event.sortcard) { + var prompt = event.prompt || "选择一个位置"; + if (event.tosort) { + prompt += "放置" + get.translation(event.tosort); + } + event.dialog = ui.create.dialog(prompt, "hidden"); + if (event.sortcard && event.sortcard.length) { + event.dialog.addSmall(event.sortcard); + } + else { + event.dialog.buttons = []; + event.dialog.add(ui.create.div(".buttons")); + } + var buttons = event.dialog.content.lastChild; + var sortnum = 2; + if (event.sorttop) { + sortnum = 1; + } + for (var i = 0; i < event.dialog.buttons.length + sortnum; i++) { + var item = ui.create.div(".button.card.pointerdiv.mebg"); + item.style.width = "50px"; + buttons.insertBefore(item, event.dialog.buttons[i]); + item.innerHTML = `
第${get.cnNumber(i + 1, true)}张
`; + if (i == event.dialog.buttons.length + 1) { + item.firstChild.innerHTML = "牌堆底"; + } + item.link = get.cnNumber(i, true); + item.listen(ui.click.dialogcontrol); + } + + event.dialog.forcebutton = true; + event.dialog.classList.add("forcebutton"); + event.dialog.open(); + } + else if (event.dialogcontrol) { + event.dialog = ui.create.dialog(event.prompt || "选择一项", "hidden"); + for (var i = 0; i < event.controls.length; i++) { + var item = event.dialog.add(``); + item.firstChild.listen(ui.click.dialogcontrol); + item.firstChild.link = event.controls[i]; + } + event.dialog.forcebutton = true; + event.dialog.classList.add("forcebutton"); + if (event.addDialog) { + for (var i = 0; i < event.addDialog.length; i++) { + if (get.itemtype(event.addDialog[i]) == "cards") { + event.dialog.addSmall(event.addDialog[i]); + } + else { + event.dialog.add(event.addDialog[i]); + } + } + event.dialog.add(ui.create.div(".placeholder.slim")); + } + event.dialog.open(); + } + else { + if (event.seperate || lib.config.seperate_control) { + var controls = event.controls.slice(0); + var num = 0; + controls.remove("cancel2"); + if (event.direct && controls.length == 1 || event.forceDirect) { + event.result = { + control: event.controls[0].link, + links: get.links([event.controls[0]]), + }; + return; + } + else { + event.controlbars = []; + for (var i = 0; i < event.controls.length; i++) { + event.controlbars.push(ui.create.control([event.controls[i]])); + } + } + } + else { + var controls = event.controls.slice(0); + var num = 0; + controls.remove("cancel2"); + if (event.direct && controls.length == 1 || event.forceDirect) { + event.result = { + control: event.controls[0].link, + links: get.links([event.controls[0]]), + }; + return; + } + event.controlbar = ui.create.control(event.controls); + } + if (event.dialog) { + if (Array.isArray(event.dialog)) { + event.dialog = ui.create.dialog.apply(this, event.dialog); + } + event.dialog.open(); + } + else if (event.choiceList) { + event.dialog = ui.create.dialog(event.prompt || "选择一项", "hidden"); + event.dialog.forcebutton = true; + event.dialog.open(); + for (var i = 0; i < event.choiceList.length; i++) { + event.dialog.add(``); + } + } + else if (event.prompt) { + event.dialog = ui.create.dialog(event.prompt); + if (event.prompt2) { + event.dialog.addText(event.prompt2, Boolean(event.prompt2.length <= 20 || event.centerprompt2)); + } + } + } + game.pause(); + game.countChoose(); + event.choosing = true; + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.result == "ai") { + event.result = {}; + if (event.ai) { + var result = event.ai(event.getParent(), player); + if (typeof result == "number") event.result.control = event.controls[result]; + else event.result.control = result; + } + else event.result.control = event.controls[event.choice]; + } + event.result.index = event.controls.indexOf(event.result.control); + event.choosing = false; + _status.imchoosing = false; + if (event.dialog && event.dialog.close) event.dialog.close(); + if (event.controlbar) event.controlbar.close(); + if (event.controlbars) { + for (var i = 0; i < event.controlbars.length; i++) { + event.controlbars[i].close(); + } + } + event.resume(); + }, + chooseBool: function () { + "step 0" + if (event.isMine()) { + if (event.frequentSkill && !lib.config.autoskilllist.contains(event.frequentSkill)) { + ui.click.ok(); + return; + } + else if (event.hsskill && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + ui.create.confirm("oc"); + if (event.createDialog && !event.dialog) { + if (Array.isArray(event.createDialog)) { + event.dialog = ui.create.dialog.apply(this, event.createDialog); + if (event.dialogselectx) { + for (var i = 0; i < event.dialog.buttons.length; i++) { + event.dialog.buttons[i].classList.add("selectedx"); + } + } + } + } + if (event.dialog) { + event.dialog.open(); + } + else if (event.prompt) { + event.dialog = ui.create.dialog(event.prompt); + if (event.prompt2) { + event.dialog.addText(event.prompt2, event.prompt2.length <= 20); + } + } + game.pause(); + game.countChoose(); + event.choosing = true; + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + "step 1" + if (event.result == "ai") { + if (event.ai) { + event.choice = event.ai(event.getParent(), player); + } + event.result = { bool: event.choice }; + } + _status.imchoosing = false; + event.choosing = false; + if (event.dialog) event.dialog.close(); + event.resume(); + }, + chooseDrawRecover: function () { + "step 0" + if (player.isHealthy() && event.forced) { + player.draw(event.num1); + event.finish(); + return; + } + var controls = ["draw_card"]; + if (player.isDamaged()) { + event.num2 = Math.min(event.num2, player.maxHp - player.hp); + controls.push("recover_hp"); + } + if (!event.forced) { + controls.push("cancel2"); + } + var prompt = event.prompt; + if (!prompt) { + if (player.isHealthy()) { + prompt = "是否摸" + get.cnNumber(event.num1) + "张牌?"; + } + else { + prompt = "摸" + get.cnNumber(event.num1) + "张牌或回复" + get.cnNumber(event.num2) + "点体力"; + } + } + var next = player.chooseControl(controls); + next.set("prompt", prompt); + if (event.hsskill) next.setHiddenSkill(event.hsskill); + if (event.ai) { + next.set("ai", event.ai); + } + else { + var choice; + if (player.isDamaged() && get.recoverEffect(player) > 0 && ( + player.hp == 1 || player.needsToDiscard() || + player.hasSkillTag("maixie_hp") || event.num2 > event.num1 || + (event.num2 == event.num1 && player.needsToDiscard(1)) + )) { + choice = "recover_hp"; + } + else { + choice = "draw_card"; + } + next.set("ai", function () { + return _status.event.choice; + }); + next.set("choice", choice); + } + "step 1" + if (result.control != "cancel2") { + if (event.logSkill) { + if (typeof event.logSkill == "string") { + player.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + if (result.control == "draw_card") { + player.draw(event.num1); + } + else { + player.recover(event.num2); + } + } + event.result = result; + }, + choosePlayerCard: function () { + "step 0" + if (!event.dialog) event.dialog = ui.create.dialog("hidden"); + else if (!event.isMine()) { + event.dialog.style.display = "none"; + } + if (event.prompt) { + event.dialog.add(event.prompt); + } + else { + event.dialog.add("选择" + get.translation(target) + "的一张牌"); + } + if (event.prompt2) { + event.dialog.addText(event.prompt2); + } + var expand_length = 0; + var directh = (!lib.config.unauto_choose && !event.complexSelect); + for (var i = 0; i < event.position.length; i++) { + if (event.position[i] == "h") { + var hs = target.getCards("h"); + if (hs.length) { + expand_length += Math.ceil(hs.length / 6); + var title = event.dialog.add(`
手牌区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + hs.randomSort(); + if (event.visible || target.isUnderControl(true) || player.hasSkillTag("viewHandcard", null, target, true)) { + event.dialog.add(hs); + directh = false; + } + else { + var shown = hs.filter(card => get.is.shownCard(card)); + if (shown.length) { + var hidden = hs.filter(card => !shown.includes(card)); + var buttons = ui.create.div(".buttons", event.dialog.content); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(shown, "card", buttons)); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(hidden, "blank", buttons)); + if (event.dialog.forcebutton !== false) event.dialog.forcebutton = true; + if (event.dialog.buttons.length > 3) { + event.dialog.classList.remove("forcebutton-auto"); + } + else if (!event.dialog.noforcebutton) { + event.dialog.classList.add("forcebutton-auto"); + } + } + else { + event.dialog.add([hs, "blank"]); + } + } + } + } + else if (event.position[i] == "e") { + var es = target.getCards("e"); + if (es.length) { + expand_length += Math.ceil(es.length / 6); + var title = event.dialog.add(`
装备区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(es); + directh = false; + } + } + else if (event.position[i] == "j") { + var js = target.getCards("j"); + if (js.length) { + expand_length += Math.ceil(js.length / 6); + var title = event.dialog.add(`
判定区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(js); + directh = false; + } + } + } + if (event.dialog.buttons.length == 0) { + event.finish(); + return; + } var directFilter = (event.forced && typeof event.filterOk != "function" && typeof event.selectButton != "function" && event.filterButton == lib.filter.all); + var cs = target.getCards(event.position); + var select = get.select(event.selectButton); + if (directFilter && select[0] >= cs.length) { + event.result = { + bool: true, + buttons: event.dialog.buttons, + links: cs + } + } + else if (directFilter && directh && !event.isOnline() && select[0] == select[1]) { + event.result = { + bool: true, + buttons: event.dialog.buttons.randomGets(select[0]), + links: [] + } + for (var i = 0; i < event.result.buttons.length; i++) { + event.result.links[i] = event.result.buttons[i].link; + } + } + else { + if (event.isMine()) { + if (event.hsskill && !event.forced && _status.prehidden_skills.contains(event.hsskill)) { + ui.click.cancel(); + return; + } + event.dialog.open(); + game.check(); + game.pause(); + if (expand_length > 2) { + ui.arena.classList.add("choose-player-card"); + event.dialog.classList.add("fullheight"); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseButton(event.ai) || forced) && (!event.filterOk || event.filterOk())) ui.click.ok(); + else ui.click.cancel(); + } + event.dialog.close(); + if (event.result.links) { + event.result.cards = event.result.links.slice(0); + } + event.resume(); + setTimeout(function () { + ui.arena.classList.remove("choose-player-card"); + }, 500); + }, + discardPlayerCard: function () { + "step 0" + if (event.directresult) { + event.result = { + buttons: [], + cards: event.directresult.slice(0), + links: event.directresult.slice(0), + targets: [], + confirm: "ok", + bool: true + }; + event.cards = event.directresult.slice(0); + event.goto(2); + return; + } + if (!event.dialog) event.dialog = ui.create.dialog("hidden"); + else if (!event.isMine()) { + event.dialog.style.display = "none"; + } + if (event.prompt == undefined) { + var str = "弃置" + get.translation(target); + var range = get.select(event.selectButton); + if (range[0] == range[1]) str += get.cnNumber(range[0]); + else if (range[1] == Infinity) str += "至少" + get.cnNumber(range[0]); + else str += get.cnNumber(range[0]) + "至" + get.cnNumber(range[1]); + str += "张"; + if (event.position == "h" || event.position == undefined) str += "手"; + if (event.position == "e") str += "装备"; + str += "牌"; + event.prompt = str; + } + if (event.prompt) { + event.dialog.add(event.prompt); + } + if (event.prompt2) { + event.dialog.addText(event.prompt2); + } + var directh = (!lib.config.unauto_choose && !event.complexSelect); + var expand_length = 0; + for (var i = 0; i < event.position.length; i++) { + if (event.position[i] == "h") { + var hs = target.getDiscardableCards(player, "h"); + expand_length += Math.ceil(hs.length / 6); + if (hs.length) { + var title = event.dialog.add(`
手牌区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + hs.randomSort(); + if (event.visible || target.isUnderControl(true) || player.hasSkillTag("viewHandcard", null, target, true)) { + event.dialog.add(hs); + directh = false; + } + else { + var shown = hs.filter(card => get.is.shownCard(card)); + if (shown.length) { + var hidden = hs.filter(card => !shown.includes(card)); + var buttons = ui.create.div(".buttons", event.dialog.content); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(shown, "card", buttons)); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(hidden, "blank", buttons)); + if (event.dialog.forcebutton !== false) event.dialog.forcebutton = true; + if (event.dialog.buttons.length > 3) { + event.dialog.classList.remove("forcebutton-auto"); + } + else if (!event.dialog.noforcebutton) { + event.dialog.classList.add("forcebutton-auto"); + } + } + else { + event.dialog.add([hs, "blank"]); + } + } + } + } + else if (event.position[i] == "e") { + var es = target.getDiscardableCards(player, "e"); + if (es.length) { + expand_length += Math.ceil(es.length / 6); + var title = event.dialog.add(`
装备区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(es); + directh = false; + } + } + else if (event.position[i] == "j") { + var js = target.getDiscardableCards(player, "j"); + if (js.length) { + expand_length += Math.ceil(js.length / 6); + var title = event.dialog.add(`
判定区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(js); + directh = false; + } + } + } + if (event.dialog.buttons.length == 0) { + event.finish(); + return; + } + var directFilter = (event.forced && typeof event.filterOk != "function" && typeof event.selectButton != "function" && event.filterButton == lib.filter.all); + var cs = target.getCards(event.position); + var select = get.select(event.selectButton); + if (directFilter && select[0] >= cs.length) { + event.result = { + bool: true, + buttons: event.dialog.buttons, + links: cs + } + } + else if (directFilter && directh && !event.isOnline() && select[0] == select[1]) { + event.result = { + bool: true, + buttons: event.dialog.buttons.randomGets(select[0]), + links: [] + } + for (var i = 0; i < event.result.buttons.length; i++) { + event.result.links[i] = event.result.buttons[i].link; + } + } + else { + if (event.isMine()) { + event.dialog.open(); + game.check(); + game.pause(); + if (expand_length > 2) { + ui.arena.classList.add("discard-player-card"); + event.dialog.classList.add("fullheight"); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseButton(event.ai) || forced) && (!event.filterOk || event.filterOk())) ui.click.ok(); + else ui.click.cancel(); + } + event.dialog.close(); + "step 2" + event.resume(); + setTimeout(function () { + ui.arena.classList.remove("discard-player-card"); + }, 500); + if (event.result.bool && event.result.links && !game.online) { + if (event.logSkill) { + if (typeof event.logSkill == "string") { + player.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + var cards = []; + for (var i = 0; i < event.result.links.length; i++) { + cards.push(event.result.links[i]); + } + event.result.cards = event.result.links.slice(0); + event.cards = cards; + event.trigger("rewriteDiscardResult"); + } + "step 3" + if (event.boolline) { + player.line(target, "green"); + } + if (!event.chooseonly) { + var next = target.discard(event.cards); + if (player != target) next.notBySelf = true; + next.discarder = player; + event.done = next; + if (event.delay === false) { + next.set("delay", false); + } + } + }, + gainPlayerCard: function () { + "step 0" + if (event.directresult) { + event.result = { + buttons: [], + cards: event.directresult.slice(0), + links: event.directresult.slice(0), + targets: [], + confirm: "ok", + bool: true + }; + event.cards = event.directresult.slice(0); + event.goto(2); + return; + } + if (!event.dialog) event.dialog = ui.create.dialog("hidden"); + else if (!event.isMine()) { + event.dialog.style.display = "none"; + } + if (event.prompt == undefined) { + var str = "获得" + get.translation(target); + var range = get.select(event.selectButton); + if (range[0] == range[1]) str += get.cnNumber(range[0]); + else if (range[1] == Infinity) str += "至少" + get.cnNumber(range[0]); + else str += get.cnNumber(range[0]) + "至" + get.cnNumber(range[1]); + str += "张"; + if (event.position == "h" || event.position == undefined) str += "手"; + if (event.position == "e") str += "装备"; + str += "牌"; + event.prompt = str; + } + if (event.prompt) { + event.dialog.add(event.prompt); + } + if (event.prompt2) { + event.dialog.addText(event.prompt2); + } + var expand_length = 0; + var directh = (!lib.config.unauto_choose && !event.complexSelect); + for (var i = 0; i < event.position.length; i++) { + if (event.position[i] == "h") { + var hs = target.getGainableCards(player, "h"); + if (hs.length) { + expand_length += Math.ceil(hs.length / 6); + var title = event.dialog.add(`
手牌区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + hs.randomSort(); + if (event.visible || target.isUnderControl(true) || player.hasSkillTag("viewHandcard", null, target, true)) { + event.dialog.add(hs); + directh = false; + } + else { + var shown = hs.filter(card => get.is.shownCard(card)); + if (shown.length) { + var hidden = hs.filter(card => !shown.includes(card)); + var buttons = ui.create.div(".buttons", event.dialog.content); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(shown, "card", buttons)); + event.dialog.buttons = event.dialog.buttons.concat(ui.create.buttons(hidden, "blank", buttons)); + if (event.dialog.forcebutton !== false) event.dialog.forcebutton = true; + if (event.dialog.buttons.length > 3) { + event.dialog.classList.remove("forcebutton-auto"); + } + else if (!event.dialog.noforcebutton) { + event.dialog.classList.add("forcebutton-auto"); + } + } + else { + event.dialog.add([hs, "blank"]); + } + } + } + } + else if (event.position[i] == "e") { + var es = target.getGainableCards(player, "e"); + if (es.length) { + expand_length += Math.ceil(es.length / 6); + var title = event.dialog.add(`
装备区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(es); + directh = false; + } + } + else if (event.position[i] == "j") { + var js = target.getGainableCards(player, "j"); + if (js.length) { + expand_length += Math.ceil(js.length / 6); + var title = event.dialog.add(`
判定区
`); + title.style.margin = "0px"; + title.style.padding = "0px"; + event.dialog.add(js); + directh = false; + } + } + } + if (event.dialog.buttons.length == 0) { + event.dialog.close(); + event.finish(); + return; + } + var cs = target.getCards(event.position); + var select = get.select(event.selectButton); + var directFilter = (event.forced && typeof event.filterOk != "function" && typeof event.selectButton != "function" && event.filterButton == lib.filter.all); + if (directFilter && select[0] >= cs.length) { + event.result = { + bool: true, + buttons: event.dialog.buttons, + links: cs + } + } + else if (directFilter && directh && !event.isOnline() && select[0] == select[1]) { + event.result = { + bool: true, + buttons: event.dialog.buttons.randomGets(select[0]), + links: [] + } + for (var i = 0; i < event.result.buttons.length; i++) { + event.result.links[i] = event.result.buttons[i].link; + } + } + else { + if (event.isMine()) { + event.dialog.open(); + game.check(); + game.pause(); + if (expand_length > 2) { + ui.arena.classList.add("gain-player-card"); + event.dialog.classList.add("fullheight"); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.result = "ai"; + } + } + "step 1" + if (event.result == "ai") { + game.check(); + if ((ai.basic.chooseButton(event.ai) || forced) && (!event.filterOk || event.filterOk())) ui.click.ok(); + else ui.click.cancel(); + } + event.dialog.close(); + "step 2" + event.resume(); + setTimeout(function () { + ui.arena.classList.remove("gain-player-card"); + }, 500); + if (game.online || !event.result.bool) { + event.finish(); + } + "step 3" + if (event.logSkill && event.result.bool && !game.online) { + if (typeof event.logSkill == "string") { + player.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + player.logSkill.apply(player, event.logSkill); + } + } + var cards = []; + for (var i = 0; i < event.result.links.length; i++) { + cards.push(event.result.links[i]); + } + event.result.cards = event.result.links.slice(0); + event.cards = cards; + event.trigger("rewriteGainResult"); + "step 4" + if (event.boolline) { + player.line(target, "green"); + } + if (!event.chooseonly) { + if (event.delay !== false) { + var next = player.gain(event.cards, target, event.visibleMove ? "give" : "giveAuto", "bySelf"); + event.done = next; + } + else { + var next = player.gain(event.cards, target, "bySelf"); + event.done = next; + target[event.visibleMove ? "$give" : "$giveAuto"](cards, player); + if (event.visibleMove) next.visible = true; + } + } + else target[event.visibleMove ? "$give" : "$giveAuto"](cards, player); + }, + showHandcards: function () { + "step 0" + if (player.countCards("h") == 0) { + event.finish(); + return; + } + var cards = player.getCards("h"); + player.showCards(cards).setContent(() => void 0); + var str = get.translation(player.name) + "的手牌"; + if (typeof event.prompt == "string") { + str = event.prompt; + } + event.dialog = ui.create.dialog(str, cards); + event.dialogid = lib.status.videoId++; + event.dialog.videoId = event.dialogid; + game.broadcast(function (str, cards, id) { + ui.create.dialog(str, cards).videoId = id; + }, str, cards, event.dialogid); + game.log(player, "展示了", cards); + game.addVideo("showCards", player, [str, get.cardsInfo(cards)]); + game.delayx(2); + "step 1" + game.broadcast("closeDialog", event.dialogid); + event.dialog.close(); + }, + showCards: function () { + "step 0" + if (get.itemtype(cards) != "cards") { + event.finish(); + return; + } + if (!event.str) { + event.str = get.translation(player.name) + "展示的牌"; + } + event.dialog = ui.create.dialog(event.str, cards); + event.dialogid = lib.status.videoId++; + event.dialog.videoId = event.dialogid; + + if (event.hiddencards) { + for (var i = 0; i < event.dialog.buttons.length; i++) { + if (event.hiddencards.contains(event.dialog.buttons[i].link)) { + event.dialog.buttons[i].className = "button card"; + event.dialog.buttons[i].innerHTML = ""; + } + } + } + game.broadcast(function (str, cards, cards2, id) { + var dialog = ui.create.dialog(str, cards); + dialog.forcebutton = true; + dialog.videoId = id; + if (cards2) { + for (var i = 0; i < dialog.buttons.length; i++) { + if (cards2.contains(dialog.buttons[i].link)) { + dialog.buttons[i].className = "button card"; + dialog.buttons[i].innerHTML = ""; + } + } + } + }, event.str, cards, event.hiddencards, event.dialogid); + if (event.hiddencards) { + var cards2 = cards.slice(0); + for (var i = 0; i < event.hiddencards.length; i++) { + cards2.remove(event.hiddencards[i]); + } + game.log(player, "展示了", cards2); + } + else { + game.log(player, "展示了", cards); + } + game.addCardKnower(cards, "everyone"); + game.delayx(event.delay_time || 2.5); + game.addVideo("showCards", player, [event.str, get.cardsInfo(cards)]); + "step 1" + game.broadcast("closeDialog", event.dialogid); + event.dialog.close(); + }, + viewCards: function () { + "step 0" + game.addCardKnower(event.cards, player); + if (player == game.me) { + event.dialog = ui.create.dialog(event.str, event.cards); + if (event.isMine()) { + game.pause(); + ui.create.confirm("o"); + game.countChoose(); + event.choosing = true; + } + else { + event.finish(); + event.result = "viewed"; + setTimeout(function () { + event.dialog.close(); + }, 2 * lib.config.duration); + game.delayx(2); + } + } + else if (event.isOnline()) { + event.send(); + } + else { + event.finish(); + } + "step 1" + event.result = "viewed"; + _status.imchoosing = false; + event.choosing = false; + if (event.dialog) event.dialog.close(); + }, + moveCard: function () { + "step 0" + if (!player.canMoveCard(null, event.nojudge, event.sourceTargets, event.aimTargets, event.filter, event.canReplace ? "canReplace" : "noReplace")) { + event.finish(); + return; + } + var next = player.chooseTarget(2, function (card, player, target) { + var filterCard = get.event("filter"); + if (ui.selected.targets.length) { + if (!get.event("aimTargets").includes(target)) return false; + var from = ui.selected.targets[0]; + var js = from.getCards("j", filterCard); + for (var i = 0; i < js.length; i++) { + if (_status.event.nojudge) break; + if (target.canAddJudge(js[i])) return true; + } + if (target.isMin()) return false; + var es = from.getCards("e", filterCard); + for (var i = 0; i < es.length; i++) { + if (target.canEquip(es[i], _status.event.canReplace)) return true; + } + return false; + } + else { + if (!get.event("sourceTargets").includes(target)) return false; + var range = "ej"; + if (_status.event.nojudge) range = "e"; + return target.countCards(range, filterCard) > 0; + } + }); + next.set("nojudge", event.nojudge || false); + next.set("ai", function (target) { + var player = _status.event.player; + var att = get.attitude(player, target); + var sgnatt = get.sgn(att); + var aimTargets = get.event("aimTargets"), filterCard = get.event("filter"); + if (ui.selected.targets.length == 0) { + if (att > 0) { + if (!_status.event.nojudge && target.countCards("j", function (card) { + if (!filterCard(card)) return false; + return game.hasPlayer(function (current) { + if (!aimTargets.includes(current)) return false; + return current != target && current.canAddJudge(card) && get.attitude(player, current) < 0; + }) + })) return 14; + if (target.countCards("e", function (card) { + if (!filterCard(card)) return false; + return get.value(card, target) < 0 && game.hasPlayer(function (current) { + if (!aimTargets.includes(current)) return false; + return current != target && get.attitude(player, current) < 0 && current.canEquip(card, _status.event.canReplace) && get.effect(target, card, player, player) < 0; + }); + }) > 0) return 9; + } + else if (att < 0) { + if (game.hasPlayer(function (current) { + if (current != target && get.attitude(player, current) > 0) { + var es = target.getCards("e", filterCard); + for (var i = 0; i < es.length; i++) { + if (get.value(es[i], target) > 0 && current.canEquip(es[i], _status.event.canReplace) && get.effect(current, es[i], player, player) > (_status.event.canReplace ? get.effect(target, es[i], player, player) : 0)) return true; + } + } + })) { + return -att; + } + } + return 0; + } + var es = ui.selected.targets[0].getCards("e", filterCard); + var i; + var att2 = get.sgn(get.attitude(player, ui.selected.targets[0])); + for (i = 0; i < es.length; i++) { + if (sgnatt != 0 && att2 != 0 && sgnatt != att2 && + get.sgn(get.value(es[i], ui.selected.targets[0])) == -att2 && + get.sgn(get.effect(target, es[i], player, target)) == sgnatt && + target.canEquip(es[i], _status.event.canReplace)) { + return Math.abs(att); + } + } + if (i == es.length && (_status.event.nojudge || !ui.selected.targets[0].countCards("j", function (card) { + if (!filterCard(card)) return false; + return target.canAddJudge(card); + }) || att2 <= 0)) { + return 0; + } + return -att * att2; + }); + next.set("multitarget", true); + next.set("targetprompt", _status.event.targetprompt || ["被移走", "移动目标"]); + next.set("prompt", event.prompt || "移动场上的一张牌"); + next.set("filter", event.filter); + next.set("sourceTargets", event.sourceTargets || game.filterPlayer()); + next.set("aimTargets", event.aimTargets || game.filterPlayer()); + next.set("canReplace", event.canReplace); + next.set("custom", get.copy(event.custom)); + if (event.prompt2) next.set("prompt2", event.prompt2); + if (event.forced) next.set("forced", true); + "step 1" + event.result = result; + if (result.bool) { + if (event.logSkill) player.logSkill(event.logSkill, result.targets, false); + player.line2(result.targets, "green"); + event.targets = result.targets; + } + else { + event.finish(); + } + "step 2" + game.delay(); + "step 3" + if (targets.length == 2) { + player.choosePlayerCard("ej", true, function (button) { + var player = _status.event.player; + var targets0 = _status.event.targets0; + var targets1 = _status.event.targets1; + if (get.attitude(player, targets0) > 0 && get.attitude(player, targets1) < 0) { + if (get.position(button.link) == "j") return 12; + if (get.value(button.link, targets0) < 0 && get.effect(targets1, button.link, player, targets1) > 0) return 10; + return 0; + } + else { + if (get.position(button.link) == "j") return -10; + return get.value(button.link) * get.effect(targets1, button.link, player, targets1); + } + }, targets[0]).set("nojudge", event.nojudge || false).set("targets0", targets[0]).set("targets1", targets[1]).set("filterButton", function (button) { + var targets1 = _status.event.targets1; + if (!get.event("filter")(button.link)) return false; + if (get.position(button.link) == "j") { + if (_status.event.nojudge) return false; + return targets1.canAddJudge(button.link); + } + else { + return targets1.canEquip(button.link, _status.event.canReplace); + } + }).set("filter", event.filter).set("canReplace", event.canReplace).set("custom", get.copy(event.custom)); + } + else { + event.finish(); + } + "step 4" + if (result.bool && result.links.length) { + var link = result.links[0]; + if (get.position(link) == "e") { + event.targets[1].equip(link); + } + else if (link.viewAs) { + event.targets[1].addJudge({ name: link.viewAs }, [link]); + } + else { + event.targets[1].addJudge(link); + } + event.targets[0].$give(link, event.targets[1], false); + game.log(event.targets[0], "的", link, "被移动给了", event.targets[1]) + event.result.card = link; + event.result.position = get.position(link); + game.delay(); + } + }, + useCard: function () { + "step 0" + if (!card) { + console.log("err: no card", get.translation(event.player)); + event.finish(); + return; + } + if (!get.info(card, false).noForceDie) event.forceDie = true; + if (cards.length) { + var owner = (get.owner(cards[0]) || player); + var next = owner.lose(cards, "visible", ui.ordering).set("type", "use"); + var directDiscard = []; + for (var i = 0; i < cards.length; i++) { + if (!next.cards.contains(cards[i])) { + directDiscard.push(cards[i]); + } + } + if (directDiscard.length) game.cardsGotoOrdering(directDiscard); + } + //player.using=cards; + var cardaudio = true; + if (event.skill) { + if (lib.skill[event.skill].audio) { + cardaudio = false; + } + if (lib.skill[event.skill].log != false) { + player.logSkill(event.skill); + } + if (get.info(event.skill).popname) { + player.tryCardAnimate(card, event.card.name, "metal", true); + } + } + else if (!event.nopopup) { + if (lib.translate[event.card.name + "_pop"]) { + player.tryCardAnimate(card, lib.translate[event.card.name + "_pop"], "metal"); + } + else { + player.tryCardAnimate(card, event.card.name, "metal"); + } + } + if (event.audio === false) { + cardaudio = false; + } + if (cardaudio) game.broadcastAll((player, card) => { + game.playCardAudio(card, player); + /* + if(!lib.config.background_audio||get.type(card)=="equip"&&!lib.config.equip_audio) return; + const sex=player.sex=="female"?"female":"male"; + var nature=get.natureList(card)[0]; + if(card.name=="sha"&&["fire","thunder","ice","stab"].includes(nature)){ + game.playAudio("card",sex,`${card.name}_${nature}`); + return; + } + const audio=lib.card[card.name].audio; + if(typeof audio=="string"){ + const audioInfo=audio.split(":"); + if(audio.startsWith("db:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,audioInfo[2],`${card.name}_${sex}.${audioInfo[3]||"mp3"}`); + else if(audio.startsWith("ext:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${card.name}_${sex}.${audioInfo[2]||"mp3"}`); + else game.playAudio("card",sex,`${audioInfo[0]}.${audioInfo[1]||"mp3"}`); + } + else game.playAudio("card",sex,card.name);*/ + }, player, card); + if (event.animate != false && event.line != false) { + if (card.name == "wuxie" && event.getParent()._info_map) { + var evtmap = event.getParent()._info_map; + if (evtmap._source) evtmap = evtmap._source; + var lining = (evtmap.multitarget ? evtmap.targets : evtmap.target) || event.player; + if (Array.isArray(lining) && event.getTrigger().name == "jiedao") { + player.line(lining[0], "green"); + } + else { + player.line(lining, "green"); + } + } + else if (card.name == "youdishenru" && event.getParent().source) { + var lining = event.getParent().sourcex || event.getParent().source2 || event.getParent().source; + if (lining == player && event.getParent().sourcex2) { + lining = event.getParent().sourcex2; + } + if (Array.isArray(lining) && event.getTrigger().name == "jiedao") { + player.line(lining[0], "green"); + } + else { + player.line(lining, "green"); + } + } + else { + var config = {}; + var nature = get.natureList(card)[0]; + if (nature || card.classList && card.classList.contains(nature)) config.color = nature; + if (event.addedTarget) { + player.line2(targets.concat(event.addedTargets), config); + } + else if (get.info(card, false).multitarget && targets.length > 1 && !get.info(card, false).multiline) { + player.line2(targets, config); + } + else { + player.line(targets, config); + } + } + if (event.throw !== false) player.$throw(cards); + if (lib.config.sync_speed && cards[0] && cards[0].clone) { + var waitingForTransition = get.time(); + event.waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete event.waitingForTransition; + }); + } + } + event.id = get.id(); + if (!Array.isArray(event.excluded)) event.excluded = []; + if (!Array.isArray(event.directHit)) event.directHit = []; + if (typeof event.customArgs != "object" || typeof event.customArgs.default != "object") event.customArgs = { default: {} }; + if (typeof event.baseDamage != "number") event.baseDamage = get.info(card, false).baseDamage || 1; + if (typeof event.effectCount != "number") event.effectCount = get.info(card, false).effectCount || 1; + event.effectedCount = 0; + if (event.oncard) { + event.oncard(event.card, event.player); + } + player.actionHistory[player.actionHistory.length - 1].useCard.push(event); + game.getGlobalHistory().useCard.push(event); + if (event.addCount !== false) { + if (player.stat[player.stat.length - 1].card[card.name] == undefined) { + player.stat[player.stat.length - 1].card[card.name] = 1; + } + else { + player.stat[player.stat.length - 1].card[card.name]++; + } + } + if (event.skill) { + if (player.stat[player.stat.length - 1].skill[event.skill] == undefined) { + player.stat[player.stat.length - 1].skill[event.skill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[event.skill]++; + } + var sourceSkill = get.info(event.skill).sourceSkill; + if (sourceSkill) { + if (player.stat[player.stat.length - 1].skill[sourceSkill] == undefined) { + player.stat[player.stat.length - 1].skill[sourceSkill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[sourceSkill]++; + } + } + } + if (targets.length) { + var str = (targets.length == 1 && targets[0] == player) ? "#b自己" : targets; + if (cards.length && !card.isCard) { + if (event.addedTarget) { + game.log(player, "对", str, "使用了", card, "(", cards, ",指向", event.addedTargets, ")"); + } + else { + game.log(player, "对", str, "使用了", card, "(", cards, ")"); + } + } + else { + if (event.addedTarget) { + game.log(player, "对", str, "使用了", card, "(指向", event.addedTargets, ")"); + } + else { + game.log(player, "对", str, "使用了", card); + } + } + } + else { + if (cards.length && !card.isCard) { + if (event.addedTarget) { + game.log(player, "使用了", card, "(", cards, ",指向", event.addedTargets, ")"); + } + else { + game.log(player, "使用了", card, "(", cards, ")"); + } + } + else { + if (event.addedTarget) { + game.log(player, "使用了", card, "(指向", event.addedTargets, ")"); + } + else { + game.log(player, "使用了", card); + } + } + } + if (card.name == "wuxie") { + game.logv(player, [card, cards], [event.getTrigger().card]); + } + else { + game.logv(player, [card, cards], targets); + } + event.trigger("useCard1"); + "step 1" + event.trigger("yingbian"); + "step 2" + event.trigger("useCard2"); + "step 3" + event.trigger("useCard"); + event._oncancel = function () { + game.broadcastAll(function (id) { + if (ui.tempnowuxie && ui.tempnowuxie._origin == id) { + ui.tempnowuxie.close(); + delete ui.tempnowuxie; + } + }, event.id); + }; + "step 4" + event.sortTarget = function (animate, sort) { + var info = get.info(card, false); + if (num == 0 && targets.length > 1) { + if (!info.multitarget) { + if (!event.fixedSeat && !sort) { + targets.sortBySeat((_status.currentPhase || player)); + } + if (animate) for (var i = 0; i < targets.length; i++) { + targets[i].animate("target"); + } + } + else if (animate) { + for (var i = 0; i < targets.length; i++) { + targets[i].animate("target"); + } + } + } + } + event.sortTarget(); + event.getTriggerTarget = function (list1, list2) { + var listx = list1.slice(0).sortBySeat((_status.currentPhase || player)); + for (var i = 0; i < listx.length; i++) { + if (get.numOf(list2, listx[i]) < get.numOf(listx, listx[i])) return listx[i]; + } + return null; + } + "step 5" + if (event.all_excluded) return; + if (!event.triggeredTargets1) event.triggeredTargets1 = []; + var target = event.getTriggerTarget(targets, event.triggeredTargets1); + if (target) { + event.triggeredTargets1.push(target); + var next = game.createEvent("useCardToPlayer", false); + if (!event.isFirstTarget1) { + event.isFirstTarget1 = true; + next.isFirstTarget = true; + } + next.setContent("emptyEvent"); + next.targets = targets; + next.target = target; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.excluded = event.excluded; + next.directHit = event.directHit; + next.customArgs = event.customArgs; + if (event.forceDie) next.forceDie = true; + event.redo(); + } + "step 6" + if (event.all_excluded) return; + if (!event.triggeredTargets2) event.triggeredTargets2 = []; + var target = event.getTriggerTarget(targets, event.triggeredTargets2); + if (target) { + event.triggeredTargets2.push(target); + var next = game.createEvent("useCardToTarget", false); + if (!event.isFirstTarget2) { + event.isFirstTarget2 = true; + next.isFirstTarget = true; + } + next.setContent("emptyEvent"); + next.targets = targets; + next.target = target; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.excluded = event.excluded; + next.directHit = event.directHit; + next.customArgs = event.customArgs; + if (event.forceDie) next.forceDie = true; + event.redo(); + } + "step 7" + var info = get.info(card, false); + if (!info.nodelay && event.animate != false) { + if (event.delayx !== false) { + if (event.waitingForTransition) { + _status.waitingForTransition = event.waitingForTransition; + game.pause(); + } + else { + game.delayx(); + } + } + } + "step 8" + if (event.all_excluded) return; + if (!event.triggeredTargets3) event.triggeredTargets3 = []; + var target = event.getTriggerTarget(targets, event.triggeredTargets3); + if (target) { + event.triggeredTargets3.push(target); + var next = game.createEvent("useCardToPlayered", false); + if (!event.isFirstTarget3) { + event.isFirstTarget3 = true; + next.isFirstTarget = true; + } + next.setContent("emptyEvent"); + next.targets = targets; + next.target = target; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.excluded = event.excluded; + next.directHit = event.directHit; + next.customArgs = event.customArgs; + if (event.forceDie) next.forceDie = true; + event.redo(); + } + "step 9" + if (event.all_excluded) return; + if (!event.triggeredTargets4) event.triggeredTargets4 = []; + var target = event.getTriggerTarget(targets, event.triggeredTargets4); + if (target) { + event.triggeredTargets4.push(target); + var next = game.createEvent("useCardToTargeted", false); + if (!event.isFirstTarget4) { + event.isFirstTarget4 = true; + next.isFirstTarget = true; + } + next.setContent("emptyEvent"); + next.targets = targets; + next.target = target; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.excluded = event.excluded; + next.directHit = event.directHit; + next.customArgs = event.customArgs; + if (event.forceDie) next.forceDie = true; + if (targets.length == event.triggeredTargets4.length) { + event.sortTarget(); + } + event.redo(); + } + "step 10" + if (event.all_excluded) return; + event.effectedCount++; + event.num = 0; + var info = get.info(card, false); + if (info.contentBefore) { + var next = game.createEvent(card.name + "ContentBefore"); + next.setContent(info.contentBefore); + next.targets = targets; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.type = "precard"; + if (event.forceDie) next.forceDie = true; + } + else if (info.reverseOrder && get.is.versus() && targets.length > 1) { + var next = game.createEvent(card.name + "ContentBefore"); + next.setContent("reverseOrder"); + next.targets = targets; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.type = "precard"; + if (event.forceDie) next.forceDie = true; + } + else if (info.singleCard && info.filterAddedTarget && event.addedTargets && event.addedTargets.length < targets.length) { + var next = game.createEvent(card.name + "ContentBefore"); + next.setContent("addExtraTarget"); + next.target = target; + next.targets = targets; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.type = "precard"; + next.addedTarget = event.addedTarget; + next.addedTargets = event.addedTargets; + if (event.forceDie) next.forceDie = true; + } + "step 11" + if (event.all_excluded) return; + var info = get.info(card, false); + if (num == 0 && targets.length > 1) { + event.sortTarget(true, true); + } + if (targets[num] && targets[num].isDead()) return; + if (targets[num] && targets[num].isOut()) return; + if (targets[num] && targets[num].removed) return; + if (targets[num] && info.ignoreTarget && info.ignoreTarget(card, player, targets[num])) return; + if (targets.length == 0 && !info.notarget) return; + if (targets[num] && event.excluded.contains(targets[num])) { + var next = game.createEvent("useCardToExcluded", false); + next.setContent("emptyEvent"); + next.targets = targets; + next.target = targets[num]; + next.num = num; + next.card = card; + next.cards = cards; + next.player = player; + return; + } + var next = game.createEvent(card.name); + next.setContent(info.content); + next.targets = targets; + next.card = card; + next.cards = cards; + next.player = player; + next.num = num; + next.type = "card"; + next.skill = event.skill; + next.multitarget = info.multitarget; + next.preResult = event.preResult; + next.baseDamage = event.baseDamage; + if (event.forceDie) next.forceDie = true; + if (event.addedTargets) { + next.addedTargets = event.addedTargets; + next.addedTarget = event.addedTargets[num]; + next._targets = event._targets; + } + if (info.targetDelay === false) { + event.targetDelay = false; + } + next.target = targets[num]; + for (var i in event.customArgs.default) next[i] = event.customArgs.default[i]; + if (next.target && event.customArgs[next.target.playerid]) { + var customArgs = event.customArgs[next.target.playerid]; + for (var i in customArgs) next[i] = customArgs[i]; + } + if (next.target && event.directHit.contains(next.target)) next.directHit = true; + if (next.target && !info.multitarget) { + if (num == 0 && targets.length > 1) { + // var ttt=next.target; + // setTimeout(function(){ttt.animate("target");},0.5*lib.config.duration); + } + else { + next.target.animate("target"); + } + } + if (!info.nodelay && num > 0) { + if (event.targetDelay !== false) { + game.delayx(0.5); + } + } + "step 12" + if (event.all_excluded) return; + if (!get.info(event.card, false).multitarget && num < targets.length - 1 && !event.cancelled) { + event.num++; + event.goto(11); + } + "step 13" + if (event.all_excluded) return; + if (get.info(card, false).contentAfter) { + var next = game.createEvent(card.name + "ContentAfter"); + next.setContent(get.info(card, false).contentAfter); + next.targets = targets; + next.card = card; + next.cards = cards; + next.player = player; + next.skill = event.skill; + next.preResult = event.preResult; + next.type = "postcard"; + if (event.forceDie) next.forceDie = true; + } + "step 14" + if (event.all_excluded) return; + if (event.effectedCount < event.effectCount) { + if (document.getElementsByClassName("thrown").length) { + if (event.delayx !== false && get.info(event.card, false).finalDelay !== false) game.delayx(); + } + event.goto(10); + } + "step 15" + if (event.postAi) { + event.player.logAi(event.targets, event.card); + } + if (event._result) { + event.result = event._result; + } + //delete player.using; + if (document.getElementsByClassName("thrown").length) { + if (event.delayx !== false && get.info(event.card, false).finalDelay !== false) game.delayx(); + } + else { + event.finish(); + } + "step 16" + event._oncancel(); + }, + useSkill: function () { + "step 0" + var info = get.info(event.skill); + if (!info.noForceDie) event.forceDie = true; + if (!info.noForceOut) event.includeOut = true; + event._skill = event.skill; + game.trySkillAudio(event.skill, player); + var checkShow = player.checkShow(event.skill); + if (info.discard != false && info.lose != false && !info.viewAs) { + player.discard(cards).delay = false; + if (lib.config.low_performance) { + event.discardTransition = true; + } + } + else { + if (info.lose != false) { + if (info.losetrigger == false) { + var losecard = player.lose(cards, ui.special)._triggered = null; + } + else { + var losecard = player.lose(cards, ui.special); + if (info.visible) losecard.visible = true; + if (info.loseTo) losecard.position = ui[info.loseTo]; + if (info.insert) losecard.insert_card = true; + if (losecard.position == ui.special && info.toStorage) losecard.toStorage = true; + } + } + if (!info.prepare && info.viewAs) { + player.$throw(cards); + if (losecard) losecard.visible = true; + if (lib.config.sync_speed && cards[0] && cards[0].clone) { + var waitingForTransition = get.time(); + event.waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete event.waitingForTransition; + }); + } + } + } + if (info.line != false && targets.length) { + var config = {}; + if (get.is.object(info.line)) config = info.line; + else if (info.line == "fire") { + config.color = "fire"; + } + else if (info.line == "thunder") { + config.color = "thunder"; + } + else if (info.line === undefined || info.line == "green") { + config.color = "green"; + } + if (info.multitarget && !info.multiline && targets.length > 1) { + player.line2(targets, config); + } + else { + player.line(targets, config); + } + } + var str = ""; + if (targets && targets.length && info.log != "notarget") { + str += `对${targets[0] == player ? "自己" : get.translation(targets[0])}`; + for (var i = 1; i < targets.length; i++) { + str += "、" + (targets[i] == player ? "自己" : get.translation(targets[i])); + } + str += "" + } + str += "发动了"; + if (!info.direct && info.log !== false) { + game.log(player, str, "【" + get.skillTranslation(skill, player) + "】"); + if (info.logv !== false) game.logv(player, skill, targets); + player.trySkillAnimate(skill, skill, checkShow); + } + if (event.addCount != false) { + if (player.stat[player.stat.length - 1].skill[skill] == undefined) { + player.stat[player.stat.length - 1].skill[skill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[skill]++; + } + var sourceSkill = get.info(skill).sourceSkill; + if (sourceSkill) { + if (player.stat[player.stat.length - 1].skill[sourceSkill] == undefined) { + player.stat[player.stat.length - 1].skill[sourceSkill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[sourceSkill]++; + } + } + } + if (player.stat[player.stat.length - 1].allSkills == undefined) { + player.stat[player.stat.length - 1].allSkills = 1; + } + else { + player.stat[player.stat.length - 1].allSkills++; + } + if (info.prepare) { + switch (info.prepare) { + case "give": if (losecard) losecard.visible = true; player.$give(cards, targets[0]); break; + case "give2": player.$give(cards.length, targets[0]); break; + case "throw": if (losecard) losecard.visible = true; player.$throw(cards); break; + case "throw2": player.$throw(cards.length); break; + default: info.prepare(cards, player, targets); + } + } + if (info.round) { + var roundname = skill + "_roundcount"; + player.storage[roundname] = game.roundNumber; + player.syncStorage(roundname); + player.markSkill(roundname); + } + var name = event.skill; + var players = player.getSkills(false, false, false); + var equips = player.getSkills("e"); + var global = lib.skill.global.slice(0); + var logInfo = { + skill: name, + targets: targets, + event: _status.event, + }; + if (info.sourceSkill) { + logInfo.sourceSkill = info.sourceSkill; + if (global.contains(info.sourceSkill)) { + logInfo.type = "global"; + } + else if (players.contains(info.sourceSkill)) { + logInfo.type = "player"; + } + else if (equips.contains(info.sourceSkill)) { + logInfo.type = "equip"; + } + } + else { + if (global.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "global"; + } + else if (players.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "player"; + } + else if (equips.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "equip"; + } + else { + var bool = false; + for (var i of players) { + var expand = [i]; + game.expandSkills(expand); + if (expand.contains(name)) { + bool = true; + logInfo.sourceSkill = i; + logInfo.type = "player"; + break; + } + } + if (!bool) { + for (var i of players) { + var expand = [i]; + game.expandSkills(expand); + if (expand.contains(name)) { + logInfo.sourceSkill = i; + logInfo.type = "equip"; + break; + } + } + } + } + } + event.sourceSkill = logInfo.sourceSkill; + event.type = logInfo.type; + player.getHistory("useSkill").push(logInfo); + event.trigger("useSkill"); + "step 1" + var info = get.info(event.skill); + if (info && info.contentBefore) { + var next = game.createEvent(event.skill + "ContentBefore"); + next.setContent(info.contentBefore); + next.targets = targets; + next.cards = cards; + next.player = player; + if (event.forceDie) next.forceDie = true; + if (event.includeOut) next.includeOut = true; + } + "step 2" + if (!event.skill) { + console.log("error: no skill", get.translation(event.player), event.player.getSkills()); + if (event._skill) { + event.skill = event._skill; + console.log(event._skill); + } + else { + event.finish(); + return; + } + } + var info = get.info(event.skill); + if (targets[num] && targets[num].isDead() || + targets[num] && targets[num].isOut() || + targets[num] && targets[num].removed) { + if (!info.multitarget && num < targets.length - 1) { + event.num++; + event.redo(); + } + return; + } + var next = game.createEvent(event.skill); + next.setContent(info.content); + next.targets = targets; + next.cards = cards; + next.player = player; + next.num = num; + next.multitarget = info.multitarget; + if (num == 0 && next.targets.length > 1) { + if (!info.multitarget) { + lib.tempSortSeat = player; + targets.sort(lib.sort.seat); + delete lib.tempSortSeat; + } + for (var i = 0; i < targets.length; i++) { + targets[i].animate("target"); + } + } + next.target = targets[num]; + if (event.forceDie) next.forceDie = true; + if (event.includeOut) next.includeOut = true; + if (next.target && !info.multitarget) { + if (num == 0 && targets.length > 1) { + // var ttt=next.target; + // setTimeout(function(){ttt.animate("target");},0.5*lib.config.duration); + } + else { + next.target.animate("target"); + } + } + if (num == 0) { + if (typeof info.delay == "number") game.delay(info.delay); + else if (info.delay !== false && info.delay !== 0) { + if (event.waitingForTransition) { + _status.waitingForTransition = event.waitingForTransition; + game.pause(); + } + else { + game.delayx() + } + } + } + else game.delayx(0.5); + if (!info.multitarget && num < targets.length - 1) { + event.num++; + event.redo(); + } + "step 3" + var info = get.info(event.skill); + if (info && info.contentAfter) { + var next = game.createEvent(event.skill + "ContentAfter"); + next.setContent(info.contentAfter); + next.targets = targets; + next.cards = cards; + next.player = player; + if (event.forceDie) next.forceDie = true; + if (event.includeOut) next.includeOut = true; + } + "step 4" + if (player.getStat().allSkills > 200) { + player._noSkill = true; + console.log(player.name, event.skill); + } + if (document.getElementsByClassName("thrown").length) { + if (event.skill && get.info(event.skill).delay !== false && get.info(event.skill).delay !== 0) game.delayx(); + } + else { + event.finish(); + } + "step 5" + ui.clear(); + }, + draw: function () { + // if(lib.config.background_audio){ + // game.playAudio("effect","draw"); + // } + // game.broadcast(function(){ + // if(lib.config.background_audio){ + // game.playAudio("effect","draw"); + // } + // }); + if (typeof event.minnum == "number" && num < event.minnum) { + num = event.minnum; + } + if (event.drawDeck) { + if (event.drawDeck > num) { + event.drawDeck = num; + } + num -= event.drawDeck; + } + if (event.log != false) { + if (num > 0) { + if (event.bottom) game.log(player, "从牌堆底摸了" + get.cnNumber(num) + "张牌"); + else game.log(player, "摸了" + get.cnNumber(num) + "张牌"); + } + if (event.drawDeck) { + game.log(player, "从牌库中获得了" + get.cnNumber(event.drawDeck) + "张牌"); + } + } + var cards; + if (num > 0) { + if (event.bottom) cards = get.bottomCards(num); + else if (player.getTopCards) cards = player.getTopCards(num); + else cards = get.cards(num); + } + else { + cards = []; + } + if (event.drawDeck) { + cards = cards.concat(player.getDeckCards(event.drawDeck)); + } + if (event.animate != false) { + if (event.visible) { + var next = player.gain(cards, "gain2"); + if (event.bottom) game.log(player, "从牌堆底摸了" + get.cnNumber(num) + "张牌(", cards, ")"); + else game.log(player, "摸了" + get.cnNumber(num) + "张牌(", cards, ")"); + } + else { + var next = player.gain(cards, "draw"); + } + } + else { + var next = player.gain(cards); + if (event.$draw) { + player.$draw(cards.length); + } + } + if (event.gaintag) next.gaintag.addArray(event.gaintag); + event.result = cards; + }, + discard: function () { + "step 0" + game.log(player, "弃置了", cards); + event.done = player.lose(cards, event.position, "visible"); + event.done.type = "discard"; + if (event.discarder) event.done.discarder = event.discarder; + "step 1" + event.trigger("discard"); + }, + loseToDiscardpile: function () { + "step 0" + if (event.log != false) game.log(player, "将", cards, "置入了弃牌堆"); + var next = player.lose(cards, event.position); + if (event.insert_index) next.insert_index = event.insert_index; + if (event.insert_card) next.insert_card = true; + if (!event.blank) next.visible = true; + next.type = "loseToDiscardpile"; + event.done = next; + "step 1" + event.trigger("loseToDiscardpile"); + }, + respond: function () { + "step 0" + var cardaudio = true; + if (event.skill) { + if (lib.skill[event.skill].audio) { + cardaudio = false; + } + player.logSkill(event.skill); + player.checkShow(event.skill, true); + if (lib.skill[event.skill].onrespond && !game.online) { + lib.skill[event.skill].onrespond(event, player); + } + } + else if (!event.nopopup) player.tryCardAnimate(card, card.name, "wood"); + if (cardaudio && event.getParent(3).name == "useCard") game.broadcastAll((player, card) => { + game.playCardAudio(card, player); + /* + if(!lib.config.background_audio) return; + const sex=player.sex=="female"?"female":"male",audio=lib.card[card.name].audio; + if(typeof audio=="string"){ + const audioInfo=audio.split(":"); + if(audio.startsWith("db:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,audioInfo[2],`${card.name}_${sex}.${audioInfo[3]||"mp3"}`); + else if(audio.startsWith("ext:")) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${card.name}_${sex}.${audioInfo[2]||"mp3"}`); + else game.playAudio("card",sex,`${audioInfo[0]}.${audioInfo[1]||"mp3"}`); + } + else game.playAudio("card",sex,card.name);*/ + }, player, card); + if (event.skill) { + if (player.stat[player.stat.length - 1].skill[event.skill] == undefined) { + player.stat[player.stat.length - 1].skill[event.skill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[event.skill]++; + } + var sourceSkill = get.info(event.skill).sourceSkill; + if (sourceSkill) { + if (player.stat[player.stat.length - 1].skill[sourceSkill] == undefined) { + player.stat[player.stat.length - 1].skill[sourceSkill] = 1; + } + else { + player.stat[player.stat.length - 1].skill[sourceSkill]++; + } + } + } + if (cards.length && (cards.length > 1 || cards[0].name != card.name)) { + game.log(player, "打出了", card, "(", cards, ")"); + } + else { + game.log(player, "打出了", card); + } + player.actionHistory[player.actionHistory.length - 1].respond.push(event); + if (cards.length) { + var owner = (get.owner(cards[0]) || player); + var next = owner.lose(cards, "visible", ui.ordering).set("type", "use"); + var directDiscard = []; + for (var i = 0; i < cards.length; i++) { + if (!next.cards.contains(cards[i])) { + directDiscard.push(cards[i]); + } + } + if (directDiscard.length) game.cardsGotoOrdering(directDiscard); + } + if (event.animate != false && event.throw !== false) { + for (var i = 0; i < cards.length; i++) { + player.$throw(cards[i]); + if (event.highlight) { + cards[i].clone.classList.add("thrownhighlight"); + game.addVideo("highlightnode", player, get.cardInfo(cards[i])); + } + } + if (event.highlight) { + game.broadcast(function (cards) { + for (var i = 0; i < cards.length; i++) { + if (cards[i].clone) { + cards[i].clone.classList.add("thrownhighlight"); + } + } + }, cards); + } + } + event.trigger("respond"); + "step 1" + game.delayx(0.5); + }, + swapHandcards: function () { + "step 0" + event.cards1 = event.cards1 || player.getCards("h"); + event.cards2 = event.cards2 || target.getCards("h"); + game.loseAsync({ + player: player, + target: target, + cards1: event.cards1, + cards2: event.cards2, + }).setContent("swapHandcardsx"); + "step 1" + game.loseAsync({ + gain_list: [ + [player, event.cards2.filterInD()], + [target, event.cards1.filterInD()] + ], + }).setContent("gaincardMultiple"); + "step 2" + game.delayx(); + }, + swapHandcardsx: function () { + "step 0" + player.$giveAuto(event.cards1, target); + target.$giveAuto(event.cards2, player); + "step 1" + event.cards = event.cards1; + var next = player.lose(event.cards, ui.ordering); + next.getlx = false; + next.relatedEvent = event.getParent(); + if (player == game.me) { + event.delayed = true; + } + else { + next.delay = false; + } + "step 2" + event.cards = event.cards2; + var next = target.lose(event.cards, ui.ordering); + next.getlx = false; + next.relatedEvent = event.getParent(); + if (target == game.me) { + event.delayed = true; + } + else { + next.delay = false; + } + "step 3" + if (!event.delayed) game.delay(); + }, + gainMultiple: function () { + "step 0" + event.delayed = false; + event.num = 0; + event.cards = []; + "step 1" + player.gainPlayerCard(targets[num], event.position, true).set("boolline", false).set("delay", num == targets.length - 1); + "step 2" + if (result.bool) { + event.cards.addArray(result.cards); + if (num == targets.length - 1) event.delayed = true; + } + event.num++; + if (event.num < targets.length) { + event.goto(1); + } + "step 3" + if (!event.delayed) game.delay(); + }, + gain: function () { + "step 0" + if (event.animate == "give") event.visible = true; + if (cards) { + var map = {}; + for (var i of cards) { + var owner = get.owner(i, "judge"); + if (owner && (owner != player || get.position(i) != "h")) { + var id = owner.playerid; + if (!map[id]) map[id] = [[], [], []]; + map[id][0].push(i); + var position = get.position(i); + if (position == "h") map[id][1].push(i); + else map[id][2].push(i); + } + else if (!event.updatePile && get.position(i) == "c") event.updatePile = true; + } + event.losing_map = map; + for (var i in map) { + var owner = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + var next = owner.lose(map[i][0], ui.special).set("type", "gain").set("forceDie", true).set("getlx", false); + if (event.visible == true) { + next.visible = true; + } + event.relatedLose = next; + } + } + else { + event.finish(); + } + "step 1" + for (var i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("handcard", player, event)) { + cards[i].selfDestroy(event); + cards.splice(i--, 1); + } + else if (event.losing_map) { + for (var id in event.losing_map) { + if (event.losing_map[id][0].contains(cards[i])) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[id]; + var hs = source.getCards("hejsx"); + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } else { + cards[i].addKnower(event.visible ? "everyone" : source); + } + } + } + } + } + if (cards.length == 0) { + event.finish(); + return; + } + player.getHistory("gain").push(event); + //if(event.source&&event.delay!==false) game.delayx(); + "step 2" + if (player.getStat().gain == undefined) { + player.getStat().gain = cards.length; + } + else { + player.getStat().gain += cards.length; + } + "step 3" + var sort; + var frag1 = document.createDocumentFragment(); + var frag2 = document.createDocumentFragment(); + var hs = player.getCards("hs"); + for (var i = 0; i < cards.length; i++) { + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + for (var num = 0; num < cards.length; num++) { + sort = lib.config.sort_card(cards[num]); + if (lib.config.reverse_sort) sort = -sort; + if (["o", "d"].contains(get.position(cards[num], true))) { + cards[num].addKnower("everyone"); + } + cards[num].fix(); + cards[num].style.transform = ""; + cards[num].addGaintag(event.gaintag); + if (event.knowers) { + cards[num].addKnower(event.knowers);//添加事件设定的知情者。 + } + if (_status.discarded) { + _status.discarded.remove(cards[num]); + } + // cards[num].vanishtag.length=0; + for (var num2 = 0; num2 < cards[num].vanishtag.length; num2++) { + if (cards[num].vanishtag[num2][0] != "_") { + cards[num].vanishtag.splice(num2--, 1); + } + } + if (player == game.me) { + cards[num].classList.add("drawinghidden"); + } + if (get.is.singleHandcard() || sort > 1) frag1.appendChild(cards[num]); + else frag2.appendChild(cards[num]); + } + var addv = function () { + if (player == game.me) { + game.addVideo("gain12", player, [get.cardsInfo(frag1.childNodes), get.cardsInfo(frag2.childNodes), event.gaintag]); + } + }; + var broadcast = function () { + game.broadcast(function (player, cards, num, gaintag) { + player.directgain(cards, null, gaintag); + _status.cardPileNum = num; + }, player, cards, ui.cardPile.childNodes.length, event.gaintag); + }; + if (event.animate == "draw") { + player.$draw(cards.length); + game.pause(); + setTimeout(function () { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + game.resume(); + }, get.delayx(500, 500)); + } + else if (event.animate == "gain") { + player.$gain(cards, event.log); + game.pause(); + setTimeout(function () { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + game.resume(); + }, get.delayx(700, 700)); + } + else if (event.animate == "gain2" || event.animate == "draw2") { + var gain2t = 300; + if (player.$gain2(cards, event.log) && player == game.me) { + gain2t = 500; + } + game.pause(); + setTimeout(function () { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + game.resume(); + }, get.delayx(gain2t, gain2t)); + } + else if (event.animate == "give" || event.animate == "giveAuto") { + var evtmap = event.losing_map; + if (event.animate == "give") { + for (var i in evtmap) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + source.$give(evtmap[i][0], player, event.log) + } + } + else { + for (var i in evtmap) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + if (evtmap[i][1].length) source.$giveAuto(evtmap[i][1], player, event.log); + if (evtmap[i][2].length) source.$give(evtmap[i][2], player, event.log); + } + } + game.pause(); + setTimeout(function () { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + game.resume(); + }, get.delayx(500, 500)); + } + else if (typeof event.animate == "function") { + var time = event.animate(event); + game.pause(); + setTimeout(function () { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + game.resume(); + }, get.delayx(time, time)); + } + else { + addv(); + player.node.handcards1.insertBefore(frag1, player.node.handcards1.firstChild); + player.node.handcards2.insertBefore(frag2, player.node.handcards2.firstChild); + player.update(); + if (player == game.me) ui.updatehl(); + broadcast(); + event.finish(); + } + "step 4" + game.delayx(); + if (event.updatePile) game.updateRoundNumber(); + }, + addToExpansion: function () { + "step 0" + if (event.animate == "give") event.visible = true; + if (cards) { + var map = {}; + for (var i of cards) { + var owner = get.owner(i, "judge"); + if (owner && (owner != player || get.position(i) != "x")) { + var id = owner.playerid; + if (!map[id]) map[id] = [[], [], []]; + map[id][0].push(i); + var position = get.position(i); + if (position == "h") map[id][1].push(i); + else map[id][2].push(i); + } + else if (!event.updatePile && get.position(i) == "c") event.updatePile = true; + } + event.losing_map = map; + for (var i in map) { + var owner = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + var next = owner.lose(map[i][0], ui.special).set("type", "loseToExpansion").set("forceDie", true).set("getlx", false); + if (event.visible == true) next.visible = true; + event.relatedLose = next; + } + } + else { + event.finish(); + } + "step 1" + for (var i = 0; i < cards.length; i++) { + if (cards[i].willBeDestroyed("expansion", player, event)) { + cards[i].selfDestroy(event); + cards.splice(i--, 1); + } + else if (event.losing_map) { + for (var id in event.losing_map) { + if (event.losing_map[id][0].contains(cards[i])) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[id]; + var hs = source.getCards("hejsx"); + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + } + } + } + if (cards.length == 0) { + event.finish(); + return; + } + "step 2" + var hs = player.getCards("x"); + for (var i = 0; i < cards.length; i++) { + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + for (var num = 0; num < cards.length; num++) { + if (_status.discarded) { + _status.discarded.remove(cards[num]); + } + for (var num2 = 0; num2 < cards[num].vanishtag.length; num2++) { + if (cards[num].vanishtag[num2][0] != "_") { + cards[num].vanishtag.splice(num2--, 1); + } + } + } + if (event.animate == "draw") { + player.$draw(cards.length); + if (event.log) game.log(player, "将", get.cnNumber(cards.length), "张牌置于了武将牌上"); + game.pause(); + setTimeout(function () { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + game.resume(); + }, get.delayx(500, 500)); + } + else if (event.animate == "gain") { + player.$gain(cards, false); + game.pause(); + setTimeout(function () { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + game.resume(); + }, get.delayx(700, 700)); + } + else if (event.animate == "gain2" || event.animate == "draw2") { + var gain2t = 300; + if (player.$gain2(cards) && player == game.me) { + gain2t = 500; + } + game.pause(); + setTimeout(function () { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + game.resume(); + }, get.delayx(gain2t, gain2t)); + } + else if (event.animate == "give" || event.animate == "giveAuto") { + var evtmap = event.losing_map; + if (event.animate == "give") { + for (var i in evtmap) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + source.$give(evtmap[i][0], player, false); + if (event.log) game.log(player, "将", evtmap[i][0], "置于了武将牌上"); + } + } + else { + for (var i in evtmap) { + var source = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + if (evtmap[i][1].length) { + source.$giveAuto(evtmap[i][1], player, false); + if (event.log) game.log(player, "将", get.cnNumber(evtmap[i][1].length), "张牌置于了武将牌上"); + } + if (evtmap[i][2].length) { + source.$give(evtmap[i][2], player, false); + if (event.log) game.log(player, "将", evtmap[i][2], "置于了武将牌上"); + } + } + } + game.pause(); + setTimeout(function () { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + game.resume(); + }, get.delayx(500, 500)); + } + else if (typeof event.animate == "function") { + var time = event.animate(event); + game.pause(); + setTimeout(function () { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + game.resume(); + }, get.delayx(time, time)); + } + else { + player.$addToExpansion(cards, null, event.gaintag); + for (var i of event.gaintag) player.markSkill(i); + event.finish(); + } + "step 4" + game.delayx(); + if (event.updatePile) game.updateRoundNumber(); + }, + lose: function () { + "step 0" + var evt = event.getParent(); + if ((evt.name != "discard" || event.type != "discard") && (evt.name != "loseToDiscardpile" || event.type != "loseToDiscardpile")) { + event.delay = false; + return; + } + if (evt.delay === false) event.delay = false; + if (evt.animate != false) { + evt.discardid = lib.status.videoId++; + game.broadcastAll(function (player, cards, id, visible) { + player.$throw(cards, null, "nobroadcast"); + var cardnodes = []; + cardnodes._discardtime = get.time(); + for (var i = 0; i < cards.length; i++) { + if (cards[i].clone) { + cardnodes.push(cards[i].clone); + if (!visible) { + cards[i].clone.classList.add("infohidden"); + cards[i].clone.classList.add("infoflip"); + } + } + } + ui.todiscard[id] = cardnodes; + }, player, cards, evt.discardid, event.visible); + if (lib.config.sync_speed && cards[0] && cards[0].clone) { + if (evt.delay != false) { + var waitingForTransition = get.time(); + evt.waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete evt.waitingForTransition; + }); + } + else if (evt.getParent().discardTransition) { + delete evt.getParent().discardTransition; + var waitingForTransition = get.time(); + evt.getParent().waitingForTransition = waitingForTransition; + cards[0].clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + delete evt.getParent().waitingForTransition; + }); + } + } + } + "step 1" + event.gaintag_map = {}; + var hs = [], es = [], js = [], ss = [], xs = []; + var unmarks = []; + if (event.insert_card && event.position == ui.cardPile) event.cards.reverse(); + var hej = player.getCards("hejsx"); + event.stockcards = cards.slice(0); + for (var i = 0; i < cards.length; i++) { + if (!hej.contains(cards[i])) { + cards.splice(i--, 1); + continue; + } + else if (cards[i].parentNode) { + if (cards[i].parentNode.classList.contains("equips")) { + cards[i].original = "e"; + es.push(cards[i]); + } + else if (cards[i].parentNode.classList.contains("judges")) { + cards[i].original = "j"; + js.push(cards[i]); + } + else if (cards[i].parentNode.classList.contains("expansions")) { + cards[i].original = "x"; + xs.push(cards[i]); + if (cards[i].gaintag && cards[i].gaintag.length) unmarks.addArray(cards[i].gaintag); + } + else if (cards[i].parentNode.classList.contains("handcards")) { + if (cards[i].classList.contains("glows")) { + cards[i].original = "s"; + ss.push(cards[i]); + } + else { + cards[i].original = "h"; + hs.push(cards[i]); + } + } + else { + cards[i].original = null; + } + } + if (cards[i].gaintag && cards[i].gaintag.length) { + event.gaintag_map[cards[i].cardid] = cards[i].gaintag.slice(0); + cards[i].removeGaintag(true); + } + + cards[i].style.transform += " scale(0.2)"; + cards[i].classList.remove("glow"); + cards[i].classList.remove("glows"); + cards[i].recheck(); + + var info = lib.card[cards[i].name]; + if (Object.prototype.hasOwnProperty.call(cards[i], "_destroy")) { + if (cards[i]._destroy) { + cards[i].delete(); + cards[i].destroyed = cards[i]._destroy; + continue; + } + } + else if (Object.prototype.hasOwnProperty.call(cards[i], "destroyed")) { + if (event.getlx !== false && event.position && cards[i].willBeDestroyed(event.position.id, null, event)) { + cards[i].selfDestroy(event); + continue; + } + } + else if (info.destroy) { + cards[i].delete(); + cards[i].destroyed = info.destroy; + continue; + } + if (event.position) { + if (_status.discarded) { + if (event.position == ui.discardPile) { + _status.discarded.add(cards[i]); + } + else { + _status.discarded.remove(cards[i]); + } + } + if (event.insert_index) { + cards[i].fix(); + event.position.insertBefore(cards[i], event.insert_index(event, cards[i])); + } + else if (event.insert_card) { + cards[i].fix(); + event.position.insertBefore(cards[i], event.position.firstChild); + } + else if (event.position == ui.cardPile) { + cards[i].fix(); + event.position.appendChild(cards[i]); + } + else cards[i].goto(event.position); + } + else { + cards[i].remove(); + } + //if(ss.contains(cards[i])) cards.splice(i--,1); + } + if (player == game.me) ui.updatehl(); + ui.updatej(player); + game.broadcast(function (player, cards, num) { + for (var i = 0; i < cards.length; i++) { + cards[i].classList.remove("glow"); + cards[i].classList.remove("glows"); + cards[i].fix(); + cards[i].remove(); + } + if (player == game.me) { + ui.updatehl(); + } + ui.updatej(player); + _status.cardPileNum = num; + }, player, cards, ui.cardPile.childNodes.length); + game.addVideo("lose", player, [get.cardsInfo(hs), get.cardsInfo(es), get.cardsInfo(js), get.cardsInfo(ss)]); + event.cards2 = hs.concat(es); + player.getHistory("lose").push(event); + game.getGlobalHistory().cardMove.push(event); + player.update(); + game.addVideo("loseAfter", player); + event.num = 0; + if (event.position == ui.ordering) { + var evt = event.relatedEvent || event.getParent(); + if (!evt.orderingCards) evt.orderingCards = []; + if (!evt.noOrdering && !evt.cardsOrdered) { + evt.cardsOrdered = true; + var next = game.createEvent("orderingDiscard", false, evt.getParent()); + next.relatedEvent = evt; + next.setContent("orderingDiscard"); + } + if (!evt.noOrdering) { + evt.orderingCards.addArray(cards); + } + } + else if (event.position == ui.cardPile) { + game.updateRoundNumber(); + } + if (unmarks.length) { + for (var i of unmarks) { + player[(lib.skill[i] && lib.skill[i].mark || player.hasCard((card) => card.hasGaintag(i), "x")) ? "markSkill" : "unmarkSkill"](i); + } + } + event.hs = hs; + event.es = es; + event.js = js; + event.ss = ss; + event.xs = xs; + game.clearCardKnowers(hs); + if (hs.length && !event.visible) { + player.getCards("h").forEach(hcard => { hcard.clearKnowers(); }); + } + "step 2" + if (num < cards.length) { + if (event.es.contains(cards[num])) { + event.loseEquip = true; + player.removeEquipTrigger(cards[num]); + var info = get.info(cards[num]); + if (info.onLose && (!info.filterLose || info.filterLose(cards[num], player))) { + event.goto(3); + return; + } + } + event.num++; + event.redo(); + } + else { + if (event.loseEquip) { + player.addEquipTrigger(); + } + event.goto(4); + } + "step 3" + var info = get.info(cards[num]); + if (info.loseDelay != false && (player.isAlive() || info.forceDie)) { + player.popup(cards[num].name); + game.delayx(); + } + if (Array.isArray(info.onLose)) { + for (var i = 0; i < info.onLose.length; i++) { + var next = game.createEvent("lose_" + cards[num].name); + next.setContent(info.onLose[i]); + if (info.forceDie) next.forceDie = true; + next.player = player; + next.card = cards[num]; + } + } + else { + var next = game.createEvent("lose_" + cards[num].name); + next.setContent(info.onLose); + next.player = player; + if (info.forceDie) next.forceDie = true; + next.card = cards[num]; + } + event.num++; + event.goto(2); + "step 4" + if (event.toRenku) { + _status.renku.addArray(cards.filter(function (card) { + return !card.willBeDestroyed("renku", null, event); + })); + if (_status.renku.length > 6) { + var cards = _status.renku.splice(0, _status.renku.length - 6); + game.log(cards, "从仁库进入了弃牌堆"); + game.cardsDiscard(cards).set("outRange", true).fromRenku = true; + } + game.updateRenku(); + } + "step 5" + var evt = event.getParent(); + if ((evt.name != "discard" && event.type != "discard") && (evt.name != "loseToDiscardpile" && event.type != "loseToDiscardpile")) return; + if (event.animate === false || event.delay === false) return; + if (evt.delay != false) { + if (evt.waitingForTransition) { + _status.waitingForTransition = evt.waitingForTransition; + game.pause(); + } + else { + game.delayx(); + } + } + }, + damage: function () { + "step 0" + event.forceDie = true; + if (event.unreal) { event.goto(4); return; } + event.trigger("damageBegin1"); + "step 1" + event.trigger("damageBegin2"); + "step 2" + event.trigger("damageBegin3"); + "step 3" + event.trigger("damageBegin4"); + "step 4" + //moved changeHujia to changeHp + if (player.hujia > 0 && !player.hasSkillTag("nohujia")) { + var damageAudioInfo = lib.natureAudio.hujia_damage[event.nature]; + if (!damageAudioInfo || damageAudioInfo == "normal") { + damageAudioInfo = "effect/hujia_damage" + (num > 1 ? "2" : "") + ".mp3"; + } else if (damageAudioInfo == "default") { + damageAudioInfo = "effect/hujia_damage_" + event.nature + (num > 1 ? "2" : "") + ".mp3"; + } else { + damageAudioInfo = damageAudioInfo[num > 1 ? 2 : 1]; + } + game.broadcastAll(function (damageAudioInfo) { + if (lib.config.background_audio) game.playAudio(damageAudioInfo); + }, damageAudioInfo); + } else { + var damageAudioInfo = lib.natureAudio.damage[event.nature]; + if (!damageAudioInfo || damageAudioInfo == "normal") { + damageAudioInfo = "effect/damage" + (num > 1 ? "2" : "") + ".mp3"; + } else if (damageAudioInfo == "default") { + damageAudioInfo = "effect/damage_" + event.nature + (num > 1 ? "2" : "") + ".mp3"; + } else { + damageAudioInfo = damageAudioInfo[num > 1 ? 2 : 1]; + } + game.broadcastAll(function (damageAudioInfo) { + if (lib.config.background_audio) game.playAudio(damageAudioInfo); + }, damageAudioInfo); + } + var str = event.unreal ? "视为受到了" : "受到了"; + if (source) str += `来自${source == player ? "自己" : get.translation(source)}的`; + str += get.cnNumber(num) + "点"; + if (event.nature) str += get.translation(event.nature) + "属性"; + str += "伤害"; + game.log(player, str); + if (player.stat[player.stat.length - 1].damaged == undefined) { + player.stat[player.stat.length - 1].damaged = num; + } + else { + player.stat[player.stat.length - 1].damaged += num; + } + if (source) { + source.getHistory("sourceDamage").push(event); + if (source.stat[source.stat.length - 1].damage == undefined) { + source.stat[source.stat.length - 1].damage = num; + } + else { + source.stat[source.stat.length - 1].damage += num; + } + } + player.getHistory("damage").push(event); + if (!event.unreal) { + if (event.notrigger) { + player.changeHp(-num, false)._triggered = null; + } + else { + player.changeHp(-num, false); + } + } + if (event.animate !== false) { + player.$damage(source); + var natures = (event.nature || "").split(lib.natureSeparator); + game.broadcastAll(function (natures, player) { + if (lib.config.animation && !lib.config.low_performance) { + if (natures.includes("fire")) { + player.$fire(); + } + if (natures.includes("thunder")) { + player.$thunder(); + } + } + }, natures, player); + var numx = player.hasSkillTag("nohujia") ? num : Math.max(0, num - player.hujia); + player.$damagepop(-numx, natures[0]); + } + if (event.unreal) event.goto(6) + if (!event.notrigger) { + if (num == 0) { + event.trigger("damageZero"); + event._triggered = null; + } + else { + event.trigger("damage"); + } + } + "step 5" + if (player.hp <= 0 && player.isAlive() && !event.nodying) { + game.delayx(); + event._dyinged = true; + player.dying(event); + } + if (source && lib.config.border_style == "auto") { + var dnum = 0; + for (var j = 0; j < source.stat.length; j++) { + if (source.stat[j].damage != undefined) dnum += source.stat[j].damage; + } + if (dnum >= 2) { + if (lib.config.autoborder_start == "silver") { + dnum += 4; + } + else if (lib.config.autoborder_start == "gold") { + dnum += 8; + } + } + if (lib.config.autoborder_count == "damage") { + source.node.framebg.dataset.decoration = ""; + if (dnum >= 10) { + source.node.framebg.dataset.auto = "gold"; + if (dnum >= 12) source.node.framebg.dataset.decoration = "gold"; + } + else if (dnum >= 6) { + source.node.framebg.dataset.auto = "silver"; + if (dnum >= 8) source.node.framebg.dataset.decoration = "silver"; + } + else if (dnum >= 2) { + source.node.framebg.dataset.auto = "bronze"; + if (dnum >= 4) source.node.framebg.dataset.decoration = "bronze"; + } + if (dnum >= 2) { + source.classList.add("topcount"); + } + } + else if (lib.config.autoborder_count == "mix") { + source.node.framebg.dataset.decoration = ""; + switch (source.node.framebg.dataset.auto) { + case "bronze": if (dnum >= 4) source.node.framebg.dataset.decoration = "bronze"; break; + case "silver": if (dnum >= 8) source.node.framebg.dataset.decoration = "silver"; break; + case "gold": if (dnum >= 12) source.node.framebg.dataset.decoration = "gold"; break; + } + } + } + "step 6" + if (!event.notrigger) event.trigger("damageSource"); + }, + recover: function () { + if (lib.config.background_audio) { + game.playAudio("effect", "recover"); + } + game.broadcast(function () { + if (lib.config.background_audio) { + game.playAudio("effect", "recover"); + } + }); + if (num > player.maxHp - player.hp) { + num = player.maxHp - player.hp; + event.num = num; + } + if (num > 0) { + player.changeHp(num, false); + game.broadcastAll(function (player) { + if (lib.config.animation && !lib.config.low_performance) { + player.$recover(); + } + }, player); + player.$damagepop(num, "wood"); + game.log(player, "回复了" + get.cnNumber(num) + "点体力") + } + }, + loseHp: function () { + "step 0" + if (lib.config.background_audio) { + game.playAudio("effect", "loseHp"); + } + game.broadcast(function () { + if (lib.config.background_audio) { + game.playAudio("effect", "loseHp"); + } + }); + game.log(player, "失去了" + get.cnNumber(num) + "点体力") + player.changeHp(-num); + "step 1" + if (player.hp <= 0 && !event.nodying) { + game.delayx(); + event._dyinged = true; + player.dying(event); + } + }, + doubleDraw: function () { + "step 0" + player.chooseBool("你的主副将体力上限之和是奇数,是否摸一张牌?"); + "step 1" + if (result.bool) { + player.draw(); + } + }, + loseMaxHp: function () { + "step 0" + game.log(player, "减少了" + get.cnNumber(num) + "点体力上限"); + player.maxHp -= num; + event.loseHp = Math.max(0, player.hp - player.maxHp); + player.update(); + "step 1" + if (player.maxHp <= 0) { + player.die(event); + } + }, + gainMaxHp: function () { + "step 0" + game.log(player, "增加了" + get.cnNumber(num) + "点体力上限"); + player.maxHp += num; + player.update(); + }, + changeHp: function () { + //add to GlobalHistory + game.getGlobalHistory().changeHp.push(event); + //changeHujia moved here + if (num < 0 && player.hujia > 0 && event.getParent().name == "damage" && !player.hasSkillTag("nohujia")) { + event.hujia = Math.min(-num, player.hujia); + event.getParent().hujia = event.hujia; + event.num += event.hujia; + //log moved to changeHujia + //game.log(player,"的护甲抵挡了"+get.cnNumber(event.hujia)+"点伤害"); + player.changeHujia(-event.hujia).type = "damage"; + } + //old part + num = event.num; + player.hp += num; + if (isNaN(player.hp)) player.hp = 0; + if (player.hp > player.maxHp) player.hp = player.maxHp; + player.update(); + if (event.popup !== false) { + player.$damagepop(num, "water"); + } + if (_status.dying.contains(player) && player.hp > 0) { + _status.dying.remove(player); + game.broadcast(function (list) { + _status.dying = list; + }, _status.dying); + var evt = event.getParent("_save"); + if (evt && evt.finish) evt.finish(); + evt = event.getParent("dying"); + if (evt && evt.finish) evt.finish() + } + event.trigger("changeHp"); + }, + changeHujia: function () { + if (num > 0) { + game.log(player, "获得了" + get.cnNumber(num) + "点护甲"); + } + else if (num < 0) { + if (-num > player.hujia) { + num = -player.hujia; + event.num = num; + } + switch (event.type) { //log moved here + case "damage": + game.log(player, "的护甲抵挡了" + get.cnNumber(-num) + "点伤害"); + break; + case "lose": + game.log(player, "失去了" + get.cnNumber(-num) + "点护甲"); + break; + } + } + player.hujia += num; + //if(player.hujia<0){ + // player.hujia=0; + //} + player.update(); + }, + dying: function () { + "step 0" + event.forceDie = true; + if (player.isDying() || player.hp > 0) { + event.finish(); + return; + } + _status.dying.unshift(player); + game.broadcast(function (list) { + _status.dying = list; + }, _status.dying); + event.trigger("dying"); + game.log(player, "濒死"); + "step 1" + delete event.filterStop; + if (player.hp > 0 || event.nodying) { + _status.dying.remove(player); + game.broadcast(function (list) { + _status.dying = list; + }, _status.dying); + event.finish(); + } + else if (!event.skipTao) { + var next = game.createEvent("_save"); + var start = false; + var starts = [_status.currentPhase, event.source, event.player, game.me, game.players[0]]; + for (var i = 0; i < starts.length; i++) { + if (get.itemtype(starts[i]) == "player") { + start = starts[i]; break; + } + } + next.player = start; + next._trigger = event; + next.triggername = "_save"; + next.forceDie = true; + next.setContent(lib.skill._save.content); + } + "step 2" + _status.dying.remove(player); + game.broadcast(function (list) { + _status.dying = list; + }, _status.dying); + if (player.hp <= 0 && !event.nodying && !player.nodying) player.die(event.reason); + }, + die: function () { + "step 0" + event.forceDie = true; + if (_status.roundStart == player) { + _status.roundStart = player.next || player.getNext() || game.players[0]; + } + if (ui.land && ui.land.player == player) { + game.addVideo("destroyLand"); + ui.land.destroy(); + } + var unseen = false; + if (player.classList.contains("unseen")) { + player.classList.remove("unseen"); + unseen = true; + } + var logvid = game.logv(player, "die", source); + event.logvid = logvid; + if (unseen) { + player.classList.add("unseen"); + } + if (source) { + game.log(player, "被", source, "杀害"); + if (source.stat[source.stat.length - 1].kill == undefined) { + source.stat[source.stat.length - 1].kill = 1; + } + else { + source.stat[source.stat.length - 1].kill++; + } + } + else { + game.log(player, "阵亡") + } + + + // player.removeEquipTrigger(); + + // for(var i in lib.skill.globalmap){ + // if(lib.skill.globalmap[i].contains(player)){ + // lib.skill.globalmap[i].remove(player); + // if(lib.skill.globalmap[i].length==0&&!lib.skill[i].globalFixed){ + // game.removeGlobalSkill(i); + // } + // } + // } + game.broadcastAll(function (player) { + player.classList.add("dead"); + player.removeLink(); + player.classList.remove("turnedover"); + player.classList.remove("out"); + player.node.count.innerHTML = "0"; + player.node.hp.hide(); + player.node.equips.hide(); + player.node.count.hide(); + player.previous.next = player.next; + player.next.previous = player.previous; + game.players.remove(player); + game.dead.push(player); + _status.dying.remove(player); + + if (lib.config.background_speak) { + if (lib.character[player.name] && lib.character[player.name][4].some(tag => /^die:.+$/.test(tag))) { + var tag = lib.character[player.name][4].find(tag => /^die:.+$/.test(tag)); + var reg = new RegExp("^ext:(.+)?/"); + var match = tag.match(/^die:(.+)$/); + if (match) { + var path = match[1]; + if (reg.test(path)) path = path.replace(reg, (_o, p) => `../extension/${p}/`); + game.playAudio(path); + } + } + else if (lib.character[player.name] && lib.character[player.name][4].some(tag => tag.startsWith("die_audio"))) { + var tag = lib.character[player.name][4].find(tag => tag.startsWith("die_audio")); + var list = tag.split(":").slice(1); + game.playAudio("die", list.length ? list[0] : player.name); + } + else { + game.playAudio("die", player.name, function () { + game.playAudio("die", player.name.slice(player.name.indexOf("_") + 1)); + }); + } + } + }, player); + + game.addVideo("diex", player); + if (event.animate !== false) { + player.$die(source); + } + if (player.hp != 0) { + player.changeHp(0 - player.hp, false).forceDie = true; + } + "step 1" + if (player.dieAfter) player.dieAfter(source); + "step 2" + event.trigger("die"); + "step 3" + if (player.isDead()) { + if (!game.reserveDead) { + for (var mark in player.marks) { + player.unmarkSkill(mark); + } + while (player.node.marks.childNodes.length > 1) { + player.node.marks.lastChild.remove(); + } + game.broadcast(function (player) { + while (player.node.marks.childNodes.length > 1) { + player.node.marks.lastChild.remove(); + } + }, player); + } + for (var i in player.tempSkills) { + player.removeSkill(i); + } + var skills = player.getSkills(); + for (var i = 0; i < skills.length; i++) { + if (lib.skill[skills[i]].temp) { + player.removeSkill(skills[i]); + } + } + if (_status.characterlist) { + if (lib.character[player.name] && !player.name.startsWith("gz_shibing") && !player.name.startsWith("gz_jun_")) _status.characterlist.add(player.name); + if (lib.character[player.name1] && !player.name1.startsWith("gz_shibing") && !player.name1.startsWith("gz_jun_")) _status.characterlist.add(player.name1); + if (lib.character[player.name2] && !player.name2.startsWith("gz_shibing") && !player.name2.startsWith("gz_jun_")) _status.characterlist.add(player.name2); + } + event.cards = player.getCards("hejsx"); + if (event.cards.length) { + player.discard(event.cards).forceDie = true; + //player.$throw(event.cards,1000); + } + } + "step 4" + if (player.dieAfter2) player.dieAfter2(source); + "step 5" + game.broadcastAll(function (player) { + if (game.online && player == game.me && !_status.over && !game.controlOver && !ui.exit) { + if (lib.mode[lib.configOL.mode].config.dierestart) { + ui.create.exit(); + } + } + }, player); + if (!_status.connectMode && player == game.me && !_status.over && !game.controlOver) { + ui.control.show(); + if (get.config("revive") && lib.mode[lib.config.mode].config.revive && !ui.revive) { + ui.revive = ui.create.control("revive", ui.click.dierevive); + } + if (get.config("continue_game") && !ui.continue_game && lib.mode[lib.config.mode].config.continue_game && !_status.brawl && !game.no_continue_game) { + ui.continue_game = ui.create.control("再战", game.reloadCurrent); + } + if (get.config("dierestart") && lib.mode[lib.config.mode].config.dierestart && !ui.restart) { + ui.restart = ui.create.control("restart", game.reload); + } + } + + if (!_status.connectMode && player == game.me && !game.modeSwapPlayer) { + // _status.auto=false; + if (ui.auto) { + // ui.auto.classList.remove("glow"); + ui.auto.hide(); + } + if (ui.wuxie) ui.wuxie.hide(); + } + + if (typeof _status.coin == "number" && source && !_status.auto) { + if (source == game.me || source.isUnderControl()) { + _status.coin += 10; + } + } + if (source && lib.config.border_style == "auto" && (lib.config.autoborder_count == "kill" || lib.config.autoborder_count == "mix")) { + switch (source.node.framebg.dataset.auto) { + case "gold": case "silver": source.node.framebg.dataset.auto = "gold"; break; + case "bronze": source.node.framebg.dataset.auto = "silver"; break; + default: source.node.framebg.dataset.auto = lib.config.autoborder_start || "bronze"; + } + if (lib.config.autoborder_count == "kill") { + source.node.framebg.dataset.decoration = source.node.framebg.dataset.auto; + } + else { + var dnum = 0; + for (var j = 0; j < source.stat.length; j++) { + if (source.stat[j].damage != undefined) dnum += source.stat[j].damage; + } + source.node.framebg.dataset.decoration = ""; + switch (source.node.framebg.dataset.auto) { + case "bronze": if (dnum >= 4) source.node.framebg.dataset.decoration = "bronze"; break; + case "silver": if (dnum >= 8) source.node.framebg.dataset.decoration = "silver"; break; + case "gold": if (dnum >= 12) source.node.framebg.dataset.decoration = "gold"; break; + } + } + source.classList.add("topcount"); + } + }, + addJudge: function () { + "step 0" + if (cards) { + var owner = get.owner(cards[0]); + if (owner) { + event.relatedLose = owner.lose(cards, "visible", ui.special).set("getlx", false); + } + else if (get.position(cards[0]) == "c") event.updatePile = true; + } + "step 1" + if (cards[0].willBeDestroyed("judge", player, event)) { + cards[0].selfDestroy(event); + event.finish(); + return; + } + else if (event.relatedLose) { + var owner = event.relatedLose.player; + if (owner.getCards("hejsx").contains(card)) { + event.finish(); + return; + } + } + cards[0].fix(); + cards[0].style.transform = ""; + cards[0].classList.remove("drawinghidden"); + delete cards[0]._transform; + var viewAs = typeof card == "string" ? card : card.name; + if (!lib.card[viewAs] || !lib.card[viewAs].effect) { + game.cardsDiscard(cards[0]); + } + else { + cards[0].style.transform = ""; + cards[0].classList.add("drawinghidden"); + player.node.judges.insertBefore(cards[0], player.node.judges.firstChild); + if (_status.discarded) { + _status.discarded.remove(cards[0]); + } + ui.updatej(player); + game.broadcast(function (player, card, viewAs) { + card.fix(); + card.style.transform = ""; + card.classList.add("drawinghidden"); + card.viewAs = viewAs; + if (viewAs && viewAs != card.name && (card.classList.contains("fullskin") || card.classList.contains("fullborder"))) { + card.classList.add("fakejudge"); + card.node.background.innerHTML = lib.translate[viewAs + "_bg"] || get.translation(viewAs)[0] + } + else { + card.classList.remove("fakejudge"); + } + player.node.judges.insertBefore(card, player.node.judges.firstChild); + ui.updatej(player); + if (card.clone && (card.clone.parentNode == player.parentNode || card.clone.parentNode == ui.arena)) { + card.clone.moveDelete(player); + game.addVideo("gain2", player, get.cardsInfo([card])); + } + }, player, cards[0], viewAs); + if (cards[0].clone && (cards[0].clone.parentNode == player.parentNode || cards[0].clone.parentNode == ui.arena)) { + cards[0].clone.moveDelete(player); + game.addVideo("gain2", player, get.cardsInfo(cards)); + } + // player.$gain2(cards); + if (get.itemtype(card) != "card") { + if (typeof card == "string") cards[0].viewAs = card; + else cards[0].viewAs = card.name; + } + else { + delete cards[0].viewAs; + } + if (cards[0].viewAs && cards[0].viewAs != cards[0].name) { + if (cards[0].classList.contains("fullskin") || cards[0].classList.contains("fullborder")) { + cards[0].classList.add("fakejudge"); + cards[0].node.background.innerHTML = lib.translate[cards[0].viewAs + "_bg"] || get.translation(cards[0].viewAs)[0]; + } + game.log(player, `被贴上了${get.translation(cards[0].viewAs)}(`, cards, ")"); + } + else { + cards[0].classList.remove("fakejudge"); + game.log(player, "被贴上了", cards); + } + game.addVideo("addJudge", player, [get.cardInfo(cards[0]), cards[0].viewAs]); + } + if (event.updatePile) game.updateRoundNumber(); + }, + judge: function () { + "step 0" + var judgestr = get.translation(player) + "的" + event.judgestr + "判定"; + event.videoId = lib.status.videoId++; + var cardj = event.directresult; + if (!cardj) { + if (player.getTopCards) cardj = player.getTopCards()[0]; + else cardj = get.cards()[0]; + } + var owner = get.owner(cardj); + if (owner) { + owner.lose(cardj, "visible", ui.ordering); + } + else { + var nextj = game.cardsGotoOrdering(cardj); + if (event.position != ui.discardPile) nextj.noOrdering = true; + } + player.judging.unshift(cardj); + game.addVideo("judge1", player, [get.cardInfo(player.judging[0]), judgestr, event.videoId]); + game.broadcastAll(function (player, card, str, id, cardid) { + var event; + if (game.online) { + event = {}; + } + else { + event = _status.event; + } + if (game.chess) { + event.node = card.copy("thrown", "center", ui.arena).animate("start"); + } + else { + event.node = player.$throwordered(card.copy(), true); + } + if (lib.cardOL) lib.cardOL[cardid] = event.node; + event.node.cardid = cardid; + event.node.classList.add("thrownhighlight"); + ui.arena.classList.add("thrownhighlight"); + event.dialog = ui.create.dialog(str); + event.dialog.classList.add("center"); + event.dialog.videoId = id; + }, player, player.judging[0], judgestr, event.videoId, get.id()); + + game.log(player, "进行" + event.judgestr + "判定,亮出的判定牌为", player.judging[0]); + game.delay(2); + if (!event.noJudgeTrigger) event.trigger("judge"); + "step 1" + event.result = { + card: player.judging[0], + name: player.judging[0].name, + number: get.number(player.judging[0]), + suit: get.suit(player.judging[0]), + color: get.color(player.judging[0]), + node: event.node, + }; + if (event.fixedResult) { + for (var i in event.fixedResult) { + event.result[i] = event.fixedResult[i]; + } + } + event.result.judge = event.judge(event.result); + if (event.result.judge > 0) event.result.bool = true; + else if (event.result.judge < 0) event.result.bool = false; + else event.result.bool = null; + player.judging.shift(); + game.checkMod(player, event.result, "judge", player); + if (event.judge2) { + var judge2 = event.judge2(event.result); + if (typeof judge2 == "boolean") player.tryJudgeAnimate(judge2); + } + if (event.clearArena != false) { + game.broadcastAll(ui.clear); + } + game.broadcast(function (id) { + var dialog = get.idDialog(id); + if (dialog) { + dialog.close(); + } + ui.arena.classList.remove("thrownhighlight"); + }, event.videoId); + event.dialog.close(); + game.addVideo("judge2", null, event.videoId); + ui.arena.classList.remove("thrownhighlight"); + game.log(player, "的判定结果为", event.result.card); + event.trigger("judgeFixing"); + if (event.callback) { + var next = game.createEvent("judgeCallback", false); + next.player = player; + next.card = event.result.card; + next.judgeResult = get.copy(event.result); + next.setContent(event.callback); + } + else { + if (!get.owner(event.result.card)) { + if (event.position != ui.discardPile) event.position.appendChild(event.result.card); + } + } + }, + turnOver: function () { + game.log(player, "翻面"); + player.classList.toggle("turnedover"); + game.broadcast(function (player) { + player.classList.toggle("turnedover"); + }, player); + game.addVideo("turnOver", player, player.classList.contains("turnedover")); + }, + link: function () { + if (player.isLinked()) { + game.log(player, "解除连环"); + } + else { + game.log(player, "被连环"); + } + if (lib.config.background_audio) { + game.playAudio("effect", "link"); + } + game.broadcast(function () { + if (lib.config.background_audio) { + game.playAudio("effect", "link"); + } + }); + player.classList.remove("target"); + if (get.is.linked2(player)) { + player.classList.toggle("linked2"); + } + else { + player.classList.toggle("linked"); + } + ui.updatej(player); + ui.updatem(player); + game.broadcast(function (player, linked) { + player.classList.remove("target"); + if (get.is.linked2(player)) { + if (linked) { + player.classList.add("linked2"); + } + else { + player.classList.remove("linked2"); + } + } + else { + if (linked) { + player.classList.add("linked"); + } + else { + player.classList.remove("linked"); + } + } + ui.updatej(player); + ui.updatem(player); + }, player, player.isLinked()); + game.addVideo("link", player, player.isLinked()); + }, + chooseToGuanxing: function () { + "step 0" + var cards = get.cards(num); + game.cardsGotoOrdering(cards); + var next = player.chooseToMove(); + next.set("list", [ + ["牌堆顶", cards], + ["牌堆底"], + ]); + next.set("prompt", "点击将牌移动到牌堆顶或牌堆底"); + next.processAI = event.processAI || function (list) { + var cards = list[0][1], player = _status.event.player; + var top = []; + var bottom; + cards.sort(function (a, b) { + return get.value(b, player) - get.value(a, player); + }); + while (cards.length) { + if (get.value(cards[0], player) <= 5) break; + top.unshift(cards.shift()); + } + bottom = cards; + return [top, bottom]; + }; + "step 1" + var top = result.moved[0]; + var bottom = result.moved[1]; + top.reverse(); + for (var i = 0; i < top.length; i++) { + ui.cardPile.insertBefore(top[i], ui.cardPile.firstChild); + } + for (i = 0; i < bottom.length; i++) { + ui.cardPile.appendChild(bottom[i]); + } + game.addCardKnower(top, player); + game.addCardKnower(bottom, player); + player.popup(get.cnNumber(top.length) + "上" + get.cnNumber(bottom.length) + "下"); + game.log(player, "将" + get.cnNumber(top.length) + "张牌置于牌堆顶"); + game.updateRoundNumber(); + game.delayx(); + }, + }, + Player, + Card, + VCard, + Button, + GameEvent, + GameEventPromise, + Dialog, + Control, + Client, + NodeWS, + WS, + /** + * @legacy Use {@link lib.element.Player.prototype} instead. + */ + get player() { + return this.Player.prototype; + }, + /** + * @legacy Use {@link lib.element.Card.prototype} instead. + */ + get card() { + return this.Card.prototype; + }, + /** + * @legacy Use {@link lib.element.Button.prototype} instead. + */ + get button() { + return this.Button.prototype; + }, + /** + * @legacy Use {@link lib.element.GameEvent.prototype} instead. + */ + get event() { + return this.GameEvent.prototype; + }, + /** + * @legacy Use {@link lib.element.Dialog.prototype} instead. + */ + get dialog() { + return this.Dialog.prototype; + }, + /** + * @legacy Use {@link lib.element.Control.prototype} instead. + */ + get control() { + return this.Control.prototype; + }, + /** + * @legacy Use {@link lib.element.Client.prototype} instead. + */ + get client() { + return this.Client.prototype; + }, + /** + * @legacy Use {@link lib.element.NodeWS.prototype} instead. + */ + get nodews() { + return this.NodeWS.prototype; + } +}; diff --git a/noname/library/element/button.js b/noname/library/element/button.js new file mode 100644 index 000000000..9a978cd55 --- /dev/null +++ b/noname/library/element/button.js @@ -0,0 +1,30 @@ +export class Button extends HTMLDivElement { + /** + * @param {{}} item + * @param {keyof typeof ui.create.buttonPresets | (item: {}, type: Function, position?: HTMLDivElement, noClick?: true, button?: HTMLDivElement) => HTMLDivElement} type + * @param {HTMLDivElement} [position] + * @param {true} [noClick] + * @param {HTMLDivElement} [button] + */ + constructor(item, type, position, noClick, button) { + if (ui.create.buttonPresets[type]) button = ui.create.buttonPresets[type](item, type, position, noClick, button); + else if (typeof type == "function") button = type(item, type, position, noClick, button); + Object.setPrototypeOf(button, lib.element.Button.prototype); + if (!noClick) button.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.button); + else { + button.classList.add("noclick"); + const intro = button.querySelector(".intro"); + if (intro) intro.remove(); + } + return button; + } + exclude() { + if (_status.event.excludeButton == undefined) { + _status.event.excludeButton = []; + } + _status.event.excludeButton.add(this); + } + get updateTransform() { + return lib.element.Card.prototype.updateTransform; + } +} diff --git a/noname/library/element/card.js b/noname/library/element/card.js new file mode 100644 index 000000000..e8b08c4bd --- /dev/null +++ b/noname/library/element/card.js @@ -0,0 +1,775 @@ +export class Card extends HTMLDivElement { + /** + * @param {HTMLDivElement} [position] + * @param {"noclick"} [info] + * @param {true} [noclick] + */ + constructor(position, info, noclick) { + const card = ui.create.div(".card", position); + Object.setPrototypeOf(card, lib.element.Card.prototype); + card.build(info, noclick); + return card; + } + build(info, noclick) { + let card = this; + card.buildNode(); + card.buildIntro(noclick); + card.buildProperty(); + card.buildEventListener(info); + } + buildEventListener(info) { + let card = this; + if (info != "noclick") { + card.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.card); + if (lib.config.touchscreen) { + card.addEventListener("touchstart", ui.click.cardtouchstart); + card.addEventListener("touchmove", ui.click.cardtouchmove); + } + if (lib.cardSelectObserver) lib.cardSelectObserver.observe(card, { + attributes: true + }); + } + } + buildProperty() { + let card = this; + card.storage = {}; + card.vanishtag = []; + card.gaintag = []; + card._uncheck = []; + } + buildNode() { + this.node = { + image: ui.create.div(".image", this), + info: ui.create.div(".info", this), + name: ui.create.div(".name", this), + name2: ui.create.div(".name2", this), + background: ui.create.div(".background", this), + intro: ui.create.div(".intro", this), + range: ui.create.div(".range", this), + gaintag: ui.create.div(".gaintag", this), + }; + this.node.intro.innerHTML = lib.config.intro; + } + buildIntro(noclick) { + if (!noclick) lib.setIntro(this); + } + //执行销毁一张牌的钩子函数 + selfDestroy(event) { + if (this._selfDestroyed) return; + this._selfDestroyed = true; + this.fix(); + this.delete(); + const info = get.info(this, false); + if (!info) return; + if (info.destroyLog !== false) game.log(this, "被销毁了"); + if (info.onDestroy) info.onDestroy(this, event); + } + //判断一张牌进入某个区域后是否会被销毁 + willBeDestroyed(targetPosition, player, event) { + const destroyed = this.destroyed; + if (typeof destroyed == "function") { + return destroyed(this, targetPosition, player, event); + } + else if (lib.skill[destroyed]) { + if (player) { + if (player.hasSkill(destroyed)) { + delete this.destroyed; + return false; + } + } + return true; + } + else if (typeof destroyed == "string") { + return (destroyed == targetPosition); + } + return destroyed; + } + hasNature(nature, player) { + return game.hasNature(this, nature, player); + } + //只针对【杀】起效果 + addNature(nature) { + let natures = []; + if (!this.nature) this.nature = ""; + else { + natures.addArray(get.natureList(this.nature)); + } + natures.addArray(get.natureList(nature)); + this.nature = get.nature(natures); + this.classList.add(nature); + let str = get.translation(this.nature) + "杀"; + this.node.name.innerText = str; + let name = get.name(this, false); + do { + if (name == "sha") { + let _bg; + for (const n of natures) if (lib.natureBg.has(n)) _bg = n; + if (_bg) { + this.node.image.setBackgroundImage(lib.natureBg.get(_bg)); + break; + } + } + this.node.image.setBackgroundImage("image/card/" + name + ".png"); + } + while (0); + return this.nature; + } + removeNature(nature) { + if (!this.nature) return; + let natures = get.natureList(this.nature); + natures.remove(nature); + if (!natures.length) delete this.nature; + else this.nature = get.nature(natures); + this.classList.remove(nature); + let str = get.translation(this.nature) + "杀"; + this.node.name.innerText = str; + let name = get.name(this, false); + do { + if (name == "sha") { + let _bg; + for (const n of natures) if (lib.natureBg.has(n)) _bg = n; + if (_bg) { + this.node.image.setBackgroundImage(lib.natureBg.get(_bg)); + break; + } + } + this.node.image.setBackgroundImage("image/card/" + name + ".png"); + } + while (0); + return this.nature; + } + addGaintag(gaintag) { + if (Array.isArray(gaintag)) this.gaintag = gaintag.slice(0); + else this.gaintag.add(gaintag); + var str = ""; + for (var gi = 0; gi < this.gaintag.length; gi++) { + var translate = get.translation(this.gaintag[gi]); + if (translate != "invisible") { + str += translate; + if (gi < this.gaintag.length - 1) str += " "; + } + } + this.node.gaintag.innerHTML = str; + } + removeGaintag(tag) { + if (tag === true) { + if (this.gaintag && this.gaintag.length || this.node.gaintag.innerHTML.length) this.addGaintag([]); + } + else if (this.hasGaintag(tag)) { + this.gaintag.remove(tag); + this.addGaintag(this.gaintag); + } + } + hasGaintag(tag) { + return this.gaintag && this.gaintag.contains(tag); + } + /** + * @param {[string, number, string, string] | { + * suit: string; + * number: number; + * name: string; + * nature: string; + * }} card + */ + init(card) { + if (Array.isArray(card)) { + if (card[2] == "huosha") { + card[2] = "sha"; + card[3] = "fire"; + } + else if (card[2] == "leisha") { + card[2] = "sha"; + card[3] = "thunder"; + } + else if (card[2] == "cisha") { + card[2] = "sha"; + card[3] = "stab"; + } + else if (card[2].length > 3) { + let prefix = card[2].slice(0, card[2].lastIndexOf("sha")); + if (lib.nature.has(prefix)) { + if (prefix.length + 3 == card[2].length) { + card[2] = "sha"; + card[3] = prefix; + } + } + if (card[2].startsWith("sha_")) { + let suffix = card[2].slice(4); + let natureList = suffix.split("_"); + card[2] = "sha"; + card[3] = get.nature(natureList); + } + } + } + else if (typeof card == "object") { + card = [card.suit, card.number, card.name, card.nature]; + } + var cardnum = card[1] || ""; + if (parseInt(cardnum) == cardnum) cardnum = parseInt(cardnum); + + if (!lib.card[card[2]]) { + lib.card[card[2]] = {}; + } + var info = lib.card[card[2]]; + if (info.global && !this.classList.contains("button")) { + if (Array.isArray(info.global)) { + while (info.global.length) { + game.addGlobalSkill(info.global.shift()); + } + } + else if (typeof info.global == "string") { + game.addGlobalSkill(info.global); + } + delete info.global; + } + this.suit = card[0]; + this.number = parseInt(card[1]) || 0; + this.name = card[2]; + + if (info.destroy && (typeof info.destroy != "boolean" && !lib.skill[info.destroy])) { + this.destroyed = info.destroy; + } + + if (_status.connectMode && !game.online && lib.cardOL && !this.cardid) { + this.cardid = get.id(); + lib.cardOL[this.cardid] = this; + } + if (!_status.connectMode && !_status.video) { + this.cardid = get.id(); + } + + this.$init(card); + + if (this.inits) { + for (var i = 0; i < this.inits.length; i++) { + this.inits[i](this); + } + } + if (typeof info.init == "function") info.init(); + + return this; + } + /** + * @param {[string, number, string, string]} card + */ + $init(card) { + var info = lib.card[card[2]]; + var cardnum = card[1] || ""; + if (parseInt(cardnum) == cardnum) cardnum = parseInt(cardnum); + if (cardnum > 0 && cardnum < 14) { + cardnum = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"][cardnum - 1]; + } + if (this.name) { + this.classList.remove("epic"); + this.classList.remove("legend"); + this.classList.remove("gold"); + this.classList.remove("unique"); + this.style.background = ""; + var subtype = get.subtype(this, false); + if (subtype) { + this.classList.remove(subtype); + } + } + if (info.epic) { + this.classList.add("epic"); + } + else if (info.legend) { + this.classList.add("legend"); + } + else if (info.gold) { + this.classList.add("gold"); + } + else if (info.unique) { + this.classList.add("unique"); + } + var bg = card[2]; + if (info.cardimage) { + bg = info.cardimage; + } + var img = lib.card[bg].image; + if (img) { + if (img.startsWith("db:")) { + img = img.slice(3); + } + else if (!img.startsWith("ext:")) { + img = null; + } + } + this.classList.remove("fullskin"); + this.classList.remove("fullimage"); + this.classList.remove("fullborder"); + this.dataset.cardName = card[2]; + this.dataset.cardType = info.type || ""; + this.dataset.cardSubype = info.subtype || ""; + this.dataset.cardMultitarget = info.multitarget ? "1" : "0"; + this.node.name.dataset.nature = ""; + this.node.info.classList.remove("red"); + if (!lib.config.hide_card_image && lib.card[bg].fullskin) { + this.classList.add("fullskin"); + if (img) { + if (img.startsWith("ext:")) { + this.node.image.setBackgroundImage(img.replace(/^ext:/, "extension/")); + } + else { + this.node.image.setBackgroundDB(img); + } + } + else { + if (lib.card[bg].modeimage) { + this.node.image.setBackgroundImage("image/mode/" + lib.card[bg].modeimage + "/card/" + bg + ".png"); + } + else { + do { + let nature = card[3]; + if (bg == "sha" && typeof nature == "string") { + let natures = get.natureList(nature), _bg; + for (const n of natures) if (lib.natureBg.has(n)) _bg = n; + if (_bg) { + this.node.image.setBackgroundImage(lib.natureBg.get(_bg)); + break; + } + } + this.node.image.setBackgroundImage("image/card/" + bg + ".png"); + } + while (0); + } + } + } + else if (lib.card[bg].image == "background") { + if (card[3]) this.node.background.setBackground(bg + "_" + get.natureList(card[3])[0], "card"); + else this.node.background.setBackground(bg, "card"); + } + else if (lib.card[bg].fullimage) { + this.classList.add("fullimage"); + if (img) { + if (img.startsWith("ext:")) { + this.setBackgroundImage(img.replace(/^ext:/, "extension/")); + this.style.backgroundSize = "cover"; + } + else { + this.setBackgroundDB(img); + } + } + else if (lib.card[bg].image) { + if (lib.card[bg].image.startsWith("character:")) { + this.setBackground(lib.card[bg].image.slice(10), "character"); + } + else { + this.setBackground(lib.card[bg].image); + } + } + else { + var cardPack = lib.cardPack["mode_" + get.mode()]; + if (Array.isArray(cardPack) && cardPack.contains(bg)) { + this.setBackground("mode/" + get.mode() + "/card/" + bg); + } + else { + this.setBackground("card/" + bg); + } + } + } + else if (lib.card[bg].fullborder) { + this.classList.add("fullborder"); + if (lib.card[bg].fullborder == "gold") { + this.node.name.dataset.nature = "metalmm"; + } + else if (lib.card[bg].fullborder == "silver") { + this.node.name.dataset.nature = "watermm"; + } + if (!this.node.avatar) { + this.node.avatar = ui.create.div(".cardavatar"); + this.insertBefore(this.node.avatar, this.firstChild); + } + if (!this.node.framebg) { + this.node.framebg = ui.create.div(".cardframebg"); + this.node.framebg.dataset.auto = lib.card[bg].fullborder; + this.insertBefore(this.node.framebg, this.firstChild); + } + if (img) { + if (img.startsWith("ext:")) { + this.node.avatar.setBackgroundImage(img.replace(/^ext:/, "extension/")); + this.node.avatar.style.backgroundSize = "cover"; + } + else { + this.node.avatar.setBackgroundDB(img); + } + } + else if (lib.card[bg].image) { + if (lib.card[bg].image.startsWith("character:")) { + this.node.avatar.setBackground(lib.card[bg].image.slice(10), "character"); + } + else { + this.node.avatar.setBackground(lib.card[bg].image); + } + } + else { + var cardPack = lib.cardPack["mode_" + get.mode()]; + if (Array.isArray(cardPack) && cardPack.contains(bg)) { + this.node.avatar.setBackground("mode/" + get.mode() + "/card/" + bg); + } + else { + this.node.avatar.setBackground("card/" + bg); + } + } + } + else if (lib.card[bg].image == "card") { + if (card[3]) this.setBackground(bg + "_" + get.natureList(card[3])[0], "card"); + else this.setBackground(bg, "card"); + } + else if (typeof lib.card[bg].image == "string" && !lib.card[bg].fullskin) { + if (img) { + if (img.startsWith("ext:")) { + this.setBackgroundImage(img.replace(/^ext:/, "extension/")); + this.style.backgroundSize = "cover"; + } + else { + this.setBackgroundDB(img); + } + } + else { + this.setBackground(lib.card[bg].image); + } + } + else { + this.node.background.innerHTML = lib.translate[bg + "_cbg"] || lib.translate[bg + "_bg"] || get.translation(bg)[0]; + // this.node.background.style.fontFamily=lib.config.card_font; + if (this.node.background.innerHTML.length > 1) this.node.background.classList.add("tight"); + else this.node.background.classList.remove("tight"); + } + if (!lib.card[bg].fullborder && this.node.avatar && this.node.framebg) { + this.node.avatar.remove(); + this.node.framebg.remove(); + delete this.node.avatar; + delete this.node.framebg; + } + if (info.noname && !this.classList.contains("button")) { + this.node.name.style.display = "none"; + } + if (info.color) { + this.style.color = info.color; + } + if (info.textShadow) { + this.style.textShadow = info.textShadow; + } + if (info.opacity) { + this.node.info.style.opacity = info.opacity; + this.node.name.style.opacity = info.opacity; + } + if (info.modinfo) { + this.node.info.innerHTML = info.modinfo; + } + else { + this.node.info.innerHTML = `${get.translation(card[0])} ${cardnum}`; + } + if (info.addinfo) { + if (!this.node.addinfo) { + this.node.addinfo = ui.create.div(".range", this); + } + this.node.addinfo.innerHTML = info.addinfo; + } + else if (this.node.addinfo) { + this.node.addinfo.remove(); + delete this.node.addinfo; + } + if (card[0] == "heart" || card[0] == "diamond") { + this.node.info.classList.add("red"); + } + this.node.image.className = "image"; + var name = get.translation(card[2]); + if (card[2] == "sha") { + name = ""; + let nature = card[3]; + if (nature) { + let natures = get.natureList(nature); + natures.sort(lib.sort.nature); + for (let nature of natures) { + name += lib.translate["nature_" + nature] || lib.translate[nature] || ""; + if (nature != "stab") this.node.image.classList.add(nature); + } + } + name += "杀"; + } + this.node.name.innerHTML = name; + if (name.length >= 5) { + this.node.name.classList.add("long"); + if (name.length >= 7) { + this.node.name.classList.add("longlong"); + } + } + this.node.name2.innerHTML = get.translation(card[0]) + cardnum + " " + name; + this.classList.add("card"); + if (card[3]) { + let natures = get.natureList(card[3]); + natures.forEach(n => { if (n) this.classList.add(n) }); + this.nature = natures.filter(n => lib.nature.has(n)).sort(lib.sort.nature).join(lib.natureSeparator); + } + else if (this.nature) { + this.classList.remove(this.nature); + delete this.nature; + } + if (info.subtype) this.classList.add(info.subtype); + this.node.range.innerHTML = ""; + switch (get.subtype(this, false)) { + case "equip1": + var added = false; + if (lib.card[this.name] && lib.card[this.name].distance) { + var dist = lib.card[this.name].distance; + if (dist.attackFrom) { + added = true; + this.node.range.innerHTML = "范围: " + (-dist.attackFrom + 1); + } + } + if (!added) { + this.node.range.innerHTML = "范围: 1"; + } + break; + case "equip3": + if (info.distance && info.distance.globalTo) { + this.node.range.innerHTML = "防御: " + info.distance.globalTo; + this.node.name2.innerHTML += "+"; + } + break; + case "equip4": + if (info.distance && info.distance.globalFrom) { + this.node.range.innerHTML = "进攻: " + (-info.distance.globalFrom); + this.node.name2.innerHTML += "-"; + } + break; + } + var tags = []; + if (Array.isArray(card[4])) { + tags.addArray(card[4]); + } + if (this.cardid) { + if (!_status.cardtag) { + _status.cardtag = {}; + } + for (var i in _status.cardtag) { + if (_status.cardtag[i].contains(this.cardid)) { + tags.add(i); + } + } + if (tags.length) { + var tagstr = ` `; + for (var i = 0; i < tags.length; i++) { + var tag = tags[i]; + if (!_status.cardtag[tag]) { + _status.cardtag[tag] = []; + } + _status.cardtag[tag].add(this.cardid); + tagstr += lib.translate[tag + "_tag"]; + //if(i this._knowers.add(p.playerid)); + } + } + } + removeKnower(player) { + if (!this._knowers) { + return; + } + if (typeof player == "string") { + this._knowers.remove(player); + } else { + let type = get.itemtype(player); + if (type == "player") { + this._knowers.remove(player.playerid); + } else if (type == "players") { + player.forEach(p => this._knowers.remove(p.playerid)); + } + } + } + //清除此牌的知情者。 + clearKnowers() { + if (this._knowers) delete this._knowers; + } + //判断玩家对此牌是否知情。 + isKnownBy(player) { + if (["e", "j"].includes(get.position(this))) return true;//装备区或者判定区的牌,必知情。 + let owner = get.owner(this); + if (owner) { + if (owner == player) return true;//是牌主,必知情。 + if (player.hasSkillTag("viewHandcard", null, owner, true)) return true;//有viewHandcard标签,必知情。 + if (owner.isUnderControl(true, player)) return true;//被操控,必知情。 + } + if (get.is.shownCard(this)) return true;//此牌是明置牌,必知情。 + if (this._knowers) { + return this._knowers.includes("everyone") || this._knowers.includes(player.playerid); + } + return false; + } + getSource(name) { + if (this.name == name) return true; + var info = lib.card[this.name]; + if (info && Array.isArray(info.source)) { + return info.source.contains(name); + } + return false; + } + moveDelete(player) { + this.fixed = true; + if (!this._listeningEnd || this._transitionEnded) { + this.moveTo(player); + var that = this; + setTimeout(function () { + that.delete(); + }, 200); + } + else { + this._onEndMoveDelete = player; + } + } + moveTo(player) { + this.fixed = true; + var dx, dy; + if (this.classList.contains("center")) { + var nx = [50, -52]; + var ny = [50, -52]; + nx = nx[0] * ui.arena.offsetWidth / 100 + nx[1]; + ny = ny[0] * ui.arena.offsetHeight / 100 + ny[1]; + dx = player.getLeft() + player.offsetWidth / 2 - 52 - nx; + dy = player.getTop() + player.offsetHeight / 2 - 52 - ny; + } + else { + this.style.left = this.offsetLeft + "px"; + this.style.top = this.offsetTop + "px"; + + dx = player.getLeft() + player.offsetWidth / 2 - 52 - this.offsetLeft; + dy = player.getTop() + player.offsetHeight / 2 - 52 - this.offsetTop; + } + if (get.is.mobileMe(player)) { + dx += get.cardOffset(); + if (ui.arena.classList.contains("oblongcard")) { + dy -= 16; + } + } + + + if (this.style.transform && this.style.transform != "none" && this.style.transform.indexOf("translate") == -1) { + this.style.transform += " translate(" + dx + "px," + dy + "px)"; + } + else { + this.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + return this; + } + copy() { + /** + * @type {Card} + */ + var node = this.cloneNode(true); + node.style.transform = ""; + node.name = this.name; + node.suit = this.suit; + node.number = this.number; + node.nature = this.nature; + node.classList.remove("hidden"); + node.classList.remove("start"); + node.classList.remove("thrown"); + node.classList.remove("selectable"); + node.classList.remove("selected"); + node.classList.remove("removing"); + node.classList.remove("drawinghidden"); + node.classList.remove("glows"); + node.node = { + name: node.querySelector(".name"), + info: node.querySelector(".info"), + intro: node.querySelector(".intro"), + background: node.querySelector(".background"), + image: node.querySelector(".image"), + gaintag: node.querySelector(".gaintag"), + } + node.node.gaintag.innerHTML = ""; + var clone = true; + var position; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") node.classList.add(arguments[i]); + else if (get.objtype(arguments[i]) == "div") position = arguments[i]; + else if (typeof arguments[i] == "boolean") clone = arguments[i]; + } + node.moveTo = lib.element.Card.prototype.moveTo; + node.moveDelete = lib.element.Card.prototype.moveDelete; + if (clone) this.clone = node; + if (position) position.appendChild(node); + return node; + } + uncheck(skill) { + if (skill) this._uncheck.add(skill); + this.classList.add("uncheck"); + } + recheck(skill) { + if (skill) this._uncheck.remove(skill); + else this._uncheck.length = 0; + if (this._uncheck.length == 0) this.classList.remove("uncheck"); + } + discard(bool) { + if (!this._selfDestroyed) { + this.fix(); + ui.discardPile.appendChild(this); + } + this.classList.remove("glow"); + if (bool === false) { + ui.cardPile.insertBefore(this, ui.cardPile.childNodes[Math.floor(Math.random() * ui.cardPile.childNodes.length)]); + } + else { + if (_status.discarded) { + _status.discarded.add(this); + } + } + } + hasTag(tag) { + if (this.cardid && _status.cardtag && _status.cardtag[tag] && _status.cardtag[tag].contains(this.cardid)) { + return true; + } + return false; + } + hasPosition() { + return ["h", "e", "j", "s", "x"].contains(get.position(this)); + } + isInPile() { + return ["c", "d"].contains(get.position(this)); + } +} diff --git a/noname/library/element/client.js b/noname/library/element/client.js new file mode 100644 index 000000000..c35ce4eee --- /dev/null +++ b/noname/library/element/client.js @@ -0,0 +1,61 @@ +export class Client { + /** + * @param {NodeWS | InstanceType} ws + */ + constructor(ws) { + this.ws = ws; + this.id = ws.wsid || get.id(); + this.closed = false; + } + send() { + if (this.closed) return this; + var args = Array.from(arguments); + if (typeof args[0] == "function") { + args.unshift("exec"); + } + for (var i = 1; i < args.length; i++) { + args[i] = get.stringifiedResult(args[i]); + } + try { + this.ws.send(JSON.stringify(args)); + } + catch (e) { + this.ws.close(); + } + return this; + } + close() { + lib.node.clients.remove(this); + lib.node.observing.remove(this); + if (ui.removeObserve && !lib.node.observing.length) { + ui.removeObserve.remove(); + delete ui.removeObserve; + } + this.closed = true; + if (_status.waitingForPlayer) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == this.id) { + game.connectPlayers[i].uninitOL(); + delete game.connectPlayers[i].playerid; + } + } + if (game.onlinezhu == this.id) { + game.onlinezhu = null; + } + game.updateWaiting(); + } + else if (lib.playerOL[this.id]) { + var player = lib.playerOL[this.id]; + player.setNickname(player.nickname + " - 离线"); + game.broadcast(function (player) { + player.setNickname(player.nickname + " - 离线"); + }, player); + player.unwait("ai"); + } + + if (window.isNonameServer) { + document.querySelector("#server_count").innerHTML = lib.node.clients.length; + } + return this; + } +} diff --git a/noname/library/element/control.js b/noname/library/element/control.js new file mode 100644 index 000000000..a206dcee2 --- /dev/null +++ b/noname/library/element/control.js @@ -0,0 +1,119 @@ +export class Control extends HTMLDivElement { + constructor() { + const nc = !ui.control.querySelector("div:not(.removing):not(.stayleft)"); + const controls = Array.isArray(arguments[0]) ? arguments[0] : Array.from(arguments); + const control = ui.create.div(".control"); + Object.setPrototypeOf(control, lib.element.Control.prototype); + ui.control.insertBefore(control, _status.createControl || ui.confirm); + controls.forEach(argument => { + if (argument == "nozoom") return; + if (typeof argument == "function") control.custom = argument; + else if (argument == "stayleft") { + control.stayleft = true; + control.classList.add("stayleft"); + } + else control.add(argument); + }); + ui.controls.unshift(control); + if (nc) ui.control.animate("nozoom", 100); + if (control.childNodes.length) { + control.style.transition = "opacity 0.5s"; + control.animate("controlpressdownx", 500); + ui.refresh(control); + if (!control.stayleft) control.style.transform = `translateX(-${control.offsetWidth / 2}px)`; + control.style.opacity = 1; + ui.refresh(control); + control.style.transition = ""; + } + + control.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.control2); + + if (lib.config.button_press) { + control.addEventListener(lib.config.touchscreen ? "touchstart" : "mousedown", function () { + if (this.classList.contains("disabled")) return; + this.classList.add("controlpressdown"); + if (typeof this._offset == "number") this.style.transform = `translateX(${this._offset}px) scale(0.97)`; + }); + control.addEventListener(lib.config.touchscreen ? "touchend" : "mouseup", function () { + this.classList.remove("controlpressdown"); + if (typeof this._offset == "number") this.style.transform = `translateX(${this._offset}px)`; + }); + } + + ui.updatec(); + return control; + } + open() { + ui.control.insertBefore(this, _status.createControl || ui.confirm); + ui.controls.unshift(this); + if (this.childNodes.length) { + this.style.transition = "opacity 0.5s"; + ui.refresh(this); + this.style.transform = "translateX(-" + (this.offsetWidth / 2) + "px)"; + this.style.opacity = 1; + ui.refresh(this); + this.style.transition = ""; + } + else { + this.animate("controlpressdownx", 500); + } + ui.updatec(); + return this; + } + add(item) { + var node = document.createElement("div"); + this.appendChild(node); + node.link = item; + node.innerHTML = get.translation(item); + node.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.control); + } + close() { + this.animate("controlpressdownx", 500); + + ui.controls.remove(this); + this.delete(); + + setTimeout(ui.updatec, 100); + + + if (ui.confirm == this) delete ui.confirm; + if (ui.skills == this) delete ui.skills; + if (ui.skills2 == this) delete ui.skills2; + if (ui.skills3 == this) delete ui.skills3; + } + replace() { + // this.animate("controlpressdownx",500); + if (this.replaceTransition === false) { + this.style.transitionProperty = "none"; + ui.refresh(this); + } + + while (this.childNodes.length) this.firstChild.remove(); + var i, controls; + if (Array.isArray(arguments[0])) controls = arguments[0]; + else controls = arguments; + delete this.custom; + for (i = 0; i < controls.length; i++) { + if (typeof controls[i] == "function") { + this.custom = controls[i]; + } + else { + this.add(controls[i]); + } + } + if (this.childNodes.length) { + var width = 0; + for (i = 0; i < this.childNodes.length; i++) width += this.childNodes[i].offsetWidth; + ui.refresh(this); + this.style.width = width + "px"; + } + ui.updatec(); + if (this.replaceTransition === false) { + var that = this; + setTimeout(function () { + that.style.transitionProperty = ""; + }, 200); + } + return this; + } +} diff --git a/noname/library/element/dialog.js b/noname/library/element/dialog.js new file mode 100644 index 000000000..3c880f8b8 --- /dev/null +++ b/noname/library/element/dialog.js @@ -0,0 +1,168 @@ +export class Dialog extends HTMLDivElement { + constructor() { + let hidden = false; + let noTouchScroll = false; + let forceButton = false; + let noForceButton = false; + const dialog = ui.create.div(".dialog"); + Object.setPrototypeOf(dialog, lib.element.Dialog.prototype); + dialog.contentContainer = ui.create.div(".content-container", dialog); + dialog.content = ui.create.div(".content", dialog.contentContainer); + dialog.bar1 = ui.create.div(".bar.top", dialog); + dialog.bar2 = ui.create.div(".bar.bottom", dialog); + dialog.buttons = []; + Array.from(arguments).forEach(argument => { + if (typeof argument == "boolean") dialog.static = argument; + else if (argument == "hidden") hidden = true; + else if (argument == "notouchscroll") noTouchScroll = true; + else if (argument == "forcebutton") forceButton = true; + else if (argument == "noforcebutton") noForceButton = true; + else dialog.add(argument); + }); + if (!hidden) dialog.open(); + if (!lib.config.touchscreen) dialog.contentContainer.onscroll = ui.update; + if (!noTouchScroll) { + dialog.contentContainer.ontouchstart = ui.click.dialogtouchStart; + dialog.contentContainer.ontouchmove = ui.click.touchScroll; + dialog.contentContainer.style.webkitOverflowScrolling = "touch"; + dialog.ontouchstart = ui.click.dragtouchdialog; + } + if (noForceButton) dialog.noforcebutton = true; + else if (forceButton) { + dialog.forcebutton = true; + dialog.classList.add("forcebutton"); + } + return dialog; + } + add(item, noclick, zoom) { + if (typeof item == "string") { + if (item.startsWith("###")) { + var items = item.slice(3).split("###"); + this.add(items[0], noclick, zoom); + this.addText(items[1], items[1].length <= 20, zoom); + } + else if (noclick) { + var strstr = item; + item = ui.create.div("", this.content); + item.innerHTML = strstr; + } + else { + item = ui.create.caption(item, this.content); + } + } + else if (get.objtype(item) == "div") { + this.content.appendChild(item); + } + else if (get.itemtype(item) == "cards") { + var buttons = ui.create.div(".buttons", this.content); + if (zoom) buttons.classList.add("smallzoom"); + this.buttons = this.buttons.concat(ui.create.buttons(item, "card", buttons, noclick)); + } + else if (get.itemtype(item) == "players") { + var buttons = ui.create.div(".buttons", this.content); + if (zoom) buttons.classList.add("smallzoom"); + this.buttons = this.buttons.concat(ui.create.buttons(item, "player", buttons, noclick)); + } + else if (item[1] == "textbutton") { + ui.create.textbuttons(item[0], this, noclick); + } + else { + var buttons = ui.create.div(".buttons", this.content); + if (zoom) buttons.classList.add("smallzoom"); + this.buttons = this.buttons.concat(ui.create.buttons(item[0], item[1], buttons, noclick)); + } + if (this.buttons.length) { + if (this.forcebutton !== false) this.forcebutton = true; + if (this.buttons.length > 3 || (zoom && this.buttons.length > 5)) { + this.classList.remove("forcebutton-auto"); + } + else if (!this.noforcebutton) { + this.classList.add("forcebutton-auto"); + } + } + ui.update(); + return item; + } + addText(str, center) { + if (str && str.startsWith("${str}`); + } + else { + this.add(`
${str}
`); + } + return this; + } + addSmall(item, noclick) { + return this.add(item, noclick, true); + } + addAuto(content) { + if (content && content.length > 4 && !this._hovercustomed) { + this.addSmall(content); + } + else { + this.add(content); + } + } + open() { + if (this.noopen) return; + for (var i = 0; i < ui.dialogs.length; i++) { + if (ui.dialogs[i] == this) { + this.show(); + this.refocus(); + ui.dialogs.remove(this); + ui.dialogs.unshift(this); + ui.update(); + return this; + } + if (ui.dialogs[i].static) ui.dialogs[i].unfocus(); + else ui.dialogs[i].hide(); + } + ui.dialog = this; + var translate; + if (lib.config.remember_dialog && lib.config.dialog_transform && !this.classList.contains("fixed")) { + translate = lib.config.dialog_transform; + this._dragtransform = translate; + this.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px) scale(0.8)"; + } + else { + this.style.transform = "scale(0.8)"; + } + this.style.transitionProperty = "opacity,transform"; + this.style.opacity = 0; + ui.arena.appendChild(this); + ui.dialogs.unshift(this); + ui.update(); + ui.refresh(this); + if (lib.config.remember_dialog && lib.config.dialog_transform && !this.classList.contains("fixed")) { + this.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px) scale(1)"; + } + else { + this.style.transform = "scale(1)"; + } + this.style.opacity = 1; + var that = this; + setTimeout(function () { + that.style.transitionProperty = ""; + }, 500); + return this; + } + close() { + ui.dialogs.remove(this); + this.delete(); + if (ui.dialogs.length > 0) { + ui.dialog = ui.dialogs[0]; + ui.dialog.show(); + ui.dialog.refocus(); + ui.update(); + } + // if(ui.arenalog){ + // ui.arenalog.classList.remove("withdialog"); + // } + return this; + } + setCaption(str) { + this.querySelector(".caption").innerHTML = str; + return this; + } +} diff --git a/noname/library/element/game-event-promise.js b/noname/library/element/game-event-promise.js new file mode 100644 index 000000000..5176015ac --- /dev/null +++ b/noname/library/element/game-event-promise.js @@ -0,0 +1,74 @@ +export class GameEventPromise extends Promise { + // 我谢谢你,这里是必须有的 + // 否则Promise的方法对其子类无效 + static get [Symbol.species]() { + return Promise; + } + /** + * @param { GameEvent } event + * @returns { Promise & GameEvent } + */ + constructor(event) { + super(resolve => { + // 设置为异步事件 + event.async = true; + // 事件结束后触发resolve + event.resolve = resolve; + // 如果父级事件也是一个异步的话,那应该立即执行这个事件的 + // 如果在AsyncFunction执行过程中在别的位置新建了一个异步事件,那也直接(等会set配置完)执行 + if (_status.event.next.includes(event) && _status.event.content instanceof AsyncFunction) { + if (_status.event != event) { + event.parent = _status.event; + _status.event = event; + game.getGlobalHistory("everything").push(event); + } + // 异步执行game.loop + // 不直接game.loop(event)是因为需要让别人可以手动set()和setContent() + // 再执行game.loop是因为原有的game.loop被await卡住了, + // 得新执行一个只执行这个异步事件的game.loop + Promise.resolve().then(() => game.loop(event)); + } + }); + return new Proxy(this, { + get(target, prop, receiver) { + const thisValue = Reflect.get(target, prop); + if (thisValue) { + if (typeof thisValue == "function") { + return thisValue.bind(target); + } + return thisValue; + } + const eventValue = Reflect.get(event, prop); + // 返回值如果是event,则修改为GameEventPromise类实例 + if (typeof eventValue == "function") return (function (...args) { + const returnValue = eventValue.call(event, ...args); + return returnValue == event ? receiver : returnValue; + }).bind(event); + return eventValue; + }, + set(target, prop, newValue) { + return Reflect.set(event, prop, newValue); + }, + deleteProperty(target, prop) { + return Reflect.deleteProperty(event, prop); + }, + defineProperty(target, prop, attributes) { + return Reflect.defineProperty(event, prop, attributes); + }, + has(target, prop) { + return Reflect.has(event, prop); + }, + ownKeys(target, prop) { + return Reflect.ownKeys(event, prop); + }, + }); + } + /** + * TODO: 实现debugger + */ + async debugger() { + return new Promise(resolve => { + resolve(null); + }); + } +} diff --git a/noname/library/element/game-event.js b/noname/library/element/game-event.js new file mode 100644 index 000000000..d9d4694d8 --- /dev/null +++ b/noname/library/element/game-event.js @@ -0,0 +1,841 @@ +import { Game } from "../../game.js"; +import { Get } from "../../get.js"; + +export class GameEvent { + /** + * @param {string} [name] + * @param {false} [trigger] + */ + constructor(name, trigger) { + if (typeof name == "string") { + this.name = name; + const gameEvent = Get.event(); + + if (gameEvent) { + const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`; + if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type)); + } + + Game.globalEventHandlers.addHandlerToEvent(this); + } + + this.step = 0; + this.finished = false; + /** + * @type {this[]} + */ + this.next = []; + /** + * @type {this[]} + */ + this.after = []; + this.custom = { + add: {}, + replace: {} + }; + this._aiexclude = []; + this._notrigger = []; + this._result = {}; + this._set = []; + if (trigger !== false && !Game.online) this._triggered = 0; + } + + static initialGameEvent() { + return (new this).finish(); + } + /** + * @param {keyof this} key + * @param {number} [value] + * @param {number} [baseValue] + */ + addNumber(key, value, baseValue) { + if (typeof value != "number") value = 0; + if (typeof this[key] == "number") this[key] += value; + else { + if (typeof baseValue != "number") baseValue = 0; + this[key] = baseValue + value; + } + return this; + } + /** + * @param {keyof this} key + * @param {number} [baseValue] + */ + decrease(key, baseValue) { + if (typeof this[key] == "number") this[key]--; + else this.subtractNumber(key, 1, baseValue); + return this; + } + /** + * @param {keyof this} key + * @param {number} [baseValue] + */ + increase(key, baseValue) { + if (typeof this[key] == "number") this[key]++; + else this.addNumber(key, 1, baseValue); + return this; + } + /** + * @param {keyof this} key + * @param {number} [value] + * @param {number} [baseValue] + */ + subtractNumber(key, value, baseValue) { + if (typeof value != "number") value = 0; + if (typeof this[key] == "number") this[key] -= value; + else { + if (typeof baseValue != "number") baseValue = 0; + this[key] = baseValue - value; + } + return this; + } + /** + * @param {Parameters[0]} type + * @param {GameEvent} event + * @param {{ + * state?: "begin" | "end"; + * }} option + * @returns {this} + */ + callHandler(type, event, option) { + if (this.hasHandler(type)) this.getHandler(type).forEach(handler => { + if (typeof handler == "function") handler(event, option); + }); + return this; + } + getDefaultHandlerType() { + const eventName = this.name; + if (eventName) return `on${eventName[0].toUpperCase()}${eventName.slice(1)}`; + } + /** + * @param {Parameters[0]} [type] + * @returns {((event: GameEvent, option: { + * state?: "begin" | "end"; + * }) => void)[]} + */ + getHandler(type) { + if (!type) type = this.getDefaultHandlerType(); + const currentHandler = this[type]; + if (!currentHandler) this[type] = []; + else if (!Array.isArray(currentHandler)) this[type] = [currentHandler]; + return this[type]; + } + /** + * @param {`on${Capitalize}`} [type] + */ + hasHandler(type) { + if (!type) type = this.getDefaultHandlerType(); + return Boolean(this[type] && this.getHandler(type).length); + } + /** + * @overload + * @param {...((event: GameEvent, option: { + * state?: "begin" | "end"; + * }) => void)[]} handlers + * @returns {number} + */ + /** + * @overload + * @param {Parameters[0]} type + * @param {...((event: GameEvent, option: { + * state?: "begin" | "end"; + * }) => void)[]} handlers + * @returns {number} + */ + pushHandler(type) { + return typeof type == "string" ? this.getHandler(type).push(...Array.from(arguments).slice(1)) : this.getHandler().push(...arguments); + } + changeToZero() { + this.num = 0; + this.numFixed = true; + return this; + } + + finish() { + this.finished = true; + return this; + } + putStepCache(key, value) { + if (!this._stepCache) { + this._stepCache = {}; + } + this._stepCache[key] = value; + return this; + } + getStepCache(key) { + if (!this._stepCache) return undefined; + return this._stepCache[key]; + } + clearStepCache(key) { + if (key !== undefined && key !== null) { + delete this._stepCache[key]; + } + delete this._stepCache; + return this; + } + callFuncUseStepCache(prefix, func, params) { + if (typeof func != "function") return; + if (_status.closeStepCache) return func.apply(null, params); + var cacheKey = "[" + prefix + "]" + get.paramToCacheKey.apply(null, params); + var ret = this.getStepCache(cacheKey); + if (ret === undefined || ret === null) { + ret = func.apply(null, params); + this.putStepCache(cacheKey, ret); + } + return ret; + } + putTempCache(key1, key2, value) { + if (!this._tempCache) { + this._tempCache = {}; + } + if (!this._tempCache[key1]) { + this._tempCache[key1] = {}; + } + this._tempCache[key1][key2] = value; + return value; + } + getTempCache(key1, key2) { + if (!this._tempCache) { + return undefined; + } + if (!this._tempCache[key1]) { + return undefined; + } + return this._tempCache[key1][key2]; + } + cancel(arg1, arg2, notrigger) { + this.untrigger(arg1, arg2); + this.finish(); + if (notrigger != "notrigger") { + this.trigger(this.name + "Cancelled"); + if (this.player && lib.phaseName.contains(this.name)) this.player.getHistory("skipped").add(this.name); + } + return this; + } + neutralize(event) { + this.untrigger(); + this.finish(); + this._neutralized = true; + this.trigger("eventNeutralized"); + this._neutralize_event = event || _status.event; + return this; + } + unneutralize() { + this.untrigger(); + delete this._neutralized; + delete this.finished; + if (this.type == "card" && this.card && this.name == "sha") this.directHit = true; + return this; + } + goto(step) { + this.step = step - 1; + return this; + } + redo() { + this.step--; + return this; + } + setHiddenSkill(skill) { + if (!this.player) return this; + var hidden = this.player.hiddenSkills.slice(0); + game.expandSkills(hidden); + if (hidden.contains(skill)) this.set("hsskill", skill); + return this; + } + set(key, value) { + if (arguments.length == 1 && Array.isArray(arguments[0])) { + for (var i = 0; i < arguments[0].length; i++) { + if (Array.isArray(arguments[0][i])) { + this.set(arguments[0][i][0], arguments[0][i][1]); + } + } + } + else { + if (typeof key != "string") { + console.log("warning: using non-string object as event key"); + console.log(key, value); + console.log(_status.event); + } + this[key] = value; + this._set.push([key, value]); + } + return this; + } + /** + * @param {ArrayLike | Function | keyof typeof lib.element.content} item + */ + setContent(item) { + switch (typeof item) { + case "object": + case "function": + if (item instanceof AsyncFunction) { + this.content = item; + } + else this.content = lib.init.parsex(item); + break; + default: + try { + if (!lib.element.content[item]._parsed) { + lib.element.content[item] = lib.init.parsex(lib.element.content[item]); + lib.element.content[item]._parsed = true; + } + } + catch (_) { + throw new Error(`Content ${item} may not exist.\nlib.element.content[${item}] = ${lib.element.content[item]}`); + } + this.content = lib.element.content[item]; + break; + } + return this; + } + getLogv() { + for (var i = 1; i <= 3; i++) { + var event = this.getParent(i); + if (event && event.logvid) return event.logvid; + } + return null; + } + send() { + this.player.send(function (name, args, set, event, skills) { + game.me.applySkills(skills); + var next = game.me[name].apply(game.me, args); + for (var i = 0; i < set.length; i++) { + next.set(set[i][0], set[i][1]); + } + if (next._backupevent) { + next.backup(next._backupevent); + } + next._modparent = event; + game.resume(); + }, this.name, this._args || [], this._set, + get.stringifiedResult(this.parent), get.skillState(this.player)); + this.player.wait(); + game.pause(); + return this; + } + resume() { + delete this._cardChoice; + delete this._targetChoice; + delete this._skillChoice; + return this; + } + getParent(level, forced) { + var parent, historys = []; + if (this._modparent && game.online) { + parent = this._modparent; + } + else { + parent = this.parent; + } + var toreturn = {}; + if (typeof level == "string" && forced == true) { + toreturn = null; + } + if (!parent) return toreturn; + if (typeof level == "number") { + for (var i = 1; i < level; i++) { + if (!parent) return toreturn; + parent = parent.parent; + } + } + else if (typeof level == "string") { + while (true) { + if (!parent) return toreturn; + historys.push(parent); + if (parent.name == level) return parent; + parent = parent.parent; + if (historys.contains(parent)) return toreturn; + } + } + if (toreturn === null) { + return null; + } + return parent; + } + getTrigger() { + return this.getParent()._trigger; + } + getRand(name) { + if (name) { + if (!this._rand_map) this._rand_map = {}; + if (!this._rand_map[name]) this._rand_map[name] = Math.random(); + return this._rand_map[name]; + } + if (!this._rand) this._rand = Math.random(); + return this._rand; + } + insert(content, map) { + const next = new lib.element.GameEvent(`${this.name}Inserted`, false); + this.next.push(next); + next.setContent(content); + Object.entries(map).forEach(entry => next.set(entry[0], entry[1])); + return next; + } + insertAfter(content, map) { + const next = new lib.element.GameEvent(`${this.name}Inserted`, false); + this.after.push(next); + next.setContent(content); + Object.entries(map).forEach(entry => next.set(entry[0], entry[1])); + return next; + } + backup(skill) { + this._backup = { + filterButton: this.filterButton, + selectButton: this.selectButton, + filterTarget: this.filterTarget, + selectTarget: this.selectTarget, + filterCard: this.filterCard, + selectCard: this.selectCard, + position: this.position, + forced: this.forced, + fakeforce: this.fakeforce, + _aiexclude: this._aiexclude, + complexSelect: this.complexSelect, + complexCard: this.complexCard, + complexTarget: this.complexTarget, + _cardChoice: this._cardChoice, + _targetChoice: this._targetChoice, + _skillChoice: this._skillChoice, + ai1: this.ai1, + ai2: this.ai2, + filterOk: this.filterOk, + } + if (skill) { + var info = get.info(skill); + this.skill = skill; + this._aiexclude = []; + if (typeof info.viewAs == "function") { + if (info.filterButton != undefined) this.filterButton = get.filter(info.filterButton); + if (info.selectButton != undefined) this.selectButton = info.selectButton; + if (info.filterTarget != undefined) this.filterTarget = get.filter(info.filterTarget); + if (info.selectTarget != undefined) this.selectTarget = info.selectTarget; + if (info.filterCard != undefined) { + if (info.ignoreMod) this.ignoreMod = true; + this.filterCard2 = get.filter(info.filterCard); + this.filterCard = function (card, player, event) { + var evt = event || _status.event; + if (!evt.ignoreMod && player) { + var mod = game.checkMod(card, player, "unchanged", "cardEnabled2", player); + if (mod != "unchanged") return mod; + } + return get.filter(evt.filterCard2).apply(this, arguments); + }; + } + if (info.filterOk == undefined) { + this.filterOk = function () { + var evt = _status.event; + var card = get.card(), player = get.player(); + var filter = evt._backup.filterCard; + if (filter && !filter(card, player, evt)) return false; + if (evt._backup.filterOk) return evt._backup.filterOk(); + return true; + }; + } + else this.filterOk = info.filterOk; + if (info.selectCard != undefined) this.selectCard = info.selectCard; + if (info.position != undefined) this.position = info.position; + //if(info.forced!=undefined) this.forced=info.forced; + if (info.complexSelect != undefined) this.complexSelect = info.complexSelect; + if (info.complexCard != undefined) this.complexCard = info.complexCard; + if (info.complexTarget != undefined) this.complexTarget = info.complexTarget; + if (info.ai1 != undefined) this.ai1 = info.ai1; + if (info.ai2 != undefined) this.ai2 = info.ai2; + } + else if (info.viewAs) { + if (info.filterButton != undefined) this.filterButton = get.filter(info.filterButton); + if (info.selectButton != undefined) this.selectButton = info.selectButton; + if (info.filterTarget != undefined) this.filterTarget = get.filter(info.filterTarget); + if (info.selectTarget != undefined) this.selectTarget = info.selectTarget; + if (info.filterCard != undefined) { + if (info.ignoreMod) this.ignoreMod = true; + this.filterCard2 = get.filter(info.filterCard); + this.filterCard = function (card, player, event) { + var evt = event || _status.event; + if (!evt.ignoreMod && player) { + var mod = game.checkMod(card, player, "unchanged", "cardEnabled2", player); + if (mod != "unchanged") return mod; + } + return get.filter(evt.filterCard2).apply(this, arguments); + }; + } + if (info.filterOk == undefined) { + this.filterOk = function () { + var evt = _status.event; + var card = get.card(), player = get.player(); + var filter = evt._backup.filterCard; + if (filter && !filter(card, player, evt)) return false; + if (evt._backup.filterOk) return evt._backup.filterOk() + return true; + }; + } + else this.filterOk = info.filterOk; + if (info.selectCard != undefined) this.selectCard = info.selectCard; + if (info.position != undefined) this.position = info.position; + //if(info.forced!=undefined) this.forced=info.forced; + if (info.complexSelect != undefined) this.complexSelect = info.complexSelect; + if (info.complexCard != undefined) this.complexCard = info.complexCard; + if (info.complexTarget != undefined) this.complexTarget = info.complexTarget; + if (info.ai1 != undefined) this.ai1 = info.ai1; + if (info.ai2 != undefined) this.ai2 = info.ai2; + } + else { + this.filterButton = info.filterButton ? get.filter(info.filterButton) : undefined; + this.selectButton = info.selectButton; + this.filterTarget = info.filterTarget ? get.filter(info.filterTarget) : undefined; + this.selectTarget = info.selectTarget; + this.filterCard = info.filterCard ? get.filter(info.filterCard) : undefined; + this.selectCard = info.selectCard; + this.position = info.position; + //this.forced=info.forced; + this.complexSelect = info.complexSelect; + this.complexCard = info.complexCard; + this.complexTarget = info.complexTarget; + if (info.ai1 != undefined) this.ai1 = info.ai1; + if (info.ai2 != undefined) this.ai2 = info.ai2; + this.filterOk = info.filterOk; + } + delete this.fakeforce; + } + delete this._cardChoice; + delete this._targetChoice; + delete this._skillChoice; + return this; + } + restore() { + if (this._backup) { + this.filterButton = this._backup.filterButton; + this.selectButton = this._backup.selectButton; + this.filterTarget = this._backup.filterTarget; + this.selectTarget = this._backup.selectTarget; + this.filterCard = this._backup.filterCard; + this.selectCard = this._backup.selectCard; + this.position = this._backup.position; + this.forced = this._backup.forced; + this.fakeforce = this._backup.fakeforce; + this._aiexclude = this._backup._aiexclude; + this.complexSelect = this._backup.complexSelect; + this.complexCard = this._backup.complexCard; + this.complexTarget = this._backup.complexTarget; + this.ai1 = this._backup.ai1; + this.ai2 = this._backup.ai2; + this._cardChoice = this._backup._cardChoice; + this._targetChoice = this._backup._targetChoice; + this._skillChoice = this._backup._skillChoice; + this.filterOk = this._backup.filterOk; + } + delete this.skill; + delete this.ignoreMod; + delete this.filterCard2; + return this; + } + isMine() { + return (this.player && this.player == game.me && !_status.auto && !this.player.isMad() && !game.notMe); + } + isOnline() { + return (this.player && this.player.isOnline()); + } + notLink() { + return this.getParent().name != "_lianhuan" && this.getParent().name != "_lianhuan2"; + } + isPhaseUsing(player) { + var evt = this.getParent("phaseUse"); + if (!evt || evt.name != "phaseUse") return false; + return !player || player == evt.player; + } + addTrigger(skills, player) { + if (!player || !skills) return this; + let evt = this; + if (typeof skills == "string") skills = [skills]; + game.expandSkills(skills); + while (true) { + evt = evt.getParent("arrangeTrigger"); + if (!evt || evt.name != "arrangeTrigger" || !evt.doingList) return this; + const doing = (() => { + if (evt.doing && evt.doing.player == player) return evt.doing; + return evt.doingList.find(i => i.player == player); + })(); + // if(!doing) return this; + const firstDo = evt.doingList.find(i => i.player == "firstDo"); + const lastDo = evt.doingList.find(i => i.player == "lastDo"); + + for (const skill of skills) { + const info = lib.skill[skill]; + if (!info.trigger) continue; + if (!Object.keys(info.trigger).some(i => { + if (Array.isArray(info.trigger[i])) return info.trigger[i].includes(evt.triggername); + return info.trigger[i] == evt.triggername; + })) continue; + + const playerMap = game.players.concat(game.dead).sortBySeat(evt.starter); + const priority = get.priority(skill); + const toadd = { + skill: skill, + player: player, + priority: priority, + } + const map = info.firstDo ? firstDo : info.lastDo ? lastDo : doing; + if (!map) continue; + if (map.doneList && map.doneList.some(i => i.skill == toadd.skill && i.player == toadd.player)) continue; + if (map.todoList.some(i => i.skill == toadd.skill && i.player == toadd.player)) continue; + map.todoList.add(toadd); + map.todoList.sort((a, b) => (b.priority - a.priority) || (playerMap.indexOf(a) - playerMap.indexOf(b))); + } + } + } + removeTrigger(skills, player) { + if (!player || !skills) return this; + let evt = this; + if (typeof skills == "string") skills = [skills]; + game.expandSkills(skills); + while (true) { + evt = evt.getParent("arrangeTrigger"); + if (!evt || evt.name != "arrangeTrigger" || !evt.doingList) return this; + const doing = (() => { + if (evt.doing && evt.doing.player == player) return evt.doing; + return evt.doingList.find(i => i.player == player); + })(); + // if(!doing) return this; + const firstDo = evt.doingList.find(i => i.player == "firstDo"); + const lastDo = evt.doingList.find(i => i.player == "lastDo"); + + for (const skill of skills) { + [doing, firstDo, lastDo].forEach(map => { + if (!map) return; + const toremove = map.todoList.filter(i => i.skill == skill && i.player == player); + if (toremove.length > 0) map.todoList.removeArray(toremove); + }); + } + } + } + trigger(name) { + if (_status.video) return this; + if ((this.name === "gain" || this.name === "lose") && !_status.gameDrawed) return this; + if (name === "gameDrawEnd") _status.gameDrawed = true; + if (name === "gameStart") { + lib.announce.publish("gameStart", {}); + if (_status.brawl && _status.brawl.gameStart) _status.brawl.gameStart(); + if (lib.config.show_cardpile) ui.cardPileButton.style.display = ""; + _status.gameStarted = true; + game.showHistory(); + } + if (!lib.hookmap[name] && !lib.config.compatiblemode) return this; + if (!game.players || !game.players.length) return this; + const event = this; + let start = [_status.currentPhase, event.source, event.player, game.me, game.players[0]].find(i => get.itemtype(i) == "player"); + if (!start) return this; + if (!game.players.includes(start) && !game.dead.includes(start)) start = game.findNext(start); + const firstDo = { + player: "firstDo", + todoList: [], + doneList: [], + } + const lastDo = { + player: "lastDo", + todoList: [], + doneList: [], + } + const doingList = []; + let allbool = false; + const roles = ["player", "source", "target", "global"]; + const playerMap = game.players.concat(game.dead).sortBySeat(start); + function addList(skill, player) { + if (this.listAdded[skill]) return; + this.listAdded[skill] = true; + if (player.forbiddenSkills[skill]) return; + if (player.disabledSkills[skill]) return; + + const info = lib.skill[skill]; + const list = info.firstDo ? firstDo.todoList : info.lastDo ? lastDo.todoList : this.todoList; + const priority = get.priority(skill); + list.push({ + skill: skill, + player: player, + priority: priority, + }); + if (typeof list.player == "string") list.sort((a, b) => (b.priority - a.priority) || (playerMap.indexOf(a) - playerMap.indexOf(b))); + else list.sort((a, b) => b.priority - a.priority); + allbool = true; + } + let player = start; + do { + const doing = { + player: player, + todoList: [], + doneList: [], + listAdded: {}, + addList: addList, + } + const notemp = player.skills.slice(); + for (const j in player.additionalSkills) { + if (!j.startsWith("hidden:")) notemp.addArray(player.additionalSkills[j]); + } + for (const skill in player.tempSkills) { + if (notemp.includes(skill)) continue; + const expire = player.tempSkills[skill]; + if (typeof expire === "function" && expire(event, player, name)) { + delete player.tempSkills[skill]; + player.removeSkill(skill); + } + else if (get.objtype(expire) === "object") { + for (const role of roles) { + if (role !== "global" && player !== event[role]) continue; + if (expire[role] === name || (Array.isArray(expire[role]) && expire[role].includes(name))) { + delete player.tempSkills[skill]; + player.removeSkill(skill); + } + } + } + } + if (lib.config.compatiblemode) { + let skills = player.getSkills("invisible").concat(lib.skill.global); + game.expandSkills(skills); + for (const skill of skills) { + const info = get.info(skill); + if (!info || !info.trigger) continue; + if (roles.some(role => { + if (info.trigger[role] === name) return true; + if (Array.isArray(info.trigger[role]) && info.trigger[role].includes(name)) return true; + })) doing.addList(skill, player); + } + } + else { + for (const role of roles) { + const globalTriggername = role + "_" + name; + if (lib.hook.globalskill[globalTriggername]) { + lib.hook.globalskill[globalTriggername].forEach(skill => doing.addList(skill, player)); + } + const triggername = player.playerid + "_" + role + "_" + name; + if (lib.hook[triggername]) { + lib.hook[triggername].forEach(skill => doing.addList(skill, player)); + } + } + } + delete doing.listAdded; + delete doing.addList; + doingList.push(doing); + player = player.nextSeat; + } while (player && player !== start) + doingList.unshift(firstDo); + doingList.push(lastDo); + // console.log(name,event.player,doingList.map(i=>({player:i.player,todoList:i.todoList.slice(),doneList:i.doneList.slice()}))) + + if (allbool) { + var next = game.createEvent("arrangeTrigger", false, event); + next.setContent("arrangeTrigger"); + next.doingList = doingList; + next._trigger = event; + next.triggername = name; + next.starter = start; + event._triggering = next; + } + return this; + } + untrigger(all, player) { + if (typeof all == "undefined") all = true; + var evt = this._triggering; + if (all) { + if (evt && evt.doingList) { + evt.doingList.forEach(doing => doing.todoList = []); + evt.list = []; + if (evt.doing) evt.doing.todoList = []; + } + this._triggered = 5; + } + else if (player) { + this._notrigger.add(player); + if (!evt || !evt.doingList) return this; + const doing = evt.doingList.find(doing => doing.player == player); + if (doing) doing.todoList = []; + } + return this; + } + /** + * @returns {never} + */ + typeAnnotation() { + /** + * @type {Player} + */ + this.source; + /** + * @type {Player} + */ + this.player; + /** + * @type {Player} + */ + this.target; + /** + * @type {Player[]} + */ + this.targets; + /** + * @type {Card} + */ + this.card; + /** + * @type {Card[]} + */ + this.cards; + /** + * @type {string} + */ + this.skill; + /** + * @type {boolean} + */ + this.forced; + /** + * @type {number} + */ + this.num; + /** + * @type {GameEvent} + */ + this._trigger; + /** + * @type {Record} + */ + this._result; + /** + * @type {number} + */ + this.baseDamage; + /** + * @type {Player} + */ + this.customSource; + /** + * @type {number} + */ + this.extraDamage; + /** + * @type {string} + */ + this.nature; + /** + * @type {boolean} + */ + this.notrigger; + /** + * @type {number} + */ + this.original_num; + /** + * @type {boolean} + */ + this.unreal; + throw new Error("Do not call this method"); + } + /** + * 事件转为Promise化 + * + * @returns { Promise & GameEvent } + */ + toPromise() { + if (this.async && this.resolve) { + throw new TypeError("This event has been converted into a promise"); + } + return new lib.element.GameEventPromise(this); + } +} diff --git a/noname/library/element/node-ws.js b/noname/library/element/node-ws.js new file mode 100644 index 000000000..9a16ee9ca --- /dev/null +++ b/noname/library/element/node-ws.js @@ -0,0 +1,17 @@ +export class NodeWS { + /** + * @param {string} id + */ + constructor(id) { + this.wsid = id; + } + send(message) { + game.send("server", "send", this.wsid, message); + } + on(type, func) { + this["on" + type] = func; + } + close() { + game.send("server", "close", this.wsid); + } +} diff --git a/noname/library/element/player.js b/noname/library/element/player.js new file mode 100644 index 000000000..b2f1ce367 --- /dev/null +++ b/noname/library/element/player.js @@ -0,0 +1,9438 @@ +export class Player { + /** + * @param {HTMLDivElement} [position] + * @param {true} [noclick] + */ + constructor(position, noclick) { + /** + * @type {Player} + */ + const player = ui.create.div(".player", position); + Object.setPrototypeOf(player, lib.element.Player.prototype); + player.build(noclick); + return player; + } + build(noclick) { + let player = this; + player.buildNode(); + player.buildProperty(); + player.buildExtra(); + player.buildEventListener(noclick); + } + buildNode() { + let player = this; + const node = player.node = { + avatar: ui.create.div(".avatar", player, ui.click.avatar).hide(), + avatar2: ui.create.div(".avatar2", player, ui.click.avatar2).hide(), + turnedover: ui.create.div(".turned", "
翻面
", player), + framebg: ui.create.div(".framebg", player), + intro: ui.create.div(".intro", player), + identity: ui.create.div(".identity", player), + hp: ui.create.div(".hp", player), + name: ui.create.div(".name", player), + name2: ui.create.div(".name.name2", player), + nameol: ui.create.div(".nameol", player), + count: ui.create.div(".count", player).hide(), + equips: ui.create.div(".equips", player).hide(), + judges: ui.create.div(".judges", player), + marks: ui.create.div(".marks", player), + chain: ui.create.div(".chain", "
", player), + handcards1: ui.create.div(".handcards"), + handcards2: ui.create.div(".handcards"), + expansions: ui.create.div(".expansions") + }; + node.expansions.style.display = "none"; + const chainLength = game.layout == "default" ? 64 : 40; + for (let repetition = 0; repetition < chainLength; repetition++) { + ui.create.div(node.chain.firstChild, ".cardbg").style.transform = `translateX(${repetition * 5 - 5}px)`; + } + node.action = ui.create.div(".action", node.avatar); + } + buildExtra() { + let player = this; + let node = player.node; + node.link = player.mark(" ", { + mark: get.linkintro + }); + node.link.firstChild.setBackgroundImage("image/card/tiesuo_mark.png"); + node.link.firstChild.style.backgroundSize = "cover"; + ui.create.div(node.identity); + } + buildProperty() { + let player = this; + player.phaseNumber = 0; + player.skipList = []; + player.skills = []; + player.invisibleSkills = []; + player.initedSkills = []; + player.additionalSkills = {}; + player.disabledSkills = {}; + player.hiddenSkills = []; + player.awakenedSkills = []; + player.forbiddenSkills = {}; + player.popups = []; + player.damagepopups = []; + player.judging = []; + player.stat = [{ + card: {}, + skill: {} + }]; + player.actionHistory = [{ + useCard: [], + respond: [], + skipped: [], + lose: [], + gain: [], + sourceDamage: [], + damage: [], + custom: [], + useSkill: [] + }]; + player.tempSkills = {}; + player.storage = {}; + player.marks = {}; + player.expandedSlots = {}; + player.disabledSlots = {}; + player.ai = { + friend: [], + enemy: [], + neutral: [], + handcards: { + global: [], + source: [], + viewed: [] + } + }; + player.queueCount = 0; + player.outCount = 0; + /** + * 这部分应该用d.ts写。目前只给出大概类型 + * @type { {[key in keyof Player]: (...args) => Promise & GameEvent} } + */ + player.promises = new Proxy({}, { + get(target, prop) { + const eventKeys = Object.keys(lib.element.player).filter(key => typeof lib.element.player[key] == "function"); + if (eventKeys.includes(prop)) { + return function (...args) { + /** @type { GameEvent } */ + const event = player[prop](...args); + return event.toPromise(); + }; + } + } + }); + } + buildEventListener(noclick) { + let player = this; + let node = player.node; + if (noclick) player.noclick = true; + else { + player.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.target); + node.identity.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.identity); + if (lib.config.touchscreen) player.addEventListener("touchstart", ui.click.playertouchstart); + } + } + //新函数 + changeFury(amount, limit) { + if (typeof this.storage.stratagem_fury != "number") this.storage.stratagem_fury = 0; + if (!amount) return; + const furyBefore = this.storage.stratagem_fury; + if (limit === true && typeof _status.stratagemFuryMax == "number") this.storage.stratagem_fury = Math.min(Math.max(furyBefore + amount, 0), _status.stratagemFuryMax); + else this.storage.stratagem_fury = Math.max(furyBefore + amount, 0); + const difference = this.storage.stratagem_fury - furyBefore; + if (!difference) return; + game.log(this, difference > 0 ? "获得了" : "失去了", get.cnNumber(Math.abs(difference)), "点", "#r怒气"); + this.markSkill("stratagem_fury"); + } + /** + * version 1.7 + * + * 链式创建一次性技能的api。 + * + * 使用者只需要关注技能的效果,而不是技能的本身。 + * + * v1.7 可传递作用域 + * @example + * ```js + * (function () { + * let _var = 1; + * let me = player; + * player.when("drawAfter") + * .apply(code => eval(code)) + * .then(() => console.log(_var)) + * .then("me.gainMaxHp(5)"); + * })(); + * ``` + */ + when() { + if (!_status.postReconnect.player_when) _status.postReconnect.player_when = [ + function (map) { + "use strict"; + for (let i in map) { + lib.skill[i] = { + charlotte: true, + forced: true, + popup: false, + } + if (typeof map[i] == "string") lib.translate[i] = map[i]; + } + }, {} + ]; + let triggerNames = Array.from(arguments); + let trigger; + if (triggerNames.length == 0) throw "player.when的参数数量应大于0"; + //add other triggerNames + //arguments.length = 1 + if (triggerNames.length == 1) { + //以下两种情况: + //triggerNames = [ ["xxAfter", ...args] ] + //triggerNames = [ "xxAfter" ] + if (Array.isArray(triggerNames[0]) || typeof triggerNames[0] == "string") trigger = { player: triggerNames[0] }; + //triggerNames = [ {player:"xxx"} ] + else if (get.is.object(triggerNames[0])) trigger = triggerNames[0]; + } + //arguments.length > 1 + else { + //triggerNames = [ "xxAfter", "yyBegin" ] + if (triggerNames.every(t => typeof t == "string")) trigger = { player: triggerNames }; + //triggerNames = [ {player: "xxAfter"}, {global: "yyBegin"} ] + //此处不做特殊的合并处理,由使用者自行把握,同名属性后者覆盖前者 + else if (triggerNames.every(t => get.is.object(t))) trigger = triggerNames.reduce((pre, cur) => Object.assign(pre, cur)); + } + if (!trigger) throw "player.when传参数类型错误:" + triggerNames; + let skillName; + do { + skillName = "player_when_" + Math.random().toString(36).slice(-8); + } while (lib.skill[skillName] != null); + const after = `${skillName}After`; + if (!trigger.player) trigger.player = after; + else if (Array.isArray(trigger.player)) trigger.player.add(after); + else if (typeof trigger.player == "string") trigger.player = [trigger.player, after]; + const vars = {}; + /** + * 作用域 + * @type { (code: string) => any } + */ + let scope; + let skill = { + trigger: trigger, + forced: true, + charlotte: true, + popup: false, + //必要条件 + filterFuns: [], + //充分条件 + filter2Funs: [], + contentFuns: [], + //外部变量 + get vars() { + return vars; + }, + get filter() { + return (event, player, name) => { + if (name == `${skillName}After`) { + skill.popup = false; + return true; + } + return skill.filterFuns.every(fun => Boolean(fun(event, player, name))) && + skill.filter2(event, player, name); + } + }, + get filter2() { + return (event, player, name) => { + return skill.filter2Funs.length == 0 || + skill.filter2Funs.some(fun => Boolean(fun(event, player, name))); + }; + } + }; + const warnVars = ["event", "step", "source", "player", "target", "targets", + "card", "cards", "skill", "forced", "num", "trigger", "result"]; + const errVars = ["_status", "lib", "game", "ui", "get", "ai"]; + const createContent = () => { + let varstr = ""; + for (const key in vars) { + if (warnVars.includes(key)) console.warn(`Variable "${key}" should not be referenced by vars objects`); + if (errVars.includes(key)) throw new Error(`Variable "${key}" should not be referenced by vars objects`); + varstr += `var ${key}=lib.skill["${skillName}"].vars["${key}"];\n`; + } + let str = ` + function content(){ + ${varstr}if(event.triggername=="${skillName}After"){ + player.removeSkill("${skillName}"); + delete lib.skill["${skillName}"]; + delete lib.translate["${skillName}"]; + return event.finish(); + } + `; + for (let i = 0; i < skill.contentFuns.length; i++) { + const fun2 = skill.contentFuns[i]; + const a = fun2.toString(); + //防止传入()=>xxx的情况 + const begin = a.indexOf("{") == a.indexOf("}") && a.indexOf("{") == -1 && a.indexOf("=>") > -1 ? a.indexOf("=>") + 2 : a.indexOf("{") + 1; + const str2 = a.slice(begin, a.lastIndexOf("}") != -1 ? a.lastIndexOf("}") : undefined).trim(); + str += `"step ${i}"\n\t${str2}\n\t`; + } + skill.content = lib.init.parsex((scope || eval)(str + `\n};content;`), scope); + skill.content._parsed = true; + }; + Object.defineProperty(lib.skill, skillName, { + configurable: true, + //这类技能不需要被遍历到 + enumerable: false, + writable: true, + value: skill + }); + game.broadcast(function (skillName) { + Object.defineProperty(lib.skill, skillName, { + configurable: true, + enumerable: false, + writable: true, + value: { + forced: true, + charlotte: true, + popup: false, + vars: {}, + } + }); + }, skillName); + this.addSkill(skillName); + _status.postReconnect.player_when[1][skillName] = true; + return { + filter(fun) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + skill.filterFuns.push(fun); + return this; + }, + removeFilter(fun) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + skill.filterFuns.remove(fun); + return this; + }, + filter2(fun) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + skill.filter2Funs.push(fun); + return this; + }, + removeFilter2(fun) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + skill.filter2Funs.remove(fun); + return this; + }, + then(fun) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + skill.contentFuns.push(fun); + createContent(); + return this; + }, + popup(str) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + if (typeof str == "string") skill.popup = str; + return this; + }, + translation(translation) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + if (typeof translation == "string") { + _status.postReconnect.player_when[1][skillName] = translation; + game.broadcastAll((skillName, translation) => lib.translate[skillName] = translation, skillName, translation) + } + return this; + }, + assign(obj) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + if (typeof obj == "object" && obj !== null) Object.assign(skill, obj); + return this; + }, + vars(arg) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + if (!get.is.object(arg)) throw "vars的第一个参数必须为对象"; + Object.assign(vars, arg); + createContent(); + return this; + }, + /** + * 传递外部作用域 + * + * 一般是传递一个 code=>eval(code) 函数 + * + * 传递后可在then中使用外部变量(vars的上位替代) + * + * @param {Function} _scope + */ + apply(_scope) { + if (lib.skill[skillName] != skill) throw `This skill has been destroyed`; + scope = _scope; + if (skill.contentFuns.length > 0) createContent(); + return this; + } + }; + } + //让一名角色明置一些手牌 + addShownCards() { + const cards = [], tags = []; + for (const argument of arguments) { + const type = get.itemtype(argument); + if (type == "cards") cards.addArray(argument); + else if (type == "card") cards.add(argument); + else if (typeof argument == "string" && argument.startsWith("visible_")) tags.add(argument); + } + if (!cards.length || !tags.length) return; + const next = game.createEvent("addShownCards", false); + next.player = this; + next._cards = cards; + next.gaintag = tags; + next.setContent("addShownCards"); + return next; + } + hideShownCards() { + const cards = [], tags = []; + for (const argument of arguments) { + const type = get.itemtype(argument); + if (type == "cards") cards.addArray(argument); + else if (type == "card") cards.add(argument); + else if (typeof argument == "string" && argument.startsWith("visible_")) tags.add(argument); + } + if (!cards.length) return; + const next = game.createEvent("hideShownCards", false); + next.player = this; + next._cards = cards; + next.gaintag = tags; + next.setContent("hideShownCards"); + return next; + } + //获取角色所有的明置手牌 + getShownCards() { + return this.getCards("h", function (card) { + return get.is.shownCard(card); + }); + } + //获取该角色被other所知的牌。 + getKnownCards(other, filter) { + if (!other) other = _status.event.player; + if (!other) other = this; + if (!filter) filter = (card) => { return true }; + return this.getCards("h", function (card) { + return card.isKnownBy(other) && filter(card); + }); + } + //判断此角色的手牌是否已经被看光了。 + isAllCardsKnown(other) { + if (!other) other = _status.event.player; + if (!other) other = this; + return this.countCards("h", function (card) { + return !card.isKnownBy(other); + }) == 0; + } + //判断此角色是否有被知的牌。 + hasKnownCards(other, filter) { + if (!other) other = _status.event.player; + if (!other) other = this; + if (!filter) filter = (card) => { return true }; + return this.countCards("h", function (card) { + return card.isKnownBy(other) && filter(card); + }) > 0; + } + //数此角色被知道的牌。 + countKnownCards(other, filter) { + return this.getKnownCards(other, filter).length; + } + //Execute the delay card effect + //执行延时锦囊牌效果 + executeDelayCardEffect(card, target, judge, judge2) { + const executeDelayCardEffect = game.createEvent("executeDelayCardEffect"); + executeDelayCardEffect.player = this; + executeDelayCardEffect.target = target || this; + if (typeof card == "string") { + const virtualCard = executeDelayCardEffect.card = ui.create.card(); + virtualCard._destroy = true; + virtualCard.expired = true; + const info = lib.card[card]; + virtualCard.init(["", "", card, info && info.cardnature]); + } + else if (get.itemtype(card) == "card") executeDelayCardEffect.card = card; + else _status.event.next.remove(executeDelayCardEffect); + executeDelayCardEffect.judge = judge; + executeDelayCardEffect.judge2 = judge2; + executeDelayCardEffect.setContent("executeDelayCardEffect"); + executeDelayCardEffect._args = Array.from(arguments); + return executeDelayCardEffect; + } + //Check if the card does not count toward hand limit + //检测此牌是否不计入手牌上限 + canIgnoreHandcard(card) { + return lib.filter.ignoredHandcard(card, this); + } + //Gift + //赠予 + gift(cards, target) { + const gift = game.createEvent("gift"); + gift.player = this; + gift.target = target; + const isArray = Array.isArray(cards); + if (cards && !isArray) gift.cards = [cards]; + else if (isArray && cards.length) gift.cards = cards; + else _status.event.next.remove(gift); + gift.deniedGifts = []; + gift.setContent("gift"); + gift._args = Array.from(arguments); + return gift; + } + //Check if the player can gift the card + //检测角色是否能赠予此牌 + canGift(card, target, strict) { + return lib.filter.cardGiftable(card, this, target, strict); + } + //Check if the player refuses gifts + //检测角色是否拒绝赠予 + refuseGifts(card, player) { + return this.hasSkillTag("refuseGifts", null, { + player: player, + card: card + }); + } + //Gift AI related + //赠予AI相关 + getGiftAIResultTarget(card, target) { + if (!card || target.refuseGifts(card, this)) return 0; + if (get.type(card, false) == "equip") return get.effect(target, card, target, target); + if (card.name == "du") return this.hp > target.hp ? -1 : 0; + if (target.hasSkillTag("nogain")) return 0; + return Math.max(1, get.value(card, this) - get.value(card, target)); + } + getGiftEffect(card, target) { + return this.getGiftAIResultTarget(card, target) * get.attitude(this, target); + } + //Recast + //重铸 + recast(cards, recastingLose, recastingGain) { + const recast = game.createEvent("recast"); + recast.player = this; + const isArray = Array.isArray(cards); + if (cards && !isArray) recast.cards = [cards]; + else if (isArray && cards.length) recast.cards = cards; + else _status.event.next.remove(recast); + if (typeof recastingLose != "function") recastingLose = (player, cards) => player.loseToDiscardpile(cards).log = false; + recast.recastingLose = recastingLose; + recast.recastingLosingEvents = []; + if (typeof recastingGain != "function") recastingGain = (player, cards) => player.draw(cards.length).log = false; + recast.recastingGain = recastingGain; + recast.recastingGainingEvents = []; + recast.setContent("recast"); + recast._args = Array.from(arguments); + return recast; + } + //Check if the player can recast the card + //检测角色是否能重铸此牌 + canRecast(card, source, strict) { + return lib.filter.cardRecastable(card, this, source, strict); + } + //装备栏相关 + //判断一名角色的某个区域是否被废除 + //type为要判断的区域 若为空 则判断玩家是否有任意一个被废除的区域 + hasDisabledSlot(type) { + var player = this; + if (type == "horse" || type == "equip3_4") { + return player.hasDisabledSlot(3) && (get.is.mountCombined() || player.hasDisabledSlot(4)); + } + else if (get.is.mountCombined() && type == "equip4") { + return false; + } + return player.countDisabledSlot(type) > 0; + } + //判断一名角色的某个区域被废除的数量 + //用法同上 + countDisabledSlot(type) { + var player = this; + var map = (player.disabledSlots || {}); + if (type == undefined) { + num = 0; + for (var i = 1; i <= 5; i++) { + num += player.countDisabledSlot(i); + } + return num; + } + else { + if (typeof type == "number") type = ("equip" + type); + if (get.is.mountCombined() && type == "equip4") { + return 0; + } + var num = map[type]; + if (typeof num == "number" && num > 0) return num; + return 0; + } + } + //判断一名角色是否有某个装备栏空着 + hasEmptySlot(type) { + var player = this; + if (type == "horse" || type == "equip3_4") { + return player.hasEmptySlot(3) && (get.is.mountCombined() || player.hasEmptySlot(4)); + } + else if (get.is.mountCombined() && type == "equip4") { + return false; + } + return player.countEmptySlot(type) > 0; + } + //判断一名角色的某个装备栏空位的数量 + countEmptySlot(type) { + if (!type) return 0; + var player = this; + if (typeof type == "number") type = ("equip" + type); + else if (type == "equip3_4") { + type = "equip3"; + } + return Math.max(0, player.countEnabledSlot(type) - player.getEquips(type).reduce(function (num, card) { + var types = get.subtypes(card, false); + return num + get.numOf(types, type); + }, 0)) + } + //判断一名角色是否有可以用于装备新装备牌的区域(排除金箍棒和六龙等“不可被替换装备”) + //用法同下 + hasEquipableSlot(type) { + return this.countEquipableSlot(type) > 0; + } + //统计一名角色有多少个可以用于装备新的装备牌的区域 + //用法同下 + countEquipableSlot(type) { + if (!type) return 0; + var player = this; + if (typeof type == "number") type = ("equip" + type); + else if (type == "equip3_4") { + type = "equip3"; + } + else if (get.is.mountCombined() && type == "equip4") { + return 0; + } + return Math.max(0, player.countEnabledSlot(type) - player.getEquips(type).reduce(function (num, card) { + var types = get.subtypes(card, false); + if (!lib.filter.canBeReplaced(card, player)) num += get.numOf(types, type); + return num; + }, 0)) + } + //判断一名角色是否拥有未被废除的某个区域 + //type为要判断的区域 若为空 则判断玩家是否有任意一个未被废除的区域 + hasEnabledSlot(type) { + var player = this; + if (type == "horse" || type == "equip3_4") { + return player.hasEnabledSlot(3) && (get.is.mountCombined() || player.hasEnabledSlot(4)); + } + // else if(type=="equip3_4"){ + // type="equip3"; + // } + else if (get.is.mountCombined() && type == "equip4") { + return false; + } + return player.countEnabledSlot(type) > 0; + } + //判断一名角色的某个区域未被废除的数量 + //用法同上 + countEnabledSlot(type) { + var player = this; + var map = (player.expandedSlots || {}); + if (!type) { + num = 0; + for (var i = 1; i <= 5; i++) { + num += player.countEnabledSlot(i); + } + return num; + } + else { + if (typeof type == "number") type = ("equip" + type); + if (get.is.mountCombined() && type == "equip4") { + return 0; + } + var slots = 1; + var num = map[type]; + if (typeof num == "number" && num > 0) slots += num; + slots -= player.countDisabledSlot(type); + return slots; + } + } + //获取一名角色装备区内某种类型的装备牌 + //参数可以为数字/区域字符串/实体牌/虚拟牌/牌名 + getEquips(subtype) { + var type = (typeof subtype); + switch (type) { + case "string": + if (subtype == "equip3_4") { + const cards = []; + cards.addArray(this.getEquips(3)); + cards.addArray(this.getEquips(4)); + return cards; + } + else if (subtype.startsWith("equip") && parseInt(subtype.slice(5)) > 0) { + break; + } + else if (lib.card[subtype]) { + return this.getCards("e", card => card.name == subtype); + } + else return []; + case "number": + subtype = "equip" + subtype; + break; + case "object": + subtype = get.subtype(subtype, false); + break; + default: + return []; + } + if (!subtype) return []; + return this.getCards("e", function (card) { + return get.subtypes(card, false).contains(subtype); + }) + } + //新的废除装备区/恢复装备区/扩展装备区 + //参数:废除来源角色(不写默认当前事件角色),废除区域(数字/区域字符串/数组,可以写多个,重复废除) + disableEquip() { + var next = game.createEvent("disableEquip"); + next.player = this; + next.slots = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + for (var arg of arguments[i]) { + if (typeof arg == "string") { + if (arg.startsWith("equip") && parseInt(arg.slice(5)) > 0) next.slots.push(arg); + } + else if (typeof arg == "number") { + next.slots.push("equip" + arg); + } + } + } + else if (typeof arguments[i] == "string") { + if (arguments[i].startsWith("equip") && parseInt(arguments[i].slice(5)) > 0) next.slots.push(arguments[i]); + } + else if (typeof arguments[i] == "number") { + next.slots.push("equip" + arguments[i]); + } + } + if (!next.source) next.source = _status.event.player; + if (!next.slots.length) { + _status.event.next.remove(next); + } + next.setContent("disableEquip"); + return next; + } + enableEquip() { + var next = game.createEvent("enableEquip"); + next.player = this; + next.slots = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + for (var arg of arguments[i]) { + if (typeof arg == "string") { + if (arg.startsWith("equip") && parseInt(arg.slice(5)) > 0) next.slots.push(arg); + } + else if (typeof arg == "number") { + next.slots.push("equip" + arg); + } + } + } + else if (typeof arguments[i] == "string") { + if (arguments[i].startsWith("equip") && parseInt(arguments[i].slice(5)) > 0) next.slots.push(arguments[i]); + } + else if (typeof arguments[i] == "number") { + next.slots.push("equip" + arguments[i]); + } + } + if (!next.source) next.source = _status.event.player; + if (!next.slots.length) { + _status.event.next.remove(next); + } + next.setContent("enableEquip"); + return next; + } + expandEquip() { + var next = game.createEvent("expandEquip"); + next.player = this; + next.slots = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + for (var arg of arguments[i]) { + if (typeof arg == "string") { + if (arg.startsWith("equip") && parseInt(arg.slice(5)) > 0) next.slots.push(arg); + } + else if (typeof arg == "number") { + next.slots.push("equip" + arg); + } + } + } + else if (typeof arguments[i] == "string") { + if (arguments[i].startsWith("equip") && parseInt(arguments[i].slice(5)) > 0) next.slots.push(arguments[i]); + } + else if (typeof arguments[i] == "number") { + next.slots.push("equip" + arguments[i]); + } + } + if (!next.source) next.source = _status.event.player; + if (!next.slots.length) { + _status.event.next.remove(next); + } + next.setContent("expandEquip"); + return next; + } + //判断判定区是否被废除 + isDisabledJudge() { + return Boolean(this.storage._disableJudge); + } + //同步显示扩展装备区状态 + $syncExpand(map) { + var player = this; + if (!map) { + map = (player.expandedSlots || {}); + } + game.addVideo("$syncExpand", player, get.copy(map)) + game.broadcast(function (player, map) { + player.expandedSlots = map; + player.$syncExpand(map); + }, player, map); + player.markSkill("expandedSlots"); + } + //同步装备区废除牌显示状态 + $syncDisable(map) { + const player = this; + const suits = { equip3: "+1马栏", equip4: "-1马栏", equip6: "特殊栏" }; + if (get.is.mountCombined()) suits.equip3 = "坐骑栏"; + if (!map) { + map = (player.disabledSlots || {}); + } + game.addVideo("$syncDisable", player, get.copy(map)) + game.broadcast(function (player, map) { + player.disabledSlots = map; + player.$syncDisable(map); + }, player, map) + const map2 = get.copy(map); + const cards = Array.from(player.node.equips.childNodes); + for (const card of cards) { + if (card.name.startsWith("feichu_")) { + const index = card.name.slice(7); + if (!map2[index]) map2[index] = 0; + map2[index]--; + } + } + for (const index in map2) { + if (!index.startsWith("equip") || !(parseInt(index.slice(5)) > 0)) continue; + const num = map2[index]; + if (num > 0) { + for (let i = 0; i < num; i++) { + const card = game.createCard("feichu_" + index, (suits[index] || (get.translation(index) + "栏")), ""); + card.fix(); + card.style.transform = ""; + card.classList.remove("drawinghidden"); + card.classList.add("feichu"); + delete card._transform; + const equipNum = get.equipNum(card); + let equipped = false; + for (let j = 0; j < player.node.equips.childNodes.length; j++) { + if (get.equipNum(player.node.equips.childNodes[j]) >= equipNum) { + player.node.equips.insertBefore(card, player.node.equips.childNodes[j]); + equipped = true; + break; + } + } + if (!equipped) { + player.node.equips.appendChild(card); + if (_status.discarded) { + _status.discarded.remove(card); + } + } + } + } + else if (num < 0) { + for (let i = 0; i > num; i--) { + const card = cards.find(card => card.name == "feichu_" + index); + if (card) { + player.node.equips.removeChild(card); + cards.remove(card); + } + } + } + } + } + //以下函数涉及到本次更新内容而进行修改 + canEquip(name, replace) { + const ranges = get.subtypes(name), rangex = [], player = this, combined = get.is.mountCombined(); + if (combined) { + ranges.forEach(type => { + if (type == "equip3" || type == "equip4") rangex.add("equip3_4"); + else rangex.add(type) + }) + } + else { + rangex.push(...new Set(ranges)); + } + for (let range of rangex) { + let num = this.countEquipableSlot(range); + let num2 = get.numOf(rangex, range); + if (!replace) num -= this.getEquips(range).filter(card => lib.filter.canBeReplaced(card, player)).length; + if (num < num2) return false; + } + return true; + } + //以下函数将不再进行后续维护 + countDisabled() { + return this.countDisabledSlot.apply(this, arguments) + } + isDisabled(arg) { + return this.hasDisabledSlot(arg) && !this.hasEnabledSlot(arg); + } + isEmpty(num) { + return this.countEnabledSlot(num) > this.getEquips(num).length; + } + //以下函数将被废弃 + $disableEquip() { + } + $enableEquip() { + } + //装备区End + chooseToDebate() { + var next = game.createEvent("chooseToDebate"); + next.player = this; + next._args = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "players") { + next.list = arguments[i].slice(0); + } + else { + next._args.push(arguments[i]); + } + } + next.setContent("chooseToDebate"); + return next; + } + cooperationWith(target, type, reason) { + var player = this; + if (!player.storage.cooperation) player.storage.cooperation = []; + var info = { + target: target, + type: type, + reason: reason, + }; + player.storage.cooperation.add(info); + player.addTempSkill("cooperation", { player: "dieAfter" }); + player.addSkill("cooperation_" + type, { player: "dieAfter" }); + game.log(player, "向", target, "发起了“协力”,合作类型是", "#g" + get.translation("cooperation_" + type)); + } + chooseCooperationFor() { + var next = game.createEvent("chooseCooperationFor"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.target = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + next.cardlist = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.reason = arguments[i]; + } + } + if (!next.cardlist) next.cardlist = ["cooperation_damage", "cooperation_draw", "cooperation_discard", "cooperation_use"]; + next.setContent("chooseCooperationFor"); + return next; + } + checkCooperationStatus(target, reason) { + var storage = this.getStorage("cooperation"); + for (var info of storage) { + if (info.target == target && info.reason == reason) { + var skill = lib.skill["cooperation_" + info.type]; + if (skill && skill.checkx && skill.checkx(info)) return true; + } + } + return false; + } + removeCooperation(info) { + var player = this; + var storage = player.getStorage("cooperation"); + if (!storage.contains(info)) return; + storage.remove(info); + var unmark = true, reason = info.type; + if (!storage.length) { + player.removeSkill("cooperation"); + } + else { + for (var i of storage) { + if (i.type == reason) { + unmark = false; + break; + } + } + } + if (unmark) player.removeSkill("cooperation_" + reason); + else player.markSkill("cooperation_" + reason); + } + hasClan(clan, unseen) { + if (unseen || !this.isUnseen(0)) { + var info = lib.character[this.name1]; + if (info && info[4]) { + for (var i of info[4]) { + if (typeof i == "string" && i.startsWith("clan:") && i.slice(5) == clan) return true; + } + } + } + if (this.name2 && (unseen || !this.isUnseen(1))) { + var info = lib.character[this.name2]; + if (info && info[4]) { + for (var i of info[4]) { + if (typeof i == "string" && i.startsWith("clan:") && i.slice(5) == clan) return true; + } + } + } + return false; + } + changeZhuanhuanji(skill) { + var player = this, info = get.info(skill), zhuanhuan = info.zhuanhuanji; + if (typeof zhuanhuan == "function") zhuanhuan(player, skill); + else if (zhuanhuan == "number") player.addMark(skill, 1, false); + else player.storage[skill] = !player.storage[skill]; + game.broadcastAll(function (player, skill) { + player.$changeZhuanhuanji(skill); + }, player, skill); + } + $changeZhuanhuanji(skill) { + var mark = this.marks[skill]; + if (mark) { + if (mark.firstChild.reversed) { + mark.firstChild.reversed = false; + mark.firstChild.style.transform = "none"; + } + else { + mark.firstChild.reversed = true; + mark.firstChild.style.transform = "rotate(180deg)"; + } + } + } + setSeatNum(num) { + _status.seatNumSettled = true; + game.broadcastAll(function (player, num) { + player.seatNum = num; + }, this, num); + } + getSeatNum() { + if (typeof this.seatNum == "number") return this.seatNum; + return 0; + } + hasSex(sex) { + if (this.sex == "unknown") return false; + if (this.sex == "double") return true; + return this.sex == sex; + } + sameSexAs(target) { + var sex1 = this.sex, sex2 = target.sex; + if (sex1 == "unknown" || sex2 == "unknown") return false; + if (sex1 == "double" || sex2 == "double") return true; + return sex1 == sex2; + } + differentSexFrom(target) { + var sex1 = this.sex, sex2 = target.sex; + if (sex1 == "unknown" || sex2 == "unknown") return false; + if (sex1 == "double" || sex2 == "double") return true; + return sex1 != sex2; + } + addSkillBlocker(skill) { + if (!this.storage.skill_blocker) this.storage.skill_blocker = []; + this.storage.skill_blocker.push(skill); + } + removeSkillBlocker(skill) { + if (this.storage.skill_blocker) { + this.storage.skill_blocker.remove(skill); + if (!this.storage.skill_blocker.length) delete this.storage.skill_blocker; + } + } + loseToSpecial(cards, tag, target) { + var next = game.loseAsync({ + player: this, + cards: cards, + tag: tag, + toStorage: true, + target: target || this, + }); + next.setContent(function () { + "step 0" + player.lose(cards, ui.special).set("getlx", false); + "step 1" + var cards = event.cards.slice(0); + cards.removeArray(player.getCards("hejsx")); + if (cards.length) target.directgains(cards, null, event.tag) + }); + return next; + } + addGaintag(cards, tag) { + if (get.itemtype(cards) == "card") cards = [cards]; + game.addVideo("addGaintag", this, [get.cardsInfo(cards), tag]); + game.broadcastAll(function (player, cards, tag) { + var hs = player.getCards("hejsx"); + for (var i of cards) { + if (hs.contains(i)) i.addGaintag(tag); + } + }, this, cards, tag); + } + removeGaintag(tag, cards) { + cards = cards || this.getCards("h"); + game.addVideo("removeGaintag", this, [tag, get.cardsInfo(cards)]); + game.broadcastAll(function (player, tag, cards) { + for (var i of cards) i.removeGaintag(tag); + }, this, tag, cards); + } + canSave(target) { + var player = this; + if (player.hasSkillTag("save", true, target, true)) return true; + var name = {}, hs = player.getCards("hs"); + for (var i of hs) name[get.name(i)] = true; + for (var i in lib.card) { + if (lib.card[i].savable && (lib.inpile.contains(i) || name[i])) { + if (lib.filter.cardSavable({ name: i }, player, target) && (_status.connectMode || player.hasUsableCard(i))) return true; + } + } + return false; + } + canSaveCard(card, target) { + var player = this; + var mod2 = game.checkMod(card, player, "unchanged", "cardEnabled2", player); + if (mod2 != "unchanged") return mod2; + var mod = game.checkMod(card, player, target, "unchanged", "cardSavable", player); + if (mod != "unchanged") return mod; + var savable = get.info(card).savable; + if (typeof savable == "function") savable = savable(card, player, target); + return savable; + } + showCharacter(num, log) { + var toShow = []; + if ((num == 0 || num == 2) && this.isUnseen(0)) toShow.add(this.name1); + if ((num == 1 || num == 2) && this.isUnseen(1)) toShow.add(this.name2); + if (!toShow.length) return; + this.$showCharacter(num, log); + var next = game.createEvent("showCharacter", false); + next.player = this; + next.num = num; + next.toShow = toShow; + next._args = Array.from(arguments); + next.setContent("showCharacter"); + var evt = _status.event; + evt.next.remove(next); + if (evt.logSkill) evt = evt.getParent(); + evt.after.push(next); + return next; + } + $showCharacter(num, log) { + if (num == 0 && !this.isUnseen(0)) { + return; + } + if (num == 1 && (!this.name2 || !this.isUnseen(1))) { + return; + } + if (!this.isUnseen(2)) { + return; + } + game.addVideo("showCharacter", this, num); + var skills; + switch (num) { + case 0: + if (log !== false) game.log(this, "展示了主将", "#b" + this.name1); + this.name = this.name1; + skills = lib.character[this.name][3] || []; + this.sex = lib.character[this.name][0]; + if (this.group == "unknown") this.group = lib.character[this.name][1]; + this.classList.remove("unseen"); + break; + case 1: + if (log !== false) game.log(this, "展示了副将", "#b" + this.name2); + skills = lib.character[this.name2][3] || []; + if (this.sex == "unknown") this.sex = lib.character[this.name2][0]; + if (this.name.startsWith("unknown")) this.name = this.name2; + this.classList.remove("unseen2"); + break; + case 2: + if (log !== false) { + if (this.name2) game.log(this, "展示了主将", "#b" + this.name1, "、副将", "#b" + this.name2); + else game.log(this, "展示了主将", "#b" + this.name1); + } + this.name = this.name1; + var skills = (lib.character[this.name][3] || []); + if (this.name2) skills = skills.concat(lib.character[this.name2][3] || []); + this.sex = lib.character[this.name][0]; + if (this.group == "unknown") this.group = lib.character[this.name][1]; + this.classList.remove("unseen"); + this.classList.remove("unseen2"); + break; + } + if (!this.isUnseen(2)) { + delete this.storage.nohp; + this.hp = this.storage.rawHp + this.maxHp - 1; + this.maxHp = this.storage.rawMaxHp + this.maxHp - 1; + this.node.hp.show(); + this.update(); + } + game.broadcast(function (player, name, sex, num, group) { + player.group = group; + player.name = name; + player.sex = sex; + switch (num) { + case 0: player.classList.remove("unseen"); break; + case 1: player.classList.remove("unseen2"); break; + case 2: player.classList.remove("unseen"); player.classList.remove("unseen2"); break; + } + if (!player.isUnseen(2)) { + delete player.storage.nohp; + player.node.hp.show(); + player.update(); + } + }, this, this.name, this.sex, num, this.group); + skills = skills.filter(skill => { + var info = get.info(skill); + if (info && info.zhuSkill && !this.isZhu2()) return false; + return true; + }); + for (var i = 0; i < skills.length; i++) { + if (this.hiddenSkills.contains(skills[i])) { + this.hiddenSkills.remove(skills[i]); + this.addSkill(skills[i]); + } + } + this.checkConflict(); + } + chooseToPlayBeatmap(beatmap) { + var next = game.createEvent("chooseToPlayBeatmap"); + next.player = this; + next.beatmap = beatmap; + next._args = Array.from(arguments); + next.setContent("chooseToPlayBeatmap"); + return next; + } + chooseToMove() { + var next = game.createEvent("chooseToMove"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + next.setContent("chooseToMove"); + next.filterOk = function () { return true }; + next.filterMove = function () { return true }; + return next; + } + chooseToGuanxing(num) { + var next = game.createEvent("chooseToGuanxing"); + next.num = num || 1; + next.player = this; + next.setContent("chooseToGuanxing"); + return next; + } + $throwEmotion(target, name, rotate) { + game.addVideo("throwEmotion", this, [target.dataset.position, name]); + var getLeft = function (player) { + if (player == game.me && !ui.fakeme && !ui.chess) return player.getLeft() + player.node.avatar.offsetWidth / 2; + return player.getLeft() + player.offsetWidth / 2; + } + var player = this; + var emotion = ui.create.div("", `
`, game.chess ? ui.chess : ui.window); + emotion.style.width = "60px"; + emotion.style.height = "60px"; + var width = emotion.offsetWidth / 2; + var height = emotion.offsetHeight / 2; + if (game.chess) width += 60; + var left = getLeft(player) - width; + var top = player.getTop() + player.offsetHeight / 3 - height; + emotion.style.left = left + "px"; + emotion.style.top = top + "px"; + var left2 = getLeft(target) - width; + var top2 = target.getTop() + target.offsetHeight / 3 - height; + if (["egg", "flower", "shoe"].contains(name) || rotate) { + var num1 = 0.95 + Math.random() * (1.1 - 0.95); + var num2 = 1 + Math.random() * (3 - 1); + var left2 = getLeft(target) / num1 - width; + var top2 = target.getTop() + target.offsetHeight / num2 - height; + } + else { + var left2 = getLeft(target) - width; + var top2 = target.getTop() + target.offsetHeight / 3 - height; + } + emotion.style["z-index"] = 10; + emotion.style.transform = "translateY(" + (top2 - top) + "px) translateX(" + (left2 - left) + "px)"; + if (["egg", "flower", "shoe"].contains(name) || rotate) emotion.firstElementChild.style.transform = "rotate(1440deg)"; + if (lib.config.background_audio) game.playAudio("effect", "throw_" + name + get.rand(1, 2)); + setTimeout(function () { + emotion.innerHTML = `
`; + setTimeout(function () { + emotion.delete(); + }, 1200); + }, 600); + } + tryJudgeAnimate(bool) { + var player = this; + game.broadcast(function (player, bool) { + player.trySkillAnimate(bool); + }, player, bool); + if (bool) this.popup("判定生效", "wood", false); + else this.popup("判定失效", "fire", false); + } + trySkillAnimate(name, popname, checkShow) { + if (!game.online && lib.config.skill_animation_type != "off" && lib.skill[name] && lib.skill[name].skillAnimation) { + if (lib.config.skill_animation_type == "default") { + checkShow = checkShow || "main"; + } + else { + checkShow = false; + } + if (lib.skill[name].textAnimation) { + checkShow = false; + } + this.$skill(lib.skill[name].animationStr || lib.translate[name], lib.skill[name].skillAnimation, lib.skill[name].animationColor, checkShow); + return; + } + var player = this; + game.broadcast(function (player, name, popname) { + player.trySkillAnimate(name, popname); + }, player, name, popname); + if (lib.animate.skill[name]) lib.animate.skill[name].apply(this, arguments); + else { + if (popname != name) this.popup(popname, "water", false); + else this.popup(get.skillTranslation(name, this), "water", false); + } + } + tryCardAnimate(card, name, nature, popname) { + var player = this; + game.broadcast(function (player, card, name, nature, popname) { + player.tryCardAnimate(card, name, nature, popname); + }, player, card, name, nature, popname); + if (lib.animate.card[card.name]) lib.animate.card[card.name].apply(this, arguments); + else { + if (!lib.config.show_card_prompt) return; + if (get.type(card) == "equip" && lib.config.hide_card_prompt_equip) return; + if (get.type(card) == "basic" && lib.config.hide_card_prompt_basic) return; + if (popname) player.popup({ name: card.name, nature: card.nature }, nature, false); + else player.popup(name, nature, false); + } + } + hasUsableCard(name) { + var player = this; + if (player.countCards("hs", name)) return true; + var skills = player.getSkills("invisible").concat(lib.skill.global); + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var ifo = get.info(skills[i]); + if (ifo.viewAs && typeof ifo.viewAs != "function" && ifo.viewAs.name == name) { + if (!ifo.viewAsFilter || ifo.viewAsFilter(player) !== false) { + return true; + } + } + else { + var hiddenCard = get.info(skills[i]).hiddenCard; + if (typeof hiddenCard == "function" && hiddenCard(player, name)) { + return true; + } + } + } + } + inRange(to) { + var from = this; + if (from == to || from.hasSkill("undist") || to.hasSkill("undist")) return false; + if (!game.players.contains(from) && !game.dead.contains(from)) return false; + if (!game.players.contains(to) && !game.dead.contains(to)) return false; + var mod1 = game.checkMod(from, to, "unchanged", "inRange", from); + if (mod1 != "unchanged") return mod1; + var mod2 = game.checkMod(from, to, "unchanged", "inRangeOf", to); + if (mod2 != "unchanged") return mod2; + var range = from.getAttackRange(); + if (range < 1) return false; + var player = from, m, n = 1, i; + var fxy, txy; + if (game.chess) { + fxy = from.getXY(); + txy = to.getXY(); + n = Math.abs(fxy[0] - txy[0]) + Math.abs(fxy[1] - txy[1]); + } + else if (to.isMin(true) || from.isMin(true)) {/* empty */ } + else { + var length = game.players.length; + var totalPopulation = game.players.length + game.dead.length + 1; + for (var iwhile = 0; iwhile < totalPopulation; iwhile++) { + if (player.nextSeat != to) { + player = player.nextSeat; + if (player.isAlive() && !player.isOut() && !player.hasSkill("undist") && !player.isMin(true)) n++; + } + else { + break; + } + } + for (i = 0; i < game.players.length; i++) { + if (game.players[i].isOut() || game.players[i].hasSkill("undist") || game.players[i].isMin(true)) length--; + } + if (from.isDead()) length++; + if (to.isDead()) length++; + var left = from.hasSkillTag("left_hand"); + var right = from.hasSkillTag("right_hand"); + if (left === right) n = Math.min(n, length - n); + else if (left == true) n = length - n; + } + n = game.checkMod(from, to, n, "globalFrom", from); + n = game.checkMod(from, to, n, "globalTo", to); + m = n; + m = game.checkMod(from, to, m, "attackFrom", from); + m = game.checkMod(from, to, m, "attackTo", to); + var equips1 = from.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }), equips2 = to.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + for (i = 0; i < equips1.length; i++) { + var info = get.info(equips1[i]).distance; + if (!info) continue; + if (info.globalFrom) { + m += info.globalFrom; + n += info.globalFrom; + } + } + for (i = 0; i < equips2.length; i++) { + var info = get.info(equips2[i]).distance; + if (!info) continue; + if (info.globalTo) { + m += info.globalTo; + n += info.globalTo; + } + if (info.attaclTo) { + m += info.attaclTo; + } + } + return m <= range; + } + inRangeOf(source) { + return source.inRange(this); + } + //Get the player"s HP not less than 0. Set “raw” to true to get the player"s raw HP instead. + //获取角色的体力值。设置“raw”为true以获取角色的体力。 + getHp(raw) { + return raw ? this.hp : Math.max(0, this.hp); + } + //Set “raw” to true to get the player"s raw damaged HP instead. + //设置“raw”为true以获取角色已损失的体力。 + getDamagedHp(raw) { + return this.maxHp - this.getHp(raw); + } + changeGroup(group, log, broadcast) { + var next = game.createEvent("changeGroup"); + next.player = this; + next.log = true; + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (lib.group.contains(arg)) { + next.group = arg; + } + else if (typeof arg === "boolean") { + next.log = arg; + } + else if (arg === "nobroadcast") { + next.broadcast = false; + } + } + next.setContent("changeGroup"); + return next; + } + chooseToDuiben(target) { + var next = game.createEvent("chooseToDuiben"); + next.player = this; + next.target = target; + next.setContent("chooseToDuiben"); + return next; + } + chooseToPSS(target) { + var next = game.createEvent("chooseToPSS"); + next.player = this; + next.target = target; + next.setContent("chooseToPSS"); + return next; + } + chooseToEnable() { + var next = game.createEvent("chooseToEnable"); + next.player = this; + next.setContent("chooseToEnable"); + return next; + } + chooseToDisable(horse) { + var next = game.createEvent("chooseToDisable"); + next.player = this; + if (horse) next.horse = true; + next.setContent("chooseToDisable"); + return next; + } + isPhaseUsing(notmeisok) { + if (!notmeisok && _status.currentPhase != this) return false; + return _status.event.name == "phaseUse" || _status.event.getParent("phaseUse").name == "phaseUse"; + } + swapEquip(target) { + var next = game.createEvent("swapEquip"); + next.player = this; + next.target = target; + next.setContent("swapEquip"); + return next; + } + canCompare(target) { + if (this == target) return false; + if (!this.countCards("h") || !target.countCards("h")) return false; + if (this.hasSkillTag("noCompareSource") || target.hasSkillTag("noCompareTarget")) return false; + return true; + } + $disableJudge() { + var player = this; + game.addVideo("$disableJudge", player); + player.storage._disableJudge = true; + var card = game.createCard("disable_judge", "", ""); + card.fix(); + card.classList.add("feichu"); + card.style.transform = ""; + card.classList.add("drawinghidden"); + player.node.judges.insertBefore(card, player.node.judges.firstChild); + ui.updatej(player); + } + $enableJudge() { + var player = this; + game.addVideo("$enableJudge", player); + player.storage._disableJudge = false; + for (var i = 0; i < player.node.judges.childNodes.length; i++) { + if (player.node.judges.childNodes[i].name == "disable_judge") { + player.node.judges.removeChild(player.node.judges.childNodes[i]); + break; + } + } + } + disableJudge() { + var next = game.createEvent("disableJudge"); + next.player = this; + next.source = _status.event.player; + next.setContent("disableJudge"); + return next; + } + enableJudge() { + var next = game.createEvent("enableJudge"); + next.player = this; + next.source = _status.event.player; + next.setContent("enableJudge"); + return next; + } + //原有函数 + init(character, character2, skill, update) { + if (typeof character == "string" && !lib.character[character]) { + lib.character[character] = get.character(character); + } + if (typeof character2 == "string" && !lib.character[character2]) { + lib.character[character2] = get.character(character2); + } + if (!lib.character[character]) return; + if (get.is.jun(character2)) { + var tmp = character; + character = character2; + character2 = tmp; + } + if (character2 == false) { + skill = false; + character2 = null; + } + var info = lib.character[character]; + if (!info) { + info = ["", "", 1, [], []]; + } + if (!info[4]) { + info[4] = []; + } + var skills = info[3].slice(0); + this.clearSkills(true); + + var hp1 = get.infoHp(info[2]); + var maxHp1 = get.infoMaxHp(info[2]); + var hujia1 = get.infoHujia(info[2]); + + this.name = character; + this.name1 = character; + this.tempname = []; + this.sex = info[0]; + this.group = info[1]; + this.hp = hp1; + this.maxHp = maxHp1; + this.hujia = hujia1; + this.node.intro.innerHTML = lib.config.intro; + this.node.name.dataset.nature = get.groupnature(this.group); + lib.setIntro(this); + this.node.name.innerHTML = get.slimName(character); + if (this.classList.contains("minskin") && this.node.name.querySelectorAll("br").length >= 4) { + this.node.name.classList.add("long"); + } + if (info[4].contains("hiddenSkill") && !this.noclick) { + if (!this.hiddenSkills) this.hiddenSkills = []; + this.hiddenSkills.addArray(skills); + skills = []; + this.name = "unknown"; + this.sex = "male"; + this.storage.nohp = true; + skills.add("g_hidden_ai"); + } + if (character2 && lib.character[character2]) { + var info2 = lib.character[character2]; + if (!info2) { + info2 = ["", "", 1, [], []]; + } + if (!info2[4]) { + info2[4] = []; + } + + this.name2 = character2; + var hp2 = get.infoHp(info2[2]); + var maxHp2 = get.infoMaxHp(info2[2]); + var hujia2 = get.infoHujia(info2[2]); + this.hujia += hujia2; + var double_hp; + if (_status.connectMode || get.mode() == "single") { + double_hp = "pingjun"; + } + else { + double_hp = get.config("double_hp"); + } + switch (double_hp) { + case "pingjun": { + this.maxHp = Math.floor((maxHp1 + maxHp2) / 2); + this.hp = Math.floor((hp1 + hp2) / 2); + this.singleHp = ((maxHp1 + maxHp2) % 2 === 1); + break; + } + case "zuidazhi": { + this.maxHp = Math.max(maxHp1, maxHp2); + this.hp = Math.max(hp1, hp2); + break; + } + case "zuixiaozhi": { + this.maxHp = Math.min(maxHp1, maxHp2); + this.hp = Math.min(hp1, hp2); + break; + } + case "zonghe": { + this.maxHp = maxHp1 + maxHp2; + this.hp = hp1 + hp2; + break; + } + default: { + this.maxHp = maxHp1 + maxHp2 - 3; + this.hp = hp1 + hp2 - 3; + } + } + if (info2[4].contains("hiddenSkill") && !this.noclick) { + if (!this.hiddenSkills) this.hiddenSkills = []; + this.hiddenSkills.addArray(info2[3]); + this.storage.nohp = true; + skills.add("g_hidden_ai"); + } + else skills = skills.concat(info2[3]); + } + if (this.storage.nohp) { + this.storage.rawHp = this.hp; + this.storage.rawMaxHp = this.maxHp; + this.hp = 1; + this.maxHp = 1; + this.node.hp.hide(); + } + if (skill != false) { + skills = skills.filter(skill => { + var info = get.info(skill); + if (info && info.zhuSkill && !this.isZhu2()) return false; + return true; + }); + for (var i = 0; i < skills.length; i++) { + this.addSkill(skills[i], null, true); + } + this.checkConflict(); + } + lib.group.add(this.group); + + this.$init(character, character2); + + if (this.inits) { + for (var i = 0; i < this.inits.length; i++) { + this.inits[i](this); + } + } + if (this._inits) { + for (var i = 0; i < this._inits.length; i++) { + this._inits[i](this); + } + } + if (update !== false) this.$update(); + return this; + } + $init(character, character2) { + this.classList.add("fullskin"); + var info = lib.character[character]; + if (!info) { + info = ["", "", 1, [], []]; + } + if (!info[4]) { + info[4] = []; + } + + if (!game.minskin && get.is.newLayout() && !info[4].contains("minskin")) { + this.classList.remove("minskin"); + this.node.avatar.setBackground(character, "character"); + } + else { + this.node.avatar.setBackground(character, "character"); + if (info[4].contains("minskin")) { + this.classList.add("minskin"); + } + else if (game.minskin) { + this.classList.add("minskin"); + } + else { + this.classList.remove("minskin"); + } + } + + this.node.avatar.show(); + this.node.count.show(); + this.node.equips.show(); + + this.node.intro.innerHTML = lib.config.intro; + this.node.name.dataset.nature = get.groupnature(this.group); + lib.setIntro(this); + this.node.name.innerHTML = get.slimName(character); + if (this.classList.contains("minskin") && this.node.name.querySelectorAll("br").length >= 4) { + this.node.name.classList.add("long"); + } + if (info[4].contains("hiddenSkill") && !this.noclick) { + this.classList.add(_status.video ? "unseen_v" : "unseen"); + if (!this.node.name_seat && !_status.video) { + this.node.name_seat = ui.create.div(".name.name_seat", get.verticalStr(get.translation(this.name)), this); + this.node.name_seat.dataset.nature = get.groupnature(this.group); + } + } + if (character2 && lib.character[character2]) { + var info2 = lib.character[character2]; + if (!info2) { + info2 = ["", "", 1, [], []]; + } + if (!info2[4]) { + info2[4] = []; + } + this.classList.add("fullskin2"); + this.node.avatar2.setBackground(character2, "character"); + this.node.avatar2.show(); + this.name2 = character2; + + this.node.count.classList.add("p2"); + if (info2[4].contains("hiddenSkill") && !this.noclick) { + this.classList.add(_status.video ? "unseen2_v" : "unseen2"); + } + this.node.name2.innerHTML = get.slimName(character2); + } + if (this.storage.nohp) { + this.node.hp.hide(); + } + + return this; + } + initOL(name, character) { + this.node.avatar.setBackground(character, "character"); + this.node.avatar.show(); + this.node.name.innerHTML = get.verticalStr(name); + this.nickname = name; + this.avatar = character; + this.node.nameol.innerHTML = ""; + if (lib.character[character]) this.sex = lib.character[character][0]; + } + uninitOL() { + this.node.avatar.hide(); + this.node.name.innerHTML = ""; + this.node.identity.firstChild.innerHTML = ""; + delete this.nickname; + delete this.avatar; + delete this.sex; + } + initRoom(info, info2) { + var str = ""; + this.serving = false; + if (!info || info == "server") { + this.roomempty = true; + str = "空房间"; + this.roomfull = false; + this.roomgaming = false; + this.version = null; + if (info == "server") { + this.serving = true; + } + } + else { + var config = info[2]; + this.key = info[4]; + this.roomempty = false; + str += get.modetrans(config); + str += " 模式 "; + for (var i = str.length; i < 11; i++) str += " "; + this.version = config.version; + if (config.gameStarted) { + str += `游戏中 `; + if (config.observe && config.observeReady && this.version == lib.versionOL) { + this.classList.remove("exclude"); + } + else { + this.classList.add("exclude"); + } + } + else { + str += `等待中 `; + if (this.version != lib.versionOL) { + this.classList.add("exclude"); + } + else { + this.classList.remove("exclude"); + } + } + this.maxHp = parseInt(config.number); + this.hp = Math.min(this.maxHp, info[3]); + if (this.hp < this.maxHp || config.gameStarted) str += ("人数:" + this.hp + "/" + this.maxHp); + else str += `人数:${this.hp}/${this.maxHp}`; + + str += (" (" + info[0].slice(0, 12) + " 的房间)"); + if (config.mode != "guozhan" && (config.mode != "doudizhu" || config.doudizhu_mode != "online")) { + str += "【"; + for (var i = 0; i < config.cardPack.length; i++) { + str += (get.translation(config.cardPack[i] + "_card_config").slice(0, 2)); + if (i < config.cardPack.length - 1) str += "+"; + } + str += "】"; + } + this.config = config; + if (this.hp == this.maxHp && !config.gameStarted) { + this.roomfull = true; + } + else { + this.roomfull = false; + } + if (config.gameStarted && (!config.observe || !config.observeReady)) { + this.roomgaming = true; + } + else { + this.roomgaming = false; + } + } + this.firstChild.innerHTML = str; + return this; + } + reinit(from, to, maxHp, online) { + var info1 = lib.character[from]; + var info2 = lib.character[to]; + var smooth = true, replaced = null; + if (maxHp == "nosmooth") { + smooth = false; + maxHp = null; + } + if (this.name2 == from) { + this.name2 = to; + } + else if (this.name == from || this.name1 == from) { + if (this.name1 == from) { + this.name1 = to; + } + if (!this.isUnseen(1)) { + this.name = to; + this.sex = info2[0]; + } + } + else { + return this; + } + if (online) { + return; + } + for (var i = 0; i < info1[3].length; i++) { + this.removeSkill(info1[3][i]); + } + for (var i = 0; i < info2[3].length; i++) { + var info = get.info(info2[3][i]); + if (info && info.zhuSkill && !this.isZhu2()) continue; + this.addSkill(info2[3][i]); + } + if (Array.isArray(maxHp)) { + this.maxHp = maxHp[1]; + this.hp = maxHp[0]; + } + else { + var num; + if (maxHp === false) { + num = 0; + } + else { + if (typeof maxHp != "number") { + maxHp = get.infoMaxHp(info2[2]); + } + num = maxHp - get.infoMaxHp(info1[2]); + } + if (typeof this.singleHp == "boolean") { + if (num % 2 != 0) { + if (this.singleHp) { + this.maxHp += (num + 1) / 2; + this.singleHp = false; + } + else { + this.maxHp += (num - 1) / 2; + this.singleHp = true; + if (!game.online) { + this.doubleDraw(); + } + } + } + else { + this.maxHp += num / 2; + } + } + else { + this.maxHp += num; + } + } + game.broadcast(function (player, from, to, skills) { + player.reinit(from, to, null, true); + player.applySkills(skills); + }, this, from, to, get.skillState(this)); + game.addVideo("reinit3", this, { + from: from, + to: to, + hp: this.maxHp, + avatar2: this.name2 == to + }); + + this.$reinit(from, to, maxHp, online); + this.update(); + } + $reinit(from, to, maxHp, online) { + var smooth = true; + if (maxHp == "nosmooth") { + smooth = false; + maxHp = null; + } + if (this.name2 == to) { + if (smooth) this.smoothAvatar(true); + this.node.avatar2.setBackground(to, "character"); + this.node.name2.innerHTML = get.slimName(to); + } + else if (this.name == to || this.name1 == to) { + if (smooth) this.smoothAvatar(false); + this.node.avatar.setBackground(to, "character"); + this.node.name.innerHTML = get.slimName(to); + + if (this == game.me && ui.fakeme) { + ui.fakeme.style.backgroundImage = this.node.avatar.style.backgroundImage; + } + } + } + uninit() { + this.expandedSlots = {}; + this.disabledSlots = {}; + + delete this.name; + delete this.name1; + delete this.tempname; + delete this.sex; + delete this.group; + delete this.hp; + delete this.maxHp; + delete this.hujia; + this.clearSkills(true); + + if (this.name2) { + delete this.singleHp; + delete this.name2; + } + for (var mark in this.marks) { + this.marks[mark].remove(); + } + ui.updatem(this); + + this.skipList = []; + this.skills = this.skills.filter(skill => { + return lib.skill[skill] && lib.skill[skill].superCharlotte; + }); + this.initedSkills = []; + this.additionalSkills = {}; + this.disabledSkills = {}; + this.hiddenSkills = []; + this.awakenedSkills = []; + this.forbiddenSkills = {}; + this.phaseNumber = 0; + this.stat = [{ card: {}, skill: {} }]; + this.tempSkills = {}; + this.storage = {}; + this.marks = {}; + this.ai = { friend: [], enemy: [], neutral: [] }; + + this.$uninit(); + + return this; + } + $uninit() { + this.$syncDisable(); + if (this.isDisabledJudge()) { + game.broadcastAll(function (player) { + player.storage._disableJudge = false; + for (var i = 0; i < player.node.judges.childNodes.length; i++) { + if (player.node.judges.childNodes[i].name == "disable_judge") { + player.node.judges.removeChild(player.node.judges.childNodes[i]); + break; + } + } + }, this); + } + this.node.avatar.hide(); + this.node.count.hide(); + if (this.node.wuxing) { + this.node.wuxing.hide(); + } + if (this.node.name_seat) { + this.node.name_seat.remove(); + delete this.node.name_seat; + } + this.node.hp.show(); + this.classList.remove("unseen"); + this.classList.remove("unseen2"); + + this.node.identity.style.backgroundColor = ""; + this.node.intro.innerHTML = ""; + this.node.name.innerHTML = ""; + this.node.hp.innerHTML = ""; + this.node.count.innerHTML = "0"; + + this.node.avatar2.hide(); + this.node.name2.innerHTML = ""; + this.classList.remove("fullskin2"); + this.node.count.classList.remove("p2"); + + for (var mark in this.marks) { + this.marks[mark].remove(); + } + ui.updatem(this); + } + getLeft() { + return this.offsetLeft; + } + getTop() { + return this.offsetTop; + } + smoothAvatar(vice, video) { + var div = ui.create.div(".fullsize"); + if (vice) { + div.style.background = getComputedStyle(this.node.avatar2).background; + this.node.avatar2.appendChild(div); + } + else { + div.style.background = getComputedStyle(this.node.avatar).background; + this.node.avatar.appendChild(div); + } + ui.refresh(div); + div.style.transition = "all 1s"; + setTimeout(function () { + div.classList.add("removing"); + setTimeout(function () { + div.remove(); + }, 2000); + }, 100); + if (video != false) { + game.addVideo("smoothAvatar", this, vice); + } + } + changeSeat(position, video) { + var player = this; + if (video !== false) game.addVideo("changeSeat", player, position); + var rect1 = player.getBoundingClientRect(); + player.style.transition = "all 0s"; + ui.refresh(player); + player.dataset.position = position; + var rect2 = player.getBoundingClientRect(); + var dx = rect1.left - rect2.left; + var dy = rect1.top - rect2.top; + if ((game.chess || (player.dataset.position != 0 && position != 0)) && player.classList.contains("linked")) { + player.style.transform = "rotate(-90deg) translate(" + (-dy) + "px," + (dx) + "px)"; + } + else { + player.style.transform = "translate(" + (dx) + "px," + (dy) + "px)"; + } + setTimeout(function () { + player.style.transition = ""; + ui.refresh(player); + player.style.transform = ""; + }, 100); + } + send() { + if (!this.ws || this.ws.closed) return this; + this.ws.send.apply(this.ws, arguments); + return this; + } + getId() { + if (_status.video || _status.connectMode) return this; + if (this.playerid) { + delete game.playerMap[this.playerid]; + } + this.playerid = get.id(); + game.playerMap[this.playerid] = this; + return this; + } + throwEmotion(target, emotion, rotate) { + game.broadcastAll(function (player, target, emotion, rotate) { + player.$throwEmotion(target, emotion, rotate); + }, this, target, emotion, rotate); + } + emotion(pack, id) { + var str = ``; + this.say(str); + game.broadcast(function (id, str) { + if (lib.playerOL[id]) { + lib.playerOL[id].say(str); + } + else if (game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == id) { + game.connectPlayers[i].say(str); + return; + } + } + } + }, this.playerid, str); + } + chat(str) { + if (get.is.banWords(str)) return; + this.say(str); + game.broadcast(function (id, str) { + if (lib.playerOL[id]) { + lib.playerOL[id].say(str); + } + else if (game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == id) { + game.connectPlayers[i].say(str); + return; + } + } + } + }, this.playerid, str); + } + say(str) { + str = str.replace(/##assetURL##/g, lib.assetURL); + var dialog = ui.create.dialog("hidden"); + dialog.classList.add("static"); + dialog.add(`
${str}
`); + dialog.classList.add("popped"); + ui.window.appendChild(dialog); + var width = dialog.content.firstChild.firstChild.offsetWidth; + if (width < 190) { + dialog._mod_height = -16; + } + else { + dialog.content.firstChild.style.textAlign = "left"; + } + dialog.style.width = (width + 16) + "px"; + var refnode; + if (this.node && this.node.avatar && this.parentNode == ui.arena) { + refnode = this.node.avatar; + } + if (refnode) { + lib.placePoppedDialog(dialog, { + clientX: (ui.arena.offsetLeft + this.getLeft() + refnode.offsetLeft + refnode.offsetWidth / 2) * game.documentZoom, + clientY: (ui.arena.offsetTop + this.getTop() + refnode.offsetTop + refnode.offsetHeight / 4) * game.documentZoom + }); + } + else { + lib.placePoppedDialog(dialog, { + clientX: (this.getLeft() + this.offsetWidth / 2) * game.documentZoom, + clientY: (this.getTop() + this.offsetHeight / 4) * game.documentZoom + }); + } + if (dialog._mod_height) { + dialog.content.firstChild.style.padding = 0; + } + setTimeout(function () { + dialog.delete(); + }, lib.quickVoice.includes(str) ? 3800 : 2000); + var name = get.translation(this.name); + var info = [name ? (name + "[" + this.nickname + "]") : this.nickname, str]; + lib.chatHistory.push(info); + if (_status.addChatEntry) { + if (_status.addChatEntry._origin.parentNode) { + _status.addChatEntry(info, false); + } + else { + delete _status.addChatEntry; + } + } + if (lib.config.background_speak && lib.quickVoice.includes(str)) { + game.playAudio("voice", (this.sex == "female" ? "female" : "male"), lib.quickVoice.indexOf(str)); + } + } + showGiveup() { + this._giveUp = true; + if (this == game.me) { + ui.create.giveup(); + } + else if (this.isOnline2()) { + this.send(ui.create.giveup); + } + } + applySkills(skills) { + for (var i in skills) { + if (i == "global") { + lib.skill.global = skills[i]; + } + //else if(i=="skillinfo"){ + // for(var j in skills[i]){ + // if(!lib.skill[j]){ + // lib.skill[j]={}; + // } + // lib.skill[j].chooseButton=skills[i][j]; + // } + //} + else if (i == "stat") { + this.stat = [skills.stat]; + } + else if (lib.playerOL[i]) { + for (var j in skills[i]) { + lib.playerOL[i][j] = skills[i][j]; + } + } + } + } + getState() { + var state = { + hp: this.hp, + maxHp: this.maxHp, + nickname: this.nickname, + sex: this.sex, + group: this.group, + name: this.name, + name1: this.name1, + name2: this.name2, + handcards: this.getCards("hs"), + gaintag: [], + equips: this.getCards("e"), + judges: this.getCards("j"), + specials: this.getCards("s"), + expansions: this.getCards("x"), + expansion_gaintag: [], + disableJudge: this.isDisabledJudge(), + disabledSlots: this.disabledSlots, + expandedSlots: this.expandedSlots, + views: [], + position: parseInt(this.dataset.position), + hujia: this.hujia, + side: this.side, + identityShown: this.identityShown, + identityNode: [this.node.identity.innerHTML, this.node.identity.dataset.color], + identity: this.identity, + dead: this.isDead(), + linked: this.isLinked(), + turnedover: this.isTurnedOver(), + out: this.isOut(), + phaseNumber: this.phaseNumber, + unseen: this.isUnseen(0), + unseen2: this.isUnseen(1), + seatNum: this.seatNum, + } + for (var i = 0; i < state.judges.length; i++) { + state.views[i] = state.judges[i].viewAs; + } + for (var i = 0; i < state.handcards.length; i++) { + state.gaintag[i] = state.handcards[i].gaintag; + } + for (var i = 0; i < state.expansions.length; i++) { + state.expansion_gaintag[i] = state.expansions[i].gaintag; + } + if (this.getModeState) { + state.mode = this.getModeState(); + } + return state; + } + setNickname(str) { + this.node.nameol.innerHTML = (str || this.nickname || "").slice(0, 12); + return this; + } + setAvatar(name, name2, video, fakeme) { + var node; + if (this.name2 == name) { + node = this.node.avatar2; + this.smoothAvatar(true, video); + } + else if (this.name == name) { + node = this.node.avatar; + this.smoothAvatar(false, video); + } + if (node) { + node.setBackground(name2, "character"); + if (this == game.me && ui.fakeme && fakeme !== false) { + ui.fakeme.style.backgroundImage = node.style.backgroundImage; + } + if (video != false) { + game.addVideo("setAvatar", this, [name, name2]); + } + } + game.broadcast(function (player, name, name2) { + player.setAvatar(name, name2, false); + }, this, name, name2); + } + setAvatarQueue(name, list) { + var node; + var player = this; + if (player.name2 == name) { + node = player.node.avatar2; + } + else { + node = player.node.avatar; + } + if (node._avatarqueue) { + for (var i = 0; i < list.length; i++) { + node._avatarqueue.push(list[i]); + } + } + else { + var func = function () { + if (node._avatarqueue.length) { + player.setAvatar(name, node._avatarqueue.shift(), false, false); + } + else { + clearInterval(node._avatarqueueinterval); + delete node._avatarqueue; + delete node._avatarqueueinterval; + player.setAvatar(name, name, false, false); + } + }; + node._avatarqueue = list.slice(0); + node._avatarqueueinterval = setInterval(func, 1000); + func(); + } + game.addVideo("setAvatarQueue", this, [name, list]); + } + flashAvatar(skill, name) { + if (lib.skill[name] && !lib.character[name]) { + var stop = false; + var list = lib.config.all.characters.slice(0); + for (var i in lib.characterPack) { + list.add(i); + } + for (var i = 0; i < list.length; i++) { + for (var j in lib.characterPack[list[i]]) { + if (lib.characterPack[list[i]][j][3].contains(name)) { + name = j; + stop = true; + break; + } + } + if (stop) { + break; + } + } + } + if (lib.character[this.name2] && lib.character[this.name2][3].contains(skill)) { + this.setAvatarQueue(this.name2, [name]); + } + else { + this.setAvatarQueue(this.name, [name]); + } + } + update() { + if (_status.video && arguments.length == 0) return; + if (this.hp >= this.maxHp) this.hp = this.maxHp; + game.broadcast(function (player, hp, maxHp, hujia) { + player.hp = hp; + player.maxHp = maxHp; + player.hujia = hujia; + player.$update(); + }, this, this.hp, this.maxHp, this.hujia); + this.$update(...arguments); + } + $update() { + if (this.hp >= this.maxHp) this.hp = this.maxHp; + var hp = this.node.hp; + hp.style.transition = "none"; + if (!_status.video) { + if (this.hujia) { + this.markSkill("ghujia"); + } + else { + this.unmarkSkill("ghujia"); + } + } + if (!this.storage.nohp) { + if (this.maxHp == Infinity) { + hp.innerHTML = "∞"; + } + else if (game.layout == "default" && this.maxHp > 14) { + hp.innerHTML = this.hp + "/" + this.maxHp; + hp.classList.add("text"); + } + else if (get.is.newLayout() && + ( + this.maxHp > 9 || + (this.maxHp > 5 && this.classList.contains("minskin")) || + ((game.layout == "mobile" || game.layout == "long") && this.dataset.position == 0 && this.maxHp > 7) + )) { + hp.innerHTML = this.hp + "
/
" + this.maxHp + "
"; + if (this.hp == 0) { + hp.lastChild.classList.add("lost"); + } + hp.classList.add("textstyle"); + // hp.classList.remove("long"); + } + else { + hp.innerHTML = ""; + hp.classList.remove("text"); + hp.classList.remove("textstyle"); + while (this.maxHp > hp.childNodes.length) { + ui.create.div(hp); + } + while (Math.max(0, this.maxHp) < hp.childNodes.length) { + hp.removeChild(hp.lastChild); + } + for (var i = 0; i < this.maxHp; i++) { + var index = i; + if (get.is.newLayout()) { + index = this.maxHp - i - 1; + } + if (i < this.hp) { + hp.childNodes[index].classList.remove("lost"); + } + else { + hp.childNodes[index].classList.add("lost"); + } + } + // if(this.maxHp==9){ + // hp.classList.add("long"); + // } + // else{ + // hp.classList.remove("long"); + // } + } + if (hp.classList.contains("room")) { + hp.dataset.condition = "high"; + } + else if (this.hp == 0) { + hp.dataset.condition = ""; + } + else if (this.hp > Math.round(this.maxHp / 2) || this.hp === this.maxHp) { + hp.dataset.condition = "high"; + } + else if (this.hp > Math.floor(this.maxHp / 3)) { + hp.dataset.condition = "mid"; + } + else { + hp.dataset.condition = "low"; + } + + setTimeout(function () { + hp.style.transition = ""; + }); + } + var numh = this.countCards("h"); + if (_status.video) { + numh = arguments[0]; + } + if (numh >= 10) { + numh = numh.toString(); + this.node.count.dataset.condition = "low"; + this.node.count.innerHTML = numh[0] + "
" + numh[1]; + } + else { + if (numh > 5) { + this.node.count.dataset.condition = "higher"; + } + else if (numh > 2) { + this.node.count.dataset.condition = "high"; + } + else if (numh > 0) { + this.node.count.dataset.condition = "mid"; + } + else { + this.node.count.dataset.condition = "none"; + } + this.node.count.innerHTML = numh; + } + if (this.updates) { + for (var i = 0; i < this.updates.length; i++) { + this.updates[i](this); + } + } + if (!_status.video) { + game.addVideo("update", this, [this.countCards("h"), this.hp, this.maxHp, this.hujia]); + } + this.updateMarks(); + return this; + } + clearMark(i, log) { + let num = this.countMark(i); + if (num > 0) this.removeMark(i, num, log) + } + removeMark(i, num, log) { + if (typeof num != "number" || !num) num = 1; + if (typeof this.storage[i] != "number" || !this.storage[i]) return; + if (num > this.storage[i]) num = this.storage[i]; + this.storage[i] -= num; + if (log !== false) { + var str = false; + var info = get.info(i); + if (info && info.intro && (info.intro.name || info.intro.name2)) str = info.intro.name2 || info.intro.name; + else str = lib.translate[i]; + if (str) game.log(this, "移去了", get.cnNumber(num), "个", "#g【" + str + "】"); + } + this.syncStorage(i); + this[(this.storage[i] || (lib.skill[i] && lib.skill[i].mark)) ? "markSkill" : "unmarkSkill"](i); + } + addMark(i, num, log) { + if (typeof num != "number" || !num) num = 1; + if (typeof this.storage[i] != "number") this.storage[i] = 0; + this.storage[i] += num; + if (log !== false) { + var str = false; + var info = get.info(i); + if (info && info.intro && (info.intro.name || info.intro.name2)) str = info.intro.name2 || info.intro.name; + else str = lib.translate[i]; + if (str) game.log(this, "获得了", get.cnNumber(num), "个", "#g【" + str + "】"); + } + this.syncStorage(i); + this.markSkill(i); + } + setMark(name, num, log) { + const count = this.countMark(name); + if (count > num) this.removeMark(name, count - num, log); + else if (count < num) this.addMark(name, num - count, log); + } + countMark(i) { + if (this.storage[i] == undefined) return 0; + if (typeof this.storage[i] == "number") return this.storage[i]; + if (Array.isArray(this.storage[i])) return this.storage[i].length; + return 0; + } + hasMark(i) { + return this.countMark(i) > 0; + } + updateMark(i, storage) { + if (!this.marks[i]) { + if (lib.skill[i] && lib.skill[i].intro && (this.storage[i] || lib.skill[i].intro.markcount)) { + this.markSkill(i); + if (!this.marks[i]) return this; + } + else { + return this; + } + } + if (storage && this.storage[i]) { + this.syncStorage(i); + } + if (i == "ghujia" || ((!this.marks[i].querySelector(".image") || this.storage[i + "_markcount"]) && + lib.skill[i] && lib.skill[i].intro && !lib.skill[i].intro.nocount && + (this.storage[i] || this.storage[i + "_markcount"] || lib.skill[i].intro.markcount))) { + this.marks[i].classList.add("overflowmark") + var num = 0; + if (typeof lib.skill[i].intro.markcount == "function") { + num = lib.skill[i].intro.markcount(this.storage[i], this); + } + else if (lib.skill[i].intro.markcount == "expansion") { + num = this.countCards("x", (card) => card.hasGaintag(i)); + } + else if (typeof this.storage[i + "_markcount"] == "number") { + num = this.storage[i + "_markcount"]; + } + else if (i == "ghujia") { + num = this.hujia; + } + else if (typeof this.storage[i] == "number") { + num = this.storage[i]; + } + else if (Array.isArray(this.storage[i])) { + num = this.storage[i].length; + } + if (num) { + if (!this.marks[i].markcount) { + this.marks[i].markcount = ui.create.div(".markcount.menubutton", this.marks[i]); + } + this.marks[i].markcount.innerHTML = num; + } + else if (this.marks[i].markcount) { + this.marks[i].markcount.delete(); + delete this.marks[i].markcount; + } + } + else { + if (this.marks[i].markcount) { + this.marks[i].markcount.delete(); + delete this.marks[i].markcount; + } + if (lib.skill[i].mark == "auto") { + this.unmarkSkill(i); + } + } + return this; + } + updateMarks(connect) { + if (typeof connect == "string" && _status.connectMode && !game.online) { + game.broadcast(function (player, storage, skill) { + player.storage[skill] = storage; + player.updateMarks(); + }, this, this.storage[connect], connect); + } + for (var i in this.marks) { + this.updateMark(i); + } + } + num(arg1, arg2, arg3) { + if (get.itemtype(arg1) == "position") { + return this.get(arg1, arg2, arg3).length; + } + else if (arg1 == "s") { + if (typeof arg2 == "boolean") { + return game.expandSkills(this.getSkills(arg2).concat(lib.skill.global)).contains(arg3); + } + else { + return game.expandSkills(this.getSkills().concat(lib.skill.global)).contains(arg2); + } + } + } + line(target, config) { + if (get.itemtype(target) == "players") { + for (var i = 0; i < target.length; i++) { + this.line(target[i], config); + } + } + else if (get.itemtype(target) == "player") { + if (target == this) return; + game.broadcast(function (player, target, config) { + player.line(target, config); + }, this, target, config); + game.addVideo("line", this, [target.dataset.position, config]); + game.linexy([ + this.getLeft() + this.offsetWidth / 2, + this.getTop() + this.offsetHeight / 2, + target.getLeft() + target.offsetWidth / 2, + target.getTop() + target.offsetHeight / 2 + ], config, true); + } + } + line2(targets, config) { + this.line(targets[0], config); + targets = targets.slice(0); + for (var i = 1; i < targets.length; i++) { + (function (j) { + setTimeout(function () { + targets[j - 1].line(targets[j], config); + }, lib.config.duration * i); + }(i)); + } + } + getNext() { + if (this.hasSkill("undist")) return null; + var target = this; + for (var i = 0; i < game.players.length - 1; i++) { + target = target.next; + if (!target.hasSkill("undist")) { + return target; + } + } + return null; + } + getPrevious() { + if (this.hasSkill("undist")) return null; + var target = this; + for (var i = 0; i < game.players.length - 1; i++) { + target = target.previous; + if (!target.hasSkill("undist")) { + return target; + } + } + return null; + } + countUsed(card, type) { + if (type === true) { + var num = 0; + var history = this.getHistory("useCard"); + for (var i = 0; i < history.length; i++) { + if (!card) num++; + else if (typeof card == "string" && history[i].card && card == history[i].card.name) num++; + else if (typeof card == "object" && history[i].card && card.name == history[i].card.name) num++; + } + return num; + } + var num; + var stat = this.getStat("card"); + if (!card) { + num = 0; + for (var i in stat) { + if (typeof stat[i] == "number") num += stat[i]; + } + return num; + } + if (typeof card == "object") { + card = card.name; + } + num = stat[card]; + if (typeof num != "number") return 0; + return num; + } + countSkill(skill) { + var num = this.getStat("skill")[skill]; + if (num == undefined) return 0; + return num; + } + getStockSkills(unowned, unique, hidden) { + var list = []; + if (lib.character[this.name] && (hidden || !this.isUnseen(0))) { + list.addArray(lib.character[this.name][3]); + } + if (lib.character[this.name1] && (hidden || !this.isUnseen(0))) { + list.addArray(lib.character[this.name1][3]); + } + if (lib.character[this.name2] && (hidden || !this.isUnseen(1))) { + list.addArray(lib.character[this.name2][3]); + } + if (!unowned) { + for (var i = 0; i < list.length; i++) { + if (!this.hasSkill(list[i])) { + list.splice(i--, 1); + } + } + } + if (!unique) { + for (var i = 0; i < list.length; i++) { + var info = lib.skill[list[i]]; + if (!info || info.unique || info.temp || info.sub || info.charlotte) { + list.splice(i--, 1); + } + } + } + return list; + } + /** + * @param {string} [arg1="h"] + * @param {string | Record | (card: Card) => boolean} [arg2] + * @returns {Card[]} + */ + getCards(arg1, arg2) { + if (typeof arg1 != "string") { + arg1 = "h"; + } + var cards = [], cards1 = []; + var i, j; + for (i = 0; i < arg1.length; i++) { + if (arg1[i] == "h") { + for (j = 0; j < this.node.handcards1.childElementCount; j++) { + if (!this.node.handcards1.childNodes[j].classList.contains("removing") && !this.node.handcards1.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards1.childNodes[j]); + } + } + for (j = 0; j < this.node.handcards2.childElementCount; j++) { + if (!this.node.handcards2.childNodes[j].classList.contains("removing") && !this.node.handcards2.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards2.childNodes[j]); + } + } + } + else if (arg1[i] == "s") { + for (j = 0; j < this.node.handcards1.childElementCount; j++) { + if (!this.node.handcards1.childNodes[j].classList.contains("removing") && this.node.handcards1.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards1.childNodes[j]); + } + } + for (j = 0; j < this.node.handcards2.childElementCount; j++) { + if (!this.node.handcards2.childNodes[j].classList.contains("removing") && this.node.handcards2.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards2.childNodes[j]); + } + } + } + else if (arg1[i] == "e") { + for (j = 0; j < this.node.equips.childElementCount; j++) { + if (!this.node.equips.childNodes[j].classList.contains("removing") && !this.node.equips.childNodes[j].classList.contains("feichu")) { + cards.push(this.node.equips.childNodes[j]); + } + } + } + else if (arg1[i] == "j") { + for (j = 0; j < this.node.judges.childElementCount; j++) { + if (!this.node.judges.childNodes[j].classList.contains("removing") && !this.node.judges.childNodes[j].classList.contains("feichu")) { + cards.push(this.node.judges.childNodes[j]); + if (this.node.judges.childNodes[j].viewAs && arguments.length > 1) { + this.node.judges.childNodes[j].tempJudge = this.node.judges.childNodes[j].name; + this.node.judges.childNodes[j].name = this.node.judges.childNodes[j].viewAs; + cards1.push(this.node.judges.childNodes[j]); + } + } + } + } + else if (arg1[i] == "x") { + for (j = 0; j < this.node.expansions.childElementCount; j++) { + if (!this.node.expansions.childNodes[j].classList.contains("removing")) { + cards.push(this.node.expansions.childNodes[j]); + } + } + } + } + if (arguments.length == 1) { + return cards; + } + if (arg2) { + if (typeof arg2 == "string") { + for (i = 0; i < cards.length; i++) { + if (get.name(cards[i]) != arg2) { + cards.splice(i, 1); i--; + } + } + } + else if (typeof arg2 == "object") { + for (i = 0; i < cards.length; i++) { + for (j in arg2) { + var value; + if (j == "type" || j == "subtype" || j == "color" || j == "suit" || j == "number") { + value = get[j](cards[i]); + } + else { + value = cards[i][j]; + } + if ((typeof arg2[j] == "string" && value != arg2[j]) || + (Array.isArray(arg2[j]) && !arg2[j].contains(value))) { + cards.splice(i--, 1); break; + } + } + } + } + else if (typeof arg2 == "function") { + for (i = 0; i < cards.length; i++) { + if (!arg2(cards[i])) { + cards.splice(i--, 1); + } + } + } + } + for (i = 0; i < cards1.length; i++) { + if (cards1[i].tempJudge) { + cards1[i].name = cards1[i].tempJudge; + delete cards1[i].tempJudge; + } + } + return cards; + } + getDiscardableCards(player, arg1, arg2) { + var cards = this.getCards(arg1, arg2); + for (var i = 0; i < cards.length; i++) { + if (!lib.filter.canBeDiscarded(cards[i], player, this)) { + cards.splice(i--, 1); + } + } + return cards; + } + getGainableCards(player, arg1, arg2) { + var cards = this.getCards(arg1, arg2); + for (var i = 0; i < cards.length; i++) { + if (!lib.filter.canBeGained(cards[i], player, this)) { + cards.splice(i--, 1); + } + } + return cards; + } + getGainableSkills(func) { + var list = []; + var names = [this.name, this.name1, this.name2]; + for (var i = 0; i < names.length; i++) { + list.addArray(get.gainableSkillsName(names[i], func)); + } + return list; + } + countCards(arg1, arg2) { + return this.getCards(arg1, arg2).length; + } + countDiscardableCards(player, arg1, arg2) { + return this.getDiscardableCards(player, arg1, arg2).length; + } + countGainableCards(player, arg1, arg2) { + return this.getGainableCards(player, arg1, arg2).length; + } + getOriginalSkills() { + var skills = []; + if (lib.character[this.name] && !this.isUnseen(0)) { + skills.addArray(lib.character[this.name][3]); + } + if (this.name2 && lib.character[this.name2] && !this.isUnseen(1)) { + skills.addArray(lib.character[this.name2][3]); + } + return skills; + } + getModableSkills(useCache) { + var func = function (player) { + var skills = player.getSkills().concat(lib.skill.global); + game.expandSkills(skills); + skills = skills.filter(function (skill) { + var info = get.info(skill); + return info && info.mod; + }); + skills.sort((a, b) => get.priority(a) - get.priority(b)); + return skills; + }; + if (!useCache) return func(this); + return game.callFuncUseStepCache("player.getModableSkills", func, [this]); + } + getSkills(arg2, arg3, arg4) { + var skills = this.skills.slice(0); + var es = []; + var i, j; + if (arg3 !== false) { + for (i = 0; i < this.node.equips.childElementCount; i++) { + if (!this.node.equips.childNodes[i].classList.contains("removing")) { + var equipskills = get.info(this.node.equips.childNodes[i], false).skills; + if (equipskills) { + es.addArray(equipskills); + } + } + } + if (arg2 == "e") { + return es; + } + } + for (var i in this.additionalSkills) { + if (Array.isArray(this.additionalSkills[i]) && (arg2 || i.indexOf("hidden:") !== 0)) { + for (j = 0; j < this.additionalSkills[i].length; j++) { + if (this.additionalSkills[i][j]) { + skills.add(this.additionalSkills[i][j]); + } + } + } + else if (this.additionalSkills[i] && typeof this.additionalSkills[i] == "string") { + skills.add(this.additionalSkills[i]); + } + } + for (var i in this.tempSkills) { + skills.add(i); + } + if (arg2) skills.addArray(this.hiddenSkills); + if (arg2 === false || arg2 == "invisible") skills.addArray(this.invisibleSkills); + if (arg3 !== false) skills.addArray(es); + for (var i in this.forbiddenSkills) { + skills.remove(i); + } + if (arg4 !== false) { + skills = game.filterSkills(skills, this, es); + } + return skills; + } + get(arg1, arg2, arg3, arg4) { + var i, j; + if (arg1 == "s") { + var skills = this.skills.slice(0); + var es = []; + if (arg3 !== false) { + for (i = 0; i < this.node.equips.childElementCount; i++) { + if (!this.node.equips.childNodes[i].classList.contains("removing") && !this.node.equips.childNodes[i].classList.contains("feichu")) { + var equipskills = get.info(this.node.equips.childNodes[i]).skills; + if (equipskills) { + es.addArray(equipskills); + } + } + } + if (arg2 == "e") { + return es; + } + } + for (var i in this.additionalSkills) { + if (Array.isArray(this.additionalSkills[i])) { + for (j = 0; j < this.additionalSkills[i].length; j++) { + if (this.additionalSkills[i][j]) { + skills.add(this.additionalSkills[i][j]); + } + } + } + else if (this.additionalSkills[i] && typeof this.additionalSkills[i] == "string") { + skills.add(this.additionalSkills[i]); + } + } + for (var i in this.tempSkills) { + skills.add(i); + } + if (arg2) skills.addArray(this.hiddenSkills); + if (arg3 !== false) skills.addArray(es); + for (var i in this.forbiddenSkills) { + skills.remove(i); + } + if (arg4 !== false) { + skills = game.filterSkills(skills, this, es); + } + return skills; + } + else if (get.is.pos(arg1)) { + var cards = [], cards1 = []; + for (i = 0; i < arg1.length; i++) { + if (arg1[i] == "h") { + for (j = 0; j < this.node.handcards1.childElementCount; j++) { + if (!this.node.handcards1.childNodes[j].classList.contains("removing") && !this.node.handcards1.childNodes[j].classList.contains("feichu") && !this.node.handcards1.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards1.childNodes[j]); + } + } + for (j = 0; j < this.node.handcards2.childElementCount; j++) { + if (!this.node.handcards2.childNodes[j].classList.contains("removing") && !this.node.handcards2.childNodes[j].classList.contains("feichu") && !this.node.handcards2.childNodes[j].classList.contains("glows")) { + cards.push(this.node.handcards2.childNodes[j]); + } + } + } + else if (arg1[i] == "e") { + for (j = 0; j < this.node.equips.childElementCount; j++) { + if (!this.node.equips.childNodes[j].classList.contains("removing") && !this.node.equips.childNodes[j].classList.contains("feichu")) { + cards.push(this.node.equips.childNodes[j]); + } + } + if (arguments.length == 2 && typeof arg2 == "string" && /1|2|3|4|5/.test(arg2)) { + for (j = 0; j < cards.length; j++) { + if (get.subtype(cards[j]) == "equip" + arg2) return cards[j]; + } + return; + } + } + else if (arg1[i] == "j") { + for (j = 0; j < this.node.judges.childElementCount; j++) { + if (!this.node.judges.childNodes[j].classList.contains("removing") && !this.node.judges.childNodes[j].classList.contains("feichu")) { + cards.push(this.node.judges.childNodes[j]); + if (this.node.judges.childNodes[j].viewAs && arguments.length > 1) { + this.node.judges.childNodes[j].tempJudge = this.node.judges.childNodes[j].name; + this.node.judges.childNodes[j].name = this.node.judges.childNodes[j].viewAs; + cards1.push(this.node.judges.childNodes[j]); + } + } + } + } + } + if (arguments.length == 1) { + return cards; + } + if (arg2 != undefined) { + if (typeof arg3 == "function") { + var cards2 = cards.slice(0); + cards.sort(function (a, b) { + return arg3(b, cards2) - arg3(a, cards2); + }); + } + if (typeof arg2 == "string") { + for (i = 0; i < cards.length; i++) { + if (cards[i].name != arg2) { + cards.splice(i, 1); i--; + } + } + } + else if (typeof arg2 == "object") { + for (i = 0; i < cards.length; i++) { + for (j in arg2) { + if (j == "type") { + if (typeof arg2[j] == "object") { + if (arg2[j].contains(get.type(cards[i])) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (get.type(cards[i]) != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + else if (j == "subtype") { + if (typeof arg2[j] == "object") { + if (arg2[j].contains(get.subtype(cards[i])) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (get.subtype(cards[i]) != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + else if (j == "color") { + if (typeof arg2[j] == "object") { + if (arg2[j].contains(get.color(cards[i])) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (get.color(cards[i]) != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + else if (j == "suit") { + if (typeof arg2[j] == "object") { + if (arg2[j].contains(get.suit(cards[i])) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (get.suit(cards[i]) != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + else if (j == "number") { + if (typeof arg2[j] == "object") { + if (arg2[j].contains(get.number(cards[i])) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (get.number(cards[i]) != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + else if (typeof arg2[j] == "object") { + if (arg2[j].contains(cards[i][j]) == false) { + cards.splice(i, 1); i--; break; + } + } + else if (typeof arg2[j] == "string") { + if (cards[i][j] != arg2[j]) { + cards.splice(i, 1); i--; break; + } + } + } + } + } + else if (typeof arg2 == "number" && arg2 > 0) { + cards.splice(arg2); + } + else if (typeof arg2 == "function") { + for (i = 0; i < cards.length; i++) { + if (!arg2(cards[i])) { + cards.splice(i, 1); i--; + } + } + } + } + for (i = 0; i < cards1.length; i++) { + if (cards1[i].tempJudge) { + cards1[i].name = cards1[i].tempJudge; + delete cards1[i].tempJudge; + } + } + if (arg2 === 0) return cards[0]; + if (typeof arg3 == "number") { + if (arg3 == 0) return cards[0]; + cards.splice(arg3); + } + if (typeof arg4 == "number") { + if (arg4 == 0) return cards[0]; + cards.splice(arg4); + } + return cards; + } + } + syncStorage(skill) { + switch (get.itemtype(this.storage[skill])) { + case "cards": game.addVideo("storage", this, [skill, get.cardsInfo(this.storage[skill]), "cards"]); break; + case "card": game.addVideo("storage", this, [skill, get.cardInfo(this.storage[skill]), "card"]); break; + default: + try { + game.addVideo("storage", this, [skill, JSON.parse(JSON.stringify(this.storage[skill]))]); + } + catch (e) { + console.log(this.storage[skill]); + } + } + } + syncSkills() { + game.broadcast(function (player, skills) { + player.applySkills(skills); + }, this, get.skillState(this)); + } + playerfocus(time) { + time = time || 1000; + this.classList.add("playerfocus"); + ui.arena.classList.add("playerfocus"); + var that = this; + setTimeout(function () { + that.classList.remove("playerfocus"); + ui.arena.classList.remove("playerfocus"); + }, time); + game.addVideo("playerfocus", this, time); + game.broadcast(function (player, time) { + player.playerfocus(time); + }, this, time); + return this; + } + setIdentity(identity, nature) { + if (!identity) identity = this.identity; + if (get.is.jun(this)) { + this.node.identity.firstChild.innerHTML = "君"; + } + else { + this.node.identity.firstChild.innerHTML = get.translation(identity); + } + this.node.identity.dataset.color = nature || identity; + return this; + } + insertPhase(skill, insert) { + var evt = _status.event.getParent("phase"); + var next; + if (evt && evt.parent && evt.parent.next) { + evt = evt.parent; + next = game.createEvent("phase", false, evt); + } + else if (_status.event.parent && _status.event.parent.next) { + evt = _status.event.parent; + next = game.createEvent("phase", false, evt); + } + else { + evt = null; + next = game.createEvent("phase", false); + } + if (evt && insert && evt.next.contains(next)) { + evt.next.remove(next); + evt.next.unshift(next); + } + next.player = this; + next.forceDie = true; + next.includeOut = true; + next.skill = skill || _status.event.name; + next.setContent("phase"); + return next; + } + insertEvent(name, content, arg) { + var evt = _status.event.getParent("phase"); + var next; + if (evt && evt.parent && evt.parent.next) { + next = game.createEvent(name, null, evt.parent); + } + else { + next = game.createEvent(name); + } + for (var i in arg) { + next[i] = arg[i]; + } + next.player = this; + next.setContent(content); + return next; + } + phase(skill) { + var next = game.createEvent("phase", false); + next.player = this; + next.setContent("phase"); + if (!_status.roundStart) { + _status.roundStart = this; + } + if (skill) { + next.skill = skill; + } + next.forceDie = true; + next.includeOut = true; + return next; + } + phaseZhunbei() { + var next = game.createEvent("phaseZhunbei"); + next.player = this; + next.setContent("phaseZhunbei"); + return next; + } + phaseJudge() { + var next = game.createEvent("phaseJudge"); + next.player = this; + next.setContent("phaseJudge"); + return next; + } + phaseDraw() { + var next = game.createEvent("phaseDraw"); + next.player = this; + next.num = 2; + if ((get.config("first_less") || _status.connectMode || _status.first_less_forced) && game.phaseNumber == 1 && _status.first_less) { + next.num--; + } + next.setContent("phaseDraw"); + return next; + } + phaseUse() { + var next = game.createEvent("phaseUse"); + next.player = this; + next.setContent("phaseUse"); + return next; + } + phaseDiscard() { + var next = game.createEvent("phaseDiscard"); + next.player = this; + next.setContent("phaseDiscard"); + return next; + } + phaseJieshu() { + var next = game.createEvent("phaseJieshu"); + next.player = this; + next.setContent("phaseJieshu"); + return next; + } + chooseToUse(use) { + var next = game.createEvent("chooseToUse"); + next.player = this; + if (arguments.length == 1 && get.objtype(arguments[0]) == "object") { + for (var i in use) { + next[i] = use[i]; + } + } + else { + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number" || get.itemtype(arguments[i]) == "select") { + next.selectTarget = arguments[i]; + } + else if ((typeof arguments[i] == "object" && arguments[i]) || typeof arguments[i] == "function") { + if (get.itemtype(arguments[i]) == "player" || next.filterCard) { + next.filterTarget = arguments[i]; + } + else next.filterCard = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + } + if (typeof next.filterCard == "object") { + next.filterCard = get.filter(next.filterCard); + } + if (typeof next.filterTarget == "object") { + next.filterTarget = get.filter(next.filterTarget, 2); + } + if (next.filterCard == undefined) { + next.filterCard = lib.filter.filterCard; + } + if (next.selectCard == undefined) { + next.selectCard = [1, 1]; + } + if (next.filterTarget == undefined) { + next.filterTarget = lib.filter.filterTarget; + } + if (next.selectTarget == undefined) { + next.selectTarget = lib.filter.selectTarget; + } + if (next.position == undefined) { + next.position = "hs"; + } + if (next.ai1 == undefined) next.ai1 = get.order; + if (next.ai2 == undefined) next.ai2 = get.effect_use; + next.setContent("chooseToUse"); + next._args = Array.from(arguments); + return next; + } + chooseToRespond() { + var next = game.createEvent("chooseToRespond"); + next.player = this; + var filter; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + next.selectCard = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectCard = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (typeof arguments[i] == "function") { + if (next.filterCard) next.ai = arguments[i]; + else next.filterCard = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterCard = get.filter(arguments[i]); + filter = arguments[i]; + } + else if (arguments[i] == "nosource") { + next.nosource = true; + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + if (next.filterCard == undefined) next.filterCard = lib.filter.all; + if (next.selectCard == undefined) next.selectCard = [1, 1]; + if (next.source == undefined && !next.nosource) next.source = _status.event.player; + if (next.ai == undefined) next.ai = get.unuseful2; + if (next.prompt != false) { + if (typeof next.prompt == "string") { + //next.dialog=next.prompt; + } + else { + var str = "请打出" + get.cnNumber(next.selectCard[0]) + "张" + if (filter) { + if (filter.name) { + str += get.translation(filter.name); + } + else { + str += "牌"; + } + } + else { + str += "牌"; + } + if (_status.event.getParent().name == "useCard") { + var cardname = _status.event.name; + if (lib.card[cardname] && lib.translate[cardname]) { + str += "响应" + lib.translate[cardname]; + } + } + next.prompt = str; + } + } + next.position = "hs"; + if (next.ai2 == undefined) next.ai2 = (() => 1); + next.setContent("chooseToRespond"); + next._args = Array.from(arguments); + return next; + } + chooseToDiscard() { + var next = game.createEvent("chooseToDiscard"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + next.selectCard = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectCard = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "dialog") { + next.dialog = arguments[i]; + next.prompt = false; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (typeof arguments[i] == "function") { + if (next.filterCard) next.ai = arguments[i]; + else next.filterCard = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterCard = get.filter(arguments[i]); + } + else if (typeof arguments[i] == "string") { + get.evtprompt(next, arguments[i]); + } + if (arguments[i] === null) { + for (var i = 0; i < arguments.length; i++) { + console.log(arguments[i]); + } + } + } + if (next.isMine() == false && next.dialog) next.dialog.style.display = "none"; + if (next.filterCard == undefined) next.filterCard = lib.filter.all; + if (next.selectCard == undefined) next.selectCard = [1, 1]; + if (next.ai == undefined) next.ai = get.unuseful; + next.autochoose = function () { + if (!this.forced) return false; + if (typeof this.selectCard == "function") return false; + var cards = this.player.getCards(this.position); + var num = cards.length; + for (var i = 0; i < cards.length; i++) { + if (!lib.filter.cardDiscardable(cards[i], this.player, this)) num--; + } + return get.select(this.selectCard)[0] >= num; + } + next.setContent("chooseToDiscard"); + next._args = Array.from(arguments); + return next; + } + chooseToCompare(target, check) { + var next = game.createEvent("chooseToCompare"); + next.player = this; + if (Array.isArray(target)) { + next.targets = target; + if (check) next.ai = check; + else next.ai = function (card) { + if (typeof card == "string" && lib.skill[card]) { + var ais = lib.skill[card].check || function () { return 0 }; + return ais(); + } + var addi = (get.value(card) >= 8 && get.type(card) != "equip") ? -3 : 0; + if (card.name == "du") addi -= 3; + var source = _status.event.source; + var player = _status.event.player; + var event = _status.event.getParent(); + var getn = function (card) { + if (player.hasSkill("tianbian") && get.suit(card) == "heart") return 13 * (event.small ? -1 : 1); + return get.number(card) * (event.small ? -1 : 1); + } + if (source && source != player) { + if (get.attitude(player, source) > 1) { + if (event.small) return getn(card) - get.value(card) / 2 + addi; + return -getn(card) - get.value(card) / 2 + addi; + } + if (event.small) return -getn(card) - get.value(card) / 2 + addi; + return getn(card) - get.value(card) / 2 + addi; + } + else { + if (event.small) return -getn(card) - get.value(card) / 2 + addi; + return getn(card) - get.value(card) / 2 + addi; + } + } + next.setContent("chooseToCompareMultiple"); + } + else { + next.target = target; + if (check) next.ai = check; + else next.ai = function (card) { + if (typeof card == "string" && lib.skill[card]) { + var ais = lib.skill[card].check || function () { return 0 }; + return ais(); + } + var player = get.owner(card); + var getn = function (card) { + if (player.hasSkill("tianbian") && get.suit(card) == "heart") return 13; + return get.number(card); + } + var event = _status.event.getParent(); + var to = (player == event.player ? event.target : event.player); + var addi = (get.value(card) >= 8 && get.type(card) != "equip") ? -6 : 0; + if (card.name == "du") addi -= 5; + if (player == event.player) { + if (event.small) { + return -getn(card) - get.value(card) / 2 + addi; + } + return getn(card) - get.value(card) / 2 + addi; + } + else { + if ((get.attitude(player, to) <= 0) == Boolean(event.small)) { + return -getn(card) - get.value(card) / 2 + addi; + } + return getn(card) - get.value(card) / 2 + addi; + } + } + next.setContent("chooseToCompare"); + } + next.forceDie = true; + next._args = Array.from(arguments); + return next; + } + chooseSkill(target) { + var next = game.createEvent("chooseSkill"); + next.player = this; + next.setContent("chooseSkill"); + next.target = target; + for (var i = 1; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + else if (typeof arguments[i] == "function") { + next.func = arguments[i]; + } + } + } + discoverCard(list) { + var next = game.createEvent("discoverCard"); + next.player = this; + next.setContent("discoverCard"); + next.list = list || lib.inpile.slice(0); + next.forced = true; + for (var i = 1; i < arguments.length; i++) { + if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (typeof arguments[i] == "string") { + switch (arguments[i]) { + case "use": next.use = true; break; + case "nogain": next.nogain = true; break; + default: next.prompt = arguments[i]; + } + } + else if (typeof arguments[i] == "number") { + next.num = arguments[i]; + } + else if (typeof arguments[i] === "function") { + next.ai = arguments[i]; + } + } + return next; + } + chooseCardButton() { + var cards, prompt, forced, select; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") cards = arguments[i]; + else if (typeof arguments[i] == "boolean") forced = arguments[i]; + else if (typeof arguments[i] == "string") prompt = arguments[i]; + else if (get.itemtype(arguments[i]) == "select" || typeof arguments[i] == "number") select = arguments[i]; + } + if (prompt == undefined) prompt = "请选择卡牌"; + return this.chooseButton(forced, select, "hidden", [prompt, cards, "hidden"]); + } + chooseVCardButton() { + var list, prompt, forced, select, notype = false; + for (var i = 0; i < arguments.length; i++) { + if (Array.isArray(arguments[i])) { + list = arguments[i]; + } + else if (arguments[i] == "notype") { + notype = true; + } + else if (typeof arguments[i] == "boolean") forced = arguments[i]; + else if (typeof arguments[i] == "string") prompt = arguments[i]; + else if (get.itemtype(arguments[i]) == "select" || typeof arguments[i] == "number") select = arguments[i]; + } + for (var i = 0; i < list.length; i++) { + list[i] = [notype ? "" : (get.subtype(list[i], false) || get.type(list[i])), "", list[i]]; + } + if (prompt == undefined) prompt = "请选择卡牌"; + return this.chooseButton(forced, select, "hidden", [prompt, [list, "vcard"], "hidden"]); + } + chooseButton() { + var next = game.createEvent("chooseButton"); + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "dialog") { + next.dialog = arguments[i]; + next.closeDialog = true; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectButton = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.selectButton = [arguments[i], arguments[i]]; + } + else if (typeof arguments[i] == "function") { + if (next.ai) next.filterButton = arguments[i]; + else next.ai = arguments[i]; + } + else if (Array.isArray(arguments[i])) { + next.createDialog = arguments[i]; + } + } + next.player = this; + if (typeof next.forced != "boolean") next.forced = false; + if (next.isMine() == false && next.dialog) next.dialog.style.display = "none"; + if (next.filterButton == undefined) next.filterButton = lib.filter.filterButton; + if (next.selectButton == undefined) next.selectButton = [1, 1]; + if (next.ai == undefined) next.ai = function () { return 1 }; + next.setContent("chooseButton"); + next._args = Array.from(arguments); + next.forceDie = true; + return next; + } + chooseButtonOL(list, callback, ai) { + var next = game.createEvent("chooseButtonOL"); + next.list = list; + next.setContent("chooseButtonOL"); + next.ai = ai; + next.callback = callback; + next._args = Array.from(arguments); + return next; + } + chooseCardOL() { + var next = game.createEvent("chooseCardOL"); + next._args = []; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "players") { + next.list = arguments[i].slice(0); + } + else { + next._args.push(arguments[i]); + } + } + next.setContent("chooseCardOL"); + next._args.add("glow_result"); + return next; + } + chooseCard(choose) { + var next = game.createEvent("chooseCard"); + next.player = this; + if (arguments.length == 1 && get.is.object(choose)) { + for (var i in choose) { + next[i] = choose[i]; + } + } + else { + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + next.selectCard = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectCard = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (typeof arguments[i] == "function") { + if (next.filterCard) next.ai = arguments[i]; + else next.filterCard = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterCard = get.filter(arguments[i]); + } + else if (arguments[i] == "glow_result") { + next.glow_result = true; + } + else if (typeof arguments[i] == "string") { + get.evtprompt(next, arguments[i]); + } + } + } + if (next.filterCard == undefined) next.filterCard = lib.filter.all; + if (next.selectCard == undefined) next.selectCard = [1, 1]; + if (next.ai == undefined) next.ai = get.unuseful3; + next.setContent("chooseCard"); + next._args = Array.from(arguments); + return next; + } + chooseUseTarget() { + var next = game.createEvent("chooseUseTarget"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "players") { + next.targets = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + next.targets = [arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectTarget = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.selectTarget = [arguments[i], arguments[i]]; + } + else if (get.is.object(arguments[i]) && arguments[i].name) { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "string") { + if (arguments[i] == "nopopup") { + next.nopopup = true; + } + else if (arguments[i] == "noanimate") { + next.animate = false; + } + else if (arguments[i] == "nothrow") { + next.throw = false; + } + else if (arguments[i] == "nodistance") { + next.nodistance = true; + } + else if (arguments[i] == "noTargetDelay") { + next.noTargetDelay = true; + } + else if (arguments[i] == "nodelayx") { + next.nodelayx = true; + } + else if (lib.card[arguments[i]] && !next.card) { + next.card = { name: arguments[i], isCard: true }; + } + else get.evtprompt(next, arguments[i]); + } + else if (arguments[i] === true) { + next.forced = true; + } + else if (arguments[i] === false) { + next.addCount = false; + } + } + if (!next.targets) next.targets = game.players.slice(0); + if (next.cards == undefined) { + if (get.itemtype(next.card) == "card") { + next.cards = [next.card]; + } + else next.cards = []; + } + else if (next.card == undefined) { + if (next.cards) { + next.card = next.cards[0]; + } + } + next.setContent("chooseUseTarget"); + next._args = Array.from(arguments); + return next; + // Fully Online-Ready! Enjoy It! + } + chooseTarget() { + var next = game.createEvent("chooseTarget"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + next.selectTarget = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectTarget = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "dialog") { + next.dialog = arguments[i]; + next.prompt = false; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (typeof arguments[i] == "function") { + if (next.filterTarget) next.ai = arguments[i]; + else next.filterTarget = arguments[i]; + } + else if (typeof arguments[i] == "string") { + get.evtprompt(next, arguments[i]); + } + } + if (next.filterTarget == undefined) next.filterTarget = lib.filter.all; + if (next.selectTarget == undefined) next.selectTarget = [1, 1]; + if (next.ai == undefined) next.ai = get.attitude2; + next.setContent("chooseTarget"); + next._args = Array.from(arguments); + next.forceDie = true; + return next; + } + chooseCardTarget(choose) { + var next = game.createEvent("chooseCardTarget"); + next.player = this; + if (arguments.length == 1) { + for (var i in choose) { + next[i] = choose[i]; + } + } + if (typeof next.filterCard == "object") { + next.filterCard = get.filter(next.filterCard); + } + if (typeof next.filterTarget == "object") { + next.filterTarget = get.filter(next.filterTarget, 2); + } + if (next.filterCard == undefined || next.filterCard === true) { + next.filterCard = lib.filter.all; + } + if (next.selectCard == undefined) { + next.selectCard = 1; + } + if (next.filterTarget == undefined || next.filterTarget === true) { + next.filterTarget = lib.filter.all; + } + if (next.selectTarget == undefined) { + next.selectTarget = 1; + } + if (next.ai1 == undefined) next.ai1 = get.unuseful2; + if (next.ai2 == undefined) next.ai2 = get.attitude2; + next.setContent("chooseCardTarget"); + next._args = Array.from(arguments); + return next; + } + chooseControlList() { + var list = []; + var prompt = null; + var forced = "cancel2"; + var func = null; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + if (!prompt) { + prompt = arguments[i]; + } + else { + list.push(arguments[i]); + } + } + else if (Array.isArray(arguments[i])) { + list = arguments[i]; + } + else if (arguments[i] === true) { + forced = null; + } + else if (typeof arguments[i] == "function") { + func = arguments[i]; + } + } + return this.chooseControl(forced, func).set("choiceList", list).set("prompt", prompt); + } + chooseControl() { + var next = game.createEvent("chooseControl"); + next.controls = []; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + if (arguments[i] == "dialogcontrol") { + next.dialogcontrol = true; + } + else if (arguments[i] == "seperate") { + next.seperate = true; + } + else { + next.controls.push(arguments[i]); + } + } + else if (Array.isArray(arguments[i])) { + next.controls = next.controls.concat(arguments[i]); + } + else if (typeof arguments[i] == "function") { + next.ai = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.choice = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "dialog") { + next.dialog = arguments[i]; + } + } + next.player = this; + if (next.choice == undefined) next.choice = 0; + next.setContent("chooseControl"); + next._args = Array.from(arguments); + next.forceDie = true; + return next; + } + chooseBool() { + var next = game.createEvent("chooseBool"); + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "boolean") { + next.choice = arguments[i]; + } + else if (typeof arguments[i] == "function") { + next.ai = arguments[i]; + } + else if (typeof arguments[i] == "string") { + get.evtprompt(next, arguments[i]); + } + else if (get.itemtype(arguments[i]) == "dialog") { + next.dialog = arguments[i]; + } + if (next.choice == undefined) next.choice = true; + } + next.player = this; + next.setContent("chooseBool"); + next._args = Array.from(arguments); + next.forceDie = true; + return next; + } + chooseDrawRecover() { + var next = game.createEvent("chooseDrawRecover", false); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + if (typeof next.num1 == "number") { + next.num2 = arguments[i]; + } + else { + next.num1 = arguments[i]; + } + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + else if (typeof arguments[i] == "function") { + next.ai = arguments[i]; + } + } + if (typeof next.num1 != "number") { + next.num1 = 1; + } + if (typeof next.num2 != "number") { + next.num2 = 1; + } + next.setContent("chooseDrawRecover"); + return next; + } + choosePlayerCard() { + var next = game.createEvent("choosePlayerCard"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.target = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.selectButton = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectButton = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (arguments[i] == "visible") { + next.visible = true; + } + else if (typeof arguments[i] == "function") { + if (next.ai) next.filterButton = arguments[i]; + else next.ai = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterButton = get.filter(arguments[i]); + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + if (next.filterButton == undefined) next.filterButton = lib.filter.all; + if (next.position == undefined) next.position = "he"; + if (next.selectButton == undefined) next.selectButton = [1, 1]; + if (next.ai == undefined) next.ai = function (button) { + var val = get.buttonValue(button); + if (get.attitude(_status.event.player, get.owner(button.link)) > 0) return -val; + return val; + }; + next.setContent("choosePlayerCard"); + next._args = Array.from(arguments); + return next; + } + discardPlayerCard() { + var next = game.createEvent("discardPlayerCard"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.target = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.selectButton = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectButton = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (arguments[i] == "visible") { + next.visible = true; + } + else if (typeof arguments[i] == "function") { + if (next.ai) next.filterButton = arguments[i]; + else next.ai = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterButton = get.filter(arguments[i]); + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + if (next.filterButton == undefined) next.filterButton = lib.filter.all; + if (next.position == undefined) next.position = "he"; + if (next.selectButton == undefined) next.selectButton = [1, 1]; + if (next.ai == undefined) next.ai = function (button) { + var val = get.buttonValue(button); + if (get.attitude(_status.event.player, get.owner(button.link)) > 0) return -val; + return val; + }; + next.setContent("discardPlayerCard"); + next._args = Array.from(arguments); + return next; + } + gainPlayerCard() { + var next = game.createEvent("gainPlayerCard"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.target = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.selectButton = [arguments[i], arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "select") { + next.selectButton = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + next.position = arguments[i]; + } + else if (arguments[i] == "visible") { + next.visible = true; + } + else if (arguments[i] == "visibleMove") { + next.visibleMove = true; + } + else if (typeof arguments[i] == "function") { + if (next.ai) next.filterButton = arguments[i]; + else next.ai = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filterButton = get.filter(arguments[i]); + } + else if (typeof arguments[i] == "string") { + next.prompt = arguments[i]; + } + } + if (next.filterButton == undefined) next.filterButton = lib.filter.all; + if (next.position == undefined) next.position = "he"; + if (next.selectButton == undefined) next.selectButton = [1, 1]; + if (next.ai == undefined) next.ai = function (button) { + var val = get.buttonValue(button); + if (get.attitude(_status.event.player, get.owner(button.link)) > 0) return -val; + return val; + }; + next.setContent("gainPlayerCard"); + next._args = Array.from(arguments); + return next; + } + showHandcards(str) { + var next = game.createEvent("showHandcards"); + next.player = this; + if (typeof str == "string") { + next.prompt = str; + } + next.setContent("showHandcards"); + next._args = Array.from(arguments); + return next; + } + showCards(cards, str) { + var next = game.createEvent("showCards"); + next.player = this; + next.str = str; + if (typeof cards == "string") { + str = cards; + cards = next.str; + next.str = str; + } + if (get.itemtype(cards) == "card") next.cards = [cards]; + else if (get.itemtype(cards) == "cards") next.cards = cards.slice(0); + else _status.event.next.remove(next); + next.setContent("showCards"); + next._args = Array.from(arguments); + return next; + } + viewCards(str, cards) { + var next = game.createEvent("viewCards"); + next.player = this; + next.str = str; + next.cards = cards.slice(0); + next.setContent("viewCards"); + next._args = Array.from(arguments); + return next; + } + viewHandcards(target) { + var cards = target.getCards("h"); + if (cards.length) { + return this.viewCards(get.translation(target) + "的手牌", cards); + } + else { + return false; + } + } + canMoveCard(withatt, nojudge) { + const player = this; + const args = Array.from(arguments).slice(2); + let sourceTargets, aimTargets, filterCard, canReplace; + args.forEach(arg => { + if (get.itemtype(arg) == "players") { + if (!sourceTargets) sourceTargets = arg; + else if (!aimTargets) aimTargets = arg; + } + else if (get.itemtype(arg) == "player") { + if (!sourceTargets) sourceTargets = [arg]; + else if (!aimTargets) aimTargets = [arg]; + } + else if (typeof arg == "function") { + filterCard = arg; + } + else if (typeof arg == "object" && arg) { + filterCard = get.filter(arg); + } + else if (arg == "canReplace") { + canReplace = true; + } + }); + if (!sourceTargets) sourceTargets = game.filterPlayer(); + if (!aimTargets) aimTargets = game.filterPlayer(); + return sourceTargets.some(current => { + const att = get.sgn(get.attitude(player, current)); + if (!withatt || att != 0) { + var es = current.getCards("e", filterCard); + for (var i = 0; i < es.length; i++) { + if (aimTargets.some(current2 => { + if (withatt) { + if (get.sgn(get.value(es[i], current)) != -att) return false; + var att2 = get.sgn(get.attitude(player, current2)); + if (!canReplace || att < 0 && current2.countEquipableSlot(get.subtype(es[i]))) { + if (att == att2 || att2 != get.sgn(get.effect(current2, es[i], player, current2))) return false; + } + } + return current != current2 && !current2.isMin() && current2.canEquip(es[i], canReplace); + })) { + return true; + } + } + } + if (!nojudge && (!withatt || att > 0)) { + var js = current.getCards("j", filterCard); + for (var i = 0; i < js.length; i++) { + if (game.hasPlayer(function (current2) { + if (withatt) { + var att2 = get.attitude(player, current2); + if (att2 >= 0) return false; + } + return current != current2 && current2.canAddJudge(js[i]); + })) { + return true; + } + } + } + }); + } + moveCard() { + var next = game.createEvent("moveCard"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "boolean") { + next.forced = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "players") { + if (!next.sourceTargets) next.sourceTargets = arguments[i]; + else if (!next.aimTargets) next.aimTargets = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + if (!next.sourceTargets) next.sourceTargets = [arguments[i]]; + else if (!next.aimTargets) next.aimTargets = [arguments[i]]; + } + else if (typeof arguments[i] == "string") { + if (arguments[i] == "canReplace") { + next.canReplace = true; + } + else { + get.evtprompt(next, arguments[i]); + } + } + else if (Array.isArray(arguments[i])) { + for (var j = 0; j < arguments[i].length; j++) { + if (typeof arguments[i][j] != "string") break; + } + if (j == arguments[i].length) { + next.targetprompt = arguments[i]; + } + } + else if (typeof arguments[i] == "function") { + next.filter = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i]) { + next.filter = get.filter(arguments[i]); + } + } + if (!next.sourceTargets) next.sourceTargets = game.filterPlayer(); + if (!next.aimTargets) next.aimTargets = game.filterPlayer(); + if (next.filter == undefined) next.filter = lib.filter.all; + next.setContent("moveCard"); + next._args = Array.from(arguments); + return next; + } + useResult(result, event) { + event = event || _status.event; + if (result._sendskill) { + lib.skill[result._sendskill[0]] = result._sendskill[1]; + } + if (event.onresult) { + event.onresult(result); + } + if (result.skill) { + var info = get.info(result.skill); + if (info.onuse) { + info.onuse(result, this); + } + // if(info.direct&&!info.clearTime){ + // _status.noclearcountdown=true; + // } + } + if (event.logSkill) { + if (typeof event.logSkill == "string") { + this.logSkill(event.logSkill); + } + else if (Array.isArray(event.logSkill)) { + this.logSkill.apply(this, event.logSkill); + } + } + if (result.card || !result.skill) { + result.used = result.card || result.cards[0]; + var next = this.useCard(result.used, result.cards, result.targets, result.skill); + next.oncard = event.oncard; + next.respondTo = event.respondTo; + if (event.addCount === false) { + next.addCount = false; + } + if (result._apply_args) { + for (var i in result._apply_args) { + next[i] = result._apply_args[i]; + } + } + return next; + } + else if (result.skill) { + result.used = result.skill; + return this.useSkill(result.skill, result.cards, result.targets); + } + } + useCard() { + var next = game.createEvent("useCard"); + next.player = this; + next.num = 0; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "players") { + next.targets = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + next.targets = [arguments[i]]; + } + else if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i] && arguments[i].name) { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "string") { + if (arguments[i] == "noai") { + next.noai = true; + } + else if (arguments[i] == "nowuxie") { + next.nowuxie = true; + } + else { + next.skill = arguments[i]; + } + } + else if (typeof arguments[i] == "boolean") { + next.addCount = arguments[i]; + } + } + if (next.cards == undefined) { + if (get.itemtype(next.card) == "card") { + next.cards = [next.card]; + } + else next.cards = []; + } + else if (next.card == undefined) { + if (next.cards) { + next.card = next.cards[0]; + } + } + if (!next.targets) { + next.targets = []; + } + if (next.card) { + next.card = get.autoViewAs(next.card, next.cards); + var info = get.info(next.card); + if (info.changeTarget) { + info.changeTarget(next.player, next.targets); + } + if (info.singleCard) { + next._targets = next.targets.slice(0); + next.target = next.targets[0]; + next.addedTargets = next.targets.splice(1); + if (next.addedTargets.length) { + next.addedTarget = next.addedTargets[0]; + } + } + } + for (var i = 0; i < next.targets.length; i++) { + if (get.attitude(this, next.targets[i]) >= -1 && get.attitude(this, next.targets[i]) < 0) { + if (!this.ai.tempIgnore) this.ai.tempIgnore = []; + this.ai.tempIgnore.add(next.targets[i]); + } + } + if (typeof this.logAi == "function" && !next.noai && !get.info(next.card).noai) { + var postAi = get.info(next.card).postAi; + if (postAi && postAi(next.targets)) { + next.postAi = true; + } + else { + this.logAi(next.targets, next.card); + } + } + next.stocktargets = next.targets.slice(0); + next.setContent("useCard"); + return next; + } + useSkill() { + var next = game.createEvent("useSkill"); + next.player = this; + next.num = 0; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "players") { + next.targets = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.skill = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.addCount = arguments[i]; + } + } + if (next.cards == undefined) { + next.cards = []; + } + if (next.skill && get.info(next.skill) && get.info(next.skill).changeTarget) { + get.info(next.skill).changeTarget(next.player, next.targets); + } + if (next.targets) { + for (var i = 0; i < next.targets.length; i++) { + if (get.attitude(this, next.targets[i]) >= -1 && get.attitude(this, next.targets[i]) < 0) { + if (!this.ai.tempIgnore) this.ai.tempIgnore = []; + this.ai.tempIgnore.add(next.targets[i]); + } + } + if (typeof this.logAi == "function") { + this.logAi(next.targets, next.skill); + } + } + else { + next.targets = []; + } + next.setContent("useSkill"); + return next; + } + drawTo(num, args) { + var num2 = num - this.countCards("h"); + if (!num2) return; + var next = this.draw(num2); + if (Array.isArray(args)) { + for (var i = 0; i < args.length; i++) { + if (get.itemtype(args[i]) == "player") { + next.source = args[i]; + } + else if (typeof args[i] == "boolean") { + next.animate = args[i]; + } + else if (args[i] == "nodelay") { + next.animate = false; + next.$draw = true; + } + else if (args[i] == "visible") { + next.visible = true; + } + else if (args[i] == "bottom") { + next.bottom = true; + } + else if (typeof args[i] == "object" && args[i] && args[i].drawDeck != undefined) { + next.drawDeck = args[i].drawDeck; + } + } + } + return next; + } + draw() { + var next = game.createEvent("draw"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.num = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.animate = arguments[i]; + } + else if (arguments[i] == "nodelay") { + next.animate = false; + next.$draw = true; + } + else if (arguments[i] == "visible") { + next.visible = true; + } + else if (arguments[i] == "bottom") { + next.bottom = true; + } + else if (typeof arguments[i] == "object" && arguments[i] && arguments[i].drawDeck != undefined) { + next.drawDeck = arguments[i].drawDeck; + } + } + if (next.num == undefined) next.num = 1; + if (next.num <= 0) _status.event.next.remove(next); + next.setContent("draw"); + if (lib.config.mode == "stone" && _status.mode == "deck" && + next.drawDeck == undefined && !next.player.isMin() && next.num > 1) { + next.drawDeck = 1; + } + next.result = []; + return next; + } + randomDiscard() { + var position = "he", num = 1, delay = null; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + num = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + position = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + delay = arguments[i]; + } + } + var cards = this.getCards(position).randomGets(num); + if (cards.length) { + var next = this.discard(cards, "notBySelf"); + if (typeof delay == "boolean") { + next.delay = delay; + } + } + return cards; + } + randomGain() { + var position = "he", num = 1, target = null, line = false; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + num = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "position") { + position = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + target = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + line = arguments[i]; + } + } + if (target) { + var cards = target.getCards(position).randomGets(num); + if (cards.length) { + if (line) { + this.line(target, "green"); + } + this.gain(cards, target, "log", "bySelf"); + target.$giveAuto(cards, this); + } + return cards; + } + return []; + } + discard() { + var next = game.createEvent("discard"); + next.player = this; + next.num = 0; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.cards = [arguments[i]]; + } + else if (typeof arguments[i] == "boolean") { + next.animate = arguments[i]; + } + else if (get.objtype(arguments[i]) == "div") { + next.position = arguments[i]; + } + else if (arguments[i] == "notBySelf") { + next.notBySelf = true; + } + } + if (next.cards == undefined) _status.event.next.remove(next); + next.setContent("discard"); + return next; + } + loseToDiscardpile() { + var next = game.createEvent("loseToDiscardpile"); + next.player = this; + next.num = 0; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.cards = [arguments[i]]; + } + else if (typeof arguments[i] == "boolean") { + next.animate = arguments[i]; + } + else if (get.objtype(arguments[i]) == "div") { + next.position = arguments[i]; + } + else if (arguments[i] == "notBySelf") { + next.notBySelf = true; + } + else if (arguments[i] == "insert") { + next.insert_card = true; + } + else if (arguments[i] == "blank") { + next.blank = true; + } + } + if (next.cards == undefined) _status.event.next.remove(next); + next.setContent("loseToDiscardpile"); + return next; + } + respond() { + var next = game.createEvent("respond"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i] && arguments[i].name) { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "boolean") next.animate = arguments[i]; + else if (arguments[i] == "highlight") next.highlight = true; + else if (arguments[i] == "noOrdering") next.noOrdering = true; + else if (typeof arguments[i] == "string") next.skill = arguments[i]; + } + if (next.cards == undefined) { + if (get.itemtype(next.card) == "card") { + next.cards = [next.card]; + } + else { + next.cards = []; + } + } + else if (next.card == undefined) { + if (next.cards) { + next.card = next.cards[0]; + if (!next.skill) { + next.card = get.autoViewAs(next.card, next.cards); + } + } + } + next.setContent("respond"); + return next; + } + swapHandcards(target, cards1, cards2) { + var next = game.createEvent("swapHandcards", false); + next.player = this; + next.target = target; + if (cards1) next.cards1 = cards1; + if (cards2) next.cards2 = cards2; + next.setContent("swapHandcards"); + return next; + } + directequip(cards) { + for (var i = 0; i < cards.length; i++) { + this.$equip(cards[i]); + } + if (!_status.video) { + game.addVideo("directequip", this, get.cardsInfo(cards)); + } + } + $addToExpansion(cards, broadcast, gaintag) { + var hs = this.getCards("x"); + for (var i = 0; i < cards.length; i++) { + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + for (var i = 0; i < cards.length; i++) { + cards[i].fix(); + if (gaintag) cards[i].addGaintag(gaintag); + var sort = lib.config.sort_card(cards[i]); + this.node.expansions.insertBefore(cards[i], this.node.expansions.firstChild); + } + if (broadcast !== false) game.broadcast(function (player, cards, gaintag) { + player.$addToExpansion(cards, null, gaintag); + }, this, cards, gaintag); + return this; + } + directgain(cards, broadcast, gaintag) { + var hs = this.getCards("hs"); + for (var i = 0; i < cards.length; i++) { + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + for (var i = 0; i < cards.length; i++) { + cards[i].fix(); + if (gaintag) cards[i].addGaintag(gaintag); + var sort = lib.config.sort_card(cards[i]); + if (this == game.me) { + cards[i].classList.add("drawinghidden"); + } + if (get.is.singleHandcard() || sort > 0) { + this.node.handcards1.insertBefore(cards[i], this.node.handcards1.firstChild); + } + else { + this.node.handcards2.insertBefore(cards[i], this.node.handcards2.firstChild); + } + } + if (this == game.me || _status.video) ui.updatehl(); + if (!_status.video) { + game.addVideo("directgain", this, get.cardsInfo(cards)); + this.update(); + } + if (broadcast !== false) game.broadcast(function (player, cards) { + player.directgain(cards); + }, this, cards); + return this; + } + directgains(cards, broadcast, gaintag) { + var hs = this.getCards("hs"); + for (var i = 0; i < cards.length; i++) { + if (hs.contains(cards[i])) { + cards.splice(i--, 1); + } + } + var addLast = function (card, node) { + if (gaintag) { + for (var i = 0; i < node.childNodes.length; i++) { + var add = node.childNodes[node.childNodes.length - i - 1]; + if (!add.classList.contains("glows")) break; + if (add.hasGaintag(gaintag)) { + node.insertBefore(card, add.nextSibling); + return; + } + } + } + node.appendChild(card); + } + for (var i = 0; i < cards.length; i++) { + cards[i].fix(); + cards[i].remove(); + if (gaintag) cards[i].addGaintag(gaintag); + cards[i].classList.add("glows"); + if (this == game.me) { + cards[i].classList.add("drawinghidden"); + } + if (get.is.singleHandcard()) { + addLast(cards[i], this.node.handcards1); + } + else { + addLast(cards[i], this.node.handcards2); + } + } + if (this == game.me || _status.video) ui.updatehl(); + if (!_status.video) { + game.addVideo("directgains", this, get.cardsInfo(cards)); + this.update(); + } + if (broadcast !== false) game.broadcast(function (player, cards, gaintag) { + player.directgains(cards, null, gaintag); + }, this, cards, gaintag); + return this; + } + gainMultiple(targets, position) { + var next = game.createEvent("gainMultiple", false); + next.setContent("gainMultiple"); + next.player = this; + next.targets = targets; + next.position = position || "h"; + return next; + } + gain() { + var next = game.createEvent("gain"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.cards = [arguments[i]]; + } + else if (arguments[i] === "log") { + next.log = true; + } + else if (arguments[i] == "fromStorage") { + next.fromStorage = true; + } + else if (arguments[i] == "fromRenku") { + next.fromStorage = true; + next.fromRenku = true; + } + else if (arguments[i] == "bySelf") { + next.bySelf = true; + } + else if (typeof arguments[i] == "string") { + next.animate = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.delay = arguments[i]; + } + } + if (next.animate == "gain2" || next.animate == "draw2") { + if (!Object.prototype.hasOwnProperty.call(next, "log")) { + next.log = true; + } + } + next.setContent("gain"); + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + var cards = [], event = this; + game.checkGlobalHistory("cardMove", function (evt) { + if (evt.name != "lose" || evt.position != position || evt.getParent() != event) return; + if (player && player != evt.player) return; + cards.addArray(evt[key]); + }); + return cards; + }; + next.getl = function (player) { + const that = this; + const map = { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + player.checkHistory("lose", function (evt) { + if (evt.parent == that) { + map.hs.addArray(evt.hs); + map.es.addArray(evt.es); + map.js.addArray(evt.js); + map.ss.addArray(evt.ss); + map.xs.addArray(evt.xs); + map.cards.addArray(evt.cards); + map.cards2.addArray(evt.cards2); + for (let key in evt.gaintag_map) { + if (!map.gaintag_map[key]) map.gaintag_map[key] = []; + map.gaintag_map[key].addArray(evt.gaintag_map[key]); + } + } + }); + return map; + }; + next.getg = function (player) { + if (this.getlx === false || player != this.player || !this.cards) return []; + return this.cards.slice(0); + } + next.gaintag = []; + return next; + } + addToExpansion() { + var next = game.createEvent("addToExpansion"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.cards = [arguments[i]]; + } + else if (arguments[i] === "log") { + next.log = true; + } + else if (arguments[i] == "fromStorage") { + next.fromStorage = true; + } + else if (arguments[i] == "fromRenku") { + next.fromStorage = true; + next.fromRenku = true; + } + else if (arguments[i] == "bySelf") { + next.bySelf = true; + } + else if (typeof arguments[i] == "string") { + next.animate = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.delay = arguments[i]; + } + } + if (next.animate == "gain2" || next.animate == "draw2" || next.animate == "give") { + if (!Object.prototype.hasOwnProperty.call(next, "log")) { + next.log = true; + } + } + next.setContent("addToExpansion"); + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + var cards = [], event = this; + game.checkGlobalHistory("cardMove", function (evt) { + if (evt.name != "lose" || evt.position != position || evt.getParent() != event) return; + if (player && player != evt.player) return; + cards.addArray(evt[key]); + }); + return cards; + }; + next.getl = function (player) { + const that = this; + const map = { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + player.checkHistory("lose", function (evt) { + if (evt.parent == that) { + map.hs.addArray(evt.hs); + map.es.addArray(evt.es); + map.js.addArray(evt.js); + map.ss.addArray(evt.ss); + map.xs.addArray(evt.xs); + map.cards.addArray(evt.cards); + map.cards2.addArray(evt.cards2); + for (let key in evt.gaintag_map) { + if (!map.gaintag_map[key]) map.gaintag_map[key] = []; + map.gaintag_map[key].addArray(evt.gaintag_map[key]); + } + } + }); + return map; + }; + next.gaintag = []; + return next; + } + give(cards, target, visible) { + var next = target.gain(cards, this); + next.animate = visible ? "give" : "giveAuto"; + next.giver = this; + return next; + } + lose() { + var next = game.createEvent("lose"); + next.player = this; + next.forceDie = true; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.cards = [arguments[i]]; + } + else if (get.objtype(arguments[i]) == "div") { + next.position = arguments[i]; + } + else if (arguments[i] == "toStorage") { + next.toStorage = true; + } + else if (arguments[i] == "toRenku") { + next.toStorage = true; + next.toRenku = true; + } + else if (arguments[i] == "visible") { + next.visible = true; + } + else if (arguments[i] == "insert") { + next.insert_card = true; + } + } + if (next.cards) { + var hej = this.getCards("hejsx"); + for (var i = 0; i < next.cards.length; i++) { + if (!hej.contains(next.cards[i])) { + next.cards.splice(i--, 1); + } + } + } + if (!next.cards || !next.cards.length) { + _status.event.next.remove(next); + } + else { + if (next.position == undefined) next.position = ui.discardPile; + next.cards = next.cards.slice(0); + } + next.setContent("lose"); + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + if (this.getlx === false || this.position != position || (player && this.player != player) || !Array.isArray(this[key])) return []; + return this[key].slice(0); + }; + next.getl = function (player) { + if (this.getlx !== false && this.player == player) return this; + return { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + }; + return next; + } + damage() { + const next = game.createEvent("damage"); + //next.forceDie=true; + next.player = this; + let noCard, noSource; + const event = _status.event; + for (const argument of arguments) { + if (get.itemtype(argument) == "cards") next.cards = argument.slice(); + else if (get.itemtype(argument) == "card") next.card = argument; + else if (typeof argument == "number") next.num = argument; + else if (get.itemtype(argument) == "player") next.source = argument; + else if (argument && typeof argument == "object" && argument.name) next.card = argument; + else if (argument == "nocard") noCard = true; + else if (argument == "nosource") noSource = true; + else if (argument == "notrigger") { + next._triggered = null; + next.notrigger = true; + } + else if (argument == "unreal") next.unreal = true; + else if (get.itemtype(argument) == "nature" && argument != "stab") next.nature = argument; + else if (get.itemtype(argument) == "natures") { + const natures = argument.split(lib.natureSeparator).remove("stab"); + if (natures.length) next.nature = natures.join(lib.natureSeparator); + } + } + if (!next.card && !noCard) next.card = event.card; + if (!next.cards && !noCard) next.cards = event.cards; + if (!next.source && !noSource) { + const source = event.customSource || event.player; + if (source && !source.isDead()) next.source = source; + } + if (typeof next.num != "number") next.num = (event.baseDamage || 1) + (event.extraDamage || 0); + next.original_num = next.num; + next.change_history = []; + next.hasNature = function (nature) { + if (!nature) return Boolean(this.nature && this.nature.length > 0); + let natures = get.natureList(nature), naturesx = get.natureList(this.nature); + if (nature == "linked") return naturesx.some(n => lib.linked.includes(n)); + return get.is.sameNature(natures, naturesx); + }; + if (next.hasNature("poison")) delete next._triggered; + next.setContent("damage"); + next.filterStop = function () { + if (this.source && this.source.isDead()) delete this.source; + var num = this.original_num; + for (var i of this.change_history) num += i; + if (num != this.num) this.change_history.push(this.num - num); + if (this.num <= 0) { + delete this.filterStop; + this.trigger("damageZero"); + this.finish(); + this._triggered = null; + return true; + } + }; + return next; + } + recover() { + var next = game.createEvent("recover"); + next.player = this; + var nocard, nosource; + var event = _status.event; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "cards") { + next.cards = arguments[i].slice(0); + } + else if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (get.itemtype(arguments[i]) == "player") { + next.source = arguments[i]; + } + else if (typeof arguments[i] == "object" && arguments[i] && arguments[i].name) { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "number") { + next.num = arguments[i]; + } + else if (arguments[i] == "nocard") { + nocard = true; + } + else if (arguments[i] == "nosource") { + nosource = true; + } + } + if (next.card == undefined && !nocard) next.card = event.card; + if (next.cards == undefined && !nocard) next.cards = event.cards; + if (next.source == undefined && !nosource) next.source = event.customSource || event.player; + if (next.num == undefined) next.num = (event.baseDamage || 1) + (event.extraDamage || 0); + if (next.num <= 0) _status.event.next.remove(next); + next.setContent("recover"); + return next; + } + doubleDraw() { + if (get.is.changban()) return; + var next = game.createEvent("doubleDraw"); + next.player = this; + next.setContent("doubleDraw"); + return next; + } + loseHp(num) { + var next = game.createEvent("loseHp"); + next.num = num; + next.player = this; + if (next.num == undefined) next.num = 1; + next.setContent("loseHp"); + return next; + } + loseMaxHp() { + var next = game.createEvent("loseMaxHp"); + next.player = this; + next.num = 1; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] === "number") { + next.num = arguments[i]; + } + else if (typeof arguments[i] === "boolean") { + next.forced = arguments[i]; + } + } + next.setContent("loseMaxHp"); + return next; + } + gainMaxHp() { + var next = game.createEvent("gainMaxHp"); + next.player = this; + next.num = 1; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] === "number") { + next.num = arguments[i]; + } + else if (typeof arguments[i] === "boolean") { + next.forced = arguments[i]; + } + } + next.setContent("gainMaxHp"); + return next; + } + changeHp(num, popup) { + var next = game.createEvent("changeHp"); + next.num = num; + if (popup != undefined) next.popup = popup; + next.player = this; + next.setContent("changeHp"); + return next; + } + + changeHujia(num, type, limit) { + var next = game.createEvent("changeHujia"); + if (typeof num != "number") { + num = 1; + } + if (limit === true) limit = 5; + if (typeof limit == "number" && this.hujia + num > parseInt(limit)) { + num = Math.max(0, parseInt(limit) - this.hujia); + } + if (typeof type != "string") { + if (num > 0) type = "gain"; + else if (num < 0) type = "lose"; + else type = "null"; + } + next.num = num; + next.player = this; + next.type = type; + next.setContent("changeHujia"); + return next; + } + getBuff() { + var list = [1, 2, 3, 4, 5, 6]; + var nodelay = false; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + list.remove(arguments[i]); + } + else if (arguments[i] === false) { + nodelay = true; + } + } + if (this.isHealthy()) { + list.remove(2); + } + if (!this.countCards("j")) { + list.remove(5); + } + if (!this.isLinked() && !this.isTurnedOver()) { + list.remove(6); + } + if (this.hasSkill("qianxing")) { + list.remove(4); + } + switch (list.randomGet()) { + case 1: this.draw(nodelay ? "nodelay" : 1); break; + case 2: this.recover(); break; + case 3: this.changeHujia(); break; + case 4: this.tempHide(); break; + case 5: this.discard(this.getCards("j")).delay = (!nodelay); break; + case 6: { + if (this.isLinked()) this.link(); + if (this.isTurnedOver()) this.turnOver(); + break; + } + } + return this; + } + getDebuff() { + var list = [1, 2, 3, 4, 5, 6]; + var nodelay = false; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "number") { + list.remove(arguments[i]); + } + else if (arguments[i] === false) { + nodelay = true; + } + } + if (this.countCards("he") == 0) { + list.remove(1); + } + if (this.isLinked()) { + list.remove(4); + } + if (this.hasSkill("fengyin")) { + list.remove(5); + } + if (this.hp == 1) { + list.remove(3); + if (list.length > 1) list.remove(2); + } + if (!list.length) return this; + var num = list.randomGet(); + switch (list.randomGet()) { + case 1: this.randomDiscard(nodelay ? false : "he"); break; + case 2: this.loseHp(); break; + case 3: this.damage(); break; + case 4: if (!this.isLinked()) this.link(); break; + case 5: this.addTempSkill("fengyin", { player: "phaseAfter" }); break; + case 6: { + var list = []; + for (var i = 0; i < lib.inpile.length; i++) { + var info = lib.card[lib.inpile[i]]; + if (info.type == "delay" && !info.cancel && !this.hasJudge(lib.inpile[i])) { + list.push(lib.inpile[i]); + } + } + if (list.length) { + var card = game.createCard(list.randomGet()); + this.addJudge(card); + this.$draw(card); + if (!nodelay) game.delay(); + } + else { + this.getDebuff(6); + } + break; + } + } + return this; + } + dying(reason) { + if (this.nodying || this.hp > 0 || this.isDying()) return; + var next = game.createEvent("dying"); + next.player = this; + next.reason = reason; + if (reason && reason.source) next.source = reason.source; + next.setContent("dying"); + next.filterStop = function () { + if (this.player.hp > 0 || this.nodying) { + delete this.filterStop; + return true; + } + }; + return next; + } + die(reason) { + var next = game.createEvent("die"); + next.player = this; + next.reason = reason; + if (reason) next.source = reason.source; + next.setContent("die"); + return next; + } + revive(hp, log) { + if (log !== false) game.log(this, "复活"); + if (this.maxHp < 1) this.maxHp = 1; + if (hp) this.hp = hp; + else { + this.hp = 1; + } + game.addVideo("revive", this); + this.classList.remove("dead"); + this.removeAttribute("style"); + this.node.avatar.style.transform = ""; + this.node.avatar2.style.transform = ""; + this.node.hp.show(); + this.node.equips.show(); + this.node.count.show(); + this.update(); + var player; + player = this.previousSeat; + while (player.isDead()) player = player.previousSeat; + player.next = this; + this.previous = player; + player = this.nextSeat; + while (player.isDead()) player = player.nextSeat; + player.previous = this; + this.next = player; + game.players.add(this); + game.dead.remove(this); + if (this == game.me) { + if (ui.auto) ui.auto.show(); + if (ui.wuxie) ui.wuxie.show(); + if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + if (ui.exit) { + ui.exit.close(); + delete ui.exit; + } + if (ui.swap) { + ui.swap.close(); + delete ui.swap; + } + if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + } + } + isMad() { + return this.hasSkill("mad"); + } + goMad(end) { + if (end) { + this.addTempSkill("mad", end); + } + else { + this.addSkill("mad"); + } + game.log(this, "进入混乱状态"); + } + unMad() { + this.removeSkill("mad"); + } + tempHide() { + this.addTempSkill("qianxing", { player: "phaseBeginStart" }); + } + addExpose(num) { + if (typeof this.ai.shown == "number" && !this.identityShown && this.ai.shown < 1) { + this.ai.shown += num; + if (this.ai.shown > 0.95) { + this.ai.shown = 0.95; + } + } + return this; + } + equip(card, draw) { + var next = game.createEvent("equip"); + next.card = card; + next.player = this; + if (draw) { + next.draw = true; + } + next.setContent(lib.element.content.equip); + if (get.is.object(next.card) && next.card.cards) next.card = next.card.cards[0]; + next.cards = [next.card]; + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + var cards = [], event = this; + game.checkGlobalHistory("cardMove", function (evt) { + if (evt.name != "lose" || evt.position != position || evt.getParent() != event) return; + if (player && player != evt.player) return; + cards.addArray(evt[key]); + }); + return cards; + }; + next.getl = function (player) { + const that = this; + const map = { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + player.checkHistory("lose", function (evt) { + if (evt.parent == that) { + map.hs.addArray(evt.hs); + map.es.addArray(evt.es); + map.js.addArray(evt.js); + map.ss.addArray(evt.ss); + map.xs.addArray(evt.xs); + map.cards.addArray(evt.cards); + map.cards2.addArray(evt.cards2); + for (let key in evt.gaintag_map) { + if (!map.gaintag_map[key]) map.gaintag_map[key] = []; + map.gaintag_map[key].addArray(evt.gaintag_map[key]); + } + } + }); + return map; + }; + return next; + } + addJudge(card, cards) { + var next = game.createEvent("addJudge"); + if (get.itemtype(card) == "card") { + next.card = card; + next.cards = [card]; + } + else { + next.cards = cards; + if (get.itemtype(next.cards) == "card") next.cards = [next.cards]; + if (typeof card == "string") { + card = { name: card }; + } + next.card = get.autoViewAs(card, next.cards) + } + next.player = this; + next.setContent("addJudge"); + next.getd = function (player, key, position) { + if (!position) position = ui.discardPile; + if (!key) key = "cards"; + var cards = [], event = this; + game.checkGlobalHistory("cardMove", function (evt) { + if (evt.name != "lose" || evt.position != position || evt.getParent() != event) return; + if (player && player != evt.player) return; + cards.addArray(evt[key]); + }); + return cards; + }; + next.getl = function (player) { + const that = this; + const map = { + player: player, + hs: [], + es: [], + js: [], + ss: [], + xs: [], + cards: [], + cards2: [], + gaintag_map: {}, + }; + player.checkHistory("lose", function (evt) { + if (evt.parent == that) { + map.hs.addArray(evt.hs); + map.es.addArray(evt.es); + map.js.addArray(evt.js); + map.ss.addArray(evt.ss); + map.xs.addArray(evt.xs); + map.cards.addArray(evt.cards); + map.cards2.addArray(evt.cards2); + for (let key in evt.gaintag_map) { + if (!map.gaintag_map[key]) map.gaintag_map[key] = []; + map.gaintag_map[key].addArray(evt.gaintag_map[key]); + } + } + }); + return map; + }; + return next; + } + canAddJudge(card) { + if (this.isDisabledJudge()) return false; + var name; + if (typeof card == "string") { + name = card; + } + else { + name = card.viewAs || card.name; + } + if (!name) return false; + if (this.hasJudge(name)) return false; + if (this.isOut()) return false; + var mod = game.checkMod(card, this, this, "unchanged", "targetEnabled", this); + if (mod != "unchanged") return mod; + return true; + } + addJudgeNext(card, unlimited) { + if (!card.expired) { + let target = this.next; + const name = card.viewAs || card.name; + const cards = (get.itemtype(card) == "card") ? [card] : card.cards; + if (get.itemtype(cards) != "cards") return; + let bool = false; + if (!unlimited && cards.some(card => { + const position = get.position(card, true); + return position != "j" && position != "o"; + })) { + game.log(card, "已被移出处理区,无法置入判定区"); + return; + } + for (let iwhile = 0; iwhile < 20; iwhile++) { + if (target.canAddJudge(card)) { + bool = true; break; + } + target = target.next; + } + if (bool) { + if (card.cards && card.cards.length) { + target.addJudge(name, card.cards[0]); + } + else if (card.name != name) { + target.addJudge(name, card); + } + else { + target.addJudge(card); + } + } + } + else { + card.expired = false; + } + } + judge() { + var next = game.createEvent("judge"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (get.itemtype(arguments[i]) == "card") { + next.card = arguments[i]; + } + else if (typeof arguments[i] == "string") { + next.skill = arguments[i]; + } + else if (typeof arguments[i] == "function") { + next.judge = arguments[i]; + } + else if (typeof arguments[i] == "boolean") { + next.clearArena = arguments[i]; + } + else if (get.objtype(arguments[i]) == "div") { + next.position = arguments[i]; + } + } + if (next.card && next.judge == undefined) { + next.judge = get.judge(next.card); + next.judge2 = get.judge2(next.card); + } + if (next.judge == undefined) next.judge = function () { return 0 }; + if (next.position == undefined) next.position = ui.discardPile; + if (next.card) next.cardname = next.card.viewAs || next.card.name; + + var str = ""; + if (next.card) str = get.translation(next.card.viewAs || next.card.name); + else if (next.skill) str = get.translation(next.skill); + else str = get.translation(_status.event.name); + next.judgestr = str; + next.setContent("judge"); + return next; + } + turnOver(bool) { + if (typeof bool == "boolean") { + if (bool) { + if (this.isTurnedOver()) return; + } + else { + if (!this.isTurnedOver()) return; + } + } + var next = game.createEvent("turnOver"); + next.player = this; + next.includeOut = true; + next.setContent("turnOver"); + return next; + } + out(skill) { + if (typeof skill == "number") { + this.outCount += skill; + } + else if (typeof skill == "string") { + if (!this.outSkills) { + this.outSkills = []; + } + this.outSkills.add(skill); + } + else { + this.outCount++; + } + if (!this.classList.contains("out")) { + this.classList.add("out"); + game.log(this, "离开游戏"); + } + if (!game.countPlayer()) { + game.over(); + } + } + in(skill) { + if (this.isOut()) { + if (typeof skill == "string") { + if (this.outSkills) { + this.outSkills.remove(skill); + if (!this.outSkills.length) { + delete this.outSkills; + } + } + } + else if (typeof skill == "number") { + this.outCount -= skill; + } + else { + if (skill === true) { + delete this.outSkills; + } + this.outCount = 0; + } + if (this.outCount <= 0 && !this.outSkills) { + this.outCount = 0; + this.classList.remove("out"); + game.log(this, "进入游戏"); + } + } + } + link(bool) { + if (typeof bool == "boolean") { + if (bool) { + if (this.isLinked()) return; + } + else { + if (!this.isLinked()) return; + } + } + var next = game.createEvent("link"); + next.player = this; + next.setContent("link"); + return next; + } + skip(name) { + this.skipList.add(name); + } + wait(callback) { + if (lib.node) { + if (typeof callback == "function") { + callback._noname_waiting = true; + lib.node.torespond[this.playerid] = callback; + } + else { + lib.node.torespond[this.playerid] = "_noname_waiting"; + } + clearTimeout(lib.node.torespondtimeout[this.playerid]); + if (this.ws && !this.ws.closed) { + var player = this; + var time = parseInt(lib.configOL.choose_timeout) * 1000; + if (_status.event._global_timer || _status.event.getParent().skillHidden) { + for (var i = 0; i < game.players.length; i++) { + game.players[i].showTimer(time); + } + player._hide_all_timer = true; + } + else if (!_status.event._global_waiting && _status.noclearcountdown !== "direct") { + player.showTimer(time); + } + lib.node.torespondtimeout[this.playerid] = setTimeout(function () { + player.unwait("ai"); + player.ws.ws.close(); + }, time + 5000); + } + } + } + unwait(result) { + if (this._hide_all_timer) { + delete this._hide_all_timer; + for (var i = 0; i < game.players.length; i++) { + game.players[i].hideTimer(); + } + } + else if (!get.event("_global_waiting") && (_status.noclearcountdown !== "direct" || result && result.bool) && !(result && result._noHidingTimer)) { + this.hideTimer(); + } + clearTimeout(lib.node.torespondtimeout[this.playerid]); + delete lib.node.torespondtimeout[this.playerid]; + if (!Object.prototype.hasOwnProperty.call(lib.node.torespond, this.playerid)) { + return; + } + var noresume = false; + var proceed = null; + if (typeof lib.node.torespond[this.playerid] == "function" && lib.node.torespond[this.playerid]._noname_waiting) { + proceed = lib.node.torespond[this.playerid](result, this); + if (proceed === false) { + noresume = true; + } + } + lib.node.torespond[this.playerid] = result; + for (var i in lib.node.torespond) { + if (lib.node.torespond[i] == "_noname_waiting") { + return; + } + else if (lib.node.torespond[i] && lib.node.torespond[i]._noname_waiting) { + return; + } + } + _status.event.result = result; + _status.event.resultOL = lib.node.torespond; + lib.node.torespond = {}; + if (typeof proceed == "function") proceed(); + else if (_status.paused && !noresume) game.resume(); + } + tempUnwait(result) { + if (!Object.prototype.hasOwnProperty.call(lib.node.torespond, this.playerid)) { + return; + } + var proceed; + if (typeof lib.node.torespond[this.playerid] == "function" && lib.node.torespond[this.playerid]._noname_waiting) { + proceed = lib.node.torespond[this.playerid](result, this); + } + if (typeof proceed == "function") proceed(); + } + logSkill(name, targets, nature, logv) { + if (get.itemtype(targets) == "player") targets = [targets]; + var nopop = false; + var popname = name; + if (Array.isArray(name)) { + popname = name[1]; + name = name[0]; + } + var checkShow = this.checkShow(name); + if (lib.translate[name]) { + this.trySkillAnimate(name, popname, checkShow); + if (Array.isArray(targets) && targets.length) { + var str; + if (targets[0] == this) { + str = "#b自己"; + if (targets.length > 1) { + str += "、"; + str += get.translation(targets.slice(1)); + } + } + else str = targets; + game.log(this, "对", str, "发动了", "【" + get.skillTranslation(name, this) + "】"); + } + else { + game.log(this, "发动了", "【" + get.skillTranslation(name, this) + "】"); + } + } + if (nature != false) { + if (nature === undefined) { + nature = "green"; + } + this.line(targets, nature); + } + var info = lib.skill[name]; + if (info && info.ai && info.ai.expose != undefined && + this.logAi && (!targets || targets.length != 1 || targets[0] != this)) { + this.logAi(lib.skill[name].ai.expose); + } + if (info && info.round) { + var roundname = name + "_roundcount"; + this.storage[roundname] = game.roundNumber; + this.syncStorage(roundname); + this.markSkill(roundname); + } + game.trySkillAudio(name, this, true); + if (game.chess) { + this.chessFocus(); + } + if (logv === true) { + game.logv(this, name, targets, null, true); + } + else if (info && info.logv !== false) { + game.logv(this, name, targets); + } + if (info) { + var player = this; + var players = player.getSkills(false, false, false); + var equips = player.getSkills("e"); + var global = lib.skill.global.slice(0); + var logInfo = { + skill: name, + targets: targets, + event: _status.event, + }; + if (info.sourceSkill) { + logInfo.sourceSkill = info.sourceSkill; + if (global.contains(info.sourceSkill)) { + logInfo.type = "global"; + } + else if (players.contains(info.sourceSkill)) { + logInfo.type = "player"; + } + else if (equips.contains(info.sourceSkill)) { + logInfo.type = "equip"; + } + } + else { + if (global.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "global"; + } + else if (players.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "player"; + } + else if (equips.contains(name)) { + logInfo.sourceSkill = name; + logInfo.type = "equip"; + } + else { + var bool = false; + for (var i of players) { + var expand = [i]; + game.expandSkills(expand); + if (expand.contains(name)) { + bool = true; + logInfo.sourceSkill = i; + logInfo.type = "player"; + break; + } + } + if (!bool) { + for (var i of players) { + var expand = [i]; + game.expandSkills(expand); + if (expand.contains(name)) { + logInfo.sourceSkill = i; + logInfo.type = "equip"; + break; + } + } + } + } + } + var next = game.createEvent("logSkill", false), evt = _status.event; + next.player = player; + next.forceDie = true; + next.includeOut = true; + evt.next.remove(next); + if (evt.logSkill) evt = evt.getParent(); + for (var i in logInfo) { + if (i == "event") next.log_event = logInfo[i]; + else next[i] = logInfo[i]; + } + evt.after.push(next); + next.setContent("emptyEvent"); + player.getHistory("useSkill").push(logInfo); + //尽可能别往这写插入结算 + //不能用来终止技能发动!!! + var next2 = game.createEvent("logSkillBegin", false); + next2.player = player; + next2.forceDie = true; + next2.includeOut = true; + for (var i in logInfo) { + if (i == "event") next2.log_event = logInfo[i]; + else next2[i] = logInfo[i]; + } + next2.setContent("emptyEvent"); + } + if (this._hookTrigger) { + for (var i = 0; i < this._hookTrigger.length; i++) { + var info = lib.skill[this._hookTrigger[i]].hookTrigger; + if (info && info.log) { + info.log(this, name, targets); + } + } + } + } + unprompt() { + if (this.node.prompt) { + this.node.prompt.delete(); + delete this.node.prompt; + } + } + prompt(str, nature) { + var node; + if (this.node.prompt) { + node = this.node.prompt; + node.innerHTML = ""; + node.className = "damage normal-font damageadded"; + } + else { + node = ui.create.div(".damage.normal-font", this); + this.node.prompt = node; + ui.refresh(node); + node.classList.add("damageadded"); + } + node.innerHTML = str; + node.dataset.nature = nature || "soil"; + } + prompt_old(name2, className) { + var node; + if (this.node.prompt) { + node = this.node.prompt; + node.innerHTML = ""; + node.className = "popup"; + } + else { + node = ui.create.div(".popup", this.parentNode); + this.node.prompt = node; + } + node.dataset.position = this.dataset.position; + if (this.dataset.position == 0 || parseInt(this.dataset.position) == parseInt(ui.arena.dataset.number) / 2 || + typeof name2 == "number" || this.classList.contains("minskin")) { + node.innerHTML = name2; + } + else { + for (var i = 0; i < name2.length; i++) { + node.innerHTML += name2[i] + "
"; + } + } + if (className) { + node.classList.add(className); + } + } + popup(name, className, nobroadcast) { + var name2 = get.translation(name); + if (!name2) return; + this.$damagepop(name2, className || "water", true, nobroadcast); + } + popup_old(name, className) { + var name2 = get.translation(name); + var node = ui.create.div(".popup", this.parentNode); + if (!name2) { + node.remove(); + return node; + } + game.addVideo("popup", this, [name, className]); + node.dataset.position = this.dataset.position; + if (this.dataset.position == 0 || parseInt(this.dataset.position) == parseInt(ui.arena.dataset.number) / 2 || + typeof name2 == "number" || this.classList.contains("minskin")) { + node.innerHTML = name2; + } + else { + for (var i = 0; i < name2.length; i++) { + node.innerHTML += name2[i] + "
"; + } + } + if (className) { + node.classList.add(className); + } + this.popups.push(node); + if (this.popups.length > 1) { + node.hide(); + } + else { + var that = this; + setTimeout(function () { that._popup(); }, 1000); + } + return node; + } + _popup() { + if (this.popups.length) { + this.popups.shift().delete(); + if (this.popups.length) { + this.popups[0].show(); + var that = this; + setTimeout(function () { that._popup(); }, 1000); + } + } + } + showTimer(time) { + if (!time && lib.configOL) { + time = parseInt(lib.configOL.choose_timeout) * 1000; + } + if (_status.connectMode && !game.online) { + game.broadcast(function (player, time) { + player.showTimer(time); + }, this, time); + } + if (this == game.me) { + return; + } + if (this.node.timer) { + this.node.timer.remove(); + } + var timer = ui.create.div(".timerbar", this); + this.node.timer = timer; + ui.create.div(this.node.timer); + var bar = ui.create.div(this.node.timer); + ui.refresh(bar); + bar.style.transitionDuration = (time / 1000) + "s"; + bar.style.transform = "scale(0,1)"; + } + hideTimer() { + if (_status.connectMode && !game.online && this.playerid) { + game.broadcast(function (player) { + player.hideTimer(); + }, this); + } + if (this.node.timer) { + this.node.timer.delete(); + delete this.node.timer; + } + } + markAuto(name, info) { + if (typeof info != "undefined") { + if (!Array.isArray(this.storage[name])) this.storage[name] = []; + if (Array.isArray(info)) { + this.storage[name].addArray(info); + } + else this.storage[name].add(info); + this.markSkill(name); + } + else { + var storage = this.storage[name]; + if (Array.isArray(storage)) { + this[storage.length > 0 ? "markSkill" : "unmarkSkill"](name); + } + else if (typeof storage == "number") { + this[storage > 0 ? "markSkill" : "unmarkSkill"](name); + } + } + } + unmarkAuto(name, info) { + var storage = this.storage[name] + if (Array.isArray(info) && Array.isArray(storage)) { + storage.removeArray(info.slice(0)); + this.markAuto(name); + } + } + getExpansions(tag) { + return this.getCards("x", (card) => card.hasGaintag(tag)); + } + countExpansions(tag) { + return this.getExpansions(tag).length; + } + hasExpansions(tag) { + return this.countExpansions(tag) > 0; + } + setStorage(name, value, mark) { + this.storage[name] = value; + if (mark) this.markAuto(name); + return value; + } + getStorage(name) { + return this.storage[name] || []; + } + hasStorage(name, value) { + if (!(name in this.storage)) return false; + if (typeof value == "undefined") return true; + const storage = this.storage[name]; + if (storage === value) return true; + return Array.isArray(storage) && storage.includes(value); + } + hasStorageAny(name, values) { + const storage = this.storage[name]; + if (!Array.isArray(values)) values = Array.from(arguments).slice(1); + if (!storage) return false; + if (!Array.isArray(storage)) return values.contains(storage); + return values.some(item => storage.contains(item)); + } + hasStorageAll(name, values) { + const storage = this.storage[name]; + if (!Array.isArray(values)) values = Array.from(arguments).slice(1); + if (!storage) return false; + if (!Array.isArray(storage)) return false; + return values.every(item => storage.contains(item)); + } + initStorage(name, value, mark) { + return this.hasStorage(name) ? this.getStorage(name) : this.setStorage(name, value, mark); + } + updateStorage(name, operation, mark) { + return this.setStorage(name, operation(this.getStorage(name)), mark); + } + updateStorageAsync(name, operation, mark) { + return Promise.resolve(this.getStorage(name)) + .then(value => operation(value)) + .then(value => this.setStorage(name, value, mark)); + } + removeStorage(name, mark) { + if (!this.hasStorage(name)) return false; + delete this.storage[name] + if (mark) { + this.unmarkSkill(name); + } + return true; + } + markSkill(name, info, card, nobroadcast) { + if (info === true) { + this.syncStorage(name); + info = null; + } + if (get.itemtype(card) == "card") { + game.addVideo("markSkill", this, [name, get.cardInfo(card)]); + } + else { + game.addVideo("markSkill", this, [name]); + } + const func = function (storage, player, name, info, card) { + player.storage[name] = storage; + if (!info) { + if (player.marks[name]) { + player.updateMarks(); + return; + } + if (lib.skill[name]) { + info = lib.skill[name].intro; + } + if (!info) { + return; + } + } + if (player.marks[name]) { + player.marks[name].info = info; + } + else { + if (card) { + player.marks[name] = player.mark(card, info, name); + } + else { + player.marks[name] = player.mark(name, info); + } + } + player.updateMarks(); + }; + func(this.storage[name], this, name, info, card); + if (!nobroadcast) game.broadcast(func, this.storage[name], this, name, info, card); + return this; + } + unmarkSkill(name, nobroadcast) { + game.addVideo("unmarkSkill", this, name); + if (!nobroadcast) game.broadcast(function (player, name) { + if (player.marks[name]) { + player.marks[name].delete(); + player.marks[name].style.transform += " scale(0.2)"; + delete player.marks[name]; + ui.updatem(player); + } + }, this, name); + if (this.marks[name]) { + this.marks[name].delete(); + this.marks[name].style.transform += " scale(0.2)"; + delete this.marks[name]; + ui.updatem(this); + var info = lib.skill[name]; + if (!game.online && info && info.intro && info.intro.onunmark) { + if (info.intro.onunmark == "throw") { + if (get.itemtype(this.storage[name]) == "cards") { + this.$throw(this.storage[name], 1000); + game.cardsDiscard(this.storage[name]); + game.log(this.storage[name], "进入了弃牌堆"); + this.storage[name].length = 0; + } + } + else if (typeof info.intro.onunmark == "function") { + info.intro.onunmark(this.storage[name], this); + } + else delete this.storage[name]; + } + } + return this; + } + markSkillCharacter(id, target, name, content, nobroadcast) { + if (typeof target == "object") { + target = target.name; + } + const func = function (player, target, name, content, id) { + if (player.marks[id]) { + player.marks[id].name = name + "_charactermark"; + player.marks[id]._name = target; + player.marks[id].info = { + name: name, + content: content, + id: id + }; + player.marks[id].setBackground(target, "character"); + game.addVideo("changeMarkCharacter", player, { + id: id, + name: name, + content: content, + target: target + }); + } + else { + player.marks[id] = player.markCharacter(target, { + name: name, + content: content, + id: id + }); + player.marks[id]._name = target; + game.addVideo("markCharacter", player, { + name: name, + content: content, + id: id, + target: target + }); + } + } + func(this, target, name, content, id); + if (!nobroadcast) game.broadcast(func, this, target, name, content, id); + return this; + } + markCharacter(name, info, learn, learn2) { + if (typeof name == "object") { + name = name.name; + } + var node; + if (name.startsWith("unknown")) { + node = ui.create.div(".card.mark.drawinghidden"); + ui.create.div(".background.skillmark", node).innerHTML = get.translation(name)[0]; + } + else { + if (!lib.character[name]) return; + node = ui.create.div(".card.mark.drawinghidden").setBackground(name, "character"); + } + this.node.marks.insertBefore(node, this.node.marks.childNodes[1]); + node.name = name + "_charactermark"; + if (!info) { + info = {}; + } + if (!info.name) { + info.name = get.translation(name); + } + if (!info.content) { + info.content = get.skillintro(name, learn, learn2) + } + node.info = info; + node.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.card); + if (!lib.config.touchscreen) { + if (lib.config.hover_all) { + lib.setHover(node, ui.click.hoverplayer); + } + if (lib.config.right_info) { + node.oncontextmenu = ui.click.rightplayer; + } + } + ui.updatem(this); + return node; + } + mark(name, info, skill) { + if (get.itemtype(name) == "cards") { + var marks = []; + for (var i = 0; i < name.length; i++) { + marks.push(this.mark(name[i], info)); + } + return marks; + } + else { + var node; + if (get.itemtype(name) == "card") { + node = name.copy("mark"); + node.classList.add("drawinghidden"); + this.node.marks.insertBefore(node, this.node.marks.childNodes[1]); + node.suit = name.suit; + node.number = name.number; + // if(name.name&&lib.card[name.name]&&lib.card[name.name].markimage){ + // node.node.image.style.left=lib.card[name.name].markimage; + // } + + if (name.classList.contains("fullborder")) { + node.classList.add("fakejudge"); + node.classList.add("fakemark"); + (node.querySelector(".background") || ui.create.div(".background", node)).innerHTML = lib.translate[name.name + "_bg"] || get.translation(name.name)[0]; + } + + name = name.name; + } + else { + node = ui.create.div(".card.mark.drawinghidden"); + this.node.marks.insertBefore(node, this.node.marks.childNodes[1]); + if (lib.skill[name] && lib.skill[name].markimage) { + node.setBackgroundImage(lib.skill[name].markimage); + node.style["box-shadow"] = "none"; + node.style["background-size"] = "contain"; + } + else if (lib.skill[name] && lib.skill[name].markimage2) { + let img = ui.create.div(".background.skillmark", node); + img.setBackgroundImage(lib.skill[name].markimage2); + img.style["background-size"] = "contain"; + } + else { + var str = lib.translate[name + "_bg"]; + if (!str || str[0] == "+" || str[0] == "-") { + str = get.translation(name)[0]; + } + ui.create.div(".background.skillmark", node).innerHTML = str; + } + } + node.name = name; + node.skill = skill || name; + if (typeof info == "object") { + node.info = info; + } + else if (typeof info == "string") { + node.markidentifer = info; + } + node.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.card); + if (!lib.config.touchscreen) { + if (lib.config.hover_all) { + lib.setHover(node, ui.click.hoverplayer); + } + if (lib.config.right_info) { + node.oncontextmenu = ui.click.rightplayer; + } + } + this.updateMarks(); + ui.updatem(this); + return node; + } + } + unmark(name, info) { + game.addVideo("unmarkname", this, name); + if (get.itemtype(name) == "card") { + this.unmark(name.name, info); + } + else if (get.itemtype(name) == "cards") { + for (var i = 0; i < name.length; i++) { + this.unmark(name[i].name, info); + } + } + else { + for (var i = 0; i < this.node.marks.childNodes.length; i++) { + if (this.node.marks.childNodes[i].name == name && + (!info || this.node.marks.childNodes[i].markidentifer == info)) { + this.node.marks.childNodes[i].delete(); + this.node.marks.childNodes[i].style.transform += " scale(0.2)"; + ui.updatem(this); + return; + } + } + } + } + addLink() { + if (get.is.linked2(this)) { + this.classList.add("linked2"); + } + else { + this.classList.add("linked"); + } + } + removeLink() { + if (get.is.linked2(this)) { + this.classList.remove("linked2"); + } + else { + this.classList.remove("linked"); + } + } + canUse(card, target, distance, includecard) { + if (typeof card == "string") card = { name: card, isCard: true }; + var info = get.info(card); + if (info.multicheck && !info.multicheck(card, this)) return false; + if (!lib.filter.cardEnabled(card, this)) return false; + if (includecard && !lib.filter.cardUsable(card, this)) return false; + if (distance !== false && !lib.filter.targetInRange(card, this, target)) return false; + return lib.filter[includecard ? "targetEnabledx" : "targetEnabled"](card, this, target); + } + hasUseTarget(card, distance, includecard) { + var player = this; + return game.hasPlayer(function (current) { + return player.canUse(card, current, distance, includecard); + }); + } + hasValueTarget() { + return this.getUseValue.apply(this, arguments) > 0; + } + getUseValue(card, distance, includecard) { + if (typeof (card) == "string") { + card = { name: card, isCard: true }; + } + var player = this; + var targets = game.filterPlayer(); + var value = []; + var min = 0; + var info = get.info(card); + if (!info || info.notarget) return 0; + var range; + var select = get.copy(info.selectTarget); + if (select == undefined) { + if (info.filterTarget == undefined) return true; + range = [1, 1]; + } + else if (typeof select == "number") range = [select, select]; + else if (get.itemtype(select) == "select") range = select; + else if (typeof select == "function") range = select(card, player); + if (info.singleCard) range = [1, 1]; + game.checkMod(card, player, range, "selectTarget", player); + if (!range) return 0; + + for (var i = 0; i < targets.length; i++) { + if (player.canUse(card, targets[i], distance, includecard)) { + var eff = get.effect(targets[i], card, player, player); + value.push(eff); + } + } + value.sort(function (a, b) { + return b - a; + }); + for (var i = 0; i < value.length; i++) { + if (i == range[1] || range[1] != -1 && value[i] <= 0) break; + min += value[i]; + } + return min; + } + addSubPlayer(cfg) { + var skill = "subplayer_" + cfg.name + "_" + get.id(); + game.log(this, "获得了随从", "#g" + get.translation(cfg.name)) + cfg.hs = cfg.hs || []; + cfg.es = cfg.es || []; + cfg.skills = cfg.skills || []; + cfg.hp = cfg.hp || 1; + cfg.maxHp = cfg.maxHp || 1; + cfg.sex = cfg.sex || "male"; + cfg.group = cfg.group || "qun"; + cfg.skill = cfg.skill || _status.event.name; + if (!cfg.source) { + if (this.hasSkill(_status.event.name) && this.name2 && lib.character[this.name2] && + lib.character[this.name2][3].contains(_status.event.name)) { + cfg.source = this.name2; + } + else { + cfg.source = this.name; + } + } + game.broadcastAll(function (player, skill, cfg) { + lib.skill[skill] = { + intro: { + content: cfg.intro || "" + }, + mark: "character", + subplayer: cfg.skill, + ai: { + subplayer: true + } + } + lib.character[skill] = [cfg.sex, cfg.group, cfg.maxHp, cfg.skills, []]; + if (Array.isArray(cfg.image)) { + cfg.image.forEach(image => lib.character[skill][4].push(image)); + } else if (typeof cfg.image == "string") { + lib.character[skill][4].push(cfg.image); + } else { + lib.character[skill][4].push("character:" + cfg.name); + } + lib.translate[skill] = cfg.caption || get.rawName(cfg.name); + player.storage[skill] = cfg; + }, this, skill, cfg); + game.addVideo("addSubPlayer", this, [skill, lib.skill[skill], lib.character[skill], lib.translate[skill], { name: cfg.name }]); + this.addSkill(skill); + return skill; + } + removeSubPlayer(name) { + if (this.hasSkill("subplayer") && this.name == name) { + this.exitSubPlayer(true); + } + else { + if (player.storage[name].onremove) { + player.storage[name].onremove(player); + } + this.removeSkill(name); + delete this.storage[name]; + game.log(player, "牺牲了随从", "#g" + name); + _status.event.trigger("removeSubPlayer"); + } + } + callSubPlayer() { + if (this.hasSkill("subplayer")) return; + var next = game.createEvent("callSubPlayer"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + next.directresult = arguments[i]; + } + } + next.setContent("callSubPlayer"); + return next; + } + toggleSubPlayer() { + if (!this.hasSkill("subplayer")) return; + var next = game.createEvent("toggleSubPlayer"); + next.player = this; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + next.directresult = arguments[i]; + } + } + next.setContent("toggleSubPlayer"); + return next; + } + exitSubPlayer(remove) { + if (!this.hasSkill("subplayer")) return; + var next = game.createEvent("exitSubPlayer"); + next.player = this; + next.remove = remove; + next.setContent("exitSubPlayer"); + return next; + } + getSubPlayers(tag) { + var skills = this.getSkills(); + var list = []; + for (var i = 0; i < skills.length; i++) { + var name = skills[i]; + var info = lib.skill[name]; + if (tag && info.subplayer != tag) continue; + if (info.ai && info.ai.subplayer && this.storage[name] && this.storage[name].name) { + list.push(name); + } + } + return list; + } + addSkillTrigger(skills, hidden, triggeronly) { + if (typeof skills == "string") skills = [skills]; + game.expandSkills(skills); + for (const skill of skills) { + const info = lib.skill[skill]; + if (!info) { + console.error(new ReferenceError(`Cannot find ${skill} in lib.skill, failed to add ${skill}"s trigger to ${this.name}`)); + continue; + } + if (!triggeronly) { + if (info.global && (!hidden || info.globalSilent)) { + let global = info.global; + if (!Array.isArray(global)) global = [global]; + global.forEach(skill => game.addGlobalSkill(skill, this)); + } + if (this.initedSkills.includes(skill)) continue; + this.initedSkills.push(skill); + if (info.init && !_status.video) info.init(this, skill); + } + if (info.trigger && this.playerid) { + const setTrigger = (role, evt) => { + const name = this.playerid + "_" + role + "_" + evt; + if (!lib.hook[name]) lib.hook[name] = []; + lib.hook[name].add(skill); + lib.hookmap[evt] = true; + } + for (const role in info.trigger) { + let evts = info.trigger[role]; + if (!Array.isArray(evts)) evts = [evts]; + evts.forEach(evt => setTrigger(role, evt)); + } + } + if (info.hookTrigger) { + if (!this._hookTrigger) this._hookTrigger = []; + this._hookTrigger.add(skill); + } + if (_status.event && _status.event.addTrigger) _status.event.addTrigger(skill, this); + _status.event.clearStepCache(); + } + return this; + } + addSkillLog(skill) { + if (!skill) return this; + this.addSkill(skill); + if (!Array.isArray(skill)) skill = [skill]; + game.log(this, "获得了技能", ...skill.map(i => { + this.popup(i); + return "#g【" + get.translation(i) + "】"; + })); + } + removeSkillLog(skill, popup) { + if (!skill) return this; + this.removeSkill(skill); + if (!Array.isArray(skill)) skill = [skill]; + game.log(this, "失去了技能", ...skill.map(i => { + if (popup === true) this.popup(i); + return "#g【" + get.translation(i) + "】"; + })); + } + addInvisibleSkill(skill) { + if (Array.isArray(skill)) { + _status.event.clearStepCache(); + for (var i = 0; i < skill.length; i++) { + this.addInvisibleSkill(skill[i]); + } + } + else { + if (this.invisibleSkills.contains(skill)) return; + _status.event.clearStepCache(); + var info = lib.skill[skill]; + if (!info) return; + this.invisibleSkills.add(skill); + this.addSkillTrigger(skill); + if (this.awakenedSkills.contains(skill)) { + this.awakenSkill(skill); + return; + } + } + } + removeInvisibleSkill(skill) { + if (!skill) return; + if (Array.isArray(skill)) { + for (var i = 0; i < skill.length; i++) { + this.removeSkill(skill[i]); + } + } + else { + var info = lib.skill[skill]; + if (info && info.fixed && arguments[1] !== true) return skill; + game.broadcastAll(function (player, skill) { + player.invisibleSkills.remove(skill); + }, this, skill); + if (!player.hasSkill(skill, true)) player.removeSkill(skill); + } + return skill; + } + addSkill(skill, checkConflict, nobroadcast, addToSkills) { + if (Array.isArray(skill)) { + _status.event.clearStepCache(); + for (var i = 0; i < skill.length; i++) { + this.addSkill(skill[i]); + } + } + else { + if (this.skills.contains(skill)) return; + _status.event.clearStepCache(); + var info = lib.skill[skill]; + if (!info) return; + if (!addToSkills) { + this.skills.add(skill); + if (!nobroadcast) { + game.broadcast(function (player, skill) { + player.skills.add(skill); + }, this, skill); + } + } + this.addSkillTrigger(skill); + if (this.awakenedSkills.contains(skill)) { + this.awakenSkill(skill); + return; + } + if (info.init2 && !_status.video) { + info.init2(this, skill); + } + if (info.mark) { + if (info.mark == "card" && + get.itemtype(this.storage[skill]) == "card") { + this.markSkill(skill, null, this.storage[skill], nobroadcast); + } + else if (info.mark == "card" && + get.itemtype(this.storage[skill]) == "cards") { + this.markSkill(skill, null, this.storage[skill][0], nobroadcast); + } + else if (info.mark == "image") { + this.markSkill(skill, null, ui.create.card(null, "noclick").init([null, null, skill]), nobroadcast); + } + else if (info.mark == "character") { + var intro = info.intro.content; + if (typeof intro == "function") { + intro = intro(this.storage[skill], this); + } + else if (typeof intro == "string") { + intro = intro.replace(/#/g, this.storage[skill]); + intro = intro.replace(/&/g, get.cnNumber(this.storage[skill])); + intro = intro.replace(/\$/g, get.translation(this.storage[skill])); + } + var caption; + if (typeof info.intro.name == "function") { + caption = info.intro.name(this.storage[skill], this); + } + else if (typeof info.intro.name == "string") { + caption = info.name; + } + else { + caption = get.translation(skill); + } + this.markSkillCharacter(skill, this.storage[skill], caption, intro, nobroadcast); + } + else { + this.markSkill(skill, null, null, nobroadcast); + } + } + } + if (checkConflict) this.checkConflict(); + return skill; + } + addAdditionalSkill(skill, skills, keep) { + if (this.additionalSkills[skill]) { + if (keep) { + if (typeof this.additionalSkills[skill] == "string") { + this.additionalSkills[skill] = [this.additionalSkills[skill]]; + } + } + else { + this.removeAdditionalSkill(skill); + this.additionalSkills[skill] = []; + } + } + else { + this.additionalSkills[skill] = []; + } + if (typeof skills == "string") { + skills = [skills]; + } + for (var i = 0; i < skills.length; i++) { + this.addSkill(skills[i], null, true, true); + //this.skills.remove(skills[i]); + this.additionalSkills[skill].push(skills[i]); + } + this.checkConflict(); + _status.event.clearStepCache(); + return this; + } + removeAdditionalSkill(skill, target) { + const player = this; + if (this.additionalSkills[skill]) { + const additionalSkills = this.additionalSkills[skill]; + const hasAnotherSKill = function (skillkey, skill) { + return (player.skills.contains(skill) || player.tempSkills[skill] || Object.keys(player.additionalSkills).some(key => { + if (key === skillkey) return false; + if (Array.isArray(player.additionalSkills[key])) return player.additionalSkills[key].includes(skill); + return player.additionalSkills[key] == skill; + })) + } + if (Array.isArray(additionalSkills) && typeof target == "string") { + if (additionalSkills.contains(target)) { + additionalSkills.remove(target); + if (!hasAnotherSKill(skill, target)) this.removeSkill(target); + } + } + else { + delete this.additionalSkills[skill]; + if (typeof additionalSkills == "string") { + if (!hasAnotherSKill(skill, additionalSkills)) this.removeSkill(additionalSkills); + } + else if (Array.isArray(additionalSkills)) { + const skillsToRemove = additionalSkills.filter(target => !hasAnotherSKill(skill, target)) + this.removeSkill(skillsToRemove); + } + } + } + _status.event.clearStepCache(); + return this; + } + awakenSkill(skill, nounmark) { + if (!nounmark) this.unmarkSkill(skill); + this.disableSkill(skill + "_awake", skill); + this.awakenedSkills.add(skill); + if (this.storage[skill] === false) this.storage[skill] = true; + _status.event.clearStepCache(); + return this; + } + restoreSkill(skill, nomark) { + if (this.storage[skill] === true) this.storage[skill] = false; + this.awakenedSkills.remove(skill); + this.enableSkill(skill + "_awake", skill); + if (!nomark) this.markSkill(skill); + _status.event.clearStepCache(); + return this; + } + disableSkill(skill, skills) { + if (typeof skills == "string") { + if (!this.disabledSkills[skills]) { + this.disabledSkills[skills] = []; + var info = get.info(skills); + if (info.ondisable && info.onremove) { + if (typeof info.onremove == "function") { + info.onremove(this, skill); + } + else if (typeof info.onremove == "string") { + if (info.onremove == "storage") { + delete this.storage[skill]; + } + else { + var cards = this.storage[skill]; + if (get.itemtype(cards) == "card") { + cards = [cards]; + } + if (get.itemtype(cards) == "cards") { + if (this.onremove == "discard") { + this.$throw(cards); + } + if (this.onremove == "discard" || this.onremove == "lose") { + game.cardsDiscard(cards); + delete this.storage[skill]; + } + } + } + } + else if (Array.isArray(info.onremove)) { + for (var i = 0; i < info.onremove.length; i++) { + delete this.storage[info.onremove[i]]; + } + } + else if (info.onremove === true) { + delete this.storage[skill]; + } + } + } + this.disabledSkills[skills].add(skill); + var group = lib.skill[skills].group; + if (typeof group == "string" || Array.isArray(group)) { + this.disableSkill(skill, group); + } + } + else if (Array.isArray(skills)) { + for (var i = 0; i < skills.length; i++) { + this.disableSkill(skill, skills[i]); + } + } + _status.event.clearStepCache(); + return this; + } + enableSkill(skill) { + for (var i in this.disabledSkills) { + this.disabledSkills[i].remove(skill); + if (this.disabledSkills[i].length == 0) { + delete this.disabledSkills[i]; + } + } + _status.event.clearStepCache(); + return this; + } + checkMarks() { + var skills = this.getSkills(); + game.expandSkills(skills); + for (var i in this.marks) { + if (!skills.contains(i) && !this.marks[i].info.fixed) { + this.unmarkSkill(i); + } + } + return this; + } + addEquipTrigger(card) { + if (card) { + var info = get.info(card); + if (info.skills) { + for (var j = 0; j < info.skills.length; j++) { + this.addSkillTrigger(info.skills[j]); + } + } + } + else { + var es = this.getCards("e"); + for (var i = 0; i < es.length; i++) { + this.addEquipTrigger(es[i]); + } + } + _status.event.clearStepCache(); + return this; + } + removeEquipTrigger(card) { + if (card) { + var info = get.info(card); + var skills = this.getSkills(null, false); + if (info.skills) { + for (var j = 0; j < info.skills.length; j++) { + if (skills.contains(info.skills[j])) continue; + this.removeSkillTrigger(info.skills[j]); + } + } + if (info.clearLose && typeof info.onLose == "function") { + var next = game.createEvent("lose_" + card.name); + next.setContent(info.onLose); + next.player = this; + next.card = card; + } + } + else { + var es = this.getCards("e"); + for (var i = 0; i < es.length; i++) { + this.removeEquipTrigger(es[i]); + } + } + _status.event.clearStepCache(); + return this; + } + removeSkillTrigger(skills, triggeronly) { + if (typeof skills == "string") skills = [skills]; + game.expandSkills(skills); + for (const skill of skills) { + const info = lib.skill[skill]; + if (!info) { + console.error(new ReferenceError(`Cannot find ${skill} in lib.skill, failed to remove ${skill}"s trigger to ${this.name}`)); + continue; + } + if (!triggeronly) { + if (info.global) { + let global = info.global; + if (!Array.isArray(global)) global = [global]; + global.forEach(skill => game.removeGlobalSkill(skill, this)); + } + if (!this.initedSkills.includes(skill)) continue; + this.initedSkills.remove(skill); + // if(info.onremove&&!_status.video) info.onremove(this,skill); + } + if (info.trigger && this.playerid) { + const removeTrigger = (role, evt) => { + const name = this.playerid + "_" + role + "_" + evt; + if (!lib.hook[name]) return; + lib.hook[name].remove(skill); + if (lib.hook[name].length == 0) delete lib.hook[name]; + } + for (const role in info.trigger) { + let evts = info.trigger[role]; + if (!Array.isArray(evts)) evts = [evts]; + evts.forEach(evt => removeTrigger(role, evt)); + } + } + if (info.hookTrigger && this._hookTrigger) { + this._hookTrigger.remove(skill); + if (!this._hookTrigger.length) delete this._hookTrigger; + } + if (_status.event && _status.event.removeTrigger) _status.event.removeTrigger(skill, this); + _status.event.clearStepCache(); + } + return this; + } + removeSkill(skill) { + if (!skill) return; + _status.event.clearStepCache(); + if (Array.isArray(skill)) { + for (var i = 0; i < skill.length; i++) { + this.removeSkill(skill[i]); + } + } + else { + var info = lib.skill[skill]; + if (info && info.fixed && arguments[1] !== true) return skill; + this.unmarkSkill(skill); + game.broadcastAll(function (player, skill) { + player.skills.remove(skill); + player.hiddenSkills.remove(skill); + player.invisibleSkills.remove(skill); + delete player.tempSkills[skill]; + for (var i in player.additionalSkills) { + player.additionalSkills[i].remove(skill); + } + }, this, skill); + this.checkConflict(skill); + if (info) { + if (info.onremove) { + if (typeof info.onremove == "function") { + info.onremove(this, skill); + } + else if (typeof info.onremove == "string") { + if (info.onremove == "storage") { + delete this.storage[skill]; + } + else { + var cards = this.storage[skill]; + if (get.itemtype(cards) == "card") { + cards = [cards]; + } + if (get.itemtype(cards) == "cards") { + if (this.onremove == "discard") { + this.$throw(cards); + } + if (this.onremove == "discard" || this.onremove == "lose") { + game.cardsDiscard(cards); + delete this.storage[skill]; + } + } + } + } + else if (Array.isArray(info.onremove)) { + for (var i = 0; i < info.onremove.length; i++) { + delete this.storage[info.onremove[i]]; + } + } + else if (info.onremove === true) { + delete this.storage[skill]; + } + } + this.removeSkillTrigger(skill); + if (!info.keepSkill) { + this.removeAdditionalSkill(skill); + } + } + this.enableSkill(skill + "_awake"); + } + return skill; + } + addTempSkill(skill, expire, checkConflict) { + if (this.hasSkill(skill) && this.tempSkills[skill] == undefined) return; + this.addSkill(skill, checkConflict, true, true); + + if (!expire) expire = { global: ["phaseAfter", "phaseBeforeStart"] }; + else if (typeof expire == "string" || Array.isArray(expire)) expire = { global: expire }; + this.tempSkills[skill] = expire; + + if (get.objtype(expire) == "object") { + const roles = ["player", "source", "target", "global"]; + for (const i of roles) { + let triggers = expire[i]; + if (!Array.isArray(triggers)) triggers = [triggers]; + triggers.forEach(trigger => lib.hookmap[trigger] = true); + } + } + + return skill; + } + tempBanSkill(skill, expire, log) { + if (this.isTempBanned(skill)) return; + this.setStorage(`temp_ban_${skill}`, true); + + if (log !== false && this.hasSkill(skill)) game.log(this, "的技能", `#g【${get.translation(skill)}】`, "暂时失效了"); + + if (!expire) expire = { global: ["phaseAfter", "phaseBeforeStart"] }; + else if (typeof expire == "string" || Array.isArray(expire)) expire = { global: expire }; + this.when(expire).assign({ + firstDo: true, + }).vars({ + bannedSkill: skill, + }).then(() => { + delete player.storage[`temp_ban_${bannedSkill}`]; + }) + return skill; + } + isTempBanned(skill) { + return this.hasStorage(`temp_ban_${skill}`); + } + attitudeTo(target) { + if (typeof get.attitude == "function") return get.attitude(this, target); + return 0; + } + clearSkills(all) { + var list = []; + var exclude = []; + for (var i = 0; i < arguments.length; i++) { + exclude.push(arguments[i]); + } + for (i = 0; i < this.skills.length; i++) { + if (lib.skill[this.skills[i]].superCharlotte) continue; + if (!all && (lib.skill[this.skills[i]].temp || lib.skill[this.skills[i]].charlotte)) continue; + if (!exclude.contains(this.skills[i])) { + list.push(this.skills[i]); + } + } + if (all) { + for (var i in this.additionalSkills) { + this.removeAdditionalSkill(i); + } + } + this[all ? "removeSkill" : "removeSkillLog"](list); + this.checkConflict(); + this.checkMarks(); + return list; + } + checkConflict(skill) { + if (skill) { + if (this.forbiddenSkills[skill]) { + delete this.forbiddenSkills[skill]; + } + else { + for (var i in this.forbiddenSkills) { + if (this.forbiddenSkills[i].includes(skill)) { + this.forbiddenSkills[i].remove(skill) + if (!this.forbiddenSkills[i].length) { + delete this.forbiddenSkills[i]; + } + } + } + } + } + else { + this.forbiddenSkills = {}; + var forbid = []; + var getName = function (arr) { + var str = ""; + for (var i = 0; i < arr.length; i++) { + str += arr[i] + "+"; + } + return str.slice(0, str.length - 1); + } + var forbidlist = lib.config.forbid.concat(lib.config.customforbid); + var skills = this.getSkills(); + for (var i = 0; i < forbidlist.length; i++) { + if (lib.config.customforbid.contains(forbidlist[i]) || + !lib.config.forbidlist.contains(getName(forbidlist[i]))) { + for (var j = 0; j < forbidlist[i].length; j++) { + if (!skills.contains(forbidlist[i][j])) break; + } + if (j == forbidlist[i].length) { + forbid.push(forbidlist[i]); + } + } + } + for (var i = 0; i < forbid.length; i++) { + if (forbid[i][1] || this.name2) { + this.forbiddenSkills[forbid[i][0]] = this.forbiddenSkills[forbid[i][0]] || []; + if (forbid[i][1]) { + this.forbiddenSkills[forbid[i][0]].add(forbid[i][1]); + } + } + } + } + } + getHistory(key, filter, last) { + if (!key) return this.actionHistory[this.actionHistory.length - 1]; + if (!filter) return this.actionHistory[this.actionHistory.length - 1][key]; + else { + const history = this.getHistory(key); + if (last) { + const lastIndex = history.indexOf(last); + return history.filter((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }) + } + return history.filter(filter); + } + } + checkHistory(key, filter, last) { + if (!key || !filter) return; + else { + const history = this.getHistory(key); + if (last) { + const lastIndex = history.indexOf(last); + history.forEach((event, index) => { + if (index > lastIndex) return false; + filter(event); + }) + } + else { + history.forEach(filter); + } + } + } + hasHistory(key, filter, last) { + const history = this.getHistory(key); + if (!filter || typeof filter != "function") filter = lib.filter.all; + if (last) { + const lastIndex = history.indexOf(last); + return history.some((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }) + } + return history.some(filter); + } + getLastHistory(key, filter, last) { + let history = false; + for (let i = this.actionHistory.length - 1; i >= 0; i--) { + if (this.actionHistory[i].isMe) { + history = this.actionHistory[i]; break; + } + } + if (!history) return null; + if (!key) return history; + if (!filter) return history[key]; + else { + if (last) { + const lastIndex = history.indexOf(last); + return history.filter((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }) + } + return history.filter(filter); + } + } + checkAllHistory(key, filter, last) { + if (!key || !filter) return; + this.actionHistory.forEach((value) => { + let history = value[key]; + if (last && history.includes(last)) { + const lastIndex = history.indexOf(last); + history.forEach((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }); + } + else { + history.forEach(filter); + } + }); + } + getAllHistory(key, filter, last) { + const history = []; + this.actionHistory.forEach((value) => { + if (!key || !value[key]) { + history.push(value); + } + else { + history.push(...value[key]); + } + }) + if (filter) { + if (last) { + const lastIndex = history.indexOf(last); + return history.filter((event, index) => { + if (index > lastIndex) return false; + return filter(event); + }); + } + return history.filter(filter); + } + return history; + } + hasAllHistory(key, filter, last) { + return this.actionHistory.some((value) => { + let history = value[key]; + if (last && history.includes(last)) { + const lastIndex = history.indexOf(last); + if (history.some(function (event, index) { + if (index > lastIndex) return false; + return filter(event); + })) return true; + } + else { + if (history.some(filter)) return true; + } + return false; + }) + } + getLastUsed(num) { + if (typeof num != "number") num = 0; + var history = this.getHistory("useCard"); + if (history.length <= num) return null; + return history[history.length - num - 1]; + } + getStat(key) { + if (!key) return this.stat[this.stat.length - 1]; + return this.stat[this.stat.length - 1][key]; + } + getLastStat(key) { + var stat = false; + for (var i = this.stat.length - 1; i >= 0; i--) { + if (this.stat[i].isMe) { + stat = this.stat[i]; break; + } + } + if (!stat) return null + if (!key) return stat; + return stat[key]; + } + queue(time) { + if (time == false) { + clearTimeout(this.queueTimeout); + this.queueCount = 0; + return; + } + if (time == undefined) time = 500; + var player = this; + player.queueCount++; + this.queueTimeout = setTimeout(function () { + player.queueCount--; + if (player.queueCount == 0) { + player.style.transform = ""; + player.node.avatar.style.transform = ""; + player.node.avatar2.style.transform = ""; + if (game.chess) { + ui.placeChess(player, player.dataset.position); + } + if (player == game.me) ui.me.removeAttribute("style"); + } + }, time) + } + getCardUsable(card, pure) { + var player = this; + if (typeof card == "string") { + card = { name: card }; + } + card = get.autoViewAs(card); + var num = get.info(card).usable; + if (typeof num == "function") num = num(card, player); + num = game.checkMod(card, player, num, "cardUsable", player); + if (typeof num != "number") return Infinity; + if (!pure && _status.currentPhase == player) { + return num - player.countUsed(card); + } + return num; + } + getAttackRange(raw) { + const player = this; + let range = 0; + if (raw) { + range = game.checkMod(player, player, range, "globalFrom", player); + range = game.checkMod(player, player, range, "attackFrom", player); + const equips = player.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + equips.forEach(card => { + const info = get.info(card, false).distance; + if (info && info.globalFrom) { + range += info.globalFrom; + } + }) + return (player.getEquipRange() - range); + } + let base = game.checkMod(player, "unchanged", "attackRangeBase", player); + if (base != "unchanged") { + range = base; + } + else { + range = player.getEquipRange(); + } + range = game.checkMod(player, range, "attackRange", player); + return range; + } + getEquipRange(cards) { + const player = this; + if (!cards) cards = player.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + const range = cards.reduce((range, card) => { + let newRange = false; + const info = get.info(card, false); + if (info.distance) { + //如果存在attackRange 则通过attackRange动态获取攻击范围 + if (typeof info.distance.attackRange == "function") { + newRange = info.distance.attackRange(card, player); + } + //否则采用祖宗之法 + else if (typeof info.distance.attackFrom == "number") { + newRange = (1 - info.distance.attackFrom); + } + } + let isN1 = (typeof range == "number"); + let isN2 = (typeof newRange == "number"); + if (isN1 && isN2) return Math.max(range, newRange); + else return (isN1 ? range : newRange); + }, false); + return (typeof range == "number") ? range : 1; + } + getGlobalFrom() { + var player = this; + var range = 0; + range = game.checkMod(player, player, range, "globalFrom", player); + var equips = player.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + for (var i = 0; i < equips.length; i++) { + var info = get.info(equips[i]).distance; + if (!info) continue; + if (info.globalFrom) { + range += info.globalFrom; + } + } + return (-range); + } + getGlobalTo() { + var player = this; + var range = 0; + range = game.checkMod(player, player, range, "globalTo", player); + var equips = player.getCards("e", function (card) { + return !ui.selected.cards || !ui.selected.cards.contains(card); + }); + for (var i = 0; i < equips.length; i++) { + var info = get.info(equips[i]).distance; + if (!info) continue; + if (info.globalTo) { + range += info.globalTo; + } + } + return (range); + } + getHandcardLimit() { + var num = Math.max(this.hp, 0); + num = game.checkMod(this, num, "maxHandcardBase", this); + num = game.checkMod(this, num, "maxHandcard", this); + num = game.checkMod(this, num, "maxHandcardFinal", this); + return Math.max(0, num); + } + getEnemies(func) { + var player = this; + var targets; + var mode = get.mode(); + if (mode == "identity") { + if (_status.mode == "purple") { + switch (player.identity) { + case "bZhu": case "bZhong": case "rNei": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["rZhu", "rZhong", "bNei"].contains(target.identity); + }); break; + case "rZhu": case "rZhong": case "bNei": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["bZhu", "bZhong", "rNei"].contains(target.identity); + }); break; + case "rYe": case "bYe": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return !["rYe", "bYe"].contains(target.identity); + }); break; + } + } + else { + var num = get.population("fan"); + switch (player.identity) { + case "zhu": case "zhong": case "mingzhong": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + if (num >= 3) return target.identity == "fan"; + return target.identity == "nei" || target.identity == "fan"; + }); break; + case "nei": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + if (num >= 3) return target.identity == "fan"; + if (game.players.length == 2) return target != player; + return target.identity == "zhong" || target.identity == "mingzhong" || target.identity == "fan"; + }); break; + case "fan": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity != "fan"; + }); break; + case "commoner": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + if (num >= 3) return target.identity != "fan"; + return target.identity == "fan"; + }); break; + } + } + } + else if (mode == "guozhan") { + if (player.identity == "ye") { + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return true; + }); + } + else { + var group = lib.character[player.name1][1]; + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity == "ye" || lib.character[target.name1][1] != group; + }); + } + } + else if (mode == "doudizhu") { + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity != player.identity; + }); + } + else { + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.side != player.side; + }); + } + targets.remove(player); + return targets; + } + getFriends(func) { + var player = this; + var targets; + var mode = get.mode(); + var self = false; + if (func === true) { + func = null; + self = true; + } + if (mode == "identity") { + if (_status.mode == "purple") { + switch (player.identity) { + case "rZhu": case "rZhong": case "bNei": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["rZhu", "rZhong", "bNei"].contains(target.identity); + }); break; + case "bZhu": case "bZhong": case "rNei": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["bZhu", "bZhong", "rNei"].contains(target.identity); + }); break; + case "rYe": case "bYe": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["rYe", "bYe"].contains(target.identity); + }); break; + } + } + else { + switch (player.identity) { + case "zhu": case "zhong": case "mingzhong": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return ["zhu", "zhong", "mingzhong"].contains(target.identity); + }); break; + case "nei": targets = []; break; + case "fan": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity == "fan"; + }); break; + case "commoner": targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return true; + }); break; + } + } + } + else if (mode == "guozhan") { + if (player.identity == "ye") { + targets = []; + } + else { + var group = lib.character[player.name1][1]; + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity != "ye" && lib.character[target.name1][1] == group; + }); + } + } + else if (mode == "doudizhu") { + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.identity == player.identity; + }); + } + else { + targets = game.filterPlayer(function (target) { + if (func && !func(target)) return false; + return target.side == player.side; + }); + } + if (self) { + targets.add(player); + } + else { + targets.remove(player); + } + return targets; + } + isEnemyOf() { + return !this.isFriendOf.apply(this, arguments); + } + isFriendOf(player) { + if (get.mode() == "guozhan") { + if (this == player) return true; + if (this.getStorage("yexinjia_friend").includes(player) || player.getStorage("yexinjia_friend").includes(this)) return true; + if (this.identity == "unknown" || this.identity == "ye") return false; + if (player.identity == "unknown" || player.identity == "ye") return false; + return this.identity == player.identity; + } + if (get.mode() == "doudizhu") { + return this.identity == player.identity; + } + if (this.side != undefined && typeof player.side == "boolean") { + return this.side == player.side; + } + return this == player; + } + isFriendsOf(player) { + return player.getFriends(true).contains(this); + } + isEnemiesOf(player) { + return player.getEnemies().contains(this); + } + isAlive() { + return this.classList.contains("dead") == false; + } + isDead() { + return this.classList.contains("dead"); + } + isDying() { + return _status.dying.contains(this) && this.hp <= 0 && this.isAlive(); + } + isDamaged() { + return this.hp < this.maxHp && !this.storage.nohp; + } + isHealthy() { + return this.hp >= this.maxHp || this.storage.nohp; + } + isMaxHp(only, raw) { + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.getHp(raw) < this.getHp(raw) : value.getHp(raw) <= this.getHp(raw); + }); + } + isMinHp(only, raw) { + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.getHp(raw) > this.getHp(raw) : value.getHp(raw) >= this.getHp(raw); + }); + } + isMaxCard(only) { + const numberOfCards = this.countCards("he"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("he") < numberOfCards : value.countCards("he") <= numberOfCards; + }); + } + isMinCard(only) { + const numberOfCards = this.countCards("he"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("he") > numberOfCards : value.countCards("he") >= numberOfCards; + }); + } + isMaxHandcard(only) { + const numberOfHandCards = this.countCards("h"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("h") < numberOfHandCards : value.countCards("h") <= numberOfHandCards; + }); + } + isMinHandcard(only) { + const numberOfHandCards = this.countCards("h"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("h") > numberOfHandCards : value.countCards("h") >= numberOfHandCards; + }); + } + isMaxEquip(only) { + const numberOfEquipAreaCards = this.countCards("e"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("e") < numberOfEquipAreaCards : value.countCards("e") <= numberOfEquipAreaCards; + }); + } + isMinEquip(only) { + const numberOfEquipAreaCards = this.countCards("e"); + return game.players.every(value => { + if (value.isOut() || value == this) return true; + return only ? value.countCards("e") > numberOfEquipAreaCards : value.countCards("e") >= numberOfEquipAreaCards; + }); + } + isLinked() { + if (get.is.linked2(this)) { + return this.classList.contains("linked2"); + } + return this.classList.contains("linked"); + } + isTurnedOver() { + return this.classList.contains("turnedover"); + } + isOut() { + return this.classList.contains("out"); + } + isMin(distance) { + if (distance && lib.config.mode != "stone") return false; + if (this.forcemin) return true; + return this.classList.contains("minskin") && !game.chess; + } + isIn() { + return this.classList.contains("dead") == false && this.classList.contains("out") == false && !this.removed; + } + isUnseen(num) { + switch (num) { + case 0: return this.classList.contains("unseen"); + case 1: return this.classList.contains("unseen2"); + case 2: return this.classList.contains("unseen") || this.classList.contains("unseen2"); + default: return this.classList.contains("unseen") && (!this.name2 || this.classList.contains("unseen2")); + } + } + isUnderControl(self, me) { + me = (me || game.me); + var that = this._trueMe || this; + if (that.isMad() || game.notMe) return false; + if (this === me) { + if (self) return true; + return false; + } + if (that === me || this == me._trueMe) return true; + if (_status.connectMode) return false; + if (lib.config.mode == "versus") { + if (_status.mode == "three") return this.side == me.side; + if (_status.mode == "standard") return lib.storage.single_control && this.side == me.side; + if (_status.mode == "four") return get.config("four_phaseswap") && this.side == me.side; + if (_status.mode == "two") return get.config("two_phaseswap") && this.side == me.side; + return false; + } + else if (lib.config.mode == "boss") { + if (me.side) return false; + return this.side == me.side && get.config("single_control"); + } + else if (game.chess) { + if (lib.config.mode == "chess") { + if (_status.mode == "combat" && !get.config("single_control")) return false; + } + return this.side == me.side; + } + return false; + } + isOnline() { + if (this.ws && lib.node && !this.ws.closed && this.ws.inited && !this.isAuto) { + return true; + } + return false; + } + isOnline2() { + if (this.ws && lib.node && !this.ws.closed) { + return true; + } + return false; + } + isOffline() { + if (this.ws && lib.node && this.ws.closed) { + return true; + } + return false; + } + checkShow(skill, showonly) { + var sourceSkill = get.info(skill); + var noshow = false; + if (sourceSkill && sourceSkill.sourceSkill) { + skill = sourceSkill.sourceSkill; + } + if (lib.skill.global.contains(skill)) return false; + if (get.mode() != "guozhan" || game.expandSkills(this.getSkills()).contains(skill)) { + if (showonly) { + return false; + } + else { + noshow = true; + } + } + var unseen0 = this.isUnseen(0); + var name1 = this.name1 || this.name; + if (lib.character[name1] && (!showonly || unseen0)) { + var skills = game.expandSkills(lib.character[name1][3].slice(0)); + if (skills.contains(skill)) { + if (!noshow && this.isUnseen(0)) this.showCharacter(0); + return "main"; + } + } + var unseen1 = this.isUnseen(1); + var name2 = this.name2; + if (lib.character[name2] && (!showonly || unseen1)) { + var skills = game.expandSkills(lib.character[name2][3].slice(0)); + if (skills.contains(skill)) { + if (!noshow && this.isUnseen(1)) this.showCharacter(1); + return "vice"; + } + } + return false; + } + needsToDiscard(filter, add) { + let cards = this.getCards("h", card => !this.canIgnoreHandcard(card)), num = 0; + if (get.itemtype(add) === "cards") cards.addArray(add); + else if (get.itemtype(add) === "card") cards.push(add); + if (typeof filter === "number") num = filter; + else if (typeof filter === "function") cards = cards.filter(card => { + return filter(card); + }); + return Math.max(0, num + cards.length - this.getHandcardLimit()); + } + distanceTo(target, method) { + return get.distance(this, target, method); + } + distanceFrom(target, method) { + return get.distance(target, this, method); + } + hasSkill(skill, arg2, arg3, arg4) { + return game.expandSkills(this.getSkills(arg2, arg3, arg4)).contains(skill); + } + hasStockSkill(skill, arg1, arg2, arg3) { + return game.expandSkills(this.getStockSkills(arg1, arg2, arg3)).contains(skill); + } + isZhu2() { + var player = this, mode = get.mode(); + if (!this.isZhu) return false; + if (mode == "identity") { + if (_status.mode == "stratagem" && !this.identityShown) return false; + return true; + } + if (mode == "versus" && (_status.mode == "four" || _status.mode == "guandu")) return true; + return false; + } + hasZhuSkill(skill, player) { + if (!this.hasSkill(skill)) return false; + if (player) { + var mode = get.mode(); + if (mode == "identity" && _status.mode == "purple") { + if (this.identity.slice(0, 1) != player.identity.slice(0, 1)) return false; + } + if (mode == "versus" && (_status.mode == "four" || _status.mode == "guandu")) { + if (this.side != player.side) return false; + } + } + return true; + } + hasGlobalTag(tag, arg) { + var skills = lib.skill.global.slice(0); + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var info = lib.skill[skills[i]]; + if (info && info.ai) { + if (info.ai.skillTagFilter && info.ai[tag] && + info.ai.skillTagFilter(this, tag, arg) === false) continue; + if (typeof info.ai[tag] == "string") { + if (info.ai[tag] == arg) return true; + } + else if (info.ai[tag]) { + return true; + } + } + } + return false; + } + hasSkillTag(tag, hidden, arg, globalskill) { + var skills = this.getSkills(hidden); + if (globalskill) { + skills.addArray(lib.skill.global); + } + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var info = lib.skill[skills[i]]; + if (info && info.ai) { + if (info.ai.skillTagFilter && info.ai[tag] && + info.ai.skillTagFilter(this, tag, arg) === false) continue; + if (typeof info.ai[tag] == "string") { + if (info.ai[tag] == arg) return true; + } + else if (info.ai[tag]) { + return true; + } + } + } + return false; + } + hasJudge(name) { + if (name && typeof name == "object") { + name = name.viewAs || name.name; + } + var judges = this.getCards("j"); + for (var i = 0; i < judges.length; i++) { + if ((judges[i].viewAs || judges[i].name) == name) { + return true; + } + } + return false; + } + hasFriend() { + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isOut()) continue; + if (game.players[i] != this && get.attitude(game.players[i], this) > 0) { + return true; + } + } + return false; + } + hasUnknown(num) { + var mode = get.mode(); + if (typeof num != "number") { + num = 0; + } + if (mode == "identity" || mode == "guozhan") { + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].ai.shown == 0 && game.players[i] != this) { + num--; + if (num <= 0) { + return true; + } + } + } + } + return false; + } + isUnknown(player) { + var mode = get.mode(); + if (mode == "identity" || mode == "guozhan") { + if (this.ai.shown == 0 && this != player) { + return true; + } + } + return false; + } + hasWuxie(info) { + if (this.countCards("hs", "wuxie")) return true; + var skills = this.getSkills("invisible").concat(lib.skill.global); + game.expandSkills(skills); + for (var i = 0; i < skills.length; i++) { + var ifo = get.info(skills[i]); + if (ifo.hiddenWuxie && info) { + if (typeof ifo.hiddenWuxie == "function" && ifo.hiddenWuxie(this, info)) { + return true; + } + } + else if (ifo.viewAs && typeof ifo.viewAs != "function" && ifo.viewAs.name == "wuxie") { + if (!ifo.viewAsFilter || ifo.viewAsFilter(this)) { + return true; + } + } + else { + var hiddenCard = ifo.hiddenCard; + if (typeof hiddenCard == "function" && hiddenCard(this, "wuxie")) { + return true; + } + } + } + return false; + } + hasSha(respond, noauto) { + if (this.countCards("hs", "sha")) return true; + if (this.countCards("hs", "hufu")) return true; + if (!noauto && this.countCards("hs", "yuchanqian")) return true; + if (this.hasSkillTag("respondSha", true, respond ? "respond" : "use", true)) return true; + return this.hasUsableCard("sha"); + } + hasShan() { + if (this.countCards("hs", "shan")) return true; + if (this.countCards("hs", "hufu")) return true; + if (this.hasSkillTag("respondShan", true, null, true)) return true; + return this.hasUsableCard("shan"); + } + mayHaveSha(viewer, type, ignore) { + if ((this.hp > 2 || !this.isZhu && this.hp > 1) && this.hasSkillTag("respondSha", true, type, true)) return true; + if (get.itemtype(viewer) !== "player") viewer = _status.event.player; + let cards, selected = get.copy(ui.selected.cards); + if (get.itemtype(ignore) === "cards") selected.addArray(ignore); + else if (get.itemtype(ignore) === "card") selected.add(ignore); + /*if(this===viewer||get.itemtype(viewer)==="player"&&viewer.hasSkillTag("viewHandcard",null,this,true)) cards=this.getCards("h"); + else cards=this.getShownCards();*/ + if (this === viewer || get.itemtype(viewer) == "player") { + cards = this.getKnownCards(viewer); + } else { + cards = this.getShownCards(); + } + if (cards.some(card => { + if (selected.includes(card)) return false; + let name = get.name(card, this); + if (name == "sha" || name == "hufu" || name == "yuchanqian") { + if (type === "use") return lib.filter.cardEnabled(card, this); + if (type === "respond") return lib.filter.cardRespondable(card, this); + return true; + } + return false; + })) return true; + let hs = this.getCards("hs").filter(i => !cards.includes(i) && !selected.includes(i)).length; + if (hs === 0) return false; + return Math.pow(hs + (this.isPhaseUsing() ? 6 : 4), 2) > 100 * _status.event.getRand("mayHaveSha"); + } + mayHaveShan(viewer, type, ignore) { + if ((this.hp > 2 || !this.isZhu && this.hp > 1) && this.hasSkillTag("respondShan", true, type, true)) return true; + if (get.itemtype(viewer) !== "player") viewer = _status.event.player; + let cards, selected = get.copy(ui.selected.cards); + if (get.itemtype(ignore) === "cards") selected.addArray(ignore); + else if (get.itemtype(ignore) === "card") selected.add(ignore); + /*if(this===viewer||get.itemtype(viewer)==="player"&&viewer.hasSkillTag("viewHandcard",null,this,true)) cards=this.getCards("h"); + else cards=this.getShownCards();*/ + if (this === viewer || get.itemtype(viewer) == "player") { + cards = this.getKnownCards(viewer); + } else { + cards = this.getShownCards(); + } + if (cards.some(card => { + if (selected.includes(card)) return false; + let name = get.name(card, this); + if (name === "shan" || name === "hufu") { + if (type === "use") return lib.filter.cardEnabled(card, this, "forceEnable"); + if (type === "respond") return lib.filter.cardRespondable(card, this); + return true; + } + return false; + })) return true; + let hs = this.getCards("hs").filter(i => !cards.includes(i) && !selected.includes(i)).length; + if (hs === 0) return false; + return Math.pow(hs + (this.isPhaseUsing() ? 3 : 5), 2) > 100 * _status.event.getRand("mayHaveShan"); + } + hasCard(name, position) { + if (typeof name == "function") { + var hs = this.getCards(position); + for (var i = 0; i < hs.length; i++) { + if (name(hs[i])) return true; + } + } + else { + if (this.countCards(position, name)) return true; + } + return false; + } + getEquip(name) { + var es = this.getCards("e"); + if (typeof name == "object" && get.info(name)) { + name = get.info(name).subtype; + if (name) { + name = parseInt(name[5]); + } + } + else if (typeof name == "string" && name.startsWith("equip") && name.length == 6) { + name = parseInt(name[5]); + } + if (!name) { + return null; + } + for (var i = 0; i < es.length; i++) { + if (typeof name === "number") { + if (get.info(es[i]).subtype === "equip" + name) { + return es[i]; + } + } + else { + if (es[i].name === name) return es[i]; + var source = get.info(es[i]).source; + if (Array.isArray(source) && source.contains(name)) { + return es[i]; + } + } + } + return null; + } + getJudge(name) { + var judges = this.node.judges.childNodes; + for (var i = 0; i < judges.length; i++) { + if (judges[i].classList.contains("removing")) continue; + if ((judges[i].viewAs || judges[i].name) == name) { + return judges[i]; + } + } + return null; + } + $drawAuto(cards, target) { + if (this.isUnderControl(true, target)) { + this.$draw(cards); + } + else { + this.$draw(cards.length); + } + } + $draw(num, init, config) { + if (init !== false && init !== "nobroadcast") { + game.broadcast(function (player, num, init, config) { + player.$draw(num, init, config) + }, this, num, init, config); + } + var cards, node; + if (get.itemtype(num) == "cards") { + cards = num; + num = cards.length; + } + else if (get.itemtype(num) == "card") { + cards = [num]; + num = 1; + } + if (init !== false) { + if (cards) { + game.addVideo("drawCard", this, get.cardsInfo(cards)); + } + else { + game.addVideo("draw", this, num); + } + } + if (cards) { + cards = cards.slice(0); + node = cards.shift().copy("thrown", "drawingcard"); + } + else { + node = ui.create.div(".card.thrown.drawingcard"); + } + node.fixed = true; + node.hide(); + + var dx, dy; + if (game.chess) { + var rect = this.getBoundingClientRect(); + + if (rect.left <= 80) { + dx = -10; + if (rect.top <= 80) { + dy = -10; + } + else if (rect.top + rect.height + 80 >= ui.chessContainer.offsetHeight) { + dy = 10; + } + else { + dy = 0; + } + } + else if (rect.left + rect.width + 80 >= ui.chessContainer.offsetWidth) { + dx = 10; + if (rect.top <= 80) { + dy = -10; + } + else if (rect.top + rect.height + 80 >= ui.chessContainer.offsetHeight) { + dy = 10; + } + else { + dy = 0; + } + } + else if (rect.top <= 80) { + dx = 0; + dy = -10; + } + else if (rect.top + rect.height + 80 >= ui.chessContainer.offsetHeight) { + dx = 0; + dy = 10; + } + else { + dx = rect.left + this.offsetWidth / 2 - ui.arena.offsetWidth / 2; + dy = rect.top + this.offsetHeight / 2 - ui.arena.offsetHeight / 2; + } + + var coeff = 240 / Math.sqrt(dx * dx + dy * dy); + dx *= coeff; + dy *= coeff; + + node.style.left = (this.getLeft() + this.offsetWidth / 2 - 52 - dx) + "px"; + node.style.top = (this.getTop() + this.offsetHeight / 2 - 52 - dy) + "px"; + this.parentNode.appendChild(node); + } + else { + this.parentNode.appendChild(node); + node.style.left = "calc(50% - 52px)"; + node.style.top = "calc(50% - 52px)"; + + dx = this.getLeft() + this.offsetWidth / 2 - 52 - node.offsetLeft; + dy = this.getTop() + this.offsetHeight / 2 - 52 - node.offsetTop; + + if (get.is.mobileMe(this)) { + dx += get.cardOffset(); + if (ui.arena.classList.contains("oblongcard")) { + dy -= 16; + } + } + } + node.style.transitionDuration = "0.8s"; + ui.refresh(node); + if (typeof num == "number" && init !== false) { + config = { + total: num, + current: 1 + } + } + if (config && config.total > 1) { + var total = config.total, current = config.current; + var dxtotal; + if (total <= 5) { + dxtotal = Math.min(80, (total - 1) * 20); + dx += -dxtotal + 2 * dxtotal * (current - 1) / (total - 1) + } + else { + var total2 = Math.floor(total / 2); + if (current <= total2) { + total = total2; + dy -= 20; + } + else { + current -= total2; + total -= total2; + dy += 20; + } + dxtotal = Math.min(80, (total - 1) * 20); + dx += -dxtotal + 2 * dxtotal * (current - 1) / (total - 1) + } + config.current++; + } + if (node.style.transform && node.style.transform != "none" && node.style.transform.indexOf("translate") == -1) { + node.style.transform += " translate(" + dx + "px," + dy + "px)"; + } + else { + node.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + node.show(); + + node.listenTransition(function () { + node.style.transitionDuration = "0.5s"; + ui.refresh(node); + node.delete(); + }); + var that = this; + if (num && num > 1) { + if (config && config.total > 1) { + setTimeout(function () { + if (cards) { + that.$draw(cards, false, config) + } + else { + that.$draw(num - 1, false, config) + } + }, 50) + } + else { + setTimeout(function () { + if (cards) { + that.$draw(cards, false, config) + } + else { + that.$draw(num - 1, false, config) + } + }, 200); + } + } + } + $compareMultiple(card1, targets, cards) { + game.broadcast(function (player, card1, targets, cards) { + player.$compareMultiple(card1, targets, cards); + }, this, card1, targets, cards); + game.addVideo("compareMultiple", this, [get.cardInfo(card1), get.targetsInfo(targets), get.cardsInfo(cards)]); + var player = this; + var node1 = player.$throwxy2(card1, + "calc(50% - 52px)", "calc(50% + 10px)", "perspective(600px) rotateY(180deg)", true + ); + if (lib.config.cardback_style != "default") { + node1.style.transitionProperty = "none"; + ui.refresh(node1); + node1.classList.add("infohidden"); + ui.refresh(node1); + node1.style.transitionProperty = ""; + } + else { + node1.classList.add("infohidden"); + } + + node1.style.transform = "perspective(600px) rotateY(180deg) translateX(0)"; + var onEnd01 = function () { + //node1.removeEventListener("webkitTransitionEnd",onEnd01); + setTimeout(function () { + node1.style.transition = "all ease-in 0.3s"; + node1.style.transform = "perspective(600px) rotateY(270deg) translateX(52px)"; + var onEnd = function () { + node1.classList.remove("infohidden"); + node1.style.transition = "all 0s"; + ui.refresh(node1); + node1.style.transform = "perspective(600px) rotateY(-90deg) translateX(52px)"; + ui.refresh(node1); + node1.style.transition = ""; + ui.refresh(node1); + node1.style.transform = ""; + //node1.removeEventListener("webkitTransitionEnd",onEnd); + } + node1.listenTransition(onEnd); + }, 300); + }; + node1.listenTransition(onEnd01); + + setTimeout(function () { + var left0 = -targets.length * 52 - (targets.length - 1) * 8; + for (var i = 0; i < targets.length; i++) { + (function (target, card2, i) { + var left = left0 + i * 120; + var node2; + if (left < 0) { + node2 = target.$throwxy2(card2, + "calc(50% - " + (-left) + "px)", "calc(50% - 114px)", "perspective(600px) rotateY(180deg)", true + ); + } + else { + node2 = target.$throwxy2(card2, + "calc(50% + " + left + "px)", "calc(50% - 114px)", "perspective(600px) rotateY(180deg)", true + ); + } + if (lib.config.cardback_style != "default") { + node2.style.transitionProperty = "none"; + ui.refresh(node2); + node2.classList.add("infohidden"); + ui.refresh(node2); + node2.style.transitionProperty = ""; + } + else { + node2.classList.add("infohidden"); + } + node2.style.transform = "perspective(600px) rotateY(180deg) translateX(0)"; + var onEnd02 = function () { + //node2.removeEventListener("webkitTransitionEnd",onEnd02); + setTimeout(function () { + node2.style.transition = "all ease-in 0.3s"; + node2.style.transform = "perspective(600px) rotateY(270deg) translateX(52px)"; + var onEnd = function () { + node2.classList.remove("infohidden"); + node2.style.transition = "all 0s"; + ui.refresh(node2); + node2.style.transform = "perspective(600px) rotateY(-90deg) translateX(52px)"; + ui.refresh(node2); + node2.style.transition = ""; + ui.refresh(node2); + node2.style.transform = ""; + //node2.removeEventListener("webkitTransitionEnd",onEnd); + } + node2.listenTransition(onEnd); + }, 200); + }; + node2.listenTransition(onEnd02); + }(targets[i], cards[i], i)) + } + }, 200); + } + $compare(card1, target, card2) { + game.broadcast(function (player, target, card1, card2) { + player.$compare(card1, target, card2); + }, this, target, card1, card2); + game.addVideo("compare", this, [get.cardInfo(card1), target.dataset.position, get.cardInfo(card2)]); + var player = this; + var node1 = player.$throwxy2(card1, + "calc(50% - 114px)", "calc(50% - 52px)", "perspective(600px) rotateY(180deg)", true + ); + if (lib.config.cardback_style != "default") { + node1.style.transitionProperty = "none"; + ui.refresh(node1); + node1.classList.add("infohidden"); + ui.refresh(node1); + node1.style.transitionProperty = ""; + } + else { + node1.classList.add("infohidden"); + } + + node1.style.transform = "perspective(600px) rotateY(180deg) translateX(0)"; + var onEnd01 = function () { + //node1.removeEventListener("webkitTransitionEnd",onEnd01); + setTimeout(function () { + node1.style.transition = "all ease-in 0.3s"; + node1.style.transform = "perspective(600px) rotateY(270deg) translateX(52px)"; + var onEnd = function () { + node1.classList.remove("infohidden"); + node1.style.transition = "all 0s"; + ui.refresh(node1); + node1.style.transform = "perspective(600px) rotateY(-90deg) translateX(52px)"; + ui.refresh(node1); + node1.style.transition = ""; + ui.refresh(node1); + node1.style.transform = ""; + //node1.removeEventListener("webkitTransitionEnd",onEnd); + } + node1.listenTransition(onEnd); + }, 300); + }; + node1.listenTransition(onEnd01); + setTimeout(function () { + var node2 = target.$throwxy2(card2, + "calc(50% + 10px)", "calc(50% - 52px)", "perspective(600px) rotateY(180deg)", true + ); + if (lib.config.cardback_style != "default") { + node2.style.transitionProperty = "none"; + ui.refresh(node2); + node2.classList.add("infohidden"); + ui.refresh(node2); + node2.style.transitionProperty = ""; + } + else { + node2.classList.add("infohidden"); + } + node2.style.transform = "perspective(600px) rotateY(180deg) translateX(0)"; + var onEnd02 = function () { + //node2.removeEventListener("webkitTransitionEnd",onEnd02); + setTimeout(function () { + node2.style.transition = "all ease-in 0.3s"; + node2.style.transform = "perspective(600px) rotateY(270deg) translateX(52px)"; + var onEnd = function () { + node2.classList.remove("infohidden"); + node2.style.transition = "all 0s"; + ui.refresh(node2); + node2.style.transform = "perspective(600px) rotateY(-90deg) translateX(52px)"; + ui.refresh(node2); + node2.style.transition = ""; + ui.refresh(node2); + node2.style.transform = ""; + //node2.removeEventListener("webkitTransitionEnd",onEnd); + } + node2.listenTransition(onEnd); + }, 200); + }; + node2.listenTransition(onEnd02); + }, 200); + } + $throw(card, time, init, nosource) { + if (typeof card == "number") { + var tmp = card; + card = []; + while (tmp--) { + var cardx = ui.create.card(); + cardx.classList.add("infohidden"); + cardx.classList.add("infoflip"); + card.push(cardx); + } + } + if (init !== false) { + if (init !== "nobroadcast") { + game.broadcast(function (player, card, time, init, nosource) { + player.$throw(card, time, init, nosource); + }, this, card, time, init); + } + if (get.itemtype(card) != "cards") { + if (get.itemtype(card) == "card") { + card = [card]; + } + else { + return; + } + } + game.addVideo("throw", this, [get.cardsInfo(card), time, nosource]); + } + if (game.chess) { + this.chessFocus(); + } + if (get.itemtype(card) == "cards") { + var node; + for (var i = 0; i < card.length; i++) { + node = this.$throw(card[i], time, false, nosource); + } + return node; + } + else { + var node; + if (card == undefined || card.length == 0) return; + node = this.$throwordered(card.copy("thrown"), nosource); + if (time != undefined) { + node.fixed = true; + setTimeout(function () { node.delete() }, time); + } + lib.listenEnd(node); + return node; + } + } + $throwordered() { + return this.$throwordered2.apply(this, arguments); + // if(lib.config.low_performance){ + // return this.$throwordered2.apply(this,arguments); + // } + // else{ + // return this.$throwordered1.apply(this,arguments); + // } + } + $throwordered1(node, nosource) { + node.classList.add("thrown"); + node.hide(); + node.style.transitionProperty = "left,top,opacity,transform"; + for (var i = 0; i < ui.thrown.length; i++) { + if (ui.thrown[i].parentNode != ui.arena || + ui.thrown[i].classList.contains("removing")) { + ui.thrown.splice(i--, 1); + } + } + ui.thrown.push(node); + var uithrowns = ui.thrown.slice(0); + var tops; + if (game.chess) { + switch (Math.floor((ui.thrown.length - 1) / 4)) { + case 0: + tops = ["calc(50% - 82px)"]; + break; + case 1: + tops = ["calc(50% - 139px)", "calc(50% - 25px)"]; + break; + case 2: + tops = ["calc(50% - 196px)", "calc(50% - 82px)", "calc(50% + 32px)"]; + break; + default: + tops = ["calc(50% - 253px)", "calc(50% - 139px)", + "calc(50% - 25px)", "calc(50% + 89px)"]; + } + } + else { + switch (Math.floor((ui.thrown.length - 1) / 4)) { + case 0: + tops = ["calc(50% - 52px)"]; + break; + case 1: + tops = ["calc(50% - 109px)", "calc(50% + 5px)"]; + break; + case 2: + tops = ["calc(50% - 166px)", "calc(50% - 52px)", "calc(50% + 62px)"]; + break; + default: + tops = ["calc(50% - 223px)", "calc(50% - 109px)", + "calc(50% + 5px)", "calc(50% + 119px)"]; + } + } + while (uithrowns.length) { + var throwns = uithrowns.splice(0, Math.min(uithrowns.length, 4)); + switch (throwns.length) { + case 1: + throwns[0].style.left = "calc(50% - 52px)"; + break; + case 2: + throwns[0].style.left = "calc(50% - 109px)"; + throwns[1].style.left = "calc(50% + 5px)"; + break; + case 3: + throwns[0].style.left = "calc(50% - 166px)"; + throwns[1].style.left = "calc(50% - 52px)"; + throwns[2].style.left = "calc(50% + 62px)"; + break; + case 4: + throwns[0].style.left = "calc(50% - 223px)"; + throwns[1].style.left = "calc(50% - 109px)"; + throwns[2].style.left = "calc(50% + 5px)"; + throwns[3].style.left = "calc(50% + 119px)"; + break; + } + var top; + if (tops.length) { + top = tops.shift(); + } + else { + if (game.chess) { + top = "calc(50% - 82px)"; + } + else { + top = "calc(50% - 52px)"; + } + } + for (var i = 0; i < throwns.length; i++) { + throwns[i].style.top = top; + } + } + if (nosource) { + node.style.transform = "scale(0)"; + node.classList.add("center"); + } + else { + var parseCalc = function (str) { + var per = str.slice(str.indexOf("calc(") + 5, str.indexOf("%")); + var add = str.slice(str.indexOf("%") + 1, str.indexOf("px")).replace(/\s/g, ""); + return [parseInt(per), parseInt(add)]; + } + var nx = parseCalc(node.style.left); + var ny = parseCalc(node.style.top); + nx = nx[0] * ui.arena.offsetWidth / 100 + nx[1]; + ny = ny[0] * ui.arena.offsetHeight / 100 + ny[1]; + var dx, dy; + if (game.chess) { + var rect = this.getBoundingClientRect(); + dx = rect.left + this.offsetWidth / 2 - 52 - nx; + dy = rect.top + this.offsetHeight / 2 - 52 - ny; + } + else { + dx = this.getLeft() + this.offsetWidth / 2 - 52 - nx; + dy = this.getTop() + this.offsetHeight / 2 - 52 - ny; + if (get.is.mobileMe(this)) { + dx += get.cardOffset(); + if (ui.arena.classList.contains("oblongcard")) { + dy -= 16; + } + } + } + if (node.style.transform && node.style.transform != "none" && node.style.transform.indexOf("translate") == -1) { + node.style.transform += " translate(" + dx + "px," + dy + "px)"; + } + else { + node.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + } + ui.arena.appendChild(node); + ui.refresh(node); + node.style.transform = ""; + node.show(); + lib.listenEnd(node); + return node; + } + $throwordered2(node, nosource) { + node.classList.add("thrown"); + node.classList.add("center"); + node.hide(); + node.style.transitionProperty = "left,top,opacity,transform"; + + if (nosource) { + // node.style.transform="scale(0)"; + } + else { + var nx = [50, -52]; + var ny = [50, -52]; + nx = nx[0] * ui.arena.offsetWidth / 100 + nx[1]; + ny = ny[0] * ui.arena.offsetHeight / 100 + ny[1]; + var dx, dy; + if (game.chess) { + var rect = this.getBoundingClientRect(); + dx = rect.left + this.offsetWidth / 2 - 52 - nx; + dy = rect.top + this.offsetHeight / 2 - 52 - ny; + } + else { + dx = this.getLeft() + this.offsetWidth / 2 - 52 - nx; + dy = this.getTop() + this.offsetHeight / 2 - 52 - ny; + if (get.is.mobileMe(this)) { + dx += get.cardOffset(); + if (ui.arena.classList.contains("oblongcard")) { + dy -= 16; + } + } + } + if (node.style.transform && node.style.transform != "none" && node.style.transform.indexOf("translate") == -1) { + node.style.transform += " translate(" + dx + "px," + dy + "px)"; + } + else { + node.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + } + ui.arena.appendChild(node); + ui.refresh(node); + + for (var i = 0; i < ui.thrown.length; i++) { + if (ui.thrown[i].parentNode != ui.arena || + ui.thrown[i].classList.contains("removing")) { + ui.thrown.splice(i--, 1); + } + } + ui.thrown.push(node); + var uithrowns = ui.thrown.slice(0); + var tops; + switch (Math.floor((ui.thrown.length - 1) / 4)) { + case 0: + tops = [0]; + break; + case 1: + tops = [-57, 57]; + break; + case 2: + tops = [-114, 0, 114]; + break; + default: + tops = [-171, -57, 57, 171]; + } + while (uithrowns.length) { + var throwns = uithrowns.splice(0, Math.min(uithrowns.length, 4)); + switch (throwns.length) { + case 1: + throwns[0]._transthrown = "translate(0px,"; + break; + case 2: + throwns[0]._transthrown = "translate(-57px,"; + throwns[1]._transthrown = "translate(57px,"; + break; + case 3: + throwns[0]._transthrown = "translate(-114px,"; + throwns[1]._transthrown = "translate(0,"; + throwns[2]._transthrown = "translate(114px,"; + break; + case 4: + throwns[0]._transthrown = "translate(-171px,"; + throwns[1]._transthrown = "translate(-57px,"; + throwns[2]._transthrown = "translate(57px,"; + throwns[3]._transthrown = "translate(171px,"; + break; + } + var top; + if (tops.length) { + top = tops.shift(); + } + else { + top = 0; + } + if (game.chess) { + top -= 30; + } + for (var i = 0; i < throwns.length; i++) { + throwns[i].style.transform = throwns[i]._transthrown + top + "px)"; + delete throwns[i]._transthrown; + } + } + + node.show(); + lib.listenEnd(node); + return node; + } + $throwxy(card, left, top) { + var node = card.copy("thrown", "thrownhighlight"); + node.dataset.position = this.dataset.position; + node.hide(); + node.style.transitionProperty = "left,top,opacity"; + + ui.arena.appendChild(node); + ui.refresh(node); + node.show(); + node.style.left = left; + node.style.top = top; + lib.listenEnd(node); + return node; + } + $throwxy2(card, left, top, trans, flipx, flipy) { + if (game.chess) { + return this.$throwxy.apply(this, arguments); + } + var node = card.copy("thrown", "thrownhighlight"); + node.style.left = left; + node.style.top = top; + node.hide(); + // node.style.transitionProperty="left,top,opacity,transform"; + + var parseCalc = function (str) { + var per = str.slice(str.indexOf("calc(") + 5, str.indexOf("%")); + var add = str.slice(str.indexOf("%") + 1, str.indexOf("px")).replace(/\s/g, ""); + return [parseInt(per), parseInt(add)]; + } + var nx = parseCalc(node.style.left); + var ny = parseCalc(node.style.top); + nx = nx[0] * ui.arena.offsetWidth / 100 + nx[1]; + ny = ny[0] * ui.arena.offsetHeight / 100 + ny[1]; + var dx = this.getLeft() + this.offsetWidth / 2 - 52 - nx; + var dy = this.getTop() + this.offsetHeight / 2 - 52 - ny; + if (flipx) dx = -dx; + if (flipy) dy = -dy; + if (trans) { + node.style.transform = trans + " translate(" + dx + "px," + dy + "px)"; + } + else { + node.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + + ui.arena.appendChild(node); + ui.refresh(node); + node.show(); + // node.style.transform=trans||""; + lib.listenEnd(node); + return node; + } + throwDice(num) { + if (typeof num != "number") { + num = get.rand(6) + 1; + _status.event.num = num; + } + if (!game.online) { + game.pause(); + } + game.broadcastAll(function (num) { + var diceContainer = ui.create.div(".fullsize.dice-container", ui.window); + ui.window.classList.add("dicepaused"); + var dice = ui.create.div(".dice"); + var side; + + side = ui.create.div(".side.front", dice); + ui.create.div(".dot.center", side); + ui.create.div(".side.front.inner", dice); + + side = ui.create.div(".side.top", dice); + ui.create.div(".dot.dtop.dleft", side); + ui.create.div(".dot.dbottom.dright", side); + ui.create.div(".side.top.inner", dice); + + side = ui.create.div(".side.right", dice); + ui.create.div(".dot.dtop.dleft", side); + ui.create.div(".dot.center", side); + ui.create.div(".dot.dbottom.dright", side); + ui.create.div(".side.right.inner", dice); + + side = ui.create.div(".side.left", dice); + ui.create.div(".dot.dtop.dleft", side); + ui.create.div(".dot.dtop.dright", side); + ui.create.div(".dot.dbottom.dleft", side); + ui.create.div(".dot.dbottom.dright", side); + ui.create.div(".side.left.inner", dice); + + side = ui.create.div(".side.bottom", dice); + ui.create.div(".dot.center", side); + ui.create.div(".dot.dtop.dleft", side); + ui.create.div(".dot.dtop.dright", side); + ui.create.div(".dot.dbottom.dleft", side); + ui.create.div(".dot.dbottom.dright", side); + ui.create.div(".side.bottom.inner", dice); + + side = ui.create.div(".side.back", dice); + ui.create.div(".dot.dtop.dleft", side); + ui.create.div(".dot.dtop.dright", side); + ui.create.div(".dot.dbottom.dleft", side); + ui.create.div(".dot.dbottom.dright", side); + ui.create.div(".dot.center dleft", side); + ui.create.div(".dot.center dright", side); + ui.create.div(".side.back.inner", dice); + + ui.create.div(".side.cover.x", dice); + ui.create.div(".side.cover.y", dice); + ui.create.div(".side.cover.z", dice); + + var map = { + 1: [75, 0, 45], + 2: [-15, 45, 0], + 3: [165, -45, 90], + 4: [345, -45, 90], + 5: [345, -45, 180], + 6: [255, 0, 135] + }; + dice.roll = function (deg) { + if (typeof deg == "number") { + dice.current[0] += deg; + deg = dice.current; + } + deg = deg.slice(0); + dice.current = deg; + this.style.transform = "rotateX(" + deg[0] + "deg) rotateY(" + deg[1] + "deg) rotateZ(" + deg[2] + "deg)"; + }; + dice.roll(map[num]); + diceContainer.appendChild(dice); + ui.refresh(dice); + dice.roll(1025); + + dice.addEventListener("webkitTransitionEnd", function () { + if (!dice.over) { + dice.style.transition = "transform 0.8s ease"; + dice.roll(-20); + dice.over = true; + } + else if (!dice.resumed) { + setTimeout(function () { + diceContainer.delete(); + ui.window.classList.remove("dicepaused"); + }, 300); + if (!game.online) { + setTimeout(game.resume, 800); + } + dice.resumed = true; + } + }); + }, num); + } + $giveAuto(card, player) { + if (Array.isArray(card) && card.length == 0) return; + var args = Array.from(arguments); + if (_status.connectMode || (!this.isUnderControl(true) && !player.isUnderControl(true))) { + if (Array.isArray(card)) { + card = card.length; + } + else { + card = 1; + } + args[0] = card; + } + return this.$give.apply(this, args); + } + $give(card, player, log, init) { + if (init !== false) { + game.broadcast(function (source, card, player, init) { + source.$give(card, player, false, init); + }, this, card, player, init); + if (typeof card == "number" && card >= 0) { + game.addVideo("give", this, [card, player.dataset.position]); + } + else { + if (get.itemtype(card) == "card") { + card = [card]; + } + if (get.itemtype(card) == "cards") { + game.addVideo("giveCard", this, [get.cardsInfo(card), player.dataset.position]); + } + } + } + if (get.itemtype(card) == "cards") { + if (log != false && !_status.video) { + game.log(player, "从", this, "获得了", card); + } + if (this.$givemod) { + this.$givemod(card, player); + } + else { + for (var i = 0; i < card.length; i++) { + this.$give(card[i], player, false, false); + } + } + } + else if (typeof card == "number" && card >= 0) { + if (log != false && !_status.video) { + game.log(player, "从", this, "获得了" + get.cnNumber(card) + "张牌"); + } + if (this.$givemod) { + this.$givemod(card, player); + } + else { + while (card--) this.$give("", player, false, false); + } + } + else { + if (log != false && !_status.video) { + if (get.itemtype(card) == "card" && log != false) { + game.log(player, "从", this, "获得了", card); + } + else { + game.log(player, "从", this, "获得了一张牌"); + } + } + if (this.$givemod) { + this.$givemod(card, player); + } + else { + var node; + if (get.itemtype(card) == "card") { + node = card.copy("card", "thrown", false); + } + else { + node = ui.create.div(".card.thrown"); + } + // node.dataset.position=this.dataset.position; + node.fixed = true; + this.$throwordered(node); + // lib.listenEnd(node); + // node.hide(); + // node.style.transitionProperty="left,top,opacity"; + // + // node.style.transform="rotate("+(Math.random()*16-8)+"deg)"; + // + // ui.arena.appendChild(node); + // ui.refresh(node); + // node.show(); + // node.style.left="calc(50% - 52px "+((Math.random()-0.5<0)?"+":"-")+" "+Math.random()*100+"px)"; + // node.style.top="calc(50% - 52px "+((Math.random()-0.5<0)?"+":"-")+" "+Math.random()*80+"px)"; + + node.listenTransition(function () { + var dx = player.getLeft() + player.offsetWidth / 2 - 52 - node.offsetLeft; + var dy = player.getTop() + player.offsetHeight / 2 - 52 - node.offsetTop; + if (node.style.transform && node.style.transform != "none" && node.style.transform.indexOf("translate") == -1) { + node.style.transform += " translate(" + dx + "px," + dy + "px)"; + } + else { + node.style.transform = "translate(" + dx + "px," + dy + "px)"; + } + + node.delete(); + }); + // setTimeout(function(){ + // // node.removeAttribute("style"); + // // node.dataset.position=player.dataset.position; + // var dx=player.offsetLeft+player.offsetWidth/2-52-node.offsetLeft; + // var dy=player.offsetTop+player.offsetHeight/2-52-node.offsetTop; + // if(node.style.transform&&node.style.transform!="none"&&node.style.transform.indexOf("translate")==-1){ + // node.style.transform+=" translate("+dx+"px,"+dy+"px)"; + // } + // else{ + // node.style.transform="translate("+dx+"px,"+dy+"px)"; + // } + // + // node.delete(); + // },700); + } + } + } + $equip(card) { + game.broadcast(function (player, card) { + player.$equip(card); + }, this, card); + card.fix(); + card.style.transform = ""; + card.classList.remove("drawinghidden"); + delete card._transform; + var player = this; + var equipNum = get.equipNum(card); + var equipped = false; + for (var i = 0; i < player.node.equips.childNodes.length; i++) { + if (get.equipNum(player.node.equips.childNodes[i]) >= equipNum) { + player.node.equips.insertBefore(card, player.node.equips.childNodes[i]); + equipped = true; + break; + } + } + if (!equipped) { + player.node.equips.appendChild(card); + if (_status.discarded) { + _status.discarded.remove(card); + } + } + var info = get.info(card); + if (info.skills) { + for (var i = 0; i < info.skills.length; i++) { + player.addSkillTrigger(info.skills[i]); + } + } + return player; + } + $gain(card, log, init) { + if (init !== false) { + game.broadcast(function (player, card, init) { + player.$gain(card, false, init); + }, this, card, init); + if (typeof card == "number" && card >= 0) { + game.addVideo("gain", this, card); + } + else { + if (get.itemtype(card) == "card") { + card = [card]; + } + if (get.itemtype(card) == "cards") { + game.addVideo("gainCard", this, get.cardsInfo(card)); + } + else { + game.addVideo("gain", this, 1); + } + } + } + if (get.itemtype(card) == "cards") { + if (log != false && !_status.video) { + game.log(this, "获得了", card); + } + if (this.$gainmod) { + this.$gainmod(card); + } + else { + for (var i = 0; i < card.length; i++) { + this.$gain(card[i], false, false); + } + } + } + else if (typeof card == "number" && card > 1) { + if (log != false && !_status.video) { + game.log(this, "获得了" + get.cnNumber(card) + "张牌"); + } + if (this.$gainmod) { + this.$gainmod(card); + } + else { + for (var i = 0; i < card; i++) { + this.$gain(1, false, false); + } + } + } + else { + if (get.itemtype(card) == "card" && log != false && !_status.video) { + game.log(this, "获得了", card); + } + if (this.$gainmod) { + this.$gainmod(card); + } + else { + var node; + if (get.itemtype(card) == "card") { + // node=this.$throwordered(card.copy(),true); + node = card.copy("thrown", false); + } + else { + // node=this.$throwordered(ui.create.div(".card.thrown"),true); + node = ui.create.div(".card.thrown"); + node.moveTo = lib.element.Card.prototype.moveTo; + node.moveDelete = lib.element.Card.prototype.moveDelete; + } + node.fixed = true; + node.style.left = "calc(50% - 52px " + ((Math.random() - 0.5 < 0) ? "+" : "-") + " " + Math.random() * 100 + "px)"; + node.style.top = "calc(50% - 52px " + ((Math.random() - 0.5 < 0) ? "+" : "-") + " " + Math.random() * 100 + "px)"; + node.style.transform = "scale(0)"; + node.hide(); + ui.arena.appendChild(node); + ui.refresh(node); + node.show(); + node.style.transform = ""; + + lib.listenEnd(node); + var player = this; + setTimeout(function () { + node.moveDelete(player); + }, 700); + } + } + } + $gain2(cards, log) { + if (log === true) { + game.log(this, "获得了", cards); + } + game.broadcast(function (player, cards) { + player.$gain2(cards); + }, this, cards); + if (get.itemtype(cards) == "card") cards = [cards]; + else if (get.itemtype(cards) != "cards") return; + var list = [], list2 = []; + for (var i = 0; i < cards.length; i++) { + if (cards[i].clone && + (cards[i].clone.parentNode == this.parentNode || + cards[i].clone.parentNode == ui.arena) && + parseFloat(getComputedStyle(cards[i].clone).opacity) > 0.3) { + cards[i].clone.moveDelete(this); + list2.push(cards[i].clone); + } + else { + list.push(cards[i]); + } + } + if (list2.length) { + game.addVideo("gain2", this, get.cardsInfo(list2)); + } + if (list.length) { + this.$draw(list, "nobroadcast"); + return true; + } + } + $skill(name, type, color, avatar) { + if (typeof type != "string") type = "legend"; + if (!avatar) { + this.playerfocus(1500); + game.delay(2); + } + else { + game.addVideo("playerfocus2"); + game.broadcastAll(function () { + ui.arena.classList.add("playerfocus"); + setTimeout(function () { + ui.arena.classList.remove("playerfocus"); + }, 1800) + }); + game.delay(3); + } + var that = this; + setTimeout(function () { + game.broadcastAll(function (that, type, name, color, avatar) { + if (lib.config.animation && !lib.config.low_performance) { + if (game.chess) { + that["$" + type + "2"](1200); + } + else { + that["$" + type](1200); + } + } + if (name) { + that.$fullscreenpop(name, color, avatar); + } + }, that, type, name, color, avatar); + }, avatar ? 0 : 300); + } + $fire() { + game.addVideo("flame", this, "fire"); + var left, top; + if (game.chess) { + var rect = this.getBoundingClientRect(); + left = rect.left; + top = rect.top; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 20, 700, "fire"); + } + $thunder() { + game.addVideo("flame", this, "thunder"); + var left, top; + if (game.chess) { + var rect = this.getBoundingClientRect(); + left = rect.left; + top = rect.top; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "thunder"); + } + $rare2() { + game.addVideo("flame", this, "rare2"); + var rect = this.getBoundingClientRect(); + var left = rect.left; + var top = rect.top + 15; + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "rare"); + } + $epic2() { + game.addVideo("flame", this, "epic2"); + var rect = this.getBoundingClientRect(); + var left = rect.left; + var top = rect.top + 15; + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "epic"); + } + $legend2() { + game.addVideo("flame", this, "legend2"); + var rect = this.getBoundingClientRect(); + var left = rect.left; + var top = rect.top + 15; + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "legend"); + } + $rare(time) { + time = time || 700; + game.addVideo("flame", this, "rare"); + var left, top; + if (game.chess) { + left = this.getLeft() - ui.arena.offsetLeft; + top = this.getTop() - ui.arena.offsetTop; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + if (this.classList.contains("minskin")) { + top += 15; + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, time, "rare"); + } + $epic(time) { + time = time || 700; + game.addVideo("flame", this, "epic"); + var left, top; + if (game.chess) { + left = this.getLeft() - ui.arena.offsetLeft; + top = this.getTop() - ui.arena.offsetTop; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + if (this.classList.contains("minskin")) { + top += 15; + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, time, "epic"); + } + $legend(time) { + time = time || 700; + game.addVideo("flame", this, "legend"); + var left, top; + if (game.chess) { + left = this.getLeft() - ui.arena.offsetLeft; + top = this.getTop() - ui.arena.offsetTop; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + if (this.classList.contains("minskin")) { + top += 15; + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, time, "legend"); + } + $coin() { + game.broadcast(function (player) { + if (!lib.config.low_performance) { + player.$coin(); + } + }, this); + game.addVideo("flame", this, "coin"); + var left = this.getLeft() - ui.arena.offsetLeft; + var top = this.getTop() - ui.arena.offsetTop; + if (this.classList.contains("minskin")) { + top += 15; + } + top -= 25; + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "coin"); + } + $dust() { + game.broadcast(function (player) { + if (!lib.config.low_performance) { + player.$dust(); + } + }, this); + game.addVideo("flame", this, "dust"); + var left = this.getLeft() - ui.arena.offsetLeft; + var top = this.getTop() - ui.arena.offsetTop; + if (this.classList.contains("minskin")) { + top += 15; + } + top -= 25; + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "dust"); + } + $recover() { + game.addVideo("flame", this, "recover"); + var left, top; + if (game.chess) { + var rect = this.getBoundingClientRect(); + left = rect.left; + top = rect.top; + } + else { + left = this.getLeft(); + top = this.getTop(); + } + game.animate.flame(left + this.offsetWidth / 2, + top + this.offsetHeight - 30, 700, "recover"); + } + $fullscreenpop(str, nature, avatar, broadcast) { + if (broadcast !== false) game.broadcast(function (player, str, nature, avatar) { + player.$fullscreenpop(str, nature, avatar); + }, this, str, nature, avatar); + game.addVideo("fullscreenpop", this, [str, nature, avatar]); + var node = ui.create.div(".damage"); + if (avatar && this.node) { + if (avatar == "vice") { + if (lib.character[this.name2]) { + avatar = this.node.avatar2; + } + } + else { + if (lib.character[this.name]) { + avatar = this.node.avatar; + } + } + if (!get.is.div(avatar)) { + avatar = false; + } + } + else { + avatar = false; + } + if (avatar) { + node.classList.add("fullscreenavatar"); + ui.create.div("", ui.create.div(node)); + // ui.create.div("",str.split("").join("
"),ui.create.div(".text.textbg",node)); + ui.create.div("", "
" + str.split("").join("

") + "
", ui.create.div(".text", node)); + node.firstChild.firstChild.style.backgroundImage = avatar.style.backgroundImage; + node.dataset.nature = nature || "unknown"; + var num = 0; + var nodes = node.lastChild.firstChild.querySelectorAll("div"); + var interval = setInterval(function () { + if (num < nodes.length) { + nodes[num].classList.add("flashtext"); + num++; + } + else { + clearInterval(interval); + } + }, 100); + } + else { + avatar = false; + node.innerHTML = str; + node.dataset.nature = nature || "soil"; + } + if (avatar) { + var rect1 = ui.window.getBoundingClientRect(); + var rect2 = this.getBoundingClientRect(); + var dx = Math.round(2 * rect2.left + rect2.width - rect1.width); + var dy = Math.round(2 * rect2.top + rect2.height - rect1.height); + node.style.transform = "scale(0.5) translate(" + dx + "px," + dy + "px)"; + } + ui.window.appendChild(node); + ui.refresh(node); + if (avatar) { + node.style.transform = "scale(1)"; + node.style.opacity = 1; + } + else { + node.classList.add("damageadded"); + } + setTimeout(function () { + node.delete(); + node.style.transform = "scale(1.5)" + }, avatar ? 1600 : 1000); + } + $damagepop(num, nature, font, nobroadcast) { + if (typeof num == "number" || typeof num == "string") { + game.addVideo("damagepop", this, [num, nature, font]); + if (nobroadcast !== false) game.broadcast(function (player, num, nature, font) { + player.$damagepop(num, nature, font); + }, this, num, nature, font); + var node = ui.create.div(".damage"); + if (font) { + node.classList.add("normal-font"); + } + if (typeof num == "number" && num > 0) { + if (num == Infinity) num = "+∞" + else num = "+" + num; + } + else if (num == -Infinity) num = "-∞"; + node.innerHTML = num; + this.damagepopups.push(node); + node.dataset.nature = nature || "soil"; + if (this.damagepopups.length == 1) { + this.$damagepop(); + } + } + else if (this.damagepopups.length) { + var node = this.damagepopups[0]; + this.appendChild(node); + ui.refresh(node); + node.classList.add("damageadded"); + node.listenTransition(function () { + setTimeout(function () { + node.delete(); + }, 200); + }); + // setTimeout(function(){ + // node.delete(); + // },500); + var that = this; + setTimeout(function () { + that.damagepopups.shift(); + that.$damagepop(); + }, 500); + } + } + $damage(source) { + if (get.itemtype(source) == "player") { + game.addVideo("damage", this, source.dataset.position); + } + else { + game.addVideo("damage", this); + } + game.broadcast(function (player, source) { + player.$damage(source); + }, this, source); + if (source && source != this && lib.config.damage_shake) { + var left, top; + if (source.getTop() == this.getTop()) { + left = 20; + top = 0; + } + else { + var ratio = (source.getLeft() - this.getLeft()) / (source.getTop() - this.getTop()); + left = Math.abs(20 * ratio / Math.sqrt(1 + ratio * ratio)); + top = Math.abs(20 / Math.sqrt(1 + ratio * ratio)); + } + if (source.getLeft() - this.getLeft() > 0) left = -left; + if (source.getTop() - this.getTop() > 0) top = -top; + if (get.is.mobileMe(this)) { + if (this.classList.contains("linked")) { + this.node.avatar.style.transform = "translate(" + left + "px," + top + "px) rotate(-90deg)"; + this.node.avatar2.style.transform = "translate(" + left + "px," + top + "px) rotate(-90deg)"; + } + else { + this.node.avatar.style.transform = "translate(" + left + "px," + top + "px)"; + this.node.avatar2.style.transform = "translate(" + left + "px," + top + "px)"; + } + } + else if (this.classList.contains("linked") && get.is.newLayout()) { + this.style.transform = "translate(" + left + "px," + top + "px) rotate(-90deg)"; + } + else if (this._chesstransform) { + this.style.transform = "translate(" + (left + this._chesstransform[0]) + "px," + (top + this._chesstransform[1]) + "px)"; + } + else { + this.style.transform = "translate(" + left + "px," + top + "px)"; + } + } + else { + var zoom1 = 0.9, zoom2 = 0.95; + if (arguments[1] == "phase") { + zoom1 = 1.05; + zoom2 = 1.05; + } + if (get.is.mobileMe(this)) { + if (this.classList.contains("linked")) { + this.node.avatar.style.transform = "scale(" + zoom1 + ") rotate(-90deg)"; + this.node.avatar2.style.transform = "scale(" + zoom1 + ") rotate(-90deg)"; + } + else { + this.node.avatar.style.transform = "scale(" + zoom1 + ")"; + this.node.avatar2.style.transform = "scale(" + zoom1 + ")"; + } + } + else if (this.classList.contains("linked") && get.is.newLayout()) { + this.style.transform = "scale(" + zoom2 + ") rotate(-90deg)"; + } + else if (game.chess && this._chesstransform) { + this.style.transform = "translate(" + this._chesstransform[0] + "px," + this._chesstransform[1] + "px) scale(" + zoom2 + ")"; + } + else { + this.style.transform = "scale(" + zoom2 + ")"; + } + } + this.queue(); + } + $die() { + game.addVideo("die", this); + game.broadcast(function (player) { + player.$die(); + }, this); + if (lib.config.die_move != "off") { + this.$dieflip(lib.config.die_move); + } + if (this.$dieAfter) { + this.$dieAfter(); + } + } + $dieflip(type) { + var top0 = ui.window.offsetHeight / 2; + var left0 = ui.window.offsetWidth / 2; + var ratio = (left0 - this.getLeft()) / (top0 - this.getTop()); + var left = Math.abs(50 * ratio / Math.sqrt(1 + ratio * ratio)); + var top = Math.abs(50 / Math.sqrt(1 + ratio * ratio)); + if (left0 - this.getLeft() > 0) left = -left; + if (top0 - this.getTop() > 0) top = -top; + if (get.is.mobileMe(this)) { + left = -Math.random() * 5 - 10; + top = Math.random() * 5 + 10; + } + if (this._chesstransform) { + left += this._chesstransform[0]; + top += this._chesstransform[1]; + } + var transform = "translate(" + left + "px," + top + "px) " + + "rotate(" + (Math.random() * 20 - 10) + "deg) "; + if (type == "flip") { + if (game.layout == "long" || game.layout == "long2") { + transform += "rotateY(180deg)"; + } + else { + transform += ((Math.random() - 0.5 < 0) ? "rotateX(180deg)" : "rotateY(180deg)"); + } + } + if (get.is.mobileMe(this)) { + this.node.avatar.style.transform = transform; + this.node.avatar2.style.transform = transform; + this.style.transform = ""; + } + else { + this.node.avatar.style.transform = ""; + this.node.avatar2.style.transform = ""; + this.style.transform = transform; + } + this.queue(false); + } + $phaseJudge(card) { + game.addVideo("phaseJudge", this, get.cardInfo(card)); + var player = this; + var clone = player.$throw(card); + if (lib.config.low_performance && card && card.clone) { + var waitingForTransition = get.time(); + _status.waitingForTransition = waitingForTransition; + card.clone.listenTransition(function () { + if (_status.waitingForTransition == waitingForTransition && _status.paused) { + game.resume(); + } + }); + game.pause(); + } + else { + game.delay(); + } + } +} diff --git a/noname/library/element/v-card.js b/noname/library/element/v-card.js new file mode 100644 index 000000000..e202c02b8 --- /dev/null +++ b/noname/library/element/v-card.js @@ -0,0 +1,107 @@ +export class VCard { + /** + * @param {any} [suitOrCard] + * @param {number | Card[]} [numberOrCards] + * @param {string} [name] + * @param {string} [nature] + */ + constructor(suitOrCard, numberOrCards, name, nature) { + if (Array.isArray(suitOrCard)) { + /** + * @type {string} + */ + this.suit = suitOrCard[0]; + /** + * @type {number} + */ + this.number = suitOrCard[1]; + /** + * @type {string} + */ + this.name = suitOrCard[2]; + /** + * @type {string} + */ + this.nature = suitOrCard[3]; + } + else if (get.itemtype(suitOrCard) == "card") { + this.name = get.name(suitOrCard); + this.suit = get.suit(suitOrCard); + this.color = get.color(suitOrCard); + this.number = get.number(suitOrCard); + this.nature = get.nature(suitOrCard); + this.isCard = true; + this.cardid = suitOrCard.cardid; + this.wunature = suitOrCard.wunature; + /** + * @type {Record} + */ + this.storage = get.copy(suitOrCard.storage); + if (Array.isArray(numberOrCards)) this.cards = numberOrCards.slice(); + else this.cards = [suitOrCard]; + const info = get.info(this, false); + if (info) { + const autoViewAs = info.autoViewAs; + if (typeof autoViewAs == "string") this.name = autoViewAs; + } + } + else if (suitOrCard && typeof suitOrCard != "string") { + Object.keys(suitOrCard).forEach(key => { + const propertyDescriptor = Object.getOwnPropertyDescriptor(suitOrCard, key), value = propertyDescriptor.value; + if (Array.isArray(value)) this[key] = value.slice(); + else Object.defineProperty(this, key, propertyDescriptor); + }); + if (Array.isArray(numberOrCards)) { + const noCards = !this.cards; + /** + * @type {Card[]} + */ + this.cards = numberOrCards.slice(); + if (noCards) { + if (!lib.suits.includes(this.suit)) this.suit = get.suit(this); + if (!Object.keys(lib.color).includes(this.color)) this.color = get.color(this); + if (typeof this.number != "number") this.number = get.number(this); + if (!this.nature) this.nature = get.nature(this); + } + } + const info = get.info(this, false); + if (info) { + const autoViewAs = info.autoViewAs; + if (typeof autoViewAs == "string") this.name = autoViewAs; + } + } + if (typeof suitOrCard == "string") this.suit = suitOrCard; + if (typeof numberOrCards == "number") this.number = numberOrCards; + if (typeof name == "string") this.name = name; + if (typeof nature == "string") this.nature = nature; + if (!this.storage) this.storage = {}; + if (!this.cards) this.cards = []; + } + sameSuitAs(card) { + return get.suit(this) == get.suit(card); + } + differentSuitFrom(card) { + return get.suit(this) != get.suit(card); + } + sameNumberAs(card) { + return get.number(this) == get.number(card); + } + differentNumberFrom(card) { + return get.number(this) != get.number(card); + } + sameNameAs(card) { + return get.name(this) == get.name(card); + } + differentNameFrom(card) { + return get.name(this) != get.name(card); + } + /** + * @param {Player} player + */ + hasNature(nature, player) { + const natures = get.natureList(this, player); + if (!nature) return natures.length > 0; + if (nature == "linked") return natures.some(n => lib.linked.includes(n)); + return get.is.sameNature(natures, nature); + } +} diff --git a/noname/library/element/ws.js b/noname/library/element/ws.js new file mode 100644 index 000000000..880e55d27 --- /dev/null +++ b/noname/library/element/ws.js @@ -0,0 +1,62 @@ +export class WS { + static onopen() { + if (_status.connectCallback) { + _status.connectCallback(true); + delete _status.connectCallback; + } + } + + static onmessage(messageevent) { + if (messageevent.data == "heartbeat") { + this.send("heartbeat"); + return; + } + var message; + try { + message = JSON.parse(messageevent.data); + if (!Array.isArray(message) || + typeof lib.message.client[message[0]] !== "function") { + throw ("err"); + } + for (var i = 1; i < message.length; i++) { + message[i] = get.parsedResult(message[i]); + } + } + catch (e) { + console.log(e); + console.log("invalid message: " + messageevent.data); + return; + } + lib.message.client[message.shift()].apply(null, message); + } + + static onerror(e) { + if (this._nocallback) return; + if (_status.connectCallback) { + _status.connectCallback(false); + delete _status.connectCallback; + } + else { + alert("连接失败"); + } + } + + static onclose() { + if (this._nocallback) return; + if (_status.connectCallback) { + _status.connectCallback(false); + delete _status.connectCallback; + } + if (game.online || game.onlineroom) { + if ((game.servermode || game.onlinehall) && _status.over) { + void 0; + } + else { + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + } + } + game.online = false; + game.ws = null; + } +} \ No newline at end of file diff --git a/noname/library/emotion-list.d.ts b/noname/library/emotion-list.d.ts new file mode 100644 index 000000000..e0c360a10 --- /dev/null +++ b/noname/library/emotion-list.d.ts @@ -0,0 +1,4 @@ +interface EmotionList extends Record { +} + +export const emotionList: EmotionList; diff --git a/noname/library/emotion-list.js b/noname/library/emotion-list.js new file mode 100644 index 000000000..cc82d5f14 --- /dev/null +++ b/noname/library/emotion-list.js @@ -0,0 +1,10 @@ +export const emotionList = { + xiaowu_emotion: 14, + xiaokuo_emotion: 8, + shibing_emotion: 15, + guojia_emotion: 20, + zhenji_emotion: 20, + xiaosha_emotion: 20, + xiaotao_emotion: 20, + xiaojiu_emotion: 20 +}; diff --git a/noname/library/extension-menu.js b/noname/library/extension-menu.js new file mode 100644 index 000000000..7bd3dbc75 --- /dev/null +++ b/noname/library/extension-menu.js @@ -0,0 +1,11 @@ +import { BOSS } from "./extension-menu/boss.js"; +import { CARD_PILE } from "./extension-menu/card-pile.js"; +import { COIN } from "./extension-menu/coin.js"; +import { WUXING } from "./extension-menu/wuxing.js"; + +export const extensionMenu = { + cardpile: CARD_PILE, + boss: BOSS, + wuxing: WUXING, + coin: COIN +}; diff --git a/noname/library/extension-menu/boss.js b/noname/library/extension-menu/boss.js new file mode 100644 index 000000000..c5ede908f --- /dev/null +++ b/noname/library/extension-menu/boss.js @@ -0,0 +1,11 @@ +import { ENABLE_AI } from "./boss/enable-ai.js"; +import { ENABLE } from "./boss/enable.js"; +import { HIDE } from "./boss/hide.js"; +import { INTRODUCTION } from "./boss/introduction.js"; + +export const BOSS = { + enable: ENABLE, + intro: INTRODUCTION, + enableai: ENABLE_AI, + hide: HIDE +}; diff --git a/noname/library/extension-menu/boss/enable-ai.js b/noname/library/extension-menu/boss/enable-ai.js new file mode 100644 index 000000000..9ff95df58 --- /dev/null +++ b/noname/library/extension-menu/boss/enable-ai.js @@ -0,0 +1,4 @@ +export const ENABLE_AI = { + name: "随机选将可用", + init: false +}; diff --git a/noname/library/extension-menu/boss/enable.js b/noname/library/extension-menu/boss/enable.js new file mode 100644 index 000000000..7c4bfb19b --- /dev/null +++ b/noname/library/extension-menu/boss/enable.js @@ -0,0 +1,37 @@ +export const ENABLE = { + name: "开启", + init: false, + restart: true, + onswitch(bool) { + if (bool) { + var storage = { boss: {}, versus: {}, translate: {} }; + var loadversus = function () { + game.loadModeAsync("versus", function (mode) { + for (var i in mode.translate) { + storage.translate[i] = mode.translate[i]; + } + for (var i in mode.jiangeboss) { + if (mode.jiangeboss[i][4].contains("bossallowed")) { + storage.versus[i] = mode.jiangeboss[i]; + } + } + localStorage.setItem("boss_storage_playpackconfig", JSON.stringify(storage)); + }); + }; + game.loadModeAsync("boss", function (mode) { + for (var i in mode.translate) { + storage.translate[i] = mode.translate[i]; + } + for (var i in mode.characterPack.mode_boss) { + if (mode.characterPack.mode_boss[i][4].contains("bossallowed")) { + storage.boss[i] = mode.characterPack.mode_boss[i]; + } + } + loadversus(); + }); + } + else { + localStorage.removeItem("boss_storage_playpackconfig"); + } + } +}; diff --git a/noname/library/extension-menu/boss/hide.js b/noname/library/extension-menu/boss/hide.js new file mode 100644 index 000000000..07d0af97a --- /dev/null +++ b/noname/library/extension-menu/boss/hide.js @@ -0,0 +1,19 @@ +export const HIDE = { + name: "隐藏此扩展", + clear: true, + onclick() { + if (this.firstChild.innerHTML == "隐藏此扩展") { + this.firstChild.innerHTML = "此扩展将在重启后隐藏"; + lib.config.hiddenPlayPack.add("boss"); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏此扩展"; + lib.config.hiddenPlayPack.remove("boss"); + } + game.saveConfig("hiddenPlayPack", lib.config.hiddenPlayPack); + } +}; diff --git a/noname/library/extension-menu/boss/introduction.js b/noname/library/extension-menu/boss/introduction.js new file mode 100644 index 000000000..c8477163a --- /dev/null +++ b/noname/library/extension-menu/boss/introduction.js @@ -0,0 +1,5 @@ +export const INTRODUCTION = { + name: "将剑阁和挑战模式的武将添加到其它模式", + clear: true, + nopointer: true +}; diff --git a/noname/library/extension-menu/card-pile.js b/noname/library/extension-menu/card-pile.js new file mode 100644 index 000000000..ca6998e8f --- /dev/null +++ b/noname/library/extension-menu/card-pile.js @@ -0,0 +1,33 @@ +import { ENABLE } from "./card-pile/enable.js"; +import { GUOHE } from "./card-pile/guohe.js"; +import { HIDE } from "./card-pile/hide.js"; +import { INTRODUCTION } from "./card-pile/introduction.js"; +import { JIU } from "./card-pile/jiu.js"; +import { NANMAN } from "./card-pile/nanman.js"; +import { SHA_FIRE } from "./card-pile/sha-fire.js"; +import { SHA_THUNDER } from "./card-pile/sha-thunder.js"; +import { SHA } from "./card-pile/sha.js"; +import { SHAN } from "./card-pile/shan.js"; +import { SHUNSHOU } from "./card-pile/shunshou.js"; +import { TAO } from "./card-pile/tao.js"; +import { TIESUO } from "./card-pile/tiesuo.js"; +import { WANJIAN } from "./card-pile/wanjian.js"; +import { WUXIE } from "./card-pile/wuxie.js"; + +export const CARD_PILE = { + enable: ENABLE, + intro: INTRODUCTION, + sha: SHA, + huosha: SHA_FIRE, + leisha: SHA_THUNDER, + shan: SHAN, + tao: TAO, + jiu: JIU, + wuxie: WUXIE, + nanman: NANMAN, + wanjian: WANJIAN, + guohe: GUOHE, + shunshou: SHUNSHOU, + tiesuo: TIESUO, + hide: HIDE +}; diff --git a/noname/library/extension-menu/card-pile/card-pile-item.js b/noname/library/extension-menu/card-pile/card-pile-item.js new file mode 100644 index 000000000..75e2b86e2 --- /dev/null +++ b/noname/library/extension-menu/card-pile/card-pile-item.js @@ -0,0 +1,5 @@ +export const CARD_PILE_ITEM = { + "1": "补充全部", + "0.5": "补充一半", + "0": "不补充" +}; diff --git a/noname/library/extension-menu/card-pile/enable.js b/noname/library/extension-menu/card-pile/enable.js new file mode 100644 index 000000000..51f7c7be1 --- /dev/null +++ b/noname/library/extension-menu/card-pile/enable.js @@ -0,0 +1,5 @@ +export const ENABLE = { + name: "开启", + init: false, + restart: true +}; diff --git a/noname/library/extension-menu/card-pile/guohe.js b/noname/library/extension-menu/card-pile/guohe.js new file mode 100644 index 000000000..ef9adb615 --- /dev/null +++ b/noname/library/extension-menu/card-pile/guohe.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const GUOHE = { + name: "过河拆桥", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/hide.js b/noname/library/extension-menu/card-pile/hide.js new file mode 100644 index 000000000..07d0af97a --- /dev/null +++ b/noname/library/extension-menu/card-pile/hide.js @@ -0,0 +1,19 @@ +export const HIDE = { + name: "隐藏此扩展", + clear: true, + onclick() { + if (this.firstChild.innerHTML == "隐藏此扩展") { + this.firstChild.innerHTML = "此扩展将在重启后隐藏"; + lib.config.hiddenPlayPack.add("boss"); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏此扩展"; + lib.config.hiddenPlayPack.remove("boss"); + } + game.saveConfig("hiddenPlayPack", lib.config.hiddenPlayPack); + } +}; diff --git a/noname/library/extension-menu/card-pile/introduction.js b/noname/library/extension-menu/card-pile/introduction.js new file mode 100644 index 000000000..64aea608f --- /dev/null +++ b/noname/library/extension-menu/card-pile/introduction.js @@ -0,0 +1,5 @@ +export const INTRODUCTION = { + name: "将杀闪等牌在牌堆中的比例维持在与军争牌堆相同,防止开启扩展包后被过多地稀释", + clear: true, + nopointer: true +}; diff --git a/noname/library/extension-menu/card-pile/jiu.js b/noname/library/extension-menu/card-pile/jiu.js new file mode 100644 index 000000000..63c96809b --- /dev/null +++ b/noname/library/extension-menu/card-pile/jiu.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const JIU = { + name: "酒", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/nanman.js b/noname/library/extension-menu/card-pile/nanman.js new file mode 100644 index 000000000..12e50737e --- /dev/null +++ b/noname/library/extension-menu/card-pile/nanman.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const NANMAN = { + name: "南蛮入侵", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/sha-fire.js b/noname/library/extension-menu/card-pile/sha-fire.js new file mode 100644 index 000000000..411f3e23f --- /dev/null +++ b/noname/library/extension-menu/card-pile/sha-fire.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const SHA_FIRE = { + name: "火杀", + init: "1", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/sha-thunder.js b/noname/library/extension-menu/card-pile/sha-thunder.js new file mode 100644 index 000000000..aa7d4ef2d --- /dev/null +++ b/noname/library/extension-menu/card-pile/sha-thunder.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const SHA_THUNDER = { + name: "雷杀", + init: "1", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/sha.js b/noname/library/extension-menu/card-pile/sha.js new file mode 100644 index 000000000..a70b973f1 --- /dev/null +++ b/noname/library/extension-menu/card-pile/sha.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const SHA = { + name: "杀", + init: "1", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/shan.js b/noname/library/extension-menu/card-pile/shan.js new file mode 100644 index 000000000..6242ddcff --- /dev/null +++ b/noname/library/extension-menu/card-pile/shan.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const SHAN = { + name: "闪", + init: "1", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/shunshou.js b/noname/library/extension-menu/card-pile/shunshou.js new file mode 100644 index 000000000..270860eb7 --- /dev/null +++ b/noname/library/extension-menu/card-pile/shunshou.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const SHUNSHOU = { + name: "顺手牵羊", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/tao.js b/noname/library/extension-menu/card-pile/tao.js new file mode 100644 index 000000000..0bddad0d1 --- /dev/null +++ b/noname/library/extension-menu/card-pile/tao.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const TAO = { + name: "桃", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/tiesuo.js b/noname/library/extension-menu/card-pile/tiesuo.js new file mode 100644 index 000000000..4d0ba22d5 --- /dev/null +++ b/noname/library/extension-menu/card-pile/tiesuo.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const TIESUO = { + name: "铁索连环", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/wanjian.js b/noname/library/extension-menu/card-pile/wanjian.js new file mode 100644 index 000000000..796ff2822 --- /dev/null +++ b/noname/library/extension-menu/card-pile/wanjian.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const WANJIAN = { + name: "万箭齐发", + init: "0", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/card-pile/wuxie.js b/noname/library/extension-menu/card-pile/wuxie.js new file mode 100644 index 000000000..b72584853 --- /dev/null +++ b/noname/library/extension-menu/card-pile/wuxie.js @@ -0,0 +1,7 @@ +import { CARD_PILE_ITEM } from "./card-pile-item.js"; + +export const WUXIE = { + name: "无懈可击", + init: "0.5", + item: CARD_PILE_ITEM +}; diff --git a/noname/library/extension-menu/coin.js b/noname/library/extension-menu/coin.js new file mode 100644 index 000000000..b02ba4736 --- /dev/null +++ b/noname/library/extension-menu/coin.js @@ -0,0 +1,13 @@ +import { CANVAS } from "./coin/canvas.js"; +import { DISPLAY } from "./coin/display.js"; +import { ENABLE } from "./coin/enable.js"; +import { HIDE } from "./coin/hide.js"; +import { INTRODUCTION } from "./coin/introduction.js"; + +export const COIN = { + enable: ENABLE, + intro: INTRODUCTION, + display: DISPLAY, + canvas: CANVAS, + hide: HIDE +}; diff --git a/noname/library/extension-menu/coin/canvas.js b/noname/library/extension-menu/coin/canvas.js new file mode 100644 index 000000000..48265efa1 --- /dev/null +++ b/noname/library/extension-menu/coin/canvas.js @@ -0,0 +1,13 @@ +export const CANVAS = { + name: "特效置顶", + init: false, + onclick(bool) { + game.saveConfig("coin_canvas_playpackconfig", bool); + if (bool) { + ui.window.classList.add("canvas_top"); + } + else { + ui.window.classList.remove("canvas_top"); + } + } +}; diff --git a/noname/library/extension-menu/coin/display.js b/noname/library/extension-menu/coin/display.js new file mode 100644 index 000000000..84a97f577 --- /dev/null +++ b/noname/library/extension-menu/coin/display.js @@ -0,0 +1,11 @@ +import { ITEM } from "./display/item.js"; + +export const DISPLAY = { + name: "金币显示", + init: "text", + item: ITEM, + onclick(item) { + game.saveConfig("coin_display_playpackconfig", item); + if (game.changeCoin) game.changeCoin(0); + } +}; diff --git a/noname/library/extension-menu/coin/display/item.js b/noname/library/extension-menu/coin/display/item.js new file mode 100644 index 000000000..f52e1e586 --- /dev/null +++ b/noname/library/extension-menu/coin/display/item.js @@ -0,0 +1,4 @@ +export const ITEM = { + symbol: "符号", + text: "文字" +}; diff --git a/noname/library/extension-menu/coin/enable.js b/noname/library/extension-menu/coin/enable.js new file mode 100644 index 000000000..dc06677b4 --- /dev/null +++ b/noname/library/extension-menu/coin/enable.js @@ -0,0 +1,14 @@ +export const ENABLE = { + name: '开启', + init: false, + restart: true, + onclick(bool) { + if (bool) { + lib.config.plays.add('coin'); + } + else { + lib.config.plays.remove('coin'); + } + game.saveConfig('plays', lib.config.plays); + } +}; diff --git a/noname/library/extension-menu/coin/hide.js b/noname/library/extension-menu/coin/hide.js new file mode 100644 index 000000000..f4bf9c7d7 --- /dev/null +++ b/noname/library/extension-menu/coin/hide.js @@ -0,0 +1,19 @@ +export const HIDE = { + name: "隐藏此扩展", + clear: true, + onclick() { + if (this.firstChild.innerHTML == "隐藏此扩展") { + this.firstChild.innerHTML = "此扩展将在重启后隐藏"; + lib.config.hiddenPlayPack.add("coin"); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏此扩展"; + lib.config.hiddenPlayPack.remove("coin"); + } + game.saveConfig("hiddenPlayPack", lib.config.hiddenPlayPack); + } +}; diff --git a/noname/library/extension-menu/coin/introduction.js b/noname/library/extension-menu/coin/introduction.js new file mode 100644 index 000000000..3daf55ea4 --- /dev/null +++ b/noname/library/extension-menu/coin/introduction.js @@ -0,0 +1,5 @@ +export const INTRODUCTION = { + name: "每完成一次对局,可获得一定数量的金币;金币可用于购买游戏特效", + clear: true, + nopointer: true +}; diff --git a/noname/library/extension-menu/wuxing.js b/noname/library/extension-menu/wuxing.js new file mode 100644 index 000000000..d40e69020 --- /dev/null +++ b/noname/library/extension-menu/wuxing.js @@ -0,0 +1,11 @@ +import { ENABLE } from "./wuxing/enable.js"; +import { HIDE } from "./wuxing/hide.js"; +import { INTRODUCTION } from "./wuxing/introduction.js"; +import { NUMBER } from "./wuxing/number.js"; + +export const WUXING = { + enable: ENABLE, + intro: INTRODUCTION, + num: NUMBER, + hide: HIDE +}; diff --git a/noname/library/extension-menu/wuxing/enable.js b/noname/library/extension-menu/wuxing/enable.js new file mode 100644 index 000000000..51f7c7be1 --- /dev/null +++ b/noname/library/extension-menu/wuxing/enable.js @@ -0,0 +1,5 @@ +export const ENABLE = { + name: "开启", + init: false, + restart: true +}; diff --git a/noname/library/extension-menu/wuxing/hide.js b/noname/library/extension-menu/wuxing/hide.js new file mode 100644 index 000000000..6c54ab6fe --- /dev/null +++ b/noname/library/extension-menu/wuxing/hide.js @@ -0,0 +1,19 @@ +export const HIDE = { + name: "隐藏此扩展", + clear: true, + onclick() { + if (this.firstChild.innerHTML == "隐藏此扩展") { + this.firstChild.innerHTML = "此扩展将在重启后隐藏"; + lib.config.hiddenPlayPack.add("wuxing"); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏此扩展"; + lib.config.hiddenPlayPack.remove("wuxing"); + } + game.saveConfig("hiddenPlayPack", lib.config.hiddenPlayPack); + } +}; diff --git a/noname/library/extension-menu/wuxing/introduction.js b/noname/library/extension-menu/wuxing/introduction.js new file mode 100644 index 000000000..355a56658 --- /dev/null +++ b/noname/library/extension-menu/wuxing/introduction.js @@ -0,0 +1,5 @@ +export const INTRODUCTION = { + name: "每名角色和部分卡牌在游戏开始时随机获得一个属性", + clear: true, + nopointer: true +}; diff --git a/noname/library/extension-menu/wuxing/number.js b/noname/library/extension-menu/wuxing/number.js new file mode 100644 index 000000000..cb7ee5641 --- /dev/null +++ b/noname/library/extension-menu/wuxing/number.js @@ -0,0 +1,7 @@ +import { ITEM } from "./number/item.js"; + +export const NUMBER = { + name: "带属性卡牌", + init: "0.3", + item: ITEM +}; diff --git a/noname/library/extension-menu/wuxing/number/item.js b/noname/library/extension-menu/wuxing/number/item.js new file mode 100644 index 000000000..05c59627d --- /dev/null +++ b/noname/library/extension-menu/wuxing/number/item.js @@ -0,0 +1,6 @@ +export const ITEM = { + "0.1": "10%", + "0.2": "20%", + "0.3": "30%", + "0.5": "50%" +}; diff --git a/noname/library/extension-pack.js b/noname/library/extension-pack.js new file mode 100644 index 000000000..b712adc52 --- /dev/null +++ b/noname/library/extension-pack.js @@ -0,0 +1 @@ +export const extensionPack = {}; diff --git a/noname/library/filter.js b/noname/library/filter.js new file mode 100644 index 000000000..5b9e7b781 --- /dev/null +++ b/noname/library/filter.js @@ -0,0 +1,453 @@ +export class Filter { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + static all() { + return true; + } + static none() { + return false; + } + + /** + * Check if the card does not count toward the player’s hand limit + * + * 检测此牌是否不计入此角色的手牌上限 + */ + static ignoredHandcard(card, player) { + return game.checkMod(card, player, false, "ignoredHandcard", player); + } + + /** + * Check if the card is giftable + * 检测此牌是否可赠予 + */ + static cardGiftable(card, player, target, strict) { + const mod = game.checkMod(card, player, target, "unchanged", "cardGiftable", player); + if (!mod || strict && (mod == "unchanged" && (get.position(card) != "h" || !get.cardtag(card, "gifts")) || player == target)) return false; + return get.type(card, false) != "equip" || target.canEquip(card, true); + } + + /** + * Check if the card is recastable + * 检查此牌是否可重铸 + */ + static cardRecastable(card, player, source, strict) { + if (typeof player == "undefined") player = get.owner(card); + const mod = game.checkMod(card, player, source, "unchanged", "cardRecastable", player); + if (!mod) return false; + if (strict && mod == "unchanged") { + if (get.position(card) != "h") return false; + const info = get.info(card), recastable = info.recastable || info.chongzhu; + return Boolean(typeof recastable == "function" ? recastable(_status.event, player) : recastable); + } + return true; + } + // 装备栏相关 + static canBeReplaced(card, player) { + var mod = game.checkMod(card, player, "unchanged", "canBeReplaced", player); + if (mod != "unchanged") return mod; + return true; + } + // 装备栏 END + static buttonIncluded(button) { + return !(_status.event.excludeButton && _status.event.excludeButton.contains(button)); + } + static filterButton(button) { + return true; + } + static cardSavable(card, player, target) { + if (get.itemtype(card) == "card") { + var mod2 = game.checkMod(card, player, "unchanged", "cardEnabled2", player); + if (mod2 != "unchanged") return mod2; + } + var mod = game.checkMod(card, player, target, "unchanged", "cardSavable", player); + if (mod != "unchanged") return mod; + var savable = get.info(card).savable; + if (typeof savable == "function") savable = savable(card, player, target); + return savable; + } + static filterTrigger(event, player, name, skill) { + if (player._hookTrigger && player._hookTrigger.some(i => { + const info = lib.skill[i].hookTrigger; + return info && info.block && info.block(event, player, name, skill); + })) return false; + const fullskills = game.expandSkills(player.getSkills(false).concat(lib.skill.global)); + const info = get.info(skill); + if (!info) return console.log("缺少info的技能:", skill); + if (!fullskills.includes(skill)) { + if (get.mode() != "guozhan") return false; + if (info && info.noHidden) return false; + } + if (!info.trigger) return false; + if (!info.forceDie && player.isDead()) return false; + if (!info.forceOut && player.isOut()) return false; + if (!Object.keys(info.trigger).some(i => { + if (i != "global" && player != event[i]) return false; + if (Array.isArray(info.trigger[i])) return info.trigger[i].includes(name); + return info.trigger[i] == name; + })) return false; + if (info.filter && !info.filter(event, player, name)) return false; + if (event._notrigger.includes(player) && !lib.skill.global.includes(skill)) return false; + if (typeof info.usable == "number" && player.hasSkill("counttrigger") && + player.storage.counttrigger && player.storage.counttrigger[skill] >= info.usable) { + return false; + } + if (info.round && (info.round - (game.roundNumber - player.storage[skill + "_roundcount"]) > 0)) return false; + if (player.storage[`temp_ban_${skill}`] === true) return false; + return true; + } + static characterDisabled(i, libCharacter) { + if (!lib.character[i] || lib.character[i][4] && lib.character[i][4].contains("forbidai")) return true; + if (lib.character[i][4] && lib.character[i][4].contains("unseen")) return true; + if (lib.config.forbidai.contains(i)) return true; + if (lib.characterFilter[i] && !lib.characterFilter[i](get.mode())) return true; + if (_status.connectMode) { + if (lib.configOL.banned.contains(i) || lib.connectBanned.contains(i)) return true; + var double_character = false; + if (lib.configOL.mode == "guozhan") { + double_character = true; + } + else if (lib.configOL.double_character && (lib.configOL.mode == "identity" || lib.configOL.mode == "stone")) { + double_character = true; + } + else if (lib.configOL.double_character_jiange && (lib.configOL.mode == "versus" && _status.mode == "jiange")) { + double_character = true; + } + if (double_character && lib.config.forbiddouble.contains(i)) { + return true; + } + } + else { + if (lib.config.banned.contains(i)) return true; + var double_character = false; + if (get.mode() == "guozhan") { + double_character = true; + } + else if (get.config("double_character") && (lib.config.mode == "identity" || lib.config.mode == "stone")) { + double_character = true; + } + else if (get.config("double_character_jiange") && (lib.config.mode == "versus" && _status.mode == "jiange")) { + double_character = true; + } + if (double_character && lib.config.forbiddouble.contains(i)) { + return true; + } + } + } + static characterDisabled2(i) { + var info = lib.character[i]; + if (!info) return true; + if (info[4]) { + if (info[4].contains("boss")) return true; + if (info[4].contains("hiddenboss")) return true; + if (info[4].contains("minskin")) return true; + if (info[4].contains("unseen")) return true; + if (info[4].contains("forbidai") && (!_status.event.isMine || !_status.event.isMine())) return true; + if (lib.characterFilter[i] && !lib.characterFilter[i](get.mode())) return true; + } + return false; + } + static skillDisabled(skill) { + if (!lib.translate[skill] || !lib.translate[skill + "_info"]) return true; + var info = lib.skill[skill]; + if (info && !info.unique && !info.temp && !info.sub && !info.fixed && !info.vanish) { + return false; + } + return true; + } + static cardEnabled(card, player, event) { + if (player == undefined) player = _status.event.player; + if (!player) return false; + if (get.itemtype(card) == "card") { + var mod2 = game.checkMod(card, player, event, "unchanged", "cardEnabled2", player); + if (mod2 != "unchanged") return mod2; + } + card = get.autoViewAs(card); + if (event === "forceEnable") { + var mod = game.checkMod(card, player, event, "unchanged", "cardEnabled", player); + if (mod != "unchanged") return mod; + return true; + } + else { + var filter = get.info(card).enable; + if (!filter) return; + var mod = game.checkMod(card, player, event, "unchanged", "cardEnabled", player); + if (mod != "unchanged") return mod; + if (typeof filter == "boolean") return filter; + if (typeof filter == "function") return filter(card, player, event); + } + } + static cardRespondable(card, player, event) { + event = event || _status.event; + if (event.name != "chooseToRespond") return true; + var source = event.getParent().player; + if (source && source != player) { + if (source.hasSkillTag("norespond", false, [card, player, event], true)) { + return false; + } + } + if (player == undefined) player = _status.event.player; + if (get.itemtype(card) == "card") { + var mod2 = game.checkMod(card, player, event, "unchanged", "cardEnabled2", player); + if (mod2 != "unchanged") return mod2; + } + var mod = game.checkMod(card, player, "unchanged", "cardRespondable", player); + if (mod != "unchanged") return mod; + return true; + } + static cardUsable2(card, player, event) { + card = get.autoViewAs(card); + var info = get.info(card); + if (info.updateUsable == "phaseUse") { + event = event || _status.event; + if (event.type == "chooseToUse_button") event = event.getParent(); + if (player != _status.event.player) return true; + if (event.getParent().name != "phaseUse") return true; + if (event.getParent().player != player) return true; + } + var num = info.usable; + if (typeof num == "function") num = num(card, player); + num = game.checkMod(card, player, num, "cardUsable", player); + if (typeof num != "number") return true; + else return (player.countUsed(card) < num); + } + static cardUsable(card, player, event) { + card = get.autoViewAs(card); + var info = get.info(card); + event = event || _status.event; + if (event.type == "chooseToUse_button") event = event.getParent(); + if (player != _status.event.player) return true; + if (info.updateUsable == "phaseUse") { + if (event.getParent().name != "phaseUse") return true; + if (event.getParent().player != player) return true; + } + event.addCount_extra = true; + var num = info.usable; + if (typeof num == "function") num = num(card, player); + num = game.checkMod(card, player, num, "cardUsable", player); + if (typeof num != "number") { + return (typeof num == "boolean") ? num : true; + } + if (player.countUsed(card) < num) return true; + if (game.hasPlayer(function (current) { + return game.checkMod(card, player, current, false, "cardUsableTarget", player); + })) { + return true; + } + return false; + } + static cardDiscardable(card, player, event) { + event = event || _status.event; + if (typeof event != "string") event = event.getParent().name; + var mod = game.checkMod(card, player, event, "unchanged", "cardDiscardable", player); + if (mod != "unchanged") return mod; + return true; + } + static canBeDiscarded(card, player, target, event) { + event = event || _status.event; + if (typeof event != "string") event = event.getParent().name; + var mod = game.checkMod(card, player, target, event, "unchanged", "canBeDiscarded", target); + if (mod != "unchanged") return mod; + return true; + } + static canBeGained(card, player, target, event) { + event = event || _status.event; + if (typeof event != "string") event = event.getParent().name; + var mod = game.checkMod(card, player, target, event, "unchanged", "canBeGained", target); + if (mod != "unchanged") return mod; + return true; + } + static cardAiIncluded(card) { + if (_status.event.isMine()) return true; + return (_status.event._aiexclude.contains(card) == false); + } + static filterCard(card, player, event) { + var info = get.info(card); + //if(info.toself&&!lib.filter.targetEnabled(card,player,player)) return false; + if (player == undefined) player = _status.event.player; + if (!lib.filter.cardEnabled(card, player, event) || !lib.filter.cardUsable(card, player, event)) return false; + if (info.notarget) return true; + var range; + var select = get.copy(info.selectTarget); + if (select == undefined) { + if (info.filterTarget == undefined) return true; + range = [1, 1]; + } + else if (typeof select == "number") range = [select, select]; + else if (get.itemtype(select) == "select") range = select; + else if (typeof select == "function") range = select(card, player); + game.checkMod(card, player, range, "selectTarget", player); + if (!range || range[1] != -1) return true; + var filterTarget = (event && event.filterTarget) ? event.filterTarget : lib.filter.filterTarget; + return game.hasPlayer(function (current) { + return filterTarget(card, player, current); + }); + } + static targetEnabledx(card, player, target) { + if (!card) return false; + if (!target || !target.isIn()) return false; + var event = _status.event; + if (event._backup && event._backup.filterCard == lib.filter.filterCard && (!lib.filter.cardEnabled(card, player, event) || !lib.filter.cardUsable(card, player, event))) return false; + if (event.addCount_extra) { + if (!lib.filter.cardUsable2(card, player) && !game.checkMod(card, player, target, false, "cardUsableTarget", player)) return false; + } + var info = get.info(card); + if (info.singleCard && info.filterAddedTarget && ui.selected.targets.length) return Boolean(info.filterAddedTarget(card, player, target, ui.selected.targets[ui.selected.targets.length - 1])); + return lib.filter.targetEnabled.apply(this, arguments); + } + static targetEnabled(card, player, target) { + if (!card) return false; + if (!target || !target.isIn()) return false; + var info = get.info(card); + var filter = info.filterTarget; + if (!info.singleCard || ui.selected.targets.length == 0) { + var mod = game.checkMod(card, player, target, "unchanged", "playerEnabled", player); + if (mod != "unchanged") return mod; + var mod = game.checkMod(card, player, target, "unchanged", "targetEnabled", target); + if (mod != "unchanged") return mod; + } + if (typeof filter == "boolean") return filter; + if (typeof filter == "function") return Boolean(filter(card, player, target)); + } + static targetEnabled2(card, player, target) { + if (!card) return false; + if (!target || !target.isIn()) return false; + if (lib.filter.targetEnabled(card, player, target)) return true; + + if (game.checkMod(card, player, target, "unchanged", "playerEnabled", player) == false) return false; + if (game.checkMod(card, player, target, "unchanged", "targetEnabled", target) == false) return false; + + var filter = get.info(card).modTarget; + if (typeof filter == "boolean") return filter; + if (typeof filter == "function") return Boolean(filter(card, player, target)); + return false; + } + static targetEnabled3(card, player, target) { + if (!card) return false; + if (!target || !target.isIn()) return false; + var info = get.info(card); + + if (info.filterTarget == true) return true; + if (typeof info.filterTarget == "function" && info.filterTarget(card, player, target)) return true; + + if (info.modTarget == true) return true; + if (typeof info.modTarget == "function" && info.modTarget(card, player, target)) return true; + return false; + } + static targetInRange(card, player, target) { + var info = get.info(card); + var range = info.range; + var outrange = info.outrange; + if (range == undefined && outrange == undefined) return true; + + var mod = game.checkMod(card, player, target, "unchanged", "targetInRange", player); + var extra = 0; + if (mod != "unchanged") { + if (typeof mod == "boolean") return mod; + if (typeof mod == "number") extra = mod; + } + if (typeof info.range == "function") return info.range(card, player, target); + + if (player.hasSkill("undist") || target.hasSkill("undist")) return false; + for (var i in range) { + if (i == "attack") { + var range2 = player.getAttackRange(); + if (range2 <= 0) return false; + var distance = get.distance(player, target) + extra; + if (range[i] <= distance - range2) return false; + } + else { + var distance = get.distance(player, target, i) + extra; + if (range[i] < distance) return false; + } + } + for (var i in outrange) { + if (i == "attack") { + var range2 = player.getAttackRange(); + if (range2 <= 0) return false; + var distance = get.distance(player, target) + extra; + if (outrange[i] > distance - range2 + 1) return false; + } + else { + var distance = get.distance(player, target, i) + extra; + if (outrange[i] > distance) return false; + } + } + return true; + } + static filterTarget(card, player, target) { + return (lib.filter.targetEnabledx(card, player, target) && + lib.filter.targetInRange(card, player, target)); + } + static filterTarget2(card, player, target) { + return (lib.filter.targetEnabled2(card, player, target) && + lib.filter.targetInRange(card, player, target)); + } + static notMe(card, player, target) { + return player != target; + } + static isMe(card, player, target) { + return player == target; + } + static attackFrom(card, player, target) { + return get.distance(player, target, "attack") <= 1; + } + static globalFrom(card, player, target) { + return get.distance(player, target) <= 1; + } + static selectCard() { + return [1, 1]; + } + static selectTarget(card, player) { + if (!card) card = get.card(); + if (!player) player = get.player(); + if (card == undefined) return; + var range, info = get.info(card); + var select = get.copy(info.selectTarget); + if (select == undefined) { + if (info.filterTarget == undefined) return [0, 0]; + range = [1, 1]; + } + else if (typeof select == "number") range = [select, select]; + else if (get.itemtype(select) == "select") range = select; + else if (typeof select == "function") range = select(card, player); + game.checkMod(card, player, range, "selectTarget", player); + if (info.singleCard && info.filterAddedTarget) return [range[0] * 2, range[1] * 2]; + return range; + } + static judge(card, player, target) { + return target.canAddJudge(card); + } + static autoRespondSha() { + return !this.player.hasSha(true); + } + static autoRespondShan() { + return !this.player.hasShan(); + } + static wuxieSwap(event) { + if (event.type == "wuxie") { + if (ui.wuxie && ui.wuxie.classList.contains("glow")) { + return true; + } + if (ui.tempnowuxie && ui.tempnowuxie.classList.contains("glow") && event.state > 0) { + var triggerevent = event.getTrigger(); + if (triggerevent) { + if (ui.tempnowuxie._origin == triggerevent.parent.id) { + return true; + } + } + else if (ui.tempnowuxie._origin == _status.event.id2) { + return true; + } + } + if (lib.config.wuxie_self) { + var tw = event.info_map; + if (tw.player && tw.player.isUnderControl(true) && !tw.player.hasSkillTag("noautowuxie") && + (!tw.targets || tw.targets.length <= 1) && !tw.noai) { + return true; + } + } + } + } +} diff --git a/noname/library/group-nature.js b/noname/library/group-nature.js new file mode 100644 index 000000000..837fd19c9 --- /dev/null +++ b/noname/library/group-nature.js @@ -0,0 +1,11 @@ +export const groupNature = { + shen: "shen", + wei: "water", + shu: "soil", + wu: "wood", + qun: "qun", + western: "thunder", + key: "key", + jin: "thunder", + ye: "thunder" +}; diff --git a/noname/library/handler-option.d.ts b/noname/library/handler-option.d.ts new file mode 100644 index 000000000..1eafddc46 --- /dev/null +++ b/noname/library/handler-option.d.ts @@ -0,0 +1,3 @@ +export interface HandlerOption extends Record { + state: "begin" | "end"; +} diff --git a/noname/library/help.js b/noname/library/help.js new file mode 100644 index 000000000..9c3a8ac38 --- /dev/null +++ b/noname/library/help.js @@ -0,0 +1,32 @@ +export const HELP = { + 关于游戏: `
关于无名杀
  • 无名杀官方发布地址仅有GitHub仓库!
    点击前往Github仓库
  • 无名杀基于GPLv3开源协议。
    点击查看GPLv3协议
  • 其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!`, + 游戏操作: "
    • 长按/鼠标悬停/右键单击显示信息。
    • 触屏模式中,双指点击切换暂停;下划显示菜单,上划切换托管。
    • 键盘快捷键
      " + + "
      A切换托管
      W切换不询问无懈
      空格暂停
    • 编辑牌堆
      在卡牌包中修改牌堆后,将自动创建一个临时牌堆,在所有模式中共用,当保存当前牌堆后,临时牌堆被清除。每个模式可设置不同的已保存牌堆,设置的牌堆优先级大于临时牌堆。
    ", + 游戏命令: `
    变量名
    • 场上角色
      game.players
    • 阵亡角色
      game.dead` + + "
    • 玩家
      game.me
    • 玩家的上/下家
      game.me.previous/next" + + "
    • 玩家的上/下家(含阵亡)
      game.me.previousSeat/
      nextSeat" + + "
    • 牌堆
      ui.cardPile
    • 弃牌堆
      ui.discardPile
    " + + `
    角色属性
    • 体力值
      player.hp` + + `
    • 体力上限
      player.maxHp
    • 身份
      player.identity
    • 手牌
      player.getCards("h")
    • 装备牌
      player.getCards("e")
    • 判定牌
      player.getCards("j")` + + "
    • 是否存活/横置/翻面
      player.isAlive()/
      isLinked()/
      isTurnedOver()
    " + + `
    角色操作
    • 受到伤害
      player.damage(source,
      num)` + + "
    • 回复体力
      player.recover(num)
    • 摸牌
      player.draw(num)
    • 获得牌
      player.gain(cards)
    • 弃牌
      player.discard(cards)" + + "
    • 使用卡牌
      player.useCard(card,
      targets)
    • 死亡
      player.die()
    • 复活
      player.revive(hp)
    " + + `
    游戏操作
    • 在命令框中输出结果
      game.print(str)
    • 清除命令框中的内容
      cls
    • 上一条/下一条输入的内容
      up/down
    • 游戏结束
      game.over(bool)` + + "
    • 角色资料
      lib.character
    • 卡牌资料
      lib.card
    ", + 游戏名词: "
    • 智囊:无名杀默认为过河拆桥/无懈可击/无中生有/洞烛先机。牌堆中没有的智囊牌会被过滤。可在卡牌设置中自行增减。若没有可用的智囊,则改为随机选取的三种锦囊牌的牌名。" + + "
    • 仁库:部分武将使用的游戏外共通区域。至多包含六张牌。当有新牌注入后,若牌数超过上限,则将最早进入仁库的溢出牌置入弃牌堆。" + + "
    • 护甲:和体力类似,每点护甲可抵挡1点伤害,但不影响手牌上限。" + + "
    • 随从:通过技能获得,拥有独立的技能、手牌区和装备区(共享判定区),出场时替代主武将的位置;随从死亡时自动切换回主武将。" + + "
    • 发现:从三张随机亮出的牌中选择一张,若无特殊说明,则获得此牌。" + + "
    • 蓄能技:发动时可以增大黄色的数字。若如此做,红色数字于技能的结算过程中改为原来的两倍。" + + "
    • 施法:若技能的拥有者未拥有等待执行的同名“施法”效果,则其可以发动“施法”技能。其须选择声明一个数字X(X∈[1, 3]),在此之后的第X个回合结束时,其执行“施法”效果,且效果中的数字X视为与技能发动者声明的X相同。" + + "
    • 共同拼点:一种特殊的拼点结算。发起者与被指定的拼点目标同时亮出拼点牌,进行一次决算:其中拼点牌点数唯一最大的角色赢,其他角色均没赢;若没有点数唯一最大的拼点牌,则所有角色拼点均没赢。" + + "
    • 强令:若一名角色拥有带有“强令”的技能,则该技能的发动时机为“出牌阶段开始时”。若技能拥有者发动该技能,其须发布“强令”给一名其他角色,并在对应技能的时间节点加以判断目标角色是否成功完成该强令所要求的任务条件。成功或失败则会根据技能效果执行不同结算流程。" + + "
    • 摧坚:若一名角色拥有带有“摧坚”的技能,则该技能的发动时机为“当你使用伤害牌指定第一个目标后”。你可以对其中一个目标发动“摧坚”技能,然后执行后续效果。其中,后续效果里的X等于该目标的非charlotte技能的数量。" + + "
    • 妄行:一种特殊的选项。若一名角色拥有带有“妄行”的技能,则该技能触发时,你须选择声明一个数字X(X∈{1,2,3,4}),技能后续中的X即为你选择的数字。选择完毕后,你获得如下效果:回合结束时,你选择一项:1.弃置X张牌;2.减1点体力上限。" + + "
    • 搏击:若一名角色拥有带有“搏击”的技能,则当该搏击技能触发时,若本次技能的目标角色在你攻击范围内,且你在其攻击范围内,则你执行技能主体效果时,同时额外执行“搏击”后的额外效果。" + + "
    • 游击:若一名角色拥有带有“游击”的技能,则当该游击技能执行至“游击”处时,若本次技能的目标角色在你的攻击范围内,且你不在其攻击范围内,则你可以执行“游击”后的额外效果。" + + "
    • 激昂:一名角色发动“昂扬技”标签技能后,此技能失效,直至从此刻至满足此技能“激昂”条件后。" + + "" +}; diff --git a/noname/library/hook-map.d.ts b/noname/library/hook-map.d.ts new file mode 100644 index 000000000..b0346797b --- /dev/null +++ b/noname/library/hook-map.d.ts @@ -0,0 +1,4 @@ +interface HookMap extends Record { +} + +export const hookMap: HookMap; diff --git a/noname/library/hook-map.js b/noname/library/hook-map.js new file mode 100644 index 000000000..e6b7bd544 --- /dev/null +++ b/noname/library/hook-map.js @@ -0,0 +1 @@ +export const hookMap = {}; diff --git a/noname/library/hook.js b/noname/library/hook.js new file mode 100644 index 000000000..66f9be85b --- /dev/null +++ b/noname/library/hook.js @@ -0,0 +1,5 @@ +import { globalSkill } from "./hook/global-skill.js"; + +export const hook = { + globalskill: globalSkill +}; diff --git a/noname/library/hook/global-skill.js b/noname/library/hook/global-skill.js new file mode 100644 index 000000000..ce47b7528 --- /dev/null +++ b/noname/library/hook/global-skill.js @@ -0,0 +1 @@ +export const globalSkill = {}; diff --git a/noname/library/hooks.js b/noname/library/hooks.js new file mode 100644 index 000000000..4fb7176f1 --- /dev/null +++ b/noname/library/hooks.js @@ -0,0 +1,190 @@ +import { Game } from "../game.js"; +import { Library } from "../library.js"; + +/** + * 函数钩子 + */ +export const hooks = { + /** + * 本体势力的颜色 + */ + addGroup: [(id, _short, _name, config) => { + if ("color" in config && config.color != null) { + let color1, color2, color3, color4; + if (typeof config.color == "string" && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(config.color)) { + let c1 = parseInt(`0x${config.color.slice(1, 3)}`); + let c2 = parseInt(`0x${config.color.slice(3, 5)}`); + let c3 = parseInt(`0x${config.color.slice(5, 7)}`); + color1 = color2 = color3 = color4 = [c1, c2, c3, 1]; + } + else if (Array.isArray(config.color) && config.color.length == 4) { + if (config.color.every(item => Array.isArray(item))) { + color1 = config.color[0]; + color2 = config.color[1]; + color3 = config.color[2]; + color4 = config.color[3]; + } + else color1 = color2 = color3 = color4 = config.color; + } + if (color1 && color2 && color3 && color4) { + const cs = Library.linq.cselector; + const g1 = cs.group( + cs.of( + cs.class("player", "identity"), + cs.isAttr("data-color", `"${id}"`) + ), + cs.of( + "div", + cs.isAttr("data-nature", `"${id}"`) + ), + cs.of( + "span", + cs.isAttr("data-nature", `"${id}"`) + ) + ); + const g2 = cs.group( + cs.of( + "div", + cs.isAttr("data-nature", `"${id}m"`) + ), + cs.of( + "span", + cs.isAttr("data-nature", `"${id}m"`) + ) + ); + const g3 = cs.group( + cs.of( + "div", + cs.isAttr("data-nature", `"${id}mm"`) + ), + cs.of( + "span", + cs.isAttr("data-nature", `"${id}mm"`) + ) + ); + let result = {}; + result[g1] = { + textShadow: cs.group( + "black 0 0 1px", + `rgba(${color1.join()}) 0 0 2px`, + `rgba(${color2.join()}) 0 0 5px`, + `rgba(${color3.join()}) 0 0 10px`, + `rgba(${color4.join()}) 0 0 10px` + ) + }; + result[g2] = { + textShadow: cs.group( + "black 0 0 1px", + `rgba(${color1.join()}) 0 0 2px`, + `rgba(${color2.join()}) 0 0 5px`, + `rgba(${color3.join()}) 0 0 5px`, + `rgba(${color4.join()}) 0 0 5px`, + "black 0 0 1px" + ) + }; + result[g3] = { + textShadow: cs.group( + "black 0 0 1px", + `rgba(${color1.join()}) 0 0 2px`, + `rgba(${color2.join()}) 0 0 2px`, + `rgba(${color3.join()}) 0 0 2px`, + `rgba(${color4.join()}) 0 0 2px`, + "black 0 0 1px" + ) + }; + Game.dynamicStyle.addObject(result); + Library.groupnature[id] = id; + } + } + if (typeof config.image == "string") Object.defineProperty(Library.card, `group_${id}`, { + configurable: true, + enumerable: false, + writable: true, + value: { + fullskin: true, + image: config.image + } + }); + }], + /** + * 增加新属性杀 + */ + addNature: [(nature, _translation, config) => { + if (typeof config != "object") config = {}; + let linked = config.linked, order = config.order, background = config.background, lineColor = config.lineColor; + if (typeof linked != "boolean") linked = true; + if (typeof order != "number") order = 0; + if (typeof background != "string") background = ""; + if (!Array.isArray(lineColor) || lineColor.length != 3) lineColor = []; + else if (background.startsWith("ext:")) { + background = background.replace(/^ext:/, "extension/"); + } + if (linked) Library.linked.add(nature); + if (lineColor.length) Library.lineColor.set(nature, lineColor); + Library.nature.set(nature, order); + if (background.length > 0) Library.natureBg.set(nature, background); + if (config.audio) { + for (let key in config.audio) { + if (!Library.natureAudio[key]) { + Library.natureAudio[key] = config.audio[key]; + } else { + for (let key2 in config.audio[key]) { + Library.natureAudio[key][key2] = config.audio[key][key2]; + } + } + } + } + + let color1, color2; + if (typeof config.color == "string" && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(config.color)) { + let c1 = parseInt(`0x${item[1].slice(1, 3)}`); + let c2 = parseInt(`0x${item[1].slice(3, 5)}`); + let c3 = parseInt(`0x${item[1].slice(5, 7)}`); + color1 = color2 = [c1, c2, c3, 1]; + } + else if (Array.isArray(config.color) && config.color.length >= 2 && config.color.length <= 4) { + if (config.color.every(item => Array.isArray(item))) { + color1 = config.color[0]; + color2 = config.color[1]; + } + else { + let color = config.color.slice(); + if (color.length == 3) color.push(1); + color1 = color2 = color; + } + } + if (color1 && color2) { + const cs = Library.linq.cselector; + const g1 = cs.group( + cs.of( + cs.class("card", "fullskin", `${nature}`), + ">", + cs.class("name") + ) + ); + let result = {}; + result[g1] = { + color: `rgba(${color1.join()})`, + border: cs.merge( + "1px", + "solid", + `rgba(${color2.join()})` + ), + }; + Game.dynamicStyle.addObject(result); + + const g2 = cs.group( + cs.of( + cs.class("tempname", `${nature}`), + ":not([data-nature])>", + cs.class("span") + ) + ) + let result2 = {}; + result2[g2] = { + color: `rgba(${color1.join()})`, + }; + Game.dynamicStyle.addObject(result2); + } + }] +}; diff --git a/noname/library/imported.js b/noname/library/imported.js new file mode 100644 index 000000000..9e11b3747 --- /dev/null +++ b/noname/library/imported.js @@ -0,0 +1 @@ +export const imported = {}; diff --git a/noname/library/initialization.js b/noname/library/initialization.js new file mode 100644 index 000000000..9ebfb094d --- /dev/null +++ b/noname/library/initialization.js @@ -0,0 +1,3362 @@ +import { Promises } from "./initialization/promises.js"; + +export class Initialization { + static promises = Promises; + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static init() { + if (typeof __dirname === "string" && __dirname.length) { + var dirsplit = __dirname.split("/"); + for (var i = 0; i < dirsplit.length; i++) { + if (dirsplit[i]) { + var c = dirsplit[i][0]; + lib.configprefix += /[A-Z]|[a-z]/.test(c) ? c : "_"; + } + } + lib.configprefix += "_"; + } + window.resetGameTimeout = setTimeout(lib.init.reset, parseInt(localStorage.getItem(lib.configprefix + "loadtime")) || 10000); + if (window.cordovaLoadTimeout) { + clearTimeout(window.cordovaLoadTimeout); + delete window.cordovaLoadTimeout; + } + var links = document.head.querySelectorAll("link"); + for (var i = 0; i < links.length; i++) { + if (links[i].href.includes("app/color.css")) { + links[i].remove(); + break; + } + } + var index = window.location.href.indexOf("index.html?server="); + if (index != -1) { + window.isNonameServer = window.location.href.slice(index + 18); + window.nodb = true; + } + else { + index = localStorage.getItem(lib.configprefix + "asserver"); + if (index) { + window.isNonameServer = index; + window.isNonameServerIp = lib.hallURL; + } + } + + var htmlbg = localStorage.getItem(lib.configprefix + "background"); + if (htmlbg) { + if (htmlbg[0] == "[") { + try { + htmlbg = JSON.parse(htmlbg); + htmlbg = htmlbg[get.rand(htmlbg.length)]; + if (htmlbg.startsWith("custom_")) { + throw ("err"); + } + _status.htmlbg = htmlbg; + } + catch (e) { + htmlbg = null; + } + } + if (htmlbg) { + document.documentElement.style.backgroundImage = `url("${lib.assetURL}image/background/${htmlbg}.jpg")`; + document.documentElement.style.backgroundSize = "cover"; + document.documentElement.style.backgroundPosition = "50% 50%"; + } + } + + lib.get = get; + lib.ui = ui; + lib.ai = ai; + lib.game = game; + _status.event = lib.element.GameEvent.initialGameEvent(); + + HTMLDivElement.prototype.animate = function (name, time) { + var that; + if (get.is.mobileMe(this) && name == "target") { + that = ui.mebg; + } + else { + that = this; + } + that.classList.add(name); + setTimeout(function () { + that.classList.remove(name); + }, time || 1000); + return this; + }; + HTMLDivElement.prototype.hide = function () { + this.classList.add("hidden"); + return this; + }; + HTMLDivElement.prototype.unfocus = function () { + if (lib.config.transparent_dialog) this.classList.add("transparent"); + return this; + }; + HTMLDivElement.prototype.refocus = function () { + this.classList.remove("transparent"); + return this; + }; + HTMLDivElement.prototype.show = function () { + this.classList.remove("hidden"); + return this; + }; + HTMLDivElement.prototype.delete = function (time, callback) { + if (this.timeout) { + clearTimeout(this.timeout); + delete this.timeout; + } + if (!this._listeningEnd || this._transitionEnded) { + if (typeof time != "number") time = 500; + this.classList.add("removing"); + var that = this; + this.timeout = setTimeout(function () { + that.remove(); + that.classList.remove("removing"); + if (typeof callback == "function") { + callback(); + } + }, time); + } + else { + this._onEndDelete = true; + } + return this; + }; + HTMLDivElement.prototype.goto = function (position, time) { + if (this.timeout) { + clearTimeout(this.timeout); + delete this.timeout; + } + + if (typeof time != "number") time = 500; + this.classList.add("removing"); + + var that = this; + this.timeout = setTimeout(function () { + if (!that._selfDestroyed) { + position.appendChild(that); + } + that.classList.remove("removing"); + delete that.destiny; + }, time); + this.destiny = position; + return this; + }; + HTMLDivElement.prototype.fix = function () { + clearTimeout(this.timeout); + delete this.timeout; + delete this.destiny; + this.classList.remove("removing"); + return this; + }; + Object.defineProperty(HTMLDivElement.prototype, "setBackground", { + configurable: true, + enumerable: false, + writable: true, + value: function (name, type, ext, subfolder) { + if (!name) return; + let src; + if (ext == "noskin") ext = ".jpg"; + ext = ext || ".jpg"; + subfolder = subfolder || "default"; + if (type) { + let dbimage = null, extimage = null, modeimage = null, nameinfo, gzbool = false; + const mode = get.mode(); + if (type == "character") { + if (lib.characterPack[`mode_${mode}`] && lib.characterPack[`mode_${mode}`][name]) { + if (mode == "guozhan") { + nameinfo = lib.character[name]; + if (name.startsWith("gz_shibing")) name = name.slice(3, 11); + else { + if (lib.config.mode_config.guozhan.guozhanSkin && lib.character[name] && lib.character[name][4].contains("gzskin")) gzbool = true; + name = name.slice(3); + } + } + else modeimage = mode; + } + else if (name.includes("::")) { + name = name.split("::"); + modeimage = name[0]; + name = name[1]; + } + else { + nameinfo = get.character(name); + } + } + if (!modeimage && nameinfo && nameinfo[4]) for (const value of nameinfo[4]) { + if (value.startsWith("ext:")) { + extimage = value; + break; + } + else if (value.startsWith("db:")) { + dbimage = value; + break; + } + else if (value.startsWith("mode:")) { + modeimage = value.slice(5); + break; + } + else if (value.startsWith("character:")) { + name = value.slice(10); + break; + } + } + if (extimage) src = extimage.replace(/^ext:/, "extension/"); + else if (dbimage) { + this.setBackgroundDB(dbimage.slice(3)); + return this; + } + else if (modeimage) src = `image/mode/${modeimage}/character/${name}${ext}`; + else if (type == "character" && lib.config.skin[name] && arguments[2] != "noskin") src = `image/skin/${name}/${lib.config.skin[name]}${ext}`; + else if (type == "character") { + src = `image/character/${gzbool ? "gz_" : ""}${name}${ext}`; + } + else src = `image/${type}/${subfolder}/${name}${ext}`; + } + else src = `image/${name}${ext}`; + this.setBackgroundImage(src); + this.style.backgroundPositionX = "center"; + this.style.backgroundSize = "cover"; + if (type == "character") { + new Promise((_, reject) => { + const image = new Image(); + image.src = `${lib.assetURL}${src}`; + image.onerror = reject; + }).catch(() => new Promise((_, reject) => { + const nameinfo = get.character(name); + if (!nameinfo) reject("noinfo"); + const sex = nameinfo[0]; + src = `image/character/default_silhouette_${sex}${ext}`; + const image = new Image(); + image.src = `${lib.assetURL}${src}`; + image.onload = () => this.setBackgroundImage(src); + image.onerror = () => reject(`sex:${sex}`); + })).catch(reason => { + let sex; + if (reason == "noinfo") sex = "male"; + else sex = reason.slice(4); + src = `image/character/default_silhouette_${sex == "female" ? "female" : "male"}${ext}`; + const image = new Image(); + image.src = `${lib.assetURL}${src}`; + image.onload = () => this.setBackgroundImage(src); + }); + } + return this; + } + }); + HTMLDivElement.prototype.setBackgroundDB = function (img) { + return game.getDB("image", img).then(src => { + this.style.backgroundImage = `url("${src}")`; + this.style.backgroundSize = "cover"; + return this; + }); + }; + HTMLDivElement.prototype.setBackgroundImage = function (img) { + this.style.backgroundImage = `url("${lib.assetURL}${img}")`; + return this; + }, + HTMLDivElement.prototype.listen = function (func) { + if (lib.config.touchscreen) { + this.addEventListener("touchend", function (e) { + if (!_status.dragged) { + func.call(this, e); + } + }); + var fallback = function (e) { + if (!_status.touchconfirmed) { + func.call(this, e); + } + else { + this.removeEventListener("click", fallback); + } + } + this.addEventListener("click", fallback); + } + else { + this.addEventListener("click", func); + } + return this; + }; + HTMLDivElement.prototype.listenTransition = function (func, time) { + let done = false; + const callback = () => { + if (!done) { + done = true; + func.call(this); + } + clearTimeout(timer); + this.removeEventListener("webkitTransitionEnd", callback); + }; + const timer = setTimeout(callback, time || 1000); + this.addEventListener("webkitTransitionEnd", callback); + return timer; + }; + HTMLDivElement.prototype.setPosition = function () { + var position; + if (arguments.length == 4) { + position = []; + for (var i = 0; i < arguments.length; i++) position.push(arguments[i]); + } + else if (arguments.length == 1 && Array.isArray(arguments[0]) && arguments[0].length == 4) { + position = arguments[0]; + } + else { + return this; + } + var top = "calc(" + position[0] + "% "; + if (position[1] > 0) top += "+ " + position[1] + "px)"; + else top += "- " + Math.abs(position[1]) + "px)"; + var left = "calc(" + position[2] + "% "; + if (position[3] > 0) left += "+ " + position[3] + "px)"; + else left += "- " + Math.abs(position[3]) + "px)"; + this.style.top = top; + this.style.left = left; + return this; + }; + HTMLDivElement.prototype.css = function (style) { + for (var i in style) { + if (i == "innerHTML") { + this.innerHTML = style[i]; + } + else { + this.style[i] = style[i]; + } + } + return this; + }; + HTMLTableElement.prototype.get = function (row, col) { + if (row < this.childNodes.length) { + return this.childNodes[row].childNodes[col]; + } + }; + /*处理lib.nature的兼容性问题*/ + const mapHasFunc = function (item) { + return this.has(item) + }; + Object.defineProperty(Map.prototype, "contains", { + configurable: true, + enumerable: false, + writable: true, + value: mapHasFunc + }); + Object.defineProperty(Map.prototype, "includes", { + configurable: true, + enumerable: false, + writable: true, + value: mapHasFunc + }); + const mapAddFunc = function (item) { + this.set(item, 0); + return this; + } + Object.defineProperty(Map.prototype, "add", { + configurable: true, + enumerable: false, + writable: true, + value: mapAddFunc + }); + Object.defineProperty(Map.prototype, "push", { + configurable: true, + enumerable: false, + writable: true, + value: mapAddFunc + }); + Object.defineProperty(Map.prototype, "addArray", { + configurable: true, + enumerable: false, + writable: true, + value: function (arr) { + for (var i = 0; i < arr.length; i++) { + this.add(arr[i]); + } + return this; + } + }); + Object.defineProperty(Map.prototype, "remove", { + configurable: true, + enumerable: false, + writable: true, + value: function (item) { + this.delete(item); + return this; + } + }); + /*Map prototype end*/ + Object.defineProperty(Array.prototype, "filterInD", { + configurable: true, + enumerable: false, + writable: true, + value: function (pos) { + if (typeof pos != "string") pos = "o"; + return this.filter(card => pos.includes(get.position(card, true))); + } + }); + Object.defineProperty(Array.prototype, "someInD", { + configurable: true, + enumerable: false, + writable: true, + value: function (pos) { + if (typeof pos != "string") pos = "o"; + return this.some(card => pos.includes(get.position(card, true))); + } + }); + Object.defineProperty(Array.prototype, "everyInD", { + configurable: true, + enumerable: false, + writable: true, + value: function (pos) { + if (typeof pos != "string") pos = "o"; + return this.every(card => pos.includes(get.position(card, true))); + } + }); + /** + *@legacy Use {@link Array#includes} instead. + */ + Object.defineProperty(Array.prototype, "contains", { + configurable: true, + enumerable: false, + writable: true, + value: Array.prototype.includes + }); + Object.defineProperty(Array.prototype, "containsSome", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + return Array.from(arguments).some(i => this.includes(i)); + } + }); + Object.defineProperty(Array.prototype, "containsAll", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + return Array.from(arguments).every(i => this.includes(i)); + } + }); + + Object.defineProperty(Array.prototype, "add", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + for (const arg of arguments) { + if (this.contains(arg)) continue; + this.push(arg); + } + return this; + } + }); + Object.defineProperty(Array.prototype, "addArray", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + for (const arr of arguments) { + for (const item of arr) this.add(item); + } + return this; + } + }); + Object.defineProperty(Array.prototype, "remove", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + for (const item of arguments) { + let pos = -1; + if (typeof item == "number" && isNaN(item)) { + pos = this.findIndex(v => isNaN(v)) + } else { + pos = this.indexOf(item); + } + if (pos == -1) continue; + this.splice(pos, 1); + } + return this; + } + }); + Object.defineProperty(Array.prototype, "removeArray", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + for (const i of Array.from(arguments)) this.remove(...i); + return this; + } + }); + Object.defineProperty(Array.prototype, "unique", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + let uniqueArray = [...new Set(this)]; + this.length = uniqueArray.length; + for (let i = 0; i < uniqueArray.length; i++) this[i] = uniqueArray[i]; + return this; + } + }); + Object.defineProperty(Array.prototype, "toUniqued", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + return [...new Set(this)]; + } + }); + Object.defineProperty(Array.prototype, "randomGet", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + let arr = this.slice(0); + arr.removeArray(Array.from(arguments)); + return arr[Math.floor(Math.random() * arr.length)]; + } + }); + Object.defineProperty(Array.prototype, "randomGets", { + configurable: true, + enumerable: false, + writable: true, + value: function (num) { + if (num > this.length) num = this.length; + let arr = this.slice(0); + let list = []; + for (let i = 0; i < num; i++) { + list.push(arr.splice(Math.floor(Math.random() * arr.length), 1)[0]); + } + return list; + } + }); + Object.defineProperty(Array.prototype, "randomRemove", { + configurable: true, + enumerable: false, + writable: true, + value: function (num) { + if (typeof num == "number") { + let list = []; + for (let i = 0; i < num; i++) { + if (!this.length) break; + list.push(this.randomRemove()); + } + return list; + } + return this.splice(Math.floor(Math.random() * this.length), 1)[0]; + } + }); + Object.defineProperty(Array.prototype, "randomSort", { + configurable: true, + enumerable: false, + writable: true, + value: function () { + let list = []; + while (this.length) { + list.push(this.randomRemove()); + } + for (let i = 0; i < list.length; i++) { + this.push(list[i]); + } + return this; + } + }); + Object.defineProperty(Array.prototype, "sortBySeat", { + configurable: true, + enumerable: false, + writable: true, + value: function (target) { + lib.tempSortSeat = target; + this.sort(lib.sort.seat); + delete lib.tempSortSeat; + return this; + } + }); + /** + *@description 从数组中寻找某个特征最大的,且通过筛选的第一个元素 + */ + Object.defineProperty(Array.prototype, "maxBy", { + configurable: true, + enumerable: false, + writable: true, + value: function (sortBy, filter) { + let list = this.filter(filter || (() => true)); + if (sortBy && typeof sortBy == "function") list.sort((a, b) => sortBy(a) - sortBy(b)); + else list.sort(); + return list[list.length - 1]; + } + }); + Object.defineProperty(Array.prototype, "minBy", { + configurable: true, + enumerable: false, + writable: true, + value: function (sortBy, filter) { + let list = this.filter(filter || (() => true)); + if (sortBy && typeof sortBy == "function") list.sort((a, b) => sortBy(a) - sortBy(b)); + else list.sort(); + return list[0]; + } + }); + window.onkeydown = function (e) { + if (!ui.menuContainer || !ui.menuContainer.classList.contains("hidden")) { + if (e.keyCode == 116 || ((e.ctrlKey || e.metaKey) && e.keyCode == 82)) { + if (e.shiftKey) { + if (confirm("是否重置游戏?")) { + var noname_inited = localStorage.getItem("noname_inited"); + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem("noname_inited", noname_inited); + } + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + if (indexedDB) indexedDB.deleteDatabase(lib.configprefix + "data"); + game.reload(); + return; + } + } + else { + game.reload(); + } + } + else if (e.keyCode == 83 && (e.ctrlKey || e.metaKey)) { + if (window.saveNonameInput) { + window.saveNonameInput(); + } + e.preventDefault(); + e.stopPropagation(); + return false; + } + else if (e.keyCode == 74 && (e.ctrlKey || e.metaKey) && lib.node) { + lib.node.debug(); + } + } + else { + game.closePopped(); + var dialogs = document.querySelectorAll("#window>.dialog.popped:not(.static)"); + for (var i = 0; i < dialogs.length; i++) { + dialogs[i].delete(); + } + if (e.keyCode == 32) { + var node = ui.window.querySelector("pausedbg"); + if (node) { + node.click(); + } + else { + ui.click.pause(); + } + } + else if (e.keyCode == 65) { + if (ui.auto) ui.auto.click(); + } + else if (e.keyCode == 87) { + if (ui.wuxie && ui.wuxie.style.display != "none") { + ui.wuxie.classList.toggle("glow") + } + else if (ui.tempnowuxie) { + ui.tempnowuxie.classList.toggle("glow") + } + } + else if (e.keyCode == 116 || ((e.ctrlKey || e.metaKey) && e.keyCode == 82)) { + if (e.shiftKey) { + if (confirm("是否重置游戏?")) { + var noname_inited = localStorage.getItem("noname_inited"); + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem("noname_inited", noname_inited); + } + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + if (indexedDB) indexedDB.deleteDatabase(lib.configprefix + "data"); + game.reload(); + return; + } + } + else { + game.reload(); + } + } + else if (e.keyCode == 83 && (e.ctrlKey || e.metaKey)) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + else if (e.keyCode == 74 && (e.ctrlKey || e.metaKey) && lib.node) { + lib.node.debug(); + } + // else if(e.keyCode==27){ + // if(!ui.arena.classList.contains("paused")) ui.click.config(); + // } + } + }; + window.onload = function () { + if (lib.device) { + var script = document.createElement("script"); + script.src = "cordova.js"; + document.body.appendChild(script); + document.addEventListener("deviceready", function () { + if (lib.init.cordovaReady) { + lib.init.cordovaReady(); + delete lib.init.cordovaReady; + } + }); + } + if (_status.packLoaded) { + delete _status.packLoaded; + lib.init.onload(); + } + else { + _status.windowLoaded = true; + } + }; + + window.onerror = function (msg, src, line, column, err) { + const winPath = window.__dirname ? ("file:///" + (__dirname.replace(new RegExp("\\\\", "g"), "/") + "/")) : ""; + let str = `错误文件: ${typeof src == "string" ? decodeURI(src).replace(lib.assetURL, "").replace(winPath, "") : "未知文件"}`; + str += `\n错误信息: ${msg}`; + const tip = lib.getErrorTip(msg); + if (tip) str += `\n错误提示: ${tip}`; + str += `\n行号: ${line}`; + str += `\n列号: ${column}`; + const version = lib.version || ""; + const reg = /[^\d.]/; + const match = version.match(reg) != null; + str += "\n" + `${match ? "游戏" : "无名杀"}版本: ${version || "未知版本"}`; + if (match) str += "\n⚠️您使用的游戏代码不是源于libccy/noname无名杀官方仓库,请自行寻找您所使用的游戏版本开发者反馈!"; + if (_status && _status.event) { + let evt = _status.event; + str += `\nevent.name: ${evt.name}\nevent.step: ${evt.step}`; + if (evt.parent) str += `\nevent.parent.name: ${evt.parent.name}\nevent.parent.step: ${evt.parent.step}`; + if (evt.parent && evt.parent.parent) str += `\nevent.parent.parent.name: ${evt.parent.parent.name}\nevent.parent.parent.step: ${evt.parent.parent.step}`; + if (evt.player || evt.target || evt.source || evt.skill || evt.card) { + str += "\n-------------" + } + if (evt.player) { + if (lib.translate[evt.player.name]) str += `\nplayer: ${lib.translate[evt.player.name]}[${evt.player.name}]`; + else str += "\nplayer: " + evt.player.name; + let distance = get.distance(_status.roundStart, evt.player, "absolute"); + if (distance != Infinity) { + str += `\n座位号: ${distance + 1}`; + } + } + if (evt.target) { + if (lib.translate[evt.target.name]) str += `\ntarget: ${lib.translate[evt.target.name]}[${evt.target.name}]`; + else str += "\ntarget: " + evt.target.name; + } + if (evt.source) { + if (lib.translate[evt.source.name]) str += `\nsource: ${lib.translate[evt.source.name]}[${evt.source.name}]`; + else str += "\nsource: " + evt.source.name; + } + if (evt.skill) { + if (lib.translate[evt.skill]) str += `\nskill: ${lib.translate[evt.skill]}[${evt.skill}]`; + else str += "\nskill: " + evt.skill; + } + if (evt.card) { + if (lib.translate[evt.card.name]) str += `\ncard: ${lib.translate[evt.card.name]}[${evt.card.name}]`; + else str += "\ncard: " + evt.card.name; + } + } + str += "\n-------------"; + if (typeof line == "number" && (typeof game.readFile == "function" || location.origin != "file://")) { + const createShowCode = function (lines) { + let showCode = ""; + if (lines.length >= 10) { + if (line > 4) { + for (let i = line - 5; i < line + 6 && i < lines.length; i++) { + showCode += `${i + 1}| ${line == i + 1 ? "⚠️" : ""}${lines[i]}\n`; + } + } else { + for (let i = 0; i < line + 6 && i < lines.length; i++) { + showCode += `${i + 1}| ${line == i + 1 ? "⚠️" : ""}${lines[i]}\n`; + } + } + } else { + showCode = lines.map((_line, i) => `${i + 1}| ${line == i + 1 ? "⚠️" : ""}${_line}\n`).toString(); + } + return showCode; + } + //协议名须和html一致(网页端防跨域),且文件是js + if (typeof src == "string" && src.startsWith(location.protocol) && src.endsWith(".js")) { + //获取代码 + const codes = lib.init.reqSync("local:" + decodeURI(src).replace(lib.assetURL, "").replace(winPath, "")); + const lines = codes.split("\n"); + str += "\n" + createShowCode(lines); + str += "\n-------------"; + } + //解析parsex里的content fun内容(通常是技能content) + else if (err && err.stack && err.stack.split("\n")[1].trim().startsWith("at Object.eval [as content]")) { + const codes = _status.event.content; + if (typeof codes == "function") { + const lines = codes.toString().split("\n"); + str += "\n" + createShowCode(lines); + str += "\n-------------"; + } + } + } + if (err && err.stack) str += "\n" + decodeURI(err.stack).replace(new RegExp(lib.assetURL, "g"), "").replace(new RegExp(winPath, "g"), ""); + alert(str); + window.ea = Array.from(arguments); + window.em = msg; + window.el = line; + window.ec = column; + window.eo = err; + game.print(str); + if (!lib.config.errstop) { + _status.withError = true; + game.loop(); + } + }; + + if (window.noname_update) { + lib.version = window.noname_update.version; + lib.changeLog = window.noname_update.changeLog; + if (window.noname_update.players) { + lib.changeLog.push("players://" + JSON.stringify(window.noname_update.players)); + } + if (window.noname_update.cards) { + lib.changeLog.push("cards://" + JSON.stringify(window.noname_update.cards)); + } + delete window.noname_update; + } + var noname_inited = localStorage.getItem("noname_inited"); + if (noname_inited && noname_inited !== "nodejs") { + var ua = userAgent; + if (ua.includes("android")) { + lib.device = "android"; + } + else if (ua.includes("iphone") || ua.includes("ipad") || ua.includes("macintosh")) { + lib.device = "ios"; + } + } + + if (lib.assetURL.includes("com.widget.noname.qingyao") || lib.assetURL.includes("online.nonamekill.android")) { + alert("您正在一个不受信任的闭源客户端上运行《无名杀》。建议您更换为其他开源的无名杀客户端,避免给您带来不必要的损失。"); + } + + var config3 = null; + var proceed = function (config2) { + if (config3 === null) { + config3 = config2; + return; + } + if (config2.mode) lib.config.mode = config2.mode; + if (lib.config.mode_config[lib.config.mode] == undefined) lib.config.mode_config[lib.config.mode] = {}; + for (var i in lib.config.mode_config.global) { + if (lib.config.mode_config[lib.config.mode][i] == undefined) { + lib.config.mode_config[lib.config.mode][i] = lib.config.mode_config.global[i]; + } + } + if (lib.config.characters) { + lib.config.defaultcharacters = lib.config.characters.slice(0); + } + if (lib.config.cards) { + lib.config.defaultcards = lib.config.cards.slice(0); + } + for (var i in config2) { + if (i.includes("_mode_config")) { + var thismode = i.substr(i.indexOf("_mode_config") + 13); + if (!lib.config.mode_config[thismode]) { + lib.config.mode_config[thismode] = {}; + } + lib.config.mode_config[thismode][i.substr(0, i.indexOf("_mode_config"))] = config2[i]; + } + else { + lib.config[i] = config2[i]; + } + } + for (var i in lib.config.translate) { + lib.translate[i] = lib.config.translate[i]; + } + + lib.config.all.characters = []; + lib.config.all.cards = []; + lib.config.all.plays = []; + lib.config.all.mode = []; + + if (lib.config.debug) { + lib.init.js(lib.assetURL + "game", "asset", function () { + lib.skin = window.noname_skin_list; + delete window.noname_skin_list; + delete window.noname_asset_list; + }); + } + + if (window.isNonameServer) { + lib.config.mode = "connect"; + } + var pack = window.noname_package; + delete window.noname_package; + for (i in pack.character) { + if (lib.config.all.sgscharacters.contains(i) || lib.config.hiddenCharacterPack.indexOf(i) == -1) { + lib.config.all.characters.push(i); + lib.translate[i + "_character_config"] = pack.character[i]; + } + } + for (i in pack.card) { + if (lib.config.all.sgscards.contains(i) || lib.config.hiddenCardPack.indexOf(i) == -1) { + lib.config.all.cards.push(i); + lib.translate[i + "_card_config"] = pack.card[i]; + } + } + for (i in pack.play) { + lib.config.all.plays.push(i); + lib.translate[i + "_play_config"] = pack.play[i]; + } + for (i in pack.submode) { + for (var j in pack.submode[i]) { + lib.translate[i + "|" + j] = pack.submode[i][j]; + } + } + + if (!lib.config.gameRecord) { + lib.config.gameRecord = {}; + } + for (i in pack.mode) { + if (lib.config.hiddenModePack.indexOf(i) == -1) { + lib.config.all.mode.push(i); + lib.translate[i] = pack.mode[i]; + if (!lib.config.gameRecord[i]) { + lib.config.gameRecord[i] = { data: {} }; + } + } + } + if (lib.config.all.mode.length == 0) { + lib.config.all.mode.push("identity"); + lib.translate.identity = "身份"; + if (!lib.config.gameRecord.identity) { + lib.config.gameRecord.identity = { data: {} }; + } + } + if (pack.background) { + for (i in pack.background) { + if (lib.config.hiddenBackgroundPack.contains(i)) continue; + lib.configMenu.appearence.config.image_background.item[i] = pack.background[i]; + } + for (var i = 0; i < lib.config.customBackgroundPack.length; i++) { + var link = lib.config.customBackgroundPack[i]; + lib.configMenu.appearence.config.image_background.item[link] = link.slice(link.indexOf("_") + 1); + } + lib.configMenu.appearence.config.image_background.item.default = "默认"; + } + if (pack.music) { + if (lib.device || typeof window.require == "function") { + lib.configMenu.audio.config.background_music.item.music_custom = "自定义音乐"; + } + lib.config.all.background_music = ["music_default"]; + for (i in pack.music) { + lib.config.all.background_music.push(i); + lib.configMenu.audio.config.background_music.item[i] = pack.music[i]; + } + if (lib.config.customBackgroundMusic) { + for (i in lib.config.customBackgroundMusic) { + lib.config.all.background_music.push(i); + lib.configMenu.audio.config.background_music.item[i] = lib.config.customBackgroundMusic[i]; + } + } + lib.configMenu.audio.config.background_music.item.music_random = "随机播放"; + lib.configMenu.audio.config.background_music.item.music_off = "关闭"; + } + if (pack.theme) { + for (i in pack.theme) { + lib.configMenu.appearence.config.theme.item[i] = pack.theme[i]; + } + } + if (lib.config.extension_sources) { + for (i in lib.config.extension_sources) { + lib.configMenu.general.config.extension_source.item[i] = i; + } + } + + if (pack.font) { + ui.css.fontsheet = lib.init.sheet(); + const appearenceConfig = lib.configMenu.appearence.config, fontSheet = ui.css.fontsheet.sheet, suitsFont = lib.config.suits_font; + Object.keys(pack.font).forEach(value => { + const font = pack.font[value]; + appearenceConfig.name_font.item[value] = font; + appearenceConfig.identity_font.item[value] = font; + appearenceConfig.cardtext_font.item[value] = font; + appearenceConfig.global_font.item[value] = font; + fontSheet.insertRule(`@font-face {font-family: "${value}"; src: local("${font}"), url("${lib.assetURL}font/${value}.woff2");}`, 0); + if (suitsFont) fontSheet.insertRule(`@font-face {font-family: "${value}"; src: local("${font}"), url("${lib.assetURL}font/suits.woff2");}`, 0); + }); + if (suitsFont) fontSheet.insertRule(`@font-face {font-family: "Suits"; src: url("${lib.assetURL}font/suits.woff2");}`, 0); + fontSheet.insertRule(`@font-face {font-family: "NonameSuits"; src: url("${lib.assetURL}font/suits.woff2");}`, 0); + fontSheet.insertRule(`@font-face {font-family: "MotoyaLMaru"; src: url("${lib.assetURL}font/motoyamaru.woff2");}`, 0) + appearenceConfig.cardtext_font.item.default = "默认"; + appearenceConfig.global_font.item.default = "默认"; + } + + var ua = userAgent; + if ("ontouchstart" in document) { + if (!lib.config.totouched) { + game.saveConfig("totouched", true); + if (lib.device) { + game.saveConfig("low_performance", true); + game.saveConfig("confirm_exit", true); + game.saveConfig("touchscreen", true); + game.saveConfig("fold_mode", false); + if (ua.indexOf("ipad") == -1) { + game.saveConfig("phonelayout", true); + } + else if (lib.device == "ios") { + game.saveConfig("show_statusbar_ios", "overlay"); + } + } + else if (confirm("是否切换到触屏模式?(触屏模式可提高触屏设备的响应速度,但无法使用鼠标)")) { + game.saveConfig("touchscreen", true); + if (ua.includes("iphone") || ua.includes("android")) { + game.saveConfig("phonelayout", true); + } + game.reload(); + } + } + } + else if (lib.config.touchscreen) { + game.saveConfig("touchscreen", false); + } + if (!lib.config.toscrolled && ua.includes("macintosh")) { + game.saveConfig("toscrolled", true); + game.saveConfig("mousewheel", false); + } + + var show_splash = lib.config.show_splash; + if (show_splash == "off") { + show_splash = false; + } + else if (show_splash == "init") { + if (localStorage.getItem("show_splash_off")) { + show_splash = false; + } + } + localStorage.removeItem("show_splash_off"); + var extensionlist = []; + if (!localStorage.getItem(lib.configprefix + "disable_extension")) { + if (lib.config.extensions && lib.config.extensions.length) { + window.resetExtension = function () { + for (var i = 0; i < lib.config.extensions.length; i++) { + game.saveConfig("extension_" + lib.config.extensions[i] + "_enable", false); + } + localStorage.setItem(lib.configprefix + "disable_extension", true); + } + } + for (var i = 0; i < lib.config.plays.length; i++) { + if (lib.config.all.plays.includes(lib.config.plays[i])) { + extensionlist.push(lib.config.plays[i]); + } + } + var alerted = false; + for (var i = 0; i < lib.config.extensions.length; i++) { + if (window.bannedExtensions.contains(lib.config.extensions[i])) { + //if(!alerted) alert("读取某些扩展时出现问题。"); + alerted = true; + continue; + } + var extcontent = localStorage.getItem(lib.configprefix + "extension_" + lib.config.extensions[i]); + if (extcontent) { + //var backup_onload=lib.init.onload; + _status.evaluatingExtension = true; + try { + eval(extcontent); + } + catch (e) { + console.log(e); + } + //lib.init.onload=backup_onload; + _status.evaluatingExtension = false; + } + else if (lib.config.mode != "connect" || (!localStorage.getItem(lib.configprefix + "directstart") && show_splash)) { + extensionlist.push(lib.config.extensions[i]); + } + } + } + else { + if (lib.config.mode != "connect" || (!localStorage.getItem(lib.configprefix + "directstart") && show_splash)) { + var alerted = false; + for (var i = 0; i < lib.config.extensions.length; i++) { + if (window.bannedExtensions.contains(lib.config.extensions[i])) { + //if(!alerted) alert("读取某些扩展时出现问题。"); + alerted = true; + continue; + } + game.import("extension", { name: lib.config.extensions[i] }); + } + } + } + const loadPack = () => { + const isArray = Array.isArray; + if (isArray(lib.onprepare) && lib.onprepare.length) { + _status.onprepare = Object.freeze(lib.onprepare.map(fn => { + if (typeof fn != "function") return; + return (gnc.is.generatorFunc(fn) ? gnc.of(fn) : fn)(); + })); + } + let toLoad = lib.config.all.cards.length + lib.config.all.characters.length + 1; + if (_status.javaScriptExtensions) toLoad += _status.javaScriptExtensions.reduce((constructingToLoad, javaScriptExtension) => { + const lengths = Object.values(javaScriptExtension).reduce((constructingLengths, value) => { + if (isArray(value)) constructingLengths.push(value.length); + return constructingLengths; + }, []); + if (!lengths.length) return constructingToLoad + 1; + return constructingToLoad + Math.min(...lengths); + }, 0); + const packLoaded = gnc.of(function* () { + toLoad--; + if (toLoad) return; + if (_status.importing) { + let promises = lib.creation.array; + for (const type in _status.importing) { + promises.addArray(_status.importing[type]) + } + yield Promise.allSettled(promises); + delete _status.importing; + } + if (_status.windowLoaded) { + delete _status.windowLoaded; + lib.init.onload(); + } + else _status.packLoaded = true; + }); + if (localStorage.getItem(`${lib.configprefix}playback`)) { + toLoad++; + lib.init.js(`${lib.assetURL}mode`, lib.config.mode, packLoaded, packLoaded); + } + else if ((localStorage.getItem(`${lib.configprefix}directstart`) || !show_splash) && lib.config.all.mode.includes(lib.config.mode)) { + toLoad++; + lib.init.js(`${lib.assetURL}mode`, lib.config.mode, packLoaded, packLoaded); + } + lib.init.js(`${lib.assetURL}card`, lib.config.all.cards, packLoaded, packLoaded); + lib.init.js(`${lib.assetURL}character`, lib.config.all.characters, packLoaded, packLoaded); + lib.init.js(`${lib.assetURL}character`, "rank", packLoaded, packLoaded); + if (!_status.javaScriptExtensions) return; + const loadJavaScriptExtension = (javaScriptExtension, pathArray, fileArray, onLoadArray, onErrorArray, index) => { + if (!pathArray && !fileArray && !onLoadArray && !onErrorArray) { + lib.init.js(javaScriptExtension.path, javaScriptExtension.file, () => { + if (typeof javaScriptExtension.onload == "function") javaScriptExtension.onload(); + packLoaded(); + }, () => { + if (typeof javaScriptExtension.onerror == "function") javaScriptExtension.onerror(); + packLoaded(); + }); + return; + } + if (typeof index != "number") index = 0; + if (pathArray && index >= javaScriptExtension.path.length) return; + if (fileArray && index >= javaScriptExtension.file.length) return; + if (onLoadArray && index >= javaScriptExtension.onload.length) return; + if (onErrorArray && index >= javaScriptExtension.onerror.length) return; + const path = pathArray ? javaScriptExtension.path[index] : javaScriptExtension.path; + const file = fileArray ? javaScriptExtension.file[index] : javaScriptExtension.file; + const onLoad = onLoadArray ? javaScriptExtension.onload[index] : javaScriptExtension.onload; + const onError = onErrorArray ? javaScriptExtension.onerror[index] : javaScriptExtension.onerror; + const javaScriptExtensionOnLoad = () => { + if (typeof onLoad == "function") onLoad(); + loadJavaScriptExtension(javaScriptExtension, pathArray, fileArray, onLoadArray, onErrorArray, index + 1); + packLoaded(); + }, jsExtOnError = () => { + if (typeof onError == "function") onError(); + loadJavaScriptExtension(javaScriptExtension, pathArray, fileArray, onLoadArray, onErrorArray, index + 1); + packLoaded(); + }; + lib.init.js(path, file, javaScriptExtensionOnLoad, jsExtOnError); + }; + _status.javaScriptExtensions.forEach(javaScriptExtension => { + const pathArray = isArray(javaScriptExtension.path); + const fileArray = isArray(javaScriptExtension.file); + const onLoadArray = isArray(javaScriptExtension.onLoad); + const onErrorArray = isArray(javaScriptExtension.onError); + loadJavaScriptExtension(javaScriptExtension, pathArray, fileArray, onLoadArray, onErrorArray); + }); + }; + + var layout = lib.config.layout; + if (layout == "default" || lib.layoutfixed.indexOf(lib.config.mode) !== -1) { + layout = "mobile"; + } + if (layout == "phone") { + layout = "mobile"; + game.saveConfig("layout", "mobile"); + game.saveConfig("phonelayout", true); + } + game.layout = layout; + if (lib.config.image_background_random) { + if (_status.htmlbg) { + game.saveConfig("image_background", _status.htmlbg); + } + else { + var list = []; + for (var i in lib.configMenu.appearence.config.image_background.item) { + if (i == "default") continue; + list.push(i); + } + game.saveConfig("image_background", list.randomGet(lib.config.image_background)); + } + lib.init.background(); + } + delete _status.htmlbg; + + window.game = game; + // node:path library alternative + if (typeof module != "object" || typeof module.exports != "object") lib.init.js(`${lib.assetURL}game`, "path", () => { + lib.path = window._noname_path; + delete window._noname_path; + }, e => { + console.log(e); + }); + var styleToLoad = 6; + var styleLoaded = gnc.of(function* () { + --styleToLoad; + if (styleToLoad == 0) { + if (extensionlist.length && (lib.config.mode != "connect" || show_splash)) { + _status.extensionLoading = []; + let extToLoad = extensionlist.length; + const extLoaded = gnc.of(function* () { + --extToLoad; + if (extToLoad == 0) { + yield Promise.allSettled(_status.extensionLoading); + _status.extensionLoaded.filter(Boolean).forEach(name => { + lib.announce.publish("Noname.Init.Extension.onLoad", name); + lib.announce.publish(`Noname.Init.Extension.${name}.onLoad`, void 0); + }); + delete _status.extensionLoading; + loadPack(); + } + }); + //读取扩展 + var alerted = false; + for (var i = 0; i < extensionlist.length; i++) { + if (window.bannedExtensions.contains(extensionlist[i])) { + alerted = true; + --extToLoad; + if (extToLoad == 0) { + yield Promise.allSettled(_status.extensionLoading); + delete _status.extensionLoading; + loadPack(); + } + continue; + } + lib.init.js(lib.assetURL + "extension/" + extensionlist[i], "extension", extLoaded, (function (i) { + return gnc.of(function* () { + game.removeExtension(i); + --extToLoad; + if (extToLoad == 0) { + yield Promise.allSettled(_status.extensionLoading); + delete _status.extensionLoading; + loadPack(); + } + }); + }(extensionlist[i]))); + } + } + else { + loadPack(); + } + } + }); + if (lib.config.layout == "default") { + lib.config.layout = "mobile"; + } + ui.css.layout = lib.init.css(lib.assetURL + "layout/" + layout, "layout", styleLoaded); + if (get.is.phoneLayout()) { + ui.css.phone = lib.init.css(lib.assetURL + "layout/default", "phone", styleLoaded); + } + else { + ui.css.phone = lib.init.css(); + styleToLoad--; + } + ui.css.theme = lib.init.css(lib.assetURL + "theme/" + lib.config.theme, "style", styleLoaded); + ui.css.card_style = lib.init.css(lib.assetURL + "theme/style/card", lib.config.card_style, styleLoaded); + ui.css.cardback_style = lib.init.css(lib.assetURL + "theme/style/cardback", lib.config.cardback_style, styleLoaded); + ui.css.hp_style = lib.init.css(lib.assetURL + "theme/style/hp", lib.config.hp_style, styleLoaded); + + if (lib.config.player_style && lib.config.player_style != "default" && lib.config.player_style != "custom") { + var str = ""; + switch (lib.config.player_style) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood.jpg")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646)"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))"; break; + } + ui.css.player_stylesheet = lib.init.sheet("#window .player{background-image:" + str + "}"); + } + if (lib.config.border_style && lib.config.border_style != "default" && lib.config.border_style != "custom" && lib.config.border_style != "auto") { + ui.css.border_stylesheet = lib.init.sheet(); + var bstyle = lib.config.border_style; + if (bstyle.startsWith("dragon_")) { + bstyle = bstyle.slice(7); + } + ui.css.border_stylesheet.sheet.insertRule(`#window .player>.framebg,#window #arena.long.mobile:not(.fewplayer) .player[data-position="0"]>.framebg{display:block;background-image:url("${lib.assetURL}theme/style/player/${bstyle}1.png")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(`#window #arena.long:not(.fewplayer) .player>.framebg, #arena.oldlayout .player>.framebg{background-image:url("${lib.assetURL}theme/style/player/${bstyle}3.png")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(".player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}", 0); + } + if (lib.config.control_style && lib.config.control_style != "default" && lib.config.control_style != "custom") { + var str = ""; + switch (lib.config.control_style) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood.jpg")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px"; break; + } + if (lib.config.control_style == "wood") { + ui.css.control_stylesheet = lib.init.sheet("#window .control,#window .menubutton,#window #system>div>div,#window #system>div>.pressdown2{background-image:" + str + "}"); + } + else { + ui.css.control_stylesheet = lib.init.sheet("#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:" + str + "}"); + } + } + if (lib.config.menu_style && lib.config.menu_style != "default" && lib.config.menu_style != "custom") { + var str = ""; + switch (lib.config.menu_style) { + case "wood": str = `url("${lib.assetURL}theme/woodden/wood2.png")`; break; + case "music": str = "linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px"; break; + case "simple": str = "linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px"; break; + } + ui.css.menu_stylesheet = lib.init.sheet("html #window>.dialog.popped,html .menu,html .menubg{background-image:" + str + "}"); + } + + lib.config.duration = 500; + + if (!lib.config.touchscreen) { + document.addEventListener("mousewheel", ui.click.windowmousewheel, { passive: true }); + document.addEventListener("mousemove", ui.click.windowmousemove); + document.addEventListener("mousedown", ui.click.windowmousedown); + document.addEventListener("mouseup", ui.click.windowmouseup); + document.addEventListener("contextmenu", ui.click.right); + } + else { + document.addEventListener("touchstart", ui.click.touchconfirm); + document.addEventListener("touchstart", ui.click.windowtouchstart); + document.addEventListener("touchend", ui.click.windowtouchend); + document.addEventListener("touchmove", ui.click.windowtouchmove); + } + }; + var proceed2 = () => { + if (config3) { + proceed(config3); + } + else { + config3 = true; + } + }; + + ui.css = { + menu: lib.init.css(lib.assetURL + "layout/default", "menu", function () { + ui.css.default = lib.init.css(lib.assetURL + "layout/default", "layout"); + proceed2(); + }) + }; + + if (lib.device) { + lib.init.cordovaReady = function () { + if (lib.device == "android") { + document.addEventListener("pause", function () { + if (!_status.paused2 && (typeof _status.event.isMine == "function" && !_status.event.isMine())) { + ui.click.pause(); + } + if (ui.backgroundMusic) { + ui.backgroundMusic.pause(); + } + }); + document.addEventListener("resume", () => { + if (ui.backgroundMusic) ui.backgroundMusic.play(); + }); + document.addEventListener("backbutton", function () { + if (ui.arena && ui.arena.classList.contains("menupaused")) { + if (window.saveNonameInput) { + window.saveNonameInput(); + } + else { + ui.click.configMenu(); + } + } + else if (lib.config.confirm_exit) { + navigator.notification.confirm( + "是否退出游戏?", + function (index) { + switch (index) { + case 2: game.reload(); break; + case 3: navigator.app.exitApp(); break; + } + }, + "确认退出", + ["取消", "重新开始", "退出"] + ); + } + else { + navigator.app.exitApp(); + } + }); + if ("cordova" in window && "plugins" in window.cordova && "permissions" in window.cordova.plugins) { + const permissions = cordova.plugins.permissions; + const requests = ["WRITE_EXTERNAL_STORAGE", "READ_EXTERNAL_STORAGE"] + requests.forEach(request => { + permissions.checkPermission(permissions[request], status => { + if (!status.hasPermission) { + permissions.requestPermission(permissions[request], lib.other.ignore, lib.other.ignore); + } + }, lib.other.ignore); + }); + } + } + game.download = function (url, folder, onsuccess, onerror, dev, onprogress) { + if (!url.startsWith("http")) { + url = get.url(dev) + url; + } + var fileTransfer = new FileTransfer(); + folder = lib.assetURL + folder; + if (onprogress) { + fileTransfer.onprogress = function (progressEvent) { + onprogress(progressEvent.loaded, progressEvent.total); + }; + } + lib.config.brokenFile.add(folder); + game.saveConfigValue("brokenFile"); + fileTransfer.download(encodeURI(url), encodeURI(folder), function () { + lib.config.brokenFile.remove(folder); + game.saveConfigValue("brokenFile"); + if (onsuccess) { + onsuccess(); + } + }, onerror); + }; + game.readFile = function (filename, callback, onerror) { + window.resolveLocalFileSystemURL(lib.assetURL, function (entry) { + entry.getFile(filename, {}, function (fileEntry) { + fileEntry.file(function (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + callback(e.target.result); + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }, onerror); + }, onerror); + }, onerror); + }; + game.readFileAsText = function (filename, callback, onerror) { + window.resolveLocalFileSystemURL(lib.assetURL, function (entry) { + entry.getFile(filename, {}, function (fileEntry) { + fileEntry.file(function (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + callback(e.target.result); + }; + fileReader.readAsText(fileToLoad, "UTF-8"); + }, onerror); + }, onerror); + }, onerror); + }; + game.writeFile = function (data, path, name, callback) { + game.ensureDirectory(path, function () { + if (Object.prototype.toString.call(data) == "[object File]") { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + game.writeFile(e.target.result, path, name, callback); + }; + fileReader.readAsArrayBuffer(data, "UTF-8"); + } + else { + window.resolveLocalFileSystemURL(lib.assetURL + path, function (entry) { + entry.getFile(name, { create: true }, function (fileEntry) { + fileEntry.createWriter(function (fileWriter) { + fileWriter.onwriteend = callback; + fileWriter.write(data); + }, callback); + }, callback); + }, callback); + } + }); + }; + game.removeFile = function (dir, callback) { + window.resolveLocalFileSystemURL(lib.assetURL, function (entry) { + entry.getFile(dir, {}, function (fileEntry) { + fileEntry.remove(); + if (callback) callback(); + }, callback || (() => void 0)); + }, callback || (() => void 0)); + }; + game.getFileList = (dir, success, failure) => { + var files = [], folders = []; + window.resolveLocalFileSystemURL(lib.assetURL + dir, entry => { + var dirReader = entry.createReader(); + var entries = []; + var readEntries = () => { + dirReader.readEntries(results => { + if (!results.length) { + entries.sort(); + for (var i = 0; i < entries.length; i++) { + if (entries[i].isDirectory) { + folders.push(entries[i].name); + } + else { + files.push(entries[i].name); + } + } + success(folders, files); + } + else { + entries = entries.concat(Array.from(results)); + readEntries(); + } + }, failure); + }; + readEntries(); + }, failure); + }; + game.ensureDirectory = (list, callback, file) => { + const directoryList = typeof list == "string" ? [list] : list.slice().reverse(), num = file ? 1 : 0, access = (entry, directory, createDirectory) => { + if (directory.length <= num) { + createDirectory(); + return; + } + const str = directory.pop(); + return new Promise((resolve, reject) => entry.getDirectory(str, { + create: false + }, resolve, reject)).catch(() => new Promise(resolve => entry.getDirectory(str, { + create: true + }, resolve))).then(directoryEntry => access(directoryEntry, directory, createDirectory)); + }; + return new Promise((resolve, reject) => window.resolveLocalFileSystemURL(lib.assetURL, rootEntry => { + const createDirectory = () => { + if (directoryList.length) access(rootEntry, directoryList.pop().split("/").reverse(), createDirectory); + if (typeof callback == "function") callback(); + resolve(); + }; + createDirectory(); + }, reject)); + }; + if (ui.updateUpdate) { + ui.updateUpdate(); + } + var showbar = function () { + if (window.StatusBar) { + if (lib.device == "android") { + if (lib.config.show_statusbar_android) { + window.StatusBar.overlaysWebView(false); + window.StatusBar.backgroundColorByName("black"); + window.StatusBar.show(); + } + } + else if (lib.device == "ios") { + if (lib.config.show_statusbar_ios != "off" && lib.config.show_statusbar_ios != "auto") { + if (lib.config.show_statusbar_ios == "default") { + window.StatusBar.overlaysWebView(false); + } + else { + window.StatusBar.overlaysWebView(true); + } + window.StatusBar.backgroundColorByName("black"); + window.StatusBar.show(); + } + } + } + } + if (lib.arenaReady) { + lib.arenaReady.push(showbar); + } + else { + showbar(); + } + }; + } + else if (typeof window.require == "function") { + lib.node = { + fs: require("fs"), + path: require("path"), + debug: function () { + require("electron").remote.getCurrentWindow().toggleDevTools(); + } + }; + lib.path = lib.node.path; + game.download = function (url, folder, onsuccess, onerror, dev, onprogress) { + if (!url.startsWith("http")) { + url = get.url(dev) + url; + } + game.ensureDirectory(folder, function () { + try { + var file = lib.node.fs.createWriteStream(__dirname + "/" + folder); + } + catch (e) { + onerror(); + } + lib.config.brokenFile.add(folder); + game.saveConfigValue("brokenFile"); + if (!lib.node.http) lib.node.http = require("http"); + if (!lib.node.https) lib.node.https = require("https"); + var opts = require("url").parse(encodeURI(url)); + opts.headers = { "User-Agent": "AppleWebkit" }; + (url.startsWith("https") ? lib.node.https : lib.node.http).get(opts, function (response) { + var stream = response.pipe(file); + stream.on("finish", function () { + lib.config.brokenFile.remove(folder); + game.saveConfigValue("brokenFile"); + if (onsuccess) { + onsuccess(); + } + }); + stream.on("error", onerror); + if (onprogress) { + var streamInterval = setInterval(function () { + if (stream.closed) { + clearInterval(streamInterval); + } + else { + onprogress(stream.bytesWritten); + } + }, 200); + } + }); + }, true); + }; + game.readFile = function (filename, callback, onerror) { + lib.node.fs.readFile(__dirname + "/" + filename, function (err, data) { + if (err) { + onerror(err); + } + else { + callback(data); + } + }); + }; + game.readFileAsText = function (filename, callback, onerror) { + lib.node.fs.readFile(__dirname + "/" + filename, "utf-8", function (err, data) { + if (err) { + onerror(err); + } + else { + callback(data); + } + }); + }; + game.writeFile = function (data, path, name, callback) { + game.ensureDirectory(path, function () { + if (Object.prototype.toString.call(data) == "[object File]") { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + game.writeFile(e.target.result, path, name, callback); + }; + fileReader.readAsArrayBuffer(data, "UTF-8"); + } + else { + get.zip(function (zip) { + zip.file("i", data); + lib.node.fs.writeFile(__dirname + "/" + path + "/" + name, zip.files.i.asNodeBuffer(), null, callback); + }); + } + }); + }; + game.removeFile = function (filename, callback) { + lib.node.fs.unlink(__dirname + "/" + filename, callback || (() => void 0)); + }; + game.getFileList = (dir, success, failure) => { + var files = [], folders = []; + dir = __dirname + "/" + dir; + if (typeof failure == "undefined") { + failure = err => { + throw err; + }; + } + else if (failure == null) { + failure = () => void 0; + } + try { + lib.node.fs.readdir(dir, (err, filelist) => { + if (err) { + failure(err); + return; + } + for (var i = 0; i < filelist.length; i++) { + if (filelist[i][0] != "." && filelist[i][0] != "_") { + if (lib.node.fs.statSync(dir + "/" + filelist[i]).isDirectory()) { + folders.push(filelist[i]); + } + else { + files.push(filelist[i]); + } + } + } + success(folders, files); + }); + } + catch (e) { + failure(e); + } + }; + game.ensureDirectory = (list, callback, file) => { + const directoryList = typeof list == "string" ? [list] : list.slice().reverse(), number = file ? 1 : 0, access = (path, directory, createDirectory) => { + if (directory.length <= number) { + createDirectory(); + return; + } + path += `/${directory.pop()}`; + const fullPath = `${__dirname}${path}`; + return new Promise((resolve, reject) => lib.node.fs.access(fullPath, errnoException => { + if (errnoException) reject(); + else resolve(); + })).catch(() => new Promise((resolve, reject) => lib.node.fs.mkdir(fullPath, errnoException => { + if (errnoException) reject(errnoException); + else resolve(); + }))).then(() => access(path, directory, createDirectory), console.log); + }; + return new Promise(resolve => { + const createDirectory = () => { + if (directoryList.length) access("", directoryList.pop().split("/").reverse(), createDirectory); + else { + if (typeof callback == "function") callback(); + resolve(); + } + }; + createDirectory(); + }); + }; + if (ui.updateUpdate) { + ui.updateUpdate(); + } + } + else { + //为其他自定义平台提供文件读写函数赋值的一种方式。 + //但这种方式只能修改game的文件读写函数。 + if (window.initReadWriteFunction) { + const g = {}; + const ReadWriteFunctionName = ["download", "readFile", "readFileAsText", "writeFile", "removeFile", "getFileList", "ensureDirectory", "createDir"]; + ReadWriteFunctionName.forEach(prop => { + Object.defineProperty(g, prop, { + configurable: true, + get() { return undefined; }, + set(newValue) { + if (typeof newValue == "function") { + delete g[prop]; + g[prop] = game[prop] = newValue; + } + } + }) + }); + window.initReadWriteFunction(g); + } + window.onbeforeunload = function () { + if (lib.config.confirm_exit && !_status.reloading) { + return "是否离开游戏?" + } + else { + return null; + } + }; + } + + lib.config = window.config; + lib.configOL = {}; + delete window.config; + let config2; + if (localStorage.getItem(`${lib.configprefix}nodb`)) window.nodb = true; + if (window.indexedDB && !window.nodb) new Promise((resolve, reject) => { + const idbOpenDBRequest = window.indexedDB.open(`${lib.configprefix}data`, 4); + idbOpenDBRequest.onerror = reject; + idbOpenDBRequest.onsuccess = resolve; + idbOpenDBRequest.onupgradeneeded = idbVersionChangeEvent => { + const idbDatabase = idbVersionChangeEvent.target.result; + if (!idbDatabase.objectStoreNames.contains("video")) idbDatabase.createObjectStore("video", { + keyPath: "time" + }); + if (!idbDatabase.objectStoreNames.contains("image")) idbDatabase.createObjectStore("image"); + if (!idbDatabase.objectStoreNames.contains("audio")) idbDatabase.createObjectStore("audio"); + if (!idbDatabase.objectStoreNames.contains("config")) idbDatabase.createObjectStore("config"); + if (!idbDatabase.objectStoreNames.contains("data")) idbDatabase.createObjectStore("data"); + }; + }).then(event => { + lib.db = event.target.result; + return game.getDB("config"); + }).then(object => { + if (!object.storageImported) { + try { + config2 = JSON.parse(localStorage.getItem(`${lib.configprefix}config`)); + if (!config2 || typeof config2 != "object") throw "err"; + } + catch (err) { + config2 = {}; + } + Object.keys(config2).forEach(key => game.saveConfig(key, config2[key])); + Object.keys(lib.mode).forEach(key => { + try { + config2 = JSON.parse(localStorage.getItem(`${lib.configprefix}${key}`)); + if (!config2 || typeof config2 != "object" || get.is.empty(config2)) throw "err"; + } + catch (err) { + config2 = false; + } + localStorage.removeItem(`${lib.configprefix}${key}`); + if (config2) game.putDB("data", key, config2); + }); + game.saveConfig("storageImported", true); + lib.init.background(); + localStorage.removeItem(`${lib.configprefix}config`); + } + else config2 = object; + proceed(config2); + }); + else { + try { + config2 = JSON.parse(localStorage.getItem(lib.configprefix + "config")); + if (!config2 || typeof config2 != "object") throw "err" + } + catch (err) { + config2 = {}; + localStorage.setItem(lib.configprefix + "config", JSON.stringify({})); + } + proceed(config2); + } + } + + static reset() { + if (window.inSplash) return; + if (window.resetExtension) { + if (confirm("游戏似乎未正常载入,有可能因为部分扩展未正常载入,或者因为部分扩展未载入完毕。\n是否禁用扩展并重新打开?")) { + window.resetExtension(); + window.location.reload(); + } + } + else { + if (lib.device) { + if (navigator.notification) { + navigator.notification.confirm( + "游戏似乎未正常载入,是否重置游戏?", + function (index) { + if (index == 2) { + localStorage.removeItem("noname_inited"); + window.location.reload(); + } + else if (index == 3) { + var noname_inited = localStorage.getItem("noname_inited"); + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem("noname_inited", noname_inited); + } + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + if (indexedDB) indexedDB.deleteDatabase(lib.configprefix + "data"); + setTimeout(function () { + window.location.reload(); + }, 200); + } + }, + "确认退出", + ["取消", "重新下载", "重置设置"] + ); + } + else { + if (confirm("游戏似乎未正常载入,是否重置游戏?")) { + localStorage.removeItem("noname_inited"); + window.location.reload(); + } + } + } + else { + if (confirm("游戏似乎未正常载入,是否重置游戏?")) { + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + if (indexedDB) indexedDB.deleteDatabase(lib.configprefix + "data"); + setTimeout(function () { + window.location.reload(); + }, 200); + } + } + } + } + + static onload = gnc.of(function* () { + const libOnload = lib.onload; + delete lib.onload; + while (Array.isArray(libOnload) && libOnload.length) { + const fun = libOnload.shift(); + if (typeof fun != "function") continue; + yield (gnc.is.generatorFunc(fun) ? gnc.of(fun) : fun)(); + } + ui.updated(); + game.documentZoom = game.deviceZoom; + if (game.documentZoom != 1) { + ui.updatez(); + } + ui.background = ui.create.div(".background"); + ui.background.style.backgroundSize = "cover"; + ui.background.style.backgroundPosition = "50% 50%"; + if (lib.config.image_background && lib.config.image_background != "default" && !lib.config.image_background.startsWith("custom_")) { + ui.background.setBackgroundImage("image/background/" + lib.config.image_background + ".jpg"); + if (lib.config.image_background_blur) { + ui.background.style.filter = "blur(8px)"; + ui.background.style.webkitFilter = "blur(8px)"; + ui.background.style.transform = "scale(1.05)"; + } + } + document.documentElement.style.backgroundImage = ""; + document.documentElement.style.backgroundSize = ""; + document.documentElement.style.backgroundPosition = ""; + document.body.insertBefore(ui.background, document.body.firstChild); + document.body.onresize = ui.updatexr; + if (lib.config.touchscreen) { + document.body.addEventListener("touchstart", function (e) { + this.startX = e.touches[0].clientX / game.documentZoom; + this.startY = e.touches[0].clientY / game.documentZoom; + _status.dragged = false; + }); + document.body.addEventListener("touchmove", function (e) { + if (_status.dragged) return; + if (Math.abs(e.touches[0].clientX / game.documentZoom - this.startX) > 10 || + Math.abs(e.touches[0].clientY / game.documentZoom - this.startY) > 10) { + _status.dragged = true; + } + }); + } + + if (lib.config.image_background.startsWith("custom_")) { + ui.background.style.backgroundImage = "none"; + game.getDB("image", lib.config.image_background, function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + ui.background.style.backgroundImage = "url(" + data + ")"; + if (lib.config.image_background_blur) { + ui.background.style.filter = "blur(8px)"; + ui.background.style.webkitFilter = "blur(8px)"; + ui.background.style.transform = "scale(1.05)"; + } + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.card_style == "custom") { + game.getDB("image", "card_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.card_stylesheet) { + ui.css.card_stylesheet.remove(); + } + ui.css.card_stylesheet = lib.init.sheet(".card:not(*:empty){background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.cardback_style == "custom") { + game.getDB("image", "cardback_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.cardback_stylesheet) { + ui.css.cardback_stylesheet.remove(); + } + ui.css.cardback_stylesheet = lib.init.sheet(".card:empty,.card.infohidden{background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "cardback_style2", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.cardback_stylesheet2) { + ui.css.cardback_stylesheet2.remove(); + } + ui.css.cardback_stylesheet2 = lib.init.sheet(".card.infohidden:not(.infoflip){background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.hp_style == "custom") { + game.getDB("image", "hp_style1", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet1) { + ui.css.hp_stylesheet1.remove(); + } + ui.css.hp_stylesheet1 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="high"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style2", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet2) { + ui.css.hp_stylesheet2.remove(); + } + ui.css.hp_stylesheet2 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="mid"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style3", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet3) { + ui.css.hp_stylesheet3.remove(); + } + ui.css.hp_stylesheet3 = lib.init.sheet(`.hp:not(.text):not(.actcount)[data-condition="low"]>div:not(.lost){background-image:url(${fileLoadedEvent.target.result})}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + game.getDB("image", "hp_style4", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.hp_stylesheet4) { + ui.css.hp_stylesheet4.remove(); + } + ui.css.hp_stylesheet4 = lib.init.sheet(".hp:not(.text):not(.actcount)>.lost{background-image:url(" + fileLoadedEvent.target.result + ")}"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.player_style == "custom") { + ui.css.player_stylesheet = lib.init.sheet("#window .player{background-image:none;background-size:100% 100%;}"); + game.getDB("image", "player_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.player_stylesheet) { + ui.css.player_stylesheet.remove(); + } + ui.css.player_stylesheet = lib.init.sheet(`#window .player{background-image:url("${fileLoadedEvent.target.result}");background-size:100% 100%;}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.border_style == "custom") { + game.getDB("image", "border_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.border_stylesheet) { + ui.css.border_stylesheet.remove(); + } + ui.css.border_stylesheet = lib.init.sheet(); + ui.css.border_stylesheet.sheet.insertRule(`#window .player>.framebg{display:block;background-image:url("${fileLoadedEvent.target.result}")}`, 0); + ui.css.border_stylesheet.sheet.insertRule(".player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}", 0); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.control_style == "custom") { + game.getDB("image", "control_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.control_stylesheet) { + ui.css.control_stylesheet.remove(); + } + ui.css.control_stylesheet = lib.init.sheet(`#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:url("${fileLoadedEvent.target.result}")}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + if (lib.config.menu_style == "custom") { + game.getDB("image", "menu_style", function (fileToLoad) { + if (!fileToLoad) return; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + if (ui.css.menu_stylesheet) { + ui.css.menu_stylesheet.remove(); + } + ui.css.menu_stylesheet = lib.init.sheet(`html #window>.dialog.popped,html .menu,html .menubg{background-image:url("${fileLoadedEvent.target.result}");background-size:cover}`); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + }); + } + + var proceed2 = gnc.of(function* () { + var mode = lib.imported.mode; + var card = lib.imported.card; + var character = lib.imported.character; + var play = lib.imported.play; + delete window.game; + var i, j, k; + for (i in mode[lib.config.mode].element) { + if (!lib.element[i]) lib.element[i] = []; + for (j in mode[lib.config.mode].element[i]) { + if (j == "init") { + if (!lib.element[i].inits) lib.element[i].inits = []; + lib.element[i].inits.push(mode[lib.config.mode].element[i][j]); + } + else { + lib.element[i][j] = mode[lib.config.mode].element[i][j]; + } + } + } + for (i in mode[lib.config.mode].ai) { + if (typeof mode[lib.config.mode].ai[i] == "object") { + if (ai[i] == undefined) ai[i] = {}; + for (j in mode[lib.config.mode].ai[i]) { + ai[i][j] = mode[lib.config.mode].ai[i][j]; + } + } + else { + ai[i] = mode[lib.config.mode].ai[i]; + } + } + for (i in mode[lib.config.mode].ui) { + if (typeof mode[lib.config.mode].ui[i] == "object") { + if (ui[i] == undefined) ui[i] = {}; + for (j in mode[lib.config.mode].ui[i]) { + ui[i][j] = mode[lib.config.mode].ui[i][j]; + } + } + else { + ui[i] = mode[lib.config.mode].ui[i]; + } + } + for (i in mode[lib.config.mode].game) { + game[i] = mode[lib.config.mode].game[i]; + } + for (i in mode[lib.config.mode].get) { + get[i] = mode[lib.config.mode].get[i]; + } + lib.init.start = mode[lib.config.mode].start; + lib.init.startBefore = mode[lib.config.mode].startBefore; + if (game.onwash) { + lib.onwash.push(game.onwash); + delete game.onwash; + } + if (game.onover) { + lib.onover.push(game.onover); + delete game.onover; + } + lib.config.banned = lib.config[lib.config.mode + "_banned"] || []; + lib.config.bannedcards = lib.config[lib.config.mode + "_bannedcards"] || []; + + lib.rank = window.noname_character_rank; + delete window.noname_character_rank; + for (i in mode[lib.config.mode]) { + if (i == "element") continue; + if (i == "game") continue; + if (i == "ai") continue; + if (i == "ui") continue; + if (i == "get") continue; + if (i == "config") continue; + if (i == "onreinit") continue; + if (i == "start") continue; + if (i == "startBefore") continue; + if (lib[i] == undefined) lib[i] = (Array.isArray(mode[lib.config.mode][i])) ? [] : {}; + for (j in mode[lib.config.mode][i]) { + lib[i][j] = mode[lib.config.mode][i][j]; + } + } + if (typeof mode[lib.config.mode].init == "function") { + mode[lib.config.mode].init(); + } + + var connectCharacterPack = []; + var connectCardPack = []; + for (i in character) { + if (character[i].character) { + const characterPack = lib.characterPack[i]; + if (characterPack) Object.assign(characterPack, character[i].character); + else lib.characterPack[i] = character[i].character; + } + for (j in character[i]) { + if (j == "mode" || j == "forbid") continue; + if (j == "connect") { + connectCharacterPack.push(i); + continue; + } + if (j == "character" && !lib.config.characters.contains(i) && lib.config.mode != "connect") { + if (lib.config.mode == "chess" && get.config("chess_mode") == "leader" && get.config("chess_leader_allcharacter")) { + for (k in character[i][j]) { + lib.hiddenCharacters.push(k); + } + } + else if (lib.config.mode != "boss" || i != "boss") { + continue; + } + } + if (Array.isArray(lib[j]) && Array.isArray(character[i][j])) { + lib[j].addArray(character[i][j]); + continue; + } + for (k in character[i][j]) { + if (j == "character") { + if (!character[i][j][k][4]) { + character[i][j][k][4] = []; + } + if (character[i][j][k][4].contains("boss") || + character[i][j][k][4].contains("hiddenboss")) { + lib.config.forbidai.add(k); + } + if (lib.config.forbidai_user && lib.config.forbidai_user.contains(k)) { + lib.config.forbidai.add(k); + } + for (var l = 0; l < character[i][j][k][3].length; l++) { + lib.skilllist.add(character[i][j][k][3][l]); + } + } + if (j == "skill" && k[0] == "_" && (lib.config.mode != "connect" ? (!lib.config.characters.contains(i)) : (!character[i].connect))) { + continue; + } + if (j == "translate" && k == i) { + lib[j][k + "_character_config"] = character[i][j][k]; + } + else { + if (lib[j][k] == undefined) { + if (j == "skill" && !character[i][j][k].forceLoad && lib.config.mode == "connect" && !character[i].connect) { + lib[j][k] = { + nopop: character[i][j][k].nopop, + derivation: character[i][j][k].derivation + }; + } + else { + Object.defineProperty(lib[j], k, Object.getOwnPropertyDescriptor(character[i][j], k)); + } + if (j == "card" && lib[j][k].derivation) { + if (!lib.cardPack.mode_derivation) { + lib.cardPack.mode_derivation = [k]; + } + else { + lib.cardPack.mode_derivation.push(k); + } + } + } + else if (Array.isArray(lib[j][k]) && Array.isArray(character[i][j][k])) { + lib[j][k].addArray(character[i][j][k]); + } + else { + console.log( + `dublicate ${j} in character ${i}:\n${k}:\nlib.${j}.${k}`, + lib[j][k], + `\ncharacter.${i}.${j}.${k}`, + character[i][j][k] + ); + } + } + } + } + } + var connect_avatar_list = []; + for (var i in lib.character) { + connect_avatar_list.push(i); + } + connect_avatar_list.sort(lib.sort.capt); + for (var i = 0; i < connect_avatar_list.length; i++) { + var ia = connect_avatar_list[i]; + lib.mode.connect.config.connect_avatar.item[ia] = lib.translate[ia]; + } + if (lib.config.mode != "connect") { + var pilecfg = lib.config.customcardpile[get.config("cardpilename") || "当前牌堆"]; + if (pilecfg) { + lib.config.bannedpile = get.copy(pilecfg[0] || {}); + lib.config.addedpile = get.copy(pilecfg[1] || {}); + } + else { + lib.config.bannedpile = {}; + lib.config.addedpile = {}; + } + } + else { + lib.cardPackList = {}; + } + for (i in card) { + const cardPack = lib.cardPack[i] ? lib.cardPack[i] : lib.cardPack[i] = []; + if (card[i].card) { + for (var j in card[i].card) { + if (!card[i].card[j].hidden && card[i].translate[j + "_info"]) { + cardPack.push(j); + } + } + } + for (j in card[i]) { + if (j == "mode" || j == "forbid") continue; + if (j == "connect") { + connectCardPack.push(i); + continue; + } + if (j == "list") { + if (lib.config.mode == "connect") { + const cardPackList = lib.cardPackList[i]; + if (cardPackList) cardPackList.addArray(card[i][j]); + else lib.cardPackList[i] = card[i][j]; + } + else { + if (lib.config.cards.contains(i)) { + var pile; + if (typeof card[i][j] == "function") { + pile = card[i][j](); + } + else { + pile = card[i][j]; + } + const cardPile = lib.cardPile[i]; + if (cardPile) cardPile.addArray(pile); + else lib.cardPile[i] = pile.slice(0); + if (lib.config.bannedpile[i]) { + for (var k = 0; k < lib.config.bannedpile[i].length; k++) { + pile[lib.config.bannedpile[i][k]] = null; + } + } + for (var k = 0; k < pile.length; k++) { + if (!pile[k]) { + pile.splice(k--, 1); + } + } + if (lib.config.addedpile[i]) { + for (var k = 0; k < lib.config.addedpile[i].length; k++) { + pile.push(lib.config.addedpile[i][k]); + } + } + lib.card.list.addArray(pile); + } + } + } + else { + for (k in card[i][j]) { + if (j == "skill" && k[0] == "_" && !card[i][j][k].forceLoad && (lib.config.mode != "connect" ? (!lib.config.cards.contains(i)) : (!card[i].connect))) { + continue; + } + if (j == "translate" && k == i) { + lib[j][k + "_card_config"] = card[i][j][k]; + } + else { + if (lib[j][k] == undefined) { + if (j == "skill" && !card[i][j][k].forceLoad && lib.config.mode == "connect" && !card[i].connect) { + lib[j][k] = { + nopop: card[i][j][k].nopop, + derivation: card[i][j][k].derivation + }; + } + else { + Object.defineProperty(lib[j], k, Object.getOwnPropertyDescriptor(card[i][j], k)); + } + } + else { + console.log( + `dublicate ${j} in card ${i}:\n${k}:\nlib.${j}.${k}`, + lib[j][k], + `\ncard.${i}.${j}.${k}`, + card[i][j][k] + ); + } + if (j == "card" && lib[j][k].derivation) { + if (!lib.cardPack.mode_derivation) { + lib.cardPack.mode_derivation = [k]; + } + else { + lib.cardPack.mode_derivation.push(k); + } + } + } + } + } + } + } + if (lib.cardPack.mode_derivation) { + for (var i = 0; i < lib.cardPack.mode_derivation.length; i++) { + if (typeof lib.card[lib.cardPack.mode_derivation[i]].derivation == "string" && !lib.character[lib.card[lib.cardPack.mode_derivation[i]].derivation]) { + lib.cardPack.mode_derivation.splice(i--, 1); + } + else if (typeof lib.card[lib.cardPack.mode_derivation[i]].derivationpack == "string" && !lib.config.cards.contains(lib.card[lib.cardPack.mode_derivation[i]].derivationpack)) { + lib.cardPack.mode_derivation.splice(i--, 1); + } + } + if (lib.cardPack.mode_derivation.length == 0) { + delete lib.cardPack.mode_derivation; + } + } + if (lib.config.mode != "connect") { + for (i in play) { + if (lib.config.hiddenPlayPack.contains(i)) continue; + if (play[i].forbid && play[i].forbid.contains(lib.config.mode)) continue; + if (play[i].mode && play[i].mode.contains(lib.config.mode) == false) continue; + for (j in play[i].element) { + if (!lib.element[j]) lib.element[j] = []; + for (k in play[i].element[j]) { + if (k == "init") { + if (!lib.element[j].inits) lib.element[j].inits = []; + lib.element[j].inits.push(play[i].element[j][k]); + } + else { + lib.element[j][k] = play[i].element[j][k]; + } + } + } + for (j in play[i].ui) { + if (typeof play[i].ui[j] == "object") { + if (ui[j] == undefined) ui[j] = {}; + for (k in play[i].ui[j]) { + ui[j][k] = play[i].ui[j][k]; + } + } + else { + ui[j] = play[i].ui[j]; + } + } + for (j in play[i].game) { + game[j] = play[i].game[j]; + } + for (j in play[i].get) { + get[j] = play[i].get[j]; + } + for (j in play[i]) { + if (j == "mode" || j == "forbid" || j == "init" || j == "element" || + j == "game" || j == "get" || j == "ui" || j == "arenaReady") continue; + for (k in play[i][j]) { + if (j == "translate" && k == i) { + // lib[j][k+"_play_config"]=play[i][j][k]; + } + else { + if (lib[j][k] != undefined) { + console.log( + `dublicate ${j} in play ${i}:\n${k}:\nlib.${j}.${k}`, + lib[j][k], + `\nplay.${i}.${j}.${k}`, + play[i][j][k] + ); + } + lib[j][k] = play[i][j][k]; + } + } + } + if (typeof play[i].init == "function") play[i].init(); + if (typeof play[i].arenaReady == "function") lib.arenaReady.push(play[i].arenaReady); + } + } + + lib.connectCharacterPack = []; + lib.connectCardPack = []; + for (var i = 0; i < lib.config.all.characters.length; i++) { + var packname = lib.config.all.characters[i]; + if (connectCharacterPack.contains(packname)) { + lib.connectCharacterPack.push(packname) + } + } + for (var i = 0; i < lib.config.all.cards.length; i++) { + var packname = lib.config.all.cards[i]; + if (connectCardPack.contains(packname)) { + lib.connectCardPack.push(packname) + } + } + if (lib.config.mode != "connect") { + for (i = 0; i < lib.card.list.length; i++) { + if (lib.card.list[i][2] == "huosha") { + lib.card.list[i] = lib.card.list[i].slice(0); + lib.card.list[i][2] = "sha"; + lib.card.list[i][3] = "fire"; + } + else if (lib.card.list[i][2] == "leisha") { + lib.card.list[i] = lib.card.list[i].slice(0); + lib.card.list[i][2] = "sha"; + lib.card.list[i][3] = "thunder"; + } + if (!lib.card[lib.card.list[i][2]]) { + lib.card.list.splice(i, 1); i--; + } + else if (lib.card[lib.card.list[i][2]].mode && + lib.card[lib.card.list[i][2]].mode.contains(lib.config.mode) == false) { + lib.card.list.splice(i, 1); i--; + } + } + } + + if (lib.config.mode == "connect") { + _status.connectMode = true; + } + if (window.isNonameServer) { + lib.cheat.i(); + } + else if (lib.config.dev && (!_status.connectMode || lib.config.debug)) { + lib.cheat.i(); + } + lib.config.sort_card = get.sortCard(lib.config.sort); + delete lib.imported.character; + delete lib.imported.card; + delete lib.imported.mode; + delete lib.imported.play; + for (var i in lib.init) { + if (i.startsWith("setMode_")) { + delete lib.init[i]; + } + } + if (!_status.connectMode) { + for (var i = 0; i < lib.extensions.length; i++) { + try { + _status.extension = lib.extensions[i][0]; + _status.evaluatingExtension = lib.extensions[i][3]; + if (typeof lib.extensions[i][1] == "function") + yield (gnc.is.coroutine(lib.extensions[i][1]) ? gnc.of(lib.extensions[i][1]) : lib.extensions[i][1]).call(lib.extensions[i], lib.extensions[i][2], lib.extensions[i][4]); + if (lib.extensions[i][4]) { + if (lib.extensions[i][4].character) { + for (var j in lib.extensions[i][4].character.character) { + game.addCharacterPack(get.copy(lib.extensions[i][4].character)); + break; + } + } + if (lib.extensions[i][4].card) { + for (var j in lib.extensions[i][4].card.card) { + game.addCardPack(get.copy(lib.extensions[i][4].card)); + break; + } + } + if (lib.extensions[i][4].skill) { + for (var j in lib.extensions[i][4].skill.skill) { + game.addSkill(j, lib.extensions[i][4].skill.skill[j], + lib.extensions[i][4].skill.translate[j], + lib.extensions[i][4].skill.translate[j + "_info"], + lib.extensions[i][4].skill.translate[j + "_append"], + lib.extensions[i][4].skill.translate[j + "_ab"]); + } + } + } + delete _status.extension; + delete _status.evaluatingExtension; + } + catch (e) { + console.log(e); + } + } + } + delete lib.extensions; + + if (lib.init.startBefore) { + lib.init.startBefore(); + delete lib.init.startBefore; + } + ui.create.arena(); + game.createEvent("game", false).setContent(lib.init.start); + if (lib.mode[lib.config.mode] && lib.mode[lib.config.mode].fromextension) { + var startstr = mode[lib.config.mode].start.toString(); + if (startstr.indexOf("onfree") == -1) { + setTimeout(lib.init.onfree, 500); + } + } + delete lib.init.start; + if (Array.isArray(_status.onprepare) && _status.onprepare.length) { + yield Promise.allSettled(_status.onprepare); + delete _status.onprepare; + } + game.loop(); + }) + var proceed = gnc.of(function* () { + if (!lib.db) { + try { + lib.storage = JSON.parse(localStorage.getItem(lib.configprefix + lib.config.mode)); + if (typeof lib.storage != "object") throw ("err"); + if (lib.storage == null) throw ("err"); + } + catch (err) { + lib.storage = {}; + localStorage.setItem(lib.configprefix + lib.config.mode, "{}"); + } + yield proceed2(); + } + else { + game.getDB("data", lib.config.mode, function (obj) { + lib.storage = obj || {}; + proceed2(); + }); + } + }); + if (!lib.imported.mode || !lib.imported.mode[lib.config.mode]) { + window.inSplash = true; + clearTimeout(window.resetGameTimeout); + delete window.resetGameTimeout; + var clickedNode = false; + var clickNode = function () { + if (clickedNode) return; + this.classList.add("clicked"); + clickedNode = true; + lib.config.mode = this.link; + game.saveConfig("mode", this.link); + if (this.link == "connect") { + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + } + else { + if (game.layout != "mobile" && lib.layoutfixed.indexOf(lib.config.mode) !== -1) { + game.layout = "mobile"; + ui.css.layout.href = lib.assetURL + "layout/" + game.layout + "/layout.css"; + } + else if (game.layout == "mobile" && lib.config.layout != "mobile" && lib.layoutfixed.indexOf(lib.config.mode) === -1) { + game.layout = lib.config.layout; + if (game.layout == "default") { + ui.css.layout.href = ""; + } + else { + ui.css.layout.href = lib.assetURL + "layout/" + game.layout + "/layout.css"; + } + } + splash.delete(1000); + delete window.inSplash; + window.resetGameTimeout = setTimeout(lib.init.reset, 10000); + + this.listenTransition(function () { + lib.init.js(lib.assetURL + "mode", lib.config.mode, proceed); + }, 500); + } + } + var downNode = function () { + this.classList.add("glow"); + } + var upNode = function () { + this.classList.remove("glow"); + } + var splash = ui.create.div("#splash", document.body); + if (lib.config.touchscreen) { + splash.classList.add("touch"); + lib.setScroll(splash); + } + if (lib.config.player_border != "wide") { + splash.classList.add("slim"); + } + splash.dataset.radius_size = lib.config.radius_size; + for (var i = 0; i < lib.config.all.mode.length; i++) { + var node = ui.create.div(".hidden", splash, clickNode); + node.link = lib.config.all.mode[i]; + ui.create.div(node, ".splashtext", get.verticalStr(get.translation(lib.config.all.mode[i]))); + if (lib.config.all.stockmode.includes(lib.config.all.mode[i])) { + // 初始启动页设置 + if (lib.config.splash_style == undefined) game.saveConfig("splash_style", "style1"); + splash.dataset.splash_style = lib.config.splash_style; + // 扩展可通过window.splashurl设置素材读取路径 + if (window.splashurl == undefined) window.splashurl = "image/splash/"; + if (lib.config.splash_style == "style1" || lib.config.splash_style == "style2") { + ui.create.div(node, ".avatar").setBackgroundImage("image/splash/" + lib.config.splash_style + "/" + lib.config.all.mode[i] + ".jpg"); + } else { + ui.create.div(node, ".avatar").setBackgroundImage(splashurl + lib.config.splash_style + "/" + lib.config.all.mode[i] + ".jpg"); + } + } + else { + var avatarnode = ui.create.div(node, ".avatar"); + var avatarbg = lib.mode[lib.config.all.mode[i]].splash; + if (avatarbg.startsWith("ext:")) { + avatarnode.setBackgroundImage(avatarbg.replace(/^ext:/, "extension/")); + } + else { + avatarnode.setBackgroundDB(avatarbg); + } + } + if (!lib.config.touchscreen) { + node.addEventListener("mousedown", downNode); + node.addEventListener("mouseup", upNode); + node.addEventListener("mouseleave", upNode); + } + setTimeout((function (node) { + return function () { + node.show(); + } + }(node)), i * 100); + } + if (lib.config.mousewheel) { + splash.onmousewheel = ui.click.mousewheel; + } + } + else { + yield proceed(); + } + localStorage.removeItem(lib.configprefix + "directstart"); + delete lib.init.init; + const libOnload2 = lib.onload2; + delete lib.onload2; + while (Array.isArray(libOnload2) && libOnload2.length) { + const fun = libOnload2.shift(); + if (typeof fun != "function") continue; + yield (gnc.is.generatorFunc(fun) ? gnc.of(fun) : fun)(); + } + }) + + static startOnline() { + "step 0" + event._resultid = null; + event._result = null; + game.pause(); + "step 1" + if (result) { + if (event._resultid) { + result.id = event._resultid; + } + game.send("result", result); + } + event.goto(0); + } + + static onfree() { + if (lib.onfree) { + clearTimeout(window.resetGameTimeout); + delete window.resetGameTimeout; + if (!game.syncMenu) { + delete window.resetExtension; + localStorage.removeItem(lib.configprefix + "disable_extension"); + } + + if (game.removeFile && lib.config.brokenFile.length) { + while (lib.config.brokenFile.length) { + game.removeFile(lib.config.brokenFile.shift()); + } + game.saveConfigValue("brokenFile"); + } + + var onfree = lib.onfree; + delete lib.onfree; + var loop = function () { + if (onfree.length) { + (onfree.shift())(); + setTimeout(loop, 100); + } + }; + setTimeout(loop, 500); + if (!_status.new_tutorial) game.saveConfig("menu_loadondemand", true, lib.config.mode); + } + } + + static connection(ws) { + const client = new lib.element.Client(ws); + lib.node.clients.push(client); + if (window.isNonameServer) { + document.querySelector("#server_count").innerHTML = lib.node.clients.length; + } + ws.on("message", function (messagestr) { + var message; + try { + message = JSON.parse(messagestr); + if (!Array.isArray(message) || + typeof lib.message.server[message[0]] !== "function") { + throw ("err"); + } + for (var i = 1; i < message.length; i++) { + message[i] = get.parsedResult(message[i]); + } + } + catch (e) { + console.log(e); + console.log("invalid message: " + messagestr); + return; + } + lib.message.server[message.shift()].apply(client, message); + }); + ws.on("close", function () { + client.close(); + }); + client.send("opened"); + } + + static sheet() { + var style = document.createElement("style"); + document.head.appendChild(style); + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + style.sheet.insertRule(arguments[i], 0); + } + } + return style; + } + + static css(path, file, before) { + const style = document.createElement("link"); + style.rel = "stylesheet"; + if (path) { + if (path[path.length - 1] == "/") path = path.slice(0, path.length - 1); + if (file) path = `${path}${/^db:extension-[^:]*$/.test(path) ? ":" : "/"}${file}.css`; + (path.startsWith("db:") ? game.getDB("image", path.slice(3)).then(get.objectURL) : new Promise(resolve => resolve(path))).then(resolvedPath => { + style.href = resolvedPath; + if (typeof before == "function") { + style.addEventListener("load", before); + document.head.appendChild(style); + } + else if (before) document.head.insertBefore(style, before); + else document.head.appendChild(style); + }); + } + return style; + } + + /** + * 在扩展的precontent中调用,用于加载扩展必需的JS文件。 + * If any of the parameters is an Array, corresponding files will be loaded in order + * 如果任意参数为数组,则按顺序加载加载相应的文件 + */ + static jsForExtension(path, file, onLoad, onError) { + if (!_status.javaScriptExtensions) _status.javaScriptExtensions = []; + _status.javaScriptExtensions.push({ + path: path, + file: file, + onLoad: onLoad, + onError: onError + }); + } + + static js(path, file, onLoad, onError) { + if (path[path.length - 1] == "/") path = path.slice(0, path.length - 1); + if (path == `${lib.assetURL}mode` && lib.config.all.stockmode.indexOf(file) == -1) { + lib.genAwait(lib.init[`setMode_${file}`]()).then(onLoad); + return; + } + if (Array.isArray(file)) { + file.forEach(value => lib.init.js(path, value, onLoad, onError)); + return; + } + let scriptSource = file ? `${path}${/^db:extension-[^:]*$/.test(path) ? ":" : "/"}${file}.js` : path; + if (path.startsWith("http")) scriptSource += `?rand=${get.id()}`; + else if (lib.config.fuck_sojson && scriptSource.includes("extension") != -1 && scriptSource.startsWith(lib.assetURL)) { + const pathToRead = scriptSource.slice(lib.assetURL.length); + const alertMessage = `检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}`; + if (typeof game.readFileAsText == "function") game.readFileAsText(pathToRead, result => { + if (result.includes("sojson") || result.includes("jsjiami") || result.includes("var _0x")) alert(alertMessage); + }, () => void 0); + else if (location.origin != "file://") lib.init.reqSync(pathToRead, function () { + const result = this.responseText; + if (result.includes("sojson") || result.includes("jsjiami") || result.includes("var _0x")) alert(alertMessage); + }, () => void 0); + } + const script = document.createElement("script"); + (scriptSource.startsWith("db:") ? game.getDB("image", scriptSource.slice(3)).then(get.objectURL) : new Promise(resolve => resolve(scriptSource))).then(resolvedScriptSource => { + script.src = resolvedScriptSource; + if (path.startsWith("http")) script.addEventListener("load", () => script.remove()); + document.head.appendChild(script); + if (typeof onLoad == "function") script.addEventListener("load", onLoad); + if (typeof onError == "function") script.addEventListener("error", onError); + }); + return script; + } + + /** + * 同步lib.init.js + * @returns { void } + */ + static jsSync(path, file, onLoad, onError) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { + const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); + if (typeof onError == "function") onError(e); + else throw e; + return; + } + if (path[path.length - 1] == "/") path = path.slice(0, path.length - 1); + if (path == `${lib.assetURL}mode` && lib.config.all.stockmode.indexOf(file) == -1) { + lib.genAwait(lib.init[`setMode_${file}`]()).then(onLoad); + return; + } + if (Array.isArray(file)) { + return file.forEach(value => lib.init.jsSync(path, value, onLoad, onError)); + } + let scriptSource; + if (!file) scriptSource = path; + else scriptSource = `${path}/${file}.js`; + if (path.startsWith("http")) scriptSource += `?rand=${get.id()}`; + const xmlHttpRequest = new XMLHttpRequest(); + let data; + xmlHttpRequest.addEventListener("load", () => { + data = xmlHttpRequest.responseText; + if (!data) { + if (typeof onError == "function") onError(new Error(`${scriptSource}加载失败!`)); + return; + } + if (lib.config.fuck_sojson && scriptSource.includes("extension") != -1 && scriptSource.startsWith(lib.assetURL)) { + const pathToRead = scriptSource.slice(lib.assetURL.length); + if (data.includes("sojson") || data.includes("jsjiami") || data.includes("var _0x")) alert(`检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}`); + } + try { + window.eval(data); + if (typeof onLoad == "function") onLoad(); + } + catch (error) { + if (typeof onError == "function") onError(error); + } + }); + if (typeof onError == "function") xmlHttpRequest.addEventListener("error", onError); + xmlHttpRequest.open("GET", scriptSource, false); + xmlHttpRequest.send(); + } + + static req(str, onload, onerror, master) { + let sScriptURL; + if (str.startsWith("http")) sScriptURL = str; + else if (str.startsWith("local:")) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { + const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); + if (typeof onerror == "function") onerror(e); + else throw e; + return; + } + sScriptURL = lib.assetURL + str.slice(6); + } + else { + let url = get.url(master); + if (url[url.length - 1] != "/") url += "/"; + sScriptURL = url + str; + } + const oReq = new XMLHttpRequest(); + if (typeof onload == "function") oReq.addEventListener("load", onload); + if (typeof onerror == "function") oReq.addEventListener("error", onerror); + oReq.open("GET", sScriptURL); + oReq.send(); + } + + /** + * 同步lib.init.req + */ + static reqSync(str, onload, onerror, master) { + let sScriptURL; + if (str.startsWith("http")) sScriptURL = str; + else if (str.startsWith("local:")) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { + const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); + if (typeof onerror == "function") onerror(e); + else throw e; + return; + } + sScriptURL = lib.assetURL + str.slice(6); + } + else { + let url = get.url(master); + if (url[url.length - 1] != "/") url += "/"; + sScriptURL = url + str; + } + const oReq = new XMLHttpRequest(); + if (typeof onload == "function") oReq.addEventListener("load", onload); + if (typeof onerror == "function") oReq.addEventListener("error", onerror); + oReq.open("GET", sScriptURL, false); + oReq.send(); + if (typeof onload !== "function") return oReq.responseText; + } + + static json(url, onload, onerror) { + const oReq = new XMLHttpRequest(); + if (typeof onload == "function") oReq.addEventListener("load", () => { + let result; + try { + result = JSON.parse(oReq.responseText); + if (!result) throw ("err"); + } + catch (e) { + if (typeof onerror == "function") onerror(e); + return; + } + onload(result); + }); + if (typeof onerror == "function") oReq.addEventListener("error", onerror); + oReq.open("GET", url); + oReq.send(); + } + + /** + * 同步lib.init.json + */ + static jsonSync(url, onload, onerror) { + if (lib.assetURL.length == 0 && location.origin == "file://" && typeof game.readFile == "undefined") { + const e = new Error("浏览器file协议下无法使用此api,请在http/https协议下使用此api"); + if (typeof onerror == "function") onerror(e); + else throw e; + return; + } + const oReq = new XMLHttpRequest(); + if (typeof onload == "function") oReq.addEventListener("load", () => { + let result; + try { + result = JSON.parse(oReq.responseText); + if (!result) throw ("err"); + } + catch (e) { + if (typeof onerror == "function") onerror(e); + return; + } + onload(result); + }); + if (typeof onerror == "function") oReq.addEventListener("error", onerror); + oReq.open("GET", url, false); + oReq.send(); + } + + static cssstyles() { + if (ui.css.styles) { + ui.css.styles.remove(); + } + ui.css.styles = lib.init.sheet(); + ui.css.styles.sheet.insertRule("#arena .player>.name,#arena .button.character>.name {font-family: " + (lib.config.name_font || "xinwei") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule("#arena .player>.name,.button.character>.name {font-family: " + (lib.config.name_font || "xinwei") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule("#arena .player .identity>div {font-family: " + (lib.config.identity_font || "huangcao") + ",xinwei}", 0); + ui.css.styles.sheet.insertRule(".button.character.newstyle>.identity {font-family: " + (lib.config.identity_font || "huangcao") + ",xinwei}", 0); + if (lib.config.cardtext_font && lib.config.cardtext_font != "default") { + ui.css.styles.sheet.insertRule(".card div:not(.info):not(.background) {font-family: " + lib.config.cardtext_font + ";}", 0); + } + if (lib.config.global_font && lib.config.global_font != "default") { + ui.css.styles.sheet.insertRule("#window {font-family: " + lib.config.global_font + ",xinwei}", 0); + ui.css.styles.sheet.insertRule("#window #control{font-family: STHeiti,SimHei,Microsoft JhengHei,Microsoft YaHei,WenQuanYi Micro Hei,Suits,Helvetica,Arial,sans-serif}", 0); + } + switch (lib.config.glow_phase) { + case "yellow": ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(217, 152, 62) 0 0 15px, rgb(217, 152, 62) 0 0 15px !important;}", 0); break; + case "green": ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgba(10, 155, 67, 1) 0 0 15px, rgba(10, 155, 67, 1) 0 0 15px !important;}", 0); break; + case "purple": ui.css.styles.sheet.insertRule("#arena .player:not(.selectable):not(.selected).glow_phase {box-shadow: rgba(0, 0, 0, 0.3) 0 0 0 1px, rgb(189, 62, 170) 0 0 15px, rgb(189, 62, 170) 0 0 15px !important;}", 0); break; + } + } + + static layout(layout, nosave) { + const loadingScreen = ui.create.div(".loading-screen", document.body), loadingScreenStyle = loadingScreen.style; + loadingScreenStyle.animationDuration = "1s"; + loadingScreenStyle.animationFillMode = "forwards"; + loadingScreenStyle.animationName = "opacity-0-1"; + if (layout == "default") layout = "mobile"; + if (!nosave) game.saveConfig("layout", layout); + game.layout = layout; + ui.arena.hide(); + new Promise(resolve => setTimeout(resolve, 500)).then(() => { + if (game.layout == "default") { + ui.css.layout.href = ""; + } + else { + ui.css.layout.href = lib.assetURL + "layout/" + game.layout + "/layout.css"; + } + if (game.layout == "mobile" || game.layout == "long") { + ui.arena.classList.add("mobile"); + } + else { + ui.arena.classList.remove("mobile"); + } + if (game.layout == "mobile" || game.layout == "long" || game.layout == "long2" || game.layout == "nova") { + if (game.me && game.me.node.handcards2.childNodes.length) { + while (game.me.node.handcards2.childNodes.length) { + game.me.node.handcards1.appendChild(game.me.node.handcards2.firstChild); + } + } + } + if (game.layout == "default") { + ui.arena.classList.add("oldlayout"); + } + else { + ui.arena.classList.remove("oldlayout"); + } + if (lib.config.cardshape == "oblong" && (game.layout == "long" || game.layout == "mobile" || game.layout == "long2" || game.layout == "nova")) { + ui.arena.classList.add("oblongcard"); + ui.window.classList.add("oblongcard"); + } + else { + ui.arena.classList.remove("oblongcard"); + ui.window.classList.remove("oblongcard"); + } + //if(lib.config.textequip=="text"&&(game.layout=="long"||game.layout=="mobile")){ + if (game.layout == "long" || game.layout == "mobile") { + ui.arena.classList.add("textequip"); + } + else { + ui.arena.classList.remove("textequip"); + } + if (get.is.phoneLayout()) { + ui.css.phone.href = lib.assetURL + "layout/default/phone.css"; + ui.arena.classList.add("phone"); + } + else { + ui.css.phone.href = ""; + ui.arena.classList.remove("phone"); + } + for (var i = 0; i < game.players.length; i++) { + if (get.is.linked2(game.players[i])) { + if (game.players[i].classList.contains("linked")) { + game.players[i].classList.remove("linked"); + game.players[i].classList.add("linked2"); + } + } + else { + if (game.players[i].classList.contains("linked2")) { + game.players[i].classList.remove("linked2"); + game.players[i].classList.add("linked"); + } + } + } + if (game.layout == "long" || game.layout == "long2") { + ui.arena.classList.add("long"); + } + else { + ui.arena.classList.remove("long"); + } + if (lib.config.player_border != "wide" || game.layout == "long" || game.layout == "long2") { + ui.arena.classList.add("slim_player"); + } + else { + ui.arena.classList.remove("slim_player"); + } + if (lib.config.player_border == "normal" && lib.config.mode != "brawl" && (game.layout == "long" || game.layout == "long2")) { + ui.arena.classList.add("lslim_player"); + } + else { + ui.arena.classList.remove("lslim_player"); + } + if (lib.config.player_border == "slim") { + ui.arena.classList.add("uslim_player"); + } + else { + ui.arena.classList.remove("uslim_player"); + } + if (lib.config.player_border == "narrow") { + ui.arena.classList.add("mslim_player"); + } + else { + ui.arena.classList.remove("mslim_player"); + } + ui.updatej(); + ui.updatem(); + return new Promise(resolve => setTimeout(resolve, 100)); + }).then(() => { + ui.arena.show(); + if (game.me) game.me.update(); + return new Promise(resolve => setTimeout(resolve, 500)); + }).then(() => { + ui.updatex(); + ui.updatePlayerPositions(); + return new Promise(resolve => setTimeout(resolve, 500)); + }).then(() => { + ui.updatec(); + loadingScreenStyle.animationName = "opacity-1-0"; + loadingScreen.addEventListener("animationend", animationEvent => animationEvent.target.remove()); + }); + } + + static background() { + if (lib.config.image_background_random) { + var list = []; + for (var i in lib.configMenu.appearence.config.image_background.item) { + if (i == "default") continue; + list.push(i); + } + list.remove(lib.config.image_background); + localStorage.setItem(lib.configprefix + "background", JSON.stringify(list)); + } + else if (lib.config.image_background && lib.config.image_background != "default" && !lib.config.image_background.startsWith("custom_")) { + localStorage.setItem(lib.configprefix + "background", lib.config.image_background); + } + else if (lib.config.image_background == "default" && lib.config.theme == "simple") { + localStorage.setItem(lib.configprefix + "background", "ol_bg"); + } + else { + localStorage.removeItem(lib.configprefix + "background"); + } + } + + /** + * + * @param {*} item + * @param {Function} [scope] 作用域 + * @returns + */ + static parsex(item, scope) { + //by 诗笺、Tipx-L + /** + * @param {Function} func + */ + function Legacy(func) { + //Remove all comments + //移除所有注释 + let str = func.toString().replace(/((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("(?:\\[\s\S]|[^"\\])*"|"(?:\\[\s\S]|[^"\\])*"|(?:\r?\n|[\s\S])[^/""\\\s]*)/mg, "$2").trim(); + //获取第一个 { 后的所有字符 + str = str.slice(str.indexOf("{") + 1); + //判断代码中是否有debugger + let regex = /event\.debugger\(\)/; + let hasDebugger = false; + let insertDebugger = `yield code=>eval(code);`; + let debuggerSkip = 0; + let debuggerResult; + while ((debuggerResult = str.slice(debuggerSkip).match(regex)) != null) { + let debuggerCopy = str; + debuggerCopy = debuggerCopy.slice(0, debuggerSkip + debuggerResult.index) + insertDebugger + debuggerCopy.slice(debuggerSkip + debuggerResult.index + debuggerResult[0].length, -1); + //测试是否有错误 + try { + new GeneratorFunction(debuggerCopy); + str = debuggerCopy + "}"; + debuggerSkip += debuggerResult.index + insertDebugger.length; + hasDebugger = true; + } catch (error) { + debuggerSkip += debuggerResult.index + debuggerResult[0].length; + } + } + //func中要写步骤的话,必须要写step 0 + if (str.indexOf("step 0") == -1) { + str = "{if(event.step==1) {event.finish();return;}\n" + str; + } else { + let skip = 0; + let k = 0; + let result; + //去除99个step的限制 + while ((result = str.slice(skip).match(new RegExp(`[""]step ${k}[""]`))) != null) { + let insertStr; + if (k == 0) { + insertStr = `switch(step){case 0:`; + } else { + insertStr = `break;case ${k}:`; + } + let copy = str; + copy = copy.slice(0, skip + result.index) + insertStr + copy.slice(skip + result.index + result[0].length); + //测试是否有错误 + try { + new (hasDebugger ? GeneratorFunction : Function)(copy); + str = copy; + skip += result.index + insertStr.length; + } catch (error) { + k--; + skip += result.index + result[0].length; + } + k++; + } + str = `if(event.step==${k}){event.finish();return;}` + str; + } + if (!scope) { + return (new (hasDebugger ? GeneratorFunction : Function)("event", "step", "source", "player", "target", "targets", + "card", "cards", "skill", "forced", "num", "trigger", "result", + "_status", "lib", "game", "ui", "get", "ai", str)); + } else { + return scope(`function${hasDebugger ? "*" : ""} anonymous(event,step,source,player,target,targets, + card,cards,skill,forced,num,trigger,result, + _status,lib,game,ui,get,ai){${str}}; anonymous;`); + } + } + switch (typeof item) { + case "object": + if (Array.isArray(item)) { + let lastEvent = null; + return function* (event, step, source, player, target, targets, card, cards, skill, forced, num, trigger, result, _status, lib, game, ui, get, ai) { + if (step >= item.length) return event.finish(); + var current = item[step]; + if (typeof current != "function") throw new Error(`content ${step} of ${event.name} is not vaild: ${current}`); + var currentResult = current(event, { + event: event, + step: step, + source: source, + player: player, + target: target, + targets: targets, + card: card, + cards: cards, + skill: skill, + forced: forced, + num: num, + trigger: trigger, + result: result + }, (lastEvent && ("result" in lastEvent)) ? lastEvent.result : null); + // TODO: use `event.debugger` to replace source + if (gnc.is.generator(currentResult)) lastEvent = yield* currentResult; + else lastEvent = currentResult; + } + } + else { + if (Symbol.iterator in item) return lib.init.parsex(Array.from(item)); + if (item.toString !== Object.prototype.toString) return lib.init.parsex(item.toString()); + if ("render" in item) { + // TODO: Object Render Parse + throw new Error("NYI: Object Render Parse"); + } + // TODO: Object Other Parse + throw new Error("NYI: Object Other Parse"); + } + case "function": + if (gnc.is.generatorFunc(item)) { + let gen, lastEvent; + return function* (event, step, source, player, target, targets, card, cards, skill, forced, num, trigger, result, _status, lib, game, ui, get, ai) { + event.step = NaN; + if (!gen) gen = item(event, { + event: event, + step: step, + source: source, + player: player, + target: target, + targets: targets, + card: card, + cards: cards, + skill: skill, + forced: forced, + num: num, + trigger: trigger, + result: result + }); + var res = gen.next((lastEvent && ("result" in lastEvent)) ? lastEvent.result : null); + if (res.done) return event.finish(); + var currentResult = res.value; + // TODO: use `event.debugger` to replace source + if (typeof currentResult == "function") yield currentResult; + else { + if (Array.isArray(currentResult)) { + event.step = currentResult[1]; + currentResult = currentResult[0]; + } + lastEvent = currentResult; + } + } + } else if (item._parsed) return item; + // falls through + default: + return Legacy(item); + } + } + + static eval(func) { + if (typeof func == "function") { + return eval("(" + func.toString() + ")"); + } + else if (typeof func == "object") { + for (var i in func) { + if (Object.prototype.hasOwnProperty.call(func, i)) { + func[i] = lib.init.eval(func[i]); + } + } + } + return func; + } + + static encode(strUni) { + var strUtf = strUni.replace( + /[\u0080-\u07ff]/g, function (c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f); + }); + strUtf = strUtf.replace( + /[\u0800-\uffff]/g, function (c) { + var cc = c.charCodeAt(0); + return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f); + }); + return btoa(strUtf); + } + + static decode(str) { + var strUtf = atob(str); + var strUni = strUtf.replace( + /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, function (c) { + var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f); + return String.fromCharCode(cc); + }); + strUni = strUni.replace( + /[\u00c0-\u00df][\u0080-\u00bf]/g, function (c) { + var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f; + return String.fromCharCode(cc); + }); + return strUni; + } + + static stringify(obj) { + var str = "{" + for (var i in obj) { + str += `"${i}":` + if (Object.prototype.toString.call(obj[i]) == "[object Object]") { + str += lib.init.stringify(obj[i]); + } + else if (typeof obj[i] == "function") { + str += obj[i].toString(); + } + else { + str += JSON.stringify(obj[i]); + } + str += "," + } + str += "}"; + return str; + } + + static stringifySkill(obj) { + var str = ""; + for (var i in obj) { + str += i + ":" + if (Object.prototype.toString.call(obj[i]) == "[object Object]") { + str += "{\n" + lib.init.stringifySkill(obj[i]) + "}"; + } + else if (typeof obj[i] == "function") { + str += obj[i].toString().replace(/\t/g, ""); + } + else { + str += JSON.stringify(obj[i]); + } + str += ",\n" + } + return str; + } +} diff --git a/noname/library/initialization/promises.js b/noname/library/initialization/promises.js new file mode 100644 index 000000000..e99d29bba --- /dev/null +++ b/noname/library/initialization/promises.js @@ -0,0 +1,71 @@ +import { Initialization } from "../initialization.js"; + +/** + * 部分函数的Promise版本 + */ +export class Promises { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + /** + * Promise版的`Initialization.js` + * + * @param {string} path - 文件路径 + * @param {string | string[]} [file] - 文件名或文件名组,忽略则直接读取`path`的内容 + * @returns {Promise} + */ + js(path, file) { + return new Promise((resolve, reject) => Initialization.js(path, file, resolve, reject)); + } + + /** + * Promise版的`Initialization.css` + * + * @param {string} path - 文件路径 + * @param {string | string[]} [file] - 文件名或文件名组,忽略则直接读取`path`的内容 + * @param {Element} [before] 新样式dom的位置 + * @returns {Promise} + */ + css(path, file, before) { + return new Promise((resolve, reject) => { + const style = Initialization.css(path, file, before); + style.addEventListener("load", () => resolve(style)); + style.addEventListener("error", reject); + }); + } + + /** + * Promise版的`Initialization.req` + * + * @param {string} str - 要读取的地址 + * @param {string} [master] + * @returns {Promise} + */ + req(str, master) { + return new Promise((resolve, reject) => Initialization.req(str, resolve, reject, master)); + } + + /** + * Promise版的`Initialization.json` + * + * @param {string} url - 要读取的地址 + * @returns {Promise} + */ + json(url) { + return new Promise((resolve, reject) => Initialization.json(url, resolve, reject)); + } + + /** + * Promise版的`Initialization.sheet` + * + * @returns {Promise} + */ + sheet() { + return new Promise((resolve, reject) => { + const style = Initialization.sheet(...arguments); + style.addEventListener("load", () => resolve(style)); + style.addEventListener("error", reject); + }); + } +} \ No newline at end of file diff --git a/noname/library/internal-status.js b/noname/library/internal-status.js new file mode 100644 index 000000000..15b2aff0b --- /dev/null +++ b/noname/library/internal-status.js @@ -0,0 +1,10 @@ +export const internalStatus = { + running: false, + canvas: false, + time: 0, + reload: 0, + delayed: 0, + frameId: 0, + videoId: 0, + globalId: 0 +}; diff --git a/noname/library/linq.js b/noname/library/linq.js new file mode 100644 index 000000000..a9f50a449 --- /dev/null +++ b/noname/library/linq.js @@ -0,0 +1,106 @@ +import { Creation } from "./creation.js"; + +export const linq = { + cselector: { + hasAttr: name => `[${name}]`, + isAttr: (name, item) => `[${name}=${item}]`, + inAttr: (name, item) => `[${name}~=${item}]`, + conAttr: (name, item) => `[${name}*=${item}]`, + onAttr: (name, item) => `[${name}|=${item}]`, + bgnAttr: (name, item) => `[${name}^=${item}]`, + endAttr: (name, item) => `[${name}^=${item}]`, + merge: function () { return Array.from(arguments).join(" "); }, + of: function () { return Array.from(arguments).join(""); }, + class: function () { return `.${Array.from(arguments).join(".")}`; }, + group: function () { return Array.from(arguments).join(","); }, + media: type => `@media ${type}` + }, + dom: { + attributes: { + style(name, value) { + return { + _type: "style", + name: name, + value: value + } + } + }, + inject(element, options) { + //处理id和class + if (options.identity) { + for (const item of options.identity) { + if (item.startsWith("#")) element.id = item.slice(1); + else element.classList.add(item); + } + } + //处理属性 + if (options.attributes) { + for (const item in options.attributes) element.setAttribute(item, options.attributes[item]); + } + //处理样式 + if (options.style) { + for (const item in options.style) element.style[item] = options.style[item]; + } + //处理内容 + if (options.content) { + element.innerHTML = options.content; + } + //处理子元素 + if (options.childs) { + for (const item of options.childs) { + element.appendChild(item); + } + } + return element; + }, + generate() { + let result = Creation.nullObject; + const args = Array.from(arguments); + for (const item of args) { + switch (typeof item) { + case "object": + switch (item.constructor) { + case Object: + case null: + if ("_type" in item) { + const type = item["_type"]; + if (!(type in result)) result[type] = Creation.nullObject; + result[type][item.name] = item.value; + } + else { + if (!("style" in result)) result.style = Creation.nullObject; + for (const name in item) { + result.style[name] = item[name]; + } + } + break; + default: + if (!("childs" in result)) result.childs = Creation.array; + result.childs.add(item); + break; + } + break; + case "string": + if (/^\.|#/.test(item)) { + if (!("identity" in result)) result.identity = Creation.array; + const identities = item.split(".").filter(Boolean); + for (const item of identities) result.identity.add(item); + } + else result.content = item; + break; + } + } + return result; + }, + attribute(name, value) { + return { + _type: "attributes", + name: name, + value: value + } + }, + div() { + return this.inject(document.createElement("div"), this.generate(...arguments)); + } + } +}; diff --git a/noname/library/message.js b/noname/library/message.js new file mode 100644 index 000000000..3df039f39 --- /dev/null +++ b/noname/library/message.js @@ -0,0 +1,1092 @@ +export const message = { + server: { + init: function (version, config, banned_info) { + if (lib.node.banned.contains(banned_info)) { + this.send("denied", "banned"); + } + else if (config.id && lib.playerOL && lib.playerOL[config.id]) { + var player = lib.playerOL[config.id]; + player.setNickname(); + player.ws = this; + player.isAuto = false; + this.id = config.id; + game.broadcast(function (player) { + player.setNickname(); + }, player); + this.send("reinit", lib.configOL, get.arenaState(), game.getState ? game.getState() : {}, game.ip, null, _status.onreconnect, _status.cardtag, _status.postReconnect); + } + else if (version != lib.versionOL) { + this.send("denied", "version"); + lib.node.clients.remove(this); + this.closed = true; + } + else if (!_status.waitingForPlayer) { + if (game.phaseNumber && lib.configOL.observe) { + lib.node.observing.push(this); + this.send("reinit", lib.configOL, get.arenaState(), game.getState ? game.getState() : {}, game.ip, game.players[0].playerid, null, _status.cardtag); + if (!ui.removeObserve) { + ui.removeObserve = ui.create.system("移除旁观", function () { + lib.configOL.observe = false; + if (game.onlineroom) { + game.send("server", "config", lib.configOL); + } + while (lib.node.observing.length) { + lib.node.observing.shift().ws.close(); + } + this.remove(); + delete ui.removeObserve; + }, true, true); + } + } + else { + this.send("denied", "gaming"); + lib.node.clients.remove(this); + this.closed = true; + } + } + else if (lib.node.clients.length - (window.isNonameServer ? 1 : 0) >= parseInt(lib.configOL.number)) { + this.send("denied", "number"); + lib.node.clients.remove(this); + this.closed = true; + } + else { + if (config) { + this.avatar = config.avatar; + this.nickname = config.nickname; + } + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].classList.contains("unselectable2")) continue; + if (game.connectPlayers[i] != game.me && !game.connectPlayers[i].playerid) { + game.connectPlayers[i].playerid = this.id; + game.connectPlayers[i].initOL(this.nickname, this.avatar); + game.connectPlayers[i].ws = this; + break; + } + } + this.send("init", this.id, lib.configOL, game.ip, window.isNonameServer, game.roomId); + } + }, + inited: function () { + this.inited = true; + if (_status.waitingForPlayer) { + game.updateWaiting(); + } + }, + reinited: function () { + this.inited = true; + }, + result: function (result) { + if (lib.node.observing.contains(this)) return; + var player = lib.playerOL[this.id]; + if (player) { + player.unwait(result); + } + }, + tempResult: function (result) { + if (lib.node.observing.contains(this)) return; + var player = lib.playerOL[this.id]; + if (player) { + player.tempUnwait(result); + } + }, + startGame: function () { + if (this.id == game.onlinezhu) { + game.resume(); + } + }, + changeRoomConfig: function (config) { + if (this.id == game.onlinezhu) { + game.broadcastAll(function (config) { + for (var i in config) { + lib.configOL[i] = config[i]; + } + if (ui.connectStartBar) { + ui.connectStartBar.firstChild.innerHTML = get.modetrans(lib.configOL, true); + } + }, config); + if (lib.configOL.mode == "identity" && lib.configOL.identity_mode == "zhong" && game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + game.connectPlayers[i].classList.remove("unselectable2"); + } + lib.configOL.number = 8; + game.updateWaiting(); + } + if (game.onlineroom) { + game.send("server", "config", lib.configOL); + } + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == this.id) { + game.connectPlayers[i].chat("房间设置已更改"); + } + } + } + }, + changeNumConfig: function (num, index, bool) { + if (this.id == game.onlinezhu) { + lib.configOL.number = num; + game.send("server", "config", lib.configOL); + if (game.connectPlayers && game.connectPlayers[index]) { + if (bool) { + game.connectPlayers[index].classList.add("unselectable2"); + } + else { + game.connectPlayers[index].classList.remove("unselectable2"); + } + game.updateWaiting(); + } + } + }, + throwEmotion: function (target, emotion, rotate) { + if (lib.node.observing.contains(this)) return; + var player = lib.playerOL[this.id]; + if (player) { + player.throwEmotion(target, emotion, rotate); + } + }, + emotion: function (id, pack, emotion) { + if (lib.node.observing.contains(this)) return; + var that = this; + if (!this.id || (!lib.playerOL[this.id] && (!game.connectPlayers || !function () { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == that.id) { + return true; + } + } + return false; + }()))) return; + var player; + if (lib.playerOL[id]) { + player = lib.playerOL[id]; + } + else if (game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == id) { + player = game.connectPlayers[i]; break; + } + } + } + if (player) player.emotion(pack, emotion); + }, + chat: function (id, str) { + if (lib.node.observing.contains(this)) return; + var that = this; + if (!this.id || (!lib.playerOL[this.id] && (!game.connectPlayers || !function () { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == that.id) { + return true; + } + } + return false; + }()))) return; + var player; + if (lib.playerOL[id]) { + player = lib.playerOL[id]; + } + else if (game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == id) { + player = game.connectPlayers[i]; break; + } + } + } + if (player) player.chat(str); + }, + giveup: function (player) { + if (lib.node.observing.contains(this) || !player || !player._giveUp) return; + _status.event.next.length = 0; + game.createEvent("giveup", false).set("includeOut", true).setContent(function () { + game.log(player, "投降"); + player.popup("投降"); + player.die("nosource").includeOut = true; + }).player = player; + }, + auto: function () { + if (lib.node.observing.contains(this)) return; + var player = lib.playerOL[this.id]; + if (player) { + player.isAuto = true; + player.setNickname(player.nickname + " - 托管"); + game.broadcast(function (player) { + player.setNickname(player.nickname + " - 托管"); + }, player); + } + }, + unauto: function () { + if (lib.node.observing.contains(this)) return; + var player = lib.playerOL[this.id]; + if (player) { + player.isAuto = false; + player.setNickname(player.nickname); + game.broadcast(function (player) { + player.setNickname(player.nickname); + }, player); + } + }, + exec: function (func) { + // if(typeof func=="function"){ + // var args=Array.from(arguments); + // args.shift(); + // func.apply(this,args); + // } + }, + log: function () { + var items = []; + try { + for (var i = 0; i < arguments.length; i++) { + eval("items.push(" + arguments[i] + ")"); + } + } + catch (e) { + this.send("log", ["err"]); + return; + } + this.send("log", items); + } + }, + client: { + log: function (arr) { + if (Array.isArray(arr)) { + for (var i = 0; i < arr.length; i++) { + console.log(arr[i]); + } + } + }, + opened: function () { + game.send("init", lib.versionOL, { + id: game.onlineID, + avatar: lib.config.connect_avatar, + nickname: get.connectNickname() + }, lib.config.banned_info); + if (ui.connecting && !ui.connecting.splashtimeout) { + ui.connecting.firstChild.innerHTML = "重连成功"; + } + }, + onconnection: id => lib.init.connection(lib.wsOL[id] = new lib.element.NodeWS(id)), + onmessage: function (id, message) { + if (lib.wsOL[id]) { + lib.wsOL[id].onmessage(message); + } + }, + onclose: function (id) { + if (lib.wsOL[id]) { + lib.wsOL[id].onclose(); + } + }, + selfclose: function () { + if (game.online || game.onlineroom) { + if ((game.servermode || game.onlinehall) && _status.over) { + // later + } + else { + game.saveConfig("tmp_user_roomId"); + } + } + game.ws.close(); + }, + reloadroom: function (forced) { + if (window.isNonameServer && (forced || !_status.protectingroom)) { + game.reload(); + } + }, + createroom: function (index, config, mode) { + game.online = false; + game.onlineroom = true; + game.roomId = index; + lib.node = {}; + if (config && mode && window.isNonameServer) { + if (mode == "auto") { + mode = lib.configOL.mode; + } + game.switchMode(mode, config); + } + else { + game.switchMode(lib.configOL.mode); + } + ui.create.connecting(true); + }, + enterroomfailed: function () { + alert("请稍后再试"); + _status.enteringroom = false; + ui.create.connecting(true); + }, + roomlist: function (list, events, clients, wsid) { + game.send("server", "key", [game.onlineKey, lib.version]); + game.online = true; + game.onlinehall = true; + lib.config.recentIP.remove(_status.ip); + lib.config.recentIP.unshift(_status.ip); + lib.config.recentIP.splice(5); + if (!lib.config.reconnect_info || lib.config.reconnect_info[0] != _status.ip) { + game.saveConfig("reconnect_info", [_status.ip, null]); + } + game.saveConfig("recentIP", lib.config.recentIP); + _status.connectMode = true; + + game.clearArena(); + game.clearConnect(); + ui.pause.hide(); + ui.auto.hide(); + + clearTimeout(_status.createNodeTimeout); + game.send("server", "changeAvatar", get.connectNickname(), lib.config.connect_avatar); + + var proceed = function () { + game.ip = get.trimip(_status.ip); + ui.create.connectRooms(list); + if (events) { + ui.connectEvents = ui.create.div(".forceopaque.menubutton.large.connectevents.pointerdiv", "约战", ui.window, ui.click.connectEvents); + ui.connectEventsCount = ui.create.div(".forceopaque.menubutton.icon.connectevents.highlight.hidden", "", ui.window); + ui.connectClients = ui.create.div(".forceopaque.menubutton.large.connectevents.pointerdiv.left", "在线", ui.window, ui.click.connectClients); + ui.connectClientsCount = ui.create.div(".forceopaque.menubutton.icon.connectevents.highlight.left", "1", ui.window); + ui.createRoomButton = ui.create.div(".forceopaque.menubutton.large.connectevents.pointerdiv.left2", "创建房间", ui.window, function () { + if (!_status.creatingroom) { + _status.creatingroom = true; + ui.click.connectMenu(); + } + }); + if (events.length) { + ui.connectEventsCount.innerHTML = events.filter(function (evt) { + return evt.creator == game.onlineKey || !get.is.banWords(evt.content) + }).length; + ui.connectEventsCount.show(); + } + } + game.wsid = wsid; + lib.message.client.updaterooms(list, clients); + lib.message.client.updateevents(events); + ui.exitroom = ui.create.system("退出房间", function () { + game.saveConfig("tmp_owner_roomId"); + game.saveConfig("tmp_user_roomId"); + if (ui.rooms) { + game.saveConfig("reconnect_info"); + } + else { + if (lib.config.reconnect_info) { + lib.config.reconnect_info.length = 1; + game.saveConfig("reconnect_info", lib.config.reconnect_info); + } + } + game.reload(); + }, true); + + var findRoom = function (id) { + for (var room of ui.rooms) { + if (room.key == id) return room; + } + return false; + }; + if (typeof lib.config.tmp_owner_roomId == "string") { + if (typeof game.roomId != "string" && !findRoom(lib.config.tmp_owner_roomId)) { + lib.configOL.mode = lib.config.connect_mode; + game.roomId = lib.config.tmp_owner_roomId; + } + game.saveConfig("tmp_owner_roomId"); + } + if (typeof lib.config.tmp_user_roomId == "string") { + if (typeof game.roomId != "string") { + if (findRoom(lib.config.tmp_user_roomId)) { + game.roomId = lib.config.tmp_user_roomId; + } + else { + ui.create.connecting(); + (function () { + var n = 10; + var id = lib.config.tmp_user_roomId; + var interval = setInterval(function () { + if (n > 0) { + n--; + if (findRoom(id)) { + clearInterval(interval); + game.send("server", "enter", id, get.connectNickname(), lib.config.connect_avatar); + } + } + else { + ui.create.connecting(true); + clearInterval(interval); + } + }, 500); + }()); + } + } + game.saveConfig("tmp_user_roomId"); + } + + if (window.isNonameServer) { + var cfg = "pagecfg" + window.isNonameServer; + if (lib.config[cfg]) { + lib.configOL = lib.config[cfg][0]; + game.send("server", "server", lib.config[cfg].slice(1)); + game.saveConfig(cfg); + _status.protectingroom = true; + setTimeout(function () { + _status.protectingroom = false; + if (!lib.node || !lib.node.clients || !lib.node.clients.length) { + game.reload(); + } + }, 15000); + } + else { + game.send("server", "server"); + } + } + else if (typeof game.roomId == "string") { + var room = findRoom(game.roomId); + if (game.roomIdServer && room && (room.serving || !room.version)) { + console.log(); + if (lib.config.reconnect_info) { + lib.config.reconnect_info[2] = null; + game.saveConfig("reconnect_info", lib.config.reconnect_info); + } + } + else { + ui.create.connecting(); + game.send("server", (game.roomId == game.onlineKey) ? "create" : "enter", game.roomId, get.connectNickname(), lib.config.connect_avatar); + } + } + lib.init.onfree(); + } + if (_status.event.parent) { + game.forceOver("noover", proceed); + } + else { + proceed(); + } + }, + updaterooms: function (list, clients) { + if (ui.rooms) { + var map = {}, map2 = {}; + for (var i of ui.rooms) map2[i.key] = true; + for (var i of list) { + if (!i) continue; + map[i[4]] = i; + } + ui.window.classList.add("more_room"); + for (var i = 0; i < ui.rooms.length; i++) { + if (!map[ui.rooms[i].key]) { + ui.rooms[i].remove(); + ui.rooms.splice(i--, 1); + } + else ui.rooms[i].initRoom(list[i]); + } + for (var i of list) { + if (!i) continue; + map[i[4]] = i; + if (!map2[i[4]]) { + var player = ui.roombase.add(``); + player.roomindex = i; + player.initRoom = lib.element.Player.prototype.initRoom; + player.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.connectroom); + player.initRoom(i); + ui.rooms.push(player); + } + } + if (!_status.requestReadClipboard && get.config("read_clipboard", "connect")) { + const read = text => { + try { + var roomId = text.split("\n")[1].match(/\d+/); + var caption = ui.rooms.find(caption => caption.key == roomId); + if (caption && (_status.read_clipboard_text || confirm(`是否通过复制的内容加入${roomId}房间?`))) { + ui.click.connectroom.call(caption); + delete _status.read_clipboard_text; + } + } catch (e) { console.log(e) } + } + //每次启动只请求一次 + _status.requestReadClipboard = true; + if (_status.read_clipboard_text) { + read(_status.read_clipboard_text); + } else { + window.focus(); + if (navigator.clipboard && lib.node) { + navigator.clipboard.readText().then(read).catch(() => void 0); + } else { + var input = ui.create.node("textarea", ui.window, { opacity: "0" }); + input.select(); + var result = document.execCommand("paste"); + input.blur(); + ui.window.removeChild(input); + if (result || input.value.length > 0) read(input.value); + else if (confirm("是否输入邀请链接以加入房间?")) { + var text = prompt("请输入邀请链接"); + if (typeof text == "string" && text.length > 0) read(text); + } + } + } + } + } + lib.message.client.updateclients(clients, true); + }, + updateclients: function (clients, bool) { + if (clients && ui.connectClients) { + ui.connectClients.info = clients; + ui.connectClientsCount.innerHTML = clients.length; + } + if (_status.connectClientsCallback) { + _status.connectClientsCallback(); + } + }, + updateevents: function (events) { + if (events && ui.connectEvents) { + ui.connectEvents.info = events; + var num = events.filter(function (evt) { + return typeof evt.creator == "string" && (evt.creator == game.onlineKey || !get.is.banWords(evt.content)) + }).length; + if (num) { + ui.connectEventsCount.innerHTML = num; + ui.connectEventsCount.show(); + } + else { + ui.connectEventsCount.hide(); + } + if (_status.connectEventsCallback) { + _status.connectEventsCallback(); + } + } + }, + eventsdenied: function (reason) { + var str = "创建约战失败"; + if (reason == "total") { + str += ",约战总数不能超过20"; + } + else if (reason == "time") { + str += ",时间已过"; + } + else if (reason == "ban") { + str += ",请注意文明发言"; + } + alert(str); + }, + init: function (id, config, ip, servermode, roomId) { + game.online = true; + game.onlineID = id; + game.ip = ip; + game.servermode = servermode; + game.roomId = roomId; + if (game.servermode) { + game.saveConfig("reconnect_info", [_status.ip, id, game.roomId]); + } + else { + game.saveConfig("reconnect_info", [_status.ip, id]); + game.saveConfig("tmp_user_roomId", roomId); + } + lib.config.recentIP.remove(_status.ip); + lib.config.recentIP.unshift(_status.ip); + lib.config.recentIP.splice(5); + game.saveConfig("recentIP", lib.config.recentIP); + _status.connectMode = true; + lib.configOL = config; + lib.playerOL = {}; + lib.cardOL = {}; + + game.clearArena(); + game.finishCards(); + ui.create.roomInfo(); + ui.create.chat(); + if (game.servermode) { + ui.create.connectPlayers(get.modetrans(config, true)); + } + else { + ui.create.connectPlayers(ip); + } + ui.pause.hide(); + ui.auto.hide(); + game.clearConnect(); + clearTimeout(_status.createNodeTimeout); + + var proceed = function () { + game.loadModeAsync(config.mode, function (mode) { + for (var i in mode.ai) { + if (typeof mode.ai[i] == "object") { + if (ai[i] == undefined) ai[i] = {}; + for (var j in mode.ai[i]) { + ai[i][j] = mode.ai[i][j]; + } + } + else { + ai[i] = mode.ai[i]; + } + } + for (var i in mode.get) { + if (typeof mode.get[i] == "object") { + if (get[i] == undefined) get[i] = {}; + for (var j in mode.get[i]) { + get[i][j] = mode.get[i][j]; + } + } + else { + get[i] = mode.get[i]; + } + } + for (var i in mode.translate) { + lib.translate[i] = mode.translate[i]; + } + if (mode.game) { + game.getIdentityList = mode.game.getIdentityList; + game.updateState = mode.game.updateState; + game.getRoomInfo = mode.game.getRoomInfo; + } + if (mode.element && mode.element.player) { + Object.defineProperties(lib.element.Player.prototype, Object.getOwnPropertyDescriptors(mode.element.player)); + } + if (mode.skill) { + for (var i in mode.skill) { + lib.skill[i] = mode.skill[i]; + } + } + if (mode.card) { + for (var i in mode.card) { + lib.card[i] = mode.card[i]; + } + } + game.finishCards(); + if (mode.characterPack) { + for (var i in mode.characterPack) { + lib.characterPack[i] = mode.characterPack[i]; + } + } + _status.event = lib.element.GameEvent.initialGameEvent(); + _status.paused = false; + game.createEvent("game", false).setContent(lib.init.startOnline); + game.loop(); + game.send("inited"); + ui.create.connecting(true); + }); + } + if (_status.event.parent) { + game.forceOver("noover", proceed); + } + else { + proceed(); + } + for (var i in lib.characterPack) { + for (var j in lib.characterPack[i]) { + lib.character[j] = lib.character[j] || lib.characterPack[i][j]; + } + } + }, + reinit: function (config, state, state2, ip, observe, onreconnect, cardtag, postReconnect) { + ui.auto.show(); + ui.pause.show(); + game.clearConnect(); + clearTimeout(_status.createNodeTimeout); + game.online = true; + game.ip = ip; + game.servermode = state.servermode; + game.roomId = state.roomId; + if (state.over) { + _status.over = true; + } + if (observe) { + game.observe = true; + game.onlineID = null; + game.roomId = null; + } + if (game.servermode && !observe) { + game.saveConfig("reconnect_info", [_status.ip, game.onlineID, game.roomId]); + } + else { + game.saveConfig("reconnect_info", [_status.ip, game.onlineID]); + if (!observe) { + game.saveConfig("tmp_user_roomId", game.roomId); + } + } + _status.connectMode = true; + lib.configOL = config; + lib.playerOL = {}; + lib.cardOL = {}; + + game.loadModeAsync(config.mode, function (mode) { + for (var i in mode.ai) { + if (typeof mode.ai[i] == "object") { + if (ai[i] == undefined) ai[i] = {}; + for (var j in mode.ai[i]) { + ai[i][j] = mode.ai[i][j]; + } + } + else { + ai[i] = mode.ai[i]; + } + } + for (var i in mode.get) { + if (typeof mode.get[i] == "object") { + if (get[i] == undefined) get[i] = {}; + for (var j in mode.get[i]) { + get[i][j] = mode.get[i][j]; + } + } + else { + get[i] = mode.get[i]; + } + } + for (var i in mode.translate) { + lib.translate[i] = mode.translate[i]; + } + if (mode.game) { + game.getIdentityList = mode.game.getIdentityList; + game.getIdentityList2 = mode.game.getIdentityList2; + game.updateState = mode.game.updateState; + game.showIdentity = mode.game.showIdentity; + } + if (mode.element && mode.element.player) { + Object.defineProperties(lib.element.Player.prototype, Object.getOwnPropertyDescriptors(mode.element.player)); + } + if (mode.skill) { + for (var i in mode.skill) { + lib.skill[i] = mode.skill[i]; + } + } + if (mode.card) { + for (var i in mode.card) { + lib.card[i] = mode.card[i]; + } + } + game.finishCards(); + if (mode.characterPack) { + for (var i in mode.characterPack) { + lib.characterPack[i] = mode.characterPack[i]; + } + } + if (mode.onreinit) { + mode.onreinit(); + } + _status.cardtag = get.parsedResult(cardtag); + game.players = []; + game.dead = []; + for (var i in lib.characterPack) { + for (var j in lib.characterPack[i]) { + lib.character[j] = lib.character[j] || lib.characterPack[i][j]; + } + } + game.clearArena(); + game.finishCards(); + if (!observe) { + ui.create.chat(); + if (ui.exitroom) { + ui.exitroom.remove(); + delete ui.exitroom; + } + } + else { + if (!ui.exitroom) { + ui.create.system("退出旁观", function () { + game.saveConfig("reconnect_info"); + game.reload(); + }, true); + } + if (!lib.configOL.observe_handcard) { + ui.arena.classList.add("observe"); + } + } + postReconnect = get.parsedResult(postReconnect); + for (var i in postReconnect) { + if (Array.isArray(postReconnect[i])) { + postReconnect[i].shift().apply(this, postReconnect[i]); + } + } + state = get.parsedResult(state); + ui.arena.setNumber(state.number); + _status.mode = state.mode; + _status.renku = state.renku; + lib.inpile = state.inpile; + lib.inpile_nature = state.inpile_nature; + var pos = state.players[observe || game.onlineID].position; + for (var i in state.players) { + var info = state.players[i]; + var player = ui.create.player(ui.arena).animate("start"); + player.dataset.position = (info.position < pos) ? info.position - pos + parseInt(state.number) : info.position - pos; + if (i == observe || i == game.onlineID) { + game.me = player; + } + if (player.setModeState) { + player.setModeState(info); + } + else { + player.init(info.name1, info.name2); + if (info.name && info.name != info.name1) player.name = info.name; + } + if (!info.unseen) player.classList.remove("unseen"); + if (!info.unseen2) player.classList.remove("unseen2"); + if (!player.isUnseen(2) && player.storage.nohp) { + delete player.storage.nohp; + player.node.hp.show(); + } + player.playerid = i; + player.nickname = info.nickname; + player.changeGroup(info.group, false, "nobroadcast"); + player.identity = info.identity; + player.identityShown = info.identityShown; + player.hp = info.hp; + player.maxHp = info.maxHp; + player.hujia = info.hujia; + player.sex = info.sex; + player.side = info.side; + player.phaseNumber = info.phaseNumber; + player.seatNum = info.seatNum; + player.disabledSlots = info.disabledSlots; + player.expandedSlots = info.expandedSlots; + player.setNickname(); + if (info.dead) { + player.classList.add("dead"); + if (lib.config.die_move) { + player.$dieflip(); + } + if (player.$dieAfter) { + player.$dieAfter(); + } + game.dead.push(player); + } + else { + game.players.push(player); + } + if (info.linked) { + player.addLink(); + } + if (info.turnedover) { + player.classList.add("turnedover"); + } + if (info.out) { + player.classList.add("out"); + } + if (info.disableJudge) { + player.$disableJudge(); + } + player.$syncDisable(); + + player.directgain(info.handcards); + lib.playerOL[i] = player; + for (var i = 0; i < info.equips.length; i++) { + player.$equip(info.equips[i]); + } + for (var i = 0; i < info.handcards.length; i++) { + info.handcards[i].addGaintag(info.gaintag[i]); + } + for (var i = 0; i < info.specials.length; i++) { + info.specials[i].classList.add("glows"); + } + if (info.expansions.length) { + var expansion_gaintag = []; + player.$addToExpansion(info.expansions); + for (var i = 0; i < info.expansions.length; i++) { + info.expansions[i].addGaintag(info.expansion_gaintag[i]); + expansion_gaintag.addArray(info.expansion_gaintag[i]); + } + for (var i of expansion_gaintag) player.markSkill[i]; + } + for (var i = 0; i < info.judges.length; i++) { + if (info.views[i] && info.views[i] != info.judges[i]) { + info.judges[i].classList.add("fakejudge"); + info.judges[i].viewAs = info.views[i]; + info.judges[i].node.background.innerHTML = lib.translate[info.views[i] + "_bg"] || get.translation(info.views[i])[0] + } + player.node.judges.appendChild(info.judges[i]); + } + ui.updatej(player); + if (!player.setModeState) { + if (!game.getIdentityList && info.identityNode) { + player.node.identity.innerHTML = info.identityNode[0]; + player.node.identity.dataset.color = info.identityNode[1]; + } + else if (player == game.me || player.identityShown || observe) { + player.setIdentity(); + player.forceShown = true; + } + else { + player.setIdentity("cai"); + } + if (!lib.configOL.observe_handcard && (lib.configOL.mode == "identity" || lib.configOL.mode == "guozhan")) { + if (observe && !player.identityShown) { + player.setIdentity("cai"); + player.forceShown = false; + } + } + } + player.update(); + } + game.arrangePlayers(); + ui.create.me(true); + + _status.event = lib.element.GameEvent.initialGameEvent(); + _status.paused = false; + _status.dying = get.parsedResult(state.dying) || []; + + if (game.updateState) { + game.updateState(state2); + } + var next = game.createEvent("game", false); + next.setContent(lib.init.startOnline); + if (observe) { + next.custom.replace.target = function (player) { + if (!lib.configOL.observe_handcard && lib.configOL.mode == "guozhan") { + return; + } + if (player.isAlive()) { + if (!game.me.identityShown && lib.configOL.mode == "guozhan") { + game.me.node.identity.firstChild.innerHTML = "猜"; + game.me.node.identity.dataset.color = "unknown"; + } + game.swapPlayer(player); + if (!game.me.identityShown && lib.configOL.mode == "guozhan") { + game.me.node.identity.firstChild.innerHTML = ""; + } + } + } + } + else { + if (Array.isArray(onreconnect)) { + onreconnect.shift().apply(this, onreconnect); + } + } + game.loop(); + game.send("reinited"); + game.showHistory(); + _status.gameStarted = true; + if (lib.config.show_cardpile) { + ui.cardPileButton.style.display = ""; + } + if (!observe && game.me && (game.me.isDead() || _status.over)) { + ui.create.exit(); + } + ui.updatehl(); + ui.create.connecting(true); + }); + }, + exec: function (func) { + var key = game.onlineKey; + if (typeof func == "function") { + var args = Array.from(arguments); + args.shift(); + func.apply(this, args); + } + if (key) { + game.onlineKey = key; + localStorage.setItem(lib.configprefix + "key", game.onlineKey); + } + }, + denied: function (reason) { + switch (reason) { + case "version": + alert("加入失败:版本不匹配,请将游戏更新至最新版"); + game.saveConfig("tmp_owner_roomId"); + game.saveConfig("tmp_user_roomId"); + game.saveConfig("reconnect_info"); + break; + case "gaming": alert("加入失败:游戏已开始"); break; + case "number": alert("加入失败:房间已满"); break; + case "banned": alert("加入失败:房间拒绝你加入"); break; + case "key": + alert("您的游戏版本过低,请升级到最新版"); + game.saveConfig("tmp_owner_roomId"); + game.saveConfig("tmp_user_roomId"); + game.saveConfig("reconnect_info"); + break; + case "offline": + if (_status.paused && _status.event.name == "game") { + setTimeout(game.resume, 500); + } + break; + } + game.ws.close(); + if (_status.connectDenied) { + _status.connectDenied(); + } + }, + cancel: function (id) { + if (_status.event._parent_id == id) { + ui.click.cancel(); + } + if (_status.event.id == id) { + if (_status.event._backup) ui.click.cancel(); + ui.click.cancel(); + if (ui.confirm) { + ui.confirm.close(); + } + if (_status.event.result) { + _status.event.result.id = id; + } + } + }, + closeDialog: function (id) { + var dialog = get.idDialog(id); + if (dialog) { + dialog.close(); + } + }, + createDialog: function (id) { + var args = Array.from(arguments); + args.shift(); + ui.create.dialog.apply(this, args).videoId = id; + }, + gameStart: function () { + for (var i = 0; i < game.connectPlayers.length; i++) { + game.connectPlayers[i].delete(); + } + delete game.connectPlayers; + if (ui.connectStartButton) { + ui.connectStartButton.delete(); + delete ui.connectStartButton; + } + if (ui.connectStartBar) { + ui.connectStartBar.delete(); + delete ui.connectStartBar; + } + if (ui.connectShareButton) { + ui.connectShareButton.delete(); + delete ui.connectShareButton; + } + if (ui.roomInfo) { + ui.roomInfo.remove(); + delete ui.roomInfo; + } + if (ui.exitroom) { + ui.exitroom.remove(); + delete ui.exitroom; + } + ui.auto.show(); + ui.pause.show(); + if (lib.config.show_cardpile) { + ui.cardPileButton.style.display = ""; + } + _status.gameStarted = true; + game.showHistory(); + }, + updateWaiting: function (map) { + if (!game.connectPlayers) return; + if (!lib.translate.zhu) { + lib.translate.zhu = "主"; + } + game.onlinezhu = false; + _status.waitingForPlayer = true; + for (var i = 0; i < map.length; i++) { + if (map[i] == "disabled") { + game.connectPlayers[i].classList.add("unselectable2"); + } + else { + game.connectPlayers[i].classList.remove("unselectable2"); + if (map[i]) { + game.connectPlayers[i].initOL(map[i][0], map[i][1]); + game.connectPlayers[i].playerid = map[i][2]; + if (map[i][3] == "zhu") { + game.connectPlayers[i].setIdentity("zhu"); + if (map[i][2] == game.onlineID) { + game.onlinezhu = true; + if (ui.roomInfo) { + ui.roomInfo.innerHTML = "房间设置"; + } + if (ui.connectStartButton) { + ui.connectStartButton.innerHTML = "开始游戏"; + } + } + } + else { + game.connectPlayers[i].node.identity.firstChild.innerHTML = ""; + } + } + else { + game.connectPlayers[i].uninitOL(); + delete game.connectPlayers[i].playerid; + } + } + } + } + } +}; diff --git a/noname/library/mode.js b/noname/library/mode.js new file mode 100644 index 000000000..ec86ef09d --- /dev/null +++ b/noname/library/mode.js @@ -0,0 +1,2453 @@ +export const MODE = { + identity: { + name: "身份", + connect: { + update(config, map) { + if (config.connect_identity_mode == "stratagem") { + map.connect_round_one_use_fury.show(); + } + else { + map.connect_round_one_use_fury.hide(); + } + if (config.connect_identity_mode == "zhong") { + map.connect_player_number.hide(); + map.connect_limit_zhu.hide(); + map.connect_enhance_zhu.hide(); + map.connect_double_nei.hide(); + map.connect_enable_commoner.hide(); + map.connect_enable_year_limit.show(); + map.connect_zhong_card.show(); + map.connect_special_identity.hide(); + map.connect_double_character.show(); + } + else if (config.connect_identity_mode == "stratagem") { + map.connect_double_character.show(); + map.connect_player_number.show(); + map.connect_limit_zhu.hide(); + map.connect_enhance_zhu.hide(); + map.connect_double_nei.hide(); + map.connect_enable_commoner.hide(); + map.connect_enable_year_limit.show(); + map.connect_zhong_card.hide(); + map.connect_special_identity.hide(); + } + else if (config.connect_identity_mode == "purple") { + map.connect_player_number.hide(); + map.connect_limit_zhu.hide(); + map.connect_enhance_zhu.hide(); + map.connect_double_nei.hide(); + map.connect_enable_commoner.hide(); + map.connect_enable_year_limit.hide(); + map.connect_zhong_card.hide(); + map.connect_special_identity.hide(); + map.connect_double_character.hide(); + } + else { + map.connect_double_character.show(); + map.connect_player_number.show(); + map.connect_limit_zhu.show(); + map.connect_enhance_zhu.show(); + map.connect_double_nei[config.connect_player_number != "2" && !config.connect_enable_commoner ? "show" : "hide"](); + map.connect_enable_commoner[config.connect_player_number != "2" && !config.connect_double_nei ? "show" : "hide"](); + map.connect_enable_year_limit.show(); + map.connect_zhong_card.hide(); + + if (config.connect_player_number == "8") { + map.connect_special_identity.show(); + } + else { + map.connect_special_identity.hide(); + } + } + }, + connect_identity_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "标准", + zhong: "明忠", + stratagem: "谋攻", + purple: "3v3v2", + }, + restart: true, + frequent: true, + intro: "明忠模式和3v3v2模式详见帮助" + }, + connect_player_number: { + name: "游戏人数", + init: "8", + get item() { + return lib.mode.identity.config.player_number.item; + }, + frequent: true, + restart: true, + }, + connect_limit_zhu: { + name: "常备主候选武将数", + init: "group", + restart: true, + item: { + off: "不限制", + group: "按势力筛选", + "4": "四", + "6": "六", + "8": "八", + }, + }, + connect_zhong_card: { + name: "明忠卡牌替换", + init: true, + frequent: true, + restart: true + }, + connect_double_nei: { + name: "双内奸", + init: false, + restart: true, + // frequent:true, + get intro() { + return lib.mode.identity.config.double_nei.intro; + } + }, + connect_enable_commoner: { + name: "启用平民", + init: false, + restart: true, + frequent: false, + get intro() { + return lib.mode.identity.config.enable_commoner.intro; + } + }, + connect_double_character: { + name: "双将模式", + init: false, + frequent: true, + restart: true, + }, + connect_change_card: { + name: "启用手气卡", + init: false, + frequent: true, + restart: true, + }, + connect_special_identity: { + name: "特殊身份", + init: false, + restart: true, + frequent: true, + intro: "开启后游戏中将增加军师、大将、贼首三个身份" + }, + connect_enable_year_limit: { + name: "启用年机制", + init: false, + restart: true, + frequent: false, + get intro() { + return lib.mode.identity.config.enable_year_limit.intro; + } + }, + connect_round_one_use_fury: { + name: "开启首轮强化卡牌", + init: false, + frequent: false, + restart: true, + intro: "谋攻篇规则为第二轮开始才可使用怒气强化卡牌,开启此选项从游戏开始即可强化卡牌。" + }, + connect_enhance_zhu: { + name: "加强主公", + init: false, + restart: true, + intro: "为主公增加一个额外技能" + }, + }, + config: { + update(config, map) { + if (config.identity_mode == "stratagem") { + map.round_one_use_fury.show(); + map.nei_auto_mark_camouflage.show(); + } + else { + map.round_one_use_fury.hide(); + map.nei_auto_mark_camouflage.hide(); + } + if (config.identity_mode == "zhong") { + map.player_number.hide(); + map.enhance_zhu.hide(); + map.double_nei.hide(); + map.auto_identity.hide(); + map.choice_zhu.hide(); + map.limit_zhu.hide(); + map.choice_zhong.hide(); + map.choice_nei.hide(); + map.choice_fan.hide(); + map.enable_commoner.hide(); + map.choice_commoner.hide(); + map.enable_year_limit.show(); + map.ban_identity.hide(); + map.ban_identity2.hide(); + map.ban_identity3.hide(); + map.zhong_card.show(); + map.special_identity.hide(); + map.choose_group.show(); + map.change_choice.show(); + map.auto_mark_identity.show(); + map.double_character.show(); + map.free_choose.show(); + map.change_identity.show(); + if (config.double_character) { + map.double_hp.show(); + } + else { + map.double_hp.hide(); + } + map.continue_game.show(); + } + else if (config.identity_mode == "stratagem") { + map.continue_game.show(); + map.player_number.show(); + map.enhance_zhu.hide(); + map.auto_identity.hide(); + if (config.player_number != "2") { + map.double_nei.show(); + } + else { + map.double_nei.hide(); + } + map.choice_zhu.show(); + map.limit_zhu.hide(); + map.choice_zhong.show(); + map.choice_nei.show(); + map.choice_fan.show(); + map.enable_commoner.hide(); + map.choice_commoner.hide(); + map.enable_year_limit.show(); + map.ban_identity.show(); + if (config.ban_identity == "off") { + map.ban_identity2.hide(); + } + else { + map.ban_identity2.show(); + } + if (config.ban_identity == "off" || config.ban_identity2 == "off") { + map.ban_identity3.hide(); + } + else { + map.ban_identity3.show(); + } + map.zhong_card.hide(); + map.choose_group.show(); + map.auto_mark_identity.hide(); + map.change_choice.show(); + map.free_choose.show(); + map.change_identity.show(); + map.special_identity.hide(); + map.double_character.show(); + if (config.double_character) { + map.double_hp.show(); + } + else { + map.double_hp.hide(); + } + } + else if (config.identity_mode == "purple") { + map.player_number.hide(); + map.enhance_zhu.hide(); + map.double_nei.hide(); + map.auto_identity.hide(); + map.choice_zhu.hide(); + map.limit_zhu.hide(); + map.choice_zhong.hide(); + map.choice_nei.hide(); + map.choice_fan.hide(); + map.enable_commoner.hide(); + map.choice_commoner.hide(); + map.enable_year_limit.hide(); + map.ban_identity.hide(); + map.ban_identity2.hide(); + map.ban_identity3.hide(); + map.zhong_card.hide(); + map.special_identity.hide(); + map.double_character.hide(); + map.double_hp.hide(); + map.choose_group.hide(); + map.auto_mark_identity.hide(); + map.change_choice.hide(); + map.free_choose.hide(); + map.change_identity.hide(); + map.continue_game.hide(); + } + else { + map.continue_game.show(); + map.player_number.show(); + map.enhance_zhu.show(); + map.auto_identity.show(); + map.double_nei[config.player_number != "2" && !config.enable_commoner ? "show" : "hide"](); + map.choice_zhu.show(); + map.limit_zhu.show(); + map.choice_zhong.show(); + map.choice_nei.show(); + map.choice_fan.show(); + map.enable_commoner[config.player_number != "2" && !config.double_nei ? "show" : "hide"](); + map.choice_commoner[config.enable_commoner ? "show" : "hide"](); + map.enable_year_limit.show(); + map.ban_identity.show(); + if (config.ban_identity == "off") { + map.ban_identity2.hide(); + } + else { + map.ban_identity2.show(); + } + if (config.ban_identity == "off" || config.ban_identity2 == "off") { + map.ban_identity3.hide(); + } + else { + map.ban_identity3.show(); + } + map.zhong_card.hide(); + map.choose_group.show(); + map.auto_mark_identity.show(); + map.change_choice.show(); + map.free_choose.show(); + map.change_identity.show(); + if (config.player_number == "8") { + map.special_identity.show(); + } + else { + map.special_identity.hide(); + } + map.double_character.show(); + if (config.double_character) { + map.double_hp.show(); + } + else { + map.double_hp.hide(); + } + } + }, + identity_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "标准", + zhong: "明忠", + stratagem: "谋攻", + purple: "3v3v2", + }, + restart: true, + frequent: true, + intro: "明忠模式与谋攻模式详见帮助" + }, + player_number: { + name: "游戏人数", + init: "8", + get item() { + const minimumNumberOfPlayers = 2, maximumNumberOfPlayers = Math.max(_status.maximumNumberOfPlayers || 10, minimumNumberOfPlayers), item = {}; + for (let playerNumber = minimumNumberOfPlayers; playerNumber <= maximumNumberOfPlayers; playerNumber++) { + item[playerNumber] = `${get.cnNumber(playerNumber)}人`; + } + return item; + }, + frequent: true, + restart: true, + }, + double_nei: { + name: "双内奸", + init: false, + restart: true, + frequent: true, + intro: "若游戏人数不大于9,则开启后游戏中将有两个内奸(内奸胜利条件仍为主内1v1时击杀主公)" + }, + choose_group: { + name: "神武将选择势力", + init: true, + restart: true, + frequent: true, + intro: "若开启此选项,选择神武将的玩家需在亮出自己的武将牌之前为自己选择一个势力。" + }, + nei_fullscreenpop: { + name: "主内单挑特效", + intro: "在进入主内单挑时,弹出全屏文字特效", + init: true, + unfrequent: true, + }, + double_character: { + name: "双将模式", + init: false, + frequent: true, + restart: true, + }, + special_identity: { + name: "特殊身份", + init: false, + restart: true, + frequent: true, + intro: "开启后游戏中将增加军师、大将、贼首三个身份" + }, + zhong_card: { + name: "明忠卡牌替换", + init: true, + frequent: true, + restart: true + }, + double_hp: { + name: "双将体力上限", + init: "pingjun", + item: { + hejiansan: "和减三", + pingjun: "平均值", + zuidazhi: "最大值", + zuixiaozhi: "最小值", + zonghe: "相加", + }, + restart: true, + }, + auto_identity: { + name: "自动显示身份", + item: { + off: "关闭", + one: "一轮", + two: "两轮", + three: "三轮", + always: "始终" + }, + init: "off", + onclick(bool) { + game.saveConfig("auto_identity", bool, this._link.config.mode); + if (get.config("identity_mode") == "zhong") return; + var num; + switch (bool) { + case "一轮": num = 1; break; + case "两轮": num = 2; break; + case "三轮": num = 3; break; + default: num = 0; break; + } + if (num & !_status.identityShown && game.phaseNumber > game.players.length * num && game.showIdentity) { + _status.identityShown = true; + game.showIdentity(false); + } + }, + intro: "游戏进行若干轮将自动显示所有角色的身份", + }, + auto_mark_identity: { + name: "自动标记身份", + init: true, + intro: "根据角色的出牌行为自动标记可能的身份", + }, + enhance_zhu: { + name: "加强主公", + init: false, + restart: true, + intro: "为主公增加一个额外技能" + }, + free_choose: { + name: "自由选将", + init: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + change_identity: { + name: "自由选择身份和座位", + init: true, + onclick(bool) { + game.saveConfig("change_identity", bool, this._link.config.mode); + if (get.mode() != "identity" || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + var dialog; + if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; + else dialog = _status.event.dialog; + if (!_status.brawl || !_status.brawl.noAddSetting) { + if (!dialog.querySelector("table") && get.config("change_identity")) _status.event.getParent().addSetting(dialog); + else _status.event.getParent().removeSetting(dialog); + } + ui.update(); + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (get.mode() != "identity" || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + } + }, + change_card: { + name: "开启手气卡", + init: "disabled", + item: { + disabled: "禁用", + once: "一次", + twice: "两次", + unlimited: "无限", + }, + }, + round_one_use_fury: { + name: "开启首轮强化卡牌", + init: false, + frequent: false, + restart: true, + intro: "谋攻篇规则为第二轮开始才可使用怒气强化卡牌,开启此选项从游戏开始即可强化卡牌。" + }, + nei_auto_mark_camouflage: { + name: "内奸自动标记伪装反贼", + intro: "玩家内奸在游戏开始洞察结束后,自动将被洞察角色标记为反贼。", + init: false, + unfrequent: true, + }, + continue_game: { + name: "显示再战", + init: false, + onclick(bool) { + game.saveConfig("continue_game", bool, this._link.config.mode); + if (get.config("continue_game") && get.mode() == "identity") { + if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { + ui.continue_game = ui.create.control("再战", game.reloadCurrent); + } + } + else if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + }, + intro: "游戏结束后可选择用相同的武将再进行一局游戏" + }, + dierestart: { + name: "死亡后显示重来", + init: true, + onclick(bool) { + game.saveConfig("dierestart", bool, this._link.config.mode); + if (get.config("dierestart") && get.mode() == "identity") { + if (!ui.restart && game.me.isDead() && !_status.connectMode) { + ui.restart = ui.create.control("restart", game.reload); + } + } + else if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + } + }, + revive: { + name: "死亡后显示复活", + init: false, + onclick(bool) { + game.saveConfig("revive", bool, this._link.config.mode); + if (get.config("revive") && get.mode() == "identity") { + if (!ui.revive && game.me.isDead()) { + ui.revive = ui.create.control("revive", ui.click.dierevive); + } + } + else if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + } + }, + ban_identity: { + name: "屏蔽身份", + init: "off", + item: { + off: "关闭", + zhu: "主公", + zhong: "忠臣", + nei: "内奸", + fan: "反贼", + }, + }, + ban_identity2: { + name: "屏蔽身份2", + init: "off", + item: { + off: "关闭", + zhu: "主公", + zhong: "忠臣", + nei: "内奸", + fan: "反贼", + }, + }, + ban_identity3: { + name: "屏蔽身份3", + init: "off", + item: { + off: "关闭", + zhu: "主公", + zhong: "忠臣", + nei: "内奸", + fan: "反贼", + }, + }, + ai_strategy: { + name: "内奸策略", + init: "ai_strategy_1", + item: { + ai_strategy_1: "均衡", + ai_strategy_2: "偏反", + ai_strategy_3: "偏忠", + ai_strategy_4: "酱油", + ai_strategy_5: "天使", + ai_strategy_6: "仇主", + }, + intro: "设置内奸对主忠反的态度" + }, + difficulty: { + name: "AI对人类态度", + init: "normal", + item: { + easy: "友好", + normal: "一般", + hard: "仇视", + }, + }, + choice_zhu: { + name: "主公候选武将数", + init: "3", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + limit_zhu: { + name: "常备主候选武将数", + init: "group", + restart: true, + item: { + off: "不限制", + group: "按势力筛选", + "4": "四", + "6": "六", + "8": "八", + }, + }, + choice_zhong: { + name: "忠臣候选武将数", + init: "4", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + choice_nei: { + name: "内奸候选武将数", + init: "5", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + choice_fan: { + name: "反贼候选武将数", + init: "3", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + enable_commoner: { + name: "启用平民", + init: false, + restart: true, + frequent: false, + intro: "开启后游戏中将有一个平民(身份)加入游戏。
      具体规则请查看帮助。", + }, + choice_commoner: { + name: "平民候选武将数", + init: "4", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + enable_year_limit: { + name: "启用年机制", + init: false, + restart: true, + frequent: false, + intro: "开启后将会加入年机制。
      年机制的具体规则请查看帮助。", + }, + } + }, + guozhan: { + name: "国战", + connect: { + connect_guozhan_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "势备", + yingbian: "应变", + old: "怀旧", + }, + frequent: true, + restart: true, + intro: "
    • 势备:默认模式,使用线下《君临天下·势备篇》的牌堆进行游戏。
    • 应变:使用OL的应变国战牌堆进行游戏。
    • 怀旧:使用传统国战的牌堆进行游戏。", + }, + connect_player_number: { + name: "游戏人数", + init: "8", + get item() { + return lib.mode.guozhan.config.player_number.item; + }, + frequent: true, + restart: true, + }, + connect_aozhan: { + name: "鏖战模式", + init: true, + intro: "若开启此选项,则将在游戏中引入“鏖战模式”的规则:
      当游戏中仅剩四名或更少角色时(七人以下游戏时改为三名或更少),若此时全场没有超过一名势力相同的角色,则从一个新的回合开始,游戏进入鏖战模式直至游戏结束。
      ◇在鏖战模式下,【桃】只能当做【杀】或【闪】使用或打出,不能用来回复体力。
      注:进入鏖战模式后,即使之后有两名或者更多势力相同的角色出现,仍然不会取消鏖战模式。", + frequent: true, + restart: true, + }, + get connect_separatism() { + return lib.mode.guozhan.config.separatism; + }, + connect_initshow_draw: { + name: "首亮奖励", + item: { + "off": "关闭", + "draw": "摸牌", + "mark": "标记", + }, + init: "mark", + frequent: true, + intro: "第一个明置武将牌的角色可获得首亮奖励" + }, + connect_viewnext: { + name: "观看下家副将", + init: false, + intro: "若开启此选项,所有的玩家将在挑选武将后,分发起始手牌之前,分别观看自己下家的副将。", + }, + connect_zhulian: { + name: "珠联璧合", + init: true, + intro: "主将和副将都明置后,若为特定组合,可获得【珠联璧合】标记" + }, + connect_junzhu: { + name: "替换君主", + init: true, + restart: true, + intro: "若开启此选项,玩家的第一个回合开始时,若其主武将牌有对应的君主武将牌,则其可以将此武将牌替换为对应的君主武将牌,然后重新调整体力上限。若玩家的体力上限因此增大,则玩家回复等量的体力。" + }, + connect_change_card: { + name: "启用手气卡", + init: false, + frequent: true, + restart: true, + } + }, + config: { + update(config, map) { + if (config.onlyguozhan) { + map.junzhu.show(); + } + else { + map.junzhu.hide(); + } + ui.aozhan_bgm = map.aozhan_bgm; + map.aozhan_bgm._link.config.updatex.call(map.aozhan_bgm, []); + }, + guozhan_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "势备", + yingbian: "应变", + old: "怀旧", + free: "自由", + }, + frequent: true, + restart: true, + intro: "
    • 势备:默认模式,使用线下《君临天下·势备篇》的牌堆进行游戏。
    • 应变:使用OL的应变国战牌堆进行游戏。
    • 怀旧:使用传统国战的牌堆进行游戏。
    • 自由:使用玩家的自定义牌堆进行游戏。", + }, + player_number: { + name: "游戏人数", + init: "8", + get item() { + const minimumNumberOfPlayers = 2, maximumNumberOfPlayers = Math.max(_status.maximumNumberOfPlayers || 12, minimumNumberOfPlayers), item = {}; + for (let playerNumber = minimumNumberOfPlayers; playerNumber <= maximumNumberOfPlayers; playerNumber++) { + item[playerNumber] = `${get.cnNumber(playerNumber)}人`; + } + return item; + }, + frequent: true, + restart: true, + }, + aozhan: { + name: "鏖战模式", + init: true, + frequent: true, + restart: true, + intro: "若开启此选项,则将在游戏中引入“鏖战模式”的规则:
      当游戏中仅剩四名或更少角色时(七人以下游戏时改为三名或更少),若此时全场没有超过一名势力相同的角色,则从一个新的回合开始,游戏进入鏖战模式直至游戏结束。
      ◇在鏖战模式下,【桃】只能当做【杀】或【闪】使用或打出,不能用来回复体力。
      注:进入鏖战模式后,即使之后有两名或者更多势力相同的角色出现,仍然不会取消鏖战模式。", + }, + separatism: { + name: "群雄割据", + init: false, + frequent: true, + restart: true, + intro: "开放不同势力组合,以优先亮出的武将牌作为自己的势力,双势力武将则使用列表的第一个势力" + }, + initshow_draw: { + name: "首亮奖励", + item: { + "off": "关闭", + "draw": "摸牌", + "mark": "标记", + }, + init: "mark", + frequent: true, + intro: "第一个明置身份牌的角色可获得摸牌奖励" + }, + viewnext: { + name: "观看下家副将", + init: false, + intro: "若开启此选项,所有的玩家将在挑选武将后,分发起始手牌之前,分别观看自己下家的副将。", + }, + aozhan_bgm: { + updatex() { + this.lastChild.innerHTML = this._link.config.item[lib.config.mode_config.guozhan.aozhan_bgm]; + if (!Array.isArray(_status.aozhanBGMToRemove)) return; + const menu = this._link.menu; + for (let i = 0; i < menu.childElementCount; i++) { + const link = menu.childNodes[i]._link; + if (["disabled", "random"].includes(link) || !_status.aozhanBGMToRemove.includes(link)) continue; + _status.aozhanBGMToRemove.remove(link); + menu.childNodes[i].delete(); + } + }, + name: "鏖战背景音乐", + item: { + disabled: "不启用", + online: "Online", + rewrite: "Rewrite", + chaoming: "潮鸣", + random: "随机播放", + }, + init: "rewrite", + onclick(item) { + game.saveConfig("aozhan_bgm", item, this._link.config.mode); + if (_status._aozhan == true) game.playBackgroundMusic(); + }, + }, + zhulian: { + name: "珠联璧合", + init: true, + // frequent:true, + intro: "主将和副将都明置后,若为特定组合,可获得【珠联璧合】标记" + }, + changeViceType: { + name: "副将变更方式", + init: "default", + item: { + default: "发现式", + online: "随机式", + }, + frequent: true, + restart: true, + }, + onlyguozhan: { + name: "使用国战武将", + init: true, + frequent: true, + restart: true, + intro: "开启武将技能将替换为国战版本并禁用非国战武将" + }, + guozhanSkin: { + name: "使用国战皮肤", + init: true, + frequent: true, + restart: true, + intro: "开启此选项后,将会把有国战专属皮肤的武将替换为国战皮肤" + }, + junzhu: { + name: "替换君主", + init: true, + // frequent:true, + restart: true, + intro: "若开启此选项,玩家的第一个回合开始时,若其主武将牌有对应的君主武将牌,则其可以将此武将牌替换为对应的君主武将牌,然后重新调整体力上限。若玩家的体力上限因此增大,则玩家回复等量的体力。" + }, + double_hp: { + name: "双将体力上限", + init: "pingjun", + item: { + hejiansan: "和减三", + pingjun: "平均值", + zuidazhi: "最大值", + zuixiaozhi: "最小值", + zonghe: "相加", + }, + restart: true, + }, + free_choose: { + name: "自由选将", + init: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + onlyguozhanexpand: { + name: "默认展开自由选将", + init: false, + restart: true, + intro: "开启后自由选将对话框将默认显示全部武将" + }, + change_identity: { + name: "自由选择座位", + init: true, + onclick(bool) { + game.saveConfig("change_identity", bool, this._link.config.mode); + if (get.mode() != "guozhan" || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + var dialog; + if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; + else dialog = _status.event.dialog; + if (!_status.brawl || !_status.brawl.noAddSetting) { + if (!dialog.querySelector("table") && get.config("change_identity")) _status.event.getParent().addSetting(dialog); + else _status.event.getParent().removeSetting(dialog); + } + ui.update(); + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (get.mode() != "guozhan" || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + } + }, + change_card: { + name: "开启手气卡", + init: "disabled", + item: { + disabled: "禁用", + once: "一次", + twice: "两次", + unlimited: "无限", + } + }, + continue_game: { + name: "显示再战", + init: true, + intro: "游戏结束后可选择用相同的武将再进行一局游戏", + onclick(bool) { + game.saveConfig("continue_game", bool, this._link.config.mode); + if (get.config("continue_game") && get.mode() == "guozhan") { + if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { + ui.continue_game = ui.create.control("再战", game.reloadCurrent); + } + } + else if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + } + }, + dierestart: { + name: "死亡后显示重来", + init: true, + onclick(bool) { + game.saveConfig("dierestart", bool, this._link.config.mode); + if (get.config("dierestart") && get.mode() == "guozhan") { + if (!ui.restart && game.me.isDead() && !_status.connectMode) { + ui.restart = ui.create.control("restart", game.reload); + } + } + else if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + } + }, + revive: { + name: "死亡后显示复活", + init: false, + onclick(bool) { + game.saveConfig("revive", bool, this._link.config.mode); + if (get.config("revive") && get.mode() == "guozhan") { + if (!ui.revive && game.me.isDead()) { + ui.revive = ui.create.control("revive", ui.click.dierevive); + } + } + else if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + } + }, + difficulty: { + name: "AI对人类态度", + init: "normal", + item: { + easy: "友好", + normal: "一般", + hard: "仇视", + } + }, + choice_num: { + name: "候选武将数", + init: "7", + restart: true, + item: { + "5": "五", + "6": "六", + "7": "七", + "8": "八", + "9": "九", + "10": "十", + } + }, + } + }, + versus: { + name: "对决", + connect: { + update(config, map) { + if (config.connect_versus_mode == "1v1") { + map.connect_choice_num.show(); + map.connect_replace_number.show(); + } + else { + map.connect_choice_num.hide(); + map.connect_replace_number.hide(); + } + if (config.connect_versus_mode == "2v2" || config.connect_versus_mode == "3v3") { + map.connect_replace_handcard.show(); + } + else { + map.connect_replace_handcard.hide(); + } + }, + connect_versus_mode: { + name: "游戏模式", + init: "1v1", + item: { + "1v1": "1v1", + "2v2": "2v2", + "3v3": "3v3", + "4v4": "4v4", + "guandu": "官渡", + }, + frequent: true + }, + connect_replace_handcard: { + name: "四号位保护", + init: true, + frequent: true, + intro: "最后行动的角色起始手牌数+1" + }, + connect_olfeiyang_four: { + name: "四号位获得【飞扬】", + init: true, + frequent: true, + intro: "最后行动的角色获得技能【飞扬】(准备阶段,你可以弃置三张牌,然后弃置判定区的一张牌)", + }, + connect_choice_num: { + name: "侯选武将数", + init: "20", + frequent: true, + item: { + "12": "12人", + "16": "16人", + "20": "20人", + "24": "24人", + "40": "40人", + } + }, + connect_replace_number: { + name: "替补人数", + init: "2", + frequent: true, + item: { + "0": "无", + "1": "1人", + "2": "2人", + "3": "3人", + "4": "4人", + "5": "5人", + } + } + }, + config: { + update(config, map) { + if (config.versus_mode == "four") { + map.change_choice.hide(); + map.ladder.show(); + if (config.ladder) { + map.ladder_monthly.show(); + map.ladder_reset.show(); + } + else { + map.ladder_monthly.hide(); + map.ladder_reset.hide(); + } + map.enable_all.show(); + map.enable_all_cards_four.show(); + map.four_assign.show(); + map.four_phaseswap.show(); + map.expand_dialog.show(); + map.fouralign.show(); + map.edit_character_four.show(); + map.reset_character_four.show(); + } + else { + map.change_choice.show(); + map.ladder.hide(); + map.ladder_monthly.hide(); + map.ladder_reset.hide(); + map.enable_all.hide(); + map.enable_all_cards_four.hide(); + map.four_assign.hide(); + map.four_phaseswap.hide(); + map.expand_dialog.hide(); + map.fouralign.hide(); + map.edit_character_four.hide(); + map.reset_character_four.hide(); + } + if (config.versus_mode == "three") { + map.edit_character_three.show(); + map.reset_character_three.show(); + } + else { + map.edit_character_three.hide(); + map.reset_character_three.hide(); + } + if (config.versus_mode == "three" || config.versus_mode == "one") { + map.enable_all_three.show(); + map.enable_all_cards.show(); + } + else { + map.enable_all_three.hide(); + map.enable_all_cards.hide(); + } + if (config.versus_mode == "jiange" || config.versus_mode == "two" || config.versus_mode == "endless" || + config.versus_mode == "three" || config.versus_mode == "one" || config.versus_mode == "siguo") { + map.free_choose.show(); + } + else { + map.free_choose.hide(); + } + if (config.versus_mode == "jiange") { + map.double_character_jiange.show(); + } + else { + map.double_character_jiange.hide(); + } + if (config.versus_mode == "two") { + map.replace_handcard_two.show(); + map.olfeiyang_four.show(); + map.replace_character_two.show(); + map.two_assign.show(); + map.two_phaseswap.show(); + } + else { + map.replace_handcard_two.hide(); + map.olfeiyang_four.hide(); + map.replace_character_two.hide(); + map.two_assign.hide(); + map.two_phaseswap.hide(); + } + if (config.versus_mode == "two" || config.versus_mode == "siguo" || config.versus_mode == "four") { + if (config.versus_mode == "four" && (config.four_assign || config.four_phaseswap)) { + map.change_identity.hide(); + } + else { + map.change_identity.show(); + } + } + else { + map.change_identity.hide(); + } + if (config.versus_mode == "siguo") { + map.siguo_character.show(); + } + else { + map.siguo_character.hide(); + } + }, + versus_mode: { + name: "游戏模式", + init: "four", + item: { + four: "对抗", + three: "统率", + two: "欢乐", + guandu: "官渡", + jiange: "剑阁", + siguo: "四国", + standard: "自由" + }, + restart: true, + frequent: true, + }, + ladder: { + name: "天梯模式", + init: true, + frequent: true, + restart: true + }, + ladder_monthly: { + name: "每月重置天梯", + init: true, + frequent: true, + }, + enable_all: { + name: "启用全部武将", + init: false, + frequent: true, + restart: true, + }, + enable_all_cards_four: { + name: "启用全部卡牌", + init: false, + frequent: true, + restart: true, + }, + enable_all_three: { + name: "启用全部武将", + init: false, + frequent: true, + restart: true, + }, + enable_all_cards: { + name: "启用全部卡牌", + init: false, + frequent: true, + restart: true, + }, + four_assign: { + name: "代替队友选将", + init: false, + restart: true, + }, + four_phaseswap: { + name: "代替队友行动", + init: false, + restart: true, + }, + two_assign: { + name: "代替队友选将", + init: false, + restart: true, + }, + two_phaseswap: { + name: "代替队友行动", + init: false, + restart: true, + }, + free_choose: { + name: "自由选将", + init: true, + frequent: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (!ui.create.cheat2) return; + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + fouralign: { + name: "自由选择阵型", + init: false + }, + change_identity: { + name: "自由选择座位", + init: true, + onclick(bool) { + game.saveConfig("change_identity", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (_status.mode == "four") { + if (get.config("four_assign") || get.config("four_phaseswap")) return; + if (bool) { + if (_status.event.parent.addSetting) { + _status.event.parent.addSetting(); + } + } + else { + var seats = _status.event.parent.seatsbutton; + if (seats) { + while (seats.length) { + seats.shift().remove(); + } + delete _status.event.parent.seatsbutton; + } + } + } + else { + var dialog; + if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; + else dialog = _status.event.dialog; + if (!_status.brawl || !_status.brawl.noAddSetting) { + if (!dialog.querySelector("table") && get.config("change_identity")) _status.event.getParent().addSetting(dialog); + else _status.event.getParent().removeSetting(dialog); + } + ui.update(); + } + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + }, + frequent: true, + }, + double_character_jiange: { + name: "双将模式", + init: false, + frequent: true, + }, + replace_handcard_two: { + name: "四号位保护", + init: true, + frequent: true, + intro: "最后行动的角色起始手牌+1" + }, + olfeiyang_four: { + name: "四号位获得【飞扬】", + init: true, + frequent: true, + intro: "最后行动的角色获得技能【飞扬】(准备阶段,你可以弃置三张牌,然后弃置判定区的一张牌)", + }, + replace_character_two: { + name: "替补模式", + init: false, + frequent: true, + intro: "每个额外选择一名武将,死亡后用该武将代替重新上场,替补武将用完时失败" + }, + expand_dialog: { + name: "默认展开选将框", + intro: "选将框打开时直接显示全部武将(可能使游戏在开始时卡顿)", + init: false, + }, + siguo_character: { + name: "专属武将出场率", + init: "increase", + item: { + increase: "大概率", + normal: "默认概率", + off: "不出现", + }, + frequent: true + }, + ladder_reset: { + name: "重置天梯数据", + onclick() { + var node = this; + if (node._clearing) { + game.save("ladder", { + current: 900, + top: 900, + month: (new Date()).getMonth() + }); + ui.ladder.innerHTML = "卫士五"; + clearTimeout(node._clearing); + node.firstChild.innerHTML = "重置天梯数据"; + delete node._clearing; + return; + } + node.firstChild.innerHTML = "单击以确认 (3)"; + node._clearing = setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (2)"; + node._clearing = setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (1)"; + node._clearing = setTimeout(function () { + node.firstChild.innerHTML = "重置天梯数据"; + delete node._clearing; + }, 1000); + }, 1000); + }, 1000); + }, + clear: true, + }, + edit_character_three: { + name: "编辑统率将池", + clear: true, + onclick() { + if (get.mode() != "versus") { + alert("请进入对决模式,然后再编辑将池"); + return; + } + var container = ui.create.div(".popup-container.editor"); + var node = container; + var map = get.config("character_three") || lib.choiceThree; + var str = "character=[\n "; + for (var i = 0; i < map.length; i++) { + str += `"${map[i]}",`; + if (i + 1 < map.length && (i + 1) % 5 == 0) str += "\n "; + } + str += "\n];"; + node.code = str; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + var character = null; + eval(code); + if (!Array.isArray(character)) { + throw ("err"); + } + } + catch (e) { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + game.saveConfig("character_three", character, "versus"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + delete window.saveNonameInput; + }; + window.saveNonameInput = saveInput; + var editor = ui.create.editor(container, saveInput); + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, editor); + } + } + }, + }, + reset_character_three: { + name: "重置统率将池", + intro: "将统率三军模式下的将池重置为默认将池", + clear: true, + onclick() { + if (confirm("该操作不可撤销!是否清除统率三军模式的自定义将池,并将其重置为默认将池?")) { + game.saveConfig("character_three", null, "versus"); + alert("将池已重置"); + } + }, + }, + edit_character_four: { + name: "编辑4v4将池", + clear: true, + onclick() { + if (get.mode() != "versus") { + alert("请进入对决模式,然后再编辑将池"); + return; + } + var container = ui.create.div(".popup-container.editor"); + var node = container; + var map = get.config("character_four") || lib.choiceFour; + var str = "character=[\n "; + for (var i = 0; i < map.length; i++) { + str += `"${map[i]}",`; + if (i + 1 < map.length && (i + 1) % 5 == 0) str += "\n "; + } + str += "\n];"; + node.code = str; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + var character = null; + eval(code); + if (!Array.isArray(character)) { + throw ("err"); + } + } + catch (e) { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + game.saveConfig("character_four", character, "versus"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + delete window.saveNonameInput; + }; + window.saveNonameInput = saveInput; + var editor = ui.create.editor(container, saveInput); + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, editor); + } + } + }, + }, + reset_character_four: { + name: "重置4v4将池", + intro: "将4v4模式下的将池重置为默认将池", + clear: true, + onclick() { + if (confirm("该操作不可撤销!是否清除4v4模式的自定义将池,并将其重置为默认将池?")) { + game.saveConfig("character_four", null, "versus"); + alert("将池已重置"); + } + }, + }, + } + }, + connect: { + name: "联机", + config: { + connect_nickname: { + name: "联机昵称", + input: true, + frequent: true, + }, + connect_avatar: { + name: "联机头像", + init: "caocao", + item: {}, + frequent: true, + onclick(item) { + game.saveConfig("connect_avatar", item); + game.saveConfig("connect_avatar", item, "connect"); + } + }, + hall_ip: { + name: "联机大厅", + input: true, + frequent: true, + }, + hall_button: { + name: "联机大厅按钮", + init: true, + frequent: true, + onclick(bool) { + game.saveConfig("hall_button", bool, "connect"); + if (ui.hall_button) { + if (bool) { + ui.hall_button.style.display = ""; + } + else { + ui.hall_button.style.display = "none"; + } + } + } + }, + wss_mode: { + name: "使用WSS协议", + init: false, + frequent: true, + intro: "在用户填写的IP地址没有直接指定使用WS/WSS协议的情况下,默认使用WSS协议,而非WS协议来连接到联机服务器。
      请不要轻易勾选此项!", + }, + read_clipboard: { + name: "读取邀请链接", + init: false, + frequent: true, + intro: "读取剪贴板以解析邀请链接自动加入联机房间", + } + } + }, + boss: { + name: "挑战", + config: { + free_choose: { + name: "自由选将", + init: true, + frequent: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + }, + frequent: true, + }, + single_control: { + name: "单人控制", + init: true, + frequent: true, + onclick(bool) { + game.saveConfig("single_control", bool, this._link.config.mode); + if (ui.single_swap && game.me != game.boss) { + if (bool) { + ui.single_swap.style.display = "none"; + } + else { + ui.single_swap.style.display = ""; + } + } + }, + intro: "只控制一名角色,其他角色由AI控制" + } + } + }, + doudizhu: { + name: "斗地主", + connect: { + update(config, map) { + if (config.connect_doudizhu_mode == "online") { + map.connect_change_card.hide(); + } + else { + map.connect_change_card.show(); + } + if (config.connect_doudizhu_mode != "normal") { + map.connect_double_character.hide(); + } + else { + map.connect_double_character.show(); + } + }, + connect_doudizhu_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "休闲", + kaihei: "开黑", + huanle: "欢乐", + binglin: "兵临", + online: "智斗", + }, + restart: true, + frequent: true, + }, + connect_double_character: { + name: "双将模式", + init: false, + frequent: true, + restart: true, + }, + connect_change_card: { + name: "启用手气卡", + init: false, + frequent: true, + restart: true, + }, + }, + config: { + update(config, map) { + if (config.doudizhu_mode == "online") { + map.change_card.hide(); + map.edit_character.show(); + map.reset_character.show(); + } + else { + map.change_card.show(); + map.edit_character.hide(); + map.reset_character.hide(); + } + if (config.doudizhu_mode != "normal") { + map.double_character.hide(); + map.free_choose.hide(); + map.change_identity.hide(); + map.change_choice.hide(); + map.continue_game.hide(); + map.dierestart.hide(); + map.choice_zhu.hide(); + map.choice_fan.hide(); + map.revive.hide(); + } + else { + map.double_character.show(); + map.free_choose.show(); + map.change_identity.show(); + map.change_choice.show(); + map.continue_game.show(); + map.dierestart.show(); + map.choice_zhu.show(); + map.choice_fan.show(); + map.revive.show(); + } + if (config.double_character && config.doudizhu_mode == "normal") { + map.double_hp.show(); + } + else { + map.double_hp.hide(); + } + }, + doudizhu_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "休闲", + kaihei: "开黑", + huanle: "欢乐", + binglin: "兵临", + online: "智斗", + }, + restart: true, + frequent: true, + }, + double_character: { + name: "双将模式", + init: false, + frequent: true, + restart: true, + }, + double_hp: { + name: "双将体力上限", + init: "pingjun", + item: { + hejiansan: "和减三", + pingjun: "平均值", + zuidazhi: "最大值", + zuixiaozhi: "最小值", + zonghe: "相加", + }, + restart: true, + }, + free_choose: { + name: "自由选将", + init: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + change_identity: { + name: "自由选择身份和座位", + init: true, + onclick(bool) { + game.saveConfig("change_identity", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + var dialog; + if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; + else dialog = _status.event.dialog; + if (!_status.brawl || !_status.brawl.noAddSetting) { + if (!dialog.querySelector("table") && get.config("change_identity")) _status.event.getParent().addSetting(dialog); + else _status.event.getParent().removeSetting(dialog); + } + ui.update(); + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + } + }, + change_card: { + name: "开启手气卡", + init: "disabled", + item: { + disabled: "禁用", + once: "一次", + twice: "两次", + unlimited: "无限", + }, + }, + continue_game: { + name: "显示再战", + init: false, + onclick(bool) { + game.saveConfig("continue_game", bool, this._link.config.mode); + if (get.config("continue_game")) { + if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { + ui.continue_game = ui.create.control("再战", game.reloadCurrent); + } + } + else if (ui.continue_game) { + ui.continue_game.close(); + delete ui.continue_game; + } + }, + intro: "游戏结束后可选择用相同的武将再进行一局游戏" + }, + dierestart: { + name: "死亡后显示重来", + init: true, + onclick(bool) { + game.saveConfig("dierestart", bool, this._link.config.mode); + if (get.config("dierestart")) { + if (!ui.restart && game.me.isDead() && !_status.connectMode) { + ui.restart = ui.create.control("restart", game.reload); + } + } + else if (ui.restart) { + ui.restart.close(); + delete ui.restart; + } + } + }, + revive: { + name: "死亡后显示复活", + init: false, + onclick(bool) { + game.saveConfig("revive", bool, this._link.config.mode); + if (get.config("revive")) { + if (!ui.revive && game.me.isDead()) { + ui.revive = ui.create.control("revive", ui.click.dierevive); + } + } + else if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + } + }, + choice_zhu: { + name: "地主候选武将数", + init: "3", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + choice_fan: { + name: "农民候选武将数", + init: "3", + restart: true, + item: { + "3": "三", + "4": "四", + "5": "五", + "6": "六", + "8": "八", + "10": "十", + }, + }, + edit_character: { + name: "编辑将池", + clear: true, + onclick() { + if (get.mode() != "doudizhu") { + alert("请进入斗地主模式,然后再编辑将池"); + return; + } + var container = ui.create.div(".popup-container.editor"); + var node = container; + var map = get.config("character_online") || lib.characterOnline; + node.code = "character=" + get.stringify(map) + "\n/*\n 这里是智斗三国模式的武将将池。\n 您可以在这里编辑对武将将池进行编辑,然后点击“保存”按钮即可保存。\n 将池中的Key势力武将,仅同时在没有被禁用的情况下,才会出现在选将框中。\n 而非Key势力的武将,只要所在的武将包没有被隐藏,即可出现在选将框中。\n 该将池为单机模式/联机模式通用将池。在这里编辑后,即使进入联机模式,也依然会生效。\n 但联机模式本身禁用的武将(如神貂蝉)不会出现在联机模式的选将框中。\n*/"; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + var character = null; + eval(code); + if (!get.is.object(character)) { + throw ("err"); + } + var groups = []; + for (var i in character) { + if (!Array.isArray(character[i])) throw ("type"); + if (character[i].length >= 3) groups.push(i); + } + if (groups.length < 3) throw ("enough"); + } + catch (e) { + if (e == "type") { + alert("请严格按照格式填写,不要写入不为数组的数据"); + } + else if (e == "enough") { + alert("请保证至少写入了3个势力,且每个势力至少有3个武将"); + } + else if (e == "err") { + alert("代码格式有错误,请对比示例代码仔细检查"); + } + else { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + } + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + game.saveConfig("character_online", character, "doudizhu"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + delete window.saveNonameInput; + }; + window.saveNonameInput = saveInput; + var editor = ui.create.editor(container, saveInput); + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, editor); + } + } + }, + }, + reset_character: { + name: "重置将池", + intro: "将智斗三国模式下的将池重置为默认将池", + clear: true, + onclick() { + if (confirm("该操作不可撤销!是否清除智斗三国模式的自定义将池,并将其重置为默认将池?")) { + game.saveConfig("character_online", null, "doudizhu"); + alert("将池已重置"); + } + }, + }, + } + }, + single: { + name: "单挑", + connect: { + connect_single_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "新1v1", + dianjiang: "点将单挑", + changban: "血战长坂坡", + }, + restart: true, + frequent: true, + }, + connect_enable_jin: { + name: "启用晋势力武将", + init: false, + restart: true, + frequent: true, + }, + update(config, map) { + if (config.connect_single_mode != "normal") { + map.connect_enable_jin.hide(); + } + else { + map.connect_enable_jin.show(); + } + }, + }, + config: { + single_mode: { + name: "游戏模式", + init: "normal", + item: { + normal: "新1v1", + dianjiang: "点将单挑", + changban: "血战长坂坡", + }, + restart: true, + frequent: true, + }, + enable_jin: { + name: "启用晋势力武将", + init: false, + restart: true, + frequent: true, + }, + update(config, map) { + if (config.single_mode != "normal") { + map.enable_jin.hide(); + } + else { + map.enable_jin.show(); + } + }, + } + }, + chess: { + name: "战棋", + config: { + chess_mode: { + name: "游戏模式", + init: "combat", + item: { + combat: "自由", + three: "统率", + leader: "君主", + }, + restart: true, + frequent: true, + }, + update(config, map) { + if (config.chess_mode == "leader") { + map.chess_leader_save.show(); + map.chess_leader_clear.show(); + map.chess_leader_allcharacter.show(); + map.chess_character.hide(); + } + else { + map.chess_leader_save.hide(); + map.chess_leader_clear.hide(); + map.chess_leader_allcharacter.hide(); + map.chess_character.show(); + } + if (config.chess_mode == "combat") { + map.free_choose.show(); + map.change_choice.show(); + } + else { + map.free_choose.hide(); + map.change_choice.hide(); + } + }, + chess_leader_save: { + name: "选择历程", + init: "save1", + item: { + save1: "一", + save2: "二", + save3: "三", + save4: "四", + save5: "五", + }, + restart: true, + frequent: true, + }, + chess_leader_allcharacter: { + name: "启用全部角色", + init: true, + onclick(bool) { + if (confirm("调整该设置将清除所有进度,是否继续?")) { + for (var i = 1; i < 6; i++) game.save("save" + i, null, "chess"); + game.saveConfig("chess_leader_allcharacter", bool, "chess") + if (get.mode() == "chess") game.reload(); + return; + } + else this.classList.toggle("on"); + }, + }, + chess_leader_clear: { + name: "清除进度", + onclick() { + var node = this; + if (node._clearing) { + for (var i = 1; i < 6; i++) game.save("save" + i, null, "chess"); + game.reload(); + return; + } + node._clearing = true; + node.firstChild.innerHTML = "单击以确认 (3)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (2)"; + setTimeout(function () { + node.firstChild.innerHTML = "单击以确认 (1)"; + setTimeout(function () { + node.firstChild.innerHTML = "清除进度"; + delete node._clearing; + }, 1000); + }, 1000); + }, 1000); + }, + clear: true, + frequent: true, + }, + chess_obstacle: { + name: "随机路障", + init: "0.2", + item: { + "0": "关闭", + "0.2": "少量", + "0.333": "中量", + "0.5": "大量", + }, + frequent: true, + }, + show_range: { + name: "显示卡牌范围", + init: true, + }, + show_distance: { + name: "显示距离", + init: true, + }, + chess_character: { + name: "战棋武将", + init: true, + frequent: true, + }, + chess_card: { + name: "战棋卡牌", + init: true, + frequent: true, + }, + free_choose: { + name: "自由选将", + init: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + }, + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + }, + }, + chessscroll_speed: { + name: "边缘滚动速度", + init: "20", + intro: "鼠标移至屏幕边缘时自动滚屏", + item: { + "0": "不滚动", + "10": "10格/秒", + "20": "20格/秒", + "30": "30格/秒", + } + } + } + }, + tafang: { + name: "塔防", + config: { + tafang_turn: { + name: "游戏胜利", + init: "10", + frequent: true, + item: { + "10": "十回合", + "20": "二十回合", + "30": "三十回合", + "1000": "无限", + } + }, + tafang_difficulty: { + name: "战斗难度", + init: "2", + frequent: true, + item: { + "1": "简单", + "2": "普通", + "3": "困难", + } + }, + show_range: { + name: "显示卡牌范围", + init: true, + }, + show_distance: { + name: "显示距离", + init: true, + }, + chessscroll_speed: { + name: "边缘滚动速度", + intro: "鼠标移至屏幕边缘时自动滚屏", + init: "20", + item: { + "0": "不滚动", + "10": "10格/秒", + "20": "20格/秒", + "30": "30格/秒", + } + } + } + }, + brawl: { + name: "乱斗", + config: { + huanhuazhizhan: { + name: "幻化之战", + init: true, + frequent: true + }, + duzhansanguo: { + name: "毒战三国", + init: true, + frequent: true + }, + daozhiyueying: { + name: "导师月英", + init: true, + frequent: true + }, + weiwoduzun: { + name: "唯我独尊", + init: true, + frequent: true + }, + tongxingzhizheng: { + name: "同姓之争", + init: true, + frequent: true + }, + jiazuzhizheng: { + name: "家族之争", + init: true, + frequent: true + }, + tongqueduopao: { + name: "铜雀夺袍", + init: true, + frequent: true + }, + tongjiangmoshi: { + name: "同将模式", + init: true, + frequent: true + }, + baiyidujiang: { + name: "白衣渡江", + init: true, + frequent: true + }, + qianlidanji: { + name: "千里单骑", + init: true, + frequent: true + }, + liangjunduilei: { + name: "两军对垒", + init: true, + frequent: true + }, + scene: { + name: "创建场景", + init: true, + frequent: true + } + } + }, + stone: { + name: "炉石", + config: { + battle_number: { + name: "出场人数", + init: "1", + frequent: true, + item: { + "1": "一人", + "2": "两人", + "3": "三人", + "4": "四人", + "6": "六人", + "8": "八人", + "10": "十人", + }, + onclick(num) { + game.saveConfig("battle_number", num, this._link.config.mode); + if (_status.connectMode) return; + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (_status.event.getParent().changeDialog) { + _status.event.getParent().changeDialog(); + } + } + }, + mana_mode: { + name: "行动值变化", + init: "inc", + item: { + inf: "涨落", + inc: "递增" + }, + frequent: true + }, + skill_bar: { + name: "怒气值", + init: true, + frequent: true, + restart: true, + }, + double_character: { + name: "双将模式", + init: false, + frequent: true, + restart() { + return _status.event.getParent().name != "chooseCharacter" || _status.event.name != "chooseButton"; + } + }, + free_choose: { + name: "自由选将", + init: true, + onclick(bool) { + game.saveConfig("free_choose", bool, this._link.config.mode); + if (_status.connectMode) return; + if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat2 && get.config("free_choose")) ui.create.cheat2(); + else if (ui.cheat2 && !get.config("free_choose")) { + ui.cheat2.close(); + delete ui.cheat2; + } + } + }, + change_choice: { + name: "开启换将卡", + init: true, + onclick(bool) { + game.saveConfig("change_choice", bool, this._link.config.mode); + if (_status.connectMode) return; + if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; + if (!ui.cheat && get.config("change_choice")) ui.create.cheat(); + else if (ui.cheat && !get.config("change_choice")) { + ui.cheat.close(); + delete ui.cheat; + } + } + } + } + } +}; diff --git a/noname/library/nature-audio.js b/noname/library/nature-audio.js new file mode 100644 index 000000000..2b3a5410d --- /dev/null +++ b/noname/library/nature-audio.js @@ -0,0 +1,39 @@ +export const natureAudio = { + damage: { + fire: "default",//默认,即语音放置在audio/effect下,以damage_fire.mp3 damage_fire2.mp3命名。 + thunder: "default", + ice: "default", + stab: "normal",//正常,即与普通伤害音效相同。 + /* + "example":{ + 1:"../extension/XXX/damage_example.mp3",//1点伤害。 + 2:"../extension/XXX/damage_example2.mp3",//2点及以上伤害 + } + */ + }, + hujia_damage: { + fire: "default",//默认,即语音放置在audio/effect下,以hujia_damage_fire.mp3 hujia_damage_fire2.mp3命名。 + thunder: "default", + ice: "normal",//正常,即与普通伤害音效相同。 + /* + "example":{ + 1:"../extension/XXX/damage_example.mp3",//1点伤害。 + 2:"../extension/XXX/damage_example2.mp3",//2点及以上伤害 + } + */ + }, + sha: { + fire: "default",//默认,即语音放置在audio/card/male与audio/card/female下,命名为sha_fire.mp3 + thunder: "default", + ice: "default", + stab: "default", + poison: "normal",//正常,即播放“杀”的音效。 + kami: "normal", + /* + "example":{ + "male":"../extension/XXXX/sha_example_male.mp3", + "female":"../extension/XXXX/sha_example_female.mp3" + } + */ + } +}; diff --git a/noname/library/other.js b/noname/library/other.js new file mode 100644 index 000000000..d44663a69 --- /dev/null +++ b/noname/library/other.js @@ -0,0 +1,8 @@ +export class Other { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static ignore() { + } +} diff --git a/noname/library/perfect-pair.js b/noname/library/perfect-pair.js new file mode 100644 index 000000000..4f9b0b11c --- /dev/null +++ b/noname/library/perfect-pair.js @@ -0,0 +1 @@ +export const perfectPair = {}; diff --git a/noname/library/pinyins.js b/noname/library/pinyins.js new file mode 100644 index 000000000..942ed99d4 --- /dev/null +++ b/noname/library/pinyins.js @@ -0,0 +1,5 @@ +import { pinyinsMetadata } from "./pinyins/metadata.js"; + +export const pinyins = { + _metadata: pinyinsMetadata +}; diff --git a/noname/library/pinyins/metadata.js b/noname/library/pinyins/metadata.js new file mode 100644 index 000000000..b47c726f1 --- /dev/null +++ b/noname/library/pinyins/metadata.js @@ -0,0 +1,10 @@ +import { nonMedial } from "./metadata/non-medial.js"; +import { rhyme } from "./metadata/rhyme.js"; + +export const pinyinsMetadata = { + shengmu: ["zh", "ch", "sh", "b", "p", "m", "f", "d", "t", "l", "n", "g", "k", "h", "j", "q", "x", "r", "z", "c", "s", "y", "w"], + special_shengmu: ["j", "q", "x", "y"], + feijiemu: nonMedial, + zhengtirendu: ["zhi", "chi", "shi", "ri", "zi", "ci", "si"], + yunjiao: rhyme +}; diff --git a/noname/library/pinyins/metadata/non-medial.js b/noname/library/pinyins/metadata/non-medial.js new file mode 100644 index 000000000..c40cfa75d --- /dev/null +++ b/noname/library/pinyins/metadata/non-medial.js @@ -0,0 +1,5 @@ +export const nonMedial = { + i: ["ing", "iu", "ie", "in"], + u: ["ui", "un"], + ü: ["üe", "ün"], +}; diff --git a/noname/library/pinyins/metadata/rhyme.js b/noname/library/pinyins/metadata/rhyme.js new file mode 100644 index 000000000..f6215f3a3 --- /dev/null +++ b/noname/library/pinyins/metadata/rhyme.js @@ -0,0 +1,16 @@ +export const rhyme = { + 一麻: ["a", "ia", "ua"], + 二波: ["o", "e", "uo"], + 三皆: ["ie", "üe"], + 四开: ["ai", "uai"], + 五微: ["ei", "ui"], + 六豪: ["ao", "iao"], + 七尤: ["ou", "iu"], + 八寒: ["an", "ian", "uan", "üan"], + 九文: ["en", "in", "un", "ün"], + 十唐: ["ang", "iang", "uang"], + 十一庚: ["eng", "ing", "ong", "ung"], + 十二齐: ["i", "er", "ü"], + 十三支: ["-i"], + 十四姑: ["u"] +}; diff --git a/noname/library/promise-resolve.d.ts b/noname/library/promise-resolve.d.ts new file mode 100644 index 000000000..37290ecda --- /dev/null +++ b/noname/library/promise-resolve.d.ts @@ -0,0 +1 @@ +export type PromiseResolve = (value: T) => void; diff --git a/noname/library/skill.js b/noname/library/skill.js new file mode 100644 index 000000000..76e8c6efd --- /dev/null +++ b/noname/library/skill.js @@ -0,0 +1,1307 @@ +export const skill = { + stratagem_fury: { + marktext: "🔥", + intro: { + name: "怒气", + content: (storage, player) => { + const stratagemFuryMax = _status.stratagemFuryMax, fury = storage || 0; + return `当前怒气值:${typeof stratagemFuryMax == "number" ? `${fury}/${stratagemFuryMax}` : fury}`; + } + } + }, + _stratagem_add_buff: { + log: false, + enable: "chooseToUse", + filter: (event, player) => { + const fury = player.storage.stratagem_fury; + if (!fury) return false; + const stratagemSettings = event.stratagemSettings; + if (!stratagemSettings || !stratagemSettings.roundOneUseFury && game.roundNumber < 2) return false; + const cards = player.getCards("hs"); + if (!cards.length) return false; + const cost = lib.stratagemBuff.cost, names = Array.from(cost.keys()); + if (!names.length) return false; + return cards.some(card => game.checkMod(card, player, "unchanged", "cardEnabled2", player) && names.some(availableName => availableName == get.name(card, player) && event.filterCard(new lib.element.VCard({ + name: availableName, + nature: get.nature(card, player), + isCard: true, + cards: [card] + }), player, event) && fury >= cost.get(availableName))); + }, + onChooseToUse: event => { + const player = _status.event.player, fury = player.storage.stratagem_fury; + if (!fury) return; + if (!event.stratagemSettings && !game.online) event.set("stratagemSettings", { + roundOneUseFury: _status.connectMode ? lib.configOL.round_one_use_fury : get.config("round_one_use_fury") + }); + const cost = lib.stratagemBuff.cost.get("shan"); + if (typeof cost != "number" || !event.shanRequired) return; + event.addNumber("shanIgnored", Math.min(player.countCards(lib.skill._stratagem_add_buff.position, { + name: "shan" + }), Math.floor(fury / cost))); + }, + check: card => { + const player = _status.event.player; + if (_status.event.type == "phase") { + const cardName = get.name(card, player); + if (cardName == "sha") { + if (game.hasPlayer(current => { + if (!player.canUse(card, current)) return false; + const storage = player.storage, zhibi = storage.zhibi; + return (zhibi && !zhibi.includes(current) || (get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1))) && current.mayHaveShan() && player.hasSkill("jiu"); + })) return 1; + return 0; + } + if (cardName == "tao") { + if (player.hp <= 2 && player.getDamagedHp() >= 2) return 1; + return 0; + } + return 1; + } + if (_status.event.type == "dying") return get.attitude(player, _status.event.dying) > 3 ? 1 : 0; + return (_status.event.getParent().shanRequired || 1) > 1 && get.damageEffect(player, _status.event.getParent().player || player, player) < 0 ? 1 : 0; + }, + position: "hs", + filterCard: (card, player, event) => { + if (!event) event = _status.event; + const filterCard = event._backup.filterCard; + const cost = lib.stratagemBuff.cost; + return Array.from(cost.keys()).some(availableName => availableName == get.name(card, player) && filterCard(new lib.element.VCard({ + name: availableName, + nature: get.nature(card, player), + isCard: true, + cards: [card] + }), player, _status.event) && player.storage.stratagem_fury >= cost.get(availableName)); + }, + viewAs: (cards, player) => { + const cardName = get.name(cards[0], player); + return cardName ? new lib.element.VCard({ + name: cardName, + nature: get.nature(cards[0], player), + suit: get.suit(cards[0], player), + number: get.number(cards[0], player), + isCard: true, + cards: [cards[0]], + storage: { + stratagem_buffed: 1 + } + }) : new lib.element.VCard(); + }, + prompt: () => { + const span = document.createElement("span"); + span.classList.add("text"); + span.style.fontFamily = "yuanli"; + const stratagemBuff = lib.stratagemBuff, cost = stratagemBuff.cost; + stratagemBuff.prompt.forEach((prompt, cardName) => { + const li = document.createElement("li"); + li.innerHTML = `【${get.translation(cardName)}】:${cost.get(cardName)}点怒气。${prompt()}`; + span.appendChild(li); + }); + return `当你需要使用位于“强化表”内的非虚拟卡牌时,你可以消耗对应数量的怒气将其强化并使用。${document.createElement("hr").outerHTML}${span.outerHTML}`; + }, + onuse: (result, player) => { + player.logSkill(result.skill); + const stratagemBuff = lib.stratagemBuff, cardName = result.card.name; + player.changeFury(-stratagemBuff.cost.get(cardName), true); + const gameEvent = get.event(), effect = stratagemBuff.effect.get(cardName); + if (typeof effect == "function") gameEvent.pushHandler("onNextUseCard", effect); + gameEvent.pushHandler("onNextUseCard", (event, option) => { + if (event.step == 0 && option.state == "end") game.broadcastAll(cards => cards.forEach(card => card.clone.classList.add("stratagem-fury-glow")), event.cards); + }); + }, + ai: { + order: (item, player) => { + if (!player) player = _status.event.player; + if (_status.event.type == "phase") for (const card of player.getCards("hs")) { + if (!game.checkMod(card, player, "unchanged", "cardEnabled2", player)) continue; + const cardName = get.name(card, player); + if (cardName == "sha") { + if (game.hasPlayer(current => { + if (!player.canUse(card, current)) return false; + const storage = player.storage, zhibi = storage.zhibi; + return (zhibi && !zhibi.contains(current) || (get.effect(current, card, player, player) >= 2 - Math.max(0, (storage.stratagem_fury || 0) - 1))) && current.mayHaveShan(); + })) return get.order(card, player) + 0.5; + } + else if (cardName == "tao" && player.hp <= 2 && player.getDamagedHp() >= 2) return get.order(card, player) + 0.5; + return 8; + } + return 3.5; + }, + directHit_ai: true, + skillTagFilter: (player, tag, arg) => { + const card = get.autoViewAs(arg.card); + if (card.name != "sha" || !card.storage.stratagem_buffed) return false; + const target = arg.target; + if (target.countCards("h", "shan") >= 1 && !target.storage.stratagem_fury) return false; + } + } + }, + expandedSlots: { + markimage: "image/card/expandedSlots.png", + intro: { + markcount: function (storage, player) { + var all = 0, storage = player.expandedSlots; + if (!storage) return 0; + for (var key in storage) { + var num = storage[key]; + if (typeof num == "number" && num > 0) { + all += num; + } + } + return all; + }, + content: function (storage, player) { + storage = player.expandedSlots; + if (!storage) return "当前没有扩展装备栏"; + const keys = Object.keys(storage).sort(), combined = get.is.mountCombined(); + let str = ""; + for (const key of keys) { + const num = storage[key]; + if (typeof num == "number" && num > 0) { + let trans = get.translation(key); + if (combined && key == "equip3") trans = "坐骑"; + str += "
    • " + trans + "栏:" + num + "个
      " + } + } + if (str.length) return str.slice(0, str.length - 4); + return "当前没有扩展装备栏"; + }, + }, + }, + charge: { + markimage: "image/card/charge.png", + intro: { + content: "当前蓄力点数:#", + }, + }, + cooperation: { + charlotte: true, + trigger: { + global: ["phaseAfter", "dieAfter"], + }, + forced: true, + lastDo: true, + filter: function (event, player) { + if (event.name == "die" && event.player.isAlive()) return false; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.target == event.player) return true; + } + return false; + }, + content: function () { + for (var i = 0; i < player.storage.cooperation.length; i++) { + var info = player.storage.cooperation[i]; + if (info.target == trigger.player) { + player.removeCooperation(info); + i--; + } + } + }, + onremove: function (player, skill) { + var storage = player.getStorage(skill); + var reasons = []; + for (var i of storage) reasons.add(i.type); + for (var i of reasons) player.removeSkill(skill + "_" + i); + delete player.storage[i]; + }, + subSkill: { + damage: { + mark: true, + trigger: { global: "damage" }, + forced: true, + charlotte: true, + popup: false, + firstDo: true, + filter: function (event, player) { + if (!event.source) return false; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "damage" && (event.source == player || event.source == info.target)) return true; + } + return false; + }, + checkx: (info) => (info.damage && info.damage > 3), + content: function () { + var source = trigger.source; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "damage" && (source == player || source == info.target)) { + if (!info.damage) info.damage = 0; + info.damage += trigger.num; + } + } + player.markSkill("cooperation_damage"); + }, + marktext: "仇", + intro: { + name: "协力 - 同仇", + markcount: function (storage, player) { + return Math.max.apply(Math, player.getStorage("cooperation").map(function (info) { + return info.damage || 0; + })); + }, + content: function (storage, player) { + var str = "", storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "damage") { + str += "
    • 协力角色:" + get.translation(info.target); + str += "
    • 协力原因:" + get.translation(info.reason); + str += "
    • 协力进度:" + var num = (info.damage || 0); + str += num; + str += "/4"; + str += (num > 3 ? " (已完成)" : " (未完成)"); + str += "
        "; + } + } + return str.slice(4, str.length - 6); + }, + }, + }, + draw: { + mark: true, + trigger: { global: "gainAfter" }, + forced: true, + charlotte: true, + popup: false, + firstDo: true, + filter: function (event, player) { + if (event.getParent().name != "draw") return false; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "draw" && (event.player == player || event.player == info.target)) return true; + } + return false; + }, + checkx: (info) => (info.draw && info.draw > 7), + content: function () { + var source = trigger.player; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "draw" && (source == player || source == info.target)) { + if (!info.draw) info.draw = 0; + info.draw += trigger.cards.length; + } + } + player.markSkill("cooperation_draw"); + }, + marktext: "进", + intro: { + name: "协力 - 并进", + markcount: function (storage, player) { + return Math.max.apply(Math, player.getStorage("cooperation").map(function (info) { + return info.draw || 0; + })); + }, + content: function (storage, player) { + var str = "", storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "draw") { + str += "
    • 协力角色:" + get.translation(info.target); + str += "
    • 协力原因:" + get.translation(info.reason); + str += "
    • 协力进度:" + var num = (info.draw || 0); + str += num; + str += "/8"; + str += (num > 7 ? " (已完成)" : " (未完成)"); + str += "
        "; + } + } + return str.slice(4, str.length - 6); + }, + }, + }, + discard: { + mark: true, + trigger: { global: "loseAfter" }, + forced: true, + charlotte: true, + popup: false, + firstDo: true, + filter: function (event, player) { + if (event.type != "discard") return false; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "discard" && (event.player == player || event.player == info.target)) return true; + } + return false; + }, + checkx: (info) => (info.discard && info.discard.length > 3), + content: function () { + var source = trigger.player; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "discard" && (source == player || source == info.target)) { + if (!info.discard) info.discard = []; + for (var i of trigger.cards2) { + var suit = get.suit(i, player); + if (lib.suit.contains(suit)) info.discard.add(suit); + } + } + } + player.markSkill("cooperation_discard"); + }, + marktext: "财", + intro: { + name: "协力 - 疏财", + markcount: function (storage, player) { + return Math.max.apply(Math, player.getStorage("cooperation").map(function (info) { + return info.discard ? info.discard.length : 0; + })); + }, + content: function (storage, player) { + var str = "", storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "discard") { + str += "
    • 协力角色:" + get.translation(info.target); + str += "
    • 协力原因:" + get.translation(info.reason); + str += "
    • 进度:"; + var suits = info.discard || []; + var suits2 = [["spade", "♠", "♤"], ["heart", "♥", "♡"], ["club", "♣", "♧"], ["diamond", "♦", "♢"]]; + for (var i of suits2) { + str += (suits.contains(i[0]) ? i[1] : i[2]); + } + str += (suits.length > 3 ? " (已完成)" : " (未完成)"); + str += "
        "; + } + } + return str.slice(4, str.length - 6); + }, + }, + }, + use: { + mark: true, + trigger: { global: "useCard1" }, + forced: true, + charlotte: true, + popup: false, + firstDo: true, + filter: function (event, player) { + var suit = get.suit(event.card); + if (!lib.suit.contains(suit)) return false; + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "use" + && (event.player == player || event.player == info.target) && + (!info.used || !info.used.contains(suit))) return true; + } + return false; + }, + checkx: (info) => (info.used && info.used.length > 3), + content: function () { + var source = trigger.player, suit = get.suit(trigger.card); + var storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "use" && (source == player || source == info.target)) { + if (!info.used) info.used = []; + info.used.add(suit); + } + } + player.markSkill("cooperation_use"); + }, + marktext: "戮", + intro: { + name: "协力 - 戮力", + markcount: function (storage, player) { + return Math.max.apply(Math, player.getStorage("cooperation").map(function (info) { + return info.used ? info.used.length : 0; + })); + }, + content: function (storage, player) { + var str = "", storage = player.getStorage("cooperation"); + for (var info of storage) { + if (info.type == "use") { + str += "
    • 协力角色:" + get.translation(info.target); + str += "
    • 协力原因:" + get.translation(info.reason); + str += "
    • 进度:"; + var suits = info.used || []; + var suits2 = [["spade", "♠", "♤"], ["heart", "♥", "♡"], ["club", "♣", "♧"], ["diamond", "♦", "♢"]]; + for (var i of suits2) { + str += (suits.contains(i[0]) ? i[1] : i[2]); + } + str += (suits.length > 3 ? " (已完成)" : " (未完成)"); + str += "
        "; + } + } + return str.slice(4, str.length - 6); + }, + }, + }, + }, + }, + zhengsu: { + trigger: { player: "phaseDiscardEnd" }, + forced: true, + charlotte: true, + filter: function (event, player) { + return (player.storage.zhengsu_leijin || player.storage.zhengsu_bianzhen || player.storage.zhengsu_mingzhi); + }, + content: function () { + player.chooseDrawRecover(2, "整肃奖励:摸两张牌或回复1点体力"); + }, + subSkill: { + leijin: { + mod: { + aiOrder: function (player, card, num) { + if (typeof card.number != "number") return; + var history = player.getHistory("useCard", evt => evt.isPhaseUsing()); + if (history.length == 0) return num + 10 * (14 - card.number); + var num = get.number(history[0].card); + if (!num) return; + for (var i = 1; i < history.length; i++) { + var num2 = get.number(history[i].card); + if (!num2 || num2 <= num) return; + num = num2; + } + if (card.number > num) return num + 10 * (14 - card.number); + }, + }, + mark: true, + trigger: { player: "useCard1" }, + lastDo: true, + charlotte: true, + forced: true, + popup: false, + onremove: true, + filter: function (event, player) { + return player.isPhaseUsing() && player.storage.zhengsu_leijin !== false; + }, + content: function () { + var list = player.getHistory("useCard", function (evt) { + return evt.isPhaseUsing(player); + }); + var goon = true; + for (var i = 0; i < list.length; i++) { + var num = get.number(list[i].card); + if (typeof num != "number") { + goon = false; + break; + } + if (i > 0) { + var num2 = get.number(list[i - 1].card); + if (typeof num2 != "number" || num2 >= num) { + goon = false; + break; + } + } + } + if (!goon) { + game.broadcastAll(function (player) { + player.storage.zhengsu_leijin = false; + if (player.marks.zhengsu_leijin) player.marks.zhengsu_leijin.firstChild.innerHTML = "╳"; + delete player.storage.zhengsu_leijin_markcount; + }, player); + } + else { + if (list.length > 2) { + game.broadcastAll(function (player, num) { + if (player.marks.zhengsu_leijin) player.marks.zhengsu_leijin.firstChild.innerHTML = "○"; + player.storage.zhengsu_leijin = true; + player.storage.zhengsu_leijin_markcount = num; + }, player, num); + } + else game.broadcastAll(function (player, num) { + player.storage.zhengsu_leijin_markcount = num; + }, player, num); + } + player.markSkill("zhengsu_leijin"); + }, + intro: { + content: "
    • 条件:回合内所有于出牌阶段使用的牌点数递增且不少于三张。", + }, + }, + bianzhen: { + mark: true, + trigger: { player: "useCard1" }, + firstDo: true, + charlotte: true, + forced: true, + popup: false, + onremove: true, + filter: function (event, player) { + return player.isPhaseUsing() && player.storage.zhengsu_bianzhen !== false; + }, + content: function () { + var list = player.getHistory("useCard", function (evt) { + return evt.isPhaseUsing(); + }); + var goon = true, suit = get.suit(list[0].card, false); + if (suit == "none") { + goon = false; + } + else { + for (var i = 1; i < list.length; i++) { + if (get.suit(list[i]) != suit) { + goon = false; + break; + } + } + } + if (!goon) { + game.broadcastAll(function (player) { + player.storage.zhengsu_bianzhen = false; + if (player.marks.zhengsu_bianzhen) player.marks.zhengsu_bianzhen.firstChild.innerHTML = "╳"; + }, player); + } + else { + if (list.length > 1) { + game.broadcastAll(function (player) { + if (player.marks.zhengsu_bianzhen) player.marks.zhengsu_bianzhen.firstChild.innerHTML = "○"; + player.storage.zhengsu_bianzhen = true; + }, player); + } + else game.broadcastAll(function (player, suit) { + if (player.marks.zhengsu_bianzhen) player.marks.zhengsu_bianzhen.firstChild.innerHTML = get.translation(suit); + }, player, suit); + } + player.markSkill("zhengsu_bianzhen"); + }, + intro: { + content: "
    • 条件:回合内所有于出牌阶段使用的牌花色相同且不少于两张。", + }, + ai: { + effect: { + player_use: function (card, player, target) { + if (typeof card != "object" || !player.isPhaseUsing()) return; + var suitx = get.suit(card); + var history = player.getHistory("useCard"); + if (!history.length) { + var val = 0; + if (player.hasCard(function (cardx) { + return get.suit(cardx) == suitx && card != cardx && (!card.cards || !card.cards.contains(cardx)) && player.hasValueTarget(cardx); + }, "hs")) val = [2, 0.1]; + if (val) return val; + return; + } + var num = 0; + var suit = false; + for (var i = 0; i < history.length; i++) { + var suit2 = get.suit(history[i].card); + if (!lib.suit.contains(suit2)) return; + if (suit && suit != suit2) return; + suit = suit2; + num++; + } + if (suitx == suit && num == 1) return [1, 0.1]; + if (suitx != suit && (num > 1 || num <= 1 && player.hasCard(function (cardx) { + return get.suit(cardx) == suit && player.hasValueTarget(cardx); + }, "hs"))) return "zeroplayertarget"; + }, + }, + }, + }, + mingzhi: { + mark: true, + trigger: { player: "loseAfter" }, + firstDo: true, + charlotte: true, + forced: true, + popup: false, + onremove: true, + filter: function (event, player) { + if (player.storage.zhengsu_mingzhi === false || event.type != "discard") return false; + var evt = event.getParent("phaseDiscard"); + return evt && evt.player == player; + }, + content: function () { + var goon = true, list = []; + player.getHistory("lose", function (event) { + if (!goon || event.type != "discard") return false; + var evt = event.getParent("phaseDiscard"); + if (evt && evt.player == player) { + for (var i of event.cards2) { + var suit = get.suit(i, player); + if (list.contains(suit)) { + goon = false; + break; + } + else list.push(suit); + } + } + }); + if (!goon) { + game.broadcastAll(function (player) { + player.storage.zhengsu_mingzhi = false; + if (player.marks.zhengsu_mingzhi) player.marks.zhengsu_mingzhi.firstChild.innerHTML = "╳"; + delete player.storage.zhengsu_mingzhi_list; + }, player); + } + else { + if (list.length > 1) { + game.broadcastAll(function (player, list) { + if (player.marks.zhengsu_mingzhi) player.marks.zhengsu_mingzhi.firstChild.innerHTML = "○"; + player.storage.zhengsu_mingzhi = true; + player.storage.zhengsu_mingzhi_list = list; + player.storage.zhengsu_mingzhi_markcount = list.length; + }, player, list); + } + else game.broadcastAll(function (player, list) { + player.storage.zhengsu_mingzhi_list = list; + player.storage.zhengsu_mingzhi_markcount = list.length; + }, player, list); + } + player.markSkill("zhengsu_mingzhi"); + }, + intro: { + content: "
    • 条件:回合内所有于弃牌阶段弃置的牌花色均不相同且不少于两张。", + }, + }, + }, + }, + renku: { + intro: { + markcount: function () { + return _status.renku.length; + }, + mark: function (dialog, content, player) { + if (!_status.renku.length) return "仁库中没有牌"; + else dialog.addAuto(_status.renku); + }, + content: function () { + if (!_status.renku.length) return "仁库中没有牌"; + return get.translation(_status.renku); + }, + }, + }, + _showHiddenCharacter: { + trigger: { player: ["changeHp", "phaseBeginStart", "loseMaxHpBegin", "gainMaxHpBegin"] }, + firstDo: true, + forced: true, + popup: false, + priority: 25, + filter: function (event, player, name) { + return player.isUnseen(2) && get.mode() != "guozhan"; + }, + content: function () { + player.showCharacter(2); + player.removeSkill("g_hidden_ai"); + }, + }, + _kamisha: { + trigger: { source: "damageBegin2" }, + //forced:true, + popup: false, + prompt: function (event, player) { + return "是否防止即将对" + get.translation(event.player) + "造成的伤害,改为令其减少" + get.cnNumber(event.num) + "点体力上限?"; + }, + filter: function (event, player) { + return event.hasNature("kami") && event.num > 0; + }, + ruleSkill: true, + check: function (event, player) { + var att = get.attitude(player, event.player); + if (event.player.hp == event.player.maxHp) return att < 0; + if (event.player.hp == event.player.maxHp - 1 && + (event.player.maxHp <= 3 || event.player.hasSkillTag("maixie"))) return att < 0; + return att > 0; + }, + content: function () { + trigger.cancel(); + trigger.player.loseMaxHp(trigger.num).source = player; + }, + }, + aozhan: { + charlotte: true, + mod: { + targetEnabled: function (card) { + if (card.name == "tao" && (card.isCard && card.cardid || get.itemtype(card) == "card")) return false; + }, + cardSavable: function (card) { + if (card.name == "tao" && (card.isCard && card.cardid || get.itemtype(card) == "card")) return false; + }, + }, + group: ["aozhan_sha", "aozhan_shan"], + subSkill: { + sha: { + enable: ["chooseToUse", "chooseToRespond"], + filterCard: { + name: "tao", + }, + viewAs: { + name: "sha", + isCard: true, + }, + viewAsFilter: function (player) { + if (!player.countCards("hs", "tao")) return false; + }, + position: "hs", + prompt: "将一张桃当杀使用或打出", + check: function () { return 1 }, + ai: { + respondSha: true, + skillTagFilter: function (player) { + if (!player.countCards("hs", "tao")) return false; + }, + order: function () { + return get.order({ name: "sha" }) - 0.1; + }, + }, + sub: true, + }, + shan: { + enable: ["chooseToRespond", "chooseToUse"], + filterCard: { + name: "tao", + }, + viewAs: { + name: "shan", + isCard: true, + }, + prompt: "将一张桃当闪打出", + check: function () { return 1 }, + viewAsFilter: function (player) { + if (!player.countCards("hs", "tao")) return false; + }, + position: "hs", + ai: { + respondShan: true, + skillTagFilter: function (player) { + if (!player.countCards("hs", "tao")) return false; + }, + }, + sub: true, + }, + }, + }, + global: [], + globalmap: {}, + storage: {}, + undist: {}, + others: {}, + zhu: {}, + zhuSkill: {}, + land_used: {}, + unequip: { ai: { unequip: true } }, + subplayer: { + trigger: { player: "dieBefore" }, + forced: true, + priority: -9, + onremove: true, + mark: "character", + intro: { + content: function (storage, player) { + if (typeof storage.intro2 == "string") return storage.intro2; + if (typeof storage.intro2 == "function") return storage.intro2(storage, player); + return "死亡前切换回主武将" + }, + name: function (storage) { + return get.rawName(storage.name); + } + }, + content: function () { + trigger.cancel(); + var evt = trigger.getParent("damage"); + if (evt.player == player) { + evt.untrigger(false, player); + } + player.exitSubPlayer(true); + }, + ai: { + nosave: true + } + }, + autoswap: { + firstDo: true, + trigger: { + player: ["playercontrol", "chooseToUseBegin", "chooseToRespondBegin", "chooseToDiscardBegin", "chooseToCompareBegin", + "chooseButtonBegin", "chooseCardBegin", "chooseTargetBegin", "chooseCardTargetBegin", "chooseControlBegin", + "chooseBoolBegin", "choosePlayerCardBegin", "discardPlayerCardBegin", "gainPlayerCardBegin", "chooseToMoveBegin", "chooseToPlayBeatmapBegin"] + }, + forced: true, + priority: 100, + forceDie: true, + popup: false, + filter: function (event, player) { + if (event.autochoose && event.autochoose()) return false; + if (lib.filter.wuxieSwap(event)) return false; + if (_status.auto || !player.isUnderControl()) return false; + return true; + }, + content: function () { + game.swapPlayerAuto(player); + }, + }, + dualside: { + charlotte: true, + subSkill: { + turn: { + trigger: { player: ["turnOverAfter", "dieBefore"] }, + silent: true, + filter: function (event, player) { + if (player.storage.dualside_over) return false; + return Array.isArray(player.storage.dualside); + }, + content: function () { + var cfg = player.storage.dualside; + var bool = player.isTurnedOver(); + if (trigger.name == "die") { + bool = !bool; + } + if (bool) { + cfg[1] = player.hp; + cfg[2] = player.maxHp; + player.reinit(cfg[0], cfg[3], [cfg[4], cfg[5]]); + player.unmarkSkill("dualside"); + player.markSkillCharacter("dualside", { name: cfg[0] }, "正面", "当前体力:" + cfg[1] + "/" + cfg[2]); + } + else { + cfg[4] = player.hp; + cfg[5] = player.maxHp; + player.reinit(cfg[3], cfg[0], [cfg[1], cfg[2]]); + player.unmarkSkill("dualside"); + player.markSkillCharacter("dualside", { name: cfg[3] }, "背面", "当前体力:" + cfg[4] + "/" + cfg[5]); + } + + if (trigger.name == "die") { + trigger.cancel(); + delete player.storage.dualside; + player.storage.dualside_over = true; + player.unmarkSkill("dualside"); + } + } + }, + init: { + trigger: { global: "gameStart", player: "enterGame" }, + silent: true, + content: function () { + var list = [player.name, player.name1, player.name2]; + for (var i = 0; i < list.length; i++) { + if (list[i] && lib.character[list[i]]) { + var info = lib.character[list[i]]; + if (info[3].contains("dualside") && info[4]) { + player.storage.dualside = [list[i], player.hp, player.maxHp]; + for (var j = 0; j < info[4].length; j++) { + if (info[4][j].startsWith("dualside:")) { + var name2 = info[4][j].slice(9); + var info2 = lib.character[name2]; + player.storage.dualside.push(name2); + player.storage.dualside.push(get.infoHp(info2[2])); + player.storage.dualside.push(get.infoMaxHp(info2[2])); + } + } + } + } + } + var cfg = player.storage.dualside; + if (get.mode() == "guozhan") { + if (player.name1 == cfg[0]) { + player.showCharacter(0); + } + else { + player.showCharacter(1); + } + } + player.markSkillCharacter("dualside", { name: cfg[3] }, "背面", "当前体力:" + cfg[4] + "/" + cfg[5]); + } + } + }, + group: ["dualside_init", "dualside_turn"] + }, + fengyin: { + init: function (player, skill) { + player.addSkillBlocker(skill); + }, + onremove: function (player, skill) { + player.removeSkillBlocker(skill); + }, + charlotte: true, + skillBlocker: function (skill, player) { + return !lib.skill[skill].charlotte && !get.is.locked(skill, player); + }, + mark: true, + intro: { + content: function (storage, player, skill) { + var list = player.getSkills(null, false, false).filter(function (i) { + return lib.skill.fengyin.skillBlocker(i, player); + }); + if (list.length) return "失效技能:" + get.translation(list); + return "无失效技能"; + } + } + }, + baiban: { + init: function (player, skill) { + player.addSkillBlocker(skill); + }, + onremove: function (player, skill) { + player.removeSkillBlocker(skill); + }, + charlotte: true, + skillBlocker: function (skill, player) { + return !lib.skill[skill].charlotte; + }, + mark: true, + intro: { + content: function (storage, player, skill) { + var list = player.getSkills(null, false, false).filter(function (i) { + return lib.skill.baiban.skillBlocker(i, player); + }); + if (list.length) return "失效技能:" + get.translation(list); + return "无失效技能"; + } + } + }, + qianxing: { + mark: true, + nopop: true, + init: function (player) { + game.log(player, "获得了", "【潜行】"); + }, + intro: { + content: "锁定技,你不能成为其他角色的卡牌的目标" + }, + mod: { + targetEnabled: function (card, player, target) { + if (player != target) return false; + } + } + }, + mianyi: { + trigger: { player: "damageBefore" }, + mark: true, + forced: true, + init: function (player) { + game.log(player, "获得了", "【免疫】"); + }, + content: function () { + trigger.cancel(); + }, + ai: { + nofire: true, + nothunder: true, + nodamage: true, + effect: { + target: function (card, player, target, current) { + if (get.tag(card, "damage")) return [0, 0]; + } + }, + }, + intro: { + content: "防止一切伤害" + } + }, + mad: { + mark: true, + locked: true, + intro: { + content: "已进入混乱状态", + name: "混乱", + onunmark: function (storage, player) { + game.log(player, "解除混乱状态"); + } + } + }, + ghujia: { + intro: { + content: function (content, player) { + return "已有" + get.cnNumber(player.hujia) + "点护甲值"; + } + }, + markimage: "image/card/shield.png", + }, + counttrigger: { + trigger: { global: "phaseAfter" }, + silent: true, + charlotte: true, + priority: -100, + lastDo: true, + content: function () { + player.removeSkill("counttrigger"); + delete player.storage.counttrigger; + }, + group: "counttrigger_2", + subSkill: { + 2: { + trigger: { global: ["phaseBeforeStart", "roundStart"] }, + silent: true, + charlotte: true, + firstDo: true, + priority: 100, + content: function () { + player.removeSkill("counttrigger"); + delete player.storage.counttrigger; + }, + } + } + }, + _recovercheck: { + trigger: { player: "recoverBefore" }, + forced: true, + priority: 100, + firstDo: true, + popup: false, + filter: function (event, player) { + return player.hp >= player.maxHp; + }, + content: function () { + trigger.cancel(); + }, + }, + _usecard: { + trigger: { global: "useCardAfter" }, + forced: true, + popup: false, + priority: -100, + lastDo: true, + filter: function (event) { + return !event._cleared && event.card.name != "wuxie"; + }, + content: function () { + game.broadcastAll(function () { + ui.clear(); + }); + event._cleared = true; + } + }, + _discard: { + trigger: { global: ["discardAfter", "loseToDiscardpileAfter", "loseAsyncAfter"] }, + forced: true, + popup: false, + priority: -100, + lastDo: true, + filter: function (event) { + return ui.todiscard[event.discardid] ? true : false; + }, + content: function () { + game.broadcastAll(function (id) { + var todiscard = ui.todiscard[id]; + delete ui.todiscard[id]; + if (todiscard) { + var time = 1000; + if (typeof todiscard._discardtime == "number") { + time += todiscard._discardtime - get.time(); + } + if (time < 0) { + time = 0; + } + setTimeout(function () { + for (var i = 0; i < todiscard.length; i++) { + todiscard[i].delete(); + } + }, time); + } + }, trigger.discardid); + } + }, + _save: { + priority: 5, + forced: true, + popup: false, + filter: function (event, player) { + return false; + }, + content: function () { + "step 0" + event.dying = trigger.player; + if (!event.acted) event.acted = []; + "step 1" + if (trigger.player.isDead()) { + event.finish(); + return; + } + event.acted.push(player); + var str = get.translation(trigger.player) + "濒死,是否帮助?"; + var str2 = "当前体力:" + trigger.player.hp; + if (lib.config.tao_enemy && event.dying.side != player.side && lib.config.mode != "identity" && lib.config.mode != "guozhan" && !event.dying.hasSkillTag("revertsave")) { + event._result = { bool: false } + } + else if (player.canSave(event.dying)) { + player.chooseToUse({ + filterCard: function (card, player, event) { + event = event || _status.event; + return lib.filter.cardSavable(card, player, event.dying); + }, + filterTarget: function (card, player, target) { + if (target != _status.event.dying) return false; + if (!card) return false; + var info = get.info(card); + if (!info.singleCard || ui.selected.targets.length == 0) { + var mod = game.checkMod(card, player, target, "unchanged", "playerEnabled", player); + if (mod == false) return false; + var mod = game.checkMod(card, player, target, "unchanged", "targetEnabled", target); + if (mod != "unchanged") return mod; + } + return true; + }, + prompt: str, + prompt2: str2, + ai1: function (card) { + if (typeof card == "string") { + var info = get.info(card); + if (info.ai && info.ai.order) { + if (typeof info.ai.order == "number") { + return info.ai.order; + } + else if (typeof info.ai.order == "function") { + return info.ai.order(); + } + } + } + return 1; + }, + ai2: get.effect_use, + type: "dying", + targetRequired: true, + dying: event.dying + }); + } + else { + event._result = { bool: false } + } + "step 2" + if (result.bool) { + var player = trigger.player; + if (player.hp <= 0 && !trigger.nodying && !player.nodying && player.isAlive() && !player.isOut() && !player.removed) event.goto(0); + else trigger.untrigger(); + } + else { + for (var i = 0; i < 20; i++) { + if (event.acted.contains(event.player.next)) { + break; + } + else { + event.player = event.player.next; + if (!event.player.isOut()) { + event.goto(1); + break; + } + } + } + } + } + }, + _ismin: { + mod: { + cardEnabled: function (card, player) { + if (player.isMin()) { + if (get.type(card) == "equip") return false; + } + } + } + }, + _recasting: { + enable: "phaseUse", + logv: false, + prompt: "将要重铸的牌置入弃牌堆并摸一张牌", + filter: (event, player) => player.hasCard(card => lib.skill._recasting.filterCard(card, player), lib.skill._recasting.position), + position: "he", + filterCard: (card, player) => player.canRecast(card, null, true), + discard: false, + lose: false, + delay: false, + content: () => { + player.recast(cards, null, (player, cards) => { + var numberOfCardsToDraw = cards.length; + cards.forEach(value => { + if (lib.config.mode == "stone" && _status.mode == "deck" && !player.isMin() && get.type(value).startsWith("stone")) { + var stonecard = get.stonecard(1, player.career); + if (stonecard.length) { + numberOfCardsToDraw -= stonecard.length; + player.gain(game.createCard(stonecard.randomGet()), "draw"); + } + else player.draw({ + drawDeck: 1 + }).log = false; + } + else if (get.subtype(value) == "spell_gold") { + var libCard = get.libCard(info => info.subtype == "spell_silver"); + if (!libCard.length) return; + numberOfCardsToDraw--; + player.gain(game.createCard(libCard.randomGet()), "draw"); + } + else if (get.subtype(value) == "spell_silver") { + var libCard = get.libCard(info => info.subtype == "spell_bronze"); + if (!libCard.length) return; + numberOfCardsToDraw--; + player.gain(game.createCard(libCard.randomGet()), "draw"); + } + }); + if (numberOfCardsToDraw) player.draw(numberOfCardsToDraw).log = false; + }); + }, + ai: { + basic: { + order: 6 + }, + result: { + player: 1 + } + } + }, + _lianhuan: { + trigger: { player: "damageAfter" }, + filter: function (event, player) { + return event.lianhuanable == true; + }, + forced: true, + popup: false, + logv: false, + forceDie: true, + //priority:-5, + content: function () { + "step 0" + event.logvid = trigger.getLogv(); + "step 1" + event.targets = game.filterPlayer(function (current) { + return current != event.player && current.isLinked(); + }); + lib.tempSortSeat = _status.currentPhase || player; + event.targets.sort(lib.sort.seat); + delete lib.tempSortSeat; + event._args = [trigger.num, trigger.nature, trigger.cards, trigger.card]; + if (trigger.source) event._args.push(trigger.source); + else event._args.push("nosource"); + "step 2" + if (event.targets.length) { + var target = event.targets.shift(); + if (target.isLinked()) target.damage.apply(target, event._args.slice(0)); + event.redo(); + } + }, + }, + _lianhuan4: { + trigger: { player: "changeHp" }, + priority: -10, + forced: true, + popup: false, + forceDie: true, + filter: function (event, player) { + var evt = event.getParent(); + return evt && evt.name == "damage" && evt.hasNature("linked") && player.isLinked(); + }, + content: function () { + player.link(); + if (trigger.getParent().notLink()) trigger.getParent().lianhuanable = true; + } + }, + /** + * @deprecated + */ + _chongzhu: { + get filter() { + return lib.skill._recasting.filter; + }, + set filter(filter) { + lib.skill._recasting.filter = filter; + }, + get filterCard() { + return lib.skill._recasting.filterCard; + }, + set filterCard(filterCard) { + lib.skill._recasting.filterCard = filterCard; + }, + get content() { + return lib.skill._recasting.content; + }, + set content(content) { + lib.skill._recasting.content = content; + }, + get ai() { + return lib.skill._recasting.ai; + }, + set ai(ai) { + lib.skill._recasting.ai = ai; + } + } +}; diff --git a/noname/library/skin.d.ts b/noname/library/skin.d.ts new file mode 100644 index 000000000..80e4a2c6d --- /dev/null +++ b/noname/library/skin.d.ts @@ -0,0 +1,4 @@ +interface Skin extends Record { +} + +export const skin: Skin; diff --git a/noname/library/skin.js b/noname/library/skin.js new file mode 100644 index 000000000..62b959fb8 --- /dev/null +++ b/noname/library/skin.js @@ -0,0 +1 @@ +export const skin = {}; diff --git a/noname/library/sort.js b/noname/library/sort.js new file mode 100644 index 000000000..54375c6b1 --- /dev/null +++ b/noname/library/sort.js @@ -0,0 +1,133 @@ +export class Sort { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + static nature(a, b) { + return (lib.nature.get(b) || 0) - (lib.nature.get(a) || 0); + } + static group(a, b) { + const groupSort = function (group) { + let base = 0; + if (group == "wei") return base; + if (group == "shu") return base + 1; + if (group == "wu") return base + 2; + if (group == "qun") return base + 3; + if (group == "jin") return base + 4; + if (group == "key") return base + 5; + if (group == "western") return base + 6; + if (group == "shen") return base + 7; + if (group == "double") return base + 7; + return base + 9; + } + return groupSort(a) - groupSort(b); + } + static character(a, b) { + const groupSort = function (name) { + const info = get.character(name); + if (!info) return 7; + let base = 0; + if (get.is.double(name, true)) base = 9; + const group = info[1]; + if (group == "shen") return base - 1; + if (group == "wei") return base; + if (group == "shu") return base + 1; + if (group == "wu") return base + 2; + if (group == "qun") return base + 3; + if (group == "jin") return base + 4; + if (group == "key") return base + 5; + if (group == "western") return base + 6; + return base + 7; + } + const del = groupSort(a) - groupSort(b); + if (del != 0) return del; + let aa = a, bb = b; + if (a.includes("_")) { + a = a.slice(a.indexOf("_") + 1); + } + if (b.includes("_")) { + b = b.slice(b.indexOf("_") + 1); + } + if (a != b) { + return a > b ? 1 : -1; + } + return aa > bb ? 1 : -1; + } + static card(a, b) { + var typeSort = function (name) { + var type = get.type(name); + if (!type) return 10; + if (type == "basic") return -1; + if (type == "trick") return 0; + if (type == "delay") return 1; + if (type == "equip") { + var type2 = get.subtype(name, false); + if (type2 && type2.slice) return 1 + parseInt(type2.slice(5) || 7); + return 8.5 + } + return 9; + } + var del = typeSort(a) - typeSort(b); + if (del != 0) return del; + var aa = a, bb = b; + if (a.includes("_")) { + a = a.slice(a.indexOf("_") + 1); + } + if (b.includes("_")) { + b = b.slice(b.indexOf("_") + 1); + } + if (a != b) { + return a > b ? 1 : -1; + } + return aa > bb ? 1 : -1; + } + static random() { + return (Math.random() - 0.5); + } + static seat(a, b) { + var player = lib.tempSortSeat || _status.event.player; + var delta = get.distance(player, a, "absolute") - get.distance(player, b, "absolute"); + if (delta) return delta; + delta = parseInt(a.dataset.position) - parseInt(b.dataset.position); + if (player.side == game.me.side) return delta; + return -delta; + } + static position(a, b) { + return parseInt(a.dataset.position) - parseInt(b.dataset.position); + } + static priority(a, b) { + var i1 = get.info(a[0]), i2 = get.info(b[0]); + if (i1.priority == undefined) i1.priority = 0; + if (i2.priority == undefined) i2.priority = 0; + if (i1.priority == i2.priority) { + if (i1.forced == undefined && i2.forced == undefined) return 0; + if (i1.forced && i2.forced) return 0; + if (i1.forced) return 1; + if (i2.forced) return -1; + } + return i2.priority - i1.priority; + } + static number(a, b) { + return get.number(a) - get.number(b); + } + static number2(a, b) { + return get.number(b) - get.number(a); + } + static capt(a, b) { + var aa = a, bb = b; + if (aa.includes("_")) { + aa = aa.slice(aa.indexOf("_") + 1); + } + if (bb.includes("_")) { + bb = bb.slice(bb.indexOf("_") + 1); + } + if (aa != bb) { + return aa > bb ? 1 : -1; + } + return a > b ? 1 : -1; + } + static name(a, b) { + if (a > b) return 1; + if (a < b) return -1; + return 0; + } +} diff --git a/noname/library/stratagem-buff.js b/noname/library/stratagem-buff.js new file mode 100644 index 000000000..549cb781f --- /dev/null +++ b/noname/library/stratagem-buff.js @@ -0,0 +1,72 @@ +import { Game } from "../game.js"; +import { Get } from "../get.js"; +import { GameEvent } from "./element/game-event.js"; +import { VCard } from "./element/v-card.js"; + +export const stratagemBuff = { + cost: new Map([ + ["sha", 1], + ["shan", 1], + ["juedou", 2], + ["huogong", 2], + ["tao", 3] + ]), + /** + * @type {Map void>} + */ + effect: new Map([ + ["sha", (event, option) => { + if (event.step != 0 || option.state != "end") return; + Game.log(event.player, "触发了强化效果"); + Game.log(event.card, "抵消所需要的", new VCard({ + name: "shan" + }), "数+1"); + const map = event.customArgs; + Game.players.concat(Game.dead).forEach(current => { + const id = current.playerid; + if (!map[id]) map[id] = {}; + if (typeof map[id].shanRequired == "number") map[id].shanRequired++; + else map[id].shanRequired = 2; + }); + }], + ["shan", (event, option) => { + if (event.step != 0 || option.state != "end") return; + Game.log(event.player, "触发了强化效果"); + Game.log("使用", event.card, "时视为两张", new VCard({ + name: "shan" + }), "的效果"); + event.player.when("useCard").filter(evt => evt == event).then(() => { + trigger.getParent(2).decrease("shanRequired", 1); + }); + }], + ["juedou", (event, option) => { + if (event.step != 0 || option.state != "end") return; + Game.log(event.player, "触发了强化效果"); + Game.log("对", event.card, "的目标造成伤害时,伤害+1"); + event.player.when({ + source: "damageBegin1" + }).filter(evt => evt.getParent(2) == event && event.targets.includes(evt.player)).then(() => { + trigger.increase("num"); + }); + }], + ["huogong", (event, option) => { + if (event.step != 0 || option.state != "end") return; + Game.log(event.player, "触发了强化效果"); + Game.log(event.card, "造成的伤害+1"); + event.increase("baseDamage", 1); + }], + ["tao", (event, option) => { + if (event.step != 0 || option.state != "end") return; + Game.log(event.player, "触发了强化效果"); + Game.log(event.card, "回复的体力+1"); + event.increase("baseDamage", 1); + }] + ]), + prompt: new Map([ + ["sha", () => `抵消所需要的【${Get.translation("shan")}】数+1。`], + ["shan", () => `使用时视为两张【${Get.translation("shan")}】的效果。`], + ["juedou", () => "对此牌的目标造成伤害时,伤害+1。"], + ["huogong", () => "造成的伤害+1。"], + ["tao", () => "回复的体力+1。"] + ]) +}; diff --git a/noname/library/translate.js b/noname/library/translate.js new file mode 100644 index 000000000..dfdcbaea5 --- /dev/null +++ b/noname/library/translate.js @@ -0,0 +1,217 @@ +export const translate = { + flower: "鲜花", + egg: "鸡蛋", + wine: "酒杯", + shoe: "拖鞋", + yuxisx: "玉玺", + jiasuo: "枷锁", + junk: "平凡", + common: "普通", + rare: "精品", + epic: "史诗", + legend: "传说", + default: "默认", + special: "特殊", + zhenfa: "阵法", + aozhan: "鏖战", + mode_derivation_card_config: "衍生", + mode_banned_card_config: "禁卡", + mode_favourite_character_config: "收藏", + mode_banned_character_config: "禁将", + heart: "♥︎", + diamond: "♦︎", + spade: "♠︎", + club: "♣︎", + none: "◈", + ghujia: "护甲", + ghujia_bg: "甲", + heart2: "红桃", + diamond2: "方片", + spade2: "黑桃", + club2: "梅花", + none2: "无色", + red: "红色", + black: "黑色", + ok: "确定", + ok2: "确定", + cancel: "取消", + cancel2: "取消", + restart: "重新开始", + setting: "设置", + start: "开始", + random: "随机", + _out: "无效", + agree: "同意", + refuse: "拒绝", + fire: "火", + thunder: "雷", + poison: "毒", + kami: "神", + ice: "冰", + stab: "刺", + wei: "魏", + shu: "蜀", + wu: "吴", + qun: "群", + shen: "神", + western: "西", + key: "键", + jin: "晋", + double: "双", + wei2: "魏国", + shu2: "蜀国", + wu2: "吴国", + qun2: "群雄", + shen2: "神明", + western2: "西方", + key2: "KEY", + jin2: "晋朝", + double2: "双势力", + male: "男", + female: "女", + mad: "混乱", + mad_bg: "疯", + draw_card: "摸牌", + discard_card: "弃牌", + take_damage: "受伤害", + reset_character: "复原武将牌", + recover_hp: "回复体力", + lose_hp: "失去体力", + get_damage: "受伤害", + weiColor: "#b0d0e2", + shuColor: "#ffddb9", + wuColor: "#b2d9a9", + qunColor: "#f6f6f6", + shenColor: "#ffe14c", + westernColor: "#ffe14c", + jinColor: "#ffe14c", + keyColor: "#c9b1fd", + basic: "基本", + equip: "装备", + trick: "锦囊", + delay: "延时锦囊", + character: "角色", + revive: "复活", + equip1: "武器", + equip2: "防具", + equip3: "防御马", + "equip3_4": "坐骑", + equip4: "攻击马", + equip5: "宝物", + equip6: "特殊装备", + zero: "零", + one: "一", + two: "二", + three: "三", + four: "四", + five: "五", + six: "六", + seven: "七", + eight: "八", + nine: "九", + ten: "十", + _recasting: "重铸", + _lianhuan: "连环", + _lianhuan2: "连环", + _kamisha: "神杀", + _icesha: "冰杀", + qianxing: "潜行", + mianyi: "免疫", + fengyin: "封印", + baiban: "白板", + _disableJudge: "判定区", + + xiaowu_emotion: "小无表情", + guojia_emotion: "郭嘉表情", + zhenji_emotion: "甄姬表情", + shibing_emotion: "士兵表情", + xiaosha_emotion: "小杀表情", + xiaotao_emotion: "小桃表情", + xiaojiu_emotion: "小酒表情", + xiaokuo_emotion: "小扩表情", + + pause: "暂停", + config: "选项", + auto: "托管", + + unknown: "未知", + unknown0: "一号位", + unknown1: "二号位", + unknown2: "三号位", + unknown3: "四号位", + unknown4: "五号位", + unknown5: "六号位", + unknown6: "七号位", + unknown7: "八号位", + unknown8: "九号位", + unknown9: "十号位", + unknown10: "十一号位", + unknown11: "十二号位", + + feichu_equip1: "已废除", + feichu_equip1_info: "武器栏已废除", + feichu_equip2: "已废除", + feichu_equip2_info: "防具栏已废除", + feichu_equip3: "已废除", + feichu_equip3_info: "防御坐骑栏已废除", + feichu_equip4: "已废除", + feichu_equip4_info: "攻击坐骑栏已废除", + feichu_equip5: "已废除", + feichu_equip5_info: "宝物栏已废除", + feichu_equip6: "已废除", + feichu_equip6_info: "特殊装备栏已废除", + feichu_equip1_bg: "废", + feichu_equip2_bg: "废", + feichu_equip3_bg: "废", + feichu_equip4_bg: "废", + feichu_equip5_bg: "废", + feichu_equip6_bg: "废", + disable_judge: "已废除", + disable_judge_info: "判定区已废除", + disable_judge_bg: "废", + pss: "手势", + pss_paper: "布", + pss_scissor: "剪刀", + pss_stone: "石头", + pss_paper_info: "石头剪刀布时的一种手势。克制石头,但被剪刀克制。", + pss_scissor_info: "石头剪刀布时的一种手势。克制布,但被石头克制。", + pss_stone_info: "石头剪刀布时的一种手势。克制剪刀,但被布克制。", + renku: "仁库", + group_wei: "魏势力", + group_shu: "蜀势力", + group_wu: "吴势力", + group_qun: "群势力", + group_key: "键势力", + group_jin: "晋势力", + group_wei_bg: "魏", + group_shu_bg: "蜀", + group_wu_bg: "吴", + group_qun_bg: "群", + group_key_bg: "键", + group_jin_bg: "晋", + zhengsu: "整肃", + zhengsu_leijin: "擂进", + zhengsu_bianzhen: "变阵", + zhengsu_mingzhi: "鸣止", + zhengsu_leijin_info: "回合内所有于出牌阶段使用的牌点数递增且不少于三张。", + zhengsu_bianzhen_info: "回合内所有于出牌阶段使用的牌花色相同且不少于两张。", + zhengsu_mingzhi_info: "回合内所有于弃牌阶段弃置的牌花色均不相同且不少于两张。", + db_atk: "策略", + db_atk1: "全军出击", + db_atk2: "分兵围城", + db_def: "策略", + db_def1: "奇袭粮道", + db_def2: "开城诱敌", + cooperation_damage: "同仇", + cooperation_damage_info: "双方累计造成至少4点伤害", + cooperation_draw: "并进", + cooperation_draw_info: "双方累计摸至少八张牌", + cooperation_discard: "疏财", + cooperation_discard_info: "双方累计弃置至少4种花色的牌", + cooperation_use: "戮力", + cooperation_use_info: "双方累计使用至少4种花色的牌", + charge: "蓄力值", + expandedSlots: "扩展装备栏", + stratagem_fury: "怒气", + _stratagem_add_buff: "强化" +}; diff --git a/noname/library/update-urls.d.ts b/noname/library/update-urls.d.ts new file mode 100644 index 000000000..5c68821f2 --- /dev/null +++ b/noname/library/update-urls.d.ts @@ -0,0 +1,4 @@ +interface UpdateURLs extends Record { +} + +export const updateURLs: UpdateURLs; diff --git a/noname/library/update-urls.js b/noname/library/update-urls.js new file mode 100644 index 000000000..e69287285 --- /dev/null +++ b/noname/library/update-urls.js @@ -0,0 +1,4 @@ +export const updateURLs = { + coding: "https://gitcode.net/sinat_33405273/noname/-/raw/", + github: "https://raw.githubusercontent.com/libccy/noname" +}; diff --git a/noname/library/yingbian.js b/noname/library/yingbian.js new file mode 100644 index 000000000..09a11d89f --- /dev/null +++ b/noname/library/yingbian.js @@ -0,0 +1,42 @@ +import { condition } from "./yingbian/condition.js"; + +export const yingbian = { + condition, + effect: new Map([ + ["add", () => { + trigger.yingbian_addTarget = true; + }], + ["remove", () => { + trigger.yingbian_removeTarget = true; + }], + ["damage", () => { + if (typeof trigger.baseDamage != "number") trigger.baseDamage = 1; + trigger.baseDamage++; + game.log(card, "的伤害值基数+1"); + }], + ["draw", () => { + player.draw(); + }], + ["gain", () => { + const cardx = trigger.respondTo; + if (cardx && cardx[1] && cardx[1].cards && cardx[1].cards.filterInD("od").length) player.gain(cardx[1].cards.filterInD("od"), "gain2"); + }], + ["hit", () => { + trigger.directHit.addArray(game.players).addArray(game.dead); + game.log(card, "不可被响应"); + }], + ["all", () => { + card.yingbian_all = true; + game.log(card, "执行所有选项"); + }] + ]), + prompt: new Map([ + ["add", "目标+1"], + ["remove", "目标-1"], + ["damage", "伤害+1"], + ["draw", "摸一张牌"], + ["gain", "获得响应的牌"], + ["hit", "此牌不可被响应"], + ["all", "无视条件执行所有选项"] + ]) +}; diff --git a/noname/library/yingbian/condition.js b/noname/library/yingbian/condition.js new file mode 100644 index 000000000..fb80cd59e --- /dev/null +++ b/noname/library/yingbian/condition.js @@ -0,0 +1,132 @@ +export const condition = { + color: new Map([ + ["zhuzhan", "wood"], + ["kongchao", "soil"], + ["fujia", "orange"], + ["canqu", "fire"], + ["force", "metal"] + ]), + complex: new Map([ + ["zhuzhan", function (event) { + const yingbianZhuzhan = game.createEvent("yingbianZhuzhan"); + yingbianZhuzhan.player = event.player; + yingbianZhuzhan.card = event.card; + yingbianZhuzhan._trigger = event; + yingbianZhuzhan.yingbianZhuzhanAI = event.yingbianZhuzhanAI; + yingbianZhuzhan.afterYingbianZhuzhan = event.afterYingbianZhuzhan; + yingbianZhuzhan.setContent(() => { + "step 0" + event._global_waiting = true; + event.send = (player, card, source, targets, id, id2, yingbianZhuzhanAI, skillState) => { + if (skillState) player.applySkills(skillState); + var type = get.type2(card), str = get.translation(source); + if (targets && targets.length) str += `对${get.translation(targets)}`; + str += `使用了${get.translation(card)},是否弃置一张${get.translation(type)}为其助战?`; + player.chooseCard({ + filterCard: (card, player) => get.type2(card) == type && lib.filter.cardDiscardable(card, player), + prompt: str, + position: "h", + _global_waiting: true, + id: id, + id2: id2, + ai: typeof yingbianZhuzhanAI == "function" ? yingbianZhuzhanAI(player, card, source, targets) : cardx => { + var info = get.info(card); + if (info && info.ai && info.ai.yingbian) { + var ai = info.ai.yingbian(card, source, targets, player); + if (!ai) return 0; + return ai - get.value(cardx); + } + else if (get.attitude(player, source) <= 0) return 0; + return 5 - get.value(cardx); + } + }); + if (!game.online) return; + _status.event._resultid = id; + game.resume(); + }; + "step 1" + var type = get.type2(card); + event.list = game.filterPlayer(current => current != player && current.countCards("h") && (_status.connectMode || current.hasCard(cardx => get.type2(cardx) == type, "h"))).sortBySeat(_status.currentPhase || player); + event.id = get.id(); + "step 2" + if (!event.list.length) event.finish(); + else if (_status.connectMode && (event.list[0].isOnline() || event.list[0] == game.me)) event.goto(4); + else event.send(event.current = event.list.shift(), event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI); + "step 3" + if (result.bool) { + event.zhuzhanresult = event.current; + event.zhuzhanresult2 = result; + if (event.current != game.me) game.delayx(); + event.goto(8); + } + else event.goto(2); + "step 4" + var id = event.id, sendback = (result, player) => { + if (result && result.id == id && !event.zhuzhanresult && result.bool) { + event.zhuzhanresult = player; + event.zhuzhanresult2 = result; + game.broadcast("cancel", id); + if (_status.event.id == id && _status.event.name == "chooseCard" && _status.paused) return () => { + event.resultOL = _status.event.resultOL; + ui.click.cancel(); + if (ui.confirm) ui.confirm.close(); + }; + } + else if (_status.event.id == id && _status.event.name == "chooseCard" && _status.paused) return () => event.resultOL = _status.event.resultOL; + }, withme = false, withol = false, list = event.list; + for (var i = 0; i < list.length; i++) { + var current = list[i]; + if (current.isOnline()) { + withol = true; + current.wait(sendback); + current.send(event.send, current, event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI, get.skillState(current)); + list.splice(i--, 1); + } + else if (current == game.me) { + withme = true; + event.send(current, event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI); + list.splice(i--, 1); + } + } + if (!withme) event.goto(6); + if (_status.connectMode && (withme || withol)) game.players.forEach(value => { + if (value != player) value.showTimer(); + }); + event.withol = withol; + "step 5" + if (!result || !result.bool || event.zhuzhanresult) return; + game.broadcast("cancel", event.id); + event.zhuzhanresult = game.me; + event.zhuzhanresult2 = result; + "step 6" + if (event.withol && !event.resultOL) game.pause(); + "step 7" + game.players.forEach(value => value.hideTimer()); + "step 8" + if (event.zhuzhanresult) { + var target = event.zhuzhanresult; + target.line(player, "green"); + target.discard(event.zhuzhanresult2.cards).discarder = target; + if (typeof event.afterYingbianZhuzhan == "function") event.afterYingbianZhuzhan(event, trigger); + var yingbianCondition = event.name.slice(8).toLowerCase(), yingbianConditionTag = `yingbian_${yingbianCondition}_tag`; + target.popup(yingbianConditionTag, lib.yingbian.condition.color.get(yingbianCondition)); + game.log(target, "响应了", player, "发起的", yingbianConditionTag); + target.addExpose(0.2); + event.result = { + bool: true + } + } + else event.result = { + bool: false + }; + }); + yingbianZhuzhan._args = Array.from(arguments); + return yingbianZhuzhan; + }] + ]), + simple: new Map([ + ["kongchao", event => !event.player.countCards("h")], + ["fujia", event => event.player.isMaxHandcard()], + ["canqu", event => event.player.getHp() == 1] + ]) +}; diff --git a/noname/status.js b/noname/status.js new file mode 100644 index 000000000..da2043a33 --- /dev/null +++ b/noname/status.js @@ -0,0 +1,34 @@ +import { GameEvent } from "./library/element/game-event.js"; +import { ai } from "./game-status/ai.js"; +import { cardTag } from "./game-status/card-tag.js"; +import { postReconnect } from "./game-status/post-reconnect.js"; + +export const status = { + paused: false, + paused2: false, + paused3: false, + over: false, + clicked: false, + auto: false, + event: GameEvent.initialGameEvent(), + ai: ai, + lastdragchange: [], + skillaudio: [], + dieClose: [], + dragline: [], + dying: [], + /** + * @type {import("./game-status/global-history.js").GlobalHistory[]} + */ + globalHistory: [{ + cardMove: [], + custom: [], + useCard: [], + changeHp: [], + everything: [] + }], + cardtag: cardTag, + renku: [], + prehidden_skills: [], + postReconnect +} diff --git a/noname/ui.js b/noname/ui.js new file mode 100644 index 000000000..284d00363 --- /dev/null +++ b/noname/ui.js @@ -0,0 +1,586 @@ +import { Click } from "./ui/click.js"; +import { Create } from "./ui/create.js"; +import { selected } from "./ui/selected.js"; + +class HTMLWindowElement extends HTMLDivElement { +} + +customElements.define("window", HTMLWindowElement, { + extends: "div" +}); + +export class UI { + static updates = []; + static thrown = []; + static touchlines = []; + static todiscard = {}; + /** + * @type {HTMLStyleElement[]} + */ + static playerPositions = []; + static create = Create; + static click = Click; + static selected = selected; + /** + * @type {HTMLWindowElement} + */ + static window; + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static refresh(node) { + void window.getComputedStyle(node, null).getPropertyValue("opacity"); + } + static updatec() { + if (_status.noupdatec) return; + var length = 0, minoffset = -Infinity; + var controls = []; + var widths = []; + var leftwidths = []; + var add = function (node, first) { + var thiswidth = parseInt(node.style.width); + if (thiswidth) { + thiswidth += 8; + length += thiswidth; + if (first) { + leftwidths.push(thiswidth); + } + else { + widths.push(thiswidth); + } + } + else { + length += node.offsetWidth; + if (first) { + leftwidths.push(node.offsetWidth); + } + else { + widths.push(node.offsetWidth); + } + } + if (first) { + controls.unshift(node); + } + else { + controls.push(node); + } + } + widths = leftwidths.concat(widths); + var staylefts = []; + for (var i = 0; i < ui.control.childNodes.length; i++) { + if (ui.control.childNodes[i].classList.contains("removing")) continue; + if (lib.config.wuxie_right && ui.control.childNodes[i].stayleft) { + staylefts.push(ui.control.childNodes[i]); + } + else { + add(ui.control.childNodes[i]); + } + } + if (staylefts.length) { + var fullwidth = 0; + var fullright = (game.layout == "long" || game.layout == "long2" || game.chess || (game.layout != "nova" && parseInt(ui.arena.dataset.number) <= 5)); + for (var i = 0; i < widths.length; i++) { + fullwidth += widths[i] + 6; + if (get.is.phoneLayout()) fullwidth += 6; + } + fullwidth /= 2; + var currentLeft = 0; + for (var stayleft of staylefts) { + stayleft.currentLeft = currentLeft; + fullwidth += stayleft.offsetWidth; + currentLeft += stayleft.offsetWidth; + if (get.is.phoneLayout()) { + fullwidth += 18; + currentLeft += 18; + } + else { + fullwidth += 12; + currentLeft += 12; + } + } + if (fullright) { + fullwidth += 124; + if ((game.layout == "long2" || game.layout == "nova") && ui.arena.dataset.number == "8" && get.mode() != "boss") { + fullwidth += game.me.getLeft(); + } + } + else { + fullwidth += 154; + } + for (var stayleft of staylefts) { + if (game.layout != "default") { + var current_offset = stayleft._offset; + if (fullright) { + stayleft._offset = Math.ceil(-ui.arena.offsetWidth / 2) + 135; + if ((game.layout == "long2" || game.layout == "nova") && ui.arena.dataset.number == "8" && get.mode() != "boss") { + stayleft._offset += game.me.getLeft(); + } + } + else { + stayleft._offset = Math.ceil(-ui.arena.offsetWidth / 2) + 165; + } + stayleft._offset += stayleft.currentLeft; + + if (current_offset != stayleft._offset) { + stayleft.animate("controlpressdownx", 500); + stayleft.style.transform = "translateX(" + stayleft._offset + "px)"; + } + } + else { + add(stayleft, true); + } + } + if (staylefts.length && controls.length) { + var last = staylefts[staylefts.length - 1]; + minoffset = last._offset + last.offsetWidth + (get.is.phoneLayout() ? 18 : 12); + } + } + if (!controls.length) return; + var offset = -length / 2; + if (minoffset > offset) offset = minoffset; + var control = controls.shift(); + if (control._offset != offset) { + control.animate("controlpressdownx", 500); + control.style.transform = "translateX(" + offset + "px)"; + control._offset = offset; + } + while (controls.length) { + var control = controls.shift(); + var width = widths.shift(); + offset += width + 6; + if (get.is.phoneLayout()) { + offset += 6; + } + if (control._offset != offset) { + control.animate("controlpressdownx", 500); + control.style.transform = "translateX(" + offset + "px)"; + control._offset = offset; + } + } + } + static updatex() { + ui.update.apply(this, arguments); + ui.updatehl(); + for (var i = 0; i < lib.onresize.length; i++) { + lib.onresize[i](); + } + var cfg = game.documentZoom / game.deviceZoom; + ui.updated(); + game.documentZoom = cfg * game.deviceZoom; + ui.updatez(); + delete ui._updatexr; + } + static updatexr() { + if (ui._updatexr) { + clearTimeout(ui._updatexr); + } + ui._updatexr = setTimeout(ui.updatex, 500); + } + static updatejm(player, nodes, start, inv) { + if (typeof start != "number") { + start = 0; + } + var str; + if (get.is.mobileMe(player) || game.layout == "default" || player.classList.contains("linked")) { + str = "translateX("; + if (inv) { + str += "-"; + } + } + else { + str = "translateY("; + } + var num = 0; + for (var i = 0; i < nodes.childElementCount; i++) { + var node = nodes.childNodes[i]; + if (i < start) { + node.style.transform = ""; + } + else if (node.classList.contains("removing")) { + start++; + } + else { + ui.refresh(node); + node.classList.remove("drawinghidden"); + node._transform = str + ((i - start) * 28) + "px)"; + node.style.transform = node._transform; + } + } + } + static updatem(player) { + if (player) { + var start = 0; + if (!player.classList.contains("linked2") || !ui.arena.classList.contains("nolink")) { + start = 1; + } + ui.updatejm(player, player.node.marks, start, get.is.mobileMe(player)); + } + else { + for (var i = 0; i < game.players.length; i++) { + ui.updatem(game.players[i]); + } + } + } + static updatej(player) { + if (player) { + ui.updatejm(player, player.node.judges); + } + else { + for (var i = 0; i < game.players.length; i++) { + ui.updatej(game.players[i]); + } + } + } + static updatehl() { + if (!game.me) return; + if (!ui.handcards1Container || !ui.handcards2Container) return; + if (!ui.handcards1Container.childNodes.length) return; + var hs1 = [], hs2 = []; + for (var i = 0; i < ui.handcards1Container.firstChild.childElementCount; i++) { + if (!ui.handcards1Container.firstChild.childNodes[i].classList.contains("removing")) { + hs1.push(ui.handcards1Container.firstChild.childNodes[i]); + } + } + for (var i = 0; i < ui.handcards2Container.firstChild.childElementCount; i++) { + if (!ui.handcards2Container.firstChild.childNodes[i].classList.contains("removing")) { + hs2.push(ui.handcards2Container.firstChild.childNodes[i]); + } + } + var offset1, offset12 = 0; + if (!lib.config.fold_card) { + offset1 = 112; + ui.handcards1Container.classList.add("scrollh"); + } + else { + offset1 = Math.min(112, (ui.handcards1Container.offsetWidth - 128) / (hs1.length - 1)); + if (hs1.length > 1 && offset1 < 32) { + offset1 = 32; + ui.handcards1Container.classList.add("scrollh"); + } + else { + ui.handcards1Container.classList.remove("scrollh"); + } + } + if (offset1 < 100) { + offset12 = 100 - offset1; + } + for (var i = 0; i < hs1.length; i++) { + hs1[i].style.transform = "translateX(" + (i * offset1) + "px)"; + hs1[i]._transform = "translateX(" + (i * offset1) + "px)"; + ui.refresh(hs1[i]); + hs1[i].classList.remove("drawinghidden"); + if (offset12 > 40) { + offset12 = 90 - hs1[i].node.info.offsetWidth; + hs1[i].node.info.querySelector("span").style.display = "none"; + if (hs1[i].node.name.classList.contains("long")) { + hs1[i].node.name.style.transform = "translateY(16px) scale(0.85)"; + hs1[i].node.name.style.transformOrigin = "top left"; + } + else { + hs1[i].node.name.style.transform = "translateY(16px)"; + } + hs1[i].node.info.style.transform = "translateX(-" + offset12 + "px) translateY(-3px)"; + } + else { + hs1[i].node.info.querySelector("span").style.display = ""; + hs1[i].node.name.style.transform = ""; + hs1[i].node.name.style.transformOrigin = ""; + hs1[i].node.info.style.transform = "translateX(-" + offset12 + "px)"; + } + } + ui.handcards1Container.firstChild.style.width = (offset1 * (hs1.length - 1) + 118) + "px"; + + var offset2, offset22 = 0; + if (!lib.config.fold_card) { + offset2 = 112; + ui.handcards2Container.classList.add("scrollh"); + } + else { + offset2 = Math.min(112, (ui.handcards2Container.offsetWidth - 128) / (hs2.length - 1)); + if (hs2.length > 1 && offset2 < 32) { + offset2 = 32; + ui.handcards2Container.classList.add("scrollh"); + } + else { + ui.handcards2Container.classList.remove("scrollh"); + } + } + if (offset2 < 100) { + offset22 = 100 - offset2; + } + for (var i = 0; i < hs2.length; i++) { + hs2[i].style.transform = "translateX(" + (i * offset2) + "px)"; + hs2[i]._transform = "translateX(" + (i * offset2) + "px)"; + ui.refresh(hs2[i]); + hs2[i].classList.remove("drawinghidden"); + if (offset22 > 40) { + offset22 = 90 - hs2[i].node.info.offsetWidth; + hs2[i].node.info.querySelector("span").style.display = "none"; + if (hs2[i].node.name.classList.contains("long")) { + hs2[i].node.name.style.transform = "translateY(16px) scale(0.85)"; + hs2[i].node.name.style.transformOrigin = "top left"; + } + else { + hs2[i].node.name.style.transform = "translateY(16px)"; + } + hs2[i].node.info.style.transform = "translateX(-" + offset22 + "px) translateY(-3px)"; + } + else { + hs2[i].node.info.querySelector("span").style.display = ""; + hs2[i].node.name.style.transform = ""; + hs2[i].node.name.style.transformOrigin = ""; + hs2[i].node.info.style.transform = "translateX(-" + offset22 + "px)"; + } + } + ui.handcards2Container.firstChild.style.width = (offset2 * (hs2.length - 1) + 118) + "px"; + } + static updateh(compute) { + if (!game.me) return; + if (!ui.handcards1Container) return; + if (lib.config.low_performance) { + if (compute) { + ui.updatehl(); + setTimeout(ui.updatehl, 1000); + } + return; + } + if (compute) { + ui.handcards1Container._handcardsWidth = ui.handcards1Container.offsetWidth; + ui.handcards2Container._handcardsWidth = ui.handcards2Container.offsetWidth; + } + ui.updatehx(game.me.node.handcards1); + ui.updatehx(game.me.node.handcards2); + } + static updatehx(node) { + var width = node.parentNode._handcardsWidth; + var num = node.childElementCount - node.getElementsByClassName("removing").length; + node.classList.remove("fold0"); + node.classList.remove("fold1"); + node.classList.remove("fold2"); + node.classList.remove("fold3"); + if (num * 78 + 40 >= width) { + // node.dataset.fold=3; + node.classList.add("fold3"); + } + else if (num * 93 + 25 >= width) { + // node.dataset.fold=2; + node.classList.add("fold2"); + } + else if (num * 112 + 6 >= width) { + // node.dataset.fold=1; + node.classList.add("fold1"); + } + else { + // node.dataset.fold=0; + node.classList.add("fold0"); + } + } + static updated() { + if (document.documentElement.offsetWidth < 900 || document.documentElement.offsetHeight < 500) { + game.deviceZoom = Math.min( + Math.round(document.documentElement.offsetWidth / 98) / 10, + Math.round(document.documentElement.offsetHeight / 50) / 10 + ); + } + else { + game.deviceZoom = 1; + } + } + static updatez() { + var width = document.documentElement.offsetWidth; + var height = document.documentElement.offsetHeight; + var zoom = game.documentZoom; + if (zoom != 1) { + document.body.style.width = Math.round(width / zoom) + "px"; + document.body.style.height = Math.round(height / zoom) + "px"; + document.body.style.transform = "scale(" + (Math.floor(zoom * 100) / 100) + ")"; + } + else { + document.body.style.width = width + "px"; + document.body.style.height = height + "px"; + document.body.style.transform = ""; + } + } + static update() { + for (var i = 0; i < ui.updates.length; i++) { + ui.updates[i](); + } + if (ui.dialog && !ui.dialog.classList.contains("noupdate")) { + if (game.chess) { + if (ui.dialog.content.scrollHeight < 240 && (!ui.dialog.buttons || !ui.dialog.buttons.length) && !ui.dialog.forcebutton) { + ui.dialog.style.height = ui.dialog.content.offsetHeight + "px"; + ui.dialog.classList.add("slim"); + } + else { + ui.dialog.style.height = ""; + ui.dialog.classList.remove("slim"); + } + } + else { + if ((!ui.dialog.buttons || !ui.dialog.buttons.length) && !ui.dialog.forcebutton && ui.dialog.classList.contains("fullheight") == false && get.mode() != "stone") { + ui.dialog.classList.add("nobutton"); + if (ui.dialog.content.offsetHeight < 240) { + if (!ui.dialog._heightset) { + ui.dialog._heightset = ui.dialog.style.height || true; + } + ui.dialog.style.height = ui.dialog.content.offsetHeight + "px"; + if (lib.config.show_log != "off") { + ui.dialog.classList.add("scroll1"); + ui.dialog.classList.add("scroll2"); + return; + } + } + else { + if (typeof ui.dialog._heightset == "string") { + ui.dialog.style.height = ui.dialog._heightset; + } + else if (ui.dialog._heightset) { + ui.dialog.style.height = ""; + } + delete ui.dialog._heightset; + } + } + else { + if (typeof ui.dialog._heightset == "string") { + ui.dialog.style.height = ui.dialog._heightset; + } + else if (ui.dialog._heightset) { + ui.dialog.style.height = ""; + } + delete ui.dialog._heightset; + ui.dialog.classList.remove("nobutton"); + } + } + var height1 = ui.dialog.content.offsetHeight; + var height2 = ui.dialog.contentContainer.offsetHeight; + if (game.chess) { + if (height1 < 240) { + ui.dialog.style.height = height1 + "px"; + } + } + else { + if (!ui.dialog.forcebutton && !ui.dialog._scrollset && (height1 <= 190 || (height2 >= height1 && height2 >= 210))) { + ui.dialog.classList.remove("scroll1"); + ui.dialog.classList.remove("scroll2"); + } + else { + ui.dialog.classList.add("scroll1"); + ui.dialog.classList.add("scroll2"); + if (game.layout != "default") { + ui.dialog.style.height = Math.min(height1, ((game.layout == "long2" || game.layout == "nova") && ui.arena.classList.contains("choose-character")) ? 380 : 350) + "px"; + ui.dialog._scrollset = true; + } + } + if (game.layout == "long2" || game.layout == "nova") { + if (height1 + 240 >= ui.arena.offsetHeight) { + ui.dialog.classList.add("scroll3"); + } + else { + ui.dialog.classList.remove("scroll3"); + } + } + } + } + } + static recycle(node, key) { + if (!ui._recycle) ui._recycle = {}; + if (typeof node == "string") { + return ui._recycle[node] + } + ui._recycle[key] = node; + } + /** + * @author curpond + * @author Tipx-L + * @param {number} [numberOfPlayers] + */ + static updateConnectPlayerPositions(numberOfPlayers) { + if (typeof numberOfPlayers != "number") { + const configOL = lib.configOL; + numberOfPlayers = parseInt(configOL.player_number) || configOL.number; + } + if (!numberOfPlayers) return; + const playerPositions = ui.playerPositions; + playerPositions.forEach((position) => { + game.dynamicStyle.remove(position); + }); + playerPositions.length = 0; + const temporaryPlayer = ui.create.div(".player.connect", ui.window).hide(); + const computedStyle = getComputedStyle(temporaryPlayer); + const halfWidth = parseFloat(computedStyle.width) / 2; + const halfHeight = parseFloat(computedStyle.height) / 2; + temporaryPlayer.remove(); + const halfNumberOfPlayers = Math.round(numberOfPlayers / 2); + const upperPercentage = 100 / (halfNumberOfPlayers + 1); + const scale = 10 / numberOfPlayers; + for (let ordinal = 0; ordinal < halfNumberOfPlayers; ordinal++) { + const selector = `#window>.player.connect[data-position="${ordinal}"]`; + const css = { + left: `calc(${upperPercentage * (ordinal + 1)}% - ${halfWidth}px)`, + top: `calc(${100 / 3}% - ${halfHeight}px)` + }; + if (scale < 1) + css["transform"] = `scale(${scale})`; + + game.dynamicStyle.add(selector, css); + playerPositions.push(selector); + } + const lowerPercentage = 100 / (numberOfPlayers - halfNumberOfPlayers + 1); + for (let ordinal = halfNumberOfPlayers; ordinal < numberOfPlayers; ordinal++) { + const selector = `#window>.player.connect[data-position="${ordinal}"]`; + const css = { + left: `calc(${lowerPercentage * (ordinal - halfNumberOfPlayers + 1)}% - ${halfWidth}px)`, + top: `calc(${100 * 2 / 3}% - ${halfHeight}px)` + }; + if (scale < 1) + css["transform"] = `scale(${scale})`; + + game.dynamicStyle.add(selector, css); + playerPositions.push(selector); + } + } + /** + * @author curpond + * @author Tipx-L + * @param {number} [numberOfPlayers] + */ + static updatePlayerPositions(numberOfPlayers) { + if (typeof numberOfPlayers != "number") numberOfPlayers = ui.arena.dataset.number; + //当人数不超过8人时,还是用以前的布局 + if (!numberOfPlayers || numberOfPlayers <= 8) return; + const playerPositions = ui.playerPositions; + playerPositions.forEach((position) => { + game.dynamicStyle.remove(position); + }); + playerPositions.length = 0; + //单个人物的宽度,这里要设置玩家的实际的宽度 + const temporaryPlayer = ui.create.div(".player", ui.arena).hide(); + const computedStyle = getComputedStyle(temporaryPlayer); + const scale = 6 / numberOfPlayers; + //玩家顶部距离父容器上边缘的距离偏移的单位距离 + const quarterHeight = parseFloat(computedStyle.height) / 4 * scale; + const halfWidth = parseFloat(computedStyle.width) / 2; + temporaryPlayer.remove(); + //列数,即假如8人场,除去自己后,上面7个人占7列 + const columnCount = numberOfPlayers - 1; + const percentage = 90 / (columnCount - 1); + //仅当游戏人数大于8人,且玩家的座位号大于0时,设置玩家的位置;因为0号位是game.me在最下方,无需设置 + for (let ordinal = 1; ordinal < numberOfPlayers; ordinal++) { + const reversedOrdinal = columnCount - ordinal; + //动态计算玩家的top属性,实现拱桥的效果;只让两边的各两个人向下偏移一些 + const top = Math.max(0, Math.round(numberOfPlayers / 5) - Math.min(Math.abs(ordinal - 1), Math.abs(reversedOrdinal))) * quarterHeight; + const selector = `#arena[data-number="${numberOfPlayers}"]>.player[data-position="${ordinal}"]`; + game.dynamicStyle.add(selector, { + left: `calc(${percentage * reversedOrdinal + 5}% - ${halfWidth}px)`, + top: `${top}px`, + transform: `scale(${scale})` + }); + playerPositions.push(selector); + } + } + static updateRoundNumber(roundNumber, cardPileNumber) { + if (ui.cardPileNumber) ui.cardPileNumber.innerHTML = `${roundNumber}轮 剩余牌: ${cardPileNumber}`; + } +} diff --git a/noname/ui/click.js b/noname/ui/click.js new file mode 100644 index 000000000..900a61cff --- /dev/null +++ b/noname/ui/click.js @@ -0,0 +1,3993 @@ +export class Click { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static identitycircle() { + var list = []; + this.classList.toggle("transparent"); + for (var i = 0; i < this.parentNode.childNodes.length; i++) { + if (!this.parentNode.childNodes[i].classList.contains("transparent")) { + list.add(this.parentNode.childNodes[i].link[2]); + } + } + var info = this.link; + if (list.length == 1) { + for (var i = 0; i < this.parentNode.childNodes.length; i++) { + if (!this.parentNode.childNodes[i].classList.contains("transparent")) { + var info2 = this.parentNode.childNodes[i].link; + info[0].firstChild.innerHTML = info2[1]; + info[0].dataset.color = info2[2]; + } + } + } + else { + info[0].firstChild.innerHTML = ""; + info[0].dataset.color = ""; + ui.create.identitycircle(list, info[0].firstChild); + } + this._source._guozhanguess = list; + } + static connectEvents() { + if (this.info) { + var button = this; + var layer = ui.create.div(".poplayer", ui.window); + var uiintro = ui.create.dialog("hidden", "notouchscroll"); + this.classList.add("active"); + if (lib.config.touchscreen) { + lib.setScroll(uiintro.contentContainer); + } + layer.listen(function () { + if (this.clicked) { + this.clicked = false; + return; + } + button.classList.remove("active"); + uiintro.delete(); + this.delete(); + }); + uiintro.listen(function () { + _status.clicked = true; + }); + uiintro.style.zIndex = 21; + uiintro.classList.add("popped"); + uiintro.classList.add("static"); + uiintro.classList.add("onlineclient"); + uiintro.style.width = "180px"; + uiintro.style.height = "300px"; + uiintro.style.left = "auto"; + uiintro.style.right = "20px"; + uiintro.style.top = "auto"; + uiintro.style.bottom = "75px"; + + uiintro.refresh = function () { + if (button.focused) return; + uiintro.content.innerHTML = ""; + uiintro.addText("创建约战"); + button.textnode = uiintro.content.lastChild.lastChild; + uiintro.add(``); + uiintro.content.lastChild.style.paddingTop = 0; + button.input = uiintro.content.lastChild.lastChild; + button.input.onfocus = function () { + button.focused = true; + } + button.input.onblur = function () { + delete button.focused; + } + if (button.interval) { + button.input.disabled = true; + button.input.style.opacity = 0.6; + if (button.intervaltext) { + button.textnode.innerHTML = button.intervaltext; + } + } + var datenode = ui.create.div(uiintro.content); + datenode.style.marginTop = 0; + datenode.style.whiteSpace = "nowrap"; + var date = new Date(); + var days = []; + var currentDay = date.getDay(); + if (currentDay == 0) currentDay = 7; + for (var i = 1; i <= 7; i++) { + if (i < currentDay) { + days.push([i.toString(), "下周" + get.cnNumber(i, true)]); + } + else if (i == 7) { + days.push([i.toString(), "周日"]); + } + else if (i == currentDay) { + days.push([i.toString(), "今天"]); + } + else { + days.push([i.toString(), "周" + get.cnNumber(i, true)]); + } + } + days = days.concat(days.splice(0, currentDay - 1)); + var initday = currentDay + 1; + if (initday > 7) { + initday -= 7; + } + var daysselect = ui.create.selectlist(days, initday.toString(), datenode); + daysselect.style.width = "55px"; + var hours = []; + for (var i = 0; i < 24; i++) { + hours.push([i.toString(), i.toString() + "点"]); + } + var hoursselect = ui.create.selectlist(hours, date.getHours().toString(), datenode); + hoursselect.style.marginLeft = "5px"; + hoursselect.style.width = "55px"; + var timeconfirm = ui.create.node("button", "确定", datenode); + timeconfirm.style.marginLeft = "5px"; + timeconfirm.onclick = function () { + if (!button.input.value) { + alert("请填写约战标题"); + return; + } + var date2 = new Date(); + date2.setHours(parseInt(hoursselect.value)); + date2.setMinutes(0); + date2.setSeconds(0); + var deltaday = parseInt(daysselect.value) - currentDay; + if (deltaday < 0) { + deltaday += 7; + } + var utc = date2.getTime() + deltaday * 24 * 3600000; + if (utc < date.getTime()) { + alert("创建失败,时间已过"); + return; + } + if (get.is.banWords(button.input.value)) { + var eventnode = ui.create.div(".menubutton.videotext.onlineevent.pointerdiv", function () { + var that = this; + setTimeout(function () { + if (that.classList.contains("active")) { + if (confirm("确定要离开" + that.info.content + "?")) { + that.classList.remove("active"); + } + } + else { + if (confirm("确定要加入" + that.info.content + "?")) { + that.classList.add("active"); + } + } + }); + }, uiintro.content, 4); + var fakeinfo = { + utc: utc, + day: parseInt(daysselect.value), + hour: parseInt(hoursselect.value), + nickname: get.connectNickname(), + avatar: lib.config.connect_avatar, + content: button.input.value, + create: game.onlineKey, + members: [game.onlineKey], + }; + eventnode.info = fakeinfo; + ui.create.div(".title", fakeinfo.content, eventnode); + var str; + if (fakeinfo.day < currentDay) { + str = "下周"; + } + else { + str = "周"; + } + if (fakeinfo.day == 7) { + str += "日" + } + else { + str += get.cnNumber(fakeinfo.day, true); + } + str += " "; + var hour = fakeinfo.hour; + if (hour <= 12) { + if (hour <= 5) { + str += "凌晨"; + } + else if (hour < 12) { + str += "上午"; + } + else { + str += "中午"; + } + str += fakeinfo.hour + "点"; + } + else { + if (hour <= 17) { + str += "下午"; + } + else { + str += "晚上"; + } + str += (fakeinfo.hour - 12) + "点"; + } + ui.create.div("", "已有" + (fakeinfo.members.length) + "人加入", eventnode); + ui.create.div("", "时间:" + str, eventnode); + if (fakeinfo.members.contains(game.onlineKey)) { + eventnode.classList.add("active"); + } + button.input.value = ""; + return; + } + game.send("server", "events", { + utc: utc, + day: parseInt(daysselect.value), + hour: parseInt(hoursselect.value), + nickname: get.connectNickname(), + avatar: lib.config.connect_avatar, + content: button.input.value + }, game.onlineKey); + }; + + var num = 0; + for (var i = 0; i < button.info.length; i++) { + if (typeof button.info[i].creator == "string" && button.info[i].creator != game.onlineKey && get.is.banWords(button.info[i].content)) continue; + if (button.info[i].creator == game.onlineKey) { + num++; + } + var eventnode = ui.create.div(".menubutton.videotext.onlineevent.pointerdiv", function () { + var that = this; + if (typeof that.info.creator != "string") return; + setTimeout(function () { + if (that.classList.contains("active")) { + if (confirm("确定要离开" + that.info.content + "?")) { + game.send("server", "events", that.info.id, game.onlineKey, "leave"); + } + } + else { + if (confirm("确定要加入" + that.info.content + "?")) { + game.send("server", "events", that.info.id, game.onlineKey, "join"); + } + } + }); + }, uiintro.content); + eventnode.info = button.info[i]; + if (typeof button.info[i].creator == "string") { + ui.create.div(".title", button.info[i].content, eventnode); + var str; + if (button.info[i].day < currentDay) { + str = "下周"; + } + else { + str = "周"; + } + if (button.info[i].day == 7) { + str += "日" + } + else { + str += get.cnNumber(button.info[i].day, true); + } + str += " "; + var hour = button.info[i].hour; + if (hour <= 12) { + if (hour <= 5) { + str += "凌晨"; + } + else if (hour < 12) { + str += "上午"; + } + else { + str += "中午"; + } + str += button.info[i].hour + "点"; + } + else { + if (hour <= 17) { + str += "下午"; + } + else { + str += "晚上"; + } + str += (button.info[i].hour - 12) + "点"; + } + ui.create.div("", "创建者:" + (button.info[i].nickname), eventnode); + //ui.create.div("","创建者:"+(button.info[i].nickname)+"
      ID:"+button.info[i].creator,eventnode); + ui.create.div("", "已有" + (button.info[i].members.length) + "人加入", eventnode); + ui.create.div("", "时间:" + str, eventnode); + if (button.info[i].members.contains(game.onlineKey)) { + eventnode.classList.add("active"); + } + } + else { + ui.create.div(".title", button.info[i].title, eventnode); + ui.create.div("", button.info[i].content, eventnode); + ui.create.div("", "创建者:" + (button.info[i].nickname), eventnode); + } + } + if (num >= 3) { + button.input.disabled = true; + button.input.style.opacity = 0.6; + hoursselect.disabled = true; + daysselect.disabled = true; + timeconfirm.disabled = true; + } + } + uiintro.refresh(); + ui.window.appendChild(uiintro); + _status.connectEventsCallback = function () { + if (uiintro.parentNode == ui.window) { + uiintro.refresh(); + } + }; + } + } + static connectClients() { + if (this.info) { + var button = this; + var layer = ui.create.div(".poplayer", ui.window); + var uiintro = ui.create.dialog("hidden", "notouchscroll"); + this.classList.add("active"); + if (lib.config.touchscreen) { + lib.setScroll(uiintro.contentContainer); + } + layer.listen(function () { + if (this.clicked) { + this.clicked = false; + return; + } + button.classList.remove("active"); + uiintro.delete(); + this.delete(); + }); + uiintro.listen(function () { + _status.clicked = true; + }); + uiintro.style.zIndex = 21; + uiintro.classList.add("popped"); + uiintro.classList.add("static"); + uiintro.classList.add("onlineclient"); + uiintro.style.width = "180px"; + uiintro.style.height = "300px"; + uiintro.style.left = "auto"; + uiintro.style.right = "20px"; + uiintro.style.top = "auto"; + uiintro.style.bottom = "75px"; + + uiintro.refresh = function () { + if (button.focused) return; + uiintro.content.innerHTML = ""; + uiintro.addText("发状态"); + button.textnode = uiintro.content.lastChild.lastChild; + uiintro.add(``); + uiintro.content.lastChild.style.paddingTop = 0; + button.input = uiintro.content.lastChild.lastChild; + button.input.onfocus = function () { + button.focused = true; + } + button.input.onblur = function () { + delete button.focused; + } + if (button.interval) { + button.input.disabled = true; + button.input.style.opacity = 0.6; + if (button.intervaltext) { + button.textnode.innerHTML = button.intervaltext; + } + } + button.input.onkeydown = function (e) { + if (e.keyCode == 13 && !this.disabled) { + game.send("server", "status", this.value); + this.blur(); + this.disabled = true; + this.style.opacity = 0.6; + button.textnode.innerHTML = "发状态(10)"; + button.intervaltext = button.textnode.innerHTML; + var num = 10; + var that = this; + button.input.disabled = true; + button.input.style.opacity = 0.6; + this.value = ""; + button.interval = setInterval(function () { + num--; + if (num > 0) { + button.textnode.innerHTML = "发状态(" + num + ")"; + button.intervaltext = button.textnode.innerHTML; + } + else { + button.textnode.innerHTML = "发状态"; + button.input.disabled = false; + button.input.style.opacity = ""; + clearInterval(button.interval); + delete button.interval; + delete button.intervaltext; + } + }, 1000); + } + } + + for (var i = 0; i < button.info.length; i++) { + var node = ui.create.div(".menubutton.videonode.pointerdiv", uiintro.content); + ui.create.div(".menubutton.videoavatar", node).setBackground(button.info[i][1] || "caocao", "character"); + if (button.info[i][4] == game.wsid) { + ui.create.div(".name", `${button.info[i][0] || "无名玩家"}`, node); node.isme = true; + } + else if (button.info[i][2]) { + ui.create.div(".name", (button.info[i][0] || "无名玩家"), node); + } + else { + ui.create.div(".name", `${button.info[i][0] || "无名玩家"}`, node); + } + //show ID + //ui.create.div(".videostatus",node,button.info[i][5]); + //node.classList.add("videonodestatus"); + if (button.info[i][3]) { + ui.create.div(".videostatus", node, button.info[i][3].slice(0, 80)); + node.classList.add("videonodestatus") + } + } + }; + + uiintro.refresh(); + ui.window.appendChild(uiintro); + _status.connectClientsCallback = function () { + if (uiintro.parentNode == ui.window) { + uiintro.refresh(); + } + }; + } + } + static autoskin() { + if (!lib.config.change_skin) return; + var players = game.filterPlayer(); + var change = function (player, num, callback) { + if (num == "1") { + ui.click.skin(player.node.avatar, player.name, callback); + } + else { + ui.click.skin(player.node.avatar2, player.name2, callback); + } + }; + var finish = function () { + if (lib.config.change_skin_auto != "off") { + _status.skintimeout = setTimeout(ui.click.autoskin, parseInt(lib.config.change_skin_auto)); + } + }; + var autoskin = function () { + if (players.length) { + var player = players.randomRemove(); + var list = []; + if (player.name && !player.isUnseen(0)) { + list.push("1"); + } + if (player.name2 && !player.isUnseen(1)) { + list.push("2"); + } + if (list.length) { + change(player, list.randomRemove(), function (bool) { + if (bool) { + finish(); + } + else if (list.length) { + change(player, list[0], function (bool) { + if (bool) { + finish(); + } + else { + autoskin(); + } + }); + } + else { + autoskin(); + } + }); + } + else { + autoskin(); + } + } + } + autoskin(); + } + static skin(avatar, name, callback) { + var num = 1; + if (name.startsWith("gz_")) { + name = name.slice(3); + } + if (lib.config.skin[name]) { + num = lib.config.skin[name] + 1; + } + var fakeavatar = avatar.cloneNode(true); + var finish = function (bool) { + var player = avatar.parentNode; + if (bool) { + fakeavatar.style.boxShadow = "none"; + player.insertBefore(fakeavatar, avatar.nextSibling); + setTimeout(function () { + fakeavatar.delete(); + }, 100); + } + if (bool && lib.config.animation && !lib.config.low_performance) { + player.$rare(); + } + if (callback) { + callback(bool); + } + } + var img = new Image(); + img.onload = function () { + lib.config.skin[name] = num; + game.saveConfig("skin", lib.config.skin); + avatar.style.backgroundImage = `url("${img.src}")`; + finish(true); + } + img.onerror = function () { + if (lib.config.skin[name]) { + finish(true); + } + else { + finish(false); + } + delete lib.config.skin[name]; + game.saveConfig("skin", lib.config.skin); + avatar.setBackground(name, "character"); + } + img.src = lib.assetURL + "image/skin/" + name + "/" + num + ".jpg"; + } + static touchpop(forced) { + if (lib.config.touchscreen || forced) { + _status.touchpopping = true; + clearTimeout(_status.touchpoppingtimeout); + _status.touchpoppingtimeout = setTimeout(function () { + _status.touchpopping = false; + }, 600); + } + } + static exit() { + if (game.servermode && lib.config.reconnect_info && _status.over) { + if (!_status.roomtimeout) { + lib.config.reconnect_info[2] = game.roomId; + game.saveConfig("reconnect_info", lib.config.reconnect_info); + } + game.reload(); + return; + } + else { + if (typeof game.roomId != "string") { + game.saveConfig("reconnect_info"); + } + } + if (!ui.exit || !ui.exit.stay) { + if (lib.config.reconnect_info) { + lib.config.reconnect_info.length = 1; + game.saveConfig("reconnect_info", lib.config.reconnect_info); + } + game.saveConfig("tmp_user_roomId", undefined, false, function () { + game.reload(); + }); + } + else { + game.reload(); + } + } + static shortcut(show) { + if (show === false) { + ui.shortcut.classList.add("hidden"); + } + else { + ui.shortcut.classList.toggle("hidden"); + } + if (ui.shortcut.classList.contains("hidden")) { + ui.favmode.style.display = "none"; + if (window.StatusBar && lib.config.show_statusbar_ios == "auto") { + document.body.classList.remove("statusbar"); + window.StatusBar.hide(); + } + ui.window.classList.remove("shortcutpaused"); + } + else { + if (lib.config.show_favmode) { + ui.favmode.style.display = ""; + } + if (window.StatusBar && lib.config.show_statusbar_ios == "auto") { + document.body.classList.add("statusbar"); + window.StatusBar.overlaysWebView(true); + window.StatusBar.backgroundColorByName("black"); + window.StatusBar.show(); + } + if (_status.auto) { + ui.shortcut.autobutton.classList.add("active"); + } + else { + ui.shortcut.autobutton.classList.remove("active"); + } + ui.window.classList.add("shortcutpaused"); + } + } + static favouriteCharacter(e) { + if (typeof this.link == "string") { + if (this.innerHTML == "添加收藏") { + this.innerHTML = "移除收藏"; + lib.config.favouriteCharacter.add(this.link); + } + else { + this.innerHTML = "添加收藏"; + lib.config.favouriteCharacter.remove(this.link); + } + if (ui.favouriteCharacter) { + if (lib.config.favouriteCharacter.contains(this.link)) { + for (var i = 0; i < ui.favouriteCharacter.childElementCount; i++) { + if (ui.favouriteCharacter.childNodes[i].link == this.link) { + break; + } + } + if (i == ui.favouriteCharacter.childElementCount) { + ui.create.button(this.link, "character", ui.favouriteCharacter).listen(function (e) { + this._banning = "offline"; + ui.click.touchpop(); + ui.click.intro.call(this, e); + _status.clicked = false; + delete this._banning; + }).classList.add("noclick"); + } + } + else { + for (var i = 0; i < ui.favouriteCharacter.childElementCount; i++) { + if (ui.favouriteCharacter.childNodes[i].link == this.link) { + ui.favouriteCharacter.childNodes[i].remove(); + break; + } + } + } + var shownode = false; + for (var i = 0; i < lib.config.favouriteCharacter.length; i++) { + var favname = lib.config.favouriteCharacter[i]; + if (lib.character[favname]) { + shownode = true; break; + } + } + if (shownode) { + ui.favouriteCharacter.node.style.display = ""; + } + else { + ui.favouriteCharacter.node.style.display = "none"; + } + } + game.saveConfig("favouriteCharacter", lib.config.favouriteCharacter); + } + e.stopPropagation(); + } + static buttonnameenter() { + if (this.buttonscrollinterval) { + clearInterval(this.buttonscrollinterval); + } + var node = this.node.name; + if (node.offsetHeight < node.scrollHeight) { + var that = this; + var num = 40; + that.buttonscrollinterval = setInterval(function () { + if (node.scrollTop + node.offsetHeight >= node.scrollHeight) { + clearInterval(that.buttonscrollinterval); + delete that.buttonscrollinterval; + } + else { + if (num > 0) { + num--; + } + else { + node.scrollTop += 2; + } + } + }, 16); + } + } + static buttonnameleave() { + if (this.buttonscrollinterval) { + clearInterval(this.buttonscrollinterval); + } + var node = this.node.name; + if (node.offsetHeight < node.scrollHeight) { + var that = this; + that.buttonscrollinterval = setInterval(function () { + if (node.scrollTop == 0) { + clearInterval(that.buttonscrollinterval); + delete that.buttonscrollinterval; + } + else { + node.scrollTop -= 2; + } + }, 16); + } + } + static dragtouchdialog(e) { + if (e.touches.length > 1 && + !this.classList.contains("popped") && + !this.classList.contains("fixed")) { + _status.draggingtouchdialog = this; + this._dragorigin = { + clientX: e.touches[0].clientX, + clientY: e.touches[0].clientY, + }; + if (!this._dragtransform) { + this._dragtransform = [0, 0]; + } + this._dragorigintransform = this._dragtransform.slice(0); + e.preventDefault(); + e.stopPropagation(); + } + } + static identity(e) { + if (_status.dragged) return; + _status.clicked = true; + if (!game.getIdentityList) return; + if (_status.video) return; + if (this.parentNode.forceShown) return; + if (!_status.connectMode && this.parentNode.ai.stratagem_camouflage && get.config("nei_auto_mark_camouflage") && game.me.identity == "nei") return; + if (_status.clickingidentity) { + for (var i = 0; i < _status.clickingidentity[1].length; i++) { + _status.clickingidentity[1][i].delete(); + _status.clickingidentity[1][i].style.transform = ""; + } + if (_status.clickingidentity[0] == this.parentNode) { + delete _status.clickingidentity; + return; + } + } + var list = game.getIdentityList(this.parentNode); + if (!list) return; + if (lib.config.mark_identity_style == "click") { + var list2 = []; + for (var i in list) { + list2.push(i); + } + list2.push(list2[0]); + for (var i = 0; i < list2.length; i++) { + if (this.firstChild.innerHTML == list[list2[i]]) { + this.firstChild.innerHTML = list[list2[i + 1]]; + this.dataset.color = list2[i + 1]; + break; + } + } + } + else { + if (get.mode() == "guozhan") { + list = { wei: "魏", shu: "蜀", wu: "吴", qun: "群", jin: "晋" }; + if (_status.forceKey) list.key = "键"; + } + var list2 = get.copy(list); + if (game.getIdentityList2) { + game.getIdentityList2(list2); + } + var rect = this.parentNode.getBoundingClientRect(); + this._customintro = function (uiintro) { + if (get.mode() == "guozhan") { + uiintro.clickintro = true; + } + else { + uiintro.touchclose = true; + } + // if(lib.config.theme!="woodden"){ + uiintro.classList.add("woodbg"); + // } + if (get.is.phoneLayout()) { + uiintro.style.width = "100px"; + } + else { + uiintro.style.width = "85px"; + } + var source = this.parentNode; + for (var i in list) { + var node = ui.create.div(); + node.classList.add("guessidentity"); + node.classList.add("pointerdiv"); + ui.create.div(".menubutton.large", list2[i], node); + if (!get.is.phoneLayout()) { + node.firstChild.style.fontSize = "24px"; + node.firstChild.style.lineHeight = "24px"; + } + if (get.mode() == "guozhan") { + if (source._guozhanguess) { + if (!source._guozhanguess.contains(i)) { + node.classList.add("transparent"); + } + } + node._source = source; + node.listen(ui.click.identitycircle); + } + else { + node.listen(function () { + var info = this.link; + info[0].firstChild.innerHTML = info[1]; + info[0].dataset.color = info[2]; + _status.clicked = false; + }); + } + + node.link = [this, list[i], i]; + uiintro.add(node); + } + }; + ui.click.touchpop(); + ui.click.intro.call(this, { + clientX: (rect.left + rect.width), + clientY: (rect.top) + }); + } + } + static identity2() { + if (_status.clickingidentity) { + _status.clicked = true; + var player = _status.clickingidentity[0]; + var nodes = _status.clickingidentity[1]; + player.node.identity.dataset.color = this.dataset.color; + player.node.identity.firstChild.innerHTML = this.firstChild.innerHTML; + for (var i = 0; i < nodes.length; i++) { + nodes[i].delete(); + nodes[i].style.transform = ""; + } + delete _status.clickingidentity; + } + } + static roundmenu() { + game.closeConnectMenu(); + switch (lib.config.round_menu_func) { + case "system": + game.closePopped(); + ui.system1.classList.add("shown"); + ui.system2.classList.add("shown"); + game.closeMenu(); + ui.click.shortcut(); + break; + case "menu": + if (ui.click.configMenu) { + game.closePopped(); + game.pause2(); + ui.click.configMenu(); + ui.system1.classList.remove("shown"); + ui.system2.classList.remove("shown"); + } + break; + case "pause": + ui.click.pause(); + break; + case "auto": + ui.click.auto(); + break; + } + _status.clicked = true; + } + static pausehistory() { + if (!lib.config.auto_popped_history) return; + if (!ui.sidebar.childNodes.length) return; + var uiintro = ui.create.dialog("hidden"); + uiintro.style.maxHeight = "400px"; + uiintro.add(ui.sidebar); + return uiintro; + } + static pauseconfig() { + if (!lib.config.auto_popped_config) return; + if (get.is.phoneLayout()) return; + var uiintro = ui.create.dialog("hidden"); + uiintro.listen(function (e) { + e.stopPropagation(); + }); + + var rows = Math.floor(lib.config.all.mode.length / 3); + uiintro.type = "config"; + var modes = lib.config.modeorder || lib.config.all.mode.slice(0); + for (var i = 0; i < modes.length; i++) { + if (!lib.config.all.mode.contains(modes[i])) { + modes.splice(i--, 1); + } + } + for (var k = 0; k < rows; k++) { + var node = ui.create.div(".newgame.pointernode"); + for (var i = 0; i < 3 && i + k * 3 < modes.length; i++) { + var thismode = modes[i + k * 3]; + var div = ui.create.div(thismode == (_status.sourcemode || lib.config.mode) ? ".underlinenode.on" : ".underlinenode", node); + div.innerHTML = lib.translate[thismode]; + div.link = thismode; + div.addEventListener(lib.config.touchscreen ? "touchend" : "click", function () { + game.saveConfig("mode", this.link); + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + }); + } + uiintro.add(node); + } + + return uiintro; + } + static cardPileButton() { + var uiintro = ui.create.dialog("hidden"); + uiintro.listen(function (e) { + e.stopPropagation(); + }); + var num; + if (game.online) { + num = _status.cardPileNum || 0; + } + else { + num = ui.cardPile.childNodes.length; + } + uiintro.add(`剩余 ${num}`); + + if (_status.connectMode) return uiintro; + uiintro.add(`
      轮数 ${game.roundNumber}    洗牌 ${game.shuffleNumber}
      `); + uiintro.add(`
      弃牌堆
      `); + if (ui.discardPile.childNodes.length) { + var list = []; + for (var i = 0; i < ui.discardPile.childNodes.length; i++) { + list.unshift(ui.discardPile.childNodes[i]); + } + uiintro.addSmall([list, "card"]); + } + else { + uiintro.add(`
      `); + } + return uiintro; + } + static chat() { + ui.system1.classList.add("shown"); + ui.system2.classList.add("shown"); + + var uiintro = ui.create.dialog("hidden"); + uiintro.listen(function (e) { + e.stopPropagation(); + }); + + var list = ui.create.div(".caption"); + if (get.is.phoneLayout()) { + list.style.maxHeight = "110px"; + } + else { + list.style.maxHeight = "220px"; + } + list.style.overflow = "scroll"; + lib.setScroll(list); + uiintro.contentContainer.style.overflow = "hidden"; + + var input; + var addEntry = function (info, clear) { + if (list._chatempty) { + list.innerHTML = ""; + delete list._chatempty; + } + var node = ui.create.div(".text.chat"); + node.innerHTML = info[0] + ": " + info[1]; + list.appendChild(node); + list.scrollTop = list.scrollHeight; + uiintro.style.height = uiintro.content.scrollHeight + "px"; + } + _status.addChatEntry = addEntry; + _status.addChatEntry._origin = uiintro; + if (lib.chatHistory.length) { + for (var i = 0; i < lib.chatHistory.length; i++) { + addEntry(lib.chatHistory[i]); + } + } + else { + list._chatempty = true; + list.appendChild(ui.create.div(".text.center", "无聊天记录")) + } + uiintro.add(list); + uiintro.style.height = uiintro.content.offsetHeight + "px"; + list.scrollTop = list.scrollHeight; + + if (!_status.chatValue) _status.chatValue = ""; + var node = uiintro.add(``); + node.style.paddingTop = 0; + node.style.marginBottom = "16px"; + input = node.firstChild; + input.style.width = "calc(100% - 20px)"; + input.onchange = function () { + _status.chatValue = input.value; + } + input.onkeydown = function (e) { + if (e.keyCode == 13 && input.value) { + var player = game.me; + var str = input.value; + if (!player) { + if (game.connectPlayers) { + if (game.online) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == game.onlineID) { + player = game.connectPlayers[i]; break; + } + } + } + else { + player = game.connectPlayers[0]; + } + } + } + if (!player) return; + if (get.is.banWords(input.value)) { + player.say(input.value); + input.value = ""; + _status.chatValue = ""; + } + else { + if (game.online) { + game.send("chat", game.onlineID, str); + } + else { + player.chat(str); + } + input.value = ""; + _status.chatValue = ""; + } + } + e.stopPropagation(); + } + uiintro._onopen = function () { + input.focus(); + list.scrollTop = list.scrollHeight; + }; + uiintro._heightfixed = true; + var emotionTitle = ui.create.div(".text.center", "聊天表情", function () { + if (emotionTitle.innerHTML == "快捷语音") { + emotionTitle.innerHTML = "聊天表情"; + list2.remove(); + list3.remove(); + uiintro.add(list1); + while (list2.childNodes.length) { + list2.firstChild.remove(); + } + } + else { + emotionTitle.innerHTML = "快捷语音"; + list1.remove(); + list2.remove(); + uiintro.add(list3); + } + }); + uiintro.add(emotionTitle); + var list1 = ui.create.div(""); + if (get.is.phoneLayout()) { + list1.style.height = "110px"; + } + else { + list1.style.height = "150px"; + } + list1.style.overflow = "scroll"; + lib.setScroll(list1); + uiintro.add(list1); + uiintro.style.height = uiintro.content.scrollHeight + "px"; + var list2 = ui.create.div(""); + if (get.is.phoneLayout()) { + list2.style.height = "110px"; + } + else { + list2.style.height = "150px"; + } + list2.style.overflow = "scroll"; + lib.setScroll(list2); + //uiintro.add(list2); + for (var i in lib.emotionList) { + var emotionPack = ui.create.div(".card.fullskin", ``, function () { + emotionTitle.innerHTML = get.translation(this.pack); + for (var j = 1; j <= lib.emotionList[this.pack]; j++) { + var emotionButton = ui.create.div(".card.fullskin", ``, function () { + var player = game.me; + if (!player) { + if (game.connectPlayers) { + if (game.online) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == game.onlineID) { + player = game.connectPlayers[i]; break; + } + } + } + else { + player = game.connectPlayers[0]; + } + } + } + if (!player) return; + if (game.online) { + game.send("emotion", game.onlineID, this.pack, this.emotionID); + } + else { + player.emotion(this.pack, this.emotionID); + } + }); + emotionButton.emotionID = j; + emotionButton.pack = this.pack; + emotionButton.style.height = "50px"; + emotionButton.style.width = "50px"; + list2.appendChild(emotionButton); + } + list1.remove(); + uiintro.add(list2); + }); + emotionPack.pack = i; + emotionPack.style.height = "50px"; + emotionPack.style.width = "50px"; + list1.appendChild(emotionPack); + } + list1.scrollTop = list1.scrollHeight; + uiintro.style.height = uiintro.content.scrollHeight + "px"; + var list3 = ui.create.div(".caption"); + if (get.is.phoneLayout()) { + list3.style.height = "110px"; + } + else { + list3.style.height = "150px"; + } + list3.style.overflow = "scroll"; + lib.setScroll(list3); + for (var i = 0; i < lib.quickVoice.length; i++) { + var node = ui.create.div(".text.chat", function () { + var player = game.me; + var str = this.innerHTML; + if (!player) { + if (game.connectPlayers) { + if (game.online) { + for (var i = 0; i < game.connectPlayers.length; i++) { + if (game.connectPlayers[i].playerid == game.onlineID) { + player = game.connectPlayers[i]; break; + } + } + } + else { + player = game.connectPlayers[0]; + } + } + } + if (!player) return; + if (game.online) { + game.send("chat", game.onlineID, str); + } + else { + player.chat(str); + } + }); + node.innerHTML = lib.quickVoice[i]; + list3.appendChild(node); + } + list3.scrollTop = list1.scrollHeight; + return uiintro; + } + static volumn() { + var uiintro = ui.create.dialog("hidden"); + uiintro.listen(function (e) { + e.stopPropagation(); + }); + uiintro.add("背景音乐"); + var vol1 = ui.create.div(".volumn"); + uiintro.add(vol1); + for (var i = 0; i < 8; i++) { + var span = document.createElement("span"); + span.link = i + 1; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.volumn_background); + if (i < lib.config.volumn_background) { + span.innerHTML = "●"; + } + else { + span.innerHTML = "○"; + } + vol1.appendChild(span); + } + uiintro.add("游戏音效"); + + var vol2 = ui.create.div(".volumn"); + uiintro.add(vol2); + for (var i = 0; i < 8; i++) { + var span = document.createElement("span"); + span.link = i + 1; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.volumn_audio); + if (i < lib.config.volumn_audio) { + span.innerHTML = "●"; + } + else { + span.innerHTML = "○"; + } + vol2.appendChild(span); + } + uiintro.add(ui.create.div(".placeholder")); + return uiintro; + } + static volumn_background(e) { + if (_status.dragged) return; + var volume = this.link; + if (volume === 1 && lib.config.volumn_background === 1) { + volume = 0; + } + game.saveConfig("volumn_background", volume); + ui.backgroundMusic.volume = volume / 8; + for (var i = 0; i < 8; i++) { + if (i < lib.config.volumn_background) { + this.parentNode.childNodes[i].innerHTML = "●"; + } + else { + this.parentNode.childNodes[i].innerHTML = "○"; + } + } + e.stopPropagation(); + } + static volumn_audio(e) { + if (_status.dragged) return; + var volume = this.link; + if (volume === 1 && lib.config.volumn_audio === 1) { + volume = 0; + } + game.saveConfig("volumn_audio", volume); + for (var i = 0; i < 8; i++) { + if (i < lib.config.volumn_audio) { + this.parentNode.childNodes[i].innerHTML = "●"; + } + else { + this.parentNode.childNodes[i].innerHTML = "○"; + } + } + e.stopPropagation(); + } + static hoverpopped() { + if (this._uiintro) { + return; + } + if (!this._poppedfunc) { + return; + } + ui.click.touchpop(this.forceclick); + var uiintro = this._poppedfunc(); + if (!uiintro) return; + if (ui.currentpopped && ui.currentpopped._uiintro) { + ui.currentpopped._uiintro.delete(); + delete ui.currentpopped._uiintro; + } + ui.currentpopped = this; + uiintro.classList.add("popped"); + uiintro.classList.add("hoverdialog"); + uiintro.classList.add("static"); + this._uiintro = uiintro; + + ui.window.appendChild(uiintro); + var width = this._poppedwidth || 330; + uiintro.style.width = width + "px"; + if (get.is.phoneLayout()) { + width *= 1.3; + } + + if (uiintro._heightfixed) { + uiintro.style.height = uiintro.content.scrollHeight + "px"; + } + else { + var height = this._poppedheight || uiintro.content.scrollHeight; + var height2 = ui.window.offsetHeight - 260; + if (get.is.phoneLayout()) { + height2 = (ui.window.offsetHeight - 80) / 1.3; + } + uiintro.style.height = Math.min(height2, height) + "px"; + } + if (get.is.phoneLayout()) { + uiintro.style.top = "70px"; + } + else { + uiintro.style.top = "50px"; + } + var left = this.parentNode.offsetLeft + this.offsetLeft + this.offsetWidth / 2 - width / 2; + if (left < 10) { + left = 10; + } + else if (left + width > ui.window.offsetWidth - 10) { + left = ui.window.offsetWidth - width - 10; + } + uiintro.style.left = left + "px"; + uiintro._poppedorigin = this; + if (!lib.config.touchscreen) { + uiintro.addEventListener("mouseleave", ui.click.leavehoverpopped); + } + ui.click.shortcut(false); + if (uiintro._onopen) { + uiintro._onopen(); + } + if (this._paused2 && !lib.config.touchscreen) { + game.pause2(); + uiintro.classList.add("static"); + var layer = ui.create.div(".poplayer", ui.window); + var clicklayer = function (e) { + uiintro.delete(); + layer.remove(); + game.resume2(); + e.stopPropagation(); + return false; + } + uiintro.style.zIndex = 21; + layer.onclick = clicklayer; + layer.oncontextmenu = clicklayer; + uiintro.addEventListener("mouseleave", clicklayer); + uiintro.addEventListener("click", clicklayer); + } + } + static hoverpopped_leave() { + this._poppedalready = false; + } + static leavehoverpopped() { + if (_status.dragged) return; + if (this.classList.contains("noleave")) return; + this.delete(); + var button = this._poppedorigin; + + var uiintro = this; + setTimeout(function () { + if (button._uiintro == uiintro) { + delete button._uiintro; + } + }, 500); + + } + static dierevive() { + if (game.me.isDead()) { + game.me.revive(Math.max(1, game.me.maxHp)); + game.me.draw(2); + } + else { + if (ui.revive) { + ui.revive.close(); + delete ui.revive; + } + } + } + static dieswap() { + if (game.me.isDead()) { + _status.clicked = true; + var i, translation, intro, str; + if (ui.intro) { + ui.intro.close(); + if (ui.intro.source == "dieswap") { + delete ui.intro; + ui.control.show(); + game.resume2(); + return; + } + } + game.pause2(); + ui.control.hide(); + ui.intro = ui.create.dialog(); + ui.intro.source = "dieswap"; + + var players = []; + for (var i = 0; i < game.players.length; i++) { + if (game.players[i].isAlive()) { + players.push(game.players[i]); + } + } + ui.intro.add(players, true); + var buttons = ui.intro.querySelectorAll(".button"); + for (var i = 0; i < buttons.length; i++) { + buttons[i].addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.dieswap2); + } + } + else { + if (ui.swap) { + ui.swap.close(); + delete ui.swap; + } + } + } + static dieswap2() { + if (_status.dragged) return; + game.swapPlayer(this.link); + } + static touchconfirm() { + _status.touchconfirmed = true; + document.removeEventListener("touchstart", ui.click.touchconfirm); + } + static windowtouchstart(e) { + if (window.inSplash) return; + if (e.touches[0] && lib.config.swipe && e.touches.length < 2) { + _status._swipeorigin = { + clientX: e.touches[0].clientX, + clientY: e.touches[0].clientY, + time: get.utc() + } + } + // if(window.ForceTouch&&!_status.paused2&&!_status.forcetouchinterval&&lib.config.enable_pressure){ + // _status.forcetouchinterval=setInterval(ui.click.forcetouch,30); + // } + } + static windowtouchmove(e) { + e.preventDefault(); + if (window.inSplash) return; + if (_status.draggingroundmenu) { + delete _status._swipeorigin; + if (ui.roundmenu._dragorigin && ui.roundmenu._dragtransform && e.touches.length) { + var translate = ui.roundmenu._dragtransform.slice(0); + var dx = e.touches[0].clientX / game.documentZoom - ui.roundmenu._dragorigin.clientX / game.documentZoom; + var dy = e.touches[0].clientY / game.documentZoom - ui.roundmenu._dragorigin.clientY / game.documentZoom; + translate[0] += dx; + translate[1] += dy; + if (dx * dx + dy * dy > 100) { + if (ui.roundmenu._resetTimeout) { + clearTimeout(ui.roundmenu._resetTimeout); + delete ui.roundmenu._resetTimeout; + } + } + ui.roundmenu._dragtouches = e.touches[0]; + ui.click.checkroundtranslate(translate); + } + _status.clicked = true; + } + else if (_status.draggingtouchdialog) { + delete _status._swipeorigin; + if (_status.draggingtouchdialog._dragorigin && _status.draggingtouchdialog._dragtransform && e.touches.length) { + var translate = _status.draggingtouchdialog._dragtransform.slice(0); + var dx = e.touches[0].clientX / game.documentZoom - _status.draggingtouchdialog._dragorigin.clientX / game.documentZoom; + var dy = e.touches[0].clientY / game.documentZoom - _status.draggingtouchdialog._dragorigin.clientY / game.documentZoom; + translate[0] += dx; + translate[1] += dy; + _status.draggingtouchdialog._dragtouches = e.touches[0]; + ui.click.checkdialogtranslate(translate, _status.draggingtouchdialog); + } + _status.clicked = true; + } + else if (_status._swipeorigin && e.touches[0]) { + _status._swipeorigin.touches = e.touches[0]; + } + + if (_status.mousedragging && e.touches.length) { + e.preventDefault(); + var item = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY); + if (game.chess && ui.selected.cards.length) { + var itemtype = get.itemtype(item); + if (itemtype != "card" && itemtype != "button") { + var ex = e.touches[0].clientX / game.documentZoom - ui.arena.offsetLeft; + var ey = e.touches[0].clientY / game.documentZoom - ui.arena.offsetTop; + for (var i = 0; i < game.players.length; i++) { + var left = -ui.chessContainer.chessLeft + ui.chess.offsetLeft + game.players[i].getLeft(); + var top = -ui.chessContainer.chessTop + ui.chess.offsetTop + game.players[i].getTop(); + var width = game.players[i].offsetWidth; + var height = game.players[i].offsetHeight; + if (ex > left && ex < left + width && ey > top && ey < top + height) { + item = game.players[i]; + break; + } + } + } + } + while (item) { + if (lib.config.enable_touchdragline && _status.mouseleft && !game.chess) { + ui.canvas.width = ui.arena.offsetWidth; + ui.canvas.height = ui.arena.offsetHeight; + var ctx = ui.ctx; + ctx.shadowBlur = 5; + ctx.shadowColor = "rgba(0,0,0,0.3)"; + ctx.strokeStyle = "white"; + ctx.lineWidth = 3; + ctx.setLineDash([8, 2]); + + ctx.beginPath(); + + ctx.moveTo(_status.mousedragging.clientX / game.documentZoom - ui.arena.offsetLeft, _status.mousedragging.clientY / game.documentZoom - ui.arena.offsetTop); + + if (_status.multitarget) { + for (var i = 0; i < _status.lastdragchange.length; i++) { + var exy = _status.lastdragchange[i]._lastdragchange; + ctx.lineTo(exy[0], exy[1]); + } + } + if (!_status.selectionfull) { + ctx.lineTo(e.touches[0].clientX / game.documentZoom - ui.arena.offsetLeft, e.touches[0].clientY / game.documentZoom - ui.arena.offsetTop); + } + ctx.stroke(); + if (!_status.multitarget) { + for (var i = 0; i < _status.lastdragchange.length; i++) { + ctx.moveTo(_status.mousedragging.clientX / game.documentZoom - ui.arena.offsetLeft, _status.mousedragging.clientY / game.documentZoom - ui.arena.offsetTop); + var exy = _status.lastdragchange[i]._lastdragchange; + ctx.lineTo(exy[0], exy[1]); + ctx.stroke(); + } + } + } + + if (item == _status.mousedragorigin) { + if (_status.mouseleft) { + _status.mousedragging = null; + _status.mousedragorigin = null; + _status.clicked = false; + game.uncheck(); + game.check(); + _status.clicked = true; + } + return; + } + var itemtype = get.itemtype(item); + if (itemtype == "card" || itemtype == "button" || itemtype == "player") { + _status.mouseleft = true; + if (ui.selected.cards.length) { + ui.selected.cards[0].updateTransform(true, 100); + } + var ex = e.touches[0].clientX / game.documentZoom - ui.arena.offsetLeft; + var ey = e.touches[0].clientY / game.documentZoom - ui.arena.offsetTop; + var exx = ex, eyy = ey; + if (game.chess) { + ex -= -ui.chessContainer.chessLeft + ui.chess.offsetLeft; + ey -= -ui.chessContainer.chessTop + ui.chess.offsetTop; + } + if (itemtype != "player" || game.chess || (ex > item.offsetLeft && ex < item.offsetLeft + item.offsetWidth && + ey > item.offsetTop && ey < item.offsetTop + item.offsetHeight)) { + var targetfixed = false; + if (itemtype == "player") { + if (get.select(_status.event.selectTarget)[1] <= -1) { + targetfixed = true; + } + } + if (!targetfixed && item.classList.contains("selectable") && _status.dragstatuschanged != item) { + _status.mouseleft = true; + _status.dragstatuschanged = item; + _status.clicked = false; + _status.dragged = false; + var notbefore = itemtype == "player" && !item.classList.contains("selected"); + ui.click[itemtype].call(item); + if (item.classList.contains("selected")) { + if (notbefore) { + _status.lastdragchange.push(item); + item._lastdragchange = [exx, eyy]; + if (lib.falseitem) { + var from = [_status.mousedragging.clientX / game.documentZoom - ui.arena.offsetLeft, _status.mousedragging.clientY / game.documentZoom - ui.arena.offsetTop]; + var to = [exx, eyy]; + var node = ui.create.div(".linexy.hidden"); + node.style.left = from[0] + "px"; + node.style.top = from[1] + "px"; + node.style.transitionDuration = "0.3s"; + node.style.backgroundColor = "white"; + var dy = to[1] - from[1]; + var dx = to[0] - from[0]; + var deg = Math.atan(Math.abs(dy) / Math.abs(dx)) / Math.PI * 180; + if (dx >= 0) { + if (dy <= 0) { + deg += 90; + } + else { + deg = 90 - deg; + } + } + else { + if (dy <= 0) { + deg = 270 - deg; + } + else { + deg += 270; + } + } + node.style.transform = "rotate(" + (-deg) + "deg) scaleY(0)"; + node.style.height = get.xyDistance(from, to) + "px"; + if (game.chess) { + ui.chess.appendChild(node); + } + else { + ui.arena.appendChild(node); + } + ui.refresh(node); + node.show(); + node.style.transform = "rotate(" + (-deg) + "deg) scaleY(1)"; + ui.touchlines.push(node); + node._origin = item; + } + } + } + else { + _status.lastdragchange.remove(item); + for (var i = 0; i < ui.touchlines.length; i++) { + if (ui.touchlines[i]._origin == item) { + ui.touchlines[i].delete(); + ui.touchlines.splice(i--, 1); + } + } + } + _status.selectionfull = true; + if (_status.event.filterButton && ui.selected.buttons.length < get.select(_status.event.selectButton)[1]) { + _status.selectionfull = false; + } + else if (_status.event.filterCard && ui.selected.cards.length < get.select(_status.event.selectCard)[1]) { + _status.selectionfull = false; + } + else if (_status.event.filterTarget && ui.selected.targets.length < get.select(_status.event.selectTarget)[1]) { + _status.selectionfull = false; + } + } + } + return; + } + item = item.parentNode; + } + _status.mouseleft = true; + _status.dragstatuschanged = null; + } + } + static windowtouchend(e) { + delete _status.force; + // if(_status.forcetouchinterval){ + // clearInterval(_status.forcetouchinterval); + // delete _status.forcetouchinterval; + // } + if (window.inSplash) return; + if (e.touches.length == 1 && !_status.dragged && !_status.draggingtouchdialog) { + ui.click.pause(); + } + if (_status.draggingroundmenu) { + delete _status._swipeorigin; + if (ui.roundmenu._resetTimeout) { + clearTimeout(ui.roundmenu._resetTimeout); + delete ui.roundmenu._resetTimeout; + } + var translate; + if (ui.roundmenu._dragorigin && ui.roundmenu._dragtransform && ui.roundmenu._dragtouches) { + var dx = ui.roundmenu._dragtouches.clientX / game.documentZoom - ui.roundmenu._dragorigin.clientX / game.documentZoom; + var dy = ui.roundmenu._dragtouches.clientY / game.documentZoom - ui.roundmenu._dragorigin.clientY / game.documentZoom; + if (dx * dx + dy * dy < 1000) { + ui.click.roundmenu(); + ui.roundmenu._dragtransform = ui.roundmenu._dragorigintransform; + translate = ui.roundmenu._dragtransform; + ui.roundmenu.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px)"; + } + else { + translate = ui.roundmenu._dragtransform; + translate[0] += dx; + translate[1] += dy; + ui.click.checkroundtranslate(); + } + delete ui.roundmenu._dragorigin; + } + else { + ui.click.roundmenu(); + } + _status.clicked = false; + game.saveConfig("roundmenu_transform", translate); + delete _status.draggingroundmenu; + } + else if (_status.draggingtouchdialog) { + delete _status._swipeorigin; + var translate; + if (_status.draggingtouchdialog._dragorigin && _status.draggingtouchdialog._dragtransform && _status.draggingtouchdialog._dragtouches) { + var dx = _status.draggingtouchdialog._dragtouches.clientX / game.documentZoom - _status.draggingtouchdialog._dragorigin.clientX / game.documentZoom; + var dy = _status.draggingtouchdialog._dragtouches.clientY / game.documentZoom - _status.draggingtouchdialog._dragorigin.clientY / game.documentZoom; + translate = _status.draggingtouchdialog._dragtransform; + translate[0] += dx; + translate[1] += dy; + ui.click.checkdialogtranslate(null, _status.draggingtouchdialog); + + delete _status.draggingtouchdialog._dragorigin; + } + _status.clicked = false; + game.saveConfig("dialog_transform", translate); + delete _status.draggingtouchdialog; + _status.justdragged = true; + setTimeout(function () { + _status.justdragged = false; + }, 500); + } + else if (_status._swipeorigin && !_status.paused2 && !_status.mousedragging && _status._swipeorigin.touches && !_status.filterCharacter) { + if (get.utc() - _status._swipeorigin.time < 500) { + var dx = _status._swipeorigin.touches.clientX / game.documentZoom - _status._swipeorigin.clientX / game.documentZoom; + var dy = _status._swipeorigin.touches.clientY / game.documentZoom - _status._swipeorigin.clientY / game.documentZoom; + var goswipe = function (action) { + game.closeConnectMenu(); + switch (action) { + case "system": + game.closePopped(); + ui.system1.classList.add("shown"); + ui.system2.classList.add("shown"); + game.closeMenu(); + ui.click.shortcut(); + break; + case "menu": + if (ui.click.configMenu) { + game.closePopped(); + game.pause2(); + ui.click.configMenu(); + ui.system1.classList.remove("shown"); + ui.system2.classList.remove("shown"); + } + break; + case "pause": + ui.click.pause(); + break; + case "auto": + ui.click.auto(); + break; + case "chat": + game.closeMenu(); + if (ui.chatButton) { + ui.click.hoverpopped.call(ui.chatButton); + } + break; + } + } + if (Math.abs(dx) < 100) { + if (dy < -200) { + goswipe(lib.config.swipe_up); + } + else if (dy > 200) { + goswipe(lib.config.swipe_down); + } + } + else if (Math.abs(dy) < 100) { + if (dx < -200) { + goswipe(lib.config.swipe_left); + } + else if (dx > 200) { + goswipe(lib.config.swipe_right); + } + } + } + } + var tmpflag = false; + _status.mousedown = false; + _status.clicked = false; + if (_status.mousedragging && _status.mouseleft) { + if (game.check()) { + if (ui.confirm) { + ui.confirm.close(); + } + var event = _status.event; + if (!event.filterOk || event.filterOk()) ui.click.ok(); + ui.canvas.width = ui.arena.offsetWidth; + ui.canvas.height = ui.arena.offsetHeight; + } + else { + game.uncheck(); + game.check(); + } + } + else if (_status.mousedragging && _status.mousedragorigin) { + tmpflag = _status.mousedragorigin; + } + _status.lastdragchange.length = 0; + _status.mousedragging = null; + _status.mouseleft = false; + _status.mousedragorigin = null; + _status.dragstatuschanged = false; + while (ui.touchlines.length) { + ui.touchlines.shift().delete(); + } + if (tmpflag) { + game.check(); + } + _status.dragged = false; + _status.clicked = false; + } + static checkroundtranslate(translate) { + var translate = translate || ui.roundmenu._dragtransform; + if (translate[1] + ui.roundmenu._position[1] + 50 + ui.arena.offsetTop > ui.window.offsetHeight) { + translate[1] = ui.window.offsetHeight - (ui.roundmenu._position[1] + 50) - ui.arena.offsetTop; + } + else if (translate[1] + ui.roundmenu._position[1] + ui.arena.offsetTop < 0) { + translate[1] = -ui.roundmenu._position[1] - ui.arena.offsetTop; + } + if (translate[0] + ui.roundmenu._position[0] + 50 + ui.arena.offsetLeft > ui.window.offsetWidth) { + translate[0] = ui.window.offsetWidth - (ui.roundmenu._position[0] + 50) - ui.arena.offsetLeft; + } + else if (translate[0] + ui.roundmenu._position[0] + ui.arena.offsetLeft < 0) { + translate[0] = -ui.roundmenu._position[0] - ui.arena.offsetLeft; + } + ui.roundmenu.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px)"; + } + static checkdialogtranslate(translate, dialog) { + var translate = translate || dialog._dragtransform; + if (Math.sqrt(translate[0] * translate[0] + translate[1] * translate[1]) < 10) { + translate[0] = 0; + translate[1] = 0; + } + dialog.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px)"; + } + static windowmousewheel(e) { + _status.tempunpopup = e; + } + static windowmousemove(e) { + if (window.inSplash) return; + if (_status.tempunpopup) { + if (get.evtDistance(_status.tempunpopup, e) > 5) { + delete _status.tempunpopup; + } + } + if (e.button == 2) return; + var dialogs = document.querySelectorAll("#window>.dialog.popped:not(.static)"); + for (var i = 0; i < dialogs.length; i++) { + dialogs[i].delete(); + } + var node = _status.currentmouseenter; + var sourceitem = document.elementFromPoint(e.clientX, e.clientY); + if (game.chess && ui.selected.cards.length) { + var itemtype = get.itemtype(sourceitem); + if (itemtype != "card" && itemtype != "button") { + for (var i = 0; i < game.players.length; i++) { + var ex = e.clientX / game.documentZoom - ui.arena.offsetLeft; + var ey = e.clientY / game.documentZoom - ui.arena.offsetTop; + var left = -ui.chessContainer.chessLeft + ui.chess.offsetLeft + game.players[i].getLeft(); + var top = -ui.chessContainer.chessTop + ui.chess.offsetTop + game.players[i].getTop(); + var width = game.players[i].offsetWidth; + var height = game.players[i].offsetHeight; + if (ex > left && ex < left + width && ey > top && ey < top + height) { + sourceitem = game.players[i]; + break; + } + } + } + } + var item = sourceitem; + if (_status.mousedragging) { + e.preventDefault(); + if (lib.config.enable_dragline) { + // var i=0; + // var startPoint0=[_status.mousedragging.clientX/game.documentZoom-ui.arena.offsetLeft,_status.mousedragging.clientY/game.documentZoom-ui.arena.offsetTop]; + // var startPoint=startPoint0; + // var endPoint; + // if(_status.multitarget){ + // for(;i<_status.lastdragchange.length;i++){ + // var exy=_status.lastdragchange[i]._lastdragchange; + // endPoint=[exy[0],exy[1]]; + // _status.dragline[i]=game.linexy(startPoint.concat(endPoint),"drag",_status.dragline[i]); + // startPoint=endPoint; + // } + // } + // if(!_status.selectionfull){ + // endPoint=[e.clientX/game.documentZoom-ui.arena.offsetLeft,e.clientY/game.documentZoom-ui.arena.offsetTop]; + // _status.dragline[i]=game.linexy(startPoint.concat(endPoint),"drag",_status.dragline[i]); + // startPoint=endPoint; + // i++; + // } + // if(!_status.multitarget){ + // for(var j=0;j<_status.lastdragchange.length;j++){ + // i+=j; + // var exy=_status.lastdragchange[j]._lastdragchange; + // _status.dragline[i]=game.linexy(startPoint0.concat([exy[0],exy[1]]),"drag",_status.dragline[i]); + // } + // } + // var remained=_status.dragline.splice(i+1); + // for(var j=0;j item.offsetLeft && ex < item.offsetLeft + item.offsetWidth && + ey > item.offsetTop && ey < item.offsetTop + item.offsetHeight)) { + var targetfixed = false; + if (itemtype == "player") { + if (get.select(_status.event.selectTarget)[1] <= -1) { + targetfixed = true; + } + } + if (!targetfixed && item.classList.contains("selectable") && _status.dragstatuschanged != item) { + _status.mouseleft = true; + _status.dragstatuschanged = item; + _status.clicked = false; + var notbefore = itemtype == "player" && !item.classList.contains("selected"); + ui.click[itemtype].call(item); + if (item.classList.contains("selected")) { + if (notbefore) { + _status.lastdragchange.push(item); + item._lastdragchange = [exx, eyy]; + } + } + else { + _status.lastdragchange.remove(item); + } + _status.selectionfull = true; + if (_status.event.filterButton && ui.selected.buttons.length < get.select(_status.event.selectButton)[1]) { + _status.selectionfull = false; + } + else if (_status.event.filterCard && ui.selected.cards.length < get.select(_status.event.selectCard)[1]) { + _status.selectionfull = false; + } + else if (_status.event.filterTarget && ui.selected.targets.length < get.select(_status.event.selectTarget)[1]) { + _status.selectionfull = false; + } + } + } + return; + } + item = item.parentNode; + } + if (!_status.mouseleft) { + _status.mouseleft = true; + game.check(); + for (var i = 0; i < ui.selected.cards.length; i++) { + ui.selected.cards[i].updateTransform(true); + } + } + _status.dragstatuschanged = null; + } + else { + while (item) { + if (item == node && !node._mouseentercreated) { + ui.click.mouseentercancel(); + var hoveration; + if (typeof node._hoveration == "number") { + hoveration = node._hoveration; + } + else { + hoveration = parseInt(lib.config.hoveration); + if (node.classList.contains("button") || + (node.parentNode && node.parentNode.parentNode) == ui.me) { + hoveration += 500; + } + } + _status._mouseentertimeout = setTimeout(function () { + if (_status.currentmouseenter != node || node._mouseentercreated || _status.tempunpopup || + _status.mousedragging || _status.mousedown || !node.offsetWidth || !node.offsetHeight) { + return; + } + if (node._hoverfunc && !node._nopup) { + var dialog = node._hoverfunc.call(node, e); + if (dialog) { + dialog.classList.add("popped"); + ui.window.appendChild(dialog); + lib.placePoppedDialog(dialog, e); + if (node._hoverwidth) { + dialog.style.width = node._hoverwidth + "px"; + dialog._hovercustomed = true; + } + node._mouseenterdialog = dialog; + node._mouseentercreated = true; + } + } + }, hoveration); + break; + } + item = item.parentNode; + } + if (_status.draggingdialog) { + var ddialog = _status.draggingdialog; + if (ddialog._dragorigin && ddialog._dragtransform) { + var translate = ddialog._dragtransform.slice(0); + translate[0] += e.clientX / game.documentZoom - ddialog._dragorigin.clientX / game.documentZoom; + translate[1] += e.clientY / game.documentZoom - ddialog._dragorigin.clientY / game.documentZoom; + ui.click.checkdialogtranslate(translate, ddialog); + } + _status.clicked = true; + } + if (_status.draggingroundmenu) { + if (ui.roundmenu._dragorigin && ui.roundmenu._dragtransform) { + var translate = ui.roundmenu._dragtransform.slice(0); + translate[0] += e.clientX / game.documentZoom - ui.roundmenu._dragorigin.clientX / game.documentZoom; + translate[1] += e.clientY / game.documentZoom - ui.roundmenu._dragorigin.clientY / game.documentZoom; + ui.click.checkroundtranslate(translate); + } + _status.clicked = true; + } + } + } + static windowmousedown(e) { + if (window.inSplash) return; + if (!ui.window) return; + if (e.button == 2) return; + _status.mousedown = true; + var dialogs = ui.window.querySelectorAll("#window>.dialog.popped:not(.static)"); + for (var i = 0; i < dialogs.length; i++) { + dialogs[i].delete(); + } + var sourceitem = document.elementFromPoint(e.clientX, e.clientY); + var item = sourceitem; + while (item) { + var itemtype = get.itemtype(item); + if (itemtype == "button") break; + if (itemtype == "dialog" && + !item.classList.contains("popped") && + !item.classList.contains("fixed")) { + var ddialog = item; + _status.draggingdialog = ddialog; + ddialog._dragorigin = e; + if (!ddialog._dragtransform) { + ddialog._dragtransform = [0, 0]; + } + return; + } + if (item == ui.roundmenu) { + _status.draggingroundmenu = true; + ui.roundmenu._dragorigin = e; + if (!ui.roundmenu._dragtransform) { + ui.roundmenu._dragtransform = [0, 0]; + } + return; + } + item = item.parentNode; + } + + var evt = _status.event; + if (!lib.config.enable_drag) return; + if (!ui.arena.classList.contains("selecting")) return; + if (!evt.isMine()) return; + + item = sourceitem; + while (item) { + var itemtype = get.itemtype(item); + if (itemtype == "card" || itemtype == "button" || itemtype == "player") { + if (item.classList.contains("selectable") && + !item.classList.contains("selected") && + !item.classList.contains("noclick")) { + _status.clicked = false; + ui.click[itemtype].call(item); + if (item.classList.contains("selected")) { + _status.mousedragging = e; + _status.mousedragorigin = item; + _status.mouseleft = false; + _status.selectionfull = false; + _status.multitarget = false; + _status.lastmouseutc = get.utc(); + ui.arena.classList.add("dragging"); + } + } + return; + } + item = item.parentNode; + } + } + static cardtouchstart(e) { + if (e.touches.length != 1) return; + if (!lib.config.enable_drag) return; + if (!this.parentNode) return; + if (!this.parentNode.parentNode) return; + if (this.parentNode.parentNode.parentNode != ui.me) return; + if (this.parentNode.parentNode.classList.contains("scrollh")) return; + if (this.classList.contains("selectable") && + !this.classList.contains("selected") && + !this.classList.contains("noclick")) { + this._waitingfordrag = { + clientX: e.touches[0].clientX, + clientY: e.touches[0].clientY + }; + } + } + static cardtouchmove(e) { + ui.click.longpresscancel.call(this); + if (this._waitingfordrag) { + var drag = this._waitingfordrag; + _status.clicked = false; + _status.touchnocheck = true; + ui.click.card.call(this); + _status.touchnocheck = false; + if (this.classList.contains("selected")) { + _status.mousedragging = drag; + _status.mousedragorigin = this; + _status.mouseleft = false; + _status.selectionfull = false; + _status.multitarget = false; + } + delete this._waitingfordrag; + } + } + static windowmouseup(e) { + delete _status.force; + if (window.inSplash) return; + if (_status.draggingdialog) { + var ddialog = _status.draggingdialog; + var translate; + if (ddialog._dragorigin && ddialog._dragtransform) { + translate = ddialog._dragtransform; + translate[0] += e.clientX / game.documentZoom - ddialog._dragorigin.clientX / game.documentZoom; + translate[1] += e.clientY / game.documentZoom - ddialog._dragorigin.clientY / game.documentZoom; + ui.click.checkdialogtranslate(null, ddialog); + delete ddialog._dragorigin; + } + game.saveConfig("dialog_transform", translate); + delete _status.draggingdialog; + } + if (_status.draggingroundmenu) { + var translate; + if (ui.roundmenu._dragorigin && ui.roundmenu._dragtransform) { + var dx = e.clientX / game.documentZoom - ui.roundmenu._dragorigin.clientX / game.documentZoom; + var dy = e.clientY / game.documentZoom - ui.roundmenu._dragorigin.clientY / game.documentZoom; + if (dx * dx + dy * dy < 25) { + ui.click.roundmenu(); + } + translate = ui.roundmenu._dragtransform; + translate[0] += dx; + translate[1] += dy; + ui.click.checkroundtranslate(); + delete ui.roundmenu._dragorigin; + } + game.saveConfig("roundmenu_transform", translate); + delete _status.draggingroundmenu; + } + if (e.button == 2) { + if (_status.mousedragging) { + _status.mousedragging = null; + _status.mouseleft = false; + _status.mousedragorigin = null; + _status.dragstatuschanged = false; + game.uncheck(); + game.check(); + _status.noright = true; + } + } + else { + var tmpflag = false; + _status.mousedown = false; + for (var i = 0; i < ui.selected.cards.length; i++) { + ui.selected.cards[i].updateTransform(true); + } + if (_status.mousedragging && _status.mouseleft) { + if (game.check()) { + if (ui.confirm) { + ui.confirm.close(); + } + var event = _status.event; + if (!event.filterOk || event.filterOk()) ui.click.ok(); + } + else { + game.uncheck(); + game.check(); + } + } + else if (_status.mousedragging && _status.mousedragorigin) { + tmpflag = _status.mousedragorigin; + } + _status.lastdragchange.length = 0; + _status.mousedragging = null; + _status.mouseleft = false; + _status.mousedragorigin = null; + _status.dragstatuschanged = false; + if (ui.arena) { + ui.canvas.width = ui.arena.offsetWidth; + ui.canvas.height = ui.arena.offsetHeight; + } + if (tmpflag) { + ui.click[get.itemtype(tmpflag)].call(tmpflag); + game.check(); + } + // ui.updatehl(); + } + if (ui.arena) { + ui.arena.classList.remove("dragging"); + } + } + static mousemove() { + if (!lib.config.hover_handcard && this.parentNode && this.parentNode.parentNode == ui.me) { + return; + } + if (!_status.currentmouseenter) { + _status.currentmouseenter = this; + } + } + static mouseenter() { + if (!lib.config.hover_handcard && this.parentNode && this.parentNode.parentNode == ui.me) { + return; + } + _status.currentmouseenter = this; + } + static mouseleave() { + ui.click.mouseentercancel(); + if (_status.currentmouseenter == this) { + _status.currentmouseenter = null; + } + this._mouseentercreated = false; + } + static mousedown() { + ui.click.mouseentercancel(); + if (_status.currentmouseenter == this) { + _status.currentmouseenter = null; + } + this._mouseentercreated = true; + } + static mouseentercancel() { + if (_status._mouseentertimeout) { + clearTimeout(_status._mouseentertimeout); + delete _status._mouseentertimeout + } + } + static hoverplayer(e) { + var node = get.nodeintro(this, true); + if (node) node.style.zIndex = 21; + return node; + } + static longpressdown(e) { + if (_status.longpressed) return; + if (this._longpresstimeout) { + clearTimeout(this._longpresstimeout); + } + if (lib.config.longpress_info) { + this._longpresstimeout = setTimeout(ui.click.longpresscallback, 500); + } + this._longpressevent = e; + if (_status.longpressing && _status.longpressing != this) { + ui.click.longpresscancel.call(_status.longpressing); + } + // if(window.ForceTouch&&!_status.forcetouchinterval&&lib.config.enable_pressure){ + // _status.forcetouchinterval=setInterval(ui.click.forcetouch,30); + // } + _status.longpressing = this; + } + static longpresscallback() { + if (!_status.longpressing) return; + var node = _status.longpressing; + var func = node._longpresscallback; + var e = node._longpressevent; + if (!func || !e) return; + clearTimeout(node._longpresstimeout); + _status.force = true; + delete _status.longpressing; + delete node._longpresstimeout; + delete node._longpressevent; + if (_status.mousedragging && _status.mouseleft) return; + if (!_status.longpressed) { + _status.longpressed = true; + setTimeout(function () { + _status.longpressed = false; + }, 500); + func.call(node, e); + if (lib.config.touchscreen && lib.config.enable_drag && !node._waitingfordrag) { + _status.mousedragging = null; + _status.mousedragorigin = null; + _status.clicked = false; + game.uncheck(); + game.check(); + _status.clicked = true; + } + delete node._waitingfordrag; + ui.click.touchpop(); + } + } + static longpresscancel() { + if (this._longpresstimeout) { + clearTimeout(this._longpresstimeout); + delete this._longpresstimeout; + } + delete this._longpressevent; + if (_status.longpressing == this) { + delete _status.longpressing; + } + } + static window() { + var clicked = _status.clicked; + var dialogtouched = false; + if (_status.dialogtouched) { + _status.dialogtouched = false; + dialogtouched = true; + } + if (_status.dragged) return; + if (_status.touchpopping) return; + if (_status.reloading) return; + if (_status.clicked || _status.clicked2) { + _status.clicked = false; + _status.clicked2 = false; + } + else { + if (_status.clickingidentity) { + for (var i = 0; i < _status.clickingidentity[1].length; i++) { + _status.clickingidentity[1][i].delete(); + _status.clickingidentity[1][i].style.transform = ""; + } + delete _status.clickingidentity; + } + if (!_status.event.isMine) return; + if (ui.controls.length) { + ui.updatec(); + } + if (_status.editing) { + if (_status.editing.innerHTML.length) { + _status.editing.link = _status.editing.innerHTML; + } + _status.editing.innerHTML = get.translation(_status.editing.link); + delete _status.editing; + } + else if (_status.choosing) { + if (!_status.choosing.expand) { + _status.choosing.parentNode.style.height = ""; + _status.choosing.nextSibling.delete(); + _status.choosing.previousSibling.show(); + delete _status.choosing; + } + } + else if (ui.intro) { + ui.intro.close(); + delete ui.intro; + ui.control.show(); + game.resume2(); + } + else if ((_status.event.isMine() || _status.event.forceMine) && !dialogtouched) { + if (_status.event.custom && _status.event.custom.replace.window) { + _status.event.custom.replace.window(); + } + else { + if (_status.event.skill && _status.event.name == "chooseToUse") { + ui.click.cancel(); + } + else if (_status.event._checked) { + game.uncheck(); + game.check(); + } + } + } + if (!ui.shortcut.classList.contains("hidden")) { + ui.click.shortcut(false); + } + if (get.is.phoneLayout() && ui.menuContainer && ui.menuContainer.classList.contains("hidden")) { + if (ui.system2.classList.contains("shown")) { + _status.removinground = true; + setTimeout(function () { + _status.removinground = false; + }, 200); + } + ui.arena.classList.remove("phonetop"); + ui.system1.classList.remove("shown"); + ui.system2.classList.remove("shown"); + // if(ui.chessinfo){ + // ui.chessinfo.classList.remove("zoomed"); + // } + } + } + if (_status.tempunpop) { + _status.tempunpop = false; + } + else { + game.closePopped(); + } + if (_status.event.custom && _status.event.custom.add.window) { + _status.event.custom.add.window(clicked); + } + } + static toggle() { + if (_status.dragged) return; + if (this.parentNode.classList.contains("disabled")) return; + _status.tempunpop = true; + if (this.link) { + this.link = false; + this.classList.remove("on"); + if (this.additionalCommand) this.additionalCommand(false, this.parentNode); + } + else { + this.link = true; + this.classList.add("on"); + if (this.additionalCommand) this.additionalCommand(true, this.parentNode); + } + } + static editor() { + if (_status.dragged) return; + if (_status.editing) return; + _status.clicked = true; + this.innerHTML = ""; + _status.editing = this; + if (this.additionalCommand) this.additionalCommand(this); + } + static switcher() { + if (_status.dragged) return; + if (this.parentNode.classList.contains("disabled")) return; + if (_status.choosing) return; + _status.clicked = true; + _status.tempunpop = true; + this.previousSibling.hide(); + var node = ui.create.div(".switcher", this.parentNode).animate("start"); + for (var i = 0; i < this.choice.length; i++) { + var choice = ui.create.div(".pointerdiv", node); + choice.innerHTML = get.translation(this.choice[i]); + choice.link = this.choice[i]; + choice.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.choice); + } + // this.parentNode.style.height=(node.offsetHeight)+"px"; + _status.choosing = this; + if (!_status.choosing.expand) { + _status.choosing.expand = true; + setTimeout(function () { + _status.choosing.expand = false; + }, 500); + } + } + static choice() { + if (_status.dragged) return; + if (!_status.choosing) return; + _status.choosing.link = this.link; + _status.choosing.innerHTML = get.translation(this.link); + this.parentNode.parentNode.style.height = ""; + this.parentNode.delete(); + _status.choosing.previousSibling.show(); + delete _status.choosing; + if (this.parentNode.parentNode.querySelector(".toggle").additionalCommand) { + this.parentNode.parentNode.querySelector(".toggle").additionalCommand(this.link, this.parentNode.parentNode); + } + } + static button() { + if (_status.dragged) return; + if (_status.clicked) return; + if (_status.tempNoButton) return; + if (_status.draggingtouchdialog) return; + if (this.classList.contains("noclick")) return; + if (_status.justdragged) return; + _status.clicked = true; + var custom = _status.event.custom; + if (custom && custom.replace.button) { + custom.replace.button(this); + return; + } + if (!_status.event.isMine()) return; + if (this.classList.contains("selectable") == false) return; + if (this.classList.contains("selected")) { + ui.selected.buttons.remove(this); + this.classList.remove("selected"); + if (_status.multitarget || _status.event.complexSelect) { + game.uncheck(); + game.check(); + } + } + else { + this.classList.add("selected"); + ui.selected.buttons.add(this); + } + if (custom && custom.add && custom.add.button) { + custom.add.button(); + } + game.check(); + } + static touchintro() { + var rect = this.getBoundingClientRect(); + ui.click.touchpop(); + ui.click.intro.call(this, { + clientX: rect.left + 18, + clientY: rect.top + 12 + }); + _status.clicked = false; + } + static card() { + delete this._waitingfordrag; + if (_status.dragged) return; + if (_status.clicked) return; + if (ui.intro) return; + _status.clicked = true; + if (this.parentNode && (this.parentNode.classList.contains("judges") || this.parentNode.classList.contains("marks"))) { + var rect = this.getBoundingClientRect(); + ui.click.touchpop(); + ui.click.intro.call(this, { + clientX: rect.left + 18, + clientY: rect.top + 12 + }); + _status.clicked = false; + return; + } + var custom = _status.event.custom; + if (custom && custom.replace.card) { + custom.replace.card(this); + return; + } + if (this.classList.contains("selectable") == false) return; + if (this.classList.contains("selected")) { + ui.selected.cards.remove(this); + if (_status.multitarget || _status.event.complexSelect) { + game.uncheck(); + game.check(); + } + else { + this.classList.remove("selected"); + this.updateTransform(); + } + } + else { + ui.selected.cards.add(this); + this.classList.add("selected"); + this.updateTransform(true); + } + if (game.chess && get.config("show_range") && !_status.event.skill && this.classList.contains("selected") && + _status.event.isMine() && _status.event.name == "chooseToUse") { + var player = _status.event.player; + var range = get.info(this).range; + if (range) { + if (typeof range.attack === "number") { + player.createRangeShadow(Math.min(8, player.getAttackRange(true) + range.attack - 1)); + } + else if (typeof range.global === "number") { + player.createRangeShadow(Math.min(8, player.getGlobalFrom() + range.global)); + } + } + } + if (custom.add.card) { + custom.add.card(); + } + game.check(); + + if (lib.config.popequip && get.is.phoneLayout() && + arguments[0] != "popequip" && ui.arena && ui.arena.classList.contains("selecting") && + this.parentNode && this.parentNode.classList.contains("popequip")) { + var rect = this.getBoundingClientRect(); + ui.click.touchpop(); + ui.click.intro.call(this.parentNode, { + clientX: rect.left + 18, + clientY: rect.top + 12 + }); + } + } + static avatar() { + if (!lib.config.doubleclick_intro) return; + if (this.parentNode.isUnseen(0)) return; + if (!lib.character[this.parentNode.name]) return; + if (!ui.menuContainer) return; + var avatar = this; + var player = this.parentNode; + if (!game.players.contains(player) && !game.dead.contains(player)) return; + if (!this._doubleClicking) { + this._doubleClicking = true; + setTimeout(function () { + avatar._doubleClicking = false; + }, 500); + return; + } + // ui.click.skin(this,player.name); + game.pause2(); + ui.click.charactercard(player.name1 || player.name, null, null, true, this); + } + static avatar2() { + if (!lib.config.doubleclick_intro) return; + if (this.parentNode.classList.contains("unseen2")) return; + if (!lib.character[this.parentNode.name2]) return; + if (!ui.menuContainer) return; + var avatar = this; + var player = this.parentNode; + if (!game.players.contains(player) && !game.dead.contains(player)) return; + if (!this._doubleClicking) { + this._doubleClicking = true; + setTimeout(function () { + avatar._doubleClicking = false; + }, 500); + return; + } + // ui.click.skin(this,player.name2); + game.pause2(); + ui.click.charactercard(player.name2, null, null, true, this); + } + static connectroom(e) { + if (_status.dragged) return; + if (_status.clicked) return; + if (ui.intro) return; + if (this.roomfull) { + alert("房间已满"); + } + else if (this.roomgaming && !game.onlineID) { + if (this.config && this.config.observe) { + alert("房间暂时不可旁观"); + } + else { + alert("房间不允许旁观"); + } + } + else if (!this.roomempty && this.version != lib.versionOL) { + if (this.version > lib.versionOL) { + alert("加入失败:你的游戏版本过低"); + } + else { + alert("加入失败:房主的游戏版本过低"); + } + } + else { + if (!_status.enteringroom) { + _status.enteringroom = true; + _status.enteringroomserver = this.serving; + game.send("server", "enter", this.key, get.connectNickname(), lib.config.connect_avatar); + } + } + } + static player() { + return ui.click.target.apply(this, arguments); + } + static target(e) { + if (_status.dragged) return; + if (_status.clicked) return; + if (ui.intro) return; + if (this.classList.contains("connect")) { + if (game.online) { + if (game.onlinezhu) { + if (!this.playerid && game.connectPlayers) { + if (lib.configOL.mode == "versus" || lib.configOL.mode == "doudizhu") return; + if (lib.configOL.mode == "identity" && lib.configOL.identity_mode == "zhong") return; + if (!this.classList.contains("unselectable2") && lib.configOL.number <= 2) return; + this.classList.toggle("unselectable2") + if (this.classList.contains("unselectable2")) { + lib.configOL.number--; + } + else { + lib.configOL.number++; + } + game.send("changeNumConfig", lib.configOL.number, + game.connectPlayers.indexOf(this), this.classList.contains("unselectable2")); + } + } + return; + } + if (this.playerid) { + if (this.ws) { + if (confirm("是否踢出" + this.nickname + "?")) { + var id = get.id(); + this.ws.send(function (id) { + if (game.ws) { + game.ws.close(); + game.saveConfig("reconnect_info"); + game.saveConfig("banned_info", id); + } + }, id); + lib.node.banned.push(id); + } + } + } + else { + if (lib.configOL.mode == "versus" || lib.configOL.mode == "doudizhu" || lib.configOL.mode == "single") return; + if (lib.configOL.mode == "identity" && (lib.configOL.identity_mode == "zhong" || lib.configOL.identity_mode == "purple")) return; + if (!this.classList.contains("unselectable2") && lib.configOL.number <= 2) return; + this.classList.toggle("unselectable2") + if (this.classList.contains("unselectable2")) { + lib.configOL.number--; + } + else { + lib.configOL.number++; + } + game.send("server", "config", lib.configOL); + game.updateWaiting(); + } + return; + } + _status.clicked = true; + var custom = _status.event.custom; + if (custom && custom.replace.target) { + custom.replace.target(this, e); + return; + } + if (this.classList.contains("selectable") == false) return; + this.unprompt(); + if (this.classList.contains("selected")) { + ui.selected.targets.remove(this); + if (_status.multitarget || _status.event.complexSelect) { + game.uncheck(); + game.check(); + } + else { + this.classList.remove("selected"); + } + } + else { + ui.selected.targets.add(this); + if (_status.event.name == "chooseTarget" || _status.event.name == "chooseToUse" || _status.event.name == "chooseCardTarget") { + var targetprompt = null; + if (_status.event.targetprompt) { + targetprompt = _status.event.targetprompt; + } + else if (_status.event.skill && !get.info(_status.event.skill).viewAs) { + targetprompt = get.info(_status.event.skill).targetprompt; + } + else if (_status.event.name == "chooseToUse") { + var currentcard = get.card(); + if (currentcard) { + targetprompt = get.info(currentcard).targetprompt; + } + } + if (targetprompt) { + if (Array.isArray(targetprompt)) { + targetprompt = targetprompt[Math.min(targetprompt.length - 1, ui.selected.targets.indexOf(this))]; + } + else if (typeof targetprompt == "function") { + targetprompt = targetprompt(this); + } + if (targetprompt && typeof targetprompt == "string") { + this.prompt(targetprompt); + } + } + } + this.classList.add("selected"); + } + if (custom.add.target) { + custom.add.target(); + } + game.check(); + } + static control2() { + if (this.childNodes.length == 1 && !this._doubleclick) { + ui.click.control.call(this.firstChild); + } + } + static control() { + if (_status.dragged) return; + if (ui.control.classList.contains("hidden")) return; + var node = this.parentNode; + if (node) { + if (node._doubleclick) { + return; + } + else { + node._doubleclick = true; + setTimeout(function () { + node._doubleclick = false; + }, 500); + } + if (node.classList.contains("hidden")) return; + if (node.classList.contains("removing")) return; + if (node.classList.contains("disabled")) return; + } + if (ui.intro) { + ui.intro.close(); + delete ui.intro; + } + _status.clicked = true; + if (this.parentNode.custom) { + this.parentNode.custom(this.link, this); + return; + } + if (this.link == "ok") { + ui.click.ok(this); + } + else if (this.link == "cancel") { + ui.click.cancel(this); + } + else { + _status.event.result = { + buttons: ui.selected.buttons.slice(0), + cards: ui.selected.cards.slice(0), + targets: ui.selected.targets.slice(0), + control: this.link, + links: get.links(ui.selected.buttons) + }; + if (this.parentNode.close != false) { + game.uncheck(); + this.parentNode.close(); + } + game.resume(); + } + } + static dialogcontrol() { + _status.event.result = { + buttons: ui.selected.buttons.slice(0), + cards: ui.selected.cards.slice(0), + targets: ui.selected.targets.slice(0), + control: this.link, + links: get.links(ui.selected.buttons) + }; + game.resume(); + } + static skill(skill) { + var info = get.info(skill); + var event = _status.event; + event.backup(skill); + if (info.filterCard && info.discard != false && info.lose != false && !info.viewAs) { + var cards = event.player.getCards(event.position); + for (var i = 0; i < cards.length; i++) { + if (!lib.filter.cardDiscardable(cards[i], event.player)) { + cards[i].uncheck("useSkill"); + } + } + } + if (typeof event.skillDialog == "object") { + event.skillDialog.close(); + } + if (event.isMine()) { + event.skillDialog = true; + } + game.uncheck(); + game.check(); + if (event.skillDialog === true) { + var str = get.translation(skill); + if (info.prompt) { + var str2; + if (typeof info.prompt == "function") { + str2 = info.prompt(event); + } + else { + str2 = info.prompt; + } + event.skillDialog = ui.create.dialog(str, `
      ${str2}
      `); + if (info.longprompt) { + event.skillDialog.forcebutton = true; + ui.update(); + } + } + else if (info.promptfunc) { + event.skillDialog = ui.create.dialog(str, `
      ${info.promptfunc(event, event.player)}
      `); + } + else if (lib.dynamicTranslate[skill]) { + event.skillDialog = ui.create.dialog(str, `
      ${lib.dynamicTranslate[skill](event.player, skill)}
      `); + } + else if (lib.translate[skill + "_info"]) { + event.skillDialog = ui.create.dialog(str, `
      ${lib.translate[`${skill}_info`]}
      `); + } + } + } + static ok(node) { + const gameEvent = get.event(), custom = gameEvent.custom, replaceConfirm = custom.replace.confirm; + if (replaceConfirm) { + replaceConfirm(true); + return; + } + const result = gameEvent.result = { + buttons: ui.selected.buttons.slice(), + cards: ui.selected.cards.slice(), + targets: ui.selected.targets.slice(), + confirm: "ok", + bool: true, + links: get.links(ui.selected.buttons) + }; + if (node) node.parentNode.close(); + const skill = gameEvent.skill; + if (skill) { + result.skill = skill; + const info = get.info(skill); + if (info && info.direct && !info.clearTime) { + result._noHidingTimer = true; + } + const skillInformation = get.info(gameEvent.skill), viewAs = skillInformation.viewAs; + if (typeof viewAs == "function") { + const viewedAs = viewAs(result.cards, gameEvent.player); + if (viewedAs) result.card = get.autoViewAs(viewedAs); + } + else if (viewAs) result.card = get.autoViewAs(viewAs); + const resultCard = result.card; + if (resultCard) { + const cards = result.cards; + if (cards.length == 1) { + const firstCard = cards[0]; + if (!resultCard.suit) resultCard.suit = get.suit(firstCard); + if (!resultCard.number) resultCard.number = get.number(firstCard); + } + } + const skillDialog = gameEvent.skillDialog; + if (skillDialog && get.objtype(skillDialog) == "div") skillDialog.close(); + gameEvent.player.getCards("hej").forEach(card => card.recheck("useSkill")); + gameEvent.restore(); + } + else if (["chooseToUse", "chooseToRespond"].includes(gameEvent.name)) result.card = get.autoViewAs(result.cards[0]); + if (ui.skills) ui.skills.close(); + if (ui.skills2) ui.skills2.close(); + if (ui.skills3) ui.skills3.close(); + game.uncheck(); + const addConfirm = custom.add.confirm; + if (addConfirm) addConfirm(true); + game.resume(); + } + static cancel(node) { + var event = _status.event; + if (event.custom.replace.confirm) { + event.custom.replace.confirm(false); return; + } + if (event.skill && !event.norestore) { + if (event.skillDialog && get.objtype(event.skillDialog) == "div") { + event.skillDialog.close(); + } + if (typeof event.dialog == "string" && event.isMine()) { + event.dialog = ui.create.dialog(event.dialog); + } + if (_status.event.type == "phase" && ui.confirm) { + ui.confirm.classList.add("removing"); + } + // ui.control.animate("nozoom",100); + event.restore(); + var cards = event.player.getCards("hej"); + for (var i = 0; i < cards.length; i++) { + cards[i].recheck("useSkill"); + } + game.uncheck(); + game.check(); + return; + } + event.result = { + confirm: "cancel", + bool: false + }; + if (node) { + node.parentNode.close(); + } + if (ui.skills) ui.skills.close(); + if (ui.skills2) ui.skills2.close(); + if (ui.skills3) ui.skills3.close(); + game.uncheck(); + if (event.custom.add.confirm) { + event.custom.add.confirm(true); + } + game.resume(); + } + static logv(e) { + if (_status.currentlogv) { + if (_status.currentlogv == this) return; + if (_status.logvtimeout) { + clearTimeout(_status.logvtimeout); + } + var that = this; + _status.logvtimeout = setTimeout(function () { + if (!_status.currentlogv) { + _status.currentlogv = that; + ui.click.intro.call(that, e); + } + }, 200); + this.logvtimeout = _status.logvtimeout; + } + else { + _status.currentlogv = this; + ui.click.intro.call(this, e); + } + } + static logvleave() { + if (_status.currentlogv == this) { + setTimeout(function () { + delete _status.currentlogv; + }, 150); + } + if (this.logvtimeout) { + clearTimeout(this.logvtimeout); + if (_status.logvtimeout == this.logvtimeout) { + delete _status.logvtimeout; + } + delete this.logvtimeout; + } + } + static charactercard(name, sourcenode, noedit, resume, avatar) { + if (_status.dragged) return; + if (lib.config.theme != "simple") { + ui.window.classList.add("shortcutpaused"); + ui.menuContainer.classList.add("forceopaque"); + } + else { + ui.window.classList.add("systempaused"); + ui.menuContainer.classList.add("transparent2"); + } + if (lib.config.blur_ui) { + ui.arena.classList.add("blur"); + ui.system.classList.add("blur"); + ui.menuContainer.classList.add("blur"); + } + var layer = ui.create.div(".popup-container"); + var clicklayer = function (e) { + if (_status.touchpopping) return; + if (_status.dragged) return; + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + ui.menuContainer.classList.remove("forceopaque"); + ui.menuContainer.classList.remove("transparent2"); + ui.arena.classList.remove("blur"); + ui.system.classList.remove("blur"); + ui.menuContainer.classList.remove("blur"); + this.delete(); + e.stopPropagation(); + if (resume) game.resume2(); + return false; + } + var uiintro = ui.create.div(".menubg.charactercard", layer); + var playerbg = ui.create.div(".menubutton.large.ava", uiintro); + var bg = ui.create.div(".avatar", playerbg, function () { + if (changeskinfunc) { + changeskinfunc(); + } + }).setBackground(name, "character"); + var changeskinfunc = null; + var nameskin = name; + var nameskin2 = name; + var gzbool = false; + if (nameskin.startsWith("gz_shibing")) { + nameskin = nameskin.slice(3, 11); + } + else if (nameskin.startsWith("gz_")) { + nameskin = nameskin.slice(3); + gzbool = true; + } + var changeskin = function () { + var node = ui.create.div(".changeskin", "可换肤", playerbg); + var avatars = ui.create.div(".avatars", playerbg); + changeskinfunc = function () { + playerbg.classList.add("scroll"); + if (node._created) { + return; + } + node._created = true; + var createButtons = function (num) { + if (!num) return; + if (num >= 4) { + avatars.classList.add("scroll"); + if (lib.config.touchscreen) { + lib.setScroll(avatars); + } + } + for (var i = 0; i <= num; i++) { + var button = ui.create.div(avatars, function () { + playerbg.classList.remove("scroll"); + if (this._link) { + lib.config.skin[nameskin] = this._link; + bg.style.backgroundImage = this.style.backgroundImage; + if (sourcenode) sourcenode.style.backgroundImage = this.style.backgroundImage; + if (avatar) avatar.style.backgroundImage = this.style.backgroundImage; + game.saveConfig("skin", lib.config.skin); + } + else { + delete lib.config.skin[nameskin]; + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) { + bg.setBackground(nameskin2, "character"); + if (sourcenode) sourcenode.setBackground(nameskin2, "character"); + if (avatar) avatar.setBackground(nameskin2, "character"); + } + else { + bg.setBackground(nameskin, "character"); + if (sourcenode) sourcenode.setBackground(nameskin, "character"); + if (avatar) avatar.setBackground(nameskin, "character"); + } + game.saveConfig("skin", lib.config.skin); + } + }); + button._link = i; + if (i) { + button.setBackgroundImage("image/skin/" + nameskin + "/" + i + ".jpg"); + } + else { + if (gzbool && lib.character[nameskin2][4].contains("gzskin") && lib.config.mode_config.guozhan.guozhanSkin) button.setBackground(nameskin2, "character", "noskin"); + else button.setBackground(nameskin, "character", "noskin"); + } + } + }; + var num = 1; + var loadImage = function () { + var img = new Image(); + img.onload = function () { + num++; + loadImage(); + } + img.onerror = function () { + num--; + createButtons(num); + } + img.src = lib.assetURL + "image/skin/" + nameskin + "/" + num + ".jpg"; + } + if (lib.config.change_skin) { + loadImage(); + } + else { + createButtons(lib.skin[nameskin]); + } + }; + }; + if (lib.config.change_skin) { + var img = new Image(); + img.onload = changeskin; + img.src = lib.assetURL + "image/skin/" + nameskin + "/1.jpg"; + } + else if (lib.config.debug && lib.skin[nameskin]) { + changeskin(); + } + var ban = ui.create.div(".menubutton.large.ban.character", uiintro, "禁用", function (e) { + if (this.classList.contains("unselectable")) return; + if (typeof noedit == "string") { + this.classList.toggle("active"); + var bannedname = noedit + "_banned"; + if (!lib.config[bannedname]) { + lib.config[bannedname] = []; + } + if (this.classList.contains("active")) { + lib.config[bannedname].add(name); + } + else { + lib.config[bannedname].remove(name); + } + game.saveConfig(bannedname, lib.config[bannedname]); + ban.updateBanned(); + } + else { + ui.click.touchpop(); + ui.click.intro.call(this, e); + _status.clicked = true; + } + }); + ban.link = name; + ban._banning = "offline"; + ban.updateBanned = function () { + if (noedit === true) return; + if (lib.config[get.mode() + "_banned"] && lib.config[get.mode() + "_banned"].contains(name)) { + ban.classList.add("active"); + } + else { + ban.classList.remove("active"); + } + if (sourcenode && sourcenode.updateBanned) { + sourcenode.updateBanned(); + } + }; + ban.updateBanned(); + var fav = ui.create.div(".menubutton.large.fav", uiintro, "收藏", function () { + if (this.classList.contains("unselectable")) return; + this.classList.toggle("active"); + if (this.classList.contains("active")) { + lib.config.favouriteCharacter.add(name); + } + else { + lib.config.favouriteCharacter.remove(name); + } + game.saveConfig("favouriteCharacter", lib.config.favouriteCharacter); + }); + if (noedit === true) { + fav.classList.add("unselectable"); + ban.classList.add("unselectable"); + } + else if (lib.config.favouriteCharacter.contains(name)) { + fav.classList.add("active"); + } + + // 样式二 + if (lib.config.show_characternamepinyin == "showPinyin2" || lib.config.show_skillnamepinyin == "showPinyin2" || lib.config.show_characternamepinyin == "showCodeIdentifier2" || lib.config.show_skillnamepinyin == "showCodeIdentifier2") { + var intro = ui.create.div(".characterintro", get.characterIntro(name), uiintro); + if (lib.config.show_characternamepinyin == "showPinyin2" || lib.config.show_characternamepinyin == "showCodeIdentifier2") { + var charactername = get.rawName2(name); + var characterpinyin = lib.config.show_characternamepinyin == "showCodeIdentifier2" ? name : get.pinyin(charactername); + var nameinfo = get.character(name); + var charactersex = get.translation(nameinfo[0]); + const charactergroups = get.is.double(name, true); + let charactergroup; + if (charactergroups) charactergroup = charactergroups.map(i => get.translation(i)).join("/") + else charactergroup = get.translation(nameinfo[1]); + var characterhp = nameinfo[2]; + var characterintroinfo = get.characterIntro(name); + var spacemark = " | "; + if (charactername.length > 3) spacemark = ` | `; + intro.innerHTML = `${charactername}[${characterpinyin}]${spacemark}${charactersex}${spacemark}${charactergroup}${spacemark}${characterhp}
      ${characterintroinfo}`; + } + var intro2 = ui.create.div(".characterintro.intro2", uiintro); + var list = get.character(name, 3) || []; + var skills = ui.create.div(".characterskill", uiintro); + if (lib.config.touchscreen) { + lib.setScroll(intro); + lib.setScroll(intro2); + lib.setScroll(skills); + } + + if (lib.config.mousewheel) { + skills.onmousewheel = ui.click.mousewheel; + } + var clickSkill = function (e) { + while (intro2.firstChild) { + intro2.removeChild(intro2.lastChild); + } + var current = this.parentNode.querySelector(".active"); + if (current) { + current.classList.remove("active"); + } + this.classList.add("active"); + var skillname = get.translation(this.link); + var skilltranslationinfo = get.skillInfoTranslation(this.link); + if ((lib.config.show_skillnamepinyin == "showPinyin2" || lib.config.show_skillnamepinyin == "showCodeIdentifier2") && skillname != "阵亡") { + var skillpinyin = lib.config.show_skillnamepinyin == "showCodeIdentifier2" ? this.link : get.pinyin(skillname); + intro2.innerHTML = `${skillname}[${skillpinyin}] ${skilltranslationinfo}`; + } else { + intro2.innerHTML = `${skillname}${skilltranslationinfo}`; + } + var info = get.info(this.link); + var skill = this.link; + var playername = this.linkname; + var skillnode = this; + if (info.derivation) { + var derivation = info.derivation; + if (typeof derivation == "string") { + derivation = [derivation]; + } + for (var i = 0; i < derivation.length; i++) { + var derivationname = get.translation(derivation[i]); + var derivationtranslationinfo = get.skillInfoTranslation(derivation[i]); + if ((lib.config.show_skillnamepinyin == "showPinyin2" || lib.config.show_skillnamepinyin == "showCodeIdentifier2") && derivationname.length <= 5 && derivation[i].indexOf("_faq") == -1) { + var derivationpinyin = lib.config.show_skillnamepinyin == "showCodeIdentifier2" ? derivation[i] : get.pinyin(derivationname); + intro2.innerHTML += `

      ${derivationname}[${derivationpinyin}] ${derivationtranslationinfo}`; + } else { + intro2.innerHTML += `

      ${derivationname}${derivationtranslationinfo}`; + } + } + } + if (info.alter) { + intro2.innerHTML += `

      `; + var skillversionnode = intro2.querySelector(".hrefnode.skillversion"); + if (lib.config.vintageSkills.contains(skill)) { + skillversionnode.innerHTML = "切换至新版"; + } + else { + skillversionnode.innerHTML = "切换至旧版"; + } + skillversionnode.listen(function () { + if (lib.config.vintageSkills.contains(skill)) { + lib.config.vintageSkills.remove(skill); + lib.translate[skill + "_info"] = lib.translate[skill + "_info_alter"]; + } + else { + lib.config.vintageSkills.push(skill); + lib.translate[skill + "_info"] = lib.translate[skill + "_info_origin"]; + } + game.saveConfig("vintageSkills", lib.config.vintageSkills); + clickSkill.call(skillnode, "init"); + }); + } + // if(e!=="init") game.trySkillAudio(this.link,playername); + // 有bug,先用旧版 + if (lib.config.background_speak && e !== "init") { + var audioname = this.link; + if (info.audioname2 && info.audioname2[playername]) { + audioname = info.audioname2[playername]; + info = lib.skill[audioname]; + } + var audioinfo = info.audio; + var that = this; + var getIndex = function (i) { + if (typeof that.audioindex != "number") { + that.audioindex = i; + } + that.audioindex++; + if (that.audioindex > i) { + that.audioindex = 1; + } + return that.audioindex; + }; + if (typeof audioinfo == "string") { + if (audioinfo.indexOf("ext:") == 0) { + audioinfo = audioinfo.split(":"); + if (audioinfo.length == 3) { + if (audioinfo[2] == "true") { + game.playAudio("..", "extension", audioinfo[1], audioname); + } + else { + audioinfo[2] = parseInt(audioinfo[2]); + if (audioinfo[2]) { + game.playAudio("..", "extension", audioinfo[1], audioname + getIndex(audioinfo[2])); + } + } + } + return; + } + else { + audioname = audioinfo; + if (lib.skill[audioinfo]) { + audioinfo = lib.skill[audioinfo].audio; + } + } + } + else if (Array.isArray(audioinfo)) { + audioname = audioinfo[0]; + audioinfo = audioinfo[1]; + } + if (typeof audioinfo == "number") { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playAudio("skill", audioname + getIndex(audioinfo)); + } + else if (typeof audioinfo == "object" && "type" in audioinfo && audioinfo.type == "direct" && "files" in audioinfo) { + let audioFiles = audioinfo.files; + if (typeof audioFiles == "object") { + if (!Array.isArray(audioFiles) && playername && playername in audioFiles) audioFiles = audioFiles[playername]; + if (Array.isArray(audioFiles)) { + const length = audioFiles.length; + game.playAudio(audioFiles[getIndex(length) - 1]); + } + } + } + else if (audioinfo) { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playAudio("skill", audioname); + } + else if (true && info.audio !== false) { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playSkillAudio(audioname, getIndex(2)); + } + } + } + } else { + // 样式一 + const introduction = ui.create.div(".characterintro", uiintro), showCharacterNamePinyin = lib.config.show_characternamepinyin; + if (showCharacterNamePinyin != "doNotShow") { + const characterIntroTable = ui.create.div(".character-intro-table", introduction), span = document.createElement("span"); + span.style.fontWeight = "bold"; + const nameInfo = get.character(name), exInfo = nameInfo[4], characterName = exInfo && exInfo.includes("ruby") ? lib.translate[name] : get.rawName2(name); + span.innerHTML = characterName; + const ruby = document.createElement("ruby"); + ruby.appendChild(span); + const leftParenthesisRP = document.createElement("rp"); + leftParenthesisRP.textContent = "("; + ruby.appendChild(leftParenthesisRP); + const rt = document.createElement("rt"); + rt.innerHTML = showCharacterNamePinyin == "showCodeIdentifier" ? name : lib.translate[`${name}_rt`] || get.pinyin(characterName).join(" "); + ruby.appendChild(rt); + const rightParenthesisRP = document.createElement("rp"); + rightParenthesisRP.textContent = ")"; + ruby.appendChild(rightParenthesisRP); + characterIntroTable.appendChild(ruby); + const characterSexDiv = ui.create.div(".character-sex", characterIntroTable), exInfoSex = exInfo && exInfo.find(value => value.startsWith("sex:")), characterSex = exInfoSex ? exInfoSex.split(":").pop() : nameInfo[0]; + new Promise((resolve, reject) => { + const imageName = `sex_${characterSex}`, information = lib.card[imageName]; + if (!information) { + resolve(`${lib.assetURL}image/card/${imageName}.png`) + return; + } + const image = information.image; + if (!image) resolve(`${lib.assetURL}image/card/${imageName}.png`); + else if (image.startsWith("db:")) game.getDB("image", image.slice(3)).then(resolve, reject); + else if (image.startsWith("ext:")) resolve(`${lib.assetURL}${image.replace(/^ext:/, "extension/")}`); + else resolve(`${lib.assetURL}${image}`); + }).then(source => new Promise((resolve, reject) => { + const image = new Image(); + image.onload = () => resolve(image); + image.onerror = reject; + image.src = source; + })).then(image => characterSexDiv.appendChild(image)).catch(() => characterSexDiv.innerHTML = get.translation(characterSex)); + const characterGroupDiv = ui.create.div(".character-group", characterIntroTable), characterGroups = get.is.double(name, true); + if (characterGroups) Promise.all(characterGroups.map(characterGroup => new Promise((resolve, reject) => { + const imageName = `group_${characterGroup}`, information = lib.card[imageName]; + if (!information) resolve(`${lib.assetURL}image/card/${imageName}.png`); + const image = information.image; + if (!image) resolve(`${lib.assetURL}image/card/${imageName}.png`); + else if (image.startsWith("db:")) game.getDB("image", image.slice(3)).then(resolve, reject); + else if (image.startsWith("ext:")) resolve(`${lib.assetURL}${image.replace(/^ext:/, "extension/")}`); + else resolve(`${lib.assetURL}${image}`); + }).then(source => new Promise((resolve, reject) => { + const image = new Image(); + image.onload = () => resolve(image); + image.onerror = reject; + image.src = source; + })))).then(images => { + let documentFragment = document.createDocumentFragment(); + images.forEach(documentFragment.appendChild, documentFragment); + characterGroupDiv.appendChild(documentFragment); + }).catch(() => characterGroupDiv.innerHTML = characterGroups.map(characterGroup => get.translation(characterGroup)).join("/")); + else { + const characterGroup = nameInfo[1]; + new Promise((resolve, reject) => { + const imageName = `group_${characterGroup}`, information = lib.card[imageName]; + if (!information) resolve(`${lib.assetURL}image/card/${imageName}.png`); + const image = information.image; + if (!image) resolve(`${lib.assetURL}image/card/${imageName}.png`); + else if (image.startsWith("db:")) game.getDB("image", image.slice(3)).then(resolve, reject); + else if (image.startsWith("ext:")) resolve(`${lib.assetURL}${image.replace(/^ext:/, "extension/")}`); + else resolve(`${lib.assetURL}${image}`); + }).then(source => new Promise((resolve, reject) => { + const image = new Image(); + image.onload = () => resolve(image); + image.onerror = reject; + image.src = source; + })).then(image => characterGroupDiv.appendChild(image)).catch(() => characterGroupDiv.innerHTML = get.translation(characterGroup)); + } + const hpDiv = ui.create.div(".hp", characterIntroTable), nameInfoHP = nameInfo[2], infoHP = get.infoHp(nameInfoHP); + hpDiv.dataset.condition = infoHP < 4 ? "mid" : "high"; + ui.create.div(hpDiv); + const hpTextDiv = ui.create.div(".text", hpDiv), infoMaxHP = get.infoMaxHp(nameInfoHP); + hpTextDiv.innerHTML = infoHP == infoMaxHP ? `×${infoHP}` : `×${infoHP}/${infoMaxHP}`; + const infoShield = get.infoHujia(nameInfoHP); + if (infoShield) { + ui.create.div(".shield", hpDiv); + const shieldTextDiv = ui.create.div(".text", hpDiv); + shieldTextDiv.innerHTML = `×${infoShield}`; + } + introduction.appendChild(document.createElement("hr")); + } + const htmlParser = document.createElement("body"); + htmlParser.innerHTML = get.characterIntro(name); + Array.from(htmlParser.childNodes).forEach(value => introduction.appendChild(value)); + const introduction2 = ui.create.div(".characterintro.intro2", uiintro); + var list = get.character(name, 3) || []; + var skills = ui.create.div(".characterskill", uiintro); + if (lib.config.touchscreen) { + lib.setScroll(introduction); + lib.setScroll(introduction2); + lib.setScroll(skills); + } + + if (lib.config.mousewheel) { + skills.onmousewheel = ui.click.mousewheel; + } + var clickSkill = function (e) { + while (introduction2.firstChild) { + introduction2.removeChild(introduction2.lastChild); + } + var current = this.parentNode.querySelector(".active"); + if (current) { + current.classList.remove("active"); + } + this.classList.add("active"); + const skillNameSpan = document.createElement("span"), skillNameSpanStyle = skillNameSpan.style; + skillNameSpanStyle.fontWeight = "bold"; + const link = this.link, skillName = get.translation(link); + skillNameSpan.innerHTML = skillName; + const showSkillNamePinyin = lib.config.show_skillnamepinyin; + if (showSkillNamePinyin != "doNotShow" && skillName != "阵亡") { + const ruby = document.createElement("ruby"); + ruby.appendChild(skillNameSpan); + const leftParenthesisRP = document.createElement("rp"); + leftParenthesisRP.textContent = "("; + ruby.appendChild(leftParenthesisRP); + const rt = document.createElement("rt"); + rt.innerHTML = showSkillNamePinyin == "showCodeIdentifier" ? link : lib.translate[`${link}_rt`] || get.pinyin(skillName).join(" "); + ruby.appendChild(rt); + const rightParenthesisRP = document.createElement("rp"); + rightParenthesisRP.textContent = ")"; + ruby.appendChild(rightParenthesisRP); + const div = ui.create.div(introduction2); + div.style.marginRight = "5px"; + div.appendChild(ruby); + } + else { + skillNameSpanStyle.marginRight = "5px"; + introduction2.appendChild(skillNameSpan); + } + htmlParser.innerHTML = get.skillInfoTranslation(this.link); + Array.from(htmlParser.childNodes).forEach(childNode => introduction2.appendChild(childNode)); + var info = get.info(this.link); + var skill = this.link; + var playername = this.linkname; + var skillnode = this; + let derivations = info.derivation; + if (derivations) { + if (typeof derivations == "string") derivations = [derivations]; + derivations.forEach(derivation => { + introduction2.appendChild(document.createElement("br")); + introduction2.appendChild(document.createElement("br")); + const derivationNameSpan = document.createElement("span"), derivationNameSpanStyle = derivationNameSpan.style; + derivationNameSpanStyle.fontWeight = "bold"; + const derivationName = get.translation(derivation); + derivationNameSpan.innerHTML = derivationName; + if (showSkillNamePinyin != "doNotShow" && derivationName.length <= 5 && derivation.indexOf("_faq") == -1) { + const ruby = document.createElement("ruby"); + ruby.appendChild(derivationNameSpan); + const leftParenthesisRP = document.createElement("rp"); + leftParenthesisRP.textContent = "("; + ruby.appendChild(leftParenthesisRP); + const rt = document.createElement("rt"); + rt.innerHTML = showSkillNamePinyin == "showCodeIdentifier" ? derivation : lib.translate[`${derivation}_rt`] || get.pinyin(derivationName).join(" "); + ruby.appendChild(rt); + const rightParenthesisRP = document.createElement("rp"); + rightParenthesisRP.textContent = ")"; + ruby.appendChild(rightParenthesisRP); + const div = ui.create.div(introduction2); + div.style.marginRight = "5px"; + div.appendChild(ruby); + } + else { + derivationNameSpanStyle.marginRight = "5px"; + introduction2.appendChild(derivationNameSpan); + } + htmlParser.innerHTML = get.skillInfoTranslation(derivation); + Array.from(htmlParser.childNodes).forEach(childNode => introduction2.appendChild(childNode)); + }); + } + if (info.alter) { + introduction2.appendChild(document.createElement("br")); + introduction2.appendChild(document.createElement("br")); + ui.create.div(".hrefnode.skillversion", introduction2); + var skillversionnode = introduction2.querySelector(".hrefnode.skillversion"); + if (lib.config.vintageSkills.contains(skill)) { + skillversionnode.innerHTML = "切换至新版"; + } + else { + skillversionnode.innerHTML = "切换至旧版"; + } + skillversionnode.listen(function () { + if (lib.config.vintageSkills.contains(skill)) { + lib.config.vintageSkills.remove(skill); + lib.translate[skill + "_info"] = lib.translate[skill + "_info_alter"]; + } + else { + lib.config.vintageSkills.push(skill); + lib.translate[skill + "_info"] = lib.translate[skill + "_info_origin"]; + } + game.saveConfig("vintageSkills", lib.config.vintageSkills); + clickSkill.call(skillnode, "init"); + }); + } + // if(e!=="init") game.trySkillAudio(this.link,playername); + // 有bug,先用旧版 + if (lib.config.background_speak && e !== "init") { + var audioname = this.link; + if (info.audioname2 && info.audioname2[playername]) { + audioname = info.audioname2[playername]; + info = lib.skill[audioname]; + } + var audioinfo = info.audio; + var that = this; + var getIndex = function (i) { + if (typeof that.audioindex != "number") { + that.audioindex = i; + } + that.audioindex++; + if (that.audioindex > i) { + that.audioindex = 1; + } + return that.audioindex; + }; + if (typeof audioinfo == "string") { + if (audioinfo.indexOf("ext:") == 0) { + audioinfo = audioinfo.split(":"); + if (audioinfo.length == 3) { + if (audioinfo[2] == "true") { + game.playAudio("..", "extension", audioinfo[1], audioname); + } + else { + audioinfo[2] = parseInt(audioinfo[2]); + if (audioinfo[2]) { + game.playAudio("..", "extension", audioinfo[1], audioname + getIndex(audioinfo[2])); + } + } + } + return; + } + else { + audioname = audioinfo; + if (lib.skill[audioinfo]) { + audioinfo = lib.skill[audioinfo].audio; + } + } + } + else if (Array.isArray(audioinfo)) { + audioname = audioinfo[0]; + audioinfo = audioinfo[1]; + } + if (typeof audioinfo == "number") { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playAudio("skill", audioname + getIndex(audioinfo)); + } + else if (typeof audioinfo == "object" && "type" in audioinfo && audioinfo.type == "direct" && "files" in audioinfo) { + let audioFiles = audioinfo.files; + if (typeof audioFiles == "object") { + if (!Array.isArray(audioFiles) && playername && playername in audioFiles) audioFiles = audioFiles[playername]; + if (Array.isArray(audioFiles)) { + const length = audioFiles.length; + game.playAudio(audioFiles[getIndex(length) - 1]); + } + } + } + else if (audioinfo) { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playAudio("skill", audioname); + } + else if (true && info.audio !== false) { + if (Array.isArray(info.audioname) && info.audioname.contains(playername)) audioname = audioname + "_" + playername; + game.playSkillAudio(audioname, getIndex(2)); + } + } + } + } + + var initskill = false; + for (var i = 0; i < list.length; i++) { + if (!get.info(list[i]) || get.info(list[i]).nopop) continue; + if (!lib.translate[list[i]] || !lib.translate[list[i] + "_info"]) continue; + var skilltrans = get.translation(list[i]); + if (skilltrans.startsWith(" ")) { + skilltrans = skilltrans.slice(6); + } + var current = ui.create.div(".menubutton.large", skills, clickSkill, skilltrans); + current.link = list[i]; + current.linkname = name; + if (!initskill) { + initskill = true; + clickSkill.call(current, "init"); + } + } + + uiintro.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.touchpop); + layer.addEventListener(lib.config.touchscreen ? "touchend" : "click", clicklayer); + ui.window.appendChild(layer); + } + static intro(e) { + if (_status.dragged) return; + _status.clicked = true; + if (this.classList.contains("player") && !this.name) { + return; + } + if (this.parentNode == ui.historybar) { + if (ui.historybar.style.zIndex == "22") { + if (_status.removePop) { + if (_status.removePop(this) == false) return; + } + else { + return; + } + } + ui.historybar.style.zIndex = 22; + } + var uiintro; + if (this.classList.contains("card") && this.parentNode && + this.parentNode.classList.contains("equips") && get.is.phoneLayout() && + !get.is.mobileMe(this.parentNode.parentNode)) { + uiintro = get.nodeintro(this.parentNode.parentNode, false, e); + } + uiintro = uiintro || get.nodeintro(this, false, e); + if (!uiintro) return; + uiintro.classList.add("popped"); + uiintro.classList.add("static"); + ui.window.appendChild(uiintro); + var layer = ui.create.div(".poplayer", ui.window); + var clicklayer = function (e) { + if (_status.touchpopping) return; + delete ui.throwEmotion; + delete _status.removePop; + uiintro.delete(); + this.remove(); + ui.historybar.style.zIndex = ""; + delete _status.currentlogv; + if (!ui.arena.classList.contains("menupaused") && !uiintro.noresume) game.resume2(); + if (e && e.stopPropagation) e.stopPropagation(); + if (uiintro._onclose) { + uiintro._onclose(); + } + return false; + } + layer.addEventListener(lib.config.touchscreen ? "touchend" : "click", clicklayer); + if (!lib.config.touchscreen) layer.oncontextmenu = clicklayer; + if (this.parentNode == ui.historybar && lib.config.touchscreen) { + var rect = this.getBoundingClientRect(); + e = { clientX: 0, clientY: rect.top + 30 }; + } + lib.placePoppedDialog(uiintro, e); + if (this.parentNode == ui.historybar) { + if (lib.config.show_history == "right") { + uiintro.style.left = (ui.historybar.offsetLeft - 230) + "px"; + } + else { + uiintro.style.left = (ui.historybar.offsetLeft + 60) + "px"; + } + } + uiintro.style.zIndex = 21; + var clickintro = function () { + if (_status.touchpopping) return; + delete _status.removePop; + layer.remove(); + this.delete(); + ui.historybar.style.zIndex = ""; + delete _status.currentlogv; + if (!ui.arena.classList.contains("menupaused") && !uiintro.noresume) game.resume2(); + if (uiintro._onclose) { + uiintro._onclose(); + } + }; + var currentpop = this; + _status.removePop = function (node) { + if (node == currentpop) return false; + layer.remove(); + uiintro.delete(); + delete _status.removePop; + return true; + }; + if (uiintro.clickintro) { + uiintro.listen(function () { + _status.clicked = true; + }); + uiintro._clickintro = clicklayer; + } + else if (!lib.config.touchscreen) { + uiintro.addEventListener("mouseleave", clickintro); + uiintro.addEventListener("click", clickintro); + } + else if (uiintro.touchclose) { + uiintro.listen(clickintro); + } + uiintro._close = clicklayer; + + game.pause2(); + return uiintro; + } + static intro2() { + if (ui.intro) { + ui.intro.close(); + if (ui.intro.source == this) { + delete ui.intro; + ui.control.show(); + game.resume2(); + return; + } + } + } + static auto() { + if (!ui || !ui.auto || ui.auto.classList.contains("hidden") && arguments[0] !== "forced") return; + if (_status.paused2) return; + ui.click.shortcut(false); + if (!_status.auto) { + _status.auto = true; + ui.auto.classList.add("glow"); + ui.arena.classList.add("auto"); + + if (_status.imchoosing && _status.paused) { + if (ui.confirm) ui.confirm.close(); + ui.control.hide(); + if (_status.event.switchToAuto) { + _status.event.switchToAuto(); + } + else { + if (_status.paused && _status.imchoosing) { + game.uncheck(); + _status.event.redo(); + } + } + game.resume(); + } + else if (_status.event.switchToAuto) { + _status.event.switchToAuto(); + } + if (game.online) { + game.send("auto"); + } + else if (_status.connectMode) { + game.broadcastAll(function (player) { + player.setNickname(player.nickname + " - 托管"); + }, game.me); + } + } + else { + if (game.notMe) return; + ui.control.show(); + _status.auto = false; + ui.auto.classList.remove("glow"); + ui.arena.classList.remove("auto"); + + if (game.online) { + game.send("unauto"); + } + else if (_status.connectMode) { + game.broadcastAll(function (player) { + player.setNickname(player.nickname); + }, game.me); + } + } + } + static wuxie() { + if (this.classList.contains("hidden")) return; + this.classList.toggle("glow"); + if (this.classList.contains("glow") && _status.event.type == "wuxie" && + _status.event.isMine() && ui.confirm && _status.imchoosing) { + ui.click.cancel(ui.confirm.lastChild); + } + } + static tempnowuxie() { + if (this.classList.contains("hidden")) return; + this.classList.toggle("glow"); + if (this.classList.contains("glow") && _status.event.type == "wuxie" && + _status.event.isMine() && ui.confirm && _status.imchoosing) { + var triggerevent = _status.event.getTrigger(); + if (triggerevent && this._origin == triggerevent.parent.id) { + if (triggerevent.targets && triggerevent.num == triggerevent.targets.length - 1) { + this.close(); + } + } + ui.click.cancel(ui.confirm.lastChild); + } + } + static pause() { + if (_status.paused2 || _status.pausing || _status.nopause || !ui.pause) return; + if (!_status.video) { + if (ui.pause.classList.contains("hidden")) return; + if (!_status.gameStarted) return; + } + ui.system.hide(); + game.pause2(); + var node = ui.create.pause(); + if (!node) return; + node.animate("start"); + ui.sidebar3.innerHTML = ""; + if (lib.config.show_discardpile) { + for (var i = 0; i < ui.discardPile.childNodes.length; i++) { + var div = ui.create.div(ui.sidebar3); + div.innerHTML = get.translation(ui.discardPile.childNodes[i]); + ui.sidebar3.insertBefore(div, ui.sidebar3.firstChild); + } + } + node.appendChild(ui.sidebar); + node.appendChild(ui.sidebar3); + ui.historybar.classList.add("paused"); + ui.arena.classList.add("paused"); + ui.window.classList.add("touchinfohidden"); + ui.time.hide(); + if (game.onpause) { + game.onpause(); + } + } + static resume(e) { + if (_status.pausing) return; + if (_status.dragged) return; + if (_status.clicked) return; + this.delete(); + ui.system.show(); + ui.time.show(); + ui.historybar.classList.remove("paused"); + ui.arena.classList.remove("paused"); + ui.window.classList.remove("touchinfohidden"); + game.resume2(); + e.stopPropagation(); + if (game.onresume) { + game.onresume(); + } + return false; + } + static config() { + if (!ui.click.configMenu) return; + if (_status.paused2) _status.config2 = false; + else _status.config2 = true; + + _status.clicked = true; + game.pause2(); + ui.click.configMenu(); + ui.system1.classList.remove("shown"); + ui.system2.classList.remove("shown"); + } + static swap() { + if (_status.dragged) return; + if (this.classList.contains("dead")) return; + if (_status.over) return; + if (ui.auto) ui.auto.show(); + if (ui.wuxie) ui.wuxie.show(); + game.swapPlayer(this); + } + static mousewheel(evt) { + if (this.firstChild && this.firstChild.classList.contains("handcards") && + !this.classList.contains("scrollh")) return; + var node = this; + var num = this._scrollnum || 6; + var speed = this._scrollspeed || 16; + clearInterval(node.interval); + if (evt.detail > 0 || evt.wheelDelta < 0) { + node.interval = setInterval(function () { + if (num-- && Math.abs(node.scrollLeft + node.clientWidth - node.scrollWidth) > 0) { + node.scrollLeft += speed; + } + else { + clearInterval(node.interval); + } + }, 16); + } + else { + node.interval = setInterval(function () { + if (num-- && node.scrollLeft > 0) { + node.scrollLeft -= speed; + } + else { + clearInterval(node.interval); + } + }, 16); + } + } + static touchStart(e) { + this.startX = e.touches[0].clientX / game.documentZoom; + this.startY = e.touches[0].clientY / game.documentZoom; + _status.dragged = false; + } + static dialogtouchStart(e) { + ui.click.touchStart.call(this, e); + _status.dialogtouched = true; + } + static touchScroll(e) { + if (_status.mousedragging) return; + if (_status.draggingtouchdialog) return; + if (!_status.dragged) { + if (Math.abs(e.touches[0].clientX / game.documentZoom - this.startX) > 10 || + Math.abs(e.touches[0].clientY / game.documentZoom - this.startY) > 10) { + _status.dragged = true; + } + } + if ((this == ui.handcards1Container || this == ui.handcards2Container) && !this.classList.contains("scrollh")) { + e.preventDefault(); + } + else if (lib.device == "ios" && this.scrollHeight <= this.offsetHeight + 5 && this.scrollWidth <= this.offsetWidth + 5) { + e.preventDefault(); + } + else { + delete _status._swipeorigin; + e.stopPropagation(); + } + } + static autoskill(bool, node) { + var list = lib.config.autoskilllist; + if (bool) { + list.remove(node.link); + } + else { + list.add(node.link); + } + game.saveConfig("autoskilllist", list); + } + static skillbutton() { + this.func(this.link); + } + static autoskill2(e) { + this.classList.toggle("on"); + var list = []; + if (lib.skill[this.link].frequent) { + list.push(this.link); + } + if (lib.skill[this.link].subfrequent) { + for (var i = 0; i < lib.skill[this.link].subfrequent.length; i++) { + list.push(this.link + "_" + lib.skill[this.link].subfrequent[i]); + } + } + for (var i = 0; i < list.length; i++) { + if (this.classList.contains("on")) { + lib.config.autoskilllist.remove(list[i]); + } + else { + lib.config.autoskilllist.add(list[i]); + } + } + game.saveConfig("autoskilllist", lib.config.autoskilllist); + ui.click.touchpop(); + e.stopPropagation(); + } + static hiddenskill(e) { + this.classList.toggle("on"); + var hidden = lib.skill[this.link].preHidden; + if (Array.isArray(hidden)) { + if (this.classList.contains("on")) { + _status.prehidden_skills.removeArray(hidden); + } + else { + _status.prehidden_skills.addArray(hidden); + } + } + if (this.classList.contains("on")) { + _status.prehidden_skills.remove(this.link); + } + else { + _status.prehidden_skills.add(this.link); + } + ui.click.touchpop(); + e.stopPropagation(); + } + static rightplayer(e) { + if (this._nopup) return false; + if (_status.clickedplayer) { + return false; + } + + if (this._mouseenterdialog && this._mouseenterdialog.parentNode) { + this._mouseenterdialog.delete(); + } + else { + ui.click.intro.call(this, e); + } + _status.clickedplayer = true; + _status.clicked = false; + ui.click.longpresscancel.call(this); + return false; + } + static right(e) { + if (window.inSplash) return false; + if (lib.config.touchscreen) return; + if (_status.noright) { + _status.noright = false; + return false; + } + if (_status.clickedplayer) { + _status.clickedplayer = false; + return; + } + game.closePopped(); + switch (lib.config.right_click) { + case "shortcut": ui.click.shortcut(); break; + case "pause": ui.click.pause(); break; + case "auto": ui.click.auto(); break; + case "config": ui.click.config(); break; + } + e.preventDefault(); + return false; + } +} diff --git a/noname/ui/create.js b/noname/ui/create.js new file mode 100644 index 000000000..cb3e0c93b --- /dev/null +++ b/noname/ui/create.js @@ -0,0 +1,10066 @@ +export class Create { + static buttonPresets = { + tdnodes: (item, type, position, noclick, node) => { + node = ui.create.div(".shadowed.reduce_radius.pointerdiv.tdnode.tdnodes", position); + if (Array.isArray(item)) { + node.innerHTML = "" + (item[1]) + ""; + node.link = item[0]; + } + else { + node.innerHTML = "" + (item) + ""; + node.link = item; + } + return node; + }, + blank: (item, type, position, noclick, node) => { + node = ui.create.div(".button.card", position); + node.link = item; + return node; + }, + card: (item, type, position, noclick, node) => { + if (typeof item.copy == "function") { + node = item.copy(false); + } + else { + node = item.cloneNode(true); + } + node.classList.add("button"); + if (position) position.appendChild(node); + node.link = item; + if (item.style.backgroundImage) { + node.style.backgroundImage = item.style.backgroundImage; + node.style.backgroundSize = "cover"; + } + if (item.style.color) { + node.style.color = item.style.color; + } + if (item.nature) { + let natures = get.natureList(item.nature); + natures.forEach(n => node.classList.add(n)); + } + if (!noclick) { + lib.setIntro(node); + } + if (get.position(item) == "j" && item.viewAs && item.viewAs != item.name && lib.config.cardtempname != "off") { + ui.create.cardTempName(item, node); + } + return node; + }, + vcard: (item, type, position, noclick, node) => { + if (typeof item == "string") { + item = [get.type(item), "", item]; + } + node = ui.create.card(position, "noclick", noclick); + node.classList.add("button"); + node.init(item); + node.link = item; + return node; + }, + character: (item, type, position, noclick, node) => { + if (node) { + node.classList.add("button"); + node.classList.add("character"); + node.style.display = ""; + } + else { + node = ui.create.div(".button.character", position); + } + node._link = item; + if (_status.noReplaceCharacter && type == "characterx") type = "character"; + if (type == "characterx") { + if (lib.characterReplace[item] && lib.characterReplace[item].length) item = lib.characterReplace[item].randomGet(); + } + node.link = item; + + var double = get.is.double(node._link, true); + if (double) node._changeGroup = true; + if (type == "characterx" && lib.characterReplace[node._link] && lib.characterReplace[node._link].length > 1) node._replaceButton = true; + var func = function (node, item) { + node.setBackground(item, "character"); + if (node.node) { + node.node.name.remove(); + node.node.hp.remove(); + node.node.group.remove(); + node.node.intro.remove(); + if (node.node.replaceButton) node.node.replaceButton.remove(); + } + node.node = { + name: ui.create.div(".name", node), + hp: ui.create.div(".hp", node), + group: ui.create.div(".identity", node), + intro: ui.create.div(".intro", node), + }; + var infoitem = lib.character[item]; + if (!infoitem) { + for (var itemx in lib.characterPack) { + if (lib.characterPack[itemx][item]) { + infoitem = lib.characterPack[itemx][item]; break; + } + } + } + node.node.name.innerHTML = get.slimName(item); + if (lib.config.buttoncharacter_style == "default" || lib.config.buttoncharacter_style == "simple") { + if (lib.config.buttoncharacter_style == "simple") { + node.node.group.style.display = "none"; + } + node.classList.add("newstyle"); + node.node.name.dataset.nature = get.groupnature(get.bordergroup(infoitem)); + node.node.group.dataset.nature = get.groupnature(get.bordergroup(infoitem), "raw"); + ui.create.div(node.node.hp); + var hp = get.infoHp(infoitem[2]), maxHp = get.infoMaxHp(infoitem[2]), hujia = get.infoHujia(infoitem[2]); + var str = get.numStr(hp); + if (hp != maxHp) { + str += "/"; + str += get.numStr(maxHp); + } + var textnode = ui.create.div(".text", str, node.node.hp); + if (infoitem[2] == 0) { + node.node.hp.hide(); + } + else if (get.infoHp(infoitem[2]) <= 3) { + node.node.hp.dataset.condition = "mid"; + } + else { + node.node.hp.dataset.condition = "high"; + } + if (hujia > 0) { + ui.create.div(node.node.hp, ".shield"); + ui.create.div(".text", get.numStr(hujia), node.node.hp); + } + } + else { + var hp = get.infoHp(infoitem[2]); + var maxHp = get.infoMaxHp(infoitem[2]); + var shield = get.infoHujia(infoitem[2]); + if (maxHp > 14) { + if (typeof infoitem[2] == "string") node.node.hp.innerHTML = infoitem[2]; + else node.node.hp.innerHTML = get.numStr(infoitem[2]); + node.node.hp.classList.add("text"); + } + else { + for (var i = 0; i < maxHp; i++) { + var next = ui.create.div("", node.node.hp); + if (i >= hp) next.classList.add("exclude"); + } + for (var i = 0; i < shield; i++) { + ui.create.div(node.node.hp, ".shield"); + } + } + } + if (node.node.hp.childNodes.length == 0) { + node.node.name.style.top = "8px"; + } + if (node.node.name.querySelectorAll("br").length >= 4) { + node.node.name.classList.add("long"); + if (lib.config.buttoncharacter_style == "old") { + node.addEventListener("mouseenter", ui.click.buttonnameenter); + node.addEventListener("mouseleave", ui.click.buttonnameleave); + } + } + node.node.intro.innerHTML = lib.config.intro; + if (!noclick) { + lib.setIntro(node); + } + if (infoitem[1]) { + if (double) { + node.node.group.innerHTML = double.reduce((previousValue, currentValue) => `${previousValue}
      ${get.translation(currentValue)}
      `, ""); + if (double.length > 4) if (new Set([5, 6, 9]).has(double.length)) node.node.group.style.height = "48px"; + else node.node.group.style.height = "64px"; + } + else node.node.group.innerHTML = `
      ${get.translation(infoitem[1])}
      `; + node.node.group.style.backgroundColor = get.translation(`${get.bordergroup(infoitem)}Color`); + } + else { + node.node.group.style.display = "none"; + } + if (node._replaceButton) { + var intro = ui.create.div(".button.replaceButton", node); + node.node.replaceButton = intro; + intro.innerHTML = "切换"; + intro._node = node; + intro.addEventListener(lib.config.touchscreen ? "touchend" : "click", function () { + _status.tempNoButton = true; + var node = this._node; + var list = lib.characterReplace[node._link]; + var link = node.link; + var index = list.indexOf(link); + if (index == list.length - 1) index = 0; + else index++; + link = list[index]; + node.link = link; + node.refresh(node, link); + setTimeout(function () { + delete _status.tempNoButton; + }, 200); + }); + } + }; + node.refresh = func; + node.refresh(node, item); + + return node; + }, + characterx: (item, type, position, noclick, node) => { + return ui.create.buttonPresets.character(item, type, position, noclick, node); + }, + player: (item, type, position, noclick, node) => { + if (node) { + node.classList.add("button"); + node.classList.add("character"); + node.style.display = ""; + } + else { + node = ui.create.div(".button.character", position); + } + node._link = item; + node.link = item; + node.node = { + name: ui.create.div(".name", node), + intro: ui.create.div(".intro", node) + } + if (item.name && item.name.startsWith("unknown")) { + if (item.node && item.node.name_seat) { + node.classList.add("cardbg"); + ui.create.div(".avatar_name", node, get.translation(item.name)); + } + else { + node.setBackground(item.name1, "character"); + } + } + else { + node.setBackground(item.name, "character"); + } + return node; + } + } + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + /** + * 创建身份牌实例 + */ + static identityCard(identity, position, noclick) { + const card = ui.create.card(position, "noclick", noclick); + card.removeEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.card); + card.classList.add("button"); + card._customintro = uiintro => uiintro.add(`${get.translation(`${identity}${2}`)}的身份牌`); + const fileName = `image/card/identity_${identity}.jpg`; + new Promise((resolve, reject) => { + const image = new Image(); + image.onload = resolve; + image.onerror = reject; + image.src = `${lib.assetURL}${fileName}`; + }).then(() => { + card.classList.add("fullskin"); + card.node.image.setBackgroundImage(fileName); + }, () => card.node.background.innerHTML = get.translation(identity)[0]); + return card; + } + /** + * 让卡牌旋转 + */ + static cardSpinning(card) { + if (lib.config.cardback_style != "default") { + card.style.transitionProperty = "none"; + ui.refresh(card); + card.classList.add("infohidden"); + ui.refresh(card); + card.style.transitionProperty = ""; + } + else { + card.classList.add("infohidden"); + } + card.style.transition = "all 0s"; + card.style.transform = "perspective(600px) rotateY(180deg) translateX(0)"; + const onEnd01 = function () { + setTimeout(function () { + card.style.transition = "all ease-in 0.3s"; + card.style.transform = "perspective(600px) rotateY(270deg) translateX(52px)"; + var onEnd = function () { + card.classList.remove("infohidden"); + card.style.transition = "all 0s"; + ui.refresh(card); + card.style.transform = "perspective(600px) rotateY(-90deg) translateX(52px)"; + ui.refresh(card); + card.style.transition = ""; + ui.refresh(card); + card.style.transform = ""; + } + card.listenTransition(onEnd); + }, 300); + }; + onEnd01(); + } + /** + * 旋转的身份牌! + */ + static spinningIdentityCard(identity, dialog) { + const card = ui.create.identityCard(identity); + const buttons = ui.create.div(".buttons", dialog.content); + setTimeout(() => { + buttons.appendChild(card); + dialog.open(); + ui.create.cardSpinning(card); + }, 50); + } + /** + * 创建codemirror编辑器 + * @param {HTMLDivElement} container + * @param {Function} saveInput + */ + static editor(container, saveInput) { + const createList = []; + const containerDelete = container.delete; + const editorpage = ui.create.div(container); + //删除container的时候,删除创建的ul列表 + container.delete = function () { + for (let i = createList.length - 1; i >= 0; i--) { + createList[i].parentNode && createList[i].parentNode.removeChild(createList[i]); + } + Array.from(editorpage.children).forEach(v => { v.style.background = "" }); + containerDelete.apply(this, arguments); + } + //创建ul列表 + const createMenu = function (pos, self, List, click) { + if (!self || self == window) return; + const parent = self.parentNode; + if (parent) { + for (let i = 0; i < parent.childElementCount; i++) { + const node = parent.childNodes[i]; + if (node != self && node.ul) closeMenu.call(node); + } + } + if (self.ul) { + self.style.background = "#08f"; + createList.add(self.ul); + ui.window.appendChild(self.ul); + return self.ul; + } + const editor = container.editor; + if (!editor) return false; + self.style.background = "#08f"; + const ul = document.createElement("ul"); + container.css.call(ul, { + position: "absolute", + top: pos.bottom / game.documentZoom + "px", + left: pos.left / game.documentZoom + "px", + height: "20em", + width: pos.width * 4 / game.documentZoom + "px", + //"font-family":"shousha", + "font-size": (lib.config.codeMirror_fontSize ? lib.config.codeMirror_fontSize.slice(0, -2) : 16) / game.documentZoom + "px", + + }); + const theme = editor.options.theme; + lib.setScroll(ul); + lib.setMousewheel(ul); + ul.className = "CodeMirror-hints " + theme; + const getActive = () => { + let i = 0; + while (i < ul.childElementCount) { + if (ul.childNodes[i].classList.contains("CodeMirror-hint-active")) break; + else i++; + } + return i; + }; + const setActive = i => { + ul.childNodes[getActive()].classList.remove("CodeMirror-hint-active"); + ul.childNodes[i].classList.add("CodeMirror-hint-active"); + return i; + }; + if (List && List.length && click) { + for (let i = 0; i < List.length; ++i) { + const elt = ul.appendChild(document.createElement("li")); + elt.style.color = "black"; + elt.style.boxShadow = "none"; + const cur = List[i]; + if (cur instanceof HTMLElement) { + elt.appendChild(cur); + } else { + elt.innerHTML = cur; + } + let className = "CodeMirror-hint" + (i != 0 ? "" : " " + "CodeMirror-hint-active"); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + elt.hintId = i; + ui.window.listen.call(elt, function () { + setActive(this.hintId); + this.focus(); + click.call(this); + }); + elt.onmousemove = elt.ontouchstart = () => { + setActive(i); + }; + } + } + createList.add(ul); + ui.window.appendChild(ul); + return ul; + }; + //关闭ul列表 + const closeMenu = function () { + const ul = this.ul; + if (!ul) return false; + if (ul.parentNode) ul.parentNode.removeChild(ul); + this.style.background = ""; + //创建后不用删除了,除非以后要动态加载。 + //delete this.ul; + createList.remove(ul); + return ul; + }; + const discardConfig = ui.create.div(".editbutton", "取消", editorpage, function () { + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(null); + delete window.saveNonameInput; + }); + const saveConfig = ui.create.div(".editbutton", "保存", editorpage, saveInput); + const theme = ui.create.div(".editbutton", "主题", editorpage, function () { + if (!this || this == window) return; + if (this.ul && this.ul.parentNode) { + return closeMenu.call(this); + } + //this + const self = this; + if (!this.ul) { + //主题列表 + const list = ["mdn-like", "mbo"]; + //正在使用的主题 + const active = container.editor.options.theme; + //排个序 + list.remove(active).splice(0, 0, active); + //元素位置 + const pos = self.getBoundingClientRect(); + //点击事件 + const click = function (e) { + const theme = this.innerHTML; + container.editor.setOption("theme", theme); + setTimeout(() => container.editor.refresh(), 0); + game.saveConfig("codeMirror_theme", theme); + closeMenu.call(self); + }; + const ul = createMenu(pos, self, list, click); + self.ul = ul; + } else { + createMenu(null, self); + } + }); + const edit = ui.create.div(".editbutton", "编辑", editorpage, function () { + if (!this || this == window) return; + if (this.ul && this.ul.parentNode) { + return closeMenu.call(this); + } + const self = this; + if (!this.ul) { + const pos = this.getBoundingClientRect(); + const list = ["撤销 Ctrl+Z", "恢复撤销 Ctrl+Y"]; + const click = function (e) { + const num = this.innerHTML.indexOf("Ctrl"); + const inner = this.innerHTML.slice(num).replace("+", "-"); + container.editor.execCommand(container.editor.options.extraKeys[inner]); + setTimeout(() => container.editor.refresh(), 0); + closeMenu.call(self); + }; + const ul = createMenu(pos, self, list, click); + this.ul = ul; + } else { + createMenu(null, self); + } + }); + const fontSize = ui.create.div(".editbutton", "字号", editorpage, function () { + if (!this || this == window) return; + if (this.ul && this.ul.parentNode) { + return closeMenu.call(this); + } + const self = this; + if (!this.ul) { + const pos = this.getBoundingClientRect(); + const list = ["16px", "18px", "20px", "22px", "24px", "26px"]; + const click = function (e) { + const size = this.innerHTML; + container.style.fontSize = size.slice(0, -2) / game.documentZoom + "px"; + Array.from(self.parentElement.children).map(v => v.ul).filter(Boolean).forEach(v => { v.style.fontSize = size.slice(0, -2) / game.documentZoom + "px" }); + setTimeout(() => container.editor.refresh(), 0); + game.saveConfig("codeMirror_fontSize", size); + closeMenu.call(self); + }; + const ul = createMenu(pos, self, list, click); + this.ul = ul; + } else { + createMenu(null, self); + } + }); + const editor = ui.create.div(editorpage); + return editor; + } + static cardTempName(card, applyNode) { + let getApplyNode = applyNode || card; + let cardName = get.name(card); + let cardNature = get.nature(card); + let tempname = get.translation(cardName); + let cardTempNameConfig = lib.config.cardtempname; + let node = getApplyNode._tempName || ui.create.div(".tempname", getApplyNode); + let datasetNature = ""; + getApplyNode._tempName = node; + if (cardTempNameConfig != "image") { + //清空,避免和下面的image部分有冲突 + node.innerHTML = ""; + datasetNature = "fire"; + if (get.position(card) == "j" && card.viewAs && card.viewAs != card.name) { + datasetNature = "wood"; + tempname = get.translation(card.viewAs); + } else { + if (cardName == "sha") { + if (cardNature) tempname = get.translation(cardNature) + tempname; + if (cardNature == "thunder") datasetNature = "thunder"; + if (cardNature == "kami") datasetNature = "kami"; + if (cardNature == "ice") datasetNature = "ice"; + } + } + if (cardTempNameConfig == "default") getApplyNode._tempName.classList.add("vertical"); + if (datasetNature.length > 0) { + node.dataset.nature = datasetNature; + } else { + delete node.dataset.nature; + node.classList.add(datasetNature); + } + } else { + if (get.position(card) == "j" && card.viewAs && card.viewAs != card.name) { + cardName = card.viewAs; + tempname = get.translation(card.viewAs); + } + if (cardName == "sha") { + if (cardNature) tempname = get.translation(cardNature) + tempname; + if (cardNature == "fire") datasetNature = "fire"; + if (cardNature == "thunder") datasetNature = "thunder"; + if (cardNature == "kami") datasetNature = "kami"; + if (cardNature == "ice") datasetNature = "ice"; + } + let bg = node.querySelector("div"); + if (bg) { + Array.from(node.childNodes).filter(v => v != bg).forEach(v => node.removeChild(v)); + } + else bg = ui.create.div(node); + node.classList.add("tempimage"); + let img = lib.card[cardName].image; + if (img) { + if (img.startsWith("db:")) { + img = img.slice(3); + } + else if (!img.startsWith("ext:")) { + img = null; + } + } + if (lib.card[cardName].fullskin) { + if (img) { + if (img.startsWith("ext:")) { + bg.setBackgroundImage(img.replace(/^ext:/, "extension/")); + } + else { + bg.setBackgroundDB(img); + } + } + else { + if (lib.card[cardName].modeimage) { + bg.setBackgroundImage("image/mode/" + lib.card[cardName].modeimage + "/card/" + cardName + ".png"); + } + else { + if (cardName == "sha" && cardNature == "stab") bg.setBackgroundImage("image/card/cisha.png"); + else bg.setBackgroundImage("image/card/" + cardName + ".png"); + } + } + } + else if (lib.card[cardName].image == "background") { + if (cardNature) bg.setBackground(cardName + "_" + cardNature, "card"); + else bg.setBackground(cardName, "card"); + } + else if (lib.card[cardName].fullimage) { + if (img) { + if (img.startsWith("ext:")) { + bg.setBackgroundImage(img.replace(/^ext:/, "extension/")); + bg.style.backgroundSize = "cover"; + } + else { + bg.setBackgroundDB(img); + } + } + else if (lib.card[cardName].image) { + if (lib.card[cardName].image.startsWith("character:")) { + bg.setBackground(lib.card[cardName].image.slice(10), "character"); + } + else { + bg.setBackground(lib.card[cardName].image); + } + } + else { + let cardPack = lib.cardPack["mode_" + get.mode()]; + if (Array.isArray(cardPack) && cardPack.contains(cardName)) { + bg.setBackground("mode/" + get.mode() + "/card/" + cardName); + } + else { + bg.setBackground("card/" + cardName); + } + } + } + else if (lib.card[cardName].image == "card") { + if (cardNature) bg.setBackground(cardName + "_" + cardNature, "card"); + else bg.setBackground(cardName, "card"); + } + else if (typeof lib.card[cardName].image == "string" && !lib.card[cardName].fullskin) { + if (img) { + if (img.startsWith("ext:")) { + bg.setBackgroundImage(img.replace(/^ext:/, "extension/")); + bg.style.backgroundSize = "cover"; + } + else { + bg.setBackgroundDB(img); + } + } + else { + bg.setBackground(lib.card[cardName].image); + } + } + else { + console.warn("卡牌图片解析失败"); + } + if (datasetNature.length > 0) { + node.classList.add(datasetNature); + } + delete node.dataset.nature; + } + node.innerHTML += `${cardTempNameConfig == "default" ? get.verticalStr(tempname) : tempname}`; + node.tempname = tempname; + return node; + } + static connectRooms(list) { + ui.rooms = []; + ui.roombase = ui.create.dialog(); + ui.roombase.classList.add("fullwidth"); + ui.roombase.classList.add("fullheight"); + ui.roombase.classList.add("fixed"); + ui.roombase.classList.add("scroll1"); + ui.roombase.classList.add("scroll2"); + ui.roombase.classList.add("noupdate"); + for (var i = 0; i < list.length; i++) { + var player = ui.roombase.add(``); + player.roomindex = i; + player.initRoom = lib.element.Player.prototype.initRoom; + player.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.connectroom); + player.initRoom(list[i]); + ui.rooms.push(player); + } + } + static rarity(button) { + var rarity = game.getRarity(button.link); + if (rarity != "common" && lib.config.show_rarity) { + var intro = button.node.intro; + intro.classList.add("showintro"); + intro.style.fontFamily = "yuanli"; + intro.style.fontSize = "16px"; + intro.style.bottom = "6px"; + intro.style.left = "6px"; + switch (rarity) { + case "rare": intro.dataset.nature = "thunderm"; break; + case "epic": intro.dataset.nature = "metalm"; break; + case "legend": intro.dataset.nature = "orangem"; break; + case "junk": intro.dataset.nature = "woodm"; break; + } + intro.innerHTML = get.translation(rarity); + } + } + static div() { + var str, innerHTML, position, position2, style, divposition, listen; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + if (typeof str == "string") { + innerHTML = arguments[i]; + } + else { + str = arguments[i]; + } + } + else if (get.objtype(arguments[i]) == "div" || + get.objtype(arguments[i]) == "table" || + get.objtype(arguments[i]) == "tr" || + get.objtype(arguments[i]) == "td" || + get.objtype(arguments[i]) == "body") position = arguments[i]; + else if (typeof arguments[i] == "number") position2 = arguments[i]; + else if (get.itemtype(arguments[i]) == "divposition") divposition = arguments[i]; + else if (typeof arguments[i] == "object") style = arguments[i]; + else if (typeof arguments[i] == "function") listen = arguments[i]; + } + if (str == undefined) str = ""; + var node = document.createElement("div"); + for (var i = 0; i < str.length; i++) { + if (str[i] == ".") { + if (node.className.length != 0) { + node.className += " "; + } + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.className += str[i + 1]; + i++; + } + } + else if (str[i] == "#") { + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.id += str[i + 1]; + i++; + } + } + } + if (position) { + if (typeof position2 == "number" && position.childNodes.length > position2) { + position.insertBefore(node, position.childNodes[position2]); + } + else { + position.appendChild(node); + } + } + if (style) node.css(style); + if (divposition) node.setPosition(divposition); + if (innerHTML) node.innerHTML = innerHTML; + if (listen) node.listen(listen); + return node; + } + static filediv() { + var args = Array.from(arguments); + var func = null; + for (var i = 0; i < args.length; i++) { + if (typeof args[i] == "function") { + func = args[i]; + args.splice(i, 1); + break; + } + } + var div = ui.create.div.apply(this, args); + var input = ui.create.node("input.fileinput"); + input.type = "file"; + input.onchange = function (e) { + func.call(this, this.files[0], e); + }; + div.appendChild(input); + div.inputNode = input; + return div; + } + static node() { + var tagName, str, innerHTML, position, position2, style, divposition, listen; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") { + if (typeof tagName == "string") { + innerHTML = arguments[i]; + } + else { + tagName = arguments[i]; + } + } + else if (get.objtype(arguments[i]) == "div" || + get.objtype(arguments[i]) == "table" || + get.objtype(arguments[i]) == "tr" || + get.objtype(arguments[i]) == "td" || + get.objtype(arguments[i]) == "body") position = arguments[i]; + else if (typeof arguments[i] == "number") position2 = arguments[i]; + else if (get.itemtype(arguments[i]) == "divposition") divposition = arguments[i]; + else if (typeof arguments[i] == "object") style = arguments[i]; + else if (typeof arguments[i] == "function") listen = arguments[i]; + } + if (tagName == undefined) { + tagName = "div"; + } + else { + var i1 = tagName.indexOf("."); + var i2 = tagName.indexOf("#"); + if (i1 != -1 || i2 != -1) { + if (i2 != -1 && i2 < i1) { + i1 = i2; + } + str = tagName.slice(i1); + tagName = tagName.slice(0, i1); + } + } + var node = document.createElement(tagName); + if (str) { + for (var i = 0; i < str.length; i++) { + if (str[i] == ".") { + if (node.className.length != 0) { + node.className += " "; + } + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.className += str[i + 1]; + i++; + } + } + else if (str[i] == "#") { + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.id += str[i + 1]; + i++; + } + } + } + } + if (position) { + if (typeof position2 == "number" && position.childNodes.length > position2) { + position.insertBefore(node, position.childNodes[position2]); + } + else { + position.appendChild(node); + } + } + if (style) HTMLDivElement.prototype.css.call(node, style); + if (divposition) HTMLDivElement.prototype.setPosition.call(node, divposition); + if (innerHTML) node.innerHTML = innerHTML; + if (listen) node.onclick = listen; + return node; + } + static iframe(src) { + var layer = document.createElement("div"); + layer.classList.add("poplayer"); + layer.style.zIndex = "100"; + layer.listen(function () { + this.remove(); + }); + layer.style.background = "white"; + + var webview = document.createElement("iframe"); + webview.src = src; + webview.style.width = "100%"; + webview.style.height = "100%"; + webview.style.left = "0px"; + webview.style.top = "0px"; + webview.style.position = "absolute"; + webview.style.border = "none"; + layer.appendChild(webview); + + var backbutton = ui.create.div(".menubutton.round", "返", layer, function () { + layer.remove(); + }); + backbutton.style.bottom = "10px"; + backbutton.style.right = "10px"; + backbutton.style.background = "rgba(0,0,0,0.4)"; + backbutton.style.color = "white"; + backbutton.style.textShadow = "rgba(0,0,0,0.5) 0px 0px 2px"; + backbutton.style.boxShadow = "rgba(0, 0, 0, 0.3) 0 0 0 1px, rgba(0, 0, 0, 0.3) 0 3px 10px"; + backbutton.style.position = "fixed"; + + ui.window.appendChild(layer); + } + static identitycircle(list, target) { + var container = ui.create.div(".identitycircle.menubg", target); + var circle = ui.create.div(container); + container.dataset.num = list.length; + for (var i = 0; i < list.length; i++) { + var sec1 = ui.create.div(circle); + sec1.dataset.color = list[i]; + var sec2 = ui.create.div(circle); + sec2.dataset.color = list[i]; + var deg1 = 360 / list.length * i; + var deg2 = 0; + if (list.length == 2) { + deg2 = 90; + } + else if (list.length == 3) { + deg2 = 30; + } + sec1.style.transform = "rotate(" + deg1 + "deg)"; + sec2.style.transform = "rotate(" + (deg1 + deg2) + "deg)"; + } + } + static chat() { + var chat = ui.create.system("聊天", null, true); + ui.chatButton = chat; + lib.setPopped(chat, ui.click.chat, 220); + } + static exit() { + if (!ui.exit) { + ui.exit = ui.create.control("退出房间", ui.click.exit); + } + } + static connecting(bool) { + if (bool) { + ui.window.classList.remove("connecting"); + if (ui.connecting) { + ui.connecting.delete(); + delete ui.connecting; + } + } + else { + ui.window.classList.add("connecting"); + ui.connecting = ui.create.div(".fullsize.connectlayer"); + document.body.appendChild(ui.connecting); + ui.create.div("", "正在重连...", ui.connecting); + ui.connecting.splashtimeout = setTimeout(function () { + if (ui.connecting) { + delete ui.connecting.splashtimeout; + } + }, 300); + // setTimeout(function(){ + // if(ui.connecting){ + // ui.connecting.firstChild.show(); + // } + // },1000); + } + } + static roomInfo() { + var chat = ui.create.system(game.online ? "房间信息" : "房间设置", function () { + if (!game.online || game.onlinezhu) { + ui.click.connectMenu(); + } + }, true); + ui.roomInfo = chat; + lib.setPopped(chat, function () { + if (game.getRoomInfo) { + var uiintro = ui.create.dialog("hidden"); + game.getRoomInfo(uiintro); + return uiintro; + } + }, 180); + } + static templayer(time) { + if (typeof time != "number" || isNaN(time) || time == Infinity) { + time = 500; + } + var templayer = ui.create.div(".popup-container", ui.window); + setTimeout(function () { + templayer.remove(); + }, time); + } + static selectlist(list, init, position, onchange) { + var select = document.createElement("select"); + for (var i = 0; i < list.length; i++) { + var option = document.createElement("option"); + if (Array.isArray(list[i])) { + option.value = list[i][0]; + option.innerHTML = list[i][1]; + } + else { + option.value = list[i]; + option.innerHTML = list[i]; + } + if (init == option.value) { + option.selected = "selected"; + } + select.appendChild(option); + } + if (position) { + position.appendChild(select); + } + if (onchange) { + select.onchange = onchange; + } + return select; + } + static menu(connectMenu) { + var menuTimeout = null; + if (!connectMenu && !game.syncMenu) { + menuTimeout = setTimeout(lib.init.reset, 1000); + } + var menu, menuContainer; + var startButton; + var popupContainer; + var closeMenu = function () { + if (popupContainer.noclose) { + popupContainer.noclose = false; + return; + } + popupContainer.classList.add("hidden"); + if (popupContainer.onclose) { + popupContainer.onclose(); + } + }; + popupContainer = ui.create.div(".popup-container.hidden", ui.window, closeMenu); + + var openMenu = function (node, e, onclose) { + popupContainer.innerHTML = ""; + var left = Math.round(e.clientX / game.documentZoom); + var zoom = get.is.phoneLayout ? 1.3 : 1; + popupContainer.appendChild(node); + // var rect=node.getBoundingClientRect(); + if (node.classList.contains("visual")) { + // var num=node.querySelectorAll(".menu.visual>div").length; + // node.style.top=(e.y-node.offsetHeight/2+30)+"px"; + for (var i = 0; i < node.childElementCount; i++) { + if (node.childNodes[i].update) { + node.childNodes[i].update(); + } + } + // if(node.offsetTop<10){ + // node.style.top="10px"; + // } + } + // else if(get.is.phoneLayout()&&rect.top*1.3+rect.height*1.3+20>ui.window.offsetHeight){ + // node.style.top=(ui.winheightdow.offsetHeight-20-rect.height*1.3)/1.3+"px"; + // } + // if(e){ + var height = node.offsetHeight; + var idealtop = e.clientY / game.documentZoom; + if (idealtop < 10) { + idealtop = 10; + } + else if ((idealtop + height) * zoom + 10 > ui.window.offsetHeight) { + idealtop = (ui.window.offsetHeight - 10) / zoom - height; + } + node.style.top = idealtop + "px"; + node.style.left = left + "px"; + // } + + popupContainer.classList.remove("hidden"); + popupContainer.onclose = onclose; + }; + var clickToggle = function () { + if (this.classList.contains("disabled")) return; + this.classList.toggle("on"); + var config = this._link.config; + if (config.onclick) { + if (config.onclick.call(this, this.classList.contains("on")) === false) { + this.classList.toggle("on"); + } + } + if (config.update) { + config.update(); + } + }; + var clickSwitcher = function () { + if (this.classList.contains("disabled")) return; + var node = this; + this.classList.add("on"); + if (this._link.menu) { + var pos1 = this.lastChild.getBoundingClientRect(); + var pos2 = ui.window.getBoundingClientRect(); + if (this._link.menu.classList.contains("visual")) { + openMenu(this._link.menu, { + clientX: pos1.left + pos1.width + 5 - pos2.left, + clientY: pos1.top - pos2.top + }, function () { + node.classList.remove("on"); + }); + } + else if (this._link.menu.childElementCount > 10) { + openMenu(this._link.menu, { + clientX: pos1.left + pos1.width + 5 - pos2.left, + clientY: Math.min((ui.window.offsetHeight - 400) / 2, pos1.top - pos2.top) + }, function () { + node.classList.remove("on"); + }); + lib.setScroll(this._link.menu); + } + else { + openMenu(this._link.menu, { + clientX: pos1.left + pos1.width + 5 - pos2.left, + clientY: pos1.top - pos2.top + }, function () { + node.classList.remove("on"); + }); + } + } + }; + var clickContainer = function () { + menuContainer.classList.add("hidden"); + if (connectMenu) { + if (_status.enteringroom) { + _status.enteringroom = false; + } + if (_status.creatingroom) { + _status.creatingroom = false; + } + ui.window.classList.remove("shortcutpaused"); + } + else { + game.resume2(); + if (game.onresume2) { + game.onresume2(); + } + ui.arena.classList.remove("menupaused"); + ui.historybar.classList.remove("menupaused"); + ui.window.classList.remove("touchinfohidden"); + ui.config2.classList.remove("pressdown2"); + } + }; + var clickMenuItem = function () { + var node = this.parentNode._link; + var config = node._link.config; + node._link.current = this.link; + var tmpName = node.lastChild.innerHTML; + node.lastChild.innerHTML = config.item[this._link]; + if (config.onclick) { + if (config.onclick.call(node, this._link, this) === false) { + node.lastChild.innerHTML = tmpName; + } + } + if (config.update) { + config.update(); + } + }; + var createMenu = function (tabs, config) { + var createPage = function (position) { + var node = ui.create.div(position); + lib.setScroll(ui.create.div(".left.pane", node)); + lib.setScroll(ui.create.div(".right.pane", node)); + return node; + }; + var menu = ui.create.div(".main.menu.dialog.popped.static", config.position, function (e) { + e.stopPropagation(); + }); + if (connectMenu) { + menu.classList.add("center"); + menuContainer.classList.add("centermenu"); + } + var menuTab = ui.create.div(".menu-tab", menu); + var menuTabBar = ui.create.div(".menu-tab-bar", menu); + menuTabBar.style.left = (config.bar || 0) + "px"; + if (Math.round(2 * game.documentZoom) < 2) { + menuTabBar.style.height = "3px"; + } + var menuContent = ui.create.div(".menu-content", menu); + var clickTab = function () { + if (this.classList.contains("disabled")) return; + var active = this.parentNode.querySelector(".active"); + if (active) { + active.classList.remove("active"); + active._link.remove(); + } + this.classList.add("active"); + menuTabBar.style.transform = "translateX(" + (this.getBoundingClientRect().left - this.parentNode.firstChild.getBoundingClientRect().left) / game.documentZoom + "px)"; + menuContent.appendChild(this._link); + }; + ui.click.menuTab = function (tab) { + for (var i = 0; i < menuTab.childNodes.length; i++) { + if (menuTab.childNodes[i].innerHTML == tab) { + clickTab.call(menuTab.childNodes[i]); + return; + } + } + }; + var pages = []; + for (var i = 0; i < tabs.length; i++) { + var active = (i === (config.init || 0)); + pages[i] = createPage(active ? menuContent : null); + ui.create.div(active ? ".active" : "", tabs[i], menuTab, clickTab)._link = pages[i]; + } + return { + menu: menu, + pages: pages + }; + }; + var createConfig = function (config, position) { + var node = ui.create.div(".config", config.name); + node._link = { config: config }; + if (!config.clear) { + if (config.name != "开启") { + if (config.name == "屏蔽弱将") { + config.intro = "强度过低的武将(孙策除外)不会出现在选将框,也不会被AI选择" + } + else if (config.name == "屏蔽强将") { + config.intro = "强度过高的武将不会出现在选将框,也不会被AI选择" + } + else if (!config.intro) { + config.intro = "设置" + config.name; + } + lib.setIntro(node, function (uiintro) { + if (lib.config.touchscreen) _status.dragged = true; + uiintro.style.width = "170px"; + var str = config.intro; + if (typeof str == "function") { + str = str(); + } + uiintro._place_text = uiintro.add(`
      ${str}
      `); + }); + } + } + else { + node.innerHTML = "" + config.name + ""; + if (!config.nopointer) { + node.classList.add("pointerspan"); + } + } + if (config.item) { + if (typeof config.item == "function") { + config.item = config.item(); + } + if (Array.isArray(config.init)) { + void 0; + } + else { + node.classList.add("switcher"); + node.listen(clickSwitcher); + node._link.choosing = ui.create.div("", config.item[config.init], node); + node._link.menu = ui.create.div(".menu"); + if (config.visualMenu) { + node._link.menu.classList.add("visual"); + var updateVisual = function () { + config.visualMenu(this, this._link, config.item[this._link], config); + }; + var createNode = function (i, before) { + var visualMenu = ui.create.div(); + if (config.visualBar) { + if (before) { + node._link.menu.insertBefore(visualMenu, before); + } + else { + node._link.menu.insertBefore(visualMenu, node._link.menu.lastChild); + } + } + else { + node._link.menu.appendChild(visualMenu); + } + ui.create.div(".name", get.verticalStr(config.item[i]), visualMenu); + visualMenu._link = i; + if (config.visualMenu(visualMenu, i, config.item[i], config) !== false) { + visualMenu.listen(clickMenuItem); + } + visualMenu.update = updateVisual; + }; + if (config.visualBar) { + var visualBar = ui.create.div(node._link.menu, function () { + this.parentNode.parentNode.noclose = true; + }); + node._link.menu.classList.add("withbar"); + config.visualBar(visualBar, config.item, createNode, node); + visualBar.update = function () { + config.visualBar(visualBar, config.item, createNode, node); + } + } + for (var i in config.item) { + createNode(i); + } + lib.setScroll(node._link.menu); + node._link.menu.updateBr = function () { + var br = Array.from(this.querySelectorAll(".menu.visual>br")); + while (br.length) { + br.shift().remove(); + } + var split = []; + for (var i = 1; i < this.childElementCount; i++) { + if (i % 3 == 0) { + split.push(this.childNodes[i]); + } + } + for (var i = 0; i < split.length; i++) { + this.insertBefore(ui.create.node("br"), split[i]); + } + } + node._link.menu.updateBr(); + } + else { + for (var i in config.item) { + var textMenu = ui.create.div("", config.item[i], node._link.menu, clickMenuItem); + textMenu._link = i; + if (config.textMenu) { + config.textMenu(textMenu, i, config.item[i], config) + } + lib.setScroll(node._link.menu); + } + } + node._link.menu._link = node; + node._link.current = config.init; + } + } + else if (config.range) { + void 0; + } + else if (config.clear) { + if (node.innerHTML.length >= 15) node.style.height = "auto"; + node.listen(clickToggle); + } + else if (config.input) { + node.classList.add("switcher"); + var input = ui.create.div(node); + if (!config.fixed) { + input.contentEditable = true; + input.style.webkitUserSelect = "text"; + } + input.style.minWidth = "10px"; + input.style.maxWidth = "60%"; + input.style.overflow = "hidden"; + input.style.whiteSpace = "nowrap"; + input.onkeydown = function (e) { + if (e.keyCode == 13) { + e.preventDefault(); + e.stopPropagation(); + input.blur(); + } + }; + if (config.name == "联机昵称") { + input.innerHTML = config.init || "无名玩家"; + input.onblur = function () { + input.innerHTML = input.innerHTML.replace(/
      /g, ""); + if (!input.innerHTML || get.is.banWords(input.innerHTML)) { + input.innerHTML = "无名玩家"; + } + input.innerHTML = input.innerHTML.slice(0, 12); + game.saveConfig("connect_nickname", input.innerHTML); + game.saveConfig("connect_nickname", input.innerHTML, "connect"); + } + } + else if (config.name == "联机大厅") { + input.innerHTML = config.init || lib.hallURL; + input.onblur = function () { + if (!input.innerHTML) { + input.innerHTML = lib.hallURL; + } + input.innerHTML = input.innerHTML.replace(/
      /g, ""); + game.saveConfig("hall_ip", input.innerHTML, "connect"); + } + } + else { + input.innerHTML = config.init; + input.onblur = config.onblur; + } + } + else { + node.classList.add("toggle"); + node.listen(clickToggle); + ui.create.div(ui.create.div(node)); + if (config.init == true) { + node.classList.add("on"); + } + } + if (position) { + position.appendChild(node); + } + return node; + }; + var updateActive, updateActiveCard; + var menuUpdates = []; + menuContainer = ui.create.div(".menu-container.hidden", ui.window, clickContainer); + var menux; + if (!connectMenu) { + ui.menuContainer = menuContainer; + ui.click.configMenu = function () { + ui.click.shortcut(false) + if (menuContainer.classList.contains("hidden")) { + ui.config2.classList.add("pressdown2"); + ui.arena.classList.add("menupaused"); + ui.historybar.classList.add("menupaused"); + ui.window.classList.add("touchinfohidden"); + menuContainer.classList.remove("hidden"); + for (var i = 0; i < menuUpdates.length; i++) { + menuUpdates[i](); + } + } + else { + clickContainer.call(menuContainer); + } + } + menux = createMenu(["开始", "选项", "武将", "卡牌", "扩展", "其它"], { + position: menuContainer, bar: 40 + }); + } + else { + ui.connectMenuContainer = menuContainer; + ui.click.connectMenu = function () { + if (menuContainer.classList.contains("hidden")) { + if (_status.waitingForPlayer) { + startButton.innerHTML = "设"; + var start = menux.pages[0].firstChild; + for (var i = 0; i < start.childNodes.length; i++) { + if (start.childNodes[i].mode != lib.configOL.mode) { + start.childNodes[i].classList.add("unselectable"); + start.childNodes[i].classList.remove("active"); + if (start.childNodes[i].link) start.childNodes[i].link.remove(); + } + else { + start.childNodes[i].classList.add("active"); + if (start.childNodes[i].link) start.nextSibling.appendChild(start.childNodes[i].link); + else console.log(start.nextSibling, start.childNodes[i]); + } + } + } + ui.window.classList.add("shortcutpaused"); + menuContainer.classList.remove("hidden"); + for (var i = 0; i < menuUpdates.length; i++) { + menuUpdates[i](); + } + } + else { + clickContainer.call(menuContainer); + } + } + + menux = createMenu(["模式", "武将", "卡牌"], { + position: menuContainer, bar: 123 + }); + menu = menux.menu; + } + var menuxpages = menux.pages.slice(0); + + var copyObj = get.copy; + + (function () { + var start = menuxpages.shift(); + var rightPane = start.lastChild; + + startButton = ui.create.div(".menubutton.round.highlight", "启", start, function () { + if (this.animating || this.classList.contains("dim")) { + return; + } + var active = this.parentNode.querySelector(".active"); + if (active) { + if (connectMenu) { + if (_status.waitingForPlayer) { + var config = {}; + for (var i in lib.mode[lib.configOL.mode].connect) { + if (i == "update") continue; + config[i.slice(8)] = get.config(i, lib.configOL.mode); + } + config.zhinang_tricks = lib.config.connect_zhinang_tricks; + if (game.online) { + if (game.onlinezhu) { + game.send("changeRoomConfig", config); + } + } + else { + game.broadcastAll(function (config) { + for (var i in config) { + lib.configOL[i] = config[i]; + } + }, config); + if (lib.configOL.mode == "identity" && lib.configOL.identity_mode == "zhong" && game.connectPlayers) { + for (var i = 0; i < game.connectPlayers.length; i++) { + game.connectPlayers[i].classList.remove("unselectable2"); + } + lib.configOL.number = 8; + game.updateWaiting(); + } + if (game.onlineroom) { + game.send("server", "config", lib.configOL); + } + game.connectPlayers[0].chat("房间设置已更改"); + } + } + else if (_status.enteringroom || _status.creatingroom) { + lib.configOL.mode = active.mode; + if (_status.enteringroomserver) { + game.saveConfig("connect_mode", lib.configOL.mode); + + var config = {}; + for (var i in lib.mode[lib.configOL.mode].connect) { + if (i == "update") continue; + config[i.slice(8)] = get.config(i, lib.configOL.mode); + } + config.zhinang_tricks = lib.config.connect_zhinang_tricks; + + config.characterPack = lib.connectCharacterPack.slice(0); + config.cardPack = lib.connectCardPack.slice(0); + for (var i = 0; i < lib.config.connect_characters.length; i++) { + config.characterPack.remove(lib.config.connect_characters[i]); + } + for (var i = 0; i < lib.config.connect_cards.length; i++) { + config.cardPack.remove(lib.config.connect_cards[i]); + } + config.banned = lib.config["connect_" + active.mode + "_banned"]; + config.bannedcards = lib.config["connect_" + active.mode + "_bannedcards"]; + game.send("server", "create", game.onlineKey, get.connectNickname(), lib.config.connect_avatar, config, active.mode); + } + else { + game.send("server", "create", game.onlineKey, get.connectNickname(), lib.config.connect_avatar); + } + } + else { + localStorage.setItem(lib.configprefix + "directstart", true); + game.saveConfig("directstartmode", active.mode); + game.saveConfig("mode", "connect"); + ui.exitroom = ui.create.system("退出房间", function () { + game.saveConfig("directstartmode"); + game.reload(); + }, true); + game.switchMode(active.mode); + } + clickContainer.call(menuContainer); + } + else { + game.saveConfig("mode", active.mode); + localStorage.setItem(lib.configprefix + "directstart", true); + game.reload(); + } + } + }); + + var clickMode = function () { + if (this.classList.contains("unselectable")) return; + var active = this.parentNode.querySelector(".active"); + if (active === this) { + return; + } + active.classList.remove("active"); + active.link.remove(); + active = this; + this.classList.add("active"); + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + if (connectMenu) { + if (updateActive) updateActive(); + if (updateActiveCard) updateActiveCard(); + } + }; + + var createModeConfig = function (mode, position) { + var info = lib.mode[mode]; + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", info.name, position, clickMode); + node.mode = mode; + var connectDisplayMap = { + connect_player_number: null, + connect_versus_mode: null, + } + var updateConnectDisplayMap = function () { + if (_status.waitingForPlayer) { + if (connectDisplayMap.connect_player_number) { + connectDisplayMap.connect_player_number.style.display = "none"; + } + if (connectDisplayMap.connect_versus_mode) { + connectDisplayMap.connect_versus_mode.style.display = "none"; + } + } + }; + if (connectMenu) { + menuUpdates.push(updateConnectDisplayMap); + if (mode == lib.config.connect_mode) { + node.classList.add("active"); + } + } + else { + if (mode == lib.config.mode) { + node.classList.add("active"); + } + } + node._initLink = function () { + node.link = page; + //“更多”下的内容 + var map = {}; + var infoconfig = connectMenu ? info.connect : info.config; + if (infoconfig) { + var hiddenNodes = []; + var config = lib.config.mode_config[mode] || {}; + if (connectMenu) { + infoconfig.connect_choose_timeout = { + name: "出牌时限", + init: "30", + item: { + "10": "10秒", + "15": "15秒", + "30": "30秒", + "60": "60秒", + "90": "90秒", + }, + connect: true, + frequent: true + }; + infoconfig.connect_observe = { + name: "允许旁观", + init: true, + connect: true + }; + infoconfig.connect_observe_handcard = { + name: "允许观看手牌", + init: false, + connect: true + }; + infoconfig.connect_mount_combine = { + name: "合并坐骑栏", + init: false, + connect: true + }; + } + for (var j in infoconfig) { + if (j === "update") { + continue; + } + var cfg = copyObj(infoconfig[j]); + cfg._name = j; + cfg.mode = mode; + if (!Object.prototype.hasOwnProperty.call(config, j)) { + game.saveConfig(j, cfg.init, mode); + } + else { + cfg.init = config[j]; + } + if (!cfg.onclick) { + cfg.onclick = function (result) { + var cfg = this._link.config; + game.saveConfig(cfg._name, result, mode); + if (cfg.onsave) { + cfg.onsave.call(this, result); + } + if (!_status.connectMode || game.online) { + if (typeof cfg.restart == "function") { + if (cfg.restart()) { + startButton.classList.add("glowing"); + } + } + else if (cfg.restart) { + startButton.classList.add("glowing"); + } + } + }; + } + if (infoconfig.update) { + cfg.update = function () { + infoconfig.update(config, map); + }; + } + var cfgnode = createConfig(cfg); + map[j] = cfgnode; + if (cfg.frequent) { + page.appendChild(cfgnode); + } + else { + cfgnode.classList.add("auto-hide"); + hiddenNodes.push(cfgnode); + } + } + if (!connectMenu) { + var move = ui.create.div(".auto-hide.config", `
      上移↑
      下移↓
      `); + move.firstChild.listen(function () { + if (node.previousSibling) { + node.parentNode.insertBefore(node, node.previousSibling); + var order = []; + for (var i = 0; i < node.parentNode.childNodes.length; i++) { + order.push(node.parentNode.childNodes[i].mode); + } + game.saveConfig("modeorder", order); + } + }); + move.lastChild.listen(function () { + if (node.nextSibling) { + if (node.nextSibling.nextSibling) { + node.parentNode.insertBefore(node, node.nextSibling.nextSibling); + } + else { + node.parentNode.insertBefore(node.nextSibling, node); + } + var order = []; + for (var i = 0; i < node.parentNode.childNodes.length; i++) { + order.push(node.parentNode.childNodes[i].mode); + } + game.saveConfig("modeorder", order); + } + }); + hiddenNodes.push(move); + } + var expanded = false; + var hasexpand = true; + if (hiddenNodes.length) { + if (lib.config.fold_mode) { + var clickmore = function (type) { + if (type === "expand" && expanded) return; + if (type === "unexpand" && !expanded) return; + if (expanded) { + this.classList.remove("on"); + this.parentNode.classList.remove("expanded"); + } + else { + this.classList.add("on"); + this.parentNode.classList.add("expanded"); + } + expanded = !expanded; + }; + var morenodes = ui.create.div(".config.more", "更多
      >
      ", page); + morenodes.listen(clickmore); + morenodes._onclick = clickmore; + page.morenodes = morenodes; + } + else { + page.classList.add("expanded"); + if (!connectMenu) { + page.classList.add("expanded2"); + } + } + for (var k = 0; k < hiddenNodes.length; k++) { + page.appendChild(hiddenNodes[k]); + } + } + else { + hasexpand = false; + } + if (!connectMenu) { + var hidemode = ui.create.div(".config.pointerspan", "隐藏此模式", page, function () { + if (this.firstChild.innerHTML == "隐藏此模式") { + this.firstChild.innerHTML = "此模式将在重启后隐藏"; + lib.config.hiddenModePack.add(mode); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏此模式"; + lib.config.hiddenModePack.remove(mode); + } + game.saveConfig("hiddenModePack", lib.config.hiddenModePack); + }); + if (hasexpand) { + hidemode.classList.add("auto-hide"); + } + } + if (infoconfig.update) { + infoconfig.update(config, map); + node.update = function () { + infoconfig.update(config, map); + } + } + } + if (connectMenu) { + connectDisplayMap.connect_player_number = map.connect_player_number; + connectDisplayMap.connect_versus_mode = map.connect_versus_mode; + updateConnectDisplayMap(); + } + }; + if (!get.config("menu_loadondemand")) node._initLink(); + return node; + }; + var modeorder = lib.config.modeorder || []; + for (var i in lib.mode) { + modeorder.add(i); + } + for (var i = 0; i < modeorder.length; i++) { + if (connectMenu) { + if (!lib.mode[modeorder[i]].connect) continue; + if (!lib.config["connect_" + modeorder[i] + "_banned"]) { + lib.config["connect_" + modeorder[i] + "_banned"] = []; + } + if (!lib.config["connect_" + modeorder[i] + "_bannedcards"]) { + lib.config["connect_" + modeorder[i] + "_bannedcards"] = []; + } + } + if (lib.config.all.mode.contains(modeorder[i])) { + createModeConfig(modeorder[i], start.firstChild); + } + } + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + active.classList.add("active"); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + if (lib.config.fold_mode) { + rightPane.addEventListener("mousewheel", function (e) { + var morenodes = this.firstChild.morenodes; + if (morenodes) { + if (e.wheelDelta < 0) { + morenodes._onclick.call(morenodes, "expand"); + } + else if (this.scrollTop == 0) { + morenodes._onclick.call(morenodes, "unexpand"); + } + } + }, { passive: true }); + } + }()); + + (function () { + if (connectMenu) return; + var start = menuxpages.shift(); + var rightPane = start.lastChild; + + var clickMode = function () { + var active = this.parentNode.querySelector(".active"); + if (active === this) { + return; + } + active.classList.remove("active"); + active.link.remove(); + active = this; + active.classList.add("active"); + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + }; + + var clickAutoSkill = function (bool) { + var name = this._link.config._name; + var list = lib.config.autoskilllist; + if (bool) { + list.remove(name); + } + else { + list.add(name); + } + game.saveConfig("autoskilllist", list); + }; + var skilllistexpanded = game.expandSkills(lib.skilllist); + for (var i in lib.skill) { + if (!skilllistexpanded.contains(i)) continue; + if (lib.skill[i].frequent && lib.translate[i]) { + lib.configMenu.skill.config[i] = { + name: lib.translate[i + "_noconf"] || lib.translate[i], + init: true, + type: "autoskill", + onclick: clickAutoSkill, + intro: lib.translate[i + "_info"] + } + } + } + var clickBanSkill = function (bool) { + var name = this._link.config._name; + var list = lib.config.forbidlist; + if (bool) { + list.remove(name); + } + else { + list.add(name); + } + game.saveConfig("forbidlist", list); + }; + var forbid = lib.config.forbid; + if (!lib.config.forbidlist) { + game.saveConfig("forbidlist", []); + } + for (var i = 0; i < forbid.length; i++) { + var skip = false; + var str = ""; + var str2 = ""; + var str3 = ""; + for (var j = 0; j < forbid[i].length; j++) { + if (!lib.skilllist.contains(forbid[i][j])) { + skip = true; + break; + } + str += get.translation(forbid[i][j]) + "+"; + str2 += forbid[i][j] + "+"; + str3 += get.translation(forbid[i][j]) + ":" + lib.translate[forbid[i][j] + "_info"]; + if (j < forbid[i].length - 1) { + str3 += `
      `; + } + } + if (skip) continue; + str = str.slice(0, str.length - 1); + str2 = str2.slice(0, str2.length - 1); + + lib.configMenu.skill.config[str2] = { + name: str, + init: true, + type: "banskill", + onclick: clickBanSkill, + intro: str3 + } + } + + var updateView = null; + var updateAppearence = null; + var createModeConfig = function (mode, position) { + var info = lib.configMenu[mode]; + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", info.name, position, clickMode); + node.mode = mode; + // node._initLink=function(){ + node.link = page; + var map = {}; + if (info.config) { + var hiddenNodes = []; + var autoskillNodes = []; + var banskillNodes = []; + var custombanskillNodes = []; + var banskill; + + if (mode == "skill") { + var autoskillexpanded = false; + var banskillexpanded = false; + ui.create.div(".config.more", "自动发动
      >
      ", page, function () { + if (autoskillexpanded) { + this.classList.remove("on"); + for (var k = 0; k < autoskillNodes.length; k++) { + autoskillNodes[k].style.display = "none"; + } + } + else { + this.classList.add("on"); + for (var k = 0; k < autoskillNodes.length; k++) { + autoskillNodes[k].style.display = ""; + } + } + autoskillexpanded = !autoskillexpanded; + }); + banskill = ui.create.div(".config.more", "双将禁配
      >
      ", page, function () { + if (banskillexpanded) { + this.classList.remove("on"); + for (var k = 0; k < banskillNodes.length; k++) { + banskillNodes[k].style.display = "none"; + } + } + else { + this.classList.add("on"); + for (var k = 0; k < banskillNodes.length; k++) { + banskillNodes[k].style.display = ""; + } + } + banskillexpanded = !banskillexpanded; + }); + + var banskilladd = ui.create.div(".config.indent", `添加...`, page, function () { + this.nextSibling.classList.toggle("hidden"); + }); + banskilladd.style.display = "none"; + banskillNodes.push(banskilladd); + + var banskilladdNode = ui.create.div(".config.indent.hidden.banskilladd", page); + banskilladdNode.style.display = "none"; + banskillNodes.push(banskilladdNode); + + var matchBanSkill = function (skills1, skills2) { + if (skills1.length != skills2.length) return false; + for (var i = 0; i < skills1.length; i++) { + if (!skills2.contains(skills1[i])) return false; + } + return true; + } + var deleteCustomBanSkill = function () { + for (var i = 0; i < lib.config.customforbid.length; i++) { + if (matchBanSkill(lib.config.customforbid[i], this.parentNode.link)) { + lib.config.customforbid.splice(i--, 1); + break; + } + } + game.saveConfig("customforbid", lib.config.customforbid); + this.parentNode.remove(); + } + var createCustomBanSkill = function (skills) { + var node = ui.create.div(".config.indent.toggle"); + node.style.display = "none"; + node.link = skills; + banskillNodes.push(node); + custombanskillNodes.push(node); + var str = get.translation(skills[0]); + for (var i = 1; i < skills.length; i++) { + str += "+" + get.translation(skills[i]); + } + node.innerHTML = str; + var span = document.createElement("span"); + span.classList.add("cardpiledelete"); + span.innerHTML = "删除"; + span.onclick = deleteCustomBanSkill; + node.appendChild(span); + page.insertBefore(node, banskilladdNode.nextSibling); + return node; + }; + for (var i = 0; i < lib.config.customforbid.length; i++) { + createCustomBanSkill(lib.config.customforbid[i]); + } + (function () { + var list = []; + for (var i in lib.character) { + if (lib.character[i][3].length) + list.push([i, lib.translate[i]]); + } + + list.sort(function (a, b) { + a = a[0]; b = b[0]; + var aa = a, bb = b; + if (aa.includes("_")) { + aa = aa.slice(aa.indexOf("_") + 1); + } + if (bb.includes("_")) { + bb = bb.slice(bb.indexOf("_") + 1); + } + if (aa != bb) { + return aa > bb ? 1 : -1; + } + return a > b ? 1 : -1; + }); + + var list2 = []; + var skills = lib.character[list[0][0]][3]; + for (var i = 0; i < skills.length; i++) { + list2.push([skills[i], lib.translate[skills[i]]]); + } + + var selectname = ui.create.selectlist(list, list[0], banskilladdNode); + selectname.onchange = function () { + var skills = lib.character[this.value][3]; + skillopt.innerHTML = ""; + for (var i = 0; i < skills.length; i++) { + var option = document.createElement("option"); + option.value = skills[i]; + option.innerHTML = lib.translate[skills[i]]; + skillopt.appendChild(option); + } + }; + selectname.style.maxWidth = "85px"; + var skillopt = ui.create.selectlist(list2, list2[0], banskilladdNode); + + var span = document.createElement("span"); + span.innerHTML = "+"; + banskilladdNode.appendChild(span); + var br = document.createElement("br"); + banskilladdNode.appendChild(br); + + var selectname2 = ui.create.selectlist(list, list[0], banskilladdNode); + selectname2.onchange = function () { + var skills = lib.character[this.value][3]; + skillopt2.innerHTML = ""; + for (var i = 0; i < skills.length; i++) { + var option = document.createElement("option"); + option.value = skills[i]; + option.innerHTML = lib.translate[skills[i]]; + skillopt2.appendChild(option); + } + }; + selectname2.style.maxWidth = "85px"; + var skillopt2 = ui.create.selectlist(list2, list2[0], banskilladdNode); + var confirmbutton = document.createElement("button"); + confirmbutton.innerHTML = "确定"; + banskilladdNode.appendChild(confirmbutton); + + confirmbutton.onclick = function () { + var skills = [skillopt.value, skillopt2.value]; + if (skills[0] == skills[1]) { + skills.shift(); + } + if (!lib.config.customforbid) return; + for (var i = 0; i < lib.config.customforbid.length; i++) { + if (matchBanSkill(lib.config.customforbid[i], skills)) return; + } + lib.config.customforbid.push(skills); + game.saveConfig("customforbid", lib.config.customforbid); + createCustomBanSkill(skills).style.display = ""; + } + }()); + page.style.paddingBottom = "10px"; + } + var config = lib.config; + if (mode == "appearence") { + updateAppearence = function () { + info.config.update(config, map); + }; + } + else if (mode == "view") { + updateView = function () { + info.config.update(config, map); + }; + } + for (var j in info.config) { + if (j === "update") { + continue; + } + var cfg = copyObj(info.config[j]); + cfg._name = j; + if (!Object.prototype.hasOwnProperty.call(config, j)) { + if (cfg.type != "autoskill" && cfg.type != "banskill") { + game.saveConfig(j, cfg.init); + } + } + else { + cfg.init = config[j]; + } + if (!cfg.onclick) { + cfg.onclick = function (result) { + var cfg = this._link.config; + game.saveConfig(cfg._name, result); + if (cfg.onsave) { + cfg.onsave.call(this, result); + } + }; + } + if (info.config.update) { + if (mode == "appearence" || mode == "view") { + cfg.update = function () { + if (updateAppearence) { + updateAppearence(); + } + if (updateView) { + updateView(); + } + }; + } + else { + cfg.update = function () { + info.config.update(config, map); + }; + } + } + var cfgnode = createConfig(cfg); + if (cfg.type == "autoskill") { + autoskillNodes.push(cfgnode); + // cfgnode.style.transition="all 0s"; + cfgnode.classList.add("indent"); + // cfgnode.hide(); + cfgnode.style.display = "none"; + } + else if (cfg.type == "banskill") { + banskillNodes.push(cfgnode); + // cfgnode.style.transition="all 0s"; + cfgnode.classList.add("indent"); + // cfgnode.hide(); + cfgnode.style.display = "none"; + } + if (j == "import_data_button") { + ui.import_data_button = cfgnode; + cfgnode.hide(); + cfgnode.querySelector("button").onclick = function () { + var fileToLoad = this.previousSibling.files[0]; + if (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + if (!data) return; + try { + data = JSON.parse(lib.init.decode(data)); + if (!data || typeof data != "object") { + throw ("err"); + } + if (lib.db && (!data.config || !data.data)) { + throw ("err"); + } + } + catch (e) { + console.log(e); + alert("导入失败"); + return; + } + alert("导入成功"); + if (!lib.db) { + var noname_inited = localStorage.getItem("noname_inited"); + var onlineKey = localStorage.getItem(lib.configprefix + "key"); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem("noname_inited", noname_inited); + } + if (onlineKey) { + localStorage.setItem(lib.configprefix + "key", onlineKey); + } + for (var i in data) { + localStorage.setItem(i, data[i]); + } + } + else { + for (var i in data.config) { + game.putDB("config", i, data.config[i]); + lib.config[i] = data.config[i]; + } + for (var i in data.data) { + game.putDB("data", i, data.data[i]); + } + } + lib.init.background(); + game.reload(); + }; + fileReader.readAsText(fileToLoad, "UTF-8"); + } + } + } + else if (j == "import_music") { + cfgnode.querySelector("button").onclick = function () { + if (_status.music_importing) return; + _status.music_importing = true; + var fileToLoad = this.previousSibling.files[0]; + if (fileToLoad) { + if (!lib.config.customBackgroundMusic) lib.config.customBackgroundMusic = {}; + var name = fileToLoad.name; + if (name.includes(".")) { + name = name.slice(0, name.indexOf(".")); + } + var link = (game.writeFile ? "cdv_" : "custom_") + name; + if (lib.config.customBackgroundMusic[link]) { + if (!confirm("已经存在文件名称相同的背景音乐,是否仍然要继续导入?")) { _status.music_importing = false; return } + for (var i = 1; i < 1000; i++) { + if (!lib.config.customBackgroundMusic[link + "_" + i]) { + link = link + "_" + i; break; + } + } + } + var callback = function () { + var nodexx = ui.background_music_setting; + var nodeyy = nodexx._link.menu; + var nodezz = nodexx._link.config; + var musicname = link.slice(link.indexOf("_") + 1); + game.prompt("###请输入音乐的名称###" + musicname, true, function (str) { + if (str) musicname = str; + lib.config.customBackgroundMusic[link] = musicname; + lib.config.background_music = link; + lib.config.all.background_music.add(link); + game.saveConfig("background_music", link); + game.saveConfig("customBackgroundMusic", lib.config.customBackgroundMusic); + nodezz.item[link] = lib.config.customBackgroundMusic[link]; + var textMenu = ui.create.div("", lib.config.customBackgroundMusic[link], nodeyy, clickMenuItem, nodeyy.childElementCount - 2); + textMenu._link = link; + nodezz.updatex.call(nodexx, []); + _status.music_importing = false; + if (!_status._aozhan) game.playBackgroundMusic(); + }); + }; + if (game.writeFile) { + game.writeFile(fileToLoad, "audio/background", link + ".mp3", callback); + } + else { + game.putDB("audio", link, fileToLoad, callback); + } + } + } + } + else if (j == "extension_source") { + ui.extension_source = cfgnode; + cfgnode.updateInner = function () { + this._link.choosing.innerHTML = lib.config.extension_source; + } + } + map[j] = cfgnode; + if (!cfg.unfrequent) { + if (cfg.type == "autoskill") { + page.insertBefore(cfgnode, banskill); + } + else { + page.appendChild(cfgnode); + } + } + else { + // cfgnode.classList.add("auto-hide"); + hiddenNodes.push(cfgnode); + } + } + var expanded = false; + if (hiddenNodes.length) { + // ui.create.div(".config.more","更多
      >
      ",page,function(){ + // if(expanded){ + // this.classList.remove("on"); + // this.parentNode.classList.remove("expanded"); + // } + // else{ + // this.classList.add("on"); + // this.parentNode.classList.add("expanded"); + // } + // expanded=!expanded; + // }); + page.classList.add("morenodes"); + for (var k = 0; k < hiddenNodes.length; k++) { + page.appendChild(hiddenNodes[k]); + } + } + if (info.config.update) { + info.config.update(config, map); + } + } + // }; + // if(!get.config("menu_loadondemand")) node._initLink(); + return node; + }; + + for (var i in lib.configMenu) { + if (i != "others") createModeConfig(i, start.firstChild); + } + (function () { + if (!game.download && !lib.device) return; + var page = ui.create.div("#create-extension"); + var node = ui.create.div(".menubutton.large", "文件", start.firstChild, clickMode); + node.mode = "create"; + node._initLink = function () { + node.link = page; + var pageboard = ui.create.div(page); + + var importextensionexpanded = false; + var importExtension; + var extensionnode = ui.create.div(".config.more", "导入素材包
      >
      ", pageboard, function () { + if (importextensionexpanded) { + this.classList.remove("on"); + importExtension.style.display = "none"; + } + else { + this.classList.add("on"); + importExtension.style.display = ""; + } + importextensionexpanded = !importextensionexpanded; + }); + extensionnode.style.padding = "13px 33px 4px"; + extensionnode.style.left = "0px"; + importExtension = ui.create.div(".new_character.export.import", pageboard); + importExtension.style.padding = "0px 33px 10px"; + importExtension.style.display = "none"; + importExtension.style.width = "100%"; + importExtension.style.textAlign = "left"; + ui.create.div("", ``, importExtension); + var promptnode = ui.create.div("", `
      `, importExtension); + promptnode.style.display = "none"; + importExtension.firstChild.lastChild.onclick = function () { + if (promptnode.style.display != "none") return; + var fileToLoad = this.previousSibling.files[0]; + if (fileToLoad) { + promptnode.style.display = ""; + promptnode.firstChild.innerHTML = "正在解压..."; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + var loadData = function () { + var zip = new JSZip(); + zip.load(data); + var images = [], audios = [], fonts = [], directories = {}, directoryList = []; + Object.keys(zip.files).forEach(file => { + const parsedPath = lib.path.parse(file), directory = parsedPath.dir, fileExtension = parsedPath.ext.toLowerCase(); + if (directory.startsWith("audio") && (fileExtension == ".mp3" || fileExtension == ".ogg")) audios.push(file); + else if (directory.startsWith("font") && fileExtension == ".woff2") fonts.push(file); + else if (directory.startsWith("image") && (fileExtension == ".jpg" || fileExtension == ".png")) images.push(file); + else return; + if (!directories[directory]) { + directories[directory] = []; + directoryList.push(directory); + } + directories[directory].push(parsedPath.base); + }); + if (audios.length || fonts.length || images.length) { + var str = ""; + if (audios.length) { + str += audios.length + "个音频文件"; + } + if (fonts.length) { + if (str.length) str += "、" + str += fonts.length + "个字体文件"; + } + if (images.length) { + if (str.length) str += "、" + str += images.length + "个图片文件"; + } + var filelist = audios.concat(fonts).concat(images); + if (filelist.length > 200) { + str += ",导入时间可能较长"; + } + var assetLoaded = function () { + promptnode.firstChild.innerHTML = `导入成功。重新启动×`; + promptnode.firstChild.querySelectorAll("span")[0].onclick = game.reload; + promptnode.firstChild.querySelectorAll("span")[1].onclick = function () { + promptnode.style.display = "none"; + } + }; + if (confirm("本次将导入" + str + ",是否继续?")) { + promptnode.firstChild.innerHTML = `正在导入... 详细信息`; + promptnode.firstChild.querySelector("span.hrefnode").onclick = ui.click.consoleMenu; + if (lib.node && lib.node.fs) { + var writeFile = function () { + if (filelist.length) { + var str = filelist.shift(); + game.print(str.slice(str.lastIndexOf("/") + 1)); + lib.node.fs.writeFile(__dirname + "/" + str, zip.files[str].asNodeBuffer(), null, writeFile); + } + else { + assetLoaded(); + } + }; + game.ensureDirectory(directoryList, writeFile); + + } + else { + var getDirectory = function () { + if (directoryList.length) { + var dir = directoryList.shift(); + var filelist = directories[dir]; + window.resolveLocalFileSystemURL(lib.assetURL + dir, function (entry) { + var writeFile = function () { + if (filelist.length) { + var filename = filelist.shift(); + game.print(filename); + entry.getFile(filename, { create: true }, function (fileEntry) { + fileEntry.createWriter(function (fileWriter) { + fileWriter.onwriteend = writeFile; + fileWriter.onerror = function (e) { + game.print("Write failed: " + e.toString()); + }; + fileWriter.write(zip.files[dir + "/" + filename].asArrayBuffer()); + }); + }); + } + else { + getDirectory(); + } + }; + writeFile(); + }); + } + else { + assetLoaded(); + } + }; + game.ensureDirectory(directoryList, getDirectory); + } + } + else { + promptnode.style.display = "none"; + } + } + else { + alert("没有检测到素材"); + } + } + if (!window.JSZip) { + lib.init.js(lib.assetURL + "game", "jszip", loadData); + } + else { + loadData(); + } + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + } + } + + var dashboard = ui.create.div(pageboard); + var clickDash = function () { + ui.create.templayer(); + pageboard.hide(); + this.link.show(); + if (this.link.init) { + this.link.init(); + } + }; + var createDash = function (str1, str2, node) { + var dash = ui.create.div(".menubutton.large.dashboard"); + dashboard.appendChild(dash); + page.appendChild(node); + dash.link = node; + node.link = dash; + dash.listen(clickDash); + lib.setScroll(node); + ui.create.div("", str1, dash); + ui.create.div("", str2, dash); + }; + var createDash2 = function (str1, str2, path, page) { + var dash = ui.create.div(".menubutton.large.dashboard.dashboard2"); + page.appendChild(dash); + dash.listen(function () { + page.path = path; + enterDirectory(page, path); + }); + ui.create.div("", str1, dash); + ui.create.div("", str2, dash); + }; + var removeFile = function (selected, page) { + if (lib.node && lib.node.fs) { + var unlink = function () { + if (selected.length) { + lib.node.fs.unlink(__dirname + "/" + selected.shift().path, unlink); + } + else { + enterDirectory(page, page.currentpath); + } + } + unlink(); + } + else { + window.resolveLocalFileSystemURL(lib.assetURL + page.currentpath, function (entry) { + var unlink = function () { + if (selected.length) { + entry.getFile(selected.shift().filename, { create: false }, function (fileEntry) { + fileEntry.remove(unlink); + }); + } + else { + enterDirectory(page, page.currentpath); + } + } + unlink(); + }); + } + }; + var clickDirectory = function () { + if (_status.dragged) return; + var page = this.parentNode.parentNode.parentNode; + if (page.deletebutton.classList.contains("active")) { + if (confirm("确认删除" + this.innerHTML + "文件夹?(此操作不可撤销)")) { + if (lib.node && lib.node.fs) { + try { + var removeDirectory = function (path, callback) { + lib.node.fs.readdir(__dirname + "/" + path, function (err, list) { + if (err) { + console.log(err); + return; + } + var removeFile = function () { + if (list.length) { + var filename = list.shift(); + var url = __dirname + "/" + path + "/" + filename; + if (lib.node.fs.statSync(url).isDirectory()) { + removeDirectory(path + "/" + filename, removeFile); + } + else { + lib.node.fs.unlink(url, removeFile); + } + } + else { + lib.node.fs.rmdir(__dirname + "/" + path, callback); + } + } + removeFile(); + }); + }; + removeDirectory(this.path, function () { + enterDirectory(page, page.currentpath); + }); + } + catch (e) { + console.log(e); + } + } + else { + window.resolveLocalFileSystemURL(lib.assetURL + this.path, function (entry) { + entry.removeRecursively(function () { + enterDirectory(page, page.currentpath); + }); + }); + } + } + return; + } + enterDirectory(page, this.path); + }; + var clickFile = function () { + if (_status.dragged) return; + var page = this.parentNode.parentNode.parentNode; + if (page.deletebutton.classList.contains("active")) { + if (confirm("确认删除" + this.innerHTML + "?(此操作不可撤销)")) { + removeFile([this], page); + } + return; + } + this.classList.toggle("thundertext"); + page.clicked = true; + if (this.ext == "jpg" || this.ext == "png") { + if (this.classList.contains("thundertext")) { + if (!this.previewnode) { + this.previewnode = document.createElement("img"); + this.previewnode.src = lib.assetURL + this.path; + this.previewnode.width = "60"; + this.previewnode.style.maxHeight = "120px"; + this.parentNode.appendChild(this.previewnode); + } + } + else { + if (this.previewnode) { + this.previewnode.remove(); + delete this.previewnode; + } + } + } + else if (this.ext == "mp3" || this.ext == "ogg") { + if (this.classList.contains("thundertext")) { + if (!this.previewnode) { + this.previewnode = game.playAudio(this.path.slice(6)); + } + } + else { + if (this.previewnode) { + this.previewnode.remove(); + delete this.previewnode; + } + } + } + }; + var clickFileList = function () { + if (!this.parentNode) return; + if (this.parentNode.clicked) { + this.parentNode.clicked = false; + } + else { + var selected = Array.from(this.querySelectorAll("span.thundertext")); + for (var i = 0; i < selected.length; i++) { + selected[i].classList.remove("thundertext"); + if (selected[i].previewnode) { + selected[i].previewnode.remove(); + delete selected[i].previewnode; + } + } + } + }; + var enterDirectory = function (page, path) { + page.innerHTML = ""; + page.currentpath = path; + var backbutton = ui.create.div(".menubutton.round", "返", page, function () { + page.clicked = false; + clickFileList.call(filelist); + if (page.path == path) { + page.reset(); + } + else { + if (path.indexOf("/") == -1) { + enterDirectory(page, ""); + } + else { + enterDirectory(page, path.slice(0, path.lastIndexOf("/"))); + } + } + }); + backbutton.style.zIndex = 1; + backbutton.style.right = "10px"; + backbutton.style.bottom = "15px"; + + + var refresh = function () { + enterDirectory(page, path); + }; + var addbutton = ui.create.div(".menubutton.round", "添", page, function () { + var pos1 = this.getBoundingClientRect(); + var pos2 = ui.window.getBoundingClientRect(); + openMenu(this.menu, { + clientX: pos1.left + pos1.width + 5 - pos2.left, + clientY: pos1.top - pos2.top + }); + }); + addbutton.menu = ui.create.div(".menu"); + ui.create.div("", "添加文件", addbutton.menu, function () { + popupContainer.noclose = true; + }); + var createDir = function (str) { + if (lib.node && lib.node.fs) { + lib.node.fs.mkdir(__dirname + "/" + path + "/" + str, refresh); + } + else { + window.resolveLocalFileSystemURL(lib.assetURL + path, function (entry) { + entry.getDirectory(str, { create: true }, refresh); + }); + } + }; + ui.create.div("", "添加目录", addbutton.menu, function () { + ui.create.templayer(); + game.prompt("输入目录名称", function (str) { + if (str) { + createDir(str); + } + }); + }); + var input = document.createElement("input"); + input.className = "fileinput"; + input.type = "file"; + input.onchange = function () { + var fileToLoad = input.files[0]; + game.print(fileToLoad.name); + if (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + game.writeFile(e.target.result, path, fileToLoad.name, refresh); + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + } + }; + addbutton.menu.firstChild.appendChild(input); + addbutton.style.zIndex = 1; + addbutton.style.right = "10px"; + addbutton.style.bottom = "80px"; + + var deletebutton = ui.create.div(".menubutton.round", "删", page, function () { + if (!this.parentNode) return; + if (!this.classList.contains("active")) { + var selected = Array.from(filelist.querySelectorAll("span.thundertext")); + if (selected.length) { + if (confirm("一共要删除" + selected.length + "个文件,此操作不可撤销,是否确定?")) { + removeFile(selected, page); + } + } + else { + this.classList.add("active"); + } + } + else { + this.classList.remove("active"); + } + }); + deletebutton.style.zIndex = 1; + deletebutton.style.right = "10px"; + deletebutton.style.bottom = "145px"; + + page.backbutton = backbutton; + page.addbutton = addbutton; + page.deletebutton = deletebutton; + var filelist = ui.create.div(page); + filelist.classList.add("file-container"); + filelist.listen(clickFileList); + lib.setScroll(filelist); + game.getFileList(path, function (folders, files) { + var sort = function (a, b) { + if (a > b) return 1; + if (a < b) return -1; + return 0; + } + folders.sort(sort); + files.sort(sort); + var parent = path; + if (parent) { + parent += "/"; + } + for (var i = 0; i < folders.length; i++) { + if (!page.path && folders[i] == "app") continue; + var entry = ui.create.div("", "" + folders[i], filelist); + entry.firstChild.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickDirectory); + entry.firstChild.path = parent + folders[i] + } + for (var i = 0; i < files.length; i++) { + if (!page.path) { + if (files[i] == "app.html") continue; + if (files[i] == "main.js") continue; + if (files[i] == "package.json") continue; + } + var entry = ui.create.div("", "" + files[i], filelist); + entry.firstChild.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickFile); + entry.firstChild.ext = files[i].slice(files[i].lastIndexOf(".") + 1); + entry.firstChild.path = parent + files[i]; + entry.firstChild.filename = files[i]; + } + }); + }; + var dash1 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + page.reset = function () { + page.innerHTML = ""; + var backbutton = ui.create.div(".menubutton.round", "返", page, function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }); + backbutton.style.zIndex = 1; + backbutton.style.right = "10px"; + backbutton.style.bottom = "15px"; + var placeholder = ui.create.div(".placeholder", page); + placeholder.style.position = "relative"; + placeholder.style.display = "block"; + placeholder.style.width = "100%"; + placeholder.style.height = "14px"; + createDash2("将", "武将图片", "image/character", page); + createDash2("肤", "皮肤图片", "image/skin", page); + createDash2("卡", "卡牌图片", "image/card", page); + createDash2("模", "模式图片", "image/mode", page); + createDash2("始", "开始图片", "image/splash", page); + createDash2("景", "背景图片", "image/background", page); + }; + page.reset(); + return page; + }()); + var dash2 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + page.reset = function () { + page.innerHTML = ""; + var backbutton = ui.create.div(".menubutton.round", "返", page, function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }); + backbutton.style.zIndex = 1; + backbutton.style.right = "10px"; + backbutton.style.bottom = "15px"; + var placeholder = ui.create.div(".placeholder", page); + placeholder.style.position = "relative"; + placeholder.style.display = "block"; + placeholder.style.width = "100%"; + placeholder.style.height = "14px"; + createDash2("技", "技能配音", "audio/skill", page); + createDash2("卡", "男性卡牌", "audio/card/male", page); + createDash2("牌", "女性卡牌", "audio/card/female", page); + createDash2("亡", "阵亡配音", "audio/die", page); + createDash2("效", "游戏音效", "audio/effect", page); + createDash2("景", "背景音乐", "audio/background", page); + }; + page.reset(); + return page; + }()); + var dash3 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + page.path = "font"; + page.reset = function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }; + page.init = function () { + enterDirectory(page, "font"); + }; + return page; + }()); + var dash4 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + page.path = ""; + page.reset = function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }; + page.init = function () { + enterDirectory(page, ""); + }; + return page; + }()); + createDash("图", "图片文件", dash1); + createDash("音", "音频文件", dash2); + createDash("字", "字体文件", dash3); + createDash("全", "全部文件", dash4); + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + createModeConfig("others", start.firstChild); + + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + active.classList.add("active"); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + }()); + + (function () { + var start = menuxpages.shift(); + var rightPane = start.lastChild; + + var clickMode = function () { + var active = this.parentNode.querySelector(".active"); + if (active) { + if (active === this) { + return; + } + active.classList.remove("active"); + active.link.remove(); + } + this.classList.add("active"); + updateActive(this); + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + }; + updateActive = function (node) { + if (!node) { + node = start.firstChild.querySelector(".active"); + if (!node) { + return; + } + } + if (!node.link) { + node._initLink(); + } + for (var i = 0; i < node.link.childElementCount; i++) { + if (node.link.childNodes[i].updateBanned) { + node.link.childNodes[i].updateBanned(); + } + } + }; + var updateNodes = function () { + for (var i = 0; i < start.firstChild.childNodes.length; i++) { + var node = start.firstChild.childNodes[i]; + if (node.mode) { + if (node.mode.startsWith("mode_")) continue; + if (node.mode == "custom") continue; + if (connectMenu) { + if (!lib.config.connect_characters.contains(node.mode)) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + else { + if (lib.config.characters.contains(node.mode)) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + } + } + } + var togglePack = function (bool) { + var name = this._link.config._name; + if (connectMenu) { + if (!bool) { + lib.config.connect_characters.add(name); + } + else { + lib.config.connect_characters.remove(name); + } + game.saveConfig("connect_characters", lib.config.connect_characters); + } + else { + if (bool) { + lib.config.characters.add(name); + } + else { + lib.config.characters.remove(name); + } + game.saveConfig("characters", lib.config.characters); + } + updateNodes(); + }; + + var createModeConfig = function (mode, position, position2) { + var _info = lib.characterPack[mode]; + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", lib.translate[mode + "_character_config"], position, clickMode); + if (node.innerHTML.length >= 5) { + node.classList.add("smallfont"); + } + if (position2) { + position.insertBefore(node, position2); + } + node.mode = mode; + node._initLink = function () { + node.link = page; + page.node = node; + var list = []; + var boolAI = true; + var alterableSkills = []; + var alterableCharacters = []; + var charactersToAlter = []; + for (var i in _info) { + if (_info[i][4] && _info[i][4].contains("unseen")) continue; + if (connectMenu && lib.connectBanned.contains(i)) continue; + list.push(i); + if (boolAI && !lib.config.forbidai_user.contains(i)) boolAI = false; + for (var j = 0; j < _info[i][3].length; j++) { + if (!lib.skill[_info[i][3][j]]) { + continue; + } + if (lib.skill[_info[i][3][j]].alter) { + alterableSkills.add(_info[i][3][j]); + alterableCharacters.add(i); + if (lib.config.vintageSkills.contains(_info[i][3][j])) { + charactersToAlter.add(i); + } + } + } + } + alterableCharacters.sort(); + list.sort(lib.sort.character); + var list2 = list.slice(0); + var cfgnode = createConfig({ + name: "开启", + _name: mode, + init: connectMenu ? (!lib.config.connect_characters.contains(mode)) : (lib.config.characters.contains(mode)), + onclick: togglePack + }); + var cfgnodeAI = createConfig({ + name: "仅点将可用", + _name: mode, + init: boolAI, + intro: "将该武将包内的武将全部设置为仅点将可用", + onclick: function (bool) { + if (bool) { + for (var i = 0; i < list.length; i++) { + lib.config.forbidai_user.add(list[i]); + } + } + else { + for (var i = 0; i < list.length; i++) { + lib.config.forbidai_user.remove(list[i]); + } + } + game.saveConfig("forbidai_user", lib.config.forbidai_user); + }, + }); + if (!mode.startsWith("mode_")) { + cfgnodeAI.style.marginTop = "0px"; + page.appendChild(cfgnode); + page.appendChild(cfgnodeAI); + if (alterableCharacters.length) { + var cfgnode2 = createConfig({ + name: "新版替换", + _name: mode, + init: charactersToAlter.length == 0, + intro: "以下武将将被修改:" + get.translation(alterableCharacters), + onclick: function (bool) { + if (bool) { + for (var i = 0; i < alterableSkills.length; i++) { + lib.config.vintageSkills.remove(alterableSkills[i]); + lib.translate[alterableSkills[i] + "_info"] = lib.translate[alterableSkills[i] + "_info_alter"]; + } + } + else { + for (var i = 0; i < alterableSkills.length; i++) { + lib.config.vintageSkills.add(alterableSkills[i]); + lib.translate[alterableSkills[i] + "_info"] = lib.translate[alterableSkills[i] + "_info_origin"]; + } + } + game.saveConfig("vintageSkills", lib.config.vintageSkills); + } + }); + cfgnode2.style.marginTop = "0px"; + page.appendChild(cfgnode2); + } + } + else if (mode.startsWith("mode_extension")) { + page.appendChild(cfgnodeAI); + } + else { + page.style.paddingTop = "8px"; + } + var banCharacter = function (e) { + if (_status.clicked) { + _status.clicked = false; + return; + } + if (mode.startsWith("mode_") && !mode.startsWith("mode_extension_") && + mode != "mode_favourite" && mode != "mode_banned") { + if (!connectMenu && lib.config.show_charactercard) { + ui.click.charactercard(this.link, this, mode == "mode_guozhan" ? "guozhan" : true); + } + return; + } + ui.click.touchpop(); + this._banning = connectMenu ? "online" : "offline"; + if (!connectMenu && lib.config.show_charactercard) { + ui.click.charactercard(this.link, this); + } + else { + ui.click.intro.call(this, e); + } + _status.clicked = false; + delete this._banning; + }; + var updateBanned = function () { + var _list; + if (connectMenu) { + var mode = menux.pages[0].firstChild.querySelector(".active"); + if (mode && mode.mode) { + _list = lib.config["connect_" + mode.mode + "_banned"]; + } + } + else { + _list = lib.config[get.mode() + "_banned"]; + } + if (_list && _list.contains(this.link)) { + this.classList.add("banned"); + } + else { + this.classList.remove("banned"); + } + }; + if (lib.characterSort[mode]) { + var listb = []; + if (!connectMenu) { + listb = lib.config[get.mode() + "_banned"] || []; + } + else { + var modex = menux.pages[0].firstChild.querySelector(".active"); + if (modex && modex.mode) { + listb = lib.config["connect_" + modex.mode + "_banned"]; + } + } + for (var pak in lib.characterSort[mode]) { + var info = lib.characterSort[mode][pak]; + var listx = []; + var boolx = false; + for (var ii = 0; ii < list2.length; ii++) { + if (info.contains(list2[ii])) { + listx.add(list2[ii]); + if (!listb.contains(list2[ii])) boolx = true; + list2.splice(ii--, 1); + } + } + if (listx.length) { + var cfgnodeY = { + name: lib.translate[pak], + _name: pak, + init: boolx, + onclick: function (bool) { + var banned = []; + if (connectMenu) { + var modex = menux.pages[0].firstChild.querySelector(".active"); + if (modex && modex.mode) { + banned = lib.config["connect_" + modex.mode + "_banned"]; + } + } + else if (_status.connectMode) return; + else banned = lib.config[get.mode() + "_banned"] || []; + var listx = lib.characterSort[mode][this._link.config._name]; + if (bool) { + for (var i = 0; i < listx.length; i++) { + banned.remove(listx[i]); + } + } + else { + for (var i = 0; i < listx.length; i++) { + banned.add(listx[i]); + } + } + game.saveConfig(connectMenu ? ("connect_" + modex.mode + "_banned") : (get.mode() + "_banned"), banned); + updateActive(); + }, + }; + if (mode.startsWith("mode_") && !mode.startsWith("mode_extension_") && !mode.startsWith("mode_guozhan")) { + cfgnodeY.clear = true; + delete cfgnodeY.onclick; + } + var cfgnodeX = createConfig(cfgnodeY); + page.appendChild(cfgnodeX); + var buttons = ui.create.buttons(listx, "character", page); + for (var i = 0; i < buttons.length; i++) { + buttons[i].classList.add("noclick"); + buttons[i].listen(banCharacter); + ui.create.rarity(buttons[i]); + buttons[i].node.hp.style.transition = "all 0s"; + buttons[i].node.hp._innerHTML = buttons[i].node.hp.innerHTML; + if (mode != "mode_banned") { + buttons[i].updateBanned = updateBanned; + } + } + } + } + if (list2.length) { + var cfgnodeX = createConfig({ + name: "其他", + _name: "others", + clear: true, + }); + page.appendChild(cfgnodeX); + var buttons = ui.create.buttons(list2, "character", page); + for (var i = 0; i < buttons.length; i++) { + buttons[i].classList.add("noclick"); + buttons[i].listen(banCharacter); + ui.create.rarity(buttons[i]); + buttons[i].node.hp.style.transition = "all 0s"; + buttons[i].node.hp._innerHTML = buttons[i].node.hp.innerHTML; + if (mode != "mode_banned") { + buttons[i].updateBanned = updateBanned; + } + } + } + } + else { + var buttons = ui.create.buttons(list, "character", page); + for (var i = 0; i < buttons.length; i++) { + buttons[i].classList.add("noclick"); + ui.create.rarity(buttons[i]); + buttons[i].listen(banCharacter); + buttons[i].node.hp.style.transition = "all 0s"; + buttons[i].node.hp._innerHTML = buttons[i].node.hp.innerHTML; + if (mode != "mode_banned") { + buttons[i].updateBanned = updateBanned; + } + } + } + page.classList.add("menu-buttons"); + page.classList.add("leftbutton"); + if (!connectMenu) { + if (lib.config.all.sgscharacters.contains(mode)) { + ui.create.div(".config.pointerspan", `该武将包不可被隐藏`, page); + } + else if (!mode.startsWith("mode_")) { + ui.create.div(".config.pointerspan", "隐藏武将包", page, function () { + if (this.firstChild.innerHTML == "隐藏武将包") { + if (confirm("真的要隐藏“" + get.translation(mode + "_character_config") + "”武将包吗?\n建议使用“关闭”而不是“隐藏”功能,否则将会影响其他相关武将包的正常运行!")) { + this.firstChild.innerHTML = "武将包将在重启后隐藏"; + lib.config.hiddenCharacterPack.add(mode); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + } + else { + this.firstChild.innerHTML = "隐藏武将包"; + lib.config.hiddenCharacterPack.remove(mode); + } + game.saveConfig("hiddenCharacterPack", lib.config.hiddenCharacterPack); + }); + } + } + }; + if (!get.config("menu_loadondemand")) node._initLink(); + return node; + }; + if (lib.config.show_favourite_menu && !connectMenu && Array.isArray(lib.config.favouriteCharacter)) { + lib.characterPack.mode_favourite = {}; + for (var i = 0; i < lib.config.favouriteCharacter.length; i++) { + var favname = lib.config.favouriteCharacter[i]; + if (lib.character[favname]) { + lib.characterPack.mode_favourite[favname] = lib.character[favname]; + } + } + var favouriteCharacterNode = createModeConfig("mode_favourite", start.firstChild); + if (!favouriteCharacterNode.link) favouriteCharacterNode._initLink(); + ui.favouriteCharacter = favouriteCharacterNode.link; + if (get.is.empty(lib.characterPack.mode_favourite)) { + ui.favouriteCharacter.node.style.display = "none"; + } + delete lib.characterPack.mode_favourite; + } + if (!connectMenu && lib.config.show_ban_menu) { + lib.characterPack.mode_banned = {}; + for (var i = 0; i < lib.config.all.mode.length; i++) { + var banned = lib.config[lib.config.all.mode[i] + "_banned"]; + if (banned) { + for (var j = 0; j < banned.length; j++) { + if (lib.character[banned[j]]) { + lib.characterPack.mode_banned[banned[j]] = lib.character[banned[j]]; + } + } + } + } + var bannednode = createModeConfig("mode_banned", start.firstChild); + if (get.is.empty(lib.characterPack.mode_banned)) { + bannednode.style.display = "none"; + } + delete lib.characterPack.mode_banned; + } + var characterlist = connectMenu ? lib.connectCharacterPack : lib.config.all.characters; + for (var i = 0; i < characterlist.length; i++) { + createModeConfig(characterlist[i], start.firstChild); + } + if (!connectMenu) Object.keys(lib.characterPack).forEach(key => { + if (key.startsWith("mode_")) createModeConfig(key, start.firstChild); + }); + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + if (active.style.display == "none") { + active = active.nextSibling; + if (active.style.display == "none") { + active = active.nextSibling; + } + } + active.classList.add("active"); + updateActive(active); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + + if (!connectMenu) { + var node1 = ui.create.div(".lefttext", "全部开启", start.firstChild, function () { + game.saveConfig("characters", lib.config.all.characters); + updateNodes(); + }); + var node2 = ui.create.div(".lefttext", "恢复默认", start.firstChild, function () { + game.saveConfig("characters", lib.config.defaultcharacters); + updateNodes(); + }); + node1.style.marginTop = "12px"; + node2.style.marginTop = "7px"; + } + + updateNodes(); + }()); + + (function () { + var start = menuxpages.shift(); + var rightPane = start.lastChild; + var pileCreated = false; + var recreatePile = function () { + lib.config.customcardpile["当前牌堆"] = [lib.config.bannedpile, lib.config.addedpile]; + game.saveConfig("customcardpile", lib.config.customcardpile); + game.saveConfig("cardpilename", "当前牌堆", true); + pileCreated = false; + }; + + var clickMode = function () { + var active = this.parentNode.querySelector(".active"); + if (active === this) { + return; + } + active.classList.remove("active"); + active.link.remove(); + active = this; + this.classList.add("active"); + updateActiveCard(this); + if (this.mode == "cardpile") { + this.create(); + } + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + }; + updateActiveCard = function (node) { + if (!node) { + node = start.firstChild.querySelector(".active"); + if (!node) { + return; + } + } + if (!node.link) node._initLink(); + for (var i = 0; i < node.link.childElementCount; i++) { + if (node.link.childNodes[i].updateBanned) { + node.link.childNodes[i].updateBanned(); + } + } + }; + var updateNodes = function () { + for (var i = 0; i < start.firstChild.childNodes.length; i++) { + var node = start.firstChild.childNodes[i]; + if (node.mode) { + if (node.mode.startsWith("mode_")) continue; + if (node.mode == "custom") continue; + if (node.mode == "cardpile") continue; + if (connectMenu) { + if (!lib.config.connect_cards.contains(node.mode)) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + else { + if (lib.config.cards.contains(node.mode)) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + } + } + } + var togglePack = function (bool) { + var name = this._link.config._name; + if (connectMenu) { + if (!bool) { + lib.config.connect_cards.add(name); + } + else { + lib.config.connect_cards.remove(name); + } + game.saveConfig("connect_cards", lib.config.connect_cards); + } + else { + if (bool) { + lib.config.cards.add(name); + } + else { + lib.config.cards.remove(name); + } + game.saveConfig("cards", lib.config.cards); + } + updateNodes(); + }; + var toggleCardPile = function (bool) { + var name = this._link.config._name; + var number = this._link.config._number; + if (!lib.config.bannedpile[name]) { + lib.config.bannedpile[name] = []; + } + if (bool) { + lib.config.bannedpile[name].remove(number); + } + else { + lib.config.bannedpile[name].add(number); + } + recreatePile(); + } + + var createModeConfig = function (mode, position) { + var info = lib.cardPack[mode]; + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", lib.translate[mode + "_card_config"], position, clickMode); + if (node.innerHTML.length >= 5) { + node.classList.add("smallfont"); + } + node.mode = mode; + node._initLink = function () { + node.link = page; + var list = []; + for (var i = 0; i < info.length; i++) { + if (!lib.card[info[i]] || (lib.card[info[i]].derivation && mode != "mode_derivation")) continue; + list.push([get.translation(get.type(info[i], "trick")), "", info[i]]); + } + var sortCard = function (card) { + var type = lib.card[card[2]].type; + var subtype = lib.card[card[2]].subtype; + if (lib.cardType[subtype]) { + return lib.cardType[subtype]; + } + if (lib.cardType[type]) { + return lib.cardType[type]; + } + switch (type) { + case "basic": return 0; + case "chess": return 1.5; + case "trick": return 2; + case "delay": return 3; + case "equip": { + switch (lib.card[card[2]].subtype) { + case "equip1": return 4.1; + case "equip2": return 4.2; + case "equip3": return 4.3; + case "equip4": return 4.4; + case "equip5": return 4.5; + default: return 4; + } + } + case "zhenfa": return 5; + default: return 6; + } + } + list.sort(function (a, b) { + var sort1 = sortCard(a); + var sort2 = sortCard(b); + if (sort1 == sort2) { + return (b[2] < a[2]) ? 1 : -1; + } + else if (sort1 > sort2) { + return 1; + } + else { + return -1; + } + }); + var cfgnode = createConfig({ + name: "开启", + _name: mode, + init: lib.config.cards.contains(mode), + onclick: togglePack + }); + if (!mode.startsWith("mode_")) { + page.appendChild(cfgnode); + } + else { + page.style.paddingTop = "8px"; + } + var banCard = function (e) { + if (_status.clicked) { + _status.clicked = false; + return; + } + if (mode.startsWith("mode_") && !mode.startsWith("mode_extension_") && mode != "mode_banned") { + return; + } + ui.click.touchpop(); + this._banning = connectMenu ? "online" : "offline"; + ui.click.intro.call(this, e); + _status.clicked = false; + delete this._banning; + }; + var updateBanned = function () { + var list; + if (connectMenu) { + var mode = menux.pages[0].firstChild.querySelector(".active"); + if (mode && mode.mode) { + list = lib.config["connect_" + mode.mode + "_bannedcards"]; + } + } + else { + list = lib.config[get.mode() + "_bannedcards"]; + } + if (list && list.contains(this.link[2])) { + this.classList.add("banned"); + } + else { + this.classList.remove("banned"); + } + }; + var buttons = ui.create.buttons(list, "vcard", page); + for (var i = 0; i < buttons.length; i++) { + buttons[i].classList.add("noclick"); + buttons[i].listen(banCard); + if (mode != "mode_banned") { + buttons[i].updateBanned = updateBanned; + } + } + page.classList.add("menu-buttons"); + page.classList.add("leftbutton"); + if (!connectMenu && !lib.config.all.sgscards.contains(mode) && !mode.startsWith("mode_")) { + ui.create.div(".config.pointerspan", "隐藏卡牌包", page, function () { + if (this.firstChild.innerHTML == "隐藏卡牌包") { + this.firstChild.innerHTML = "卡牌包将在重启后隐藏"; + lib.config.hiddenCardPack.add(mode); + if (!lib.config.prompt_hidepack) { + alert("隐藏的扩展包可通过选项-其它-重置隐藏内容恢复"); + game.saveConfig("prompt_hidepack", true); + } + } + else { + this.firstChild.innerHTML = "隐藏卡牌包"; + lib.config.hiddenCardPack.remove(mode); + } + game.saveConfig("hiddenCardPack", lib.config.hiddenCardPack); + }); + } + if (!mode.startsWith("mode_") && lib.cardPile[mode]) { + var cardpileNodes = []; + var cardpileexpanded = false; + if (!lib.config.bannedpile[mode]) { + lib.config.bannedpile[mode] = []; + } + if (!lib.config.addedpile[mode]) { + lib.config.addedpile[mode] = []; + } + ui.create.div(".config.more.pile", "编辑牌堆
      >
      ", page, function () { + if (cardpileexpanded) { + this.classList.remove("on"); + for (var k = 0; k < cardpileNodes.length; k++) { + cardpileNodes[k].style.display = "none"; + } + } + else { + this.classList.add("on"); + for (var k = 0; k < cardpileNodes.length; k++) { + cardpileNodes[k].style.display = ""; + } + } + cardpileexpanded = !cardpileexpanded; + }); + var cfgnode = ui.create.div(page, ".config.pointerspan.cardpilecfg.toggle"); + var cfgaddcard = ui.create.node("button", "", "添加卡牌", cfgnode, function () { + this.parentNode.nextSibling.classList.toggle("hidden"); + }); + var cfgbancard = ui.create.node("button", "", "全部关闭", cfgnode, function () { + for (var i = 0; i < cardpileNodes.length; i++) { + if (cardpileNodes[i].type == "defaultcards" && cardpileNodes[i].classList.contains("on")) { + clickToggle.call(cardpileNodes[i]); + } + } + }); + var cfgenablecard = ui.create.node("button", "", "全部开启", cfgnode, function () { + for (var i = 0; i < cardpileNodes.length; i++) { + if (cardpileNodes[i].type == "defaultcards" && !cardpileNodes[i].classList.contains("on")) { + clickToggle.call(cardpileNodes[i]); + } + } + }); + cfgbancard.style.marginLeft = "5px"; + cfgenablecard.style.marginLeft = "5px"; + cardpileNodes.push(cfgnode); + cfgnode.style.display = "none"; + cfgnode.classList.add("cardpilecfg"); + cfgnode.classList.add("toggle"); + cfgnode.style.marginTop = "5px"; + page.appendChild(cfgnode); + + var cardpileadd = ui.create.div(".config.toggle.hidden.cardpilecfg.cardpilecfgadd", page); + var pileaddlist = []; + for (var i = 0; i < lib.config.cards.length; i++) { + if (!lib.cardPack[lib.config.cards[i]]) continue; + for (var j = 0; j < lib.cardPack[lib.config.cards[i]].length; j++) { + var cname = lib.cardPack[lib.config.cards[i]][j]; + pileaddlist.push([cname, get.translation(cname)]); + if (cname == "sha") { + pileaddlist.push(["huosha", "火杀"]); + pileaddlist.push(["leisha", "雷杀"]); + pileaddlist.push(["icesha", "冰杀"]); + pileaddlist.push(["cisha", "刺杀"]); + } + } + } + var cardpileaddname = ui.create.selectlist(pileaddlist, null, cardpileadd); + cardpileaddname.style.width = "75px"; + cardpileaddname.style.marginRight = "2px"; + cardpileaddname.style.marginLeft = "-1px"; + var cardpileaddsuit = ui.create.selectlist([ + ["heart", "红桃"], + ["diamond", "方片"], + ["club", "梅花"], + ["spade", "黑桃"], + ], null, cardpileadd); + cardpileaddsuit.style.width = "53px"; + cardpileaddsuit.style.marginRight = "2px"; + var cardpileaddnumber = ui.create.selectlist([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 + ], null, cardpileadd); + cardpileaddnumber.style.width = "43px"; + cardpileaddnumber.style.marginRight = "2px"; + var button = document.createElement("button"); + button.innerHTML = "确定"; + button.style.width = "40px"; + var deletecard = function () { + this.parentNode.remove(); + var info = this.parentNode._info; + var list = lib.config.addedpile[mode]; + for (var i = 0; i < list.length; i++) { + if (list[i][0] == info[0] && list[i][1] == info[1] && list[i][2] == info[2]) { + list.splice(i, 1); break; + } + } + recreatePile(); + }; + button.onclick = function () { + var card = [ + cardpileaddsuit.value, + cardpileaddnumber.value, + cardpileaddname.value, + ]; + lib.config.addedpile[mode].push(card); + recreatePile(); + var cfgnode = ui.create.div(".config.toggle.cardpilecfg"); + cfgnode._info = card; + cfgnode.innerHTML = get.translation(card[2]) + " " + get.translation(card[0]) + get.strNumber(card[1]); + var cfgnodedelete = document.createElement("span"); + cfgnodedelete.classList.add("cardpiledelete"); + cfgnodedelete.innerHTML = "删除"; + cfgnodedelete.onclick = deletecard; + cfgnode.appendChild(cfgnodedelete); + page.insertBefore(cfgnode, cardpileadd.nextSibling); + }; + cardpileadd.appendChild(button); + cardpileadd.style.whiteSpace = "nowrap"; + cardpileNodes.push(cardpileadd); + + for (var i = 0; i < lib.config.addedpile[mode].length; i++) { + var card = lib.config.addedpile[mode][i]; + var cfgnode = ui.create.div(".config.toggle.cardpilecfg"); + cfgnode._info = card; + cfgnode.innerHTML = get.translation(card[2]) + " " + get.translation(card[0]) + card[1]; + var cfgnodedelete = document.createElement("span"); + cfgnodedelete.classList.add("cardpiledelete"); + cfgnodedelete.innerHTML = "删除"; + cfgnodedelete.onclick = deletecard; + cfgnode.appendChild(cfgnodedelete); + cfgnode.style.display = "none"; + cardpileNodes.push(cfgnode); + page.appendChild(cfgnode); + } + + for (var i = 0; i < lib.cardPile[mode].length; i++) { + var card = lib.cardPile[mode][i]; + var cfgnode = createConfig({ + name: ((card[2] == "sha" && card[3]) ? (get.translation(card[3])) : "") + get.translation(card[2]) + " " + get.translation(card[0]) + get.strNumber(card[1]), + _number: i, + _name: mode, + init: !lib.config.bannedpile[mode].contains(i), + onclick: toggleCardPile + }); + cfgnode.type = "defaultcards"; + cardpileNodes.push(cfgnode); + cfgnode.style.display = "none"; + cfgnode.classList.add("cardpilecfg"); + page.appendChild(cfgnode); + } + ui.create.div(".menuplaceholder", page); + } + }; + if (!get.config("menu_loadondemand")) node._initLink(); + return node; + }; + if (!connectMenu && lib.config.show_ban_menu) { + lib.cardPack.mode_banned = []; + for (var i = 0; i < lib.config.all.mode.length; i++) { + var banned = lib.config[lib.config.all.mode[i] + "_bannedcards"]; + if (banned) { + for (var j = 0; j < banned.length; j++) { + lib.cardPack.mode_banned.add(banned[j]); + } + } + } + var bannednode = createModeConfig("mode_banned", start.firstChild); + if (lib.cardPack.mode_banned.length == 0) { + bannednode.style.display = "none"; + } + delete lib.cardPack.mode_banned; + } + for (var i = 0; i < lib.config.all.cards.length; i++) { + if (connectMenu && !lib.connectCardPack.contains(lib.config.all.cards[i])) continue; + createModeConfig(lib.config.all.cards[i], start.firstChild); + } + if (!connectMenu) Object.keys(lib.cardPack).forEach(key => { + if (key.startsWith("mode_")) createModeConfig(key, start.firstChild); + }); + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + if (active.style.display == "none") { + active = active.nextSibling; + } + active.classList.add("active"); + updateActiveCard(active); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + + (function () { + if (connectMenu) return; + var page = ui.create.div(".menu-buttons"); + var node = ui.create.div(".menubutton.large", "牌堆", clickMode); + start.firstChild.insertBefore(node, start.firstChild.querySelector(".lefttext")); + node.link = page; + node.mode = "cardpile"; + node.create = function () { + if (pileCreated) return; + pileCreated = true; + page.innerHTML = ""; + + var pileList = null; + var createList = function () { + if (pileList) { + pileList.remove(); + } + var list = ["默认牌堆"]; + if (lib.config.customcardpile["当前牌堆"]) { + list.push("当前牌堆"); + } + for (var i in lib.config.customcardpile) { + list.add(i); + } + var currentpile = get.config("cardpilename"); + if (!currentpile) { + if (list.contains("当前牌堆")) { + currentpile = "当前牌堆"; + } + else { + currentpile = "默认牌堆"; + } + } + pileList = ui.create.selectlist(list, currentpile, pileChoose, function (e) { + game.saveConfig("cardpilename", this.value, true); + restart.style.display = ""; + }); + pileList.style.float = "right"; + } + var pileChoose = ui.create.div(".config.toggle.cardpilecfg.nomarginleft", "选择牌堆", page); + createList(); + + var pileDel = function () { + delete lib.config.customcardpile[this.parentNode.link]; + this.parentNode.remove(); + game.saveConfig("customcardpile", lib.config.customcardpile); + for (var i in lib.config.mode_config) { + if (i == "global") continue; + if (lib.config.mode_config[i].cardpilename == this.parentNode.link) { + game.saveConfig("cardpilename", null, i); + } + } + createList(); + }; + + var restart = ui.create.div(".config.more", "重新启动", game.reload, page); + restart.style.display = "none"; + var createPileNode = function (name) { + var node = ui.create.div(".config.toggle.cardpilecfg.nomarginleft", name); + node.link = name; + var del = document.createElement("span"); + del.innerHTML = "删除"; + del.classList.add("cardpiledelete"); + del.onclick = pileDel; + node.appendChild(del); + if (name == "当前牌堆") { + page.insertBefore(node, pileChoose.nextSibling); + } + else { + page.insertBefore(node, restart); + } + }; + for (var i in lib.config.customcardpile) { + createPileNode(i); + } + var exportCardPile; + ui.create.div(".config.more", "保存当前牌堆
      >
      ", page, function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + exportCardPile.classList.remove("hidden"); + } + else { + exportCardPile.classList.add("hidden"); + } + }); + exportCardPile = ui.create.div(".config.cardpileadd.indent", page); + exportCardPile.classList.add("hidden"); + ui.create.div("", `名称:`, exportCardPile); + var input = exportCardPile.firstChild.lastChild.previousSibling; + input.value = "自定义牌堆"; + input.style.marginRight = "3px"; + input.style.width = "120px"; + exportCardPile.firstChild.lastChild.onclick = function () { + var name = input.value; + var ok = true; + if (lib.config.customcardpile[name] || name == "默认牌堆" || name == "当前牌堆") { + for (var i = 1; i <= 1000; i++) { + if (!lib.config.customcardpile[name + "(" + i + ")"]) { + name = name + "(" + i + ")"; + break; + } + } + } + lib.config.customcardpile[name] = [lib.config.bannedpile, lib.config.addedpile]; + delete lib.config.customcardpile["当前牌堆"]; + for (var i in lib.mode) { + if (lib.config.mode_config[i] && + (lib.config.mode_config[i].cardpilename == "当前牌堆" || !lib.config.mode_config[i].cardpilename)) { + game.saveConfig("cardpilename", name, i); + } + } + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].link == "当前牌堆") { + page.childNodes[i].remove(); + break; + } + } + game.saveConfig("customcardpile", lib.config.customcardpile); + createPileNode(name); + createList(); + }; + } + }()); + + if (!connectMenu) { + var node1 = ui.create.div(".lefttext", "全部开启", start.firstChild, function () { + game.saveConfig("cards", lib.config.all.cards); + updateNodes(); + }); + var node2 = ui.create.div(".lefttext", "恢复默认", start.firstChild, function () { + game.saveConfig("cards", lib.config.defaultcards); + updateNodes(); + }); + node1.style.marginTop = "12px"; + node2.style.marginTop = "7px"; + } + + updateNodes(); + }()); + + (function () { + if (connectMenu) return; + var start = menuxpages.shift(); + var rightPane = start.lastChild; + + var clickMode = function () { + if (this.mode == "get") { + this.update(); + } + var active = this.parentNode.querySelector(".active"); + if (active === this) { + return; + } + active.classList.remove("active"); + active.link.remove(); + active = this; + this.classList.add("active"); + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + updateNodes(); + }; + ui.click.extensionTab = function (name) { + ui.click.menuTab("扩展"); + for (var i = 0; i < start.firstChild.childElementCount; i++) { + if (start.firstChild.childNodes[i].innerHTML == name) { + clickMode.call(start.firstChild.childNodes[i]); + break; + } + } + } + var updateNodes = function () { + for (var i = 0; i < start.firstChild.childNodes.length; i++) { + var node = start.firstChild.childNodes[i]; + if (node.mode == "get") continue; + if (node.mode == "create") continue; + if (node.mode && node.mode.startsWith("extension_")) { + if (lib.config[node.mode + "_enable"]) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + else { + if (lib.config.plays.contains(node.mode)) { + node.classList.remove("off"); + if (node.link) node.link.firstChild.classList.add("on"); + } + else { + node.classList.add("off"); + if (node.link) node.link.firstChild.classList.remove("on"); + } + } + } + } + var togglePack = function (bool) { + var name = this._link.config._name; + if (name.startsWith("extension_")) { + if (bool) { + game.saveConfig(name, true); + } + else { + game.saveConfig(name, false); + } + } + else { + name = name.slice(0, name.indexOf("_enable_playpackconfig")); + if (bool) { + lib.config.plays.add(name); + } + else { + lib.config.plays.remove(name); + } + game.saveConfig("plays", lib.config.plays); + } + if (this.onswitch) { + this.onswitch(bool); + } + updateNodes(); + }; + + var createModeConfig = function (mode, position) { + var page = ui.create.div(""); + page.style.paddingBottom = "10px"; + var node; + if (mode.startsWith("extension_")) { + node = ui.create.div(".menubutton.large", mode.slice(10), position, clickMode); + } + else { + node = ui.create.div(".menubutton.large", lib.translate[mode + "_play_config"], position, clickMode); + } + if (node.innerHTML.length >= 5) { + node.classList.add("smallfont"); + } + node.mode = mode; + // node._initLink=function(){ + node.link = page; + for (var i in lib.extensionMenu[mode]) { + if (i == "game") continue; + var cfg = copyObj(lib.extensionMenu[mode][i]); + var j; + if (mode.startsWith("extension_")) { + j = mode + "_" + i; + } + else { + j = mode + "_" + i + "_playpackconfig"; + } + cfg._name = j; + if (!Object.prototype.hasOwnProperty.call(lib.config, j)) { + game.saveConfig(j, cfg.init); + } + else { + cfg.init = lib.config[j]; + } + + if (i == "enable") { + cfg.onclick = togglePack; + } + else if (!lib.extensionMenu[mode][i].onclick) { + cfg.onclick = function (result) { + var cfg = this._link.config; + game.saveConfig(cfg._name, result); + }; + } + var cfgnode = createConfig(cfg); + if (cfg.onswitch) { + cfgnode.onswitch = cfg.onswitch; + } + page.appendChild(cfgnode); + } + // }; + // if(!get.config("menu_loadondemand")) node._initLink(); + return node; + }; + for (var i in lib.extensionMenu) { + if (lib.config.all.stockextension.contains(i) && !lib.config.all.plays.contains(i)) continue; + if (lib.config.hiddenPlayPack.contains(i)) continue; + createModeConfig(i, start.firstChild); + } + (function () { + if (!lib.device && !lib.db) return; + if (lib.config.show_extensionmaker == false) return; + var page = ui.create.div("#create-extension"); + var node = ui.create.div(".menubutton.large", "制作扩展", start.firstChild, clickMode); + node.mode = "create"; + game.editExtension = function (name) { + node._initLink(); + game.editExtension(name); + }; + node._initLink = function () { + node.link = page; + var pageboard = ui.create.div(page); + var inputExtLine = ui.create.div(pageboard); + inputExtLine.style.transition = "all 0s"; + inputExtLine.style.padding = "10px"; + inputExtLine.style.height = "22px"; + inputExtLine.style.lineHeight = "22px"; + inputExtLine.style.whiteSpace = "nowrap"; + inputExtLine.style.overflow = "visible"; + var inputExtSpan = document.createElement("span"); + inputExtSpan.innerHTML = "扩展名:"; + inputExtLine.appendChild(inputExtSpan); + var inputExtName = document.createElement("input"); + inputExtName.type = "text"; + inputExtName.value = "无名扩展"; + inputExtName.style.width = "80px"; + inputExtName.style.textAlign = "center"; + inputExtLine.appendChild(inputExtName); + + var buttonConfirmOnclick = function () { + buttonConfirm.style.display = "none"; + inputExtSpan.style.display = "none"; + inputExtName.style.display = "none"; + authorExtLine.style.display = "none"; + introExtLine.style.display = "none"; + forumExtLine.style.display = "none"; + diskExtLine.style.display = "none"; + versionExtLine.style.display = "none"; + okExtLine.style.display = "none"; + inputExtLine.style.padding = "10px"; + buttonRename.style.display = ""; + buttonSave.style.display = ""; + buttonReset.style.display = ""; + buttonExport.style.display = ""; + inputExtSpan.innerHTML = "扩展名称:"; + inputExtName.style.width = "100px"; + inputExtName.style.textAlign = ""; + + dashboard.style.display = ""; + }; + var createExtLine = function (str, str2) { + var infoExtLine = ui.create.div(pageboard); + infoExtLine.style.display = "none"; + infoExtLine.style.padding = "0 10px 10px 10px"; + infoExtLine.style.height = "22px"; + infoExtLine.style.lineHeight = "22px"; + infoExtLine.style.whiteSpace = "nowrap"; + infoExtLine.style.overflow = "visible"; + if (typeof str == "boolean") { + var inputConfirm = document.createElement("button"); + inputConfirm.innerHTML = "确定"; + inputConfirm.onclick = buttonConfirmOnclick; + infoExtLine.appendChild(inputConfirm); + return infoExtLine; + } + var infoExtSpan = document.createElement("span"); + infoExtSpan.innerHTML = str + ":"; + infoExtLine.appendChild(infoExtSpan); + var infoExtName = document.createElement("input"); + infoExtName.type = "text"; + infoExtName.style.width = "100px"; + infoExtName.value = str2 || ""; + infoExtLine.appendChild(infoExtName); + return infoExtLine; + }; + var authorExtLine = createExtLine("扩展作者", get.connectNickname()); + var introExtLine = createExtLine("扩展描述"); + var versionExtLine = createExtLine("扩展版本", "1.0"); + var diskExtLine = createExtLine("网盘地址"); + var forumExtLine = createExtLine("讨论地址"); + var okExtLine = createExtLine(true); + + game.editExtension = function (name) { + page.currentExtension = name || "无名扩展"; + inputExtName.value = page.currentExtension; + if (name && lib.extensionPack[name]) { + authorExtLine.querySelector("input").value = lib.extensionPack[name].author || ""; + introExtLine.querySelector("input").value = lib.extensionPack[name].intro || ""; + diskExtLine.querySelector("input").value = lib.extensionPack[name].diskURL || ""; + forumExtLine.querySelector("input").value = lib.extensionPack[name].forumURL || ""; + versionExtLine.querySelector("input").value = lib.extensionPack[name].version || ""; + } + else { + authorExtLine.querySelector("input").value = get.connectNickname() || ""; + introExtLine.querySelector("input").value = ""; + diskExtLine.querySelector("input").value = ""; + forumExtLine.querySelector("input").value = ""; + versionExtLine.querySelector("input").value = "1.0"; + } + if (name) { + inputExtName.disabled = true; + buttonConfirm.style.display = "none"; + inputExtSpan.style.display = "none"; + inputExtName.style.display = "none"; + buttonRename.style.display = ""; + buttonSave.style.display = ""; + buttonReset.style.display = ""; + buttonExport.style.display = ""; + } + else { + inputExtName.disabled = false; + buttonConfirm.style.display = ""; + inputExtSpan.innerHTML = "扩展名:"; + inputExtName.style.width = "80px"; + inputExtName.style.textAlign = "center"; + inputExtSpan.style.display = ""; + inputExtName.style.display = ""; + buttonRename.style.display = "none"; + buttonSave.style.display = "none"; + buttonReset.style.display = "none"; + buttonExport.style.display = "none"; + } + + dashboard.style.display = ""; + + exportExtLine.style.display = "none"; + shareExtLine.style.display = "none"; + authorExtLine.style.display = "none"; + introExtLine.style.display = "none"; + forumExtLine.style.display = "none"; + diskExtLine.style.display = "none"; + versionExtLine.style.display = "none"; + okExtLine.style.display = "none"; + inputExtLine.style.padding = "10px"; + dash1.reset(name); + dash2.reset(name); + dash3.reset(name); + dash4.reset(name); + dash1.link.classList.remove("active"); + dash2.link.classList.remove("active"); + dash3.link.classList.remove("active"); + dash4.link.classList.remove("active"); + var active = node.parentNode.querySelector(".active"); + if (active === node) { + return; + } + active.classList.remove("active"); + active.link.remove(); + node.classList.add("active"); + rightPane.appendChild(node.link); + } + var processExtension = function (exportext) { + if (page.currentExtension) { + if (page.currentExtension != inputExtName.value && !exportext) { + game.removeExtension(page.currentExtension); + } + } + inputExtName.disabled = true; + setTimeout(function () { + var ext = {}; + var config = null, help = null; + for (var i in dash4.content) { + try { + if (i == "content" || i == "precontent") { + eval("ext[i]=" + dash4.content[i]); + if (typeof ext[i] != "function") { + throw ("err"); + } + else { + ext[i] = ext[i].toString(); + } + } + else { + eval(dash4.content[i]); + eval("ext[i]=" + i); + if (ext[i] == null || typeof ext[i] != "object") { + throw ("err"); + } + else { + ext[i] = JSON.stringify(ext[i]); + } + } + } + catch (e) { + console.log(e); + delete ext[i]; + } + } + page.currentExtension = inputExtName.value || "无名扩展"; + var str = `{name:"${page.currentExtension}"`; + for (var i in ext) { + str += "," + i + ":" + ext[i]; + } + dash2.content.pack.list = []; + for (var i = 0; i < dash2.pile.childNodes.length; i++) { + dash2.content.pack.list.push(dash2.pile.childNodes[i].link); + } + str += ",package:" + get.stringify({ + //替换die audio,加上扩展名 + character: (pack => { + var character = pack.character; + for (var key in character) { + var info = character[key]; + if (Array.isArray(info[4])) { + var tag = info[4].find(tag => /^die:.+$/.test(tag)); + if (tag) { + info[4].remove(tag); + if (typeof game.readFile == "function") { + info[4].push("die:ext:" + page.currentExtension + "/audio/die/" + tag.slice(tag.lastIndexOf("/") + 1)); + } else { + info[4].push("die:db:extension-" + page.currentExtension + ":audio/die/" + tag.slice(tag.lastIndexOf("/") + 1)); + } + } + } + } + return pack; + })(dash1.content.pack), + card: dash2.content.pack, + skill: dash3.content.pack, + intro: introExtLine.querySelector("input").value || "", + author: authorExtLine.querySelector("input").value || "", + diskURL: diskExtLine.querySelector("input").value || "", + forumURL: forumExtLine.querySelector("input").value || "", + version: versionExtLine.querySelector("input").value || "", + }); + var files = { character: [], card: [], skill: [], audio: [] }; + for (var i in dash1.content.image) { + files.character.push(i); + } + for (var i in dash1.content.audio) { + files.audio.push("audio/die/" + i); + } + for (var i in dash2.content.image) { + files.card.push(i); + } + for (var i in dash3.content.audio) { + files.skill.push(i); + } + str += ",files:" + JSON.stringify(files); + str += "}"; + var extension = { "extension.js": `game.import("extension",function(lib,game,ui,get,ai,_status){return ${str}})` }; + for (var i in dash1.content.image) { + extension[i] = dash1.content.image[i]; + } + for (var i in dash1.content.audio) { + extension["audio/die/" + i] = dash1.content.audio[i]; + } + for (var i in dash2.content.image) { + extension[i] = dash2.content.image[i]; + } + var callback = () => { + if (exportext) { + var proexport = function () { + game.importExtension(extension, null, page.currentExtension, { + intro: introExtLine.querySelector("input").value || "", + author: authorExtLine.querySelector("input").value || "", + netdisk: diskExtLine.querySelector("input").value || "", + forum: forumExtLine.querySelector("input").value || "", + version: versionExtLine.querySelector("input").value || "", + }); + }; + if (game.getFileList) { + game.getFileList("extension/" + page.currentExtension, function (folders, files) { + extension._filelist = files; + proexport(); + }); + } + else { + proexport(); + } + } + else { + game.importExtension(extension, function () { + exportExtLine.style.display = ""; + }); + } + }; + //兼容网页版情况 + if (typeof game.readFile == "function") { + game.readFile("LICENSE", function (data) { + extension["LICENSE"] = data; + game.writeFile(data, "extension/" + page.currentExtension, "LICENSE", function () { }) + callback(); + }, function () { + alert("许可证文件丢失,无法导出扩展"); + }); + } else { + callback(); + } + }, 500); + }; + var buttonConfirm = document.createElement("button"); + buttonConfirm.innerHTML = "确定"; + buttonConfirm.style.marginLeft = "5px"; + buttonConfirm.onclick = buttonConfirmOnclick; + inputExtLine.appendChild(buttonConfirm); + var buttonRename = document.createElement("button"); + buttonRename.innerHTML = "选项"; + buttonRename.style.marginLeft = "2px"; + buttonRename.style.marginRight = "2px"; + buttonRename.style.display = "none"; + buttonRename.onclick = function () { + inputExtSpan.style.display = ""; + inputExtName.style.display = ""; + authorExtLine.style.display = ""; + introExtLine.style.display = ""; + forumExtLine.style.display = ""; + diskExtLine.style.display = ""; + versionExtLine.style.display = ""; + okExtLine.style.display = "block"; + inputExtLine.style.padding = "20px 10px 10px 10px"; + inputExtName.disabled = false; + buttonRename.style.display = "none"; + buttonSave.style.display = "none"; + buttonReset.style.display = "none"; + buttonExport.style.display = "none"; + inputExtSpan.innerHTML = "扩展名称:"; + inputExtName.style.width = "100px"; + inputExtName.style.textAlign = ""; + + dashboard.style.display = "none"; + }; + inputExtLine.appendChild(buttonRename); + var buttonReset = document.createElement("button"); + buttonReset.innerHTML = "重置"; + buttonReset.style.marginLeft = "2px"; + buttonReset.style.marginRight = "2px"; + buttonReset.style.display = "none"; + buttonReset.onclick = function () { + if (confirm("当前扩展将被清除,是否确定?")) { + game.editExtension(); + } + }; + inputExtLine.appendChild(buttonReset); + var buttonSave = document.createElement("button"); + buttonSave.innerHTML = "保存"; + buttonSave.style.marginLeft = "2px"; + buttonSave.style.marginRight = "2px"; + buttonSave.style.display = "none"; + buttonSave.onclick = function () { + dash1.link.classList.remove("active"); + dash2.link.classList.remove("active"); + dash3.link.classList.remove("active"); + dash4.link.classList.remove("active"); + processExtension(); + }; + inputExtLine.appendChild(buttonSave); + var buttonExport = document.createElement("button"); + buttonExport.innerHTML = "导出"; + buttonExport.style.marginLeft = "2px"; + buttonExport.style.marginRight = "2px"; + buttonExport.style.display = "none"; + buttonExport.onclick = function () { + function oldExport() { + processExtension(true); + if (lib.config.show_extensionshare) { + shareExtLine.style.display = ""; + } + } + if (typeof game.readFile == "function" && + window.noname_shijianInterfaces && + typeof window.noname_shijianInterfaces.shareExtensionWithPassWordAsync == "function" && + confirm("是否使用诗笺版自带的导出功能来导出扩展?")) { + const extName = inputExtName.value; + if (!extName) { + alert("未检测到扩展名,将使用无名杀自带的导出功能"); + oldExport(); + return; + } + game.readFile(`extension/${extName}/extension.js`, () => { + const pwd = prompt("请输入压缩包密码,不设密码直接点确定"); + let result; + if (pwd === "" || pwd === null) { + window.noname_shijianInterfaces.shareExtensionAsync(extName); + } else { + window.noname_shijianInterfaces.shareExtensionWithPassWordAsync(extName, pwd); + } + }, () => { + alert("未检测到扩展文件,将使用无名杀自带的导出功能"); + oldExport(); + }); + } else { + oldExport(); + } + }; + inputExtLine.appendChild(buttonExport); + var exportExtLine = ui.create.div(pageboard); + exportExtLine.style.display = "none"; + exportExtLine.style.width = "calc(100% - 40px)"; + exportExtLine.style.textAlign = "left"; + exportExtLine.style.marginBottom = "5px"; + if (lib.device == "ios") { + exportExtLine.innerHTML = `已保存。退出游戏并重新打开后生效×`; + exportExtLine.querySelectorAll("span")[0].onclick = function () { + exportExtLine.style.display = "none"; + }; + } + else { + exportExtLine.innerHTML = `重启后生效。立即重启×`; + exportExtLine.querySelectorAll("span")[0].onclick = game.reload; + exportExtLine.querySelectorAll("span")[1].onclick = function () { + exportExtLine.style.display = "none"; + }; + } + + + var shareExtLine = ui.create.div(pageboard); + shareExtLine.style.display = "none"; + shareExtLine.style.width = "calc(100% - 40px)"; + shareExtLine.style.textAlign = "left"; + shareExtLine.style.marginBottom = "5px"; + shareExtLine.innerHTML = `已导出扩展。分享扩展×`; + shareExtLine.querySelectorAll("span")[0].onclick = function () { + //这个链接404了 + //game.open("https://tieba.baidu.com/p/5439380222"); + //无名杀贴吧首页 + game.open("https://tieba.baidu.com/f?ie=utf-8&kw=%E6%97%A0%E5%90%8D%E6%9D%80"); + }; + shareExtLine.querySelectorAll("span")[1].onclick = function () { + shareExtLine.style.display = "none"; + }; + + var dashboard = ui.create.div(pageboard); + var clickDash = function () { + ui.create.templayer(); + pageboard.hide(); + this.link.show(); + if (this.link.init) { + this.link.init(); + } + }; + var createDash = function (str1, str2, node) { + var dash = ui.create.div(".menubutton.large.dashboard"); + dashboard.appendChild(dash); + page.appendChild(node); + dash.link = node; + node.link = dash; + dash.listen(clickDash); + lib.setScroll(node); + ui.create.div("", str1, dash); + ui.create.div("", str2, dash); + }; + var dash1 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + var currentButton = null; + page.init = function () { + if (!page.querySelector(".button.character")) { + toggle.classList.add("on"); + newCharacter.style.display = ""; + } + }; + var updateButton = function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + editnode.classList.add("disabled"); + return; + } + name = name.split("|"); + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.character[name] || page.content.pack.character[name]) { + editnode.classList.add("disabled"); + return; + } + } + } + else { + if (lib.character[name] || page.content.pack.character[name]) { + editnode.classList.add("disabled"); + return; + } + } + if (!fakeme.image) { + if (!page.content.image[name + ".jpg"]) { + editnode.classList.add("disabled"); + return; + } + } + editnode.classList.remove("disabled"); + }; + var clickButton = lib.gnc.of(function* () { + if (currentButton == this) { + resetEditor(); + return; + } + resetEditor(); + currentButton = this; + toggle.classList.add("on"); + newCharacter.style.display = ""; + fakeme.classList.add("inited"); + fakeme.style.backgroundImage = this.style.backgroundImage; + if (page.content.pack.translate[this.link] != this.link) { + newCharacter.querySelector(".new_name").value = this.link + "|" + page.content.pack.translate[this.link]; + } + else { + newCharacter.querySelector(".new_name").value = this.link; + } + var info = page.content.pack.character[this.link]; + newCharacter.querySelector(".new_hp").value = info[2]; + sexes.value = info[0]; + groups.value = info[1]; + if (info[4]) { + for (var i = 0; i < options.childNodes.length - 1; i++) { + if (options.childNodes[i].lastChild && info[4].contains(options.childNodes[i].lastChild.name)) { + options.childNodes[i].lastChild.checked = true; + } + else if (options.childNodes[i].lastChild) { + options.childNodes[i].lastChild.checked = false; + } + } + for (var i = 0; i < info[4].length; i++) { + if (info[4][i].startsWith("des:")) { + newCharacter.querySelector(".new_des").value = info[4][i].slice(4); + } + if (info[4][i].startsWith("die:")) { + var dieaudionode = newCharacter.querySelector(".die_audio"); + dieaudionode.file = { + name: info[4][i].slice(info[4][i].lastIndexOf("/") + 1) + }; + yield new Promise(resolve => { + if (typeof game.readFile == "function") { + game.readFile(info[4][i].slice(4).replace("ext:", "extension/"), arraybuffer => { + dieaudionode.arrayBuffer = arraybuffer; + resolve(); + }, () => { + console.warn(`未找到${info[4][i].slice(4).replace("ext:", "extension/")}阵亡配音`); + resolve(); + }); + } else { + game.getDB("image", info[4][i].slice(7)).then(octetStream => { + dieaudionode.arrayBuffer = octetStream; + resolve(); + }, () => { + console.warn(`未找到${info[4][i].slice(4)}阵亡配音`); + resolve(); + }); + } + }); + } + } + } + + var skills = info[3]; + for (var i = 0; i < skills.length; i++) { + var node = document.createElement("button"); + node.skill = skills[i]; + node.onclick = deletenode; + node.innerHTML = lib.translate[skills[i]]; + skillList.firstChild.appendChild(node); + } + + toggle.innerHTML = "编辑武将
      >
      "; + editnode.innerHTML = "编辑武将"; + editnode.classList.remove("disabled"); + delnode.innerHTML = "删除"; + delnode.button = this; + }); + var createButton = function (name, image) { + var button = ui.create.div(".button.character"); + button.link = name; + button.image = image; + button.style.backgroundImage = "url(" + image + ")"; + button.style.backgroundSize = "cover"; + button.listen(clickButton); + button.classList.add("noclick"); + button.nodename = ui.create.div(button, ".name", get.verticalStr(page.content.pack.translate[name])); + button.nodename.style.top = "8px"; + page.insertBefore(button, page.childNodes[1]); + } + page.reset = function (name) { + resetEditor(); + var buttons = page.querySelectorAll(".button.character"); + var list = []; + for (var i = 0; i < buttons.length; i++) { + list.push(buttons[i]); + } + for (var i = 0; i < list.length; i++) { + list[i].remove(); + } + if (lib.extensionPack[name]) { + page.content.pack = lib.extensionPack[name].character || { + character: {}, + translate: {} + }; + page.content.image = {}; + for (var i in page.content.pack.character) { + var file = i + ".jpg"; + var loadImage = function (file, data) { + var img = new Image(); + img.crossOrigin = "Anonymous"; + img.onload = function () { + var canvas = document.createElement("CANVAS"); + var ctx = canvas.getContext("2d"); + var dataURL; + canvas.height = this.height; + canvas.width = this.width; + ctx.drawImage(this, 0, 0); + canvas.toBlob(function (blob) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + page.content.image[file] = e.target.result; + }; + fileReader.readAsArrayBuffer(blob, "UTF-8"); + }); + }; + img.src = data; + } + if (game.download) { + var url = lib.assetURL + "extension/" + name + "/" + file; + createButton(i, url); + if (lib.device == "ios" || lib.device == "android") { + window.resolveLocalFileSystemURL(lib.assetURL + "extension/" + name, function (entry) { + entry.getFile(file, {}, function (fileEntry) { + fileEntry.file(function (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + page.content.image[file] = e.target.result; + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }); + }); + }); + } + else { + loadImage(file, url); + } + } + else game.getDB("image", `extension-${name}:${file}`).then(value => { + createButton(i, value); + loadImage(file, value); + }); + } + } + else { + page.content = { + pack: { + character: {}, + translate: {} + }, + image: {}, + audio: {} + }; + toggle.classList.add("on"); + newCharacter.style.display = ""; + } + }; + ui.create.div(".config.more", `
      返回`, page, function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }); + page.content = { + pack: { + character: {}, + translate: {} + }, + image: {}, + audio: {} + }; + var newCharacter; + var toggle = ui.create.div(".config.more.on", "创建武将
      >
      ", page, function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + newCharacter.style.display = ""; + } + else { + newCharacter.style.display = "none"; + } + }); + var resetEditor = function () { + currentButton = null; + toggle.classList.remove("on"); + newCharacter.style.display = "none"; + fakeme.classList.remove("inited"); + delete fakeme.image; + delete fakeme.image64; + fakeme.style.backgroundImage = ""; + var inputs = newCharacter.querySelectorAll("input"); + for (var i = 0; i < inputs.length; i++) { + inputs[i].value = ""; + } + inputs = newCharacter.querySelectorAll("textarea"); + for (var i = 0; i < inputs.length; i++) { + inputs[i].value = ""; + } + skillList.firstChild.innerHTML = ""; + toggle.innerHTML = "创建武将
      >
      "; + editnode.innerHTML = "创建武将"; + editnode.classList.add("disabled"); + delnode.innerHTML = "取消"; + delete delnode.button; + } + + newCharacter = ui.create.div(".new_character", page); + var fakeme = ui.create.div(".avatar", newCharacter); + + var input = document.createElement("input"); + input.type = "file"; + input.accept = "image/*"; + input.className = "fileinput"; + input.onchange = function () { + var fileToLoad = input.files[0]; + if (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + fakeme.style.backgroundImage = "url(" + data + ")"; + fakeme.image64 = data; + fakeme.classList.add("inited"); + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + fakeme.image = fileLoadedEvent.target.result; + updateButton(); + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + } + } + fakeme.appendChild(input); + + ui.create.div(".select_avatar", "选择头像", fakeme); + + ui.create.div(".indent", `姓名:`, newCharacter).style.paddingTop = "8px"; + ui.create.div(".indent", `介绍:`, newCharacter).style.paddingTop = "8px"; + ui.create.div(".indent", `体力:`, newCharacter).style.paddingTop = "8px"; + newCharacter.querySelector("input.new_name").onblur = updateButton; + var sexes = ui.create.selectlist([ + ["male", "男"], + ["female", "女"], + ["double", "双性"], + ["none", "无"] + ], null, ui.create.div(".indent", "性别:", newCharacter)); + var grouplist = lib.group.map((group, i) => [lib.group[i], get.translation(lib.group[i])]); + var groups = ui.create.selectlist(grouplist, null, ui.create.div(".indent", "势力:", newCharacter)); + var dieaudio = ui.create.div(".die_audio", newCharacter, { textAlign: "left" }); + var dieaudiolabel = ui.create.node("label", "阵亡配音:", dieaudio); + var dieaudioUpload = dieaudio.appendChild(document.createElement("input")); + dieaudioUpload.type = "file"; + dieaudioUpload.accept = "audio/*"; + dieaudioUpload.style.width = "calc(100% - 100px)"; + dieaudioUpload.onchange = function () { + var fileToLoad = dieaudioUpload.files[0]; + if (fileToLoad) { + console.log(fileToLoad); + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + var blob = new Blob([data]); + dieaudio.file = fileToLoad; + dieaudio.arrayBuffer = data; + dieaudio.blob = blob; + var new_name = newCharacter.querySelector("input.new_name"); + dieaudioUpload.style.display = "none"; + dieaudiopreview.style.display = + dieaudiocancel.style.display = ""; + dieaudiotag.src = window.URL.createObjectURL(blob); + }; + fileReader.readAsArrayBuffer(fileToLoad); + } + }; + var dieaudiotag = ui.create.node("audio", dieaudio); + var dieaudiopreview = ui.create.node("button", dieaudio, () => { + if (dieaudiotag.error) { + alert("您使用的客户端不支持预览此音频!") + } else dieaudiotag.play(); + }); + dieaudiopreview.innerHTML = "播放"; + dieaudiopreview.style.display = "none"; + var dieaudiocancel = ui.create.node("button", dieaudio, () => { + dieaudiopreview.style.display = "none"; + dieaudiocancel.style.display = "none"; + if (dieaudio.blob) { + window.URL.revokeObjectURL(dieaudio.blob); + dieaudiotag.src = null; + delete dieaudio.file; + delete dieaudio.arrayBuffer; + delete dieaudio.blob; + } + dieaudioUpload.value = ""; + dieaudioUpload.style.display = ""; + }); + dieaudiocancel.innerHTML = "取消"; + dieaudiocancel.style.display = "none"; + var options = ui.create.div(".add_skill.options", `主公BOSS仅点将可用
      隐匿技
      `, newCharacter); + var addSkill = ui.create.div(".add_skill", "添加技能
      ", newCharacter); + var list = []; + for (var i in lib.character) { + if (lib.character[i][3].length) { + list.push([i, lib.translate[i]]); + } + } + list.sort(function (a, b) { + a = a[0]; b = b[0]; + var aa = a, bb = b; + if (aa.includes("_")) { + aa = aa.slice(aa.indexOf("_") + 1); + } + if (bb.includes("_")) { + bb = bb.slice(bb.indexOf("_") + 1); + } + if (aa != bb) { + return aa > bb ? 1 : -1; + } + return a > b ? 1 : -1; + }); + var list2 = []; + var skills = lib.character[list[0][0]][3]; + for (var i = 0; i < skills.length; i++) { + list2.push([skills[i], lib.translate[skills[i]]]); + } + list.unshift(["current_extension", "此扩展"]); + + var selectname = ui.create.selectlist(list, list[1], addSkill); + page.selectname = selectname; + selectname.onchange = function () { + skillopt.innerHTML = ""; + if (this.value == "current_extension") { + for (var i in dash3.content.pack.skill) { + var option = document.createElement("option"); + option.value = i; + option.innerHTML = dash3.content.pack.translate[i]; + skillopt.appendChild(option); + } + } + else { + var skills = lib.character[this.value][3]; + for (var i = 0; i < skills.length; i++) { + var option = document.createElement("option"); + option.value = skills[i]; + option.innerHTML = lib.translate[skills[i]]; + skillopt.appendChild(option); + } + } + }; + selectname.style.maxWidth = "85px"; + var skillopt = ui.create.selectlist(list2, list2[0], addSkill); + skillopt.style.maxWidth = "60px"; + page.skillopt = skillopt; + var addSkillButton = document.createElement("button"); + addSkillButton.innerHTML = "添加"; + addSkill.appendChild(addSkillButton); + page.addSkillButton = addSkillButton; + var deletenode = function () { + this.remove(); + } + addSkillButton.onclick = function () { + for (var i = 0; i < skillList.firstChild.childNodes.length; i++) { + if (skillList.firstChild.childNodes[i].skill == skillopt.value) return alert(selectname.value == "current_extension" ? "此扩展还未添加技能" : "此武将没有技能可添加"); + } + //无技能时 + if (!skillopt.value || skillopt.childElementCount == 0) return; + var node = document.createElement("button"); + node.skill = skillopt.value; + node.onclick = deletenode; + for (var i = 0; i < skillopt.childElementCount; i++) { + if (skillopt.childNodes[i].value == skillopt.value) { + node.innerHTML = skillopt.childNodes[i].innerHTML; break; + } + } + skillList.firstChild.appendChild(node); + }; + var createSkillButton = document.createElement("button"); + createSkillButton.innerHTML = "创建"; + createSkillButton.style.marginLeft = "3px"; + addSkill.appendChild(createSkillButton); + createSkillButton.onclick = function () { + ui.create.templayer(); + page.hide(); + dash3.show(); + dash3.fromchar = "add"; + dash3.toggle.classList.add("on"); + dash3.newSkill.style.display = ""; + }; + page.updateSkill = function () { + for (var i = 0; i < skillList.firstChild.childNodes.length; i++) { + var node = skillList.firstChild.childNodes[i]; + var skill = skillList.firstChild.childNodes[i].skill; + if (dash3.content.pack.skill[skill]) { + node.innerHTML = dash3.content.pack.translate[skill]; + } + else if (lib.skill[skill]) { + node.innerHTML = lib.translate[skill]; + } + else { + node.remove(); i--; + } + } + }; + var skillList = ui.create.div(".skill_list", newCharacter); + ui.create.div(skillList); + var editnode = ui.create.div(".menubutton.large.disabled", "创建武将", ui.create.div(skillList), function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + alert("请填写武将名\n提示:武将名格式为id+|+中文名,其中id必须惟一"); + return; + } + name = name.split("|"); + var translate = name[1] || name[0]; + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.character[name] || page.content.pack.character[name]) { + alert("武将名与现有武将重复,请更改\n提示:武将名格式为id+|+中文名,其中id必须惟一"); + return; + } + page.content.image[name + ".jpg"] = page.content.image[currentButton.link + ".jpg"]; + delete page.content.image[currentButton.link + ".jpg"]; + delete page.content.pack.character[currentButton.link]; + delete page.content.pack.translate[currentButton.link]; + currentButton.link = name; + } + } + else { + if (lib.character[name] || page.content.pack.character[name]) { + alert("武将名与现有武将重复,请更改\n提示:武将名格式为id+|+中文名,其中id必须惟一"); + return; + } + } + if (fakeme.image) { + page.content.image[name + ".jpg"] = fakeme.image; + } + else { + if (!page.content.image[name + ".jpg"]) { + alert("请选择武将头像"); + return; + } + } + var hp = page.querySelector("input.new_hp").value; + //体力支持‘Infinity,∞,无限’表示无限 + if (["Infinity", "∞", "无限"].includes(hp)) hp = Infinity; + else if (hp.indexOf("/") == -1) hp = parseInt(hp) || 1; + var skills = []; + for (var i = 0; i < skillList.firstChild.childNodes.length; i++) { + skills.add(skillList.firstChild.childNodes[i].skill); + } + var tags = []; + for (var i = 0; i < options.childNodes.length - 1; i++) { + if (options.childNodes[i].lastChild && options.childNodes[i].lastChild.checked) { + tags.push(options.childNodes[i].lastChild.name); + } + } + if (tags.contains("boss")) { + tags.add("bossallowed"); + } + var des = page.querySelector("input.new_des").value; + if (des) { + tags.add("des:" + des); + } + //阵亡配音 + if (dieaudio.file && dieaudio.arrayBuffer) { + var audioname = name + dieaudio.file.name.slice(dieaudio.file.name.indexOf(".")); + tags.add(`die:${typeof game.readFile == "function" ? "ext" : "db"}:audio/die/${audioname}`); + page.content.audio[audioname] = dieaudio.arrayBuffer; + } + + page.content.pack.translate[name] = translate; + page.content.pack.character[name] = [sexes.value, groups.value, hp, skills, tags]; + if (this.innerHTML == "创建武将") { + createButton(name, fakeme.image64); + } + else if (currentButton) { + if (fakeme.image64) { + currentButton.image = fakeme.image64; + currentButton.style.backgroundImage = "url(" + fakeme.image64 + ")"; + } + currentButton.nodename.innerHTML = get.verticalStr(translate); + } + resetEditor(); + dash1.link.classList.add("active"); + }); + var delnode = ui.create.div(".menubutton.large", "取消", editnode.parentNode, function () { + if (this.innerHTML == "删除") { + this.button.remove(); + var name = this.button.link; + delete dash1.content.pack.character[name]; + delete dash1.content.pack.translate[name]; + delete dash1.content.image[name]; + delete dash1.content.audio[name]; + dash1.link.classList.add("active"); + } + resetEditor(); + }); + delnode.style.marginLeft = "13px"; + + return page; + }()); + var dash2 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + var currentButton = null; + page.init = function () { + if (!page.querySelector(".button.card")) { + toggle.classList.add("on"); + newCard.style.display = ""; + } + }; + var updateButton = function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + editnode.classList.add("disabled"); + return; + } + name = name.split("|"); + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.card[name] || page.content.pack.card[name]) { + editnode.classList.add("disabled"); + return; + } + } + } + else { + if (lib.card[name] || page.content.pack.card[name]) { + editnode.classList.add("disabled"); + return; + } + } + if (!fakeme.image && !fakeme.classList.contains("inited")) { + editnode.classList.add("disabled"); + return; + } + editnode.classList.remove("disabled"); + }; + var clickButton = function () { + if (currentButton == this) { + resetEditor(); + return; + } + resetEditor(); + currentButton = this; + toggle.classList.add("on"); + newCard.style.display = ""; + fakeme.classList.add("inited"); + delete fakeme.image; + delete fakeme.image64; + if (this.classList.contains("fullskin")) { + fakeme.imagenode.style.backgroundImage = this.imagenode.style.backgroundImage; + fakeme.classList.add("fullskin"); + } + else { + fakeme.style.backgroundImage = this.style.backgroundImage; + fakeme.classList.remove("fullskin"); + } + if (page.content.pack.translate[this.link] != this.link) { + newCard.querySelector(".new_name").value = this.link + "|" + page.content.pack.translate[this.link]; + } + else { + newCard.querySelector(".new_name").value = this.link; + } + newCard.querySelector(".new_description").value = page.content.pack.translate[this.link + "_info"]; + var info = page.content.pack.card[this.link]; + container.code = "card=" + get.stringify(info); + + toggle.innerHTML = "编辑卡牌
      >
      "; + editnode.innerHTML = "编辑卡牌"; + editnode.classList.remove("disabled"); + delnode.innerHTML = "删除"; + delnode.button = this; + } + var createButton = function (name, image, fullskin) { + var button = ui.create.div(".button.card"); + button.link = name; + button.image = image; + button.imagenode = ui.create.div(".image", button); + if (image) { + if (fullskin) { + button.imagenode.style.backgroundImage = "url(" + image + ")"; + button.style.backgroundImage = ""; + button.style.backgroundSize = ""; + button.classList.add("fullskin"); + } + else { + button.style.color = "white"; + button.style.textShadow = "black 0 0 2px"; + button.imagenode.style.backgroundImage = ""; + button.style.backgroundImage = "url(" + image + ")"; + button.style.backgroundSize = "cover"; + } + } + button.listen(clickButton); + button.classList.add("noclick"); + button.nodename = ui.create.div(button, ".name", get.verticalStr(page.content.pack.translate[name])); + page.insertBefore(button, page.childNodes[1]); + } + page.reset = function (name) { + resetEditor(); + var buttons = page.querySelectorAll(".button.card"); + var list = []; + for (var i = 0; i < buttons.length; i++) { + list.push(buttons[i]); + } + for (var i = 0; i < list.length; i++) { + list[i].remove(); + } + if (lib.extensionPack[name]) { + page.content.pack = lib.extensionPack[name].card || { + card: {}, + translate: {} + }; + page.content.image = {}; + if (Array.isArray(page.content.pack.list)) { + for (var i = 0; i < page.content.pack.list.length; i++) { + var card = page.content.pack.list[i]; + var node = document.createElement("button"); + node.innerHTML = page.content.pack.translate[card[2]] + " " + lib.translate[card[0]] + card[1]; + node.name = card[2]; + node.link = card; + pile.appendChild(node); + node.onclick = function () { + this.remove(); + } + } + } + for (var i in page.content.pack.card) { + var file; + var fullskin = page.content.pack.card[i].fullskin ? true : false; + if (fullskin) { + file = i + ".png"; + } + else { + file = i + ".jpg"; + } + var loadImage = function (file, data) { + var img = new Image(); + img.crossOrigin = "Anonymous"; + img.onload = function () { + var canvas = document.createElement("CANVAS"); + var ctx = canvas.getContext("2d"); + var dataURL; + canvas.height = this.height; + canvas.width = this.width; + ctx.drawImage(this, 0, 0); + canvas.toBlob(function (blob) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + page.content.image[file] = e.target.result; + }; + fileReader.readAsArrayBuffer(blob, "UTF-8"); + }); + }; + img.src = data; + } + if (game.download) { + var url = lib.assetURL + "extension/" + name + "/" + file; + createButton(i, url, fullskin); + if (lib.device == "ios" || lib.device == "android") { + window.resolveLocalFileSystemURL(lib.assetURL + "extension/" + name, function (entry) { + entry.getFile(file, {}, function (fileEntry) { + fileEntry.file(function (fileToLoad) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + page.content.image[file] = e.target.result; + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }); + }); + }); + } + else { + loadImage(file, url); + } + } + else game.getDB("image", `extension-${name}:${file}`).then(value => { + createButton(i, value, fullskin); + loadImage(file, value); + }); + } + } + else { + page.content = { + pack: { + card: {}, + translate: {} + }, + image: {} + }; + toggle.classList.add("on"); + newCard.style.display = ""; + } + updatePile(); + }; + ui.create.div(".config.more.margin-bottom", `
      返回`, page, function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }); + page.content = { + pack: { + card: {}, + translate: {}, + list: [] + }, + image: {} + }; + var newCard; + var toggle = ui.create.div(".config.more.on", "创建卡牌
      >
      ", page, function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + newCard.style.display = ""; + } + else { + newCard.style.display = "none"; + } + }); + var resetEditor = function () { + currentButton = null; + toggle.classList.remove("on"); + newCard.style.display = "none"; + fakeme.classList.remove("inited"); + fakeme.classList.add("fullskin"); + delete fakeme.image; + delete fakeme.image64; + fakeme.style.backgroundImage = ""; + fakeme.imagenode.style.backgroundImage = ""; + var inputs = newCard.querySelectorAll("input"); + for (var i = 0; i < inputs.length; i++) { + inputs[i].value = ""; + } + toggle.innerHTML = "创建卡牌
      >
      "; + editnode.innerHTML = "创建卡牌"; + editnode.classList.add("disabled"); + delnode.innerHTML = "取消"; + delete delnode.button; + container.code = `card={\n \n}\n\n/*\n示例:\ncard={\n type:"basic",\n enable:true,\n filterTarget:true,\n content:function(){\n target.draw()\n },\n ai:{\n order:1,\n result:{\n target:1\n }\n }\n}\n此例的效果为目标摸一张牌\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + } + + newCard = ui.create.div(".new_character", page); + newCard.style.height = "173px"; + var fakeme = ui.create.div(".card.fullskin", newCard); + + var input = document.createElement("input"); + input.type = "file"; + input.accept = "image/*"; + input.className = "fileinput"; + input.onchange = function () { + var fileToLoad = input.files[0]; + if (fileToLoad) { + var fileReader = new FileReader(); + var fullimage = (fileToLoad.name.includes(".jpg")); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + if (fullimage) { + fakeme.imagenode.style.backgroundImage = ""; + fakeme.style.backgroundImage = "url(" + data + ")"; + fakeme.classList.remove("fullskin"); + } + else { + fakeme.style.backgroundImage = ""; + fakeme.imagenode.style.backgroundImage = "url(" + data + ")"; + fakeme.classList.add("fullskin"); + } + fakeme.image64 = data; + fakeme.classList.add("inited"); + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + fakeme.image = fileLoadedEvent.target.result; + updateButton(); + }; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }; + fileReader.readAsDataURL(fileToLoad, "UTF-8"); + } + } + fakeme.appendChild(input); + + fakeme.imagenode = ui.create.div(".image", fakeme); + ui.create.div(".name", "选择背景", fakeme); + + ui.create.div(".indent", `名称:`, newCard).style.paddingTop = "8px"; + ui.create.div(".indent", `描述:`, newCard).style.paddingTop = "6px"; + newCard.querySelector("input.new_name").onblur = updateButton; + var codeButton = document.createElement("button"); + newCard.appendChild(codeButton); + codeButton.innerHTML = "编辑代码"; + codeButton.style.left = "123px"; + codeButton.style.top = "66px"; + codeButton.style.position = "absolute"; + + var citeButton = document.createElement("button"); + newCard.appendChild(citeButton); + citeButton.innerHTML = "引用代码"; + citeButton.style.left = "123px"; + citeButton.style.top = "90px"; + citeButton.style.position = "absolute"; + citeButton.onclick = function () { + codeButton.style.display = "none"; + citeButton.style.display = "none"; + selectname.style.display = ""; + confirmcontainer.style.display = ""; + } + + var list = []; + for (var i in lib.card) { + if (lib.translate[i]) { + list.push([i, lib.translate[i]]); + } + } + list.sort(function (a, b) { + a = a[0]; b = b[0]; + var aa = a, bb = b; + if (aa.includes("_")) { + aa = aa.slice(aa.indexOf("_") + 1); + } + if (bb.includes("_")) { + bb = bb.slice(bb.indexOf("_") + 1); + } + if (aa != bb) { + return aa > bb ? 1 : -1; + } + return a > b ? 1 : -1; + }); + var selectname = ui.create.selectlist(list, list[0], newCard); + selectname.style.left = "123px"; + selectname.style.top = "66px"; + selectname.style.position = "absolute"; + selectname.style.display = "none"; + + var confirmcontainer = ui.create.div(newCard); + confirmcontainer.style.left = "123px"; + confirmcontainer.style.top = "90px"; + confirmcontainer.style.position = "absolute"; + confirmcontainer.style.display = "none"; + + var citeconfirm = document.createElement("button"); + citeconfirm.innerHTML = "引用"; + confirmcontainer.appendChild(citeconfirm); + citeconfirm.onclick = function () { + codeButton.style.display = ""; + citeButton.style.display = ""; + selectname.style.display = "none"; + confirmcontainer.style.display = "none"; + container.code = "card=" + get.stringify(lib.card[selectname.value]); + codeButton.onclick.call(codeButton); + if (lib.translate[selectname.value + "_info"]) { + newCard.querySelector("input.new_description").value = lib.translate[selectname.value + "_info"]; + } + } + + var citecancel = document.createElement("button"); + citecancel.innerHTML = "取消"; + citecancel.style.marginLeft = "3px"; + confirmcontainer.appendChild(citecancel); + citecancel.onclick = function () { + codeButton.style.display = ""; + citeButton.style.display = ""; + selectname.style.display = "none"; + confirmcontainer.style.display = "none"; + } + + codeButton.onclick = function () { + var node = container; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + window.saveNonameInput = saveInput; + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, editor); + } + } + } + + var container = ui.create.div(".popup-container.editor"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + var card = null; + eval(code); + if (card == null || typeof card != "object") { + throw ("err"); + } + } + catch (e) { + if (e == "err") { + alert("代码格式有错误,请对比示例代码仔细检查"); + } + else { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + } + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + dash2.link.classList.add("active"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + delete window.saveNonameInput; + }; + var editor = ui.create.editor(container, saveInput); + container.code = `card={\n \n}\n\n/*\n示例:\ncard={\n type:"basic",\n enable:true,\n filterTarget:true,\n content:function(){\n target.draw()\n },\n ai:{\n order:1,\n result:{\n target:1\n }\n }\n}\n此例的效果为目标摸一张牌\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + + var editnode = ui.create.div(".menubutton.large.new_card.disabled", "创建卡牌", newCard, function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + alert("请填写卡牌名\n提示:卡牌名格式为id+|+中文名,其中id必须惟一"); + return; + } + name = name.split("|"); + var translate = name[1] || name[0]; + var info = page.querySelector("input.new_description").value; + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.card[name] || page.content.pack.card[name]) { + alert("卡牌名与现有卡牌重复,请更改\n提示:卡牌名格式为id+|+中文名,其中id必须惟一"); + return; + } + var extname; + if (currentButton.classList.contains("fullskin")) { + extname = ".png"; + } + else { + extname = ".jpg"; + } + page.content.image[name + extname] = page.content.image[currentButton.link + extname]; + delete page.content.image[currentButton.link + extname]; + delete page.content.pack.card[currentButton.link]; + delete page.content.pack.translate[currentButton.link]; + delete page.content.pack.translate[currentButton.link + "_info"]; + currentButton.link = name; + } + } + else { + if (lib.card[name] || page.content.pack.card[name]) { + alert("卡牌名与现有卡牌重复,请更改\n提示:卡牌名格式为id+|+中文名,其中id必须惟一"); + return; + } + } + if (fakeme.image) { + if (fakeme.classList.contains("fullskin")) { + page.content.image[name + ".png"] = fakeme.image; + delete page.content.image[name + ".jpg"]; + } + else { + page.content.image[name + ".jpg"] = fakeme.image; + delete page.content.image[name + ".png"]; + } + } + else if (!fakeme.classList.contains("inited")) { + alert("请选择一个卡牌背景"); + return; + } + page.content.pack.translate[name] = translate; + page.content.pack.translate[name + "_info"] = info; + try { + var card = null; + eval(container.code); + if (card == null || typeof card != "object") { + throw ("err"); + } + page.content.pack.card[name] = card; + } + catch (e) { + page.content.pack.card[name] = {}; + } + if (fakeme.classList.contains("inited")) { + if (fakeme.classList.contains("fullskin")) { + page.content.pack.card[name].fullskin = true; + delete page.content.pack.card[name].fullimage; + } + else { + page.content.pack.card[name].fullimage = true; + delete page.content.pack.card[name].fullskin; + } + } + if (this.innerHTML == "创建卡牌") { + createButton(name, fakeme.image64, fakeme.classList.contains("fullskin")); + } + else if (currentButton) { + if (fakeme.image64) { + if (fakeme.classList.contains("fullskin")) { + currentButton.style.color = ""; + currentButton.style.textShadow = ""; + currentButton.imagenode.style.backgroundImage = "url(" + fakeme.image64 + ")"; + currentButton.style.backgroundImage = ""; + currentButton.style.backgroundSize = ""; + currentButton.classList.add("fullskin"); + } + else { + currentButton.style.color = "white"; + currentButton.style.textShadow = "black 0 0 2px"; + currentButton.imagenode.style.backgroundImage = ""; + currentButton.style.backgroundImage = "url(" + fakeme.image64 + ")"; + currentButton.style.backgroundSize = "cover"; + currentButton.classList.remove("fullskin"); + } + } + currentButton.nodename.innerHTML = get.verticalStr(translate); + } + resetEditor(); + updatePile(); + dash2.link.classList.add("active"); + }); + var delnode = ui.create.div(".menubutton.large.new_card_delete", "取消", editnode.parentNode, function () { + if (this.innerHTML == "删除") { + this.button.remove(); + var name = this.button.link; + delete dash2.content.pack.card[name]; + delete dash2.content.pack.translate[name]; + delete dash2.content.pack.translate[name + "_info"]; + delete dash2.content.image[name]; + updatePile(); + dash2.link.classList.add("active"); + } + resetEditor(); + }); + + var editPile; + var toggle2 = ui.create.div(".config.more", "编辑牌堆
      >
      ", page, function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + editPile.style.display = ""; + } + else { + editPile.style.display = "none"; + } + }); + + editPile = ui.create.div(".edit_pile", page); + editPile.style.display = "none"; + + + var cardpileadd = ui.create.div(".config.toggle.cardpilecfg.cardpilecfgadd", editPile); + var pile = ui.create.div(editPile); + page.pile = pile; + var cardpileaddname = document.createElement("select"); + var updatePile = function () { + cardpileaddname.innerHTML = ""; + var list = []; + var list2 = []; + for (var i in page.content.pack.card) { + list.push([i, page.content.pack.translate[i]]); + list2.push(i); + } + if (list.length) { + toggle2.style.display = ""; + if (toggle2.classList.contains("on")) { + editPile.style.display = ""; + } + else { + editPile.style.display = "none"; + } + for (var i = 0; i < list.length; i++) { + var option = document.createElement("option"); + option.value = list[i][0]; + option.innerHTML = list[i][1]; + cardpileaddname.appendChild(option); + } + for (var i = 0; i < pile.childNodes.length; i++) { + if (!list2.contains(pile.childNodes[i].name)) { + pile.childNodes[i].remove(); i--; + } + } + } + else { + toggle2.style.display = "none"; + editPile.style.display = "none"; + pile.innerHTML = ""; + } + }; + updatePile(); + cardpileadd.appendChild(cardpileaddname); + cardpileaddname.style.width = "75px"; + cardpileaddname.style.marginRight = "2px"; + cardpileaddname.style.marginLeft = "-1px"; + var cardpileaddsuit = ui.create.selectlist([ + ["heart", "红桃"], + ["diamond", "方片"], + ["club", "梅花"], + ["spade", "黑桃"], + ], null, cardpileadd); + cardpileaddsuit.style.width = "53px"; + cardpileaddsuit.style.marginRight = "2px"; + var cardpileaddnumber = ui.create.selectlist([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 + ], null, cardpileadd); + cardpileaddnumber.style.width = "43px"; + cardpileaddnumber.style.marginRight = "2px"; + var button = document.createElement("button"); + button.innerHTML = "确定"; + button.style.width = "40px"; + button.onclick = function () { + var card = [ + cardpileaddsuit.value, + cardpileaddnumber.value, + cardpileaddname.value, + ]; + var node = document.createElement("button"); + node.innerHTML = page.content.pack.translate[card[2]] + " " + lib.translate[card[0]] + card[1]; + node.name = card[2]; + node.link = card; + pile.appendChild(node); + node.onclick = function () { + this.remove(); + } + }; + cardpileadd.appendChild(button); + cardpileadd.style.whiteSpace = "nowrap"; + cardpileadd.style.position = "relative"; + cardpileadd.style.right = "-4px"; + + return page; + }()); + var dash3 = (function () { + var page = ui.create.div(".hidden.menu-buttons.new_skill"); + var updateButton = function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + editnode.classList.add("disabled"); + return; + } + name = name.split("|"); + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.skill[name] || page.content.pack.skill[name]) { + editnode.classList.add("disabled"); + return; + } + } + } + else { + if (lib.skill[name] || page.content.pack.skill[name]) { + editnode.classList.add("disabled"); + return; + } + } + editnode.classList.remove("disabled"); + }; + page.init = function () { + if (!page.querySelector(".menubutton:not(.large)")) { + toggle.classList.add("on"); + newSkill.style.display = ""; + } + }; + page.reset = function (name) { + resetEditor(); + var buttons = page.querySelectorAll(".menubutton:not(.large)"); + var list = []; + for (var i = 0; i < buttons.length; i++) { + list.push(buttons[i]); + } + for (var i = 0; i < list.length; i++) { + list[i].remove(); + } + if (lib.extensionPack[name]) { + page.content.pack = lib.extensionPack[name].skill || { + skill: {}, + translate: {} + }; + page.content.audio = {}; + for (var i in page.content.pack.skill) { + createButton(i); + } + dash1.updateSkill(); + } + else { + page.content = { + pack: { + skill: {}, + translate: {} + }, + audio: {} + }; + toggle.classList.add("on"); + newSkill.style.display = ""; + } + }; + ui.create.div(".config.more.margin-bottom", `
      返回`, page, function () { + ui.create.templayer(); + page.hide(); + if (page.fromchar) { + dash1.show(); + delete page.fromchar; + } + else { + pageboard.show(); + } + }); + var currentButton = null; + var clickButton = function () { + if (currentButton == this) { + resetEditor(); + return; + } + resetEditor(); + currentButton = this; + toggle.classList.add("on"); + newSkill.style.display = ""; + if (page.content.pack.translate[this.link] != this.link) { + newSkill.querySelector(".new_name").value = this.link + "|" + page.content.pack.translate[this.link]; + } + else { + newSkill.querySelector(".new_name").value = this.link; + } + newSkill.querySelector(".new_description").value = page.content.pack.translate[this.link + "_info"]; + var info = page.content.pack.skill[this.link]; + container.code = "skill=" + get.stringify(info); + + toggle.innerHTML = "编辑技能
      >
      "; + editnode.innerHTML = "编辑技能"; + editnode.classList.remove("disabled"); + delnode.button = this; + delnode.innerHTML = "删除"; + } + var createButton = function (name) { + var button = ui.create.div(".menubutton"); + button.link = name; + button.innerHTML = page.content.pack.translate[name]; + button.listen(clickButton); + page.insertBefore(button, page.childNodes[1]); + } + var newSkill; + var toggle = ui.create.div(".config.more.on", "创建技能
      >
      ", page, function () { + this.classList.toggle("on"); + if (this.classList.contains("on")) { + newSkill.style.display = ""; + } + else { + newSkill.style.display = "none"; + } + }); + page.toggle = toggle; + var resetEditor = function () { + currentButton = null; + toggle.classList.remove("on"); + newSkill.style.display = "none"; + var inputs = newSkill.querySelectorAll("input"); + for (var i = 0; i < inputs.length; i++) { + inputs[i].value = ""; + } + var inputs = newSkill.querySelectorAll("textarea"); + for (var i = 0; i < inputs.length; i++) { + inputs[i].value = ""; + } + toggle.innerHTML = "创建技能
      >
      "; + editnode.innerHTML = "创建技能"; + editnode.classList.add("disabled"); + delnode.innerHTML = "取消"; + delete delnode.button; + container.code = `skill={\n \n}\n\n/*\n示例:\nskill={\n trigger:{player:"phaseJieshuBegin"},\n frequent:true,\n content:function(){\n player.draw()\n }\n}\n此例为闭月代码\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + if (page.fromchar == "add") { + page.fromchar = true; + } + } + + newSkill = ui.create.div(".new_character.new_skill", page); + page.newSkill = newSkill; + var namenode = ui.create.div(".config", `名称:`, newSkill); + var descnode = ui.create.div(".config", `描述:`, newSkill); + namenode.querySelector("input.new_name").onblur = updateButton; + var commandline = ui.create.div(".config", newSkill); + var editbutton = document.createElement("button"); + editbutton.innerHTML = "编辑代码"; + commandline.appendChild(editbutton); + editbutton.onclick = function () { + var node = container; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + window.saveNonameInput = saveInput; + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, editor); + } + } + } + + var container = ui.create.div(".popup-container.editor"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + var skill = null; + eval(code); + if (skill == null || typeof skill != "object") { + throw ("err"); + } + } + catch (e) { + if (e == "err") { + alert("代码格式有错误,请对比示例代码仔细检查"); + } + else { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + } + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + dash3.link.classList.add("active"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + delete window.saveNonameInput; + }; + var editor = ui.create.editor(container, saveInput); + container.code = `skill={\n \n}\n\n/*\n示例:\nskill={\n trigger:{player:"phaseJieshuBegin"},\n frequent:true,\n content:function(){\n player.draw()\n }\n}\n此例为闭月代码\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + + var citebutton = document.createElement("button"); + citebutton.innerHTML = "引用代码"; + commandline.appendChild(citebutton); + citebutton.onclick = function () { + editbutton.style.display = "none"; + citebutton.style.display = "none"; + selectname.style.display = ""; + skillopt.style.display = ""; + addSkillButton.style.display = ""; + cancelSkillButton.style.display = ""; + } + + var list = []; + for (var i in lib.character) { + if (lib.character[i][3].length) { + list.push([i, lib.translate[i]]); + } + } + list.sort(function (a, b) { + a = a[0]; b = b[0]; + var aa = a, bb = b; + if (aa.includes("_")) { + aa = aa.slice(aa.indexOf("_") + 1); + } + if (bb.includes("_")) { + bb = bb.slice(bb.indexOf("_") + 1); + } + if (aa != bb) { + return aa > bb ? 1 : -1; + } + return a > b ? 1 : -1; + }); + list.push(["others", "其它"]); + var list2 = []; + var skills = lib.character[list[0][0]][3]; + for (var i = 0; i < skills.length; i++) { + list2.push([skills[i], lib.translate[skills[i]]]); + } + var selectname = ui.create.selectlist(list, list[0], commandline); + var list3 = []; + for (var i in lib.skill) { + if (i != "global" && !get.is.empty(lib.skill[i]) && !lib.skilllist.contains(i)) { + list3.push(i); + } + } + list3.sort(function (a, b) { + return a > b ? 1 : -1; + }); + selectname.onchange = function () { + var skills; + skillopt.innerHTML = ""; + if (this.value == "others") { + skills = list3; + for (var i = 0; i < skills.length; i++) { + var option = document.createElement("option"); + option.value = skills[i]; + option.innerHTML = skills[i]; + skillopt.appendChild(option); + } + } + else { + skills = lib.character[this.value][3]; + for (var i = 0; i < skills.length; i++) { + var option = document.createElement("option"); + option.value = skills[i]; + option.innerHTML = lib.translate[skills[i]]; + skillopt.appendChild(option); + } + } + }; + selectname.style.display = "none"; + selectname.style.maxWidth = "80px"; + var skillopt = ui.create.selectlist(list2, list2[0], commandline); + skillopt.style.display = "none"; + skillopt.style.maxWidth = "60px"; + var addSkillButton = document.createElement("button"); + addSkillButton.style.display = "none"; + addSkillButton.innerHTML = "引用"; + commandline.appendChild(addSkillButton); + addSkillButton.onclick = function () { + editbutton.style.display = ""; + citebutton.style.display = ""; + selectname.style.display = "none"; + skillopt.style.display = "none"; + addSkillButton.style.display = "none"; + cancelSkillButton.style.display = "none"; + container.code = "skill=" + get.stringify(lib.skill[skillopt.value]); + editbutton.onclick.call(editbutton); + if (lib.translate[skillopt.value + "_info"]) { + newSkill.querySelector("input.new_description").value = lib.translate[skillopt.value + "_info"]; + } + } + var cancelSkillButton = document.createElement("button"); + cancelSkillButton.style.display = "none"; + cancelSkillButton.innerHTML = "取消"; + commandline.appendChild(cancelSkillButton); + cancelSkillButton.onclick = function () { + editbutton.style.display = ""; + citebutton.style.display = ""; + selectname.style.display = "none"; + skillopt.style.display = "none"; + addSkillButton.style.display = "none"; + cancelSkillButton.style.display = "none"; + } + + var editnode = ui.create.div(".menubutton.large.new_skill.disabled", "创建技能", function () { + var name = page.querySelector("input.new_name").value; + if (!name) { + alert("请填写技能名\n提示:技能名格式为id+|+中文名,其中id必须惟一"); + return; + } + name = name.split("|"); + var translate = name[1] || name[0]; + var info = page.querySelector("input.new_description").value; + name = name[0]; + if (currentButton) { + if (currentButton.link != name) { + if (lib.skill[name] || page.content.pack.skill[name]) { + alert("技能名与现有技能重复,请更改\n提示:技能名格式为id+|+中文名,其中id必须惟一"); + return; + } + delete page.content.pack.skill[currentButton.link]; + delete page.content.pack.translate[currentButton.link]; + delete page.content.pack.translate[currentButton.link + "_info"]; + currentButton.link = name; + } + } + else { + if (lib.skill[name] || page.content.pack.skill[name]) { + alert("技能名与现有技能重复,请更改\n提示:技能名格式为id+|+中文名,其中id必须惟一"); + return; + } + } + page.content.pack.translate[name] = translate; + page.content.pack.translate[name + "_info"] = info; + try { + var skill = null; + eval(container.code); + if (skill == null || typeof skill != "object") { + throw ("err"); + } + page.content.pack.skill[name] = skill; + } + catch (e) { + page.content.pack.skill[name] = {}; + } + dash1.selectname.value = "current_extension"; + dash1.selectname.onchange.call(dash1.selectname); + if (this.innerHTML == "创建技能") { + createButton(name); + if (page.fromchar == "add") { + ui.create.templayer(); + page.hide(); + dash1.show(); + dash1.skillopt.value = name; + dash1.addSkillButton.onclick(); + delete page.fromchar; + } + } + else if (currentButton) { + currentButton.innerHTML = translate; + } + resetEditor(); + dash3.link.classList.add("active"); + dash1.updateSkill(); + }, newSkill); + var delnode = ui.create.div(".menubutton.large.new_card_delete", "取消", editnode.parentNode, function () { + if (this.innerHTML == "删除") { + this.button.remove(); + var name = this.button.link; + delete dash3.content.pack.skill[name]; + delete dash3.content.pack.translate[name]; + delete dash3.content.pack.translate[name + "_info"]; + dash3.link.classList.add("active"); + if (get.is.empty(dash3.content.pack.skill)) { + dash1.selectname.value = dash1.selectname.childNodes[1].value; + } + dash1.selectname.onchange.call(dash1.selectname); + dash1.updateSkill(); + resetEditor(); + } + else if (page.fromchar == "add") { + ui.create.templayer(); + page.hide(); + dash1.show(); + delete page.fromchar; + setTimeout(resetEditor, 600); + } + else { + resetEditor(); + } + }); + + page.content = { + pack: { + skill: {}, + translate: {} + }, + audio: {} + }; + return page; + }()); + var dash4 = (function () { + var page = ui.create.div(".hidden.menu-buttons"); + ui.create.div(".config.more.margin-bottom", `
      返回`, page, function () { + ui.create.templayer(); + page.hide(); + pageboard.show(); + }); + page.reset = function (name) { + page.content = {}; + if (lib.extensionPack[name]) { + for (var i in dashes) { + dashes[i].node.code = ""; + } + for (var i in lib.extensionPack[name].code) { + switch (typeof lib.extensionPack[name].code[i]) { + case "function": page.content[i] = lib.extensionPack[name].code[i].toString(); break; + case "object": page.content[i] = i + "=" + get.stringify(lib.extensionPack[name].code[i]); break; + } + } + for (var i in page.content) { + dashes[i].node.code = page.content[i] || ""; + } + } + else { + dashes.content.node.code = "function(config,pack){\n \n}\n\n/*\n函数执行时机为游戏数据加载之后、界面加载之前\n参数1扩展选项(见选项代码);参数2为扩展定义的武将、卡牌和技能等(可在此函数中修改)\n导出时本段代码中的换行、缩进以及注释将被清除\n*/"; + dashes.precontent.node.code = "function(){\n \n}\n\n/*\n函数执行时机为游戏数据加载之前,且不受禁用扩展的限制\n除添加模式外请慎用\n导出时本段代码中的换行、缩进以及注释将被清除\n*/"; + dashes.config.node.code = `config={\n \n}\n\n/*\n示例:\nconfig={\n switcher_example:{\n name:"示例列表选项",\n init:"3",\n item:{"1":"一","2":"二","3":"三"}\n },\n toggle_example:{\n name:"示例开关选项",\n init:true\n }\n}\n此例中传入的主代码函数的默认参数为{switcher_example:"3",toggle_example:true}\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + dashes.help.node.code = `help={\n \n}\n\ns/*\n示例:\nhelp={\n "帮助条目":"
      • 列表1-条目1
      • 列表1-条目2
      1. 列表2-条目1
      2. 列表2-条目2"\n}\n帮助内容将显示在菜单-选项-帮助中\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`; + } + }; + var dashes = {}; + var createCode = function (str1, str2, sub, func, link, str) { + var dash = ui.create.div(".menubutton.large.dashboard"); + dashes[link] = dash; + sub.appendChild(dash); + dash.listen(func); + dash.link = link; + ui.create.div("", str1, dash); + ui.create.div("", str2, dash); + var container = ui.create.div(".popup-container.editor"); + var saveInput = function () { + var code; + if (container.editor) { + code = container.editor.getValue(); + } + else if (container.textarea) { + code = container.textarea.value; + } + try { + if (link == "content" || link == "precontent") { + var func = null; + eval("func=" + code); + if (typeof func != "function") { + throw ("err"); + } + } + else if (link == "config") { + var config = null; + eval(code); + if (config == null || typeof config != "object") { + throw ("err"); + } + } + else if (link == "help") { + var help = null; + eval(code); + if (help == null || typeof help != "object") { + throw ("err"); + } + } + } + catch (e) { + if (e == "err") { + alert("代码格式有错误,请对比示例代码仔细检查"); + } + else { + var tip = lib.getErrorTip(e) || ""; + alert("代码语法有错误,请仔细检查(" + e + ")" + tip); + } + window.focus(); + if (container.editor) { + container.editor.focus(); + } + else if (container.textarea) { + container.textarea.focus(); + } + return; + } + dash4.link.classList.add("active"); + ui.window.classList.remove("shortcutpaused"); + ui.window.classList.remove("systempaused"); + container.delete(); + container.code = code; + page.content[link] = code; + delete window.saveNonameInput; + }; + var editor = ui.create.editor(container, saveInput); + container.code = str; + dash.editor = editor; + dash.node = container; + dash.saveInput = saveInput; + page.content[link] = str; + }; + var clickCode = function () { + var node = this.node; + ui.window.classList.add("shortcutpaused"); + ui.window.classList.add("systempaused"); + window.saveNonameInput = this.saveInput; + if (node.aced) { + ui.window.appendChild(node); + node.editor.setValue(node.code, 1); + } + else if (lib.device == "ios") { + ui.window.appendChild(node); + if (!node.textarea) { + var textarea = document.createElement("textarea"); + this.editor.appendChild(textarea); + node.textarea = textarea; + lib.setScroll(textarea); + } + node.textarea.value = node.code; + } + else { + if (!window.CodeMirror) { + lib.init.js(lib.assetURL + "game", "codemirror", () => lib.codeMirrorReady(node, this.editor)); + lib.init.css(lib.assetURL + "layout/default", "codemirror"); + } + else { + lib.codeMirrorReady(node, this.editor); + } + } + }; + page.content = {} + createCode("主", "主代码", page, clickCode, "content", "function(config,pack){\n \n}\n\n/*\n函数执行时机为游戏数据加载之后、界面加载之前\n参数1扩展选项(见选项代码);参数2为扩展定义的武将、卡牌和技能等(可在此函数中修改)\n导出时本段代码中的换行、缩进以及注释将被清除\n*/"); + createCode("启", "启动代码", page, clickCode, "precontent", "function(){\n \n}\n\n/*\n函数执行时机为游戏数据加载之前,且不受禁用扩展的限制\n除添加模式外请慎用\n导出时本段代码中的换行、缩进以及注释将被清除\n*/"); + createCode("选", "选项代码", page, clickCode, "config", `config={\n \n}\n\n/*\n示例:\nconfig={\n switcher_example:{\n name:"示例列表选项",\n init:"3",\n item:{"1":"一","2":"二","3":"三"}\n },\n toggle_example:{\n name:"示例开关选项",\n init:true\n }\n}\n此例中传入的主代码函数的默认参数为{switcher_example:"3",toggle_example:true}\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`); + createCode("帮", "帮助代码", page, clickCode, "help", `help={\n \n}\n\n/*\n示例:\nhelp={\n "帮助条目":"
        • 列表1-条目1
        • 列表1-条目2
        1. 列表2-条目1
        2. 列表2-条目2"\n}\n帮助内容将显示在菜单-选项-帮助中\n导出时本段代码中的换行、缩进以及注释将被清除\n*/`); + + return page; + }()); + createDash("将", "编辑武将", dash1); + createDash("卡", "编辑卡牌", dash2); + createDash("技", "编辑技能", dash3); + createDash("码", "编辑代码", dash4); + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + (function () { + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "获取扩展", start.firstChild, clickMode); + node.mode = "get"; + var _thisUpdate = false; + node.update = function () { + _thisUpdate = true; + }; + node._initLink = function () { + node.link = page; + page.listen(function () { + if (!page.currenttimeout) { + var active = page.querySelector(".videonode.current"); + if (active) { + active.classList.remove("current"); + } + } + }); + var importextensionexpanded = false; + page.style.paddingBottom = "10px"; + var importExtension; + var extensionNode = ui.create.div(".config.more", "导入扩展
          >
          ", page, function () { + if (importextensionexpanded) { + this.classList.remove("on"); + importExtension.style.display = "none"; + } + else { + this.classList.add("on"); + importExtension.style.display = ""; + } + importextensionexpanded = !importextensionexpanded; + }); + importExtension = ui.create.div(".new_character.export.import", page); + importExtension.style.marginLeft = "5px"; + importExtension.style.marginTop = "5px"; + importExtension.style.marginBottom = "5px"; + importExtension.style.display = "none"; + importExtension.style.width = "100%"; + importExtension.style.textAlign = "left"; + ui.create.div("", ``, importExtension); + ui.create.div(".config", "修改下载地址", page, function () { + alert("您可以在“设置→通用→获取扩展地址”中,修改下载扩展时所采用的地址。") + }) + + var extensionURL; + var source = lib.config.extension_sources, index = lib.config.extension_source; + if (source && source[index]) extensionURL = source[index]; + else extensionURL = lib.updateURL.replace(/noname/g, "noname-extension") + "/master/"; + + var reloadnode = ui.create.div(".config.toggle.pointerdiv", "重新启动", page, game.reload); + reloadnode.style.display = "none"; + var placeholder = ui.create.div(".config.toggle", page); + placeholder.style.height = 0; + placeholder.style.marginTop = "5px"; + + importExtension.firstChild.lastChild.onclick = function () { + const fileToLoad = this.previousSibling.files[0]; + if (!fileToLoad) return; + new Promise((resolve, reject) => { + const fileReader = new FileReader(); + fileReader.onerror = reject; + fileReader.onload = resolve; + fileReader.readAsArrayBuffer(fileToLoad, "UTF-8"); + }).then(progressEvent => { + if (game.importExtension(progressEvent.target.result, () => { + extensionNode.innerHTML = "导入成功,3秒后将重启"; + new Promise(resolve => setTimeout(resolve, 1000)).then(() => { + extensionNode.innerHTML = "导入成功,2秒后将重启"; + return new Promise(resolve => setTimeout(resolve, 1000)); + }).then(() => { + extensionNode.innerHTML = "导入成功,1秒后将重启"; + return new Promise(resolve => setTimeout(resolve, 1000)); + }).then(game.reload); + }) !== false) importExtension.style.display = "none"; + }); + } + + var clickExtension = function () { + var active = this.parentNode.querySelector(".videonode.current"); + if (active && active != this) { + active.classList.remove("current"); + } + this.classList.add("current"); + clearTimeout(page.currenttimeout); + page.currenttimeout = setTimeout(function () { + delete page.currenttimeout; + }, 200); + }; + var downloadExtension = function (e) { + if ((this.innerHTML != "下载扩展" && this.innerHTML != "更新扩展") || !window.JSZip) return; + this.classList.remove("update"); + if (e) { + e.stopPropagation(); + } + node.updated = true; + var that = this; + var list = []; + var size = parseFloat(this.info.size) || 0; + if (size) { + if (this.info.size.includes("MB")) { + size *= 1024 * 1024; + } + else if (this.info.size.includes("KB")) { + size *= 1024; + } + } + + this.innerHTML = "正在下载
          正在下载
          "; + this.classList.add("nopointer"); + this.classList.add("button-downloading"); + var progress = ui.create.div(".button-progress", this); + ui.create.div(progress); + var url = extensionURL + this.info.name + ".zip"; + var onprogress = function (byte, total) { + if (total) { + size = total; + } + if (byte == -1) { + byte = size; + } + progress.firstChild.style.width = Math.round(100 * byte / size) + "%"; + }; + var files = this.info.files || []; + for (var i = 0; i < files.length; i++) { + files[i] = "extension/" + that.info.name + "/" + files[i]; + } + game.checkFileList(files, function () { + files.unshift("extension/" + that.info.name + "/extension.js"); + for (var i = 0; i < files.length; i++) { + files[i] = extensionURL + that.info.name + "/" + files[i].slice(10 + that.info.name.length + 1); + } + var n1 = 0, n2 = files.length; + game.multiDownload(files, function () { + n1++; + onprogress(n1, n2); + }, function (e) { + game.print("下载失败:" + e.source); + }, function () { + onprogress(-1); + _status.importingExtension = true; + window.game = game; + lib.init.js(lib.assetURL + "extension/" + that.info.name, "extension", function () { + if (!lib.config.dev) delete window.game; + if (game.importedPack) { + var extname = game.importedPack.name; + if (lib.config.extensions.contains(extname)) { + game.removeExtension(extname, true); + } + lib.config.extensions.add(extname); + game.saveConfig("extensions", lib.config.extensions); + game.saveConfig("extension_" + extname + "_enable", true); + game.saveConfig("extension_" + extname + "_version", that.info.version); + for (var i in game.importedPack.config) { + if (game.importedPack.config[i] && Object.prototype.hasOwnProperty.call(game.importedPack.config[i], "init")) { + game.saveConfig("extension_" + extname + "_" + i, game.importedPack.config[i].init); + } + } + reloadnode.style.display = ""; + that.childNodes[0].innerHTML = "安装成功"; + that.childNodes[1].innerHTML = "安装成功"; + that.classList.remove("active"); + that.classList.remove("highlight"); + delete game.importedPack; + } + else { + that.innerHTML = "安装失败"; + that.classList.add("nopointer"); + } + _status.importingExtension = false; + }, function () { + that.innerHTML = "下载失败"; + that.classList.add("nopointer"); + _status.importingExtension = false; + }); + }, function (current) { + return "extension/" + current.slice(extensionURL.length); + }); + }); + }; + + node.update = function () { + if (this.updated) return; + if (!window.JSZip) { + lib.init.js(lib.assetURL + "game", "jszip"); + } + var toremove = []; + for (var i = 0; i < page.childElementCount; i++) { + if (page.childNodes[i].classList.contains("menubutton") || page.childNodes[i].classList.contains("loading")) { + toremove.push(page.childNodes[i]); + } + } + for (var i = 0; i < toremove.length; i++) { + toremove[i].remove(); + } + + var loading = ui.create.div(".loading.config.toggle", "载入中...", page); + var loaded = function () { + var list = []; + var extension = window.extension; + for (var i in extension) { + extension[i].name = i; + list.push(extension[i]); + } + list.randomSort(); + delete window.extension; + loading.style.display = "none"; + for (var i = 0; i < list.length; i++) { + var node = ui.create.div(".videonode.menubutton.extension.large", page, clickExtension); + ui.create.div(".caption", list[i].name, node); + ui.create.div(".text.author", "作者:" + list[i].author + "(" + list[i].size + ")", node); + ui.create.div(".text", "更新日期:" + list[i].date, node); + ui.create.div(".text", list[i].intro, node); + var download = ui.create.div(".menubutton.text.active", "下载扩展", node.firstChild, { "zIndex": "5" }); + if (game.download) { + if (list[i].netdisk) { + var linknode = ui.create.div(".text", node); + ui.create.node("span.hrefnode", "网盘链接", function () { + game.open(this.link); + }, linknode).link = list[i].netdisk; + if (list[i].forum) { + ui.create.node("span", linknode).style.marginRight = "10px"; + ui.create.node("span.hrefnode", "参与讨论", function () { + game.open(this.link); + }, linknode).link = list[i].forum; + } + } + else if (list[i].forum) { + var linknode = ui.create.div(".text", node); + ui.create.node("span.hrefnode", "参与讨论", function () { + game.open(this.link); + }, linknode).link = list[i].forum; + } + download.listen(downloadExtension); + if (lib.config.extensions.includes(list[i].name)) { + download.classList.remove("active"); + if (lib.extensionPack[list[i].name] && lib.extensionPack[list[i].name].version == list[i].version) { + download.classList.add("transparent2"); + download.classList.remove("active"); + download.innerHTML = "已安装"; + } + else if (lib.config["extension_" + list[i].name + "_version"] != list[i].version) { + download.innerHTML = "更新扩展"; + download.classList.add("highlight"); + download.classList.add("update"); + } + else { + download.classList.add("transparent2"); + download.classList.remove("active"); + download.innerHTML = "已安装"; + } + } + download.info = list[i]; + } + else { + if (list[i].forum) { + var linknode = ui.create.div(".text", node); + ui.create.node("span", linknode); + ui.create.node("span.hrefnode", "参与讨论", function () { + game.open(this.link); + }, linknode).link = list[i].forum; + } + download.listen(function () { + game.open(this.link); + }); + download.link = list[i].netdisk; + } + } + }; + window.extension = {}; + fetch(`${extensionURL}catalog.js`, { + referrerPolicy: "no-referrer" + }).then(response => response.text()).then(eval).then(loaded).catch(reason => { + console.log(reason); + delete window.extension; + loading.innerHTML = "连接失败:" + (reason instanceof Error ? reason.message : String(reason)); + }); + }; + if (_thisUpdate) node.update(); + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + active.classList.add("active"); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + updateNodes(); + }()); + + (function () { + if (connectMenu) return; + var start = menuxpages.shift(); + var rightPane = start.lastChild; + var cheatButton = ui.create.div(".menubutton.round.highlight", "作", start); + cheatButton.style.display = "none"; + var runButton = ui.create.div(".menubutton.round.highlight", "执", start); + runButton.style.display = "none"; + var clearButton = ui.create.div(".menubutton.round.highlight", "清", start); + clearButton.style.display = "none"; + clearButton.style.left = "275px"; + var playButton = ui.create.div(".menubutton.round.highlight.hidden", "播", start); + playButton.style.display = "none"; + playButton.style.left = "215px"; + playButton.style.transition = "opacity 0.3s"; + var deleteButton = ui.create.div(".menubutton.round.highlight.hidden", "删", start); + deleteButton.style.display = "none"; + deleteButton.style.left = "275px"; + deleteButton.style.transition = "opacity 0.3s"; + var saveButton = ui.create.div(".menubutton.round.highlight.hidden", "存", start); + saveButton.style.display = "none"; + saveButton.style.transition = "opacity 0.3s"; + + + var clickMode = function () { + if (this.classList.contains("off")) return; + var active = this.parentNode.querySelector(".active"); + if (active === this) { + return; + } + if (active) { + active.classList.remove("active"); + active.link.remove(); + } + active = this; + this.classList.add("active"); + if (this.link) rightPane.appendChild(this.link); + else { + this._initLink(); + rightPane.appendChild(this.link); + } + if (this.type == "cheat") { + cheatButton.style.display = ""; + } + else { + cheatButton.style.display = "none"; + } + if (this.type == "cmd") { + runButton.style.display = ""; + clearButton.style.display = ""; + } + else { + runButton.style.display = "none"; + clearButton.style.display = "none"; + } + if (this.type == "video") { + playButton.style.display = ""; + saveButton.style.display = ""; + deleteButton.style.display = ""; + } + else { + playButton.style.display = "none"; + saveButton.style.display = "none"; + deleteButton.style.display = "none"; + } + }; + + ui.click.consoleMenu = function () { + ui.click.menuTab("其它"); + clickMode.call(ui.commandnode); + }; + //更新菜单有本体函数赋值,就不要懒加载了 + (function () { + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "更新", start.firstChild, clickMode); + node.link = page; + page.classList.add("menu-help"); + var ul = document.createElement("ul"); + var li1 = document.createElement("li"); + var li2 = document.createElement("li"); + var li3 = document.createElement("li"); + const trimURL = url => { + const updateURLS = lib.updateURLS; + for (const key in updateURLS) { + const updateURL = updateURLS[key]; + if (url == updateURL) return lib.configMenu.general.config.update_link.item[key]; + } + let index = url.indexOf("://"); + if (index != -1) url = url.slice(index + 3); + index = url.indexOf("/"); + if (index != -1) url = url.slice(0, index); + if (url.length > 15) { + const list = url.split("."); + if (list.length > 1) list.shift(); + url = list.join("."); + } + if (url.length > 15) { + const list = url.split("."); + if (list.length > 1) list.pop(); + url = list.join("."); + } + return url; + } + li1.innerHTML = `游戏版本:${lib.version}

          `; + li2.innerHTML = `素材版本:${lib.config.asset_version || "无"}

          `; + li3.innerHTML = `更新地址:${trimURL(lib.config.updateURL || lib.updateURL)}

          `; + li3.style.whiteSpace = "nowrap"; + li3.style.display = "none";// coding + + var button1, button2, button3, button4, button5; + + game.checkForUpdate = function (forcecheck, dev) { + if (!dev && button1.disabled) { + return; + } + else if (dev && button3.disabled) { + return; + } + else if (!game.download) { + alert("此版本不支持游戏内更新,请手动更新"); + return; + } + else { + if (dev) { + button3.innerHTML = "正在检查更新"; + } + else { + button1.innerHTML = "正在检查更新"; + } + button3.disabled = true; + button1.disabled = true; + + var goupdate = function (files, update) { + lib.version = update.version; + if (update.dev && !lib.config.debug) { + dev = "nodev"; + } + lib.init.req("game/source.js", function () { + try { + eval(this.responseText); + if (!window.noname_source_list) { + throw ("err"); + } + } + catch (e) { + alert("更新地址有误"); + console.log(e); + return; + } + + var updates = window.noname_source_list; + delete window.noname_source_list; + if (Array.isArray(files)) { + files.add("game/update.js"); + var files2 = []; + for (var i = 0; i < files.length; i++) { + var str = files[i].indexOf("*"); + if (str != -1) { + str = files[i].slice(0, str); + files.splice(i--, 1); + for (var j = 0; j < updates.length; j++) { + if (updates[j].startsWith(str)) { + files2.push(updates[j]); + } + } + } + } + updates = files.concat(files2); + } + for (var i = 0; i < updates.length; i++) { + if (updates[i].startsWith("theme/") && !updates[i].includes(".css")) { + updates.splice(i--, 1); + } + else if (updates[i].startsWith("node_modules/") && !update.node) { + updates.splice(i--, 1); + } + } + + if (!ui.arena.classList.contains("menupaused")) { + ui.click.configMenu(); + ui.click.menuTab("其它"); + } + var p = button1.parentNode; + button1.remove(); + button3.remove(); + var span = document.createElement("span"); + var n1 = 0; + var n2 = updates.length; + span.innerHTML = "正在下载文件(" + n1 + "/" + n2 + ")"; + p.appendChild(span); + var finish = function () { + span.innerHTML = "游戏更新完毕(" + n1 + "/" + n2 + ")"; + p.appendChild(document.createElement("br")); + var button = document.createElement("button"); + button.innerHTML = "重新启动"; + button.onclick = game.reload; + button.style.marginTop = "8px"; + p.appendChild(button); + } + game.multiDownload(updates, function () { + n1++; + span.innerHTML = "正在下载文件(" + n1 + "/" + n2 + ")"; + }, function (e) { + game.print("下载失败:" + e.source); + }, function () { + setTimeout(finish, 500); + }, null, dev); + }, function () { + alert("更新地址有误"); + }, true); + }; + + lib.init.req("game/update.js", function () { + try { + eval(this.responseText); + if (!window.noname_update) { + throw ("err"); + } + } + catch (e) { + alert("更新地址有误"); + console.log(e); + return; + } + + var update = window.noname_update; + delete window.noname_update; + if (forcecheck === false) { + if (update.version == lib.config.check_version) { + return; + } + } + game.saveConfig("check_version", update.version); + var goon = true; + if (!dev) { + if (update.version.includes("beta") || update.version == lib.version) { + goon = false; + } + } + if (goon) { + var files = null; + var version = lib.version; + if (Array.isArray(update.dev) && dev) { + files = update.dev; + } + else if (Array.isArray(update.files) && update.update && !dev) { + var version1 = version.split("."); + var version2 = update.update.split("."); + for (var i = 0; i < version1.length && i < version2.length; i++) { + if (version2[i] > version1[i]) { + files = false; break; + } + else if (version1[i] > version2[i]) { + files = update.files.slice(0); break; + } + } + if (files === null) { + if (version1.length >= version2.length) { + files = update.files.slice(0); + } + } + } + var str; + if (dev) { + str = "开发版仅供测试使用,可能存在风险,是否确定更新?" + } + else { + str = "有新版本" + update.version + "可用,是否下载?"; + } + if (navigator.notification && navigator.notification.confirm) { + var str2; + if (dev) { + str2 = str; + str = "更新到开发版"; + } + else { + str2 = update.changeLog[0]; + for (var i = 1; i < update.changeLog.length; i++) { + if (update.changeLog[i].indexOf("://") == -1) { + str2 += ";" + update.changeLog[i]; + } + } + } + navigator.notification.confirm( + str2, + function (index) { + if (index == 1) { + goupdate(files, update); + } + else { + button1.disabled = false; + button1.innerHTML = "检查游戏更新"; + button3.disabled = false; + button3.innerHTML = "更新到开发版"; + } + }, + str, + ["确定", "取消"] + ); + } + else { + if (confirm(str)) { + goupdate(files, update); + } + else { + button1.disabled = false; + button1.innerHTML = "检查游戏更新"; + button3.disabled = false; + button3.innerHTML = "更新到开发版"; + } + } + } + else { + alert("当前版本已是最新"); + button1.disabled = false; + button1.innerHTML = "检查游戏更新"; + button3.disabled = false; + button3.innerHTML = "更新到开发版"; + } + }, function () { + if (forcecheck === false) { + return; + } + alert("连接失败"); + button1.disabled = false; + button1.innerHTML = "检查游戏更新"; + button3.disabled = false; + button3.innerHTML = "更新到开发版"; + }, true); + } + }; + game.checkForAssetUpdate = function (type) { + if (button2.disabled) { + return; + } + else if (game.download) { + button2.innerHTML = "正在检查更新"; + button2.disabled = true; + lib.init.req("game/asset.js", function () { + try { + eval(this.responseText); + if (!window.noname_asset_list || !window.noname_skin_list) { + throw ("err"); + } + } + catch (e) { + alert("更新地址有误"); + console.log(e); + return; + } + + var updates = window.noname_asset_list; + delete window.noname_asset_list; + var skins = window.noname_skin_list; + delete window.noname_skin_list; + var asset_version = updates.shift(); + + var skipcharacter = [], skipcard = ["tiesuo_mark", "shield"]; + if (!lib.config.asset_full) { + for (var i = 0; i < lib.config.all.sgscharacters.length; i++) { + var pack = lib.characterPack[lib.config.all.sgscharacters[i]]; + for (var j in pack) { + skipcharacter.add(j); + } + } + for (var i = 0; i < lib.config.all.sgscards.length; i++) { + var pack = lib.cardPack[lib.config.all.sgscards[i]]; + if (pack) { + skipcard = skipcard.concat(pack); + } + } + } + for (var i = 0; i < updates.length; i++) { + switch (updates[i].slice(0, 5)) { + case "image": { + if (!lib.config.asset_full) { + if (!lib.config.asset_image) { + updates.splice(i--, 1); + } + else { + if (updates[i].startsWith("image/character")) { + if (updates[i].indexOf("jun_") != 16 && updates[i].indexOf("gz_") != 16 && !skipcharacter.contains(updates[i].slice(16, updates[i].lastIndexOf(".")))) { + updates.splice(i--, 1); + } + } + else if (updates[i].startsWith("image/card")) { + let cardname = updates[i].slice(11, updates[i].lastIndexOf(".")); + if (lib.card[cardname] && !skipcard.contains(cardname)) { + updates.splice(i--, 1); + } + } + else if (updates[i].startsWith("image/mode/stone")) { + updates.splice(i--, 1); + } + } + } + break; + } + case "audio": { + if (!lib.config.asset_audio) { + updates.splice(i--, 1); + } + break; + } + case "font/": { + if (!lib.config.asset_font) { + updates.splice(i--, 1); + } + } + } + } + if (lib.config.asset_skin) { + for (var i in skins) { + for (var j = 1; j <= skins[i]; j++) { + updates.push("image/skin/" + i + "/" + j + ".jpg"); + } + } + } + if (!ui.arena.classList.contains("menupaused")) { + ui.click.configMenu(); + ui.click.menuTab("其它"); + } + + var proceed = function () { + if (updates.length == 0) { + game.print(updates); + game.saveConfig("asset_version", asset_version); + alert("素材已是最新"); + button2.disabled = false; + button2.innerHTML = "检查素材更新"; + return; + } + var p = button2.parentNode; + button2.remove(); + var span = document.createElement("span"); + span.style.whiteSpace = "nowrap"; + var n1 = 0; + var n2 = updates.length; + span.innerHTML = "正在下载素材(" + n1 + "/" + n2 + ")"; + span1.remove(); + span2.remove(); + span2_check.remove(); + span3.remove(); + span3_check.remove(); + span4.remove(); + span4_check.remove(); + span5.remove(); + span5_check.remove(); + span6.remove(); + span6_check.remove(); + span2_br.remove(); + span3_br.remove(); + span4_br.remove(); + span5_br.remove(); + span6_br.remove(); + p.appendChild(span); + + var br6 = ui.create.node("br"); + var span7 = ui.create.div(".hrefnode", "详细信息"); + span7.style.marginTop = "6px"; + span7.listen(ui.click.consoleMenu); + p.appendChild(br6); + p.appendChild(span7); + + var finish = function () { + if (n1 == n2) { + game.saveConfig("asset_version", asset_version); + } + span.innerHTML = "素材更新完毕(" + n1 + "/" + n2 + ")"; + p.appendChild(document.createElement("br")); + var button = document.createElement("button"); + button.innerHTML = "重新启动"; + button.onclick = game.reload; + button.style.marginTop = "8px"; + p.appendChild(button); + } + game.multiDownload(updates, function () { + n1++; + span.innerHTML = "正在下载素材(" + n1 + "/" + n2 + ")"; + }, function (e) { + game.print("下载失败:" + e.source); + }, function () { + setTimeout(finish, 500); + }); + }; + game.checkFileList(updates, proceed); + }, function () { + alert("连接失败"); + button2.disabled = false; + button2.innerHTML = "检查素材更新"; + }, true); + } + else { + alert("此版本不支持游戏内更新素材,请手动更新"); + } + }; + + button1 = document.createElement("button"); + button1.innerHTML = "检查游戏更新"; + button1.onclick = game.checkForUpdate; + li1.lastChild.appendChild(button1); + + button3 = document.createElement("button"); + button3.innerHTML = "更新到开发版"; + button3.style.marginLeft = "5px"; + button3.onclick = function () { + game.checkForUpdate(null, true); + }; + // if(lib.config.dev){ + // li1.lastChild.appendChild(button3); + // } + + (function () { + var updatep1 = li1.querySelector("p"); + var updatep2 = li2; + var updatep3 = li3; + var updatep4 = node; + var updatepx = ui.create.node("p"); + li1.appendChild(updatepx); + updatepx.style.display = "none"; + updatepx.style.whiteSpace = "nowrap"; + updatepx.style.marginTop = "8px"; + var buttonx = ui.create.node("button", "访问项目主页", function () { + window.open("https://github.com/libccy/noname"); + }); + updatepx.appendChild(buttonx); + ui.updateUpdate = function () { + if (!game.download) { + updatep1.style.display = "none"; + updatep2.style.display = "none"; + updatep3.style.display = "none"; + updatepx.style.display = ""; + updatep4.innerHTML = "关于"; + } + else { + updatep1.style.display = ""; + updatep2.style.display = ""; + updatep3.style.display = "none"; // coding + updatepx.style.display = "none"; + updatep4.innerHTML = "更新"; + } + } + ui.updateUpdate(); + }()); + + button4 = document.createElement("button"); + button4.innerHTML = "设置更新地址"; + button4.onclick = function () { + game.prompt("设置更新地址", function (str) { + if (str) { + game.saveConfig("updateURL", str); + li3.querySelector("span").innerHTML = trimURL(str); + button5.style.display = ""; + button6.style.display = "none"; + } + }); + }; + // li3.lastChild.appendChild(button4); + + var button6 = document.createElement("button"); + button6.innerHTML = "设为备用镜像"; + button6.style.display = "none";// coding + // button6.style.marginLeft="5px"; + button6.onclick = function () { + game.saveConfig("updateURL", lib.mirrorURL); + button5.style.display = ""; + button6.style.display = "none"; + li3.querySelector("span").innerHTML = trimURL(lib.mirrorURL); + }; + li3.lastChild.appendChild(button6); + + button5 = document.createElement("button"); + button5.innerHTML = "设为默认镜像"; + // button5.style.marginLeft="5px"; + button5.onclick = function () { + game.saveConfig("updateURL"); + button5.style.display = "none"; + button6.style.display = ""; + li3.querySelector("span").innerHTML = trimURL(lib.updateURL); + }; + li3.lastChild.appendChild(button5); + if (!lib.config.updateURL) { + button5.style.display = "none"; + } + else { + button6.style.display = "none"; + } + + button2 = document.createElement("button"); + button2.innerHTML = "检查素材更新"; + button2.onclick = game.checkForAssetUpdate; + li2.lastChild.appendChild(button2); + + var span1 = ui.create.div(".config.more", "选项
          >
          "); + span1.style.fontSize = "small"; + span1.style.display = "inline"; + span1.toggle = function () { + if (!this.classList.toggle("on")) { + game.saveConfig("asset_toggle_off", true); + span2.style.display = "none"; + span2_br.style.display = "none"; + span2_check.style.display = "none"; + span3.style.display = "none"; + span3_br.style.display = "none"; + span3_check.style.display = "none"; + span4.style.display = "none"; + span4_br.style.display = "none"; + span4_check.style.display = "none"; + span5.style.display = "none"; + span5_br.style.display = "none"; + span5_check.style.display = "none"; + span6.style.display = "none"; + span6_br.style.display = "none"; + span6_check.style.display = "none"; + } + else { + game.saveConfig("asset_toggle_off"); + span2.style.display = ""; + span2_br.style.display = ""; + span2_check.style.display = ""; + span3.style.display = ""; + span3_br.style.display = ""; + span3_check.style.display = ""; + span4.style.display = ""; + span4_br.style.display = ""; + span4_check.style.display = ""; + span5.style.display = ""; + span5_br.style.display = ""; + span5_check.style.display = ""; + span6.style.display = ""; + span6_br.style.display = ""; + span6_check.style.display = ""; + } + }; + span1.listen(span1.toggle); + li2.lastChild.appendChild(span1); + + var span6_br = ui.create.node("br"); + li2.lastChild.appendChild(span6_br); + + var span5 = ui.create.div("", "图片素材(精简,126MB)"); + span5.style.fontSize = "small"; + span5.style.lineHeight = "16px"; + var span5_check = document.createElement("input"); + span5_check.type = "checkbox"; + span5_check.style.marginLeft = "5px"; + if (lib.config.asset_image) { + span5_check.checked = true; + } + span5_check.onchange = function () { + game.saveConfig("asset_image", this.checked); + } + var span2_br = ui.create.node("br"); + + var span4 = ui.create.div("", "字体素材(48MB)"); + span4.style.fontSize = "small"; + span4.style.lineHeight = "16px"; + li2.lastChild.appendChild(span4); + var span4_check = document.createElement("input"); + span4_check.type = "checkbox"; + span4_check.style.marginLeft = "5px"; + if (lib.config.asset_font) { + span4_check.checked = true; + } + span4_check.onchange = function () { + game.saveConfig("asset_font", this.checked); + } + li2.lastChild.appendChild(span4_check); + var span3_br = ui.create.node("br"); + li2.lastChild.appendChild(span3_br); + + var span3 = ui.create.div("", "音效素材(125MB)"); + span3.style.fontSize = "small"; + span3.style.lineHeight = "16px"; + li2.lastChild.appendChild(span3); + var span3_check = document.createElement("input"); + span3_check.type = "checkbox"; + span3_check.style.marginLeft = "5px"; + if (lib.config.asset_audio) { + span3_check.checked = true; + } + span3_check.onchange = function () { + game.saveConfig("asset_audio", this.checked); + } + li2.lastChild.appendChild(span3_check); + var span4_br = ui.create.node("br"); + li2.lastChild.appendChild(span4_br); + + var span2 = ui.create.div("", "皮肤素材(351MB)"); + span2.style.fontSize = "small"; + span2.style.lineHeight = "16px"; + li2.lastChild.appendChild(span2); + var span2_check = document.createElement("input"); + span2_check.type = "checkbox"; + span2_check.style.marginLeft = "5px"; + if (lib.config.asset_skin) { + span2_check.checked = true; + } + span2_check.onchange = function () { + game.saveConfig("asset_skin", this.checked); + } + li2.lastChild.appendChild(span2_check); + var span5_br = ui.create.node("br"); + li2.lastChild.appendChild(span5_br); + + + li2.lastChild.appendChild(span5); + li2.lastChild.appendChild(span5_check); + li2.lastChild.appendChild(span2_br); + + var span6 = ui.create.div("", "图片素材(完整,203MB)"); + span6.style.fontSize = "small"; + span6.style.lineHeight = "16px"; + li2.lastChild.appendChild(span6); + var span6_check = document.createElement("input"); + span6_check.type = "checkbox"; + span6_check.style.marginLeft = "5px"; + if (lib.config.asset_full) { + span6_check.checked = true; + } + span6_check.onchange = function () { + game.saveConfig("asset_full", this.checked); + } + li2.lastChild.appendChild(span6_check); + + span2.style.display = "none"; + span2_br.style.display = "none"; + span2_check.style.display = "none"; + span3.style.display = "none"; + span3_br.style.display = "none"; + span3_check.style.display = "none"; + span4.style.display = "none"; + span4_br.style.display = "none"; + span4_check.style.display = "none"; + span5.style.display = "none"; + span5_br.style.display = "none"; + span5_check.style.display = "none"; + span6.style.display = "none"; + span6_br.style.display = "none"; + span6_check.style.display = "none"; + + ul.appendChild(li1); + ul.appendChild(li2); + ul.appendChild(li3); + page.appendChild(ul); + + + if (!lib.config.asset_toggle_off) { + span1.toggle(); + } + }()); + (function () { + var norow2 = function () { + var node = currentrow1; + if (!node) return false; + return node.innerHTML == "横置" || node.innerHTML == "翻面" || node.innerHTML == "换人" || node.innerHTML == "复活"; + }; + var checkCheat = function () { + if (norow2()) { + for (var i = 0; i < row2.childElementCount; i++) { + row2.childNodes[i].classList.remove("selectedx"); + row2.childNodes[i].classList.add("unselectable"); + } + } + else { + for (var i = 0; i < row2.childElementCount; i++) { + row2.childNodes[i].classList.remove("unselectable"); + } + } + if (currentrow1 && currentrow1.innerHTML == "复活") { + for (var i = 0; i < row3.childNodes.length; i++) { + if (row3.childNodes[i].dead) { + row3.childNodes[i].style.display = ""; + } + else { + row3.childNodes[i].style.display = "none"; + row3.childNodes[i].classList.remove("glow"); + } + row3.childNodes[i].classList.remove("unselectable"); + } + } + else { + for (var i = 0; i < row3.childElementCount; i++) { + if (currentrow1 && currentrow1.innerHTML == "换人" && row3.childNodes[i].link == game.me) { + row3.childNodes[i].classList.add("unselectable"); + } + else { + row3.childNodes[i].classList.remove("unselectable"); + } + if (!row3.childNodes[i].dead) { + row3.childNodes[i].style.display = ""; + } + else { + row3.childNodes[i].style.display = "none"; + row3.childNodes[i].classList.remove("glow"); + } + } + } + if (currentrow1 && (currentrow2 || norow2()) && row3.querySelector(".glow")) { + cheatButton.classList.add("glowing"); + return true; + } + else { + cheatButton.classList.remove("glowing"); + return false; + } + } + cheatButton.listen(function () { + if (checkCheat()) { + var num; + if (currentrow2) { + switch (currentrow2.innerHTML) { + case "一": num = 1; break; + case "二": num = 2; break; + case "三": num = 3; break; + case "四": num = 4; break; + case "五": num = 5; break; + } + } + var targets = []; + var buttons = row3.querySelectorAll(".glow"); + for (var i = 0; i < buttons.length; i++) { + targets.push(buttons[i].link); + } + while (targets.length) { + var target = targets.shift(); + switch (currentrow1.innerHTML) { + case "伤害": target.damage(num, "nosource"); break; + case "回复": target.recover(num, "nosource"); break; + case "摸牌": target.draw(num); break; + case "弃牌": target.discard(target.getCards("he").randomGets(num)); break; + case "横置": target.link(); break; + case "翻面": target.turnOver(); break; + case "复活": target.revive(target.maxHp); break; + case "换人": { + if (_status.event.isMine()) { + if (!ui.auto.classList.contains("hidden")) { + setTimeout(function () { + ui.click.auto(); + setTimeout(function () { + ui.click.auto(); + game.swapPlayer(target); + }, 500); + }); + } + } + else { + game.swapPlayer(target); + } + break; + } + } + } + if (ui.coin) { + game.changeCoin(-20); + } + clickContainer.call(menuContainer); + } + }); + + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "控制", start.firstChild, clickMode); + node.link = page; + node.type = "cheat"; + page.classList.add("menu-sym"); + + var currentrow1 = null; + var row1 = ui.create.div(".menu-cheat", page); + var clickrow1 = function () { + if (this.classList.contains("unselectable")) return; + if (currentrow1 == this) { + this.classList.remove("selectedx"); + currentrow1 = null; + } + else { + this.classList.add("selectedx"); + if (currentrow1) { + currentrow1.classList.remove("selectedx"); + } + currentrow1 = this; + if (this.innerHTML == "换人") { + for (var i = 0; i < row3.childNodes.length; i++) { + row3.childNodes[i].classList.remove("glow"); + } + } + } + checkCheat(); + }; + var nodedamage = ui.create.div(".menubutton", "伤害", row1, clickrow1); + var noderecover = ui.create.div(".menubutton", "回复", row1, clickrow1); + var nodedraw = ui.create.div(".menubutton", "摸牌", row1, clickrow1); + var nodediscard = ui.create.div(".menubutton", "弃牌", row1, clickrow1); + var nodelink = ui.create.div(".menubutton", "横置", row1, clickrow1); + var nodeturnover = ui.create.div(".menubutton", "翻面", row1, clickrow1); + var noderevive = ui.create.div(".menubutton", "复活", row1, clickrow1); + var nodereplace = ui.create.div(".menubutton", "换人", row1, clickrow1); + if (!game.canReplaceViewpoint || !game.canReplaceViewpoint()) { + nodereplace.classList.add("unselectable"); + } + + var currentrow2 = null; + var row2 = ui.create.div(".menu-cheat", page); + var clickrow2 = function () { + if (this.classList.contains("unselectable")) return; + if (currentrow2 == this) { + this.classList.remove("selectedx"); + currentrow2 = null; + } + else { + this.classList.add("selectedx"); + if (currentrow2) { + currentrow2.classList.remove("selectedx"); + } + currentrow2 = this; + } + checkCheat(); + }; + var nodex1 = ui.create.div(".menubutton", "一", row2, clickrow2); + var nodex2 = ui.create.div(".menubutton", "二", row2, clickrow2); + var nodex3 = ui.create.div(".menubutton", "三", row2, clickrow2); + var nodex4 = ui.create.div(".menubutton", "四", row2, clickrow2); + var nodex5 = ui.create.div(".menubutton", "五", row2, clickrow2); + + var row3 = ui.create.div(".menu-buttons.leftbutton.commandbutton", page); + row3.style.marginTop = "3px"; + var clickrow3 = function () { + if (this.classList.contains("unselectable")) return; + this.classList.toggle("glow"); + if (currentrow1 && currentrow1.innerHTML == "换人" && this.classList.contains("glow")) { + if (this.link == game.me) { + this.classList.remove("glow"); + } + for (var i = 0; i < row3.childElementCount; i++) { + if (row3.childNodes[i] != this) { + row3.childNodes[i].classList.remove("glow"); + } + } + } + checkCheat(); + }; + menuUpdates.push(function () { + if (_status.video || _status.connectMode) { + node.classList.add("off"); + if (node.classList.contains("active")) { + node.classList.remove("active"); + node.link.remove(); + active = start.firstChild.firstChild; + active.classList.add("active"); + rightPane.appendChild(active.link); + } + + page.remove(); + cheatButton.remove(); + if (_status.video) node.remove(); + return; + } + var list = []; + for (var i = 0; i < game.players.length; i++) { + if (lib.character[game.players[i].name] || game.players[i].name1) { + list.push(game.players[i]); + } + } + for (var i = 0; i < game.dead.length; i++) { + if (lib.character[game.dead[i].name] || game.dead[i].name1) { + list.push(game.dead[i]); + } + } + if (list.length) { + row1.show(); + row2.show(); + row3.innerHTML = ""; + var buttons = ui.create.buttons(list, "player", row3, true); + for (var i = 0; i < buttons.length; i++) { + buttons[i].listen(clickrow3); + if (game.dead.contains(buttons[i].link)) { + buttons[i].dead = true; + } + } + checkCheat(); + } + else { + row1.hide(); + row2.hide(); + } + if (lib.config.mode == "identity" || lib.config.mode == "guozhan" || lib.config.mode == "doudizhu") { + if (game.notMe || (game.me && (game.me._trueMe || game.hasPlayer(function (current) { + return current._trueMe == game.me; + }))) || !game.phaseNumber || _status.qianlidanji) { + nodereplace.classList.add("unselectable"); + } + else if (_status.event.isMine() && ui.auto.classList.contains("hidden")) { + nodereplace.classList.add("unselectable"); + } + else { + nodereplace.classList.remove("unselectable"); + } + } + if (game.dead.length == 0) { + noderevive.classList.add("unselectable"); + } + else { + noderevive.classList.remove("unselectable"); + } + checkCheat(); + }); + }()); + (function () { + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "命令", start.firstChild, clickMode); + ui.commandnode = node; + node.type = "cmd"; + menuUpdates.push(function () { + if (_status.connectMode) { + node.classList.add("off"); + if (node.classList.contains("active")) { + node.classList.remove("active"); + if (node.link) node.link.remove(); + active = start.firstChild.firstChild; + active.classList.add("active"); + rightPane.appendChild(active.link); + } + } + }); + node._initLink = function () { + node.link = page; + page.classList.add("menu-sym"); + + const text = document.createElement("div"); + text.css({ + "width": "194px", + "height": "124px", + "padding": "3px", + "borderRadius": "2px", + "boxShadow": "rgba(0, 0, 0, 0.2) 0 0 0 1px", + "textAlign": "left", + "webkitUserSelect": "initial", + "overflow": "scroll", + "position": "absolute", + "left": "30px", + "top": "50px", + "wordBreak": "break-all" + }); + + const pre = ui.create.node("pre.fullsize", text); + text.css.call(pre, { + "margin": "0", + "padding": "0", + "position": "relative", + "webkitUserSelect": "text", + "userSelect": "text" + }); + lib.setScroll(pre); + page.appendChild(text); + + const text2 = document.createElement("input"); + text.css.call(text2, { + "width": "200px", + "height": "20px", + "padding": "0", + "position": "absolute", + "top": "15px", + "left": "30px", + "resize": "none", + "border": "none", + "borderRadius": "2px", + "boxShadow": "rgba(0, 0, 0, 0.2) 0 0 0 1px" + }); + + const g = {}; + const logs = []; + let logindex = -1; + let proxyWindow = Object.assign({}, window, { + _status: _status, + lib: lib, + game: game, + ui: ui, + get: get, + ai: ai, + cheat: lib.cheat + }); + Object.defineProperties(proxyWindow, { + "_status": { + configurable: false, + enumerable: true, + writable: false + }, + "lib": { + configurable: false, + enumerable: true, + writable: false + }, + "game": { + configurable: false, + enumerable: true, + writable: false + }, + "ui": { + configurable: false, + enumerable: true, + writable: false + }, + "get": { + configurable: false, + enumerable: true, + writable: false + }, + "ai": { + configurable: false, + enumerable: true, + writable: false + }, + "cheat": { + configurable: false, + enumerable: true, + writable: false + } + }); + if (typeof window.Proxy == "function") { + proxyWindow = new Proxy(proxyWindow, { + set(target, prop, newValue) { + if (!["_status", "lib", "game", "ui", "get", "ai", "cheat"].includes(prop)) { + Reflect.set(window, prop, newValue); + } + return Reflect.set(target, prop, newValue); + } + }); + } + //使用new Function隔绝作用域,避免在控制台可以直接访问到runCommand等变量 + /** + * @type { (value:string)=>any } + */ + const fun = (new Function("window", ` + const _status=window._status; + const lib=window.lib; + const game=window.game; + const ui=window.ui; + const get=window.get; + const ai=window.ai; + const cheat=window.lib.cheat; + //使用正则匹配绝大多数的普通obj对象,避免解析成代码块。 + const reg=${/^\{([^{}]+:\s*([^\s,]*|"[^"]*"|"[^"]*"|\{[^}]*\}|\[[^\]]*\]|null|undefined|([a-zA-Z$_][a-zA-Z0-9$_]*\s*:\s*)?[a-zA-Z$_][a-zA-Z0-9$_]*\(\)))(?:,\s*([^{}]+:\s*(?:[^\s,]*|"[^"]*"|"[^"]*"|\{[^}]*\}|\[[^\]]*\]|null|undefined|([a-zA-Z$_][a-zA-Z0-9$_]*\s*:\s*)?[a-zA-Z$_][a-zA-Z0-9$_]*\(\))))*\}$/}; + return function(value){ + "use strict"; + return eval(reg.test(value)?("("+value+")"):value); + } + `))(proxyWindow); + const runCommand = () => { + if (text2.value && !["up", "down"].contains(text2.value)) { + logindex = -1; + logs.unshift(text2.value); + } + if (text2.value == "cls") { + pre.innerHTML = ""; + text2.value = ""; + } + else if (text2.value == "up") { + if (logindex + 1 < logs.length) { + text2.value = logs[++logindex]; + } + else { + text2.value = ""; + } + } + else if (text2.value == "down") { + if (logindex >= 0) { + logindex--; + if (logindex < 0) { + text2.value = ""; + } + else { + text2.value = logs[logindex]; + } + } + else { + text2.value = ""; + } + } + else if (text2.value.includes("无天使") && (text2.value.includes("无神佛") || text2.value.includes("无神") && text2.value.includes("无佛"))) { + game.print("密码正确!欢迎来到死后世界战线!"); + _status.keyVerified = true; + text2.value = ""; + } + else { + if (!game.observe && !game.online) { + try { + let value = text2.value.trim(); + if (value.endsWith(";")) value = value.slice(0, -1).trim(); + game.print(fun(value)); + } + catch (e) { + game.print(e); + } + } + text2.value = ""; + } + } + text2.addEventListener("keydown", e => { + if (e.keyCode == 13) { + runCommand(); + } + else if (e.keyCode == 38) { + if (logindex + 1 < logs.length) { + text2.value = logs[++logindex]; + } + } + else if (e.keyCode == 40) { + if (logindex >= 0) { + logindex--; + if (logindex < 0) { + text2.value = ""; + } + else { + text2.value = logs[logindex]; + } + } + } + }); + page.appendChild(text2); + game.print = function () { + const args = [...arguments]; + const printResult = args.map(arg => { + if (typeof arg != "string") { + const parse = (obj) => { + if (Array.isArray(obj)) { + return `[${obj.map(v => parse(v))}]`; + } else if (typeof obj == "function") { + return `Function`; + } else if (typeof obj != "string") { + return String(obj); + } else { + return `"${String(obj)}"`; + } + }; + if (typeof arg == "function") { + let argi; + try { + argi = get.stringify(arg); + if (argi === "") argi = arg.toString(); + } catch (_) { + argi = arg.toString(); + } + return argi.replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/"/g, "'"); + } + else if (typeof arg == "object") { + let msg = ""; + for (const name of Object.getOwnPropertyNames(arg)) { + msg += `${name}: ${parse(arg[name])}
          `; + } + return `
          ${parse(arg)}${msg}
          `; + } else { + return parse(arg); + } + } else { + const str = String(arg); + if (!/<[a-zA-Z]+[^>]*?\/?>.*?(?=<\/[a-zA-Z]+[^>]*?>|$)/.exec(str)) return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/"/g, "'"); + else return str; + } + }).join(" "); + pre.innerHTML += printResult + "
          "; + text.scrollTop = text.scrollHeight; + } + if (_status.toprint) { + game.print(...status.toprint); + delete _status.toprint; + } + runButton.listen(runCommand); + clearButton.listen(() => { + pre.innerHTML = ""; + }); + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + (function () { + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "战绩", start.firstChild, clickMode); + node.type = "rec"; + node._initLink = function () { + node.link = page; + page.style.paddingBottom = "10px"; + var reset = function () { + if (this.innerHTML == "重置") { + this.innerHTML = "确定"; + var that = this; + setTimeout(function () { + that.innerHTML = "重置"; + }, 1000); + } + else { + this.parentNode.previousSibling.remove(); + this.parentNode.remove(); + lib.config.gameRecord[this.parentNode.link] = { data: {} }; + game.saveConfig("gameRecord", lib.config.gameRecord); + } + } + for (var i = 0; i < lib.config.all.mode.length; i++) { + if (!lib.config.gameRecord[lib.config.all.mode[i]]) continue; + if (lib.config.gameRecord[lib.config.all.mode[i]].str) { + ui.create.div(".config.indent", lib.translate[lib.config.all.mode[i]], page).style.marginBottom = "-5px"; + var item = ui.create.div(".config.indent", lib.config.gameRecord[lib.config.all.mode[i]].str + "重置", page); + item.style.height = "auto"; + item.lastChild.addEventListener("click", reset); + item.lastChild.classList.add("pointerdiv"); + item.link = lib.config.all.mode[i]; + } + } + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + (function () { + if (!window.indexedDB || window.nodb) return; + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", "录像", start.firstChild, clickMode); + node.type = "video"; + lib.videos = []; + ui.create.videoNode = (video, before) => { + lib.videos.remove(video); + lib.videos[before === true ? "unshift" : "push"](video); + }; + node._initLink = function () { + node.link = page; + var store = lib.db.transaction(["video"], "readwrite").objectStore("video"); + store.openCursor().onsuccess = function (e) { + var cursor = e.target.result; + if (cursor) { + lib.videos.push(cursor.value); + cursor.continue(); + } + else { + lib.videos.sort(function (a, b) { + return parseInt(b.time) - parseInt(a.time); + }); + var clickcapt = function () { + var current = this.parentNode.querySelector(".videonode.active"); + if (current && current != this) { + current.classList.remove("active"); + } + if (this.classList.toggle("active")) { + playButton.show(); + deleteButton.show(); + saveButton.show(); + } + else { + playButton.hide(); + deleteButton.hide(); + saveButton.hide(); + } + }; + var staritem = function () { + this.parentNode.classList.toggle("starred"); + var store = lib.db.transaction(["video"], "readwrite").objectStore("video"); + if (this.parentNode.classList.contains("starred")) { + this.parentNode.link.starred = true; + } + else { + this.parentNode.link.starred = false; + } + store.put(this.parentNode.link); + } + var createNode = function (video, before) { + var node = ui.create.div(".videonode.menubutton.large", clickcapt); + node.link = video; + var nodename1 = ui.create.div(".menubutton.videoavatar", node); + nodename1.setBackground(video.name1, "character"); + if (video.name2) { + var nodename2 = ui.create.div(".menubutton.videoavatar2", node); + nodename2.setBackground(video.name2, "character"); + } + var date = new Date(video.time); + var str = date.getFullYear() + "." + (date.getMonth() + 1) + "." + (date.getDate()) + " " + + date.getHours() + ":"; + var minutes = date.getMinutes(); + if (minutes < 10) { + str += "0"; + } + str += minutes; + ui.create.div(".caption", video.name[0], node); + ui.create.div(".text", str + "
          " + video.name[1], node); + if (video.win) { + ui.create.div(".victory", "胜", node); + } + + if (before) { + page.insertBefore(node, page.firstChild); + } + else { + page.appendChild(node); + } + ui.create.div(".video_star", "★", node, staritem); + if (video.starred) { + node.classList.add("starred"); + } + } + for (var i = 0; i < lib.videos.length; i++) { + createNode(lib.videos[i]); + } + ui.create.videoNode = createNode; + var importVideoNode = ui.create.div(".config.switcher.pointerspan", + '导入录像...', function () { + this.nextSibling.classList.toggle("hidden"); + }, page); + importVideoNode.style.marginLeft = "12px"; + importVideoNode.style.marginTop = "3px"; + var importVideo = ui.create.div(".config.hidden", page); + importVideo.style.whiteSpace = "nowrap"; + importVideo.style.marginBottom = "80px"; + importVideo.style.marginLeft = "13px"; + importVideo.style.width = "calc(100% - 30px)"; + importVideo.innerHTML = ``; + importVideo.lastChild.onclick = function () { + var fileToLoad = importVideo.firstChild.files[0]; + var fileReader = new FileReader(); + fileReader.onload = function (fileLoadedEvent) { + var data = fileLoadedEvent.target.result; + if (!data) return; + try { + data = JSON.parse(lib.init.decode(data)); + } + catch (e) { + console.log(e); + alert("导入失败"); + return; + } + var store = lib.db.transaction(["video"], "readwrite").objectStore("video"); + var videos = lib.videos.slice(0); + for (var i = 0; i < videos.length; i++) { + if (videos[i].starred) { + videos.splice(i--, 1); + } + } + for (var deletei = 0; deletei < 5; deletei++) { + if (videos.length >= parseInt(lib.config.video) && videos.length) { + var toremove = videos.pop(); + lib.videos.remove(toremove); + store.delete(toremove.time); + for (var i = 0; i < page.childNodes.length; i++) { + if (page.childNodes[i].link == toremove) { + page.childNodes[i].remove(); + break; + } + } + } + else { + break; + } + } + for (var i = 0; i < lib.videos.length; i++) { + if (lib.videos[i].time == data.time) { + alert("录像已存在"); + return; + } + } + lib.videos.unshift(data); + store.put(data); + createNode(data, true); + }; + fileReader.readAsText(fileToLoad, "UTF-8"); + } + + playButton.listen(function () { + var current = this.parentNode.querySelector(".videonode.active"); + if (current) { + game.playVideo(current.link.time, current.link.mode); + } + }); + deleteButton.listen(function () { + var current = this.parentNode.querySelector(".videonode.active"); + if (current) { + lib.videos.remove(current.link); + var store = lib.db.transaction(["video"], "readwrite").objectStore("video"); + store.delete(current.link.time); + current.remove(); + } + }); + saveButton.listen(function () { + var current = this.parentNode.querySelector(".videonode.active"); + if (current) { + game.export(lib.init.encode(JSON.stringify(current.link)), + "无名杀 - 录像 - " + current.link.name[0] + " - " + current.link.name[1]); + } + }); + + ui.updateVideoMenu = function () { + var active = start.firstChild.querySelector(".active"); + if (active) { + active.classList.remove("active"); + active.link.remove(); + } + node.classList.add("active"); + rightPane.appendChild(page); + playButton.style.display = ""; + deleteButton.style.display = ""; + saveButton.style.display = ""; + } + } + }; + }; + if (!get.config("menu_loadondemand")) node._initLink(); + }()); + + + for (var i in lib.help) { + var page = ui.create.div(""); + var node = ui.create.div(".menubutton.large", i, start.firstChild, clickMode); + node.type = "help"; + node.link = page; + node.style.display = "none"; + page.classList.add("menu-help"); + page.innerHTML = lib.help[i]; + } + + if (!connectMenu) { + var node = ui.create.div(".menubutton.large", "帮助", start.firstChild, function () { + var activex = start.firstChild.querySelector(".active"); + if (this.innerHTML == "帮助") { + cheatButton.style.display = "none"; + runButton.style.display = "none"; + clearButton.style.display = "none"; + playButton.style.display = "none"; + saveButton.style.display = "none"; + deleteButton.style.display = "none"; + + this.innerHTML = "返回"; + for (var i = 0; i < start.firstChild.childElementCount; i++) { + var nodex = start.firstChild.childNodes[i]; + if (nodex == node) continue; + if (nodex.type == "help") { + nodex.style.display = ""; + if (activex && activex.type != "help") { + activex.classList.remove("active"); + activex.link.remove(); + activex = null; + nodex.classList.add("active"); + rightPane.appendChild(nodex.link); + } + } + else { + nodex.style.display = "none"; + } + } + } + else { + this.innerHTML = "帮助"; + for (var i = 0; i < start.firstChild.childElementCount; i++) { + var nodex = start.firstChild.childNodes[i]; + if (nodex == node) continue; + if (nodex.type != "help") { + nodex.style.display = ""; + if (activex && activex.type == "help") { + activex.classList.remove("active"); + activex.link.remove(); + activex = null; + clickMode.call(nodex); + } + } + else { + nodex.style.display = "none"; + } + } + } + }); + } + + var active = start.firstChild.querySelector(".active"); + if (!active) { + active = start.firstChild.firstChild; + active.classList.add("active"); + } + if (!active.link) active._initLink(); + rightPane.appendChild(active.link); + }()); + + if (menuTimeout) { + clearTimeout(menuTimeout); + delete window.resetExtension; + localStorage.removeItem(lib.configprefix + "disable_extension", true); + } + } + static table() { + var str, row, col, position, position2, fixed, style, divposition; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string") str = arguments[i]; + else if (typeof arguments[i] == "number") { + if (typeof row == "number") { + if (typeof col == "number") position2 = arguments[i]; + else col = arguments[i]; + } + else row = arguments[i]; + } + else if (get.objtype(arguments[i]) == "div" || + get.objtype(arguments[i]) == "table" || + get.objtype(arguments[i]) == "tr" || + get.objtype(arguments[i]) == "td" || + get.objtype(arguments[i]) == "body") position = arguments[i]; + else if (typeof arguments[i] == "boolean") fixed = arguments[i]; + else if (get.itemtype(arguments[i]) == "divposition") divposition = arguments[i]; + else if (typeof arguments[i] == "object") style = arguments[i]; + } + if (str == undefined) str = ""; + var node = document.createElement("table"); + for (var i = 0; i < str.length; i++) { + if (str[i] == ".") { + if (node.className.length != 0) { + node.className += " "; + } + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.className += str[i + 1]; + i++; + } + } + else if (str[i] == "#") { + while (str[i + 1] != "." && str[i + 1] != "#" && i + 1 < str.length) { + node.id += str[i + 1]; + i++; + } + } + } + var tr, td; + for (var i = 0; i < row; i++) { + tr = document.createElement("tr"); + if (fixed) tr.style.height = (100 / row) + "%"; + node.appendChild(tr); + for (var j = 0; j < col; j++) { + td = document.createElement("td"); + tr.appendChild(td); + } + } + if (position) { + if (typeof position2 == "number" && position.childNodes.length > position2) { + position.insertBefore(node, position.childNodes[position2]); + } + else { + position.appendChild(node); + } + } + return node; + } + static giveup() { + if (ui.giveup) return; + if (!lib.config.show_giveup) return; + ui.giveup = ui.create.system("投降", function () { + var player = game.me; + this.remove(); + if (game.online) { + game.send("giveup", player); + } + else { + _status.event.next.length = 0; + game.createEvent("giveup", false).set("includeOut", true).setContent(function () { + game.log(player, "投降"); + player.popup("投降"); + player.die("nosource").includeOut = true; + }).player = player; + } + if (_status.paused && _status.imchoosing && !_status.auto) { + ui.click.auto(); + } + }, true, true); + } + static groupControl(dialog) { + return ui.create.control("wei", "shu", "wu", "qun", "jin", "western", "key", function (link, node) { + if (link == "全部") { + dialog.currentcapt = ""; + dialog.currentgroup = ""; + for (var i = 0; i < dialog.buttons.length; i++) { + dialog.buttons[i].style.display = ""; + } + } + else { + if (node.classList.contains("thundertext")) { + dialog.currentgroup = null; + dialog.currentgroupnode = null; + node.classList.remove("thundertext"); + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + else { + if (dialog.currentgroupnode) { + dialog.currentgroupnode.classList.remove("thundertext"); + } + dialog.currentgroup = link; + dialog.currentgroupnode = node; + node.classList.add("thundertext"); + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.buttons[i].group != link || + (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt))) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + } + }); + } + static cardDialog() { + var args = ["thisiscard"]; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + return ui.create.characterDialog.apply(this, args); + } + static characterDialog2(filter) { + var list = []; + for (var i in lib.character) { + if (lib.character[i][4].contains("minskin")) continue; + if (lib.character[i][4].contains("boss") || lib.character[i][4].contains("hiddenboss")) { + if (lib.config.mode == "boss") continue; + if (!lib.character[i][4].contains("bossallowed")) continue; + } + + if (lib.character[i][4].contains("stonehidden")) continue; + if (lib.config.banned.contains(i)) continue; + if (filter && filter(i)) continue; + list.push(i); + } + var dialog = ui.create.dialog("hidden"); + dialog.classList.add("noupdate"); + dialog.classList.add("scroll1"); + dialog.classList.add("scroll2"); + dialog.classList.add("scroll3"); + list.sort(lib.sort.character); + dialog.classList.add("character"); + dialog.classList.add("choose-character"); + var getPack = function (name) { + for (var i in lib.characterPack) { + if (lib.characterPack[i][name]) return i; + } + return null; + } + var packs = {}; + var packnode = ui.create.div(".packnode", dialog); + lib.setScroll(packnode); + var clickCapt = function () { + var active = this.parentNode.querySelector(".active"); + if (active) { + active.classList.remove("active"); + } + this.classList.add("active"); + for (var i = 0; i < dialog.buttons.length; i++) { + if (this.pack && !this.pack.contains(dialog.buttons[i].link)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + var createNode = function (packname) { + var translate; + var pack = null; + if (packname == "最近") { + pack = get.config("recentCharacter") || []; + } + else if (packname == "收藏") { + pack = lib.config.favouriteCharacter; + } + var node = ui.create.div(".dialogbutton.menubutton.large", packname, packnode, clickCapt); + node.pack = pack; + return node; + } + dialog.add([list, "character"]); + var bool = true; + var node; + var recent = get.config("recentCharacter"); + if (recent && recent.length) { + node = createNode("最近"); + if (lib.config.character_dialog_tool == "最近") { + clickCapt.call(node); + bool = false; + } + } + if (lib.config.favouriteCharacter.length) { + node = createNode("收藏"); + if (lib.config.character_dialog_tool == "收藏") { + clickCapt.call(node); + bool = false; + } + } + var node = createNode("全部"); + if (lib.config.character_dialog_tool == "all") { + clickCapt.call(node); + bool = false; + } + if (bool) { + clickCapt.call(packnode.firstChild); + } + + var node = ui.create.div(".dialogbutton.menubutton.large", "筛选", packnode); + return dialog; + } + static characterDialog() { + // if(lib.config.character_dialog_style=="newstyle"){ + // for(var i=0;i b ? 1 : -1; + }); + groups.sort(lib.sort.group); + if (!thisiscard) { + namecapt.remove("自定义"); + namecapt.push("newline"); + for (var i in lib.characterDialogGroup) { + namecapt.push(i); + } + } + var newlined = false; + var newlined2; + var packsource; + var clickCapt = function (e) { + if (_status.dragged) return; + if (dialog.currentcapt2 == "最近" && dialog.currentcaptnode2 != this && !dialog.currentcaptnode2.inited) { + dialog.currentcapt2 = null; + dialog.currentcaptnode2.classList.remove("thundertext"); + dialog.currentcaptnode2.inited = true; + dialog.currentcaptnode2 = null; + } + if (this.alphabet) { + if (this.classList.contains("thundertext")) { + dialog.currentcapt = null; + dialog.currentcaptnode = null; + this.classList.remove("thundertext"); + if (this.touchlink) { + this.touchlink.classList.remove("active"); + } + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentgroup && dialog.buttons[i].group != dialog.currentgroup) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentcapt2 && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt, true)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + else { + if (dialog.currentcaptnode) { + dialog.currentcaptnode.classList.remove("thundertext"); + if (dialog.currentcaptnode.touchlink) { + dialog.currentcaptnode.touchlink.classList.remove("active"); + } + } + dialog.currentcapt = this.link; + dialog.currentcaptnode = this; + this.classList.add("thundertext"); + if (this.touchlink) { + this.touchlink.classList.add("active"); + } + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentcapt2 && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt, true)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentgroup && dialog.buttons[i].group != dialog.currentgroup) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + } + else { + if (newlined2) { + newlined2.style.display = "none"; + if (!packsource.onlypack) { + packsource.classList.remove("thundertext"); + if (!get.is.phoneLayout() || !lib.config.filternode_button) { + packsource.innerHTML = "武将包"; + } + } + } + if (this.classList.contains("thundertext")) { + dialog.currentcapt2 = null; + dialog.currentcaptnode2 = null; + this.classList.remove("thundertext"); + if (this.touchlink) { + this.touchlink.classList.remove("active"); + } + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentgroup && dialog.buttons[i].group != dialog.currentgroup) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + else { + if (dialog.currentcaptnode2) { + dialog.currentcaptnode2.classList.remove("thundertext"); + if (dialog.currentcaptnode2.touchlink) { + dialog.currentcaptnode2.touchlink.classList.remove("active"); + } + } + dialog.currentcapt2 = this.link; + dialog.currentcaptnode2 = this; + this.classList.add("thundertext"); + if (this.touchlink) { + this.touchlink.classList.add("active"); + } + else if (this.parentNode == newlined2) { + packsource.innerHTML = this.innerHTML; + packsource.classList.add("thundertext"); + } + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt, true)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentgroup && dialog.buttons[i].group != dialog.currentgroup) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + if (dialog.buttons[i].activate) { + dialog.buttons[i].activate(); + } + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + } + if (dialog.seperate) { + for (var i = 0; i < dialog.seperate.length; i++) { + if (!dialog.seperate[i].nextSibling.querySelector(".button:not(.nodisplay)")) { + dialog.seperate[i].style.display = "none"; + dialog.seperate[i].nextSibling.style.display = "none"; + } + else { + dialog.seperate[i].style.display = ""; + dialog.seperate[i].nextSibling.style.display = ""; + } + } + } + if (filternode) { + if (filternode.querySelector(".active")) { + packsource.classList.add("thundertext"); + } + else { + packsource.classList.remove("thundertext"); + } + } + if (e) e.stopPropagation(); + }; + for (i = 0; i < namecapt.length; i++) { + if (namecapt[i] == "newline") { + newlined = document.createElement("div"); + newlined.style.marginTop = "5px"; + newlined.style.display = "block"; + // newlined.style.fontFamily="xinwei"; + if (get.is.phoneLayout()) { + newlined.style.fontSize = "32px"; + } + else { + newlined.style.fontSize = "22px"; + } + newlined.style.textAlign = "center"; + node.appendChild(newlined); + } + else if (newlined) { + var span = ui.create.div(".tdnode.pointerdiv.shadowed.reduce_radius"); + span.style.margin = "3px"; + span.style.width = "auto"; + span.innerHTML = " " + namecapt[i].toUpperCase() + " "; + span.link = namecapt[i]; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickCapt); + newlined.appendChild(span); + node[namecapt[i]] = span; + if (namecapt[i] == "收藏") { + span._nature = "fire"; + } + else { + span._nature = "wood"; + } + } + else { + var span = document.createElement("span"); + span.innerHTML = " " + namecapt[i].toUpperCase() + " "; + span.link = namecapt[i]; + span.alphabet = true; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickCapt); + node.appendChild(span); + } + } + if (!thisiscard) { + var natures = ["water", "soil", "wood", "metal"]; + var span = document.createElement("span"); + newlined.appendChild(span); + span.style.margin = "8px"; + var clickGroup = function () { + if (_status.dragged) return; + if (dialog.currentcapt2 == "最近" && dialog.currentcaptnode2 != this && !dialog.currentcaptnode2.inited) { + dialog.currentcapt2 = null; + dialog.currentcaptnode2.classList.remove("thundertext"); + dialog.currentcaptnode2.inited = true; + dialog.currentcaptnode2 = null; + } + var node = this, link = this.link; + if (node.classList.contains("thundertext")) { + dialog.currentgroup = null; + dialog.currentgroupnode = null; + node.classList.remove("thundertext"); + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentcapt2 && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt, true)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + else { + if (dialog.currentgroupnode) { + dialog.currentgroupnode.classList.remove("thundertext"); + } + dialog.currentgroup = link; + dialog.currentgroupnode = node; + node.classList.add("thundertext"); + for (var i = 0; i < dialog.buttons.length; i++) { + if (dialog.currentcapt && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentcapt2 && dialog.buttons[i].capt != dialog.getCurrentCapt(dialog.buttons[i].link, dialog.buttons[i].capt, true)) { + dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentgroup == "double") { + if (dialog.buttons[i]._changeGroup) dialog.buttons[i].classList.remove("nodisplay"); + else dialog.buttons[i].classList.add("nodisplay"); + } + else if (dialog.currentgroup == "ye") { + if (dialog.buttons[i].group == "ye") dialog.buttons[i].classList.remove("nodisplay"); + else dialog.buttons[i].classList.add("nodisplay"); + } + else { + if (dialog.buttons[i]._changeGroup || dialog.buttons[i].group != dialog.currentgroup) { + dialog.buttons[i].classList.add("nodisplay"); + } + else { + dialog.buttons[i].classList.remove("nodisplay"); + } + } + } + } + }; + for (var i = 0; i < groups.length; i++) { + var span = ui.create.div(".tdnode.pointerdiv.shadowed.reduce_radius.reduce_margin"); + span.style.margin = "3px"; + newlined.appendChild(span); + span.innerHTML = get.translation(groups[i]); + span.link = groups[i]; + span._nature = natures[i]; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickGroup); + } + + var span = document.createElement("span"); + newlined.appendChild(span); + span.style.margin = "8px"; + + packsource = ui.create.div(".tdnode.pointerdiv.shadowed.reduce_radius.reduce_margin"); + packsource.style.margin = "3px"; + newlined.appendChild(packsource); + var filternode = null; + var clickCaptNode = function (e) { + delete _status.filterCharacter; + ui.window.classList.remove("shortcutpaused"); + filternode.delete(); + filternode.classList.remove("shown"); + clickCapt.call(this.link, e); + }; + if (get.is.phoneLayout() && lib.config.filternode_button) { + newlined.style.marginTop = ""; + packsource.innerHTML = "筛选"; + filternode = ui.create.div(".popup-container.filter-character.modenopause"); + ui.create.div(filternode); + filternode.listen(function (e) { + if (this.classList.contains("removing")) return; + delete _status.filterCharacter; + ui.window.classList.remove("shortcutpaused"); + this.delete(); + this.classList.remove("shown"); + e.stopPropagation(); + }); + for (var i = 0; i < node.childElementCount; i++) { + if (node.childNodes[i].tagName.toLowerCase() == "span") { + node.childNodes[i].style.display = "none"; + node.childNodes[i].touchlink = ui.create.div(filternode.firstChild, clickCaptNode, ".menubutton.large.capt", node.childNodes[i].innerHTML); + node.childNodes[i].touchlink.link = node.childNodes[i]; + } + } + ui.create.node("br", filternode.firstChild); + } + else { + if (onlypack) { + packsource.onlypack = true; + packsource.innerHTML = get.translation(onlypack + "_character_config"); + packsource.style.display = "none"; + packsource.previousSibling.style.display = "none"; + } + else { + packsource.innerHTML = "武将包"; + } + } + + newlined2 = document.createElement("div"); + newlined2.style.marginTop = "5px"; + newlined2.style.display = "none"; + newlined2.style.fontFamily = "xinwei"; + newlined2.classList.add("pointernode"); + if (get.is.phoneLayout()) { + newlined2.style.fontSize = "32px"; + } + else { + newlined2.style.fontSize = "22px"; + } + newlined2.style.textAlign = "center"; + node.appendChild(newlined2); + + packsource.addEventListener(lib.config.touchscreen ? "touchend" : "click", function () { + if (packsource.onlypack) return; + if (_status.dragged) return; + if (get.is.phoneLayout() && lib.config.filternode_button && filternode) { + _status.filterCharacter = true; + ui.window.classList.add("shortcutpaused"); + ui.window.appendChild(filternode); + ui.refresh(filternode); + filternode.classList.add("shown"); + var dh = filternode.offsetHeight - filternode.firstChild.offsetHeight; + if (dh > 0) { + filternode.firstChild.style.top = (dh / 2) + "px"; + } + else { + filternode.firstChild.style.top = ""; + } + } + else { + if (newlined2.style.display == "none") { + newlined2.style.display = "block"; + } + else { + newlined2.style.display = "none"; + } + } + }); + var packlist = []; + for (var i = 0; i < lib.config.all.characters.length; i++) { + if (!lib.config.characters.contains(lib.config.all.characters[i])) continue; + packlist.push(lib.config.all.characters[i]); + } + for (var i in lib.characterPack) { + if (!lib.config.all.characters.contains(i)) { + packlist.push(i); + } + } + for (var i = 0; i < packlist.length; i++) { + var span = document.createElement("div"); + span.style.display = "inline-block"; + span.style.width = "auto"; + span.style.margin = "5px"; + if (get.is.phoneLayout()) { + span.style.fontSize = "32px"; + } + else { + span.style.fontSize = "22px"; + } + span.innerHTML = lib.translate[packlist[i] + "_character_config"]; + span.link = packlist[i]; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickCapt); + newlined2.appendChild(span); + if (filternode && !onlypack) { + span.touchlink = ui.create.div(filternode.firstChild, clickCaptNode, ".menubutton.large", span.innerHTML); + span.touchlink.link = span; + } + } + } + + var groupSort; + if (thisiscard) { + groupSort = function (name) { + var type = lib.card[name[2]].type; + if (lib.cardType[type]) { + return lib.cardType[type]; + } + switch (type) { + case "basic": return 0; + case "chess": return 1.5; + case "trick": return 2; + case "delay": return 3; + case "equip": return 4; + case "zhenfa": return 5; + default: return 6; + } + } + list.sort(function (a, b) { + var del = groupSort(a) - groupSort(b); + if (del != 0) return del; + var aa = a, bb = b; + if (a.includes("_")) { + a = a.slice(a.lastIndexOf("_") + 1); + } + if (b.includes("_")) { + b = b.slice(b.lastIndexOf("_") + 1); + } + if (a != b) { + return a > b ? 1 : -1; + } + return aa > bb ? 1 : -1; + }); + } + else { + list.sort(lib.sort.character); + } + dialog = ui.create.dialog("hidden"); + dialog.classList.add("noupdate"); + dialog.classList.add("scroll1"); + dialog.classList.add("scroll2"); + dialog.classList.add("scroll3"); + dialog.addEventListener(lib.config.touchscreen ? "touchend" : "mouseup", function () { + _status.clicked2 = true; + }); + if (heightset) { + dialog.style.height = ((game.layout == "long2" || game.layout == "nova") ? 380 : 350) + "px"; + dialog._scrollset = true; + } + dialog.getCurrentCapt = function (link, capt, noalph) { + var currentcapt = noalph ? this.currentcapt2 : this.currentcapt; + if (this.seperatelist && noalph) { + if (this.seperatelist[currentcapt].contains(link)) return capt; + return null; + } + if (lib.characterDialogGroup[currentcapt]) { + return lib.characterDialogGroup[currentcapt](link, capt); + } + if (lib.characterPack[currentcapt]) { + if (lib.characterPack[currentcapt][link]) { + return capt; + } + return null; + } + return this.currentcapt; + } + if (str) { + dialog.add(str); + } + dialog.add(node); + if (thisiscard) { + if (seperate) { + seperate = seperate(list); + dialog.seperate = []; + dialog.seperatelist = seperate.list; + if (dialog.seperatelist) { + newlined = document.createElement("div"); + newlined.style.marginTop = "5px"; + newlined.style.display = "block"; + newlined.style.fontFamily = "xinwei"; + if (get.is.phoneLayout()) { + newlined.style.fontSize = "32px"; + } + else { + newlined.style.fontSize = "22px"; + } + newlined.style.textAlign = "center"; + node.appendChild(newlined); + for (var i in dialog.seperatelist) { + var span = document.createElement("span"); + span.style.margin = "3px"; + span.innerHTML = i; + span.link = i; + span.seperate = true; + span.addEventListener(lib.config.touchscreen ? "touchend" : "click", clickCapt); + newlined.appendChild(span); + } + } + for (var i in seperate) { + if (i == "list") continue; + var link = ""; + var linkcontent = seperate[i]; + if (i.includes("_link:")) { + link = i.slice(i.indexOf("_link:") + 6); + i = i.slice(0, i.indexOf("_link:")); + } + var nodesep = dialog.add(i); + nodesep.link = link; + dialog.seperate.push(nodesep); + dialog.add([linkcontent, "vcard"], noclick); + } + } + else { + dialog.add([list, "vcard"], noclick); + } + } + else { + if (precharacter) { + dialog.add([list, "precharacter"], noclick); + } + else if (characterx) { + dialog.add([list, "characterx"], noclick); + } + else { + dialog.add([list, "character"], noclick); + } + } + dialog.add(ui.create.div(".placeholder")); + for (i = 0; i < dialog.buttons.length; i++) { + if (thisiscard) { + dialog.buttons[i].capt = getCapt(dialog.buttons[i].link[2]); + } + else { + dialog.buttons[i].group = lib.character[dialog.buttons[i].link][1]; + dialog.buttons[i].capt = getCapt(dialog.buttons[i].link); + } + } + if (!expandall) { + if (!thisiscard && (lib.characterDialogGroup[lib.config.character_dialog_tool] || + lib.config.character_dialog_tool == "自创")) { + clickCapt.call(node[lib.config.character_dialog_tool]); + } + } + return dialog; + } + static dialog() { + return new lib.element.Dialog(...arguments); + } + static line2() { + var node = ui.create.line.apply(this, arguments); + node.classList.add("line2"); + return node; + } + static line() { + var two = false, func; + var node = ui.create.div(".config"); + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "string" || typeof arguments[i] == "number") { + if (two) ui.create.div(".toggle", node).innerHTML = arguments[i]; + else { + ui.create.div(node).innerHTML = arguments[i]; + two = true; + } + } + else if (typeof arguments[i] == "function") func = arguments[i]; + } + if (func) { + for (var i = 0; i < node.childNodes.length; i++) node.childNodes[i].listen(func); + } + return node; + } + static switcher(name, current, current2) { + var func; + var node = ui.create.div(".config"); + ui.create.div(node).innerHTML = get.translation(name + "_config"); + var switcher = ui.create.div(".toggle.pointerdiv", node); + switcher.name = name; + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] == "function") { + func = arguments[i]; break; + } + } + if (typeof current == "string") { + switcher.link = current; + switcher.innerHTML = get.translation(current); + switcher.contentEditable = true; + switcher.style.webkitUserSelect = "text"; + switcher.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.editor); + } + else if (typeof current == "object") { + switcher.link = current2 || current[0]; + switcher.innerHTML = get.translation(switcher.link); + switcher.choice = current; + switcher.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.switcher); + } + else { + if (current) { + switcher.classList.add("on"); + } + switcher.classList.add("onoff"); + ui.create.div(ui.create.div(switcher)); + switcher.link = current ? true : false; + switcher.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.toggle); + } + if (func) switcher.additionalCommand = func; + return node; + } + static caption(str, position) { + var caption = ui.create.div(".caption", position); + caption.innerHTML = str; + return caption; + } + static control() { + return new lib.element.Control(...arguments); + } + static confirm(str, func) { + if (ui.confirm && ui.confirm.str == str) { + return; + } + if (str == "o") { + if (ui.confirm) { + ui.confirm.replace("ok"); + } + else { + ui.confirm = ui.create.control("ok"); + } + } + else if (str == "oc" || str == "co") { + if (ui.confirm) { + ui.confirm.replace("ok", "cancel"); + } + else { + ui.confirm = ui.create.control("ok", "cancel"); + } + } + else if (str == "c") { + if (ui.confirm) { + ui.confirm.replace("cancel"); + } + else { + ui.confirm = ui.create.control("cancel"); + } + } + else if (ui.confirm) { + ui.confirm.close(); + delete ui.confirm; + } + if (ui.confirm) { + ui.confirm.str = str; + if (func) ui.confirm.custom = func; + else delete ui.confirm.custom; + } + } + static skills(skills) { + var i, same; + if (ui.skills) { + if (ui.skills.skills.length == skills.length && ui.skills.style.display != "none") { + same = true; + for (i = 0; i < skills.length; i++) { + if (ui.skills.skills.contains(skills[i]) == false) { + same = false; + break; + } + } + } + if (same) return; + ui.skills.close(); + delete ui.skills; + } + if (skills == undefined || skills.length == 0) return; + if (!_status.event.isMine()) { + _status.noupdatec = true; + } + ui.skills = ui.create.control(skills.concat([ui.click.skill])); + for (var i = 0; i < ui.skills.childNodes.length; i++) { + ui.skills.childNodes[i].innerHTML = get.skillTranslation(ui.skills.childNodes[i].link, _status.event.player); + } + if (!_status.event.isMine()) { + ui.skills.style.display = "none"; + } + else { + ui.updatec(); + } + _status.noupdatec = false; + ui.skills.skills = skills; + return ui.skills; + } + static skills2(skills) { + var i, same; + if (ui.skills2) { + if (ui.skills2.skills.length == skills.length && ui.skills2.style.display != "none") { + same = true; + for (i = 0; i < skills.length; i++) { + if (ui.skills2.skills.contains(skills[i]) == false) { + same = false; + break; + } + } + } + if (same) return; + ui.skills2.close(); + delete ui.skills2; + } + if (skills == undefined || skills.length == 0) return; + if (!_status.event.isMine()) { + _status.noupdatec = true; + } + ui.skills2 = ui.create.control(skills.concat([ui.click.skill])); + for (var i = 0; i < ui.skills2.childNodes.length; i++) { + ui.skills2.childNodes[i].innerHTML = get.skillTranslation(ui.skills2.childNodes[i].link, _status.event.player); + } + if (!_status.event.isMine()) { + ui.skills2.style.display = "none"; + } + else { + ui.updatec(); + } + _status.noupdatec = false; + ui.skills2.skills = skills; + return ui.skills2; + } + static skills3(skills) { + var i, same; + if (ui.skills3) { + if (ui.skills3.skills.length == skills.length && ui.skills3.style.display != "none") { + same = true; + for (i = 0; i < skills.length; i++) { + if (ui.skills3.skills.contains(skills[i]) == false) { + same = false; + break; + } + } + } + if (same) return; + ui.skills3.close(); + delete ui.skills3; + } + if (skills == undefined || skills.length == 0) return; + if (!_status.event.isMine()) { + _status.noupdatec = true; + } + ui.skills3 = ui.create.control(skills.concat([ui.click.skill])); + for (var i = 0; i < ui.skills3.childNodes.length; i++) { + ui.skills3.childNodes[i].innerHTML = get.skillTranslation(ui.skills3.childNodes[i].link, _status.event.player); + } + if (!_status.event.isMine()) { + ui.skills3.style.display = "none"; + } + else { + ui.updatec(); + } + _status.noupdatec = false; + ui.skills3.skills = skills; + return ui.skills3; + } + static arena() { + var i, j; + ui.window = ui.create.div("#window.hidden", document.body); + ui.create.div("#statusbg", document.body); + ui.refresh(ui.window); + if (!localStorage.getItem(lib.configprefix + "playback")) { + ui.window.show(); + } + else { + setTimeout(function () { + ui.window.show(); + }, 1000); + } + // lib.setPressure(ui.window,ui.click.pressurepause); + if (window.isNonameServer) { + ui.window.classList.add("server"); + var serverinfo = ui.create.div(".serverinfo", ui.window); + ui.create.div("", "服务器正在运行", serverinfo); + var serverinfotable = ui.create.table(2, 2, ui.create.div(serverinfo)); + serverinfotable.style.display = "inline-block"; + serverinfotable.firstChild.firstChild.innerHTML = "房间人数:"; + serverinfotable.firstChild.lastChild.id = "server_count"; + serverinfotable.firstChild.lastChild.innerHTML = "0"; + serverinfotable.lastChild.firstChild.innerHTML = "房间状态:"; + serverinfotable.lastChild.lastChild.id = "server_status"; + serverinfotable.lastChild.lastChild.innerHTML = "空闲"; + ui.create.div(".menubutton.large", "关闭服务器", function () { + if (_status.gameStarted && !confirm("关闭服务器当前进行的游戏将终止且不可恢复,是否确定关闭?")) { + return; + } + localStorage.removeItem(lib.configprefix + "asserver"); + game.reload(); + }, ui.create.div("", serverinfo)); + } + + ui.window.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.window); + ui.system = ui.create.div("#system.", ui.window); + ui.arena = ui.create.div("#arena.nome", ui.window); + if (lib.device == "ios" && !get.is.phoneLayout()) { + ui.arena.classList.add("ipad"); + } + ui.arena.setNumber = function (num) { + this.dataset.number = num; + ui.updatePlayerPositions(); + } + + if (lib.config.low_performance) { + ui.window.classList.add("low_performance"); + } + if (game.layout == "mobile" || game.layout == "long") { + ui.arena.classList.add("mobile"); + } + if (game.layout == "long" || game.layout == "long2") { + ui.arena.classList.add("long"); + } + if (game.layout == "default") { + ui.arena.classList.add("oldlayout"); + } + if (lib.config.player_border != "wide" || game.layout == "long" || game.layout == "long2") { + ui.arena.classList.add("slim_player"); + } + if (lib.config.player_border == "slim") { + ui.arena.classList.add("uslim_player"); + } + if (lib.config.player_border == "narrow") { + ui.arena.classList.add("mslim_player"); + } + if (lib.config.player_border == "normal" && lib.config.mode != "brawl" && (game.layout == "long" || game.layout == "long2")) { + ui.arena.classList.add("lslim_player"); + } + ui.window.dataset.player_border = lib.config.player_border; + if (lib.config.compatiblemode) { + ui.window.classList.add("compatiblemode"); + } + ui.window.dataset.radius_size = lib.config.radius_size || "default"; + if (game.layout == "long" || game.layout == "mobile") { + //if(lib.config.textequip=="text") ui.arena.classList.add("textequip"); + ui.arena.classList.add("textequip"); + } + if (game.layout == "long" || game.layout == "long2" || game.layout == "mobile" || game.layout == "nova") { + if (lib.config.cardshape == "oblong") { + ui.window.classList.add("oblongcard"); + ui.arena.classList.add("oblongcard"); + } + } + if (lib.config.blur_ui) { + ui.window.classList.add("blur_ui"); + } + if (lib.config.glass_ui) { + ui.window.classList.add("glass_ui"); + } + if (lib.config.custom_button) { + lib.configMenu.appearence.config.custom_button.onclick("skip"); + } + + if (lib.config.show_statusbar_ios == "overlay") { + document.body.classList.add("statusbar"); + } + if (lib.config.keep_awake) { + if (window.plugins && window.plugins.insomnia) window.plugins.insomnia.keepAwake(); + else { + lib.init.js(lib.assetURL + "game", "NoSleep", function () { + var noSleep = new NoSleep(); + document.addEventListener(lib.config.touchscreen ? "touchend" : "click", function enableNoSleep() { + document.removeEventListener(lib.config.touchscreen ? "touchend" : "click", enableNoSleep, false); + noSleep.enable(); + window.noSleep = noSleep; + }, false); + }); + } + } + lib.init.js(lib.assetURL + "game", "pinyinjs", function () { }) + lib.init.js(lib.assetURL + "game", "keyWords", function () { }); + + lib.updateURL = lib.updateURLS[lib.config.update_link] || lib.updateURLS.coding; + + lib.init.cssstyles(); + + ui.arena.dataset.player_height = lib.config.player_height || "default"; + ui.arena.dataset.player_height_nova = lib.config.player_height_nova || "default"; + // if(lib.config.player_height_nova=="long") ui.arena.classList.add("player_autolong"); + ui.arena.dataset.target_shake = lib.config.target_shake || "off"; + ui.backgroundMusic = document.createElement("audio"); + ui.backgroundMusic.volume = lib.config.volumn_background / 8; + game.playBackgroundMusic(); + ui.backgroundMusic.autoplay = true; + ui.backgroundMusic.addEventListener("ended", game.playBackgroundMusic); + ui.window.appendChild(ui.backgroundMusic); + ui.window.addEventListener(lib.config.touchscreen ? "touchend" : "click", function playMusic() { + ui.window.removeEventListener(lib.config.touchscreen ? "touchend" : "click", playMusic, false); + if (!ui.backgroundMusic.played.length && lib.config.background_music != "music_off") ui.backgroundMusic.play(); + }, false); + if (lib.config.cursor_style == "pointer") { + ui.window.classList.add("nopointer"); + } + if (lib.config.turned_style == false) { + ui.arena.classList.add("hide_turned"); + } + if (lib.config.link_style2 != "chain") { + ui.arena.classList.add("nolink"); + } + if (lib.config.show_name == false) { + ui.arena.classList.add("hide_name"); + } + if (lib.config.change_skin_auto != "off") { + _status.skintimeout = setTimeout(ui.click.autoskin, parseInt(lib.config.change_skin_auto)); + } + if (lib.config.border_style && lib.config.border_style.startsWith("dragon_")) { + ui.arena.dataset.framedecoration = lib.config.border_style.slice(7); + } + + ui.gameinfo = ui.create.div("#time", ui.window); + + ui.arenalog = ui.create.div("#arenalog", ui.arena); + if (lib.config.show_log == "off") { + ui.arenalog.style.display = "none"; + } + else { + ui.arenalog.dataset.position = lib.config.show_log; + } + ui.historybar = ui.create.div("#historybar.shadowed", ui.window); + lib.setScroll(ui.historybar); + + ui.roundmenu = ui.create.div("#roundmenu.roundarenabutton.menubutton.round", ui.arena); + ui.roundmenu._position = [180, 210]; + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + + ui.create.div(ui.roundmenu); + ui.create.div(ui.roundmenu); + + ui.create.div(ui.roundmenu); + + if (lib.config.show_time2) { + ui.roundmenu.classList.add("clock"); + } + ui.roundmenu.dataset.watchface = lib.config.watchface || "none"; + if (get.is.phoneLayout()) { + if (lib.config.show_time3) { + ui.time3 = ui.create.div(".touchinfo.left", ui.window); + } + ui.cardPileNumber = ui.create.div(".touchinfo.right", ui.window); + } + else { + if (lib.config.show_time3) { + ui.time3 = ui.create.div(ui.gameinfo); + } + ui.cardPileNumber = ui.create.div(ui.gameinfo); + } + if (!lib.config.show_cardpile_number) { + ui.cardPileNumber.style.display = "none"; + } + if (ui.time3) { + ui.time3.starttime = get.utc(); + ui.time3.interval = setInterval(function () { + var num = Math.round((get.utc() - ui.time3.starttime) / 1000); + if (num >= 3600) { + var num1 = Math.floor(num / 3600); + var num2 = Math.floor((num - num1 * 3600) / 60); + if (num2 < 10) { + num2 = "0" + num2.toString(); + } + var num3 = num - num1 * 3600 - parseInt(num2) * 60; + if (num3 < 10) { + num3 = "0" + num3.toString(); + } + ui.time3.innerHTML = num1 + ":" + num2 + ":" + num3; + } + else { + var num1 = Math.floor(num / 60); + var num2 = num - num1 * 60; + if (num2 < 10) { + num2 = "0" + num2.toString(); + } + ui.time3.innerHTML = num1 + ":" + num2; + } + }, 1000); + } + if (get.is.nomenu()) { + if (!["menu", "system"].contains(lib.config.round_menu_func)) { + lib.config.round_menu_func = "system"; + } + } + else if (!lib.config.show_round_menu) { + ui.roundmenu.style.display = "none"; + } + + var resetround = function (e) { + _status.draggingroundmenu = false; + ui.roundmenu.style.transform = ""; + ui.roundmenu._dragtransform = [0, 0]; + ui.roundmenu.style.transition = "all 0.3s"; + delete ui.roundmenu._dragtouches; + delete ui.roundmenu._dragorigin; + delete ui.roundmenu._dragorigintransform; + setTimeout(function () { + ui.roundmenu.style.transition = ""; + }, 500); + game.saveConfig("roundmenu_transform", [0, 0]); + if (e) e.stopPropagation(); + return false; + }; + ui.click.resetround = resetround; + if (lib.config.touchscreen) { + ui.roundmenu.addEventListener("touchstart", function (e) { + _status.draggingroundmenu = true; + ui.roundmenu._dragorigin = { + clientX: e.touches[0].clientX, + clientY: e.touches[0].clientY, + }; + if (!ui.roundmenu._dragtransform) { + ui.roundmenu._dragtransform = [0, 0]; + } + ui.roundmenu._dragorigintransform = ui.roundmenu._dragtransform.slice(0); + ui.roundmenu._resetTimeout = setTimeout(function () { + resetround(); + delete ui.roundmenu._resetTimeout; + }, 1000); + }); + } + else { + ui.roundmenu.oncontextmenu = resetround; + } + if (!lib.config.remember_round_button) { + game.saveConfig("roundmenu_transform"); + } + if (lib.config.roundmenu_transform) { + var translate = lib.config.roundmenu_transform; + ui.roundmenu._dragtransform = translate; + ui.roundmenu.style.transform = "translate(" + translate[0] + "px," + translate[1] + "px)"; + ui.click.checkroundtranslate(); + } + if (get.is.phoneLayout()) { + ui.arena.classList.add("phone"); + } + + ui.sidebar = ui.create.div("#sidebar"); + ui.sidebar3 = ui.create.div("#sidebar3"); + ui.canvas = document.createElement("canvas"); + + ui.arena.appendChild(ui.canvas); + ui.canvas.id = "canvas"; + ui.ctx = ui.canvas.getContext("2d"); + + ui.sidebar.ontouchstart = ui.click.touchStart; + ui.sidebar.ontouchmove = ui.click.touchScroll; + ui.sidebar.style.webkitOverflowScrolling = "touch"; + + var zoom; + switch (lib.config.ui_zoom) { + case "esmall": zoom = 0.8; break; + case "vsmall": zoom = 0.9; break; + case "small": zoom = 0.93; break; + case "big": zoom = 1.05; break; + case "vbig": zoom = 1.1; break; + case "ebig": zoom = 1.2; break; + case "eebig": zoom = 1.5; break; + case "eeebig": zoom = 1.8; break; + case "eeeebig": zoom = 2; break; + default: zoom = 1; + } + game.documentZoom = game.deviceZoom * zoom; + if (zoom != 1) { + ui.updatez(); + } + + ui.system1 = ui.create.div("#system1", ui.system); + ui.system2 = ui.create.div("#system2", ui.system); + + ui.replay = ui.create.system("重来", game.reload, true); + ui.replay.id = "restartbutton"; + ui.config2 = ui.create.system("选项", ui.click.config); + ui.pause = ui.create.system("暂停", ui.click.pause); + ui.pause.id = "pausebutton"; + if (!_status.video) { + ui.pause.hide(); + } + if (!lib.config.touchscreen) { + lib.setPopped(ui.pause, ui.click.pausehistory, 220, 400, null, true); + } + if (!lib.config.show_pause) { + ui.pause.style.display = "none"; + } + ui.cardPileButton = ui.create.system("牌堆", null, true); + ui.cardPileButton.style.display = "none"; + lib.setPopped(ui.cardPileButton, ui.click.cardPileButton, 220); + ui.wuxie = ui.create.system("不询问无懈", ui.click.wuxie, true); + if (!lib.config.touchscreen) { + lib.setPopped(ui.config2, ui.click.pauseconfig, 170); + } + ui.auto = ui.create.system("托管", ui.click.auto); + if (!game.syncMenu) { + ui.config2.classList.add("hidden"); + ui.config2.style.transition = "all 0.5s"; + ui.roundmenu.classList.add("transparent2"); + + ui.auto.style.opacity = 0.5; + ui.auto.style.transition = "all 0.5s"; + lib.onfree.push(function () { + ui.auto.style.opacity = ""; + setTimeout(function () { + ui.auto.style.transition = ""; + }, 500); + }); + } + ui.auto.id = "autobutton"; + ui.autonode = ui.create.div("#autonode", "
          托管中...
          ", ui.arena); + ui.autonode.listen(ui.click.auto); + if (lib.config.mode == "connect") { + ui.auto.hide(); + ui.pause.hide(); + } + + if (lib.forcehide) { + if (lib.forcehide.contains("replay")) ui.replay.classList.add("forcehide"); + if (lib.forcehide.contains("auto")) ui.auto.classList.add("forcehide"); + if (lib.forcehide.contains("pause")) ui.pause.classList.add("forcehide"); + if (lib.forcehide.contains("wuxie")) ui.wuxie.classList.add("forcehide"); + if (lib.forcehide.contains("cardPileButton")) ui.cardPileButton.classList.add("forcehide"); + } + ui.volumn = ui.create.system("♫"); + lib.setPopped(ui.volumn, ui.click.volumn, 200); + // if(lib.config.show_pause) ui.auto.style.marginLeft="10px"; + if (!lib.config.show_volumn) { + ui.volumn.style.display = "none"; + } + if (!lib.config.show_auto) { + ui.auto.style.display = "none"; + } + if (!lib.config.show_wuxie) { + ui.wuxie.style.display = "none"; + } + // if(!lib.config.show_cardpile||_status.connectMode){ + // ui.cardPileButton.style.display="none"; + // } + + ui.sortCard = ui.create.system("整理手牌", function () { + if (!game.me) return; + var hs = game.me.getCards("h"); + if (!hs.length) return; + game.addVideo("lose", game.me, [get.cardsInfo(hs), [], [], []]); + for (var i = 0; i < hs.length; i++) { + hs[i].goto(ui.special); + } + if (game.me.hasSkillTag("sortCardByNum")) { + var getn = function (card) { + var num = get.number(card, game.me); + if (num < 3) return 13 + num; + return num; + } + hs.sort((a, b) => (getn(b) - getn(a))); + } + else hs.sort(function (b, a) { + if (a.name != b.name) return lib.sort.card(a.name, b.name); + else if (a.suit != b.suit) return lib.suit.indexOf(a) - lib.suit.indexOf(b); + else return a.number - b.number; + }); + game.me.directgain(hs, false); + }); + if (!lib.config.show_sortcard) { + ui.sortCard.style.display = "none"; + } + ui.playerids = ui.create.system("显示身份", function () { + if (game.showIdentity) { + game.showIdentity(); + _status.identityShown = true; + } + }, true); + if (!lib.config.show_playerids || !game.showIdentity) { + ui.playerids.style.display = "none"; + } + if (!lib.config.show_replay) { + ui.replay.style.display = "none"; + } + ui.control = ui.create.div("#control", ui.arena).animate("nozoom"); + ui.cardPile = ui.create.div("#cardPile"); + ui.discardPile = ui.create.div("#discardPile"); + ui.special = ui.create.div("#special"); + ui.ordering = ui.create.div("#ordering"); + ui.dialogs = []; + ui.controls = []; + ui.style = {}; + + ui.time = ui.create.div(ui.gameinfo); + var timeInterval = function () { + var date = new Date(); + var hours = date.getHours(); + var minutes = date.getMinutes(); + if (lib.config.watchface == "simple") { + ui.roundmenu.childNodes[13].style.transform = "rotate(" + get.round((hours + 9) * 30, 2) + "deg)"; + } + else { + ui.roundmenu.childNodes[13].style.transform = "rotate(" + get.round((hours + minutes / 60 + 9) * 30, 2) + "deg)"; + } + ui.roundmenu.childNodes[12].style.transform = "rotate(" + (minutes + 45) * 6 + "deg)"; + if (minutes < 10) { + minutes = "0" + minutes.toString(); + } + ui.time.innerHTML = hours + ":" + minutes; + }; + _status.timeInterval = setInterval(timeInterval, 30000); + timeInterval(); + if (!lib.config.show_time) { + ui.time.style.display = "none"; + } + + ui.timer = ui.create.div(".skillbar.shadowed.playerbg.hidden"); + ui.timer.id = "timer"; + ui.create.div(".skillbarshadow", ui.timer); + ui.create.div(".skillbarfill", ui.timer); + ui.timer.fillnode = ui.create.div(ui.timer.lastChild); + ui.timer.popnode = ui.create.div(".skillbartext", ui.timer); + ui.timer.popnode.style.opacity = 1; + ui.timer.position = 4; + ui.timer.style.zIndex = 5; + ui.timer.set = function (text, percentage) { + if (typeof text == "string" || typeof text == "number") { + ui.timer.popnode.innerHTML = text; + } + ui.timer.fillnode.style.top = ((1 - percentage) * 100) + "%"; + } + var setTimerPosition = function (e) { + this.position++; + if (this.position > 4) { + this.position = 1; + } + var left1 = "180px"; + var left2 = "calc(100% - 245px)"; + var top1 = "210px"; + var top2 = "calc(100% - 245px)"; + if (game.layout == "default") { + left1 = "265px"; + top1 = "160px"; + left2 = "calc(100% - 330px)"; + top2 = "calc(100% - 235px)"; + } + if (this.position == 1 || this.position == 2) { + this.style.top = top2; + } + else { + this.style.top = top1; + } + if (this.position == 1 || this.position == 4) { + this.style.left = left2; + } + else { + this.style.left = left1; + } + } + ui.timer.listen(setTimerPosition); + + ui.shortcut = ui.create.div("#shortcut.hidden", ui.window); + ui.shortcut.listen(ui.click.shortcut); + ui.create.div(ui.shortcut, function (e) { e.stopPropagation() }); + ui.create.div(".menubutton.round", "重来", ui.shortcut, game.reload).dataset.position = 1; + ui.create.div(".menubutton.round", "退出", ui.shortcut, game.exit).dataset.position = 3; + ui.create.div(".menubutton.round", "记录", ui.shortcut, ui.click.pause).dataset.position = 4; + ui.shortcut.autobutton = ui.create.div(".menubutton.round", "托管", ui.shortcut, ui.click.auto); + ui.shortcut.autobutton.dataset.position = 2; + ui.favmodelist = ui.create.div(".favmodelist", ui.shortcut); + ui.favmodelist.update = function () { + const favouriteMode = lib.config.favouriteMode; + let removed = false; + for (let index = 0; index < favouriteMode.length; index++) { + if (typeof favouriteMode[index] == "string") continue; + favouriteMode.splice(index--, 1); + if (!removed) removed = true; + } + if (removed) game.saveConfigValue("favouriteMode"); + this.innerHTML = ""; + favouriteMode.slice(0, 6).forEach((value, index) => this.add(value, index)); + let mode = lib.config.mode; + const config = get.config(`${mode}_mode`); + if (typeof config == "string") mode += `|${config}`; + if (favouriteMode.contains(mode)) ui.favmode.classList.add("glow"); + else ui.favmode.classList.remove("glow"); + }; + ui.favmodelist.add = function (name, index) { + const info = name.split("|"), mode = info[0], submode = info[1], node = ui.create.div(".menubutton.large", this), dataset = node.dataset; + dataset.type = Math.min(6, lib.config.favouriteMode.length) % 2 == 0 ? "even" : "odd"; + dataset.position = index; + let str = lib.translate[name] || lib.translate[mode] || ""; + if (str.length == 2) str += "模式"; + node.innerHTML = str; + node.listen(() => { + game.saveConfig("mode", mode); + if (submode) game.saveConfig(`${mode}_mode`, submode, mode); + game.reload(); + }); + }; + ui.favmode = ui.create.system("收藏", function () { + const mode = typeof _status.mode == "string" ? `${lib.config.mode}|${_status.mode}` : lib.config.mode; + if (this.classList.contains("glow")) { + this.classList.remove("glow"); + lib.config.favouriteMode.remove(mode); + } + else { + this.classList.add("glow"); + lib.config.favouriteMode.add(mode); + } + game.saveConfig("favouriteMode", lib.config.favouriteMode); + ui.favmodelist.update(); + _status.clicked = true; + }); + ui.favmode.style.display = "none"; + ui.favmodelist.update(); + // ui.create.div(".menubutton.round","菜单",ui.shortcut,ui.click.config).dataset.position=5; + + + if (_status.connectMode) { + ui.playerids.remove(); + ui.pause.innerHTML = "记录"; + } + setTimerPosition.call(ui.timer); + ui.arena.appendChild(ui.timer); + + if (!game.syncMenu) { + lib.onfree.push(function () { + ui.create.menu(); + ui.config2.classList.remove("hidden"); + ui.roundmenu.classList.remove("transparent2"); + setTimeout(function () { + ui.config2.style.transition = ""; + }, 500); + }); + } + else { + ui.create.menu(); + } + + lib.status.date = new Date(); + lib.status.dateDelayed = 0; + + while (lib.arenaReady.length) { + (lib.arenaReady.shift())(); + } + delete lib.arenaReady; + if (lib.config.auto_check_update) { + setTimeout(function () { + game.checkForUpdate(false); + }, 3000); + } + if (!lib.config.asset_version) { + lib.onfree.push(function () { + setTimeout(function () { + if (!game.download) { + game.saveConfig("asset_version", "无"); + } + else { + var func = function () { + if (confirm("是否下载图片和字体素材?(约175MB)")) { + if (!ui.arena.classList.contains("menupaused")) { + ui.click.configMenu(); + ui.click.menuTab("其它"); + } + setTimeout(game.checkForAssetUpdate, 500); + } + else { + game.saveConfig("asset_version", "无"); + } + } + if (_status.new_tutorial) { + _status.new_tutorial = func; + } + else { + func(); + } + } + }, 3000); + }); + } + if (localStorage.getItem(lib.configprefix + "playback")) { + setTimeout(lib.init.onfree); + } + + if (lib.config.test_game) { + ui.window.classList.add("testing"); + lib.config.game_speed = "vfast"; + lib.config.low_performance = true; + lib.config.animation = false; + _status.auto = true; + ui.auto.classList.add("glow"); + setTimeout(function () { + var node = ui.create.pause().animate("start"); + node.appendChild(ui.sidebar); + node.firstChild.innerHTML = "正在测试"; + node.removeEventListener("click", ui.click.resume); + }, 500); + } + } + static system(str, func, right, before) { + var parent = right ? ui.system2 : ui.system1; + var node = ui.create.div(); + if (before) { + parent.insertBefore(node, parent.firstChild); + } + else { + parent.appendChild(node); + } + node.innerHTML = str; + if (func) { + node.listen(func); + } + if (lib.config.button_press) { + node.addEventListener(lib.config.touchscreen ? "touchstart" : "mousedown", function (e) { + if (!node.classList.contains("hidden")) node.classList.add("pressdown"); + }); + node.addEventListener(lib.config.touchscreen ? "touchend" : "mouseup", function (e) { + node.classList.remove("pressdown"); + }); + node.addEventListener(lib.config.touchscreen ? "touchmove" : "mousemove", function (e) { + node.classList.remove("pressdown"); + }); + } + return node; + } + static pause() { + if (_status.pausing) return; + ui.click.shortcut(false); + var node = ui.create.div(".pausedbg", ui.window); + _status.pausing = true; + setTimeout(function () { + _status.pausing = false; + }, 500); + if (lib.config.touchscreen) { + setTimeout(function () { + node.addEventListener("touchend", ui.click.resume); + }, 500); + } + else { + node.addEventListener("click", ui.click.resume); + } + if (!lib.config.touchscreen) { + node.oncontextmenu = ui.click.resume; + } + + var node2 = ui.create.div(node); + if (_status.connectMode) { + node2.innerHTML = ""; + } + else { + node2.innerHTML = "已暂停"; + } + + return node; + } + static prebutton(item, type, position, noclick) { + var node = ui.create.div(position); + node.style.display = "none"; + node.link = item; + node.activate = function () { + ui.create.button(item, type, position, noclick, node); + delete node.activate; + } + _status.prebutton.push(node); + return node; + } + static button(item, type, position, noClick, button) { + return new lib.element.Button(item, type, position, noClick, button); + } + static buttons(list, type, position, noclick, zoom) { + var buttons = []; + var pre = (typeof type == "string" && type.slice(0, 3) == "pre"); + if (pre) { + if (!_status.prebutton) { + _status.prebutton = []; + lib.onfree.push(function () { + for (var i = 0; i < _status.prebutton.length; i++) { + if (_status.prebutton[i].activate) { + _status.prebutton[i].activate(); + } + } + delete _status.prebutton; + }); + } + } + for (var i = 0; i < list.length; i++) { + if (pre) { + buttons.push(ui.create.prebutton(list[i], type.slice(3), position, noclick)); + } + else { + buttons.push(ui.create.button(list[i], type, position, noclick)); + } + } + return buttons; + } + static textbuttons(list, dialog, noclick) { + for (var item of list) { + var str, link; + if (Array.isArray(item)) { + str = item[1]; + link = item[0]; + } + else { + str = item; + link = item; + } + if (!str.startsWith("${str}
      `; + var next = dialog.add(str); + if (!noclick) next.firstChild.addEventListener(lib.config.touchscreen ? "touchend" : "click", ui.click.button); + next.firstChild.link = link; + Object.setPrototypeOf(next, lib.element.Button.prototype); + dialog.buttons.add(next.firstChild); + } + } + static player(position, noclick) { + return new lib.element.Player(position, noclick); + } + static connectPlayers(ip) { + ui.updateConnectPlayerPositions(); + game.connectPlayers = []; + const configOL = lib.configOL; + const numberOfPlayers = parseInt(configOL.player_number) || configOL.number; + for (let position = 0; position < numberOfPlayers; position++) { + const player = ui.create.player(ui.window); + player.dataset.position = position; + player.classList.add("connect"); + game.connectPlayers.push(player); + } + + var bar = ui.create.div(ui.window); + bar.style.height = "20px"; + bar.style.width = "80%"; + bar.style.left = "10%"; + bar.style.top = "calc(200% / 7 - 120px + 5px)"; + bar.style.textAlign = "center"; + var ipbar = ui.create.div(".shadowed", ip, bar); + ipbar.style.padding = "4px"; + ipbar.style.borderRadius = "2px"; + ipbar.style.position = "relative"; + + var button = ui.create.div(".menubutton.large.highlight.connectbutton.connectbutton1.pointerdiv", game.online ? "退出联机" : "开始游戏", ui.window, function () { + if (button.clicked) return; + if (game.online) { + if (game.onlinezhu) { + game.send("startGame"); + } + else { + game.saveConfig("tmp_owner_roomId"); + game.saveConfig("tmp_user_roomId"); + game.saveConfig("reconnect_info"); + game.reload(); + } + } + else { + var num = 0; + for (var i of game.connectPlayers) { + if (!i.nickname && !i.classList.contains("unselectable2")) num++; + } + if (num >= lib.configOL.number - 1) { + alert("至少要有两名玩家才能开始游戏!"); + return; + } + game.resume(); + } + button.delete(); + bar.delete(); + shareButton.delete(); + delete ui.connectStartButton; + delete ui.connectStartBar; + delete ui.connectShareButton; + button.clicked = true; + }); + + var shareButton = ui.create.div(".menubutton.large.highlight.connectbutton.connectbutton2.pointerdiv", "分享房间", ui.window, function () { + var text = `无名杀-联机-${lib.translate[get.mode()]}-${game.connectPlayers.filter(p => p.avatar).length}/${game.connectPlayers.filter(p => !p.classList.contains("unselectable2")).length}\n${get.connectNickname()}邀请你加入${game.roomId}房间\n联机地址:${game.ip}\n请先通过游戏内菜单-开始-联机中启用“读取邀请链接”选项`; + window.focus(); + if (navigator.clipboard && lib.node) { + navigator.clipboard.writeText(text).then(() => { + game.alert(`分享内容复制成功`); + }).catch(e => { + game.alert(`分享内容复制失败${e || ""}`); + }); + } else { + var input = ui.create.node("textarea", ui.window, { opacity: "0" }); + input.value = text; + input.focus(); + input.select(); + var result = document.execCommand("copy"); + input.blur(); + ui.window.removeChild(input); + game.alert(`分享内容复制${result ? "成功" : "失败"}`); + } + }); + + ui.connectStartButton = button; + ui.connectStartBar = bar; + ui.connectShareButton = shareButton; + } + static players(numberOfPlayers) { + if (numberOfPlayers === 0) { + return; + } + if (numberOfPlayers == undefined) numberOfPlayers = lib.configOL.number; + if (numberOfPlayers == undefined) numberOfPlayers = get.playerNumber(); + if (typeof numberOfPlayers == "string") { + numberOfPlayers = parseInt(numberOfPlayers); + } + if (!numberOfPlayers) numberOfPlayers = 5; + for (let ordinal = 0; ordinal < numberOfPlayers; ordinal++) { + const player = ui.create.player().animate("start"); + game.players.push(player); + player.dataset.position = ordinal; + } + const players = game.players; + for (let ordinal = 0; ordinal < players.length; ordinal++) { + if (ordinal > 0) { + players[ordinal].previous = players[ordinal - 1]; + players[ordinal].previousSeat = players[ordinal - 1]; + } + if (ordinal < players.length - 1) { + players[ordinal].next = players[ordinal + 1]; + players[ordinal].nextSeat = players[ordinal + 1]; + } + } + players[0].previous = players[players.length - 1]; + players[0].previousSeat = players[players.length - 1]; + players[players.length - 1].next = players[0]; + players[players.length - 1].nextSeat = players[0]; + ui.arena.setNumber(numberOfPlayers); + players.forEach(player => ui.arena.appendChild(player)); + return players; + } + static me(hasme) { + ui.mebg = ui.create.div("#mebg", ui.arena); + ui.me = ui.create.div("#me", ui.arena).animate("start"); + ui.handcards1Container = ui.create.div("#handcards1", ui.me); + ui.handcards2Container = ui.create.div("#handcards2", ui.me); + ui.arena.classList.remove("nome"); + if (lib.config.mousewheel && !lib.config.touchscreen) { + ui.handcards1Container.onmousewheel = ui.click.mousewheel; + ui.handcards2Container.onmousewheel = ui.click.mousewheel; + } + ui.handcards1Container.ontouchstart = ui.click.touchStart; + ui.handcards2Container.ontouchstart = ui.click.touchStart; + ui.handcards1Container.ontouchmove = ui.click.touchScroll; + ui.handcards2Container.ontouchmove = ui.click.touchScroll; + ui.handcards1Container.style.webkitOverflowScrolling = "touch"; + ui.handcards2Container.style.webkitOverflowScrolling = "touch"; + + if (hasme && game.me) { + ui.handcards1 = game.me.node.handcards1; + ui.handcards2 = game.me.node.handcards2; + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + // ui.updatehl(); + } + else if (game.players.length) { + game.me = game.players[0]; + ui.handcards1 = game.me.node.handcards1; + ui.handcards2 = game.me.node.handcards2; + ui.handcards1Container.appendChild(ui.handcards1); + ui.handcards2Container.appendChild(ui.handcards2); + // ui.updatehl(); + } + } + static card(position, info, noclick) { + return new lib.element.Card(position, info, noclick); + } + static cardsAsync() { + if (lib.onfree) { + _status.waitingForCards = Array.from(arguments); + lib.onfree.push(function () { + if (_status.waitingForCards) { + ui.create.cards.apply(ui.create, _status.waitingForCards); + delete _status.waitingForCards; + } + }); + } + else { + ui.create.cards.apply(ui.create, arguments); + } + } + static cards(ordered) { + if (_status.brawl) { + if (_status.brawl.cardPile) { + lib.card.list = _status.brawl.cardPile(lib.card.list); + } + if (_status.brawl.orderedPile) { + ordered = true; + } + } + if (!ordered) { + lib.card.list.randomSort(); + } + for (var i = 0; i < lib.card.list.length; i++) { + if (lib.card[lib.card.list[i][2]]) { + if (!lib.card.list[i]._replaced) { + if (!_status.connectMode) { + if (lib.config.bannedcards.contains(lib.card.list[i][2])) continue; + } + else { + if (lib.configOL.bannedcards.contains(lib.card.list[i][2])) continue; + } + if (game.bannedcards && game.bannedcards.contains(lib.card.list[i][2])) continue; + } + lib.inpile.add(lib.card.list[i][2]); + if (lib.card.list[i][2] == "sha" && lib.card.list[i][3]) lib.inpile_nature.add(lib.card.list[i][3]); + ui.create.card(ui.cardPile).init(lib.card.list[i]); + } + } + lib.inpile.sort(lib.sort.card); + const natures = Array.from(lib.nature.keys()); + lib.inpile_nature.sort(function (a, b) { + return natures.indexOf(a) - natures.indexOf(b); + }) + for (var i in _status.cardtag) { + if (!_status.cardtag[i].length) delete _status.cardtag[i]; + } + game.broadcastAll(function (num, pile, top, cardtag, inpile2) { + if (ui.cardPileNumber) ui.cardPileNumber.innerHTML = "0轮 剩余牌: " + num; + lib.inpile = pile; + _status.pileTop = top; + _status.cardtag = cardtag; + lib.inpile_nature = inpile2; + }, ui.cardPile.childNodes.length, lib.inpile, ui.cardPile.firstChild, _status.cardtag, lib.inpile_nature); + } +} diff --git a/noname/ui/css.d.ts b/noname/ui/css.d.ts new file mode 100644 index 000000000..47b9d8f9c --- /dev/null +++ b/noname/ui/css.d.ts @@ -0,0 +1,4 @@ +interface CSS extends Record { +} + +export const css: CSS; diff --git a/noname/ui/css.js b/noname/ui/css.js new file mode 100644 index 000000000..b6d078a00 --- /dev/null +++ b/noname/ui/css.js @@ -0,0 +1 @@ +export const css = {}; diff --git a/noname/ui/selected.js b/noname/ui/selected.js new file mode 100644 index 000000000..a51887017 --- /dev/null +++ b/noname/ui/selected.js @@ -0,0 +1,5 @@ +export const selected = { + buttons: [], + cards: [], + targets: [] +};