add achievement

This commit is contained in:
Vick Scarlet
2021-09-09 22:50:03 +08:00
parent d72b6c553f
commit e06139d5c0
10 changed files with 1537 additions and 48 deletions

63
src/achievement.js Normal file
View 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;

View File

@@ -1,4 +1,3 @@
import { max, sum } from './functions/util.js';
import { summary } from './functions/summary.js'
import Life from './life.js'
@@ -26,7 +25,7 @@ class App{
]);
this.#specialthanks = specialthanks;
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');
}
const keyDownCallback = (keyboardEvent) => {
@@ -35,8 +34,8 @@ class App{
pressEnterFunc && typeof pressEnterFunc === 'function' && pressEnterFunc();
}
}
window.removeEventListener('keydown', keyDownCallback);
window.addEventListener('keydown', keyDownCallback);
globalThis.removeEventListener('keydown', keyDownCallback);
globalThis.addEventListener('keydown', keyDownCallback);
}
initPages() {
@@ -109,8 +108,8 @@ class App{
<ul class="g1"></ul>
<ul class="g2"></ul>
</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="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://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://dun.mianbaoduo.com/@vickscarlet')" style="background-color:#c69; left:50%; right:auto; transform: translate(2rem,-50%);">打赏程序(顿顿饭)</button>
</div>
`);
@@ -374,10 +373,10 @@ class App{
const property = this.#life.getLastRecord();
$("#lifeProperty").html(`
<li><span>颜值</span><span>${property.CHR}</span></li>
<li><span>智力</span><span>${property.INT}</span</li>
<li><span>体质</span><span>${property.STR}</span</li>
<li><span>家境</span><span>${property.MNY}</span</li>
<li><span>快乐</span><span>${property.SPR}</span</li>
<li><span>智力</span><span>${property.INT}</span></li>
<li><span>体质</span><span>${property.STR}</span></li>
<li><span>家境</span><span>${property.MNY}</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) {

View File

@@ -1,10 +1,27 @@
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
window.hideBanners = (e) => {
globalThis.hideBanners = (e) => {
document
.querySelectorAll(".banner.visible")
.forEach((b) => b.classList.remove("visible"));

View File

@@ -1,28 +1,33 @@
import Property from './property.js';
import Event from './event.js';
import Talent from './talent.js';
import Achievement from './achievement.js';
class Life {
constructor() {
this.#property = new Property();
this.#event = new Event();
this.#talent = new Talent();
this.#achievement = new Achievement();
}
#property;
#event;
#talent;
#achievement;
#triggerTalents;
async initial() {
const [age, talents, events] = await Promise.all([
const [age, talents, events, achievements] = await Promise.all([
json('age'),
json('talents'),
json('events'),
json('achievement'),
])
this.#property.initial({age});
this.#talent.initial({talents});
this.#event.initial({events});
this.#achievement.initial({achievements});
}
restart(allocation) {
@@ -30,6 +35,10 @@ class Life {
this.#property.restart(allocation);
this.doTalent();
this.#property.restartLastStep();
this.#achievement.achieve(
this.#achievement.Opportunity.START,
this.#property
)
}
getTalentAllocationAddition(talents) {
@@ -49,6 +58,10 @@ class Life {
const isEnd = this.#property.isEnd();
const content = [talentContent, eventContent].flat();
this.#achievement.achieve(
this.#achievement.Opportunity.TRAJECTORY,
this.#property
)
return { age, content, isEnd };
}
@@ -115,6 +128,10 @@ class Life {
}
getSummary() {
this.#achievement.achieve(
this.#achievement.Opportunity.SUMMARY,
this.#property
)
return {
AGE: this.#property.get(this.#property.TYPES.HAGE),
CHR: this.#property.get(this.#property.TYPES.HCHR),
@@ -134,8 +151,18 @@ class Life {
return this.#talent.exclusive(talents, exclusive);
}
getAchievements() {
return this.#achievement.list();
}
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;

View File

@@ -38,10 +38,12 @@ class Property {
// Achievement Total
ATLT: "ATLT", // 拥有过的天赋 Achieve Talent
AEVT: "AEVT", // 触发过的事件 Achieve Event
ACHV: "ACHV", // 达成的成就 Achievement
};
#ageData;
#data;
#data = {};
initial({age}) {
@@ -160,6 +162,7 @@ class Property {
return this.lsget('extendTalent') || null;
case this.TYPES.ATLT:
case this.TYPES.AEVT:
case this.TYPES.ACHV:
return this.lsget(prop) || [];
default: return 0;
}
@@ -289,9 +292,16 @@ class Property {
this.#data[h] = max(this.#data[h], value);
}
achieve(prop, newData = []) {
achieve(prop, newData) {
let key;
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.EVT: key = this.TYPES.AEVT; break;
default: return;
@@ -302,7 +312,7 @@ class Property {
Array.from(
new Set(
lastData
.concat(newData)
.concat(newData||[])
.flat()
)
)