mirror of
https://github.com/VickScarlet/lifeRestart.git
synced 2025-07-22 20:13:57 +08:00
add achievement
This commit is contained in:
1334
data/achievement.json
Normal file
1334
data/achievement.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/achievement.xlsx
Normal file
BIN
data/achievement.xlsx
Normal file
Binary file not shown.
64
repl/app.js
64
repl/app.js
@@ -1,9 +1,26 @@
|
|||||||
import { max, sum } from '../src/functions/util.js';
|
|
||||||
import { summary } from '../src/functions/summary.js'
|
import { summary } from '../src/functions/summary.js'
|
||||||
import { readFile } from 'fs/promises';
|
import { readFile } from 'fs/promises';
|
||||||
import Life from '../src/life.js';
|
import Life from '../src/life.js';
|
||||||
|
|
||||||
global.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
globalThis.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
||||||
|
|
||||||
|
globalThis.$$eventMap = new Map();
|
||||||
|
globalThis.$$event = (tag, data) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.forEach(fn=>fn(data));
|
||||||
|
}
|
||||||
|
globalThis.$$on = (tag, fn) => {
|
||||||
|
let listener = $$eventMap.get(tag);
|
||||||
|
if(!listener) {
|
||||||
|
listener = new Set();
|
||||||
|
$$eventMap.set(tag, listener);
|
||||||
|
}
|
||||||
|
listener.add(fn);
|
||||||
|
}
|
||||||
|
globalThis.$$off = (tag, fn) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.delete(fn);
|
||||||
|
}
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -47,7 +64,7 @@ class App {
|
|||||||
|
|
||||||
async initial() {
|
async initial() {
|
||||||
this.output('Now Loading...');
|
this.output('Now Loading...');
|
||||||
this.#talentExtend = global.localStorage.talentExtend;
|
this.#talentExtend = localStorage.talentExtend;
|
||||||
await this.#life.initial();
|
await this.#life.initial();
|
||||||
this.output(`\rLoading Complete.
|
this.output(`\rLoading Complete.
|
||||||
人生重开模拟器
|
人生重开模拟器
|
||||||
@@ -55,6 +72,11 @@ class App {
|
|||||||
\n🎉键入 \x1B[4m/remake\x1B[24m 开始游戏`,
|
\n🎉键入 \x1B[4m/remake\x1B[24m 开始游戏`,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
$$on('achievement', ({name})=>this.output(`
|
||||||
|
-------------------------
|
||||||
|
解锁成就【${name}】
|
||||||
|
-------------------------
|
||||||
|
`))
|
||||||
}
|
}
|
||||||
|
|
||||||
io(input, output, exit) {
|
io(input, output, exit) {
|
||||||
@@ -289,7 +311,7 @@ class App {
|
|||||||
remake() {
|
remake() {
|
||||||
if(this.#talentExtend) {
|
if(this.#talentExtend) {
|
||||||
this.#life.talentExtend(this.#talentExtend)
|
this.#life.talentExtend(this.#talentExtend)
|
||||||
global.dumpLocalStorage();
|
dumpLocalStorage();
|
||||||
this.#talentExtend = null;
|
this.#talentExtend = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,34 +571,22 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
summary() {
|
summary() {
|
||||||
|
const summaryData = this.#life.getSummary();
|
||||||
const records = this.#life.getRecord();
|
const format = (name, type) => {
|
||||||
const s = (type, func)=>{
|
const value = summaryData[type];
|
||||||
const value = func(records.map(({[type]:v})=>v));
|
|
||||||
const { judge, grade } = summary(type, value);
|
const { judge, grade } = summary(type, value);
|
||||||
return { judge, grade, value };
|
return this.style(`grade${grade}b`, `${name}:${value} ${judge}`);
|
||||||
};
|
|
||||||
|
|
||||||
const style = (name, grade, judge, value) => this.style(`grade${grade}b`, `${name}:${value} ${judge}`);
|
|
||||||
const judge = (name, type, func) => {
|
|
||||||
const { judge, grade, value } = s(type, func);
|
|
||||||
return style(name, grade, judge, value );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'🎉 总评',
|
'🎉 总评',
|
||||||
judge('颜值', 'CHR', max),
|
format('颜值', 'CHR'),
|
||||||
judge('智力', 'INT', max),
|
format('智力', 'INT'),
|
||||||
judge('体质', 'STR', max),
|
format('体质', 'STR'),
|
||||||
judge('家境', 'MNY', max),
|
format('家境', 'MNY'),
|
||||||
judge('快乐', 'SPR', max),
|
format('快乐', 'SPR'),
|
||||||
judge('享年', 'AGE', max),
|
format('享年', 'AGE'),
|
||||||
(()=>{
|
format('总评', 'SUM'),
|
||||||
const m = type=>max(records.map(({[type]: value})=>value));
|
|
||||||
const value = Math.floor(sum(m('CHR'), m('INT'), m('STR'), m('MNY'), m('SPR'))*2 + m('AGE')/2);
|
|
||||||
const { judge, grade } = summary('SUM', value);
|
|
||||||
return style('总评', grade, judge, value );
|
|
||||||
})(),
|
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,12 +4,14 @@ import { readFile, writeFile } from 'fs/promises';
|
|||||||
async function main() {
|
async function main() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
global.localStorage = JSON.parse(await readFile('__localStorage.json'));
|
globalThis.localStorage = JSON.parse(await readFile('__localStorage.json'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
global.localStorage = {};
|
globalThis.localStorage = {};
|
||||||
}
|
}
|
||||||
|
localStorage.getItem = key => localStorage[key]===void 0? null: localStorage[key];
|
||||||
|
localStorage.setItem = (key, value) => (localStorage[key] = value);
|
||||||
|
|
||||||
global.dumpLocalStorage = async ()=>await writeFile('__localStorage.json', JSON.stringify( global.localStorage))
|
globalThis.dumpLocalStorage = async ()=>await writeFile('__localStorage.json', JSON.stringify( global.localStorage))
|
||||||
|
|
||||||
const app = new App();
|
const app = new App();
|
||||||
app.io(
|
app.io(
|
||||||
|
63
src/achievement.js
Normal file
63
src/achievement.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { clone } from './functions/util.js';
|
||||||
|
import { checkCondition } from './functions/condition.js';
|
||||||
|
|
||||||
|
class Achievement {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
// 时机
|
||||||
|
Opportunity = {
|
||||||
|
START: "START", // 分配完成点数,点击开始新人生后
|
||||||
|
TRAJECTORY: "TRAJECTORY", // 每一年的人生经历中
|
||||||
|
SUMMARY: "SUMMARY", // 人生结束,点击人生总结后
|
||||||
|
END: "END", // 游戏完成,点击重开 重开次数在这之后才会+1
|
||||||
|
};
|
||||||
|
|
||||||
|
#achievements;
|
||||||
|
|
||||||
|
initial({achievements}) {
|
||||||
|
this.#achievements = achievements;
|
||||||
|
}
|
||||||
|
|
||||||
|
list(property) {
|
||||||
|
return Object
|
||||||
|
.values(this.#achievements)
|
||||||
|
.map(({
|
||||||
|
id, name, opportunity,
|
||||||
|
description, hide, grade,
|
||||||
|
})=>({
|
||||||
|
id, name, opportunity,
|
||||||
|
description, hide, grade,
|
||||||
|
isAchieved: this.isAchieved(id, property),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
get(achievementId) {
|
||||||
|
const achievement = this.#achievements[achievementId];
|
||||||
|
if(!achievement) throw new Error(`[ERROR] No Achievement[${achievementId}]`);
|
||||||
|
return clone(achievement);
|
||||||
|
}
|
||||||
|
|
||||||
|
check(achievementId, property) {
|
||||||
|
const { condition } = this.get(achievementId);
|
||||||
|
return checkCondition(property, condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
isAchieved(achievementId, property) {
|
||||||
|
for(const [achieved] of (property.get(property.TYPES.ACHV)||[]))
|
||||||
|
if(achieved == achievementId) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
achieve(opportunity, property) {
|
||||||
|
this.list(property)
|
||||||
|
.filter(({isAchieved})=>!isAchieved)
|
||||||
|
.filter(({opportunity: o})=>o==opportunity)
|
||||||
|
.filter(({id})=>this.check(id, property))
|
||||||
|
.forEach(({id})=>{
|
||||||
|
property.achieve(property.TYPES.ACHV, id)
|
||||||
|
$$event('achievement', this.get(id))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Achievement;
|
23
src/app.js
23
src/app.js
@@ -1,4 +1,3 @@
|
|||||||
import { max, sum } from './functions/util.js';
|
|
||||||
import { summary } from './functions/summary.js'
|
import { summary } from './functions/summary.js'
|
||||||
import Life from './life.js'
|
import Life from './life.js'
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ class App{
|
|||||||
]);
|
]);
|
||||||
this.#specialthanks = specialthanks;
|
this.#specialthanks = specialthanks;
|
||||||
this.switch('index');
|
this.switch('index');
|
||||||
window.onerror = (event, source, lineno, colno, error) => {
|
globalThis.onerror = (event, source, lineno, colno, error) => {
|
||||||
this.hint(`[ERROR] at (${source}:${lineno}:${colno})\n\n${error?.stack||error||'unknow Error'}`, 'error');
|
this.hint(`[ERROR] at (${source}:${lineno}:${colno})\n\n${error?.stack||error||'unknow Error'}`, 'error');
|
||||||
}
|
}
|
||||||
const keyDownCallback = (keyboardEvent) => {
|
const keyDownCallback = (keyboardEvent) => {
|
||||||
@@ -35,8 +34,8 @@ class App{
|
|||||||
pressEnterFunc && typeof pressEnterFunc === 'function' && pressEnterFunc();
|
pressEnterFunc && typeof pressEnterFunc === 'function' && pressEnterFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.removeEventListener('keydown', keyDownCallback);
|
globalThis.removeEventListener('keydown', keyDownCallback);
|
||||||
window.addEventListener('keydown', keyDownCallback);
|
globalThis.addEventListener('keydown', keyDownCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
initPages() {
|
initPages() {
|
||||||
@@ -109,8 +108,8 @@ class App{
|
|||||||
<ul class="g1"></ul>
|
<ul class="g1"></ul>
|
||||||
<ul class="g2"></ul>
|
<ul class="g2"></ul>
|
||||||
</div>
|
</div>
|
||||||
<button class="sponsor" onclick="window.open('https://afdian.net/@LifeRestart')" style="background: linear-gradient(90deg,#946ce6,#7e5fd9); left:auto; right:50%; transform: translate(-2rem,-50%);">打赏策划(爱发电)</button>
|
<button class="sponsor" onclick="globalThis.open('https://afdian.net/@LifeRestart')" style="background: linear-gradient(90deg,#946ce6,#7e5fd9); left:auto; right:50%; transform: translate(-2rem,-50%);">打赏策划(爱发电)</button>
|
||||||
<button class="sponsor" onclick="window.open('https://dun.mianbaoduo.com/@vickscarlet')" style="background-color:#c69; left:50%; right:auto; transform: translate(2rem,-50%);">打赏程序(顿顿饭)</button>
|
<button class="sponsor" onclick="globalThis.open('https://dun.mianbaoduo.com/@vickscarlet')" style="background-color:#c69; left:50%; right:auto; transform: translate(2rem,-50%);">打赏程序(顿顿饭)</button>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
@@ -374,10 +373,10 @@ class App{
|
|||||||
const property = this.#life.getLastRecord();
|
const property = this.#life.getLastRecord();
|
||||||
$("#lifeProperty").html(`
|
$("#lifeProperty").html(`
|
||||||
<li><span>颜值</span><span>${property.CHR}</span></li>
|
<li><span>颜值</span><span>${property.CHR}</span></li>
|
||||||
<li><span>智力</span><span>${property.INT}</span</li>
|
<li><span>智力</span><span>${property.INT}</span></li>
|
||||||
<li><span>体质</span><span>${property.STR}</span</li>
|
<li><span>体质</span><span>${property.STR}</span></li>
|
||||||
<li><span>家境</span><span>${property.MNY}</span</li>
|
<li><span>家境</span><span>${property.MNY}</span></li>
|
||||||
<li><span>快乐</span><span>${property.SPR}</span</li>
|
<li><span>快乐</span><span>${property.SPR}</span></li>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -587,6 +586,10 @@ class App{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$$on('achievement', ({name})=>{
|
||||||
|
this.hint(`解锁成就【${name}】`, 'success');
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(page) {
|
switch(page) {
|
||||||
|
21
src/index.js
21
src/index.js
@@ -1,10 +1,27 @@
|
|||||||
import App from '../src/app.js';
|
import App from '../src/app.js';
|
||||||
|
|
||||||
|
globalThis.$$eventMap = new Map();
|
||||||
|
globalThis.$$event = (tag, data) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.forEach(fn=>fn(data));
|
||||||
|
}
|
||||||
|
globalThis.$$on = (tag, fn) => {
|
||||||
|
let listener = $$eventMap.get(tag);
|
||||||
|
if(!listener) {
|
||||||
|
listener = new Set();
|
||||||
|
$$eventMap.set(tag, listener);
|
||||||
|
}
|
||||||
|
listener.add(fn);
|
||||||
|
}
|
||||||
|
globalThis.$$off = (tag, fn) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.delete(fn);
|
||||||
|
}
|
||||||
|
|
||||||
window.json = async fileName => await (await fetch(`../data/${fileName}.json`)).json();
|
globalThis.json = async fileName => await (await fetch(`../data/${fileName}.json`)).json();
|
||||||
|
|
||||||
// Pssst, I've created a github package - https://github.com/brookesb91/dismissible
|
// Pssst, I've created a github package - https://github.com/brookesb91/dismissible
|
||||||
window.hideBanners = (e) => {
|
globalThis.hideBanners = (e) => {
|
||||||
document
|
document
|
||||||
.querySelectorAll(".banner.visible")
|
.querySelectorAll(".banner.visible")
|
||||||
.forEach((b) => b.classList.remove("visible"));
|
.forEach((b) => b.classList.remove("visible"));
|
||||||
|
31
src/life.js
31
src/life.js
@@ -1,28 +1,33 @@
|
|||||||
import Property from './property.js';
|
import Property from './property.js';
|
||||||
import Event from './event.js';
|
import Event from './event.js';
|
||||||
import Talent from './talent.js';
|
import Talent from './talent.js';
|
||||||
|
import Achievement from './achievement.js';
|
||||||
|
|
||||||
class Life {
|
class Life {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.#property = new Property();
|
this.#property = new Property();
|
||||||
this.#event = new Event();
|
this.#event = new Event();
|
||||||
this.#talent = new Talent();
|
this.#talent = new Talent();
|
||||||
|
this.#achievement = new Achievement();
|
||||||
}
|
}
|
||||||
|
|
||||||
#property;
|
#property;
|
||||||
#event;
|
#event;
|
||||||
#talent;
|
#talent;
|
||||||
|
#achievement;
|
||||||
#triggerTalents;
|
#triggerTalents;
|
||||||
|
|
||||||
async initial() {
|
async initial() {
|
||||||
const [age, talents, events] = await Promise.all([
|
const [age, talents, events, achievements] = await Promise.all([
|
||||||
json('age'),
|
json('age'),
|
||||||
json('talents'),
|
json('talents'),
|
||||||
json('events'),
|
json('events'),
|
||||||
|
json('achievement'),
|
||||||
])
|
])
|
||||||
this.#property.initial({age});
|
this.#property.initial({age});
|
||||||
this.#talent.initial({talents});
|
this.#talent.initial({talents});
|
||||||
this.#event.initial({events});
|
this.#event.initial({events});
|
||||||
|
this.#achievement.initial({achievements});
|
||||||
}
|
}
|
||||||
|
|
||||||
restart(allocation) {
|
restart(allocation) {
|
||||||
@@ -30,6 +35,10 @@ class Life {
|
|||||||
this.#property.restart(allocation);
|
this.#property.restart(allocation);
|
||||||
this.doTalent();
|
this.doTalent();
|
||||||
this.#property.restartLastStep();
|
this.#property.restartLastStep();
|
||||||
|
this.#achievement.achieve(
|
||||||
|
this.#achievement.Opportunity.START,
|
||||||
|
this.#property
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getTalentAllocationAddition(talents) {
|
getTalentAllocationAddition(talents) {
|
||||||
@@ -49,6 +58,10 @@ class Life {
|
|||||||
const isEnd = this.#property.isEnd();
|
const isEnd = this.#property.isEnd();
|
||||||
|
|
||||||
const content = [talentContent, eventContent].flat();
|
const content = [talentContent, eventContent].flat();
|
||||||
|
this.#achievement.achieve(
|
||||||
|
this.#achievement.Opportunity.TRAJECTORY,
|
||||||
|
this.#property
|
||||||
|
)
|
||||||
return { age, content, isEnd };
|
return { age, content, isEnd };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +128,10 @@ class Life {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSummary() {
|
getSummary() {
|
||||||
|
this.#achievement.achieve(
|
||||||
|
this.#achievement.Opportunity.SUMMARY,
|
||||||
|
this.#property
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
AGE: this.#property.get(this.#property.TYPES.HAGE),
|
AGE: this.#property.get(this.#property.TYPES.HAGE),
|
||||||
CHR: this.#property.get(this.#property.TYPES.HCHR),
|
CHR: this.#property.get(this.#property.TYPES.HCHR),
|
||||||
@@ -134,8 +151,18 @@ class Life {
|
|||||||
return this.#talent.exclusive(talents, exclusive);
|
return this.#talent.exclusive(talents, exclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAchievements() {
|
||||||
|
return this.#achievement.list();
|
||||||
|
}
|
||||||
|
|
||||||
get times() { return this.#property?.get(this.#property.TYPES.TMS) || 0; }
|
get times() { return this.#property?.get(this.#property.TYPES.TMS) || 0; }
|
||||||
set times(v) { return this.#property?.set(this.#property.TYPES.TMS, v) || 0; }
|
set times(v) {
|
||||||
|
this.#property?.set(this.#property.TYPES.TMS, v) || 0;
|
||||||
|
this.#achievement.achieve(
|
||||||
|
this.#achievement.Opportunity.END,
|
||||||
|
this.#property
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Life;
|
export default Life;
|
||||||
|
@@ -38,10 +38,12 @@ class Property {
|
|||||||
// Achievement Total
|
// Achievement Total
|
||||||
ATLT: "ATLT", // 拥有过的天赋 Achieve Talent
|
ATLT: "ATLT", // 拥有过的天赋 Achieve Talent
|
||||||
AEVT: "AEVT", // 触发过的事件 Achieve Event
|
AEVT: "AEVT", // 触发过的事件 Achieve Event
|
||||||
|
|
||||||
|
ACHV: "ACHV", // 达成的成就 Achievement
|
||||||
};
|
};
|
||||||
|
|
||||||
#ageData;
|
#ageData;
|
||||||
#data;
|
#data = {};
|
||||||
|
|
||||||
initial({age}) {
|
initial({age}) {
|
||||||
|
|
||||||
@@ -160,6 +162,7 @@ class Property {
|
|||||||
return this.lsget('extendTalent') || null;
|
return this.lsget('extendTalent') || null;
|
||||||
case this.TYPES.ATLT:
|
case this.TYPES.ATLT:
|
||||||
case this.TYPES.AEVT:
|
case this.TYPES.AEVT:
|
||||||
|
case this.TYPES.ACHV:
|
||||||
return this.lsget(prop) || [];
|
return this.lsget(prop) || [];
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
@@ -289,9 +292,16 @@ class Property {
|
|||||||
this.#data[h] = max(this.#data[h], value);
|
this.#data[h] = max(this.#data[h], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
achieve(prop, newData = []) {
|
achieve(prop, newData) {
|
||||||
let key;
|
let key;
|
||||||
switch(prop) {
|
switch(prop) {
|
||||||
|
case this.TYPES.ACHV:
|
||||||
|
const lastData = this.lsget(prop);
|
||||||
|
this.lsset(
|
||||||
|
prop,
|
||||||
|
(lastData || []).concat([[newData, Date.now()]])
|
||||||
|
);
|
||||||
|
return;
|
||||||
case this.TYPES.TLT: key = this.TYPES.ATLT; break;
|
case this.TYPES.TLT: key = this.TYPES.ATLT; break;
|
||||||
case this.TYPES.EVT: key = this.TYPES.AEVT; break;
|
case this.TYPES.EVT: key = this.TYPES.AEVT; break;
|
||||||
default: return;
|
default: return;
|
||||||
@@ -302,7 +312,7 @@ class Property {
|
|||||||
Array.from(
|
Array.from(
|
||||||
new Set(
|
new Set(
|
||||||
lastData
|
lastData
|
||||||
.concat(newData)
|
.concat(newData||[])
|
||||||
.flat()
|
.flat()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@@ -1,7 +1,30 @@
|
|||||||
import { readFile } from 'fs/promises';
|
import { readFile } from 'fs/promises';
|
||||||
import Life from '../src/life.js'
|
import Life from '../src/life.js'
|
||||||
|
|
||||||
global.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
globalThis.json = async fileName => JSON.parse(await readFile(`data/${fileName}.json`));
|
||||||
|
|
||||||
|
globalThis.localStorage = {};
|
||||||
|
localStorage.getItem = key => localStorage[key]===void 0? null: localStorage[key];
|
||||||
|
localStorage.setItem = (key, value) => (localStorage[key] = value);
|
||||||
|
|
||||||
|
|
||||||
|
globalThis.$$eventMap = new Map();
|
||||||
|
globalThis.$$event = (tag, data) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.forEach(fn=>fn(data));
|
||||||
|
}
|
||||||
|
globalThis.$$on = (tag, fn) => {
|
||||||
|
let listener = $$eventMap.get(tag);
|
||||||
|
if(!listener) {
|
||||||
|
listener = new Set();
|
||||||
|
$$eventMap.set(tag, listener);
|
||||||
|
}
|
||||||
|
listener.add(fn);
|
||||||
|
}
|
||||||
|
globalThis.$$off = (tag, fn) => {
|
||||||
|
const listener = $$eventMap.get(tag);
|
||||||
|
if(listener) listener.delete(fn);
|
||||||
|
}
|
||||||
|
|
||||||
async function debug() {
|
async function debug() {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user