From c53db8f4f57061be56d802da9ade7b3a106c800c Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Tue, 5 Dec 2023 06:23:52 -0800 Subject: [PATCH] Change the structure. --- noname.js | 4 - noname/ai.js | 6 +- noname/ai/basic.js | 88 ++++---- noname/game.js | 5 + noname/get.js | 104 +++++++++- noname/library.js | 61 +++++- noname/library/animate.js | 8 +- noname/library/animate/card.d.ts | 4 +- noname/library/animate/card.js | 2 +- noname/library/animate/skill.d.ts | 4 +- noname/library/animate/skill.js | 2 +- noname/library/announce.js | 101 ++++++++++ noname/library/channel.js | 98 +++++++++ noname/library/character-dialog-group.js | 17 ++ noname/library/config-menu.js | 5 + noname/library/config-menu/general.js | 6 + noname/library/config-menu/general/config.js | 7 + .../general/config/low-performance.js | 17 ++ .../general/config/mount-combine.js | 9 + noname/library/config.d.ts | 5 + noname/library/config.js | 1 + noname/library/element.js | 4 +- noname/library/element/game-event.js | 13 +- noname/library/element/v-card.js | 1 + noname/library/handler-option.d.ts | 3 + noname/library/hook-map.d.ts | 3 + noname/library/hook-map.js | 1 + noname/library/hook.js | 5 + noname/library/hook/global-skill.js | 1 + noname/library/hooks.js | 190 ++++++++++++++++++ noname/library/imported.js | 1 + noname/library/pinyins.js | 5 + noname/library/pinyins/metadata.js | 10 + noname/library/pinyins/metadata/non-medial.js | 5 + noname/library/pinyins/metadata/rhyme.js | 16 ++ noname/library/promise-resolve.d.ts | 1 + noname/library/stratagem-buff.js | 72 +++++++ noname/library/yingbian.js | 42 ++++ noname/library/yingbian/condition.js | 132 ++++++++++++ noname/status.js | 6 +- noname/ui.js | 21 ++ noname/ui/click.js | 5 + noname/ui/selected.js | 5 + 43 files changed, 1025 insertions(+), 71 deletions(-) create mode 100644 noname/game.js create mode 100644 noname/library/announce.js create mode 100644 noname/library/channel.js create mode 100644 noname/library/character-dialog-group.js create mode 100644 noname/library/config-menu.js create mode 100644 noname/library/config-menu/general.js create mode 100644 noname/library/config-menu/general/config.js create mode 100644 noname/library/config-menu/general/config/low-performance.js create mode 100644 noname/library/config-menu/general/config/mount-combine.js create mode 100644 noname/library/config.d.ts create mode 100644 noname/library/config.js create mode 100644 noname/library/element/v-card.js create mode 100644 noname/library/handler-option.d.ts create mode 100644 noname/library/hook-map.d.ts create mode 100644 noname/library/hook-map.js create mode 100644 noname/library/hook.js create mode 100644 noname/library/hook/global-skill.js create mode 100644 noname/library/hooks.js create mode 100644 noname/library/imported.js create mode 100644 noname/library/pinyins.js create mode 100644 noname/library/pinyins/metadata.js create mode 100644 noname/library/pinyins/metadata/non-medial.js create mode 100644 noname/library/pinyins/metadata/rhyme.js create mode 100644 noname/library/promise-resolve.d.ts create mode 100644 noname/library/stratagem-buff.js create mode 100644 noname/library/yingbian.js create mode 100644 noname/library/yingbian/condition.js create mode 100644 noname/ui.js create mode 100644 noname/ui/click.js create mode 100644 noname/ui/selected.js diff --git a/noname.js b/noname.js index 517b9e043..e69de29bb 100644 --- a/noname.js +++ b/noname.js @@ -1,4 +0,0 @@ -export * from "./noname/ai.js"; -export * from "./noname/status.js"; -export * from "./noname/library.js"; -export * from "./noname/get.js"; diff --git a/noname/ai.js b/noname/ai.js index 67ad92185..69a980d9a 100644 --- a/noname/ai.js +++ b/noname/ai.js @@ -1,7 +1,7 @@ -import { Get } from "../noname.js"; -import { BasicAI } from "./ai/basic.js"; +import { Basic } from "./ai/basic.js"; +import { Get } from "./get.js"; export const ai = { - basic: BasicAI, + basic: Basic, get: Get }; diff --git a/noname/ai/basic.js b/noname/ai/basic.js index ac6e2569e..739447fb1 100644 --- a/noname/ai/basic.js +++ b/noname/ai/basic.js @@ -1,24 +1,32 @@ -import { status as _status } from "../../noname.js"; +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`); + } -export class BasicAI { static chooseButton(check) { - var event = _status.event; + 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 (ui.selected.buttons.length >= range[0]) { + range = Get.select(event.selectButton); + if (selected.buttons.length >= range[0]) { ok = true; } if (range[1] <= -1) { j = 0; - for (i = 0; i < ui.selected.buttons.length; i++) { - j += check(ui.selected.buttons[i]); + for (i = 0; i < selected.buttons.length; i++) { + j += check(selected.buttons[i]); } return (j > 0); } - buttons = get.selectableButtons(); + buttons = Get.selectableButtons(); if (buttons.length == 0) { return ok; } @@ -41,40 +49,41 @@ export class BasicAI { } } buttons[ix].classList.add('selected'); - ui.selected.buttons.add(buttons[ix]); - game.check(); - if (ui.selected.buttons.length >= range[0]) { + selected.buttons.add(buttons[ix]); + Game.check(); + if (selected.buttons.length >= range[0]) { ok = true; } - if (ui.selected.buttons.length == range[1]) { + if (selected.buttons.length == range[1]) { return true; } } } + static chooseCard(check) { - var event = _status.event; + 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 (ui.selected.cards.length >= range[0]) { + range = Get.select(event.selectCard); + if (selected.cards.length >= range[0]) { ok = true; } if (range[1] <= -1) { - if (ui.selected.cards.length == 0) return true; + if (selected.cards.length == 0) return true; j = 0; - for (i = 0; i < ui.selected.cards.length; i++) { - effect = check(ui.selected.cards[i]); + 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()); + cards = Get.selectableCards(); + if (!status.event.player._noSkill) { + cards = cards.concat(Get.skills()); } if (cards.length == 0) { return ok; @@ -98,11 +107,11 @@ export class BasicAI { } } if (typeof cards[ix] == 'string') { - ui.click.skill(cards[ix]); - var info = get.info(event.skill); + Click.skill(cards[ix]); + var info = Get.info(event.skill); if (info.filterCard) { - check = info.check || get.unuseful2; - return (ai.basic.chooseCard(check)); + check = info.check || Get.unuseful2; + return (this.chooseCard(check)); } else { return true; @@ -110,32 +119,33 @@ export class BasicAI { } else { cards[ix].classList.add('selected'); - ui.selected.cards.add(cards[ix]); - game.check(); - if (ui.selected.cards.length >= range[0]) { + selected.cards.add(cards[ix]); + Game.check(); + if (selected.cards.length >= range[0]) { ok = true; } - if (ui.selected.cards.length == range[1]) { + if (selected.cards.length == range[1]) { return true; } } } } + static chooseTarget(check) { - var event = _status.event; + 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 (ui.selected.targets.length >= range[0]) { + range = Get.select(event.selectTarget); + if (selected.targets.length >= range[0]) { ok = true; } if (range[1] <= -1) { j = 0; - for (i = 0; i < ui.selected.targets.length; i++) { - effect = check(ui.selected.targets[i]); + 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); } @@ -144,7 +154,7 @@ export class BasicAI { else if (range[1] == 0) { return check() > 0 } - targets = get.selectableTargets(); + targets = Get.selectableTargets(); if (targets.length == 0) { return range[0] == 0 || ok; } @@ -167,12 +177,12 @@ export class BasicAI { } } targets[ix].classList.add('selected'); - ui.selected.targets.add(targets[ix]); - game.check(); - if (ui.selected.targets.length >= range[0]) { + selected.targets.add(targets[ix]); + Game.check(); + if (selected.targets.length >= range[0]) { ok = true; } - if (ui.selected.targets.length == range[1]) { + if (selected.targets.length == range[1]) { return true; } } diff --git a/noname/game.js b/noname/game.js new file mode 100644 index 000000000..b90a68079 --- /dev/null +++ b/noname/game.js @@ -0,0 +1,5 @@ +export class Game { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } +} diff --git a/noname/get.js b/noname/get.js index a4645e9dd..e7d543a8b 100644 --- a/noname/get.js +++ b/noname/get.js @@ -1,6 +1,10 @@ -import { Library as lib, status as _status } from "../noname.js"; +import { status as _status } from "./status"; export class Get { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + /** * @template T * @overload @@ -14,4 +18,102 @@ export class Get { static event(key) { return key ? _status.event[key] : _status.event; } + + /** + * @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 = get.translation(str.viewAs); + } + else { + str2 = get.translation(str.name); + } + if (str2 == "杀") { + str2 = ""; + if (typeof str.nature == "string") { + let natures = str.nature.split(lib.natureSeparator).sort(lib.sort.nature); + for (let nature of natures) { + str2 += lib.translate["nature_" + nature] || lib.translate[nature] || ""; + } + } + str2 += "杀"; + } + if (get.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 += lib.translate[i + "_tag"]; + } + } + if (tagstr) { + str2 += "·" + tagstr; + } + } + if (str.suit && str.number || str.isCard) { + var cardnum = get.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 += "(" + get.translation(str) + ")"; + } + else { + str2 += "【" + get.translation(get.suit(str, false)) + cardnum + "】"; + } + } + } + return str2; + } + if (Array.isArray(str)) { + var str2 = get.translation(str[0], arg); + for (var i = 1; i < str.length; i++) { + str2 += "、" + get.translation(str[i], arg); + } + return str2; + } + if (get.itemtype(str) == "natures") { + let natures = str.split(lib.natureSeparator).sort(lib.sort.nature); + var str2 = ""; + for (var nature of natures) { + str2 += lib.translate["nature_" + nature] || lib.translate[nature] || ""; + } + return str2; + } + if (arg == "skill") { + if (lib.translate[str + "_ab"]) return lib.translate[str + "_ab"]; + if (lib.translate[str]) return lib.translate[str].slice(0, 2); + return str; + } + else if (arg == "info") { + if (lib.translate[str + "_info"]) return lib.translate[str + "_info"]; + var str2 = str.slice(0, str.length - 1); + if (lib.translate[str2 + "_info"]) return lib.translate[str2 + "_info"]; + if (str.lastIndexOf("_") > 0) { + str2 = str.slice(0, str.lastIndexOf("_")); + if (lib.translate[str2 + "_info"]) return lib.translate[str2 + "_info"]; + } + str2 = str.slice(0, str.length - 2); + if (lib.translate[str2 + "_info"]) return lib.translate[str2 + "_info"]; + if (lib.skill[str] && lib.skill[str].prompt) return lib.skill[str].prompt; + } + if (lib.translate[str]) { + return lib.translate[str]; + } + if (typeof str == "string") { + if (lib.translate["nature_" + str]) return lib.translate["nature_" + str]; + return str; + } + if (typeof str == "number" || typeof str == "boolean") { + return str.toString(); + } + if (str && str.toString) { + return str.toString(); + } + return ""; + } } diff --git a/noname/library.js b/noname/library.js index 5776826ec..b92d40f92 100644 --- a/noname/library.js +++ b/noname/library.js @@ -1,20 +1,31 @@ import { animate } from "./library/animate.js"; +import { announce } from "./library/announce.js"; import { cardPack } from "./library/card-pack.js"; import { cardType } from "./library/card-type.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 { configMenu } from "./library/config-menu.js"; import { dynamicTranslate } from "./library/dynamic-translate.js"; import { element } from "./library/element.js"; import { emotionList } from "./library/emotion-list.js"; import { extensionPack } from "./library/extension-pack.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 { pinyins } from "./library/pinyins.js"; import { skin } from "./library/skin.js"; +import { stratagemBuff } from "./library/stratagem-buff.js"; import { updateURLs } from "./library/update-urls.js"; +import { yingbian } from "./library/yingbian.js"; -const nonameInitialized = localStorage.getItem('noname_inited'); +const nonameInitialized = localStorage.getItem("noname_inited"); export class Library { static configprefix = "noname_0.9_"; @@ -23,9 +34,9 @@ export class Library { static updateURL = updateURLs.github; static mirrorURL = updateURLs.coding; static hallURL = "47.99.105.222"; - static assetURL = typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized; + 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 compatibleEdition = Boolean(typeof nonameInitialized == "string" && nonameInitialized.match(/\/(?:com\.widget|yuri\.nakamura)\.noname\//)); static changeLog = []; static updates = []; static canvasUpdates = []; @@ -61,9 +72,53 @@ export class Library { static extensions = []; static extensionPack = extensionPack; static cardType = cardType; + static hook = hook; + static hooks = hooks; static element = element; + 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 = configMenu; 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; + }); + } + } } diff --git a/noname/library/animate.js b/noname/library/animate.js index cace6e142..7da77889e 100644 --- a/noname/library/animate.js +++ b/noname/library/animate.js @@ -1,7 +1,7 @@ -import { animateCard } from "./animate/card.js"; -import { animateSkill } from "./animate/skill.js"; +import { card } from "./animate/card.js"; +import { skill } from "./animate/skill.js"; export const animate = { - skill: animateSkill, - card: animateCard + skill, + card }; diff --git a/noname/library/animate/card.d.ts b/noname/library/animate/card.d.ts index 5534c58dd..35193ec9b 100644 --- a/noname/library/animate/card.d.ts +++ b/noname/library/animate/card.d.ts @@ -1,3 +1,3 @@ -interface AnimateCard extends Record { } +interface Card extends Record { } -export const animateCard: AnimateCard; +export const card: Card; diff --git a/noname/library/animate/card.js b/noname/library/animate/card.js index 57b8ce511..9dd692f57 100644 --- a/noname/library/animate/card.js +++ b/noname/library/animate/card.js @@ -1 +1 @@ -export const animateCard = {}; +export const card = {}; diff --git a/noname/library/animate/skill.d.ts b/noname/library/animate/skill.d.ts index d4bd33ef5..4d324ed95 100644 --- a/noname/library/animate/skill.d.ts +++ b/noname/library/animate/skill.d.ts @@ -1,3 +1,3 @@ -interface AnimateSkill extends Record { } +interface Skill extends Record { } -export const animateSkill: AnimateSkill; +export const skill: Skill; diff --git a/noname/library/animate/skill.js b/noname/library/animate/skill.js index 316153f39..b5128ac48 100644 --- a/noname/library/animate/skill.js +++ b/noname/library/animate/skill.js @@ -1 +1 @@ -export const animateSkill = {}; +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/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..f3d9fa11a --- /dev/null +++ b/noname/library/character-dialog-group.js @@ -0,0 +1,17 @@ +import { Get } from "../get.js"; +import { config } from "./config.js"; + +export class CharacterDialogGroup { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } + + static 收藏(name, capt) { + return config.favouriteCharacter.includes(name) ? capt : null; + } + + static 最近(name, capt) { + var list = Get.config("recentCharacter") || []; + return list.includes(name) ? capt : null; + } +} diff --git a/noname/library/config-menu.js b/noname/library/config-menu.js new file mode 100644 index 000000000..13f8e0057 --- /dev/null +++ b/noname/library/config-menu.js @@ -0,0 +1,5 @@ +import { general } from "./config-menu/general.js"; + +export const configMenu = { + general +}; diff --git a/noname/library/config-menu/general.js b/noname/library/config-menu/general.js new file mode 100644 index 000000000..655aaca25 --- /dev/null +++ b/noname/library/config-menu/general.js @@ -0,0 +1,6 @@ +import { config } from "./general/config.js"; + +export const general = { + name: "通用", + config: config +}; diff --git a/noname/library/config-menu/general/config.js b/noname/library/config-menu/general/config.js new file mode 100644 index 000000000..d2731c967 --- /dev/null +++ b/noname/library/config-menu/general/config.js @@ -0,0 +1,7 @@ +import { lowPerformance } from "./config/low-performance.js"; +import { mountCombine } from "./config/mount-combine.js"; + +export const config = { + mount_combine: mountCombine, + low_performance: lowPerformance +}; diff --git a/noname/library/config-menu/general/config/low-performance.js b/noname/library/config-menu/general/config/low-performance.js new file mode 100644 index 000000000..45b9b857f --- /dev/null +++ b/noname/library/config-menu/general/config/low-performance.js @@ -0,0 +1,17 @@ +import { Game } from "../../../../game.js"; +import { UI } from "../../../../ui.js"; + +export const lowPerformance = { + 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/config-menu/general/config/mount-combine.js b/noname/library/config-menu/general/config/mount-combine.js new file mode 100644 index 000000000..aa285adef --- /dev/null +++ b/noname/library/config-menu/general/config/mount-combine.js @@ -0,0 +1,9 @@ +const listItem = document.createElement("li"); +listItem.textContent = "将进攻坐骑栏和防御坐骑栏合并为同一个位置(重启后生效)。"; + +export const mountCombine = { + name: "合并坐骑栏", + init: false, + intro: listItem.outerHTML, + restart: true +}; diff --git a/noname/library/config.d.ts b/noname/library/config.d.ts new file mode 100644 index 000000000..5a3b8cd63 --- /dev/null +++ b/noname/library/config.d.ts @@ -0,0 +1,5 @@ +interface Config extends Record { + favouriteCharacter: string[]; +} + +export const config: Config; diff --git a/noname/library/config.js b/noname/library/config.js new file mode 100644 index 000000000..c4470d209 --- /dev/null +++ b/noname/library/config.js @@ -0,0 +1 @@ +export const config = {}; diff --git a/noname/library/element.js b/noname/library/element.js index f14913cbf..16f281fd8 100644 --- a/noname/library/element.js +++ b/noname/library/element.js @@ -2,6 +2,6 @@ import { GameEvent } from "./element/game-event.js"; import { Player } from "./element/player.js"; export const element = { - Player: Player, - GameEvent: GameEvent + Player, + GameEvent }; diff --git a/noname/library/element/game-event.js b/noname/library/element/game-event.js index e13272baa..40733c345 100644 --- a/noname/library/element/game-event.js +++ b/noname/library/element/game-event.js @@ -1,4 +1,5 @@ -import { Get as get } from "../../../noname.js"; +import { Game } from "../../game.js"; +import { Get } from "../../get.js"; export class GameEvent { /** @@ -8,24 +9,24 @@ export class GameEvent { constructor(name, trigger) { if (typeof name == 'string') { this.name = name; - const gameEvent = get.event(); + 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); + Game.globalEventHandlers.addHandlerToEvent(this); } this.step = 0; this.finished = false; /** - * @type {GameEvent[]} + * @type {this[]} */ this.next = []; /** - * @type {GameEvent[]} + * @type {this[]} */ this.after = []; this.custom = { @@ -36,7 +37,7 @@ export class GameEvent { this._notrigger = []; this._result = {}; this._set = []; - if (trigger !== false && !game.online) this._triggered = 0; + if (trigger !== false && !Game.online) this._triggered = 0; } static initialGameEvent() { diff --git a/noname/library/element/v-card.js b/noname/library/element/v-card.js new file mode 100644 index 000000000..db1e43907 --- /dev/null +++ b/noname/library/element/v-card.js @@ -0,0 +1 @@ +export class VCard { } 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/hook-map.d.ts b/noname/library/hook-map.d.ts new file mode 100644 index 000000000..b1f9045ae --- /dev/null +++ b/noname/library/hook-map.d.ts @@ -0,0 +1,3 @@ +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/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/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/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 index d91bb53d0..7251ce88d 100644 --- a/noname/status.js +++ b/noname/status.js @@ -1,4 +1,4 @@ -import { Library as lib } from "../noname.js"; +import { GameEvent } from "./library/element/game-event.js"; import { aiStatus } from "./status/ai.js"; import { cardTag } from "./status/card-tag.js"; import { postReconnect } from "./status/post-reconnect.js"; @@ -10,7 +10,7 @@ export const status = { over: false, clicked: false, auto: false, - event: lib.element.GameEvent.initialGameEvent(), + event: GameEvent.initialGameEvent(), ai: aiStatus, lastdragchange: [], skillaudio: [], @@ -30,5 +30,5 @@ export const status = { cardtag: cardTag, renku: [], prehidden_skills: [], - postReconnect: postReconnect + postReconnect } diff --git a/noname/ui.js b/noname/ui.js new file mode 100644 index 000000000..fe554e0a0 --- /dev/null +++ b/noname/ui.js @@ -0,0 +1,21 @@ +import { Click } from "./ui/click.js"; +import { selected } from "./ui/selected.js"; + +class HTMLWindowElement extends HTMLDivElement { } + +customElements.define("window", HTMLWindowElement, { + extends: "div" +}); + +export class UI { + static click = Click; + static selected = selected; + /** + * @type {HTMLWindowElement} + */ + static window; + + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } +} diff --git a/noname/ui/click.js b/noname/ui/click.js new file mode 100644 index 000000000..46ee65410 --- /dev/null +++ b/noname/ui/click.js @@ -0,0 +1,5 @@ +export class Click { + constructor() { + throw new TypeError(`${new.target.name} is not a constructor`); + } +} 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: [] +};