import { max, sum } from './functions/util.js'; import { summary } from './functions/summary.js' import Life from './life.js' class App{ constructor(){ this.#life = new Life(); } #life; #pages; #talentSelected = new Set(); #totalMax=20; #isEnd = false; #selectedExtendTalent = null; #hintTimeout; async initial() { this.initPages(); this.switch('loading'); await this.#life.initial(); this.switch('index'); window.onerror = (event, source, lineno, colno, error) => { this.hint(`[ERROR] at (${source}:${lineno}:${colno})\n\n${error?.stack||error||'unknow Error'}`, 'error'); } } initPages() { // Loading const loadingPage = $(`
人生重开模拟器
加载中...
`); // Index const indexPage = $(`
已重开1次
人生重开模拟器
这垃圾人生一秒也不想呆了
`); // Init theme this.setTheme(localStorage.getItem('theme')) indexPage .find('#restart') .click(()=>this.switch('talent')); indexPage .find('#rank') .click(()=>this.hint('别卷了!没有排行榜')); indexPage .find("#themeToggleBtn") .click(() => { if(localStorage.getItem('theme') == 'light') { localStorage.setItem('theme', 'dark'); } else { localStorage.setItem('theme', 'light'); } this.setTheme(localStorage.getItem('theme')) }); // Talent const talentPage = $(`
天赋抽卡
`); const createTalent = ({ grade, name, description }) => { return $(`
  • ${name}(${description})
  • `) }; talentPage .find('#random') .click(()=>{ talentPage.find('#random').hide(); const ul = talentPage.find('#talents'); this.#life.talentRandom() .forEach(talent=>{ const li = createTalent(talent); ul.append(li); li.click(()=>{ if(li.hasClass('selected')) { li.removeClass('selected') this.#talentSelected.delete(talent); } else { if(this.#talentSelected.size==3) { this.hint('只能选3个天赋'); return; } const exclusive = this.#life.exclusive( Array.from(this.#talentSelected).map(({id})=>id), talent.id ); if(exclusive != null) { for(const { name, id } of this.#talentSelected) { if(id == exclusive) { this.hint(`与已选择的天赋【${name}】冲突`); return; } } return; } li.addClass('selected'); this.#talentSelected.add(talent); } }); }); }); talentPage .find('#next') .click(()=>{ if(this.#talentSelected.size!=3) { this.hint('请选择3个天赋'); return; } this.#totalMax = 20 + this.#life.getTalentAllocationAddition(Array.from(this.#talentSelected).map(({id})=>id)); this.switch('property'); }) // Property const propertyPage = $(`
    调整初始属性
    可用属性点:0
    `); const groups = {}; const total = ()=>{ let t = 0; for(const type in groups) t += groups[type].get(); return t; } const freshTotal = ()=>{ propertyPage.find('#total').text(`可用属性点:${this.#totalMax - total()}`); } const getBtnGroups = (name, min, max)=>{ const group = $(`
  • ${name}      
  • `); const btnSub = $(``); const inputBox = $(``); const btnAdd = $(``); group.append(btnSub); group.append(inputBox); group.append(btnAdd); const limit = v=>{ v = Number(v)||0; v = Math.round(v); return v < min ? min : ( v > max ? max : v ) } const get = ()=>Number(inputBox.val()); const set = v=>{ inputBox.val(limit(v)); freshTotal(); } btnAdd.click(()=>{ if(total() >= this.#totalMax) { this.hint('没有可分配的点数了'); return; } set(get()+1); }); btnSub.click(()=>set(get()-1)); inputBox.on('input', ()=>{ const t = total(); let val = get(); if(t > this.#totalMax) { val -= t - this.#totalMax; } val = limit(val); if(val != inputBox.val()) { set(val); } freshTotal(); }); return {group, get, set}; } groups.CHR = getBtnGroups("颜值", 0, 10); // 颜值 charm CHR groups.INT = getBtnGroups("智力", 0, 10); // 智力 intelligence INT groups.STR = getBtnGroups("体质", 0, 10); // 体质 strength STR groups.MNY = getBtnGroups("家境", 0, 10); // 家境 money MNY const ul = propertyPage.find('#propertyAllocation'); for(const type in groups) { ul.append(groups[type].group); } propertyPage .find('#random') .click(()=>{ let t = this.#totalMax; const arr = [10, 10, 10, 10]; while(t>0) { const sub = Math.round(Math.random() * (Math.min(t, 10) - 1)) + 1; while(true) { const select = Math.floor(Math.random() * 4) % 4; if(arr[select] - sub <0) continue; arr[select] -= sub; t -= sub; break; } } groups.CHR.set(10 - arr[0]); groups.INT.set(10 - arr[1]); groups.STR.set(10 - arr[2]); groups.MNY.set(10 - arr[3]); }); propertyPage .find('#start') .click(()=>{ if(total() < this.#totalMax) { this.hint(`你还有${this.#totalMax-total()}属性点没有分配完`); return; } else if (total() > this.#totalMax) { this.hint(`你多使用了${total() - this.#totalMax}属性点`); return; } this.#life.restart({ CHR: groups.CHR.get(), INT: groups.INT.get(), STR: groups.STR.get(), MNY: groups.MNY.get(), SPR: 5, TLT: Array.from(this.#talentSelected).map(({id})=>id), }); this.switch('trajectory'); this.#pages.trajectory.born(); $(document).keydown(function(event){ if(event.which == 32 || event.which == 13){ $('#lifeTrajectory').click(); } }) }); // Trajectory const trajectoryPage = $(`
    `); trajectoryPage .find('#lifeTrajectory') .click(()=>{ if(this.#isEnd) return; const trajectory = this.#life.next(); const { age, content, isEnd } = trajectory; const li = $(`
  • ${age}岁:${ content.map( ({type, description, grade, name, postEvent}) => { switch(type) { case 'TLT': return `天赋【${name}】发动:${description}`; case 'EVT': return description + (postEvent?`
    ${postEvent}`:''); } } ).join('
    ') }
  • `); li.appendTo('#lifeTrajectory'); $("#lifeTrajectory").scrollTop($("#lifeTrajectory")[0].scrollHeight); if(isEnd) { $(document).keydown(function(event){}) this.#isEnd = true; trajectoryPage.find('#summary').show(); } }); trajectoryPage .find('#summary') .click(()=>{ this.switch('summary'); }) // Summary const summaryPage = $(`
    人生总结
    天赋,你可以选一个,下辈子还能抽到
    `); summaryPage .find('#again') .click(()=>{ this.times ++; this.#life.talentExtend(this.#selectedExtendTalent); this.#selectedExtendTalent = null; this.#talentSelected.clear(); this.#totalMax = 20; this.#isEnd = false; this.switch('index'); }); this.#pages = { loading: { page: loadingPage, clear: ()=>{}, }, index: { page: indexPage, btnRank: indexPage.find('#rank'), btnRestart: indexPage.find('#restart'), hint: indexPage.find('.hint'), cnt: indexPage.find('#cnt'), clear: ()=>{ indexPage.find('.hint').hide(); const times = this.times; const btnRank = indexPage.find('#rank'); const cnt = indexPage.find('#cnt'); if(times > 0) { btnRank.show(); cnt.show(); cnt.text(`已重开${times}次`); return; } btnRank.hide(); cnt.hide(); }, }, talent: { page: talentPage, clear: ()=>{ talentPage.find('ul.selectlist').empty(); talentPage.find('#random').show(); this.#totalMax = 20; }, }, property: { page: propertyPage, clear: ()=>{ freshTotal(); }, }, trajectory: { page: trajectoryPage, clear: ()=>{ trajectoryPage.find('#lifeTrajectory').empty(); trajectoryPage.find('#summary').hide(); this.#isEnd = false; }, born: ()=>{ trajectoryPage.find('#lifeTrajectory').trigger("click"); } }, summary: { page: summaryPage, clear: ()=>{ const judge = summaryPage.find('#judge'); const talents = summaryPage.find('#talents'); judge.empty(); talents.empty(); this.#talentSelected.forEach(talent=>{ const li = createTalent(talent); talents.append(li); li.click(()=>{ if(li.hasClass('selected')) { this.#selectedExtendTalent = null; li.removeClass('selected'); } else if(this.#selectedExtendTalent != null) { this.hint('只能继承一个天赋'); return; } else { this.#selectedExtendTalent = talent.id; li.addClass('selected'); } }); }); const records = this.#life.getRecord(); const s = (type, func)=>{ const value = func(records.map(({[type]:v})=>v)); const { judge, grade } = summary(type, value); return { judge, grade, value }; }; console.table(records); console.debug(records); judge.append([ (()=>{ const { judge, grade, value } = s('CHR', max); return `
  • 颜值:${value} ${judge}
  • ` })(), (()=>{ const { judge, grade, value } = s('INT', max); return `
  • 智力:${value} ${judge}
  • ` })(), (()=>{ const { judge, grade, value } = s('STR', max); return `
  • 体质:${value} ${judge}
  • ` })(), (()=>{ const { judge, grade, value } = s('MNY', max); return `
  • 家境:${value} ${judge}
  • ` })(), (()=>{ const { judge, grade, value } = s('SPR', max); return `
  • 快乐:${value} ${judge}
  • ` })(), (()=>{ const { judge, grade, value } = s('AGE', max); return `
  • 享年:${value} ${judge}
  • ` })(), (()=>{ 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 `
  • 总评:${value} ${judge}
  • ` })(), ].join('')); } } } } switch(page) { const p = this.#pages[page]; if(!p) return; $('#main').detach(); p.clear(); p.page.appendTo('body'); } hint(message, type='info') { if(this.#hintTimeout) { clearTimeout(this.#hintTimeout); this.#hintTimeout = null; } hideBanners(); requestAnimationFrame(() => { const banner = $(`.banner.${type}`); banner.addClass('visible'); banner.find('.banner-message').text(message); if(type != 'error') { this.#hintTimeout = setTimeout(hideBanners, 3000); } }); } setTheme(theme) { const themeLink = $(document).find('#themeLink'); if(theme == 'light') { themeLink.attr('href', 'light.css'); } else { themeLink.attr('href', 'dark.css'); } } get times() {return JSON.parse(localStorage.times||'0') || 0;} set times(v) {localStorage.times = JSON.stringify(parseInt(v) || 0)}; } export default App;