Change the structure.
This commit is contained in:
parent
611658114f
commit
c53db8f4f5
|
@ -1,4 +0,0 @@
|
||||||
export * from "./noname/ai.js";
|
|
||||||
export * from "./noname/status.js";
|
|
||||||
export * from "./noname/library.js";
|
|
||||||
export * from "./noname/get.js";
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Get } from "../noname.js";
|
import { Basic } from "./ai/basic.js";
|
||||||
import { BasicAI } from "./ai/basic.js";
|
import { Get } from "./get.js";
|
||||||
|
|
||||||
export const ai = {
|
export const ai = {
|
||||||
basic: BasicAI,
|
basic: Basic,
|
||||||
get: Get
|
get: Get
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) {
|
static chooseButton(check) {
|
||||||
var event = _status.event;
|
var event = status.event;
|
||||||
var i, j, range, buttons, buttons2;
|
var i, j, range, buttons, buttons2;
|
||||||
var ok = false, forced = event.forced;
|
var ok = false, forced = event.forced;
|
||||||
var iwhile = 100;
|
var iwhile = 100;
|
||||||
while (iwhile--) {
|
while (iwhile--) {
|
||||||
range = get.select(event.selectButton);
|
range = Get.select(event.selectButton);
|
||||||
if (ui.selected.buttons.length >= range[0]) {
|
if (selected.buttons.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (range[1] <= -1) {
|
if (range[1] <= -1) {
|
||||||
j = 0;
|
j = 0;
|
||||||
for (i = 0; i < ui.selected.buttons.length; i++) {
|
for (i = 0; i < selected.buttons.length; i++) {
|
||||||
j += check(ui.selected.buttons[i]);
|
j += check(selected.buttons[i]);
|
||||||
}
|
}
|
||||||
return (j > 0);
|
return (j > 0);
|
||||||
}
|
}
|
||||||
buttons = get.selectableButtons();
|
buttons = Get.selectableButtons();
|
||||||
if (buttons.length == 0) {
|
if (buttons.length == 0) {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -41,40 +49,41 @@ export class BasicAI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buttons[ix].classList.add('selected');
|
buttons[ix].classList.add('selected');
|
||||||
ui.selected.buttons.add(buttons[ix]);
|
selected.buttons.add(buttons[ix]);
|
||||||
game.check();
|
Game.check();
|
||||||
if (ui.selected.buttons.length >= range[0]) {
|
if (selected.buttons.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (ui.selected.buttons.length == range[1]) {
|
if (selected.buttons.length == range[1]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static chooseCard(check) {
|
static chooseCard(check) {
|
||||||
var event = _status.event;
|
var event = status.event;
|
||||||
if (event.filterCard == undefined) return (check() > 0);
|
if (event.filterCard == undefined) return (check() > 0);
|
||||||
var i, j, range, cards, cards2, skills, check, effect;
|
var i, j, range, cards, cards2, skills, check, effect;
|
||||||
var ok = false, forced = event.forced;
|
var ok = false, forced = event.forced;
|
||||||
var iwhile = 100;
|
var iwhile = 100;
|
||||||
while (iwhile--) {
|
while (iwhile--) {
|
||||||
range = get.select(event.selectCard);
|
range = Get.select(event.selectCard);
|
||||||
if (ui.selected.cards.length >= range[0]) {
|
if (selected.cards.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (range[1] <= -1) {
|
if (range[1] <= -1) {
|
||||||
if (ui.selected.cards.length == 0) return true;
|
if (selected.cards.length == 0) return true;
|
||||||
j = 0;
|
j = 0;
|
||||||
for (i = 0; i < ui.selected.cards.length; i++) {
|
for (i = 0; i < selected.cards.length; i++) {
|
||||||
effect = check(ui.selected.cards[i]);
|
effect = check(selected.cards[i]);
|
||||||
if (effect < 0) j -= Math.sqrt(-effect);
|
if (effect < 0) j -= Math.sqrt(-effect);
|
||||||
else j += Math.sqrt(effect);
|
else j += Math.sqrt(effect);
|
||||||
}
|
}
|
||||||
return (j > 0);
|
return (j > 0);
|
||||||
}
|
}
|
||||||
cards = get.selectableCards();
|
cards = Get.selectableCards();
|
||||||
if (!_status.event.player._noSkill) {
|
if (!status.event.player._noSkill) {
|
||||||
cards = cards.concat(get.skills());
|
cards = cards.concat(Get.skills());
|
||||||
}
|
}
|
||||||
if (cards.length == 0) {
|
if (cards.length == 0) {
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -98,11 +107,11 @@ export class BasicAI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof cards[ix] == 'string') {
|
if (typeof cards[ix] == 'string') {
|
||||||
ui.click.skill(cards[ix]);
|
Click.skill(cards[ix]);
|
||||||
var info = get.info(event.skill);
|
var info = Get.info(event.skill);
|
||||||
if (info.filterCard) {
|
if (info.filterCard) {
|
||||||
check = info.check || get.unuseful2;
|
check = info.check || Get.unuseful2;
|
||||||
return (ai.basic.chooseCard(check));
|
return (this.chooseCard(check));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -110,32 +119,33 @@ export class BasicAI {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cards[ix].classList.add('selected');
|
cards[ix].classList.add('selected');
|
||||||
ui.selected.cards.add(cards[ix]);
|
selected.cards.add(cards[ix]);
|
||||||
game.check();
|
Game.check();
|
||||||
if (ui.selected.cards.length >= range[0]) {
|
if (selected.cards.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (ui.selected.cards.length == range[1]) {
|
if (selected.cards.length == range[1]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static chooseTarget(check) {
|
static chooseTarget(check) {
|
||||||
var event = _status.event;
|
var event = status.event;
|
||||||
if (event.filterTarget == undefined) return (check() > 0);
|
if (event.filterTarget == undefined) return (check() > 0);
|
||||||
var i, j, range, targets, targets2, effect;
|
var i, j, range, targets, targets2, effect;
|
||||||
var ok = false, forced = event.forced;
|
var ok = false, forced = event.forced;
|
||||||
var iwhile = 100;
|
var iwhile = 100;
|
||||||
while (iwhile--) {
|
while (iwhile--) {
|
||||||
range = get.select(event.selectTarget);
|
range = Get.select(event.selectTarget);
|
||||||
if (ui.selected.targets.length >= range[0]) {
|
if (selected.targets.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (range[1] <= -1) {
|
if (range[1] <= -1) {
|
||||||
j = 0;
|
j = 0;
|
||||||
for (i = 0; i < ui.selected.targets.length; i++) {
|
for (i = 0; i < selected.targets.length; i++) {
|
||||||
effect = check(ui.selected.targets[i]);
|
effect = check(selected.targets[i]);
|
||||||
if (effect < 0) j -= Math.sqrt(-effect);
|
if (effect < 0) j -= Math.sqrt(-effect);
|
||||||
else j += Math.sqrt(effect);
|
else j += Math.sqrt(effect);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +154,7 @@ export class BasicAI {
|
||||||
else if (range[1] == 0) {
|
else if (range[1] == 0) {
|
||||||
return check() > 0
|
return check() > 0
|
||||||
}
|
}
|
||||||
targets = get.selectableTargets();
|
targets = Get.selectableTargets();
|
||||||
if (targets.length == 0) {
|
if (targets.length == 0) {
|
||||||
return range[0] == 0 || ok;
|
return range[0] == 0 || ok;
|
||||||
}
|
}
|
||||||
|
@ -167,12 +177,12 @@ export class BasicAI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
targets[ix].classList.add('selected');
|
targets[ix].classList.add('selected');
|
||||||
ui.selected.targets.add(targets[ix]);
|
selected.targets.add(targets[ix]);
|
||||||
game.check();
|
Game.check();
|
||||||
if (ui.selected.targets.length >= range[0]) {
|
if (selected.targets.length >= range[0]) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
if (ui.selected.targets.length == range[1]) {
|
if (selected.targets.length == range[1]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export class Game {
|
||||||
|
constructor() {
|
||||||
|
throw new TypeError(`${new.target.name} is not a constructor`);
|
||||||
|
}
|
||||||
|
}
|
104
noname/get.js
104
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 {
|
export class Get {
|
||||||
|
constructor() {
|
||||||
|
throw new TypeError(`${new.target.name} is not a constructor`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @overload
|
* @overload
|
||||||
|
@ -14,4 +18,102 @@ export class Get {
|
||||||
static event(key) {
|
static event(key) {
|
||||||
return key ? _status.event[key] : _status.event;
|
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 "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
import { animate } from "./library/animate.js";
|
import { animate } from "./library/animate.js";
|
||||||
|
import { announce } from "./library/announce.js";
|
||||||
import { cardPack } from "./library/card-pack.js";
|
import { cardPack } from "./library/card-pack.js";
|
||||||
import { cardType } from "./library/card-type.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 { characterFilter } from "./library/character-filter.js";
|
||||||
import { characterIntro } from "./library/character-intro.js";
|
import { characterIntro } from "./library/character-intro.js";
|
||||||
import { characterPack } from "./library/character-pack.js";
|
import { characterPack } from "./library/character-pack.js";
|
||||||
import { characterReplace } from "./library/character-replace.js";
|
import { characterReplace } from "./library/character-replace.js";
|
||||||
import { characterSort } from "./library/character-sort.js";
|
import { characterSort } from "./library/character-sort.js";
|
||||||
import { characterTitle } from "./library/character-title.js";
|
import { characterTitle } from "./library/character-title.js";
|
||||||
|
import { configMenu } from "./library/config-menu.js";
|
||||||
import { dynamicTranslate } from "./library/dynamic-translate.js";
|
import { dynamicTranslate } from "./library/dynamic-translate.js";
|
||||||
import { element } from "./library/element.js";
|
import { element } from "./library/element.js";
|
||||||
import { emotionList } from "./library/emotion-list.js";
|
import { emotionList } from "./library/emotion-list.js";
|
||||||
import { extensionPack } from "./library/extension-pack.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 { skin } from "./library/skin.js";
|
||||||
|
import { stratagemBuff } from "./library/stratagem-buff.js";
|
||||||
import { updateURLs } from "./library/update-urls.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 {
|
export class Library {
|
||||||
static configprefix = "noname_0.9_";
|
static configprefix = "noname_0.9_";
|
||||||
|
@ -23,9 +34,9 @@ export class Library {
|
||||||
static updateURL = updateURLs.github;
|
static updateURL = updateURLs.github;
|
||||||
static mirrorURL = updateURLs.coding;
|
static mirrorURL = updateURLs.coding;
|
||||||
static hallURL = "47.99.105.222";
|
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 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 changeLog = [];
|
||||||
static updates = [];
|
static updates = [];
|
||||||
static canvasUpdates = [];
|
static canvasUpdates = [];
|
||||||
|
@ -61,9 +72,53 @@ export class Library {
|
||||||
static extensions = [];
|
static extensions = [];
|
||||||
static extensionPack = extensionPack;
|
static extensionPack = extensionPack;
|
||||||
static cardType = cardType;
|
static cardType = cardType;
|
||||||
|
static hook = hook;
|
||||||
|
static hooks = hooks;
|
||||||
static element = element;
|
static element = element;
|
||||||
|
static Channel = Channel;
|
||||||
|
/**
|
||||||
|
* @todo Waiting for [Rintim](https://github.com/Rintim)’s pull request.
|
||||||
|
*/
|
||||||
|
static announce = announce;
|
||||||
|
/**
|
||||||
|
* @type {Map<string, string>}
|
||||||
|
*/
|
||||||
|
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() {
|
constructor() {
|
||||||
throw new TypeError(`${new.target.name} is not a 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { animateCard } from "./animate/card.js";
|
import { card } from "./animate/card.js";
|
||||||
import { animateSkill } from "./animate/skill.js";
|
import { skill } from "./animate/skill.js";
|
||||||
|
|
||||||
export const animate = {
|
export const animate = {
|
||||||
skill: animateSkill,
|
skill,
|
||||||
card: animateCard
|
card
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
interface AnimateCard extends Record<string, Function> { }
|
interface Card extends Record<string, Function> { }
|
||||||
|
|
||||||
export const animateCard: AnimateCard;
|
export const card: Card;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export const animateCard = {};
|
export const card = {};
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
interface AnimateSkill extends Record<string, Function> { }
|
interface Skill extends Record<string, Function> { }
|
||||||
|
|
||||||
export const animateSkill: AnimateSkill;
|
export const skill: Skill;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export const animateSkill = {};
|
export const skill = {};
|
||||||
|
|
|
@ -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<string, (event: Event) => 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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -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> | [T, import("./promise-resolve").PromiseResolve<void>] | null}
|
||||||
|
*/
|
||||||
|
this._buffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向该频道发送消息,在消息未被接受前将等待
|
||||||
|
*
|
||||||
|
* @param {T} value - 要发送的消息
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
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<T>}
|
||||||
|
*/
|
||||||
|
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<T>} 接收到的消息
|
||||||
|
*/
|
||||||
|
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<void>]}
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { general } from "./config-menu/general.js";
|
||||||
|
|
||||||
|
export const configMenu = {
|
||||||
|
general
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { config } from "./general/config.js";
|
||||||
|
|
||||||
|
export const general = {
|
||||||
|
name: "通用",
|
||||||
|
config: config
|
||||||
|
};
|
|
@ -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
|
||||||
|
};
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,9 @@
|
||||||
|
const listItem = document.createElement("li");
|
||||||
|
listItem.textContent = "将进攻坐骑栏和防御坐骑栏合并为同一个位置(重启后生效)。";
|
||||||
|
|
||||||
|
export const mountCombine = {
|
||||||
|
name: "合并坐骑栏",
|
||||||
|
init: false,
|
||||||
|
intro: listItem.outerHTML,
|
||||||
|
restart: true
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface Config extends Record<string, any> {
|
||||||
|
favouriteCharacter: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config: Config;
|
|
@ -0,0 +1 @@
|
||||||
|
export const config = {};
|
|
@ -2,6 +2,6 @@ import { GameEvent } from "./element/game-event.js";
|
||||||
import { Player } from "./element/player.js";
|
import { Player } from "./element/player.js";
|
||||||
|
|
||||||
export const element = {
|
export const element = {
|
||||||
Player: Player,
|
Player,
|
||||||
GameEvent: GameEvent
|
GameEvent
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Get as get } from "../../../noname.js";
|
import { Game } from "../../game.js";
|
||||||
|
import { Get } from "../../get.js";
|
||||||
|
|
||||||
export class GameEvent {
|
export class GameEvent {
|
||||||
/**
|
/**
|
||||||
|
@ -8,24 +9,24 @@ export class GameEvent {
|
||||||
constructor(name, trigger) {
|
constructor(name, trigger) {
|
||||||
if (typeof name == 'string') {
|
if (typeof name == 'string') {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
const gameEvent = get.event();
|
const gameEvent = Get.event();
|
||||||
|
|
||||||
if (gameEvent) {
|
if (gameEvent) {
|
||||||
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
const type = `onNext${name[0].toUpperCase()}${name.slice(1)}`;
|
||||||
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
if (gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
game.globalEventHandlers.addHandlerToEvent(this);
|
Game.globalEventHandlers.addHandlerToEvent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.step = 0;
|
this.step = 0;
|
||||||
this.finished = false;
|
this.finished = false;
|
||||||
/**
|
/**
|
||||||
* @type {GameEvent[]}
|
* @type {this[]}
|
||||||
*/
|
*/
|
||||||
this.next = [];
|
this.next = [];
|
||||||
/**
|
/**
|
||||||
* @type {GameEvent[]}
|
* @type {this[]}
|
||||||
*/
|
*/
|
||||||
this.after = [];
|
this.after = [];
|
||||||
this.custom = {
|
this.custom = {
|
||||||
|
@ -36,7 +37,7 @@ export class GameEvent {
|
||||||
this._notrigger = [];
|
this._notrigger = [];
|
||||||
this._result = {};
|
this._result = {};
|
||||||
this._set = [];
|
this._set = [];
|
||||||
if (trigger !== false && !game.online) this._triggered = 0;
|
if (trigger !== false && !Game.online) this._triggered = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static initialGameEvent() {
|
static initialGameEvent() {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export class VCard { }
|
|
@ -0,0 +1,3 @@
|
||||||
|
export interface HandlerOption extends Record<string, unknown> {
|
||||||
|
state: "begin" | "end";
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface HookMap extends Record<string, true> { }
|
||||||
|
|
||||||
|
export const hookMap: HookMap;
|
|
@ -0,0 +1 @@
|
||||||
|
export const hookMap = {};
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { globalSkill } from "./hook/global-skill.js";
|
||||||
|
|
||||||
|
export const hook = {
|
||||||
|
globalskill: globalSkill
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export const globalSkill = {};
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export const imported = {};
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { pinyinsMetadata } from "./pinyins/metadata.js";
|
||||||
|
|
||||||
|
export const pinyins = {
|
||||||
|
_metadata: pinyinsMetadata
|
||||||
|
};
|
|
@ -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
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const nonMedial = {
|
||||||
|
i: ["ing", "iu", "ie", "in"],
|
||||||
|
u: ["ui", "un"],
|
||||||
|
ü: ["üe", "ün"],
|
||||||
|
};
|
|
@ -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"]
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export type PromiseResolve<T> = (value: T) => void;
|
|
@ -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<string, (event: GameEvent, option: import("./handler-option").HandlerOption) => 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。"]
|
||||||
|
])
|
||||||
|
};
|
|
@ -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", "无视条件执行所有选项"]
|
||||||
|
])
|
||||||
|
};
|
|
@ -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]
|
||||||
|
])
|
||||||
|
};
|
|
@ -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 { aiStatus } from "./status/ai.js";
|
||||||
import { cardTag } from "./status/card-tag.js";
|
import { cardTag } from "./status/card-tag.js";
|
||||||
import { postReconnect } from "./status/post-reconnect.js";
|
import { postReconnect } from "./status/post-reconnect.js";
|
||||||
|
@ -10,7 +10,7 @@ export const status = {
|
||||||
over: false,
|
over: false,
|
||||||
clicked: false,
|
clicked: false,
|
||||||
auto: false,
|
auto: false,
|
||||||
event: lib.element.GameEvent.initialGameEvent(),
|
event: GameEvent.initialGameEvent(),
|
||||||
ai: aiStatus,
|
ai: aiStatus,
|
||||||
lastdragchange: [],
|
lastdragchange: [],
|
||||||
skillaudio: [],
|
skillaudio: [],
|
||||||
|
@ -30,5 +30,5 @@ export const status = {
|
||||||
cardtag: cardTag,
|
cardtag: cardTag,
|
||||||
renku: [],
|
renku: [],
|
||||||
prehidden_skills: [],
|
prehidden_skills: [],
|
||||||
postReconnect: postReconnect
|
postReconnect
|
||||||
}
|
}
|
||||||
|
|
|
@ -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`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export class Click {
|
||||||
|
constructor() {
|
||||||
|
throw new TypeError(`${new.target.name} is not a constructor`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const selected = {
|
||||||
|
buttons: [],
|
||||||
|
cards: [],
|
||||||
|
targets: []
|
||||||
|
};
|
Loading…
Reference in New Issue