ReMode').value : modeSel; var r = G.reincarnate(forms[sel].id, mode); if (r.end) { modal('归墟', '

' + esc(r.txt) + '

这一局到此为止。世界会继续转,只是里面没有你了。

', [{ label: '重开一局', cls: 'btn-gold', act: function () { backToStart(); } }]); return; } var html2 = '

' + esc(r.txt) + '

' + '

新的名字:' + esc(r.newName) + ' 形态:' + esc(r.form.name) + ' 方式:' + esc({ suhui: '宿慧', curse: '诅咒', karma: '因果继承', random: '随机新生' }[mode]) + '

' + (r.inherited.length ? '

继承的伏笔(权重 30%,优先级已提升):
' + r.inherited.map(function (k) { return '· ' + esc(k.text) + '(' + esc(k.level) + ')'; }).join('
') + '

' : '

没有继承任何伏笔。

') + (r.crossLinks.length ? '

跨档因果:
' + r.crossLinks.map(function (c) { return '· ' + esc(c.txt); }).join('
') + '

' : '') + '

世界简报:' + esc(r.brief) + '

' + '

你不在的这些年,世界照常运转。有人老了,有人死了,有些约定期限到了。

'; modal('转世·' + r.form.name, html2, [{ label: '继续这一世', cls: 'btn-gold' }]); /* 叙事插入 */ var rnd = el('div', 'round'); rnd.appendChild(headRow('转世', '第 ' + G.turn + ' 回合')); rnd.appendChild(el('div', 'sysbox box-death', '

【死亡转化·' + esc(r.form.name) + '】' + esc(r.txt) + '

' + '

新名:' + esc(r.newName) + ' | 继承伏笔 ' + r.inherited.length + ' 条 | 跨档因果 ' + r.crossLinks.length + ' 条

')); $('#storyWrap').appendChild(rnd); renderAll(); renderChoices(G.makeOptions()); autoSave(); } }]); setTimeout(function () { var list = $('#dfList'); if (!list) return; list.querySelectorAll('.death-form').forEach(function (d) { d.addEventListener('click', function () { list.querySelectorAll('.death-form').forEach(function (x) { x.classList.remove('sel'); }); d.classList.add('sel'); sel = parseInt(d.getAttribute('data-i'), 10); }); }); }, 0); } /* ============================================================ SECTION: montage 岁月如梭 ============================================================ */ function doMontage() { if (G.over) { toast('你已经死了', 'err'); return; } var html = '

时间是最公平的天道法则——你闭关百年,外界不会为你停止转动。

' + '

触发后将强制结算:① 全部存活人物的年龄、境界、势力地位、关系演变与生死判定 ② 大事件日历强制推进 ③ 全部未解伏笔的「剩余时间」到期检查 ④ 物价更新与世界简报。禁止「主角出关,外界时间停滞」。

' + '
' + '
'; modal('岁月如梭', html, [{ label: '取消', cls: 'btn-ghost' }, { label: '让时间走', cls: 'btn-gold', act: function () { var y = parseInt($('#selYears').value, 10); var during = $('#selDuring').value; var pc = G.pc; var before = { age: pc.age, realm: pc.realmIdx, qi: pc.qi }; /* 期间收益 */ var gainMult = { '闭关修炼': 1.0, '长途赶路': 0.3, '养伤': 0.2, '经营坊市': 0.4, '打磨百艺': 0.5, '陪伴故人': 0.25 }[during] || 0.5; var qiGain = Math.round(6 * pc.cultMult * (1 + (pc.six['灵性'] - 3) * 0.06) * (pc.worldQi || 1) * y * 8 * gainMult); pc.qi += qiGain; if (during === '养伤') { pc.hp = pc.hpMax; D.INJURY_TYPES.forEach(function (t) { if (pc.injury[t] > 0 && t !== '道基' && t !== '因果') pc.injury[t] = Math.max(0, pc.injury[t] - 1); }); } if (during === '经营坊市') { var m = Math.round(y * (300 + Math.random() * 900)); pc.money += m; } if (during === '打磨百艺') { var aid = Object.keys(pc.arts)[0] || '炼丹术'; if (!pc.arts[aid]) pc.arts[aid] = { bp: 0, level: 0 }; G.addArtBp(aid, y * 6); } if (during === '陪伴故人') { G.npcs.filter(function (n) { return n.alive && n.met; }).slice(0, 3).forEach(function (n) { G.npcAttitude(n, '感恩', 12, '你陪了他一段时间'); n.bond = Math.min(pc.bondCap, (n.bond || 0) + 1); pc.bonds[n.id] = n.bond; }); pc.pollution = Math.max(0, pc.pollution - 1); pc.costLevel = Math.max(0, pc.costLevel - 1); } if (during === '闭关修炼') G.addBp(pc.daoBias ? '无' : '无', y * 1.2, '长期闭关'); /* 强制结算 */ var logs = G.passYears(y, during); var settle = G._lastSettle || { npcChanges: [], deaths: [], foreshadow: [], brief: '' }; /* 突破 */ var br = null; if (pc.qi >= pc.qiNeed) br = G.tryBreakthrough(); /* 寿元耗尽 */ if (pc.age >= pc.lifeMax) { G.die('寿元耗尽(' + during + '期间)'); } var txt = N.montage(G, y, { npcChanges: settle.npcChanges || [], deaths: settle.deaths || [], foreshadow: logs.filter(function (l) { return l.indexOf('伏笔') >= 0 || l.indexOf('物价') >= 0; }), brief: settle.brief || G.worldBrief() }); curRound++; var rnd = el('div', 'round'); rnd.appendChild(headRow('岁月如梭', during + '·' + y + ' 年')); rnd.appendChild(el('div', 'story', txt)); var sum = el('div', 'sysbox'); sum.innerHTML = '

【强制结算】

' + '' + '' + '' + '' + (br ? '' : '') + '' + '' + '
时间' + before.age + ' 岁 → ' + pc.age + ' 岁(+' + y + ' 年)
道蕴积累+' + n2s(qiGain) + '(' + during + '效率 ×' + gainMult + ')
境界' + esc(D.REALMS[before.realm].name) + ' → ' + esc(D.REALMS[pc.realmIdx].name) + '
突破' + (br.ok ? '成功' : '失败') + ' ' + esc(br.txt) + '
人物结算' + (settle.npcChanges || []).length + ' 项变化,' + (settle.deaths || []).length + ' 位故去
回合推进+' + y + ' 回合 → 第 ' + G.turn + ' 回合
'; rnd.appendChild(sum); if (logs.length) rnd.appendChild(el('div', 'sysbox', '

【期间大事】

' + logs.map(function (l) { return '

· ' + esc(l) + '

'; }).join(''))); /* 期间的大事件 → 世界级叙事 */ (settle.bigEvents || []).forEach(function (e) { rnd.appendChild(el('div', 'sysbox box-world', N.worldNarrative(G, e))); }); /* 死亡叙事不可跳过 */ (settle.deaths || []).forEach(function (d) { rnd.appendChild(el('div', 'sysbox box-death', '

' + esc(d) + '

')); }); /* 期间风闻(禁止闭关期间外界完全无消息) */ if (y >= 3) { var rm = N.makeRumor(G); G.rumors.unshift(rm); rnd.appendChild(el('div', 'sysbox', '

期间有人来访/传讯,带来一条消息(可信度 ' + rm.pct + '%,来源' + esc(rm.source) + '):' + esc(rm.text) + '

')); } rnd.appendChild(el('div', 'story', '

「' + esc(N.golden({ goldenCache: G.goldenCache, rng_i: G.turn * 7 + 3 })) + '」

')); $('#storyWrap').appendChild(rnd); /* 大劫阶段推进 + 大事件:从统一队列领取 */ var st = G.takeStages(); st.forEach(function (s) { $('#storyWrap').lastChild.appendChild(el('div', 'sysbox box-stage', '

【大劫推进·' + esc(s.name) + '】

' + esc(s.desc) + '

')); }); var be = G.takeBigEvents(); be.forEach(function (e) { $('#storyWrap').lastChild.appendChild(el('div', 'sysbox box-world', N.worldNarrative(G, e))); }); renderAll(); if (G.over) { renderChoices([]); showDeath(D.DEATH_FORMS); } else renderChoices(G.makeOptions()); scrollStory(); autoSave(); } }]); } /* ============================================================ SECTION: menu 天道菜单 ============================================================ */ function showMenu() { var pc = G.pc; var html = '

四大铁律

' + '

1. 绝对不妥协:世界运转遵循严密逻辑,不因你的意愿改变物理法则、战力体系或因果律。拒绝机械降神与强行圆满。
' + '2. 绝对不遗忘:所有已发生事件、已建立因果、已死亡人物、已消耗资源,永久记录并影响后续推演。
' + '3. 绝对不套路:严禁模板化叙事、脸谱化人物、套路化奇遇。所有情节基于当前世界状态与你的行为涌现。
' + '4. 绝对不撤销:已发生之因果不可被任何方式(读档、道具、法术、祈求)撤销。因果只能被转化、被承受,或被更高级别的因果覆盖。

' + '

游玩指南

' + '

· 善用因果网追踪,注意伏笔优先级(天道级 > 因果级 > 个人级 > 日常级)
' + '· 注意世界 TICK 事件——你不在场时世界照样在转
' + '· 利用风险收益矩阵决策,注意风闻真假概率
' + '· 每十回合保存存档码,每五十回合关注大劫阶段
' + '· 善用修仙百艺降低消耗,珍惜道蕴资源
' + '· 关注代价状态机递进,避免走到「临界」进而「转化」
' + '· 接受因果不可撤销,享受死亡与转世

' + '

操作

'; modal('菜单 · 规则与存档', html, [ { label: '叙事引擎(AI)', cls: 'btn-blue', close: false, act: function () { closeModal(); setTimeout(openLLMSettings, 30); } }, { label: '切换明暗', cls: 'btn-ghost', close: false, act: function () { toggleTheme(); } }, { label: '游玩说明', cls: 'btn-ghost', close: false, act: function () { closeModal(); setTimeout(openHelp, 30); } },{ label: '关闭', cls: 'btn-ghost' }, { label: '导出存档码到文件', cls: 'btn-blue', act: function () { var r = G.makeSaveCode(); if (!r.code) { toast('导出失败', 'err'); return; } var blob = new Blob([r.code], { type: 'text/plain;charset=utf-8' }); var a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = '大道无界存档_' + pc.name + '_第' + G.turn + '回合.txt'; document.body.appendChild(a); a.click(); setTimeout(function () { URL.revokeObjectURL(a.href); document.body.removeChild(a); }, 800); toast('存档码已导出为文件', 'ok'); } }, { label: '存入新槽位', cls: 'btn-blue', act: function () { saveToSlot(); } }, { label: '重开一局', cls: 'btn-gold', act: function () { modal('重开一局', '

当前进度不会丢失(已自动存档)。确定回到启动页开始新的一局吗?

', [{ label: '取消', cls: 'btn-ghost' }, { label: '重开', cls: 'btn-gold', act: backToStart }]); } } ]); } /* ---------- 叙事引擎设置 ---------- */ function aiFormVal(id) { var e = document.getElementById(id); return e ? e.value : ''; } function aiFormChecked(id) { var e = document.getElementById(id); return !!(e && e.checked); } function aiReadForm() { return { enabled: aiFormChecked('aiEnabled'), mode: aiFormVal('aiMode') || 'direct', base: aiFormVal('aiBase').trim(), key: aiFormVal('aiKey').trim(), proxy: aiFormVal('aiProxy').trim(), proxyToken: aiFormVal('aiProxyToken').trim(), model: aiFormVal('aiModel').trim() || 'deepseek-chat', freq: aiFormVal('aiFreq') || 'major', temperature: Math.max(0, Math.min(2, parseFloat(aiFormVal('aiTemp')) || 0.95)) }; } function aiSyncModeBoxes() { var m = aiFormVal('aiMode'); var d = document.getElementById('aiDirectBox'), p = document.getElementById('aiProxyBox'); if (d) d.style.display = (m === 'direct') ? '' : 'none'; if (p) p.style.display = (m === 'proxy') ? '' : 'none'; } function openLLMSettings() { if (!window.LLM) { toast('叙事外接层未加载', 'err'); return; } var c = LLM.cfg(); var html = '
' + '

LLM 只负责把本地引擎已经算定的结果写成叙事,不参与任何数值判定;失败会自动回退本地推演。

' + '' + '' + '
' + '' + '' + '
' + '
' + '' + '' + '

代理方式下密钥不进浏览器。本地可用 node tools/serve.js,线上可用 Cloudflare Worker。

' + '
' + '' + '' + '' + '

直连方式下密钥只存在本机 localStorage,任何拿到这台机器的人都能读到;共用电脑请用代理方式。

' + '

' + '
'; modal('叙事引擎 · LLM', html, [ { label: '测试连接', cls: 'btn-blue', close: false, act: async function () { var msg = document.getElementById('aiTestMsg'); LLM.save(aiReadForm()); if (msg) msg.textContent = '连接中…'; var r = await LLM.test(); if (msg) msg.textContent = r.ok ? ('连接成功,模型回复:' + String(r.text).slice(0, 30)) : ('失败:' + (r.error || '未知错误')); toast(r.ok ? '叙事引擎连接成功' : ('连接失败:' + (r.error || '')), r.ok ? 'ok' : 'err'); } }, { label: '保存', cls: 'btn-gold', close: false, act: function () { var v = aiReadForm(); if (v.enabled && v.mode === 'direct' && (!v.base || !v.key)) { toast('直连方式需要 API 地址与 Key', 'err'); return; } if (v.enabled && v.mode === 'proxy' && !v.proxy) { toast('代理方式需要代理地址', 'err'); return; } LLM.save(v); closeModal(); toast('已保存,下一回合生效', 'ok'); if (G) renderTop(); } }, { label: '关闭', cls: 'btn-ghost' } ]); setTimeout(function () { var sel = document.getElementById('aiMode'); if (sel) sel.addEventListener('change', aiSyncModeBoxes); aiSyncModeBoxes(); }, 0); } /* ---------- 新手教程 / 游玩说明 ---------- */ var TUT_STEPS = [ { t: '这是什么游戏', b: '本地推演的修仙沙盒:没有固定剧情,也没有标准答案。你选什么,世界就按它自己的逻辑回什么。唯一不可逆的是结果——死了不能读档复活。' }, { t: '开局先读第一章', b: '每局开头是一章小说。顶部三行告诉你「你是谁、你在哪、你要做什么」,正文会点出眼前最要紧的那件事。人物道碑默认折叠在下面,想核对数值再展开。' }, { t: '每回合怎么玩', b: '读一段叙事,下面给出 4 条行动 + 1 条自由输入。每条都标了风险、收益、代价。想同时做几件事,在「组合」框里输入编号(比如 13)再点并行执行。' }, { t: '界面地图', b: '上:回合 / 大劫 / 气血 / 灵石。左:人物道碑(手机上点底部「道碑」)。右:风闻、因果、人物、世界动态、天地志、坊市、天道点、存档(手机上点「更多」)。' }, { t: '「此刻」栏', b: '抉择区上方一直显示:你在哪、你的长期目的、身上多少灵石,以及最要紧的那件事还剩几个回合到期。拿不准要干嘛时,先看这一栏。' }, { t: '代价与死亡', b: '精力、道伤、道心污染、天道监察、寿元都会累积,不是摆设。气血归零或寿元耗尽就是死;死后只能选一种转化形态,不能读档复活。' }, { t: '想用 AI 写文', b: '右上「天道」→「叙事引擎(AI)」。不配也能玩,AI 只影响文笔,不影响任何判定。' } ]; function openTutorial(startAt) { var i = startAt || 0; function draw() { var s = TUT_STEPS[i]; var body = '
新手教程 · 第 ' + (i + 1) + ' / ' + TUT_STEPS.length + ' 步
' + '

' + esc(s.t) + '

' + esc(s.b) + '

'; var foot = []; if (i > 0) foot.push({ label: '上一步', cls: 'btn-ghost', close: false, act: function () { i--; draw(); } }); else foot.push({ label: '关闭', cls: 'btn-ghost' }); if (i < TUT_STEPS.length - 1) foot.push({ label: '下一步', cls: 'btn-blue', close: false, act: function () { i++; draw(); } }); else foot.push({ label: '开始修仙', cls: 'btn-gold' }); modal('新手教程', body, foot); } draw(); } function openHelp() { var html = '
' + '

一句话:你做什么,天道就按它的逻辑回什么;没有正确答案,只有后果。

' + '

一、一回合会发生什么

' + '

1)你读一段叙事;2)从下面的行动里选一个(或自己写);3)本地引擎判定结果、结算因果与世界变化;' + '4)世界在你不在场时也照常推进(世界 TICK);5)回到第 1 步。

' + '

每十回合会推送一条「大事件预告」并更新物价;每五十回合推进一次大劫阶段。

' + '

二、界面位置

' + '

顶部:回合、大劫阶段、气血、灵石,以及右侧的岁月如梭 / 存档 / 天道。

' + '

左侧(手机:底部「道碑」):人物道碑——境界、寿元、六司、道途、道伤、生平。

' + '

右侧(手机:底部「更多」):风闻(真假待辨)、因果、天道点、结算、人物、世界动态、天地志、百艺道途、坊市、存档。

' + '

抉择区上方:「此刻」栏——你在哪、目的、灵石、最要紧的事。

' + '

三、关键数值

' + '

气血:归零即死。精力:每回合消耗,低于 15 不能行动,靠静坐恢复。

' + '

道蕴:修炼积累,突破时消耗。灵石:通用货币,交易与远行都要用。

' + '

道心污染:五阶,看到不该看的、用禁忌技艺都会涨;高了会扭曲判定。

' + '

天道监察 L0–L5:触碰禁忌会升级,L4 以上有天道化身。

' + '

道伤:肉身 / 神魂 / 因果 / 道基四类五级,直接影响战力与突破。

' + '

寿元:年龄到上限就死,闭关与岁月如梭都会真实变老。

' + '

天道点:用道伤、污染、寿元、名声换;可在「天道点」面板抵消天劫、降监察、洗因果、续命。

' + '

声誉:影响物价与 NPC 初始态度。

' + '

四、四种开档

' + '

全随机:最快,全部交给天道。半随机:先选身份类型,三选一。

' + '

关键词:给 1–3 个词,天道在因果网里找锚点。自定义:自己写人设,需通过四维校验。

' + '

五、怎么变强

' + '

闭关修炼涨修为与道蕴;打磨百艺(炼丹、炼器、布阵、符箓…)换资源;行善行恶都会塑道途,' + '道途到第三境会凝出道号,写进万古道碑。越阶挑战要有代价支撑,硬来会触发天道修正。

' + '

六、死亡与转世

' + '

气血归零、寿元耗尽都会死。死后选择转化形态(转世 / 化鬼 / 成傀 / 入道 / 归墟),' + '部分因果、记忆碎片或道伤可以带进下一世,但要付出代价。死亡不可撤销。

' + '

七、存档

' + '

每回合自动存档。「存档」面板可导出/导入存档码;「岁月如梭」可以主动跳过一段时间,' + '但外界会真实变老、势力会洗牌、伏笔会到期。

' + '

八、常见问题

' + '

为什么总是失败?选项标了风险,高风险不一定该死,但需要战力、因果或环境支撑。

' + '

为什么选项只有四五条?其余路径靠「自由输入」——直接写你想做的事。

' + '

找不到某条因果了?去「因果」面板看状态,或「天道点」面板用代价换线索。

' + '

AI 叙事怎么开?右上「天道」→「叙事引擎(AI)」,按提示填地址与密钥。

' + '
'; modal('游玩说明', html, [{ label: '知道了', cls: 'btn-gold' }]); } function bindHelpButtons() { var t = document.getElementById('btnTutorial'); if (t) t.addEventListener('click', function () { openTutorial(0); }); var h = document.getElementById('btnHelp'); if (h) h.addEventListener('click', function () { openHelp(); }); } /* ---------- 明暗主题 ---------- */ var THEME_KEY = 'ddwj_theme_v1'; function applyTheme(t) { document.documentElement.setAttribute('data-theme', t); try { localStorage.setItem(THEME_KEY, t); } catch (e) {} var b = document.getElementById('btnTheme'); if (b) { b.textContent = t === 'light' ? '亮' : '暗'; b.title = t === 'light' ? '切换为暗色' : '切换为亮色'; } var sb = document.getElementById('btnThemeStart'); if (sb) sb.textContent = t === 'light' ? '切到暗色' : '切到亮色'; } function toggleTheme() { applyTheme(document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light'); } (function initTheme() { var t = 'dark'; try { t = localStorage.getItem(THEME_KEY) || 'dark'; } catch (e) {} applyTheme(t); document.addEventListener('click', function (e) { var id = e.target && e.target.id; if (id === 'btnTheme' || id === 'btnThemeStart') toggleTheme(); }); })(); /* ---------- 数值与文案纠错:所有数量从数据实算 ---------- */ (function fixCounts() { var facts = document.getElementById('startFacts'); if (facts) facts.textContent = D.START_WORLDS.length + ' 初始世界 · ' + D.UPPER_REALMS.length + ' 上界 · 1 位面 · ' + D.SYSTEMS.length + ' 道途'; var stats = document.getElementById('startStats'); if (stats) { stats.innerHTML = '四大铁律:绝对不妥协 · 绝对不遗忘 · 绝对不套路 · 绝对不撤销
' + '初始世界 ' + D.START_WORLDS.length + ' 座 · 上界 ' + D.UPPER_REALMS.length + ' 座 · 位面 1 处 · 出身 ' + (D.ORIGINS.length - 1) + ' 种 · 灵根 ' + (D.LINGGEN.length - 1) + ' 类 · 天赋 ' + D.TALENTS.length + ' 项 · 命途缺陷 ' + D.FLAWS.length + ' 种 · 因果线 ' + D.KARMA_POOL.length + ' 条 · 世界状态 ' + D.WORLD_STATES.length + ' 项
' + '每局候选均由混沌种子动态抽取,可「换一批」;负面选择返还天道点,游戏期亦可以道伤、污染、寿元、名声换取天道点。
' + '全部推演在本机浏览器内完成,无需联网、无需接口,永不中断生成。'; } if (typeof BASE_STEPS !== 'undefined') { BASE_STEPS[0].lead = '本局的世界候选由混沌种子从 ' + D.START_WORLDS.length + ' 座初始世界中抽取 5 座,每次开档不同,可「换一批」。世界的法则、灵气与危险度决定开局叠加哪些世界状态。'; BASE_STEPS[2].lead = '本局出身候选从 ' + (D.ORIGINS.length - 1) + ' 种中抽 12 种,可换一批。出身带来初始六维、物品、百艺、声誉与因果线;负面出身返还天道点。'; BASE_STEPS[3].lead = '本局灵根候选从 ' + (D.LINGGEN.length - 1) + ' 类中抽 14 类,可换一批。神品灵根极贵且会带来额外注视;负面灵根(如九阴绝脉)返还天道点。'; BASE_STEPS[4].lead = '本局天赋候选从 ' + D.TALENTS.length + ' 项中抽 12 项正面天赋,可换一批。正面天赋消耗天道点。'; BASE_STEPS[5].lead = '本局缺陷候选从 ' + D.FLAWS.length + ' 种中抽 8 种,另有 6 项负面天赋,可换一批。每一项缺陷都会返还天道点,且会在游戏过程中周期性真实发作。'; } })(); bindHelpButtons(); function kv2(k, v) { return '
' + esc(k) + '' + esc(v == null ? '—' : v) + '
'; } function openIdentity() { if (!G || !G.opening) return; var id = G.opening.identity, pc = G.pc, sys = D.systemOf(pc); var rows = [ ['身份', id.status, D.explainIdentity('status', id.status)], ['出身', id.birth, D.explainIdentity('birth', id.birth)], ['标签', id.tag, D.explainIdentity('tag', id.tag)], ['处境', id.plight, D.explainIdentity('plight', id.plight)] ]; var html = '
' + rows.map(function (r) { return '
' + esc(r[0]) + '
' + '
' + esc(r[1]) + '

' + esc(r[2]) + '

'; }).join('') + '
道途
' + esc(sys.name + ' · ' + D.realmNameOf(pc, pc.realmIdx)) + '

' + esc(sys.desc) + '

' + '
执念
' + esc(pc.goal.name) + '

' + esc(pc.goal.desc) + '

' + '
'; modal('身份说明', html, [{ label: '知道了', cls: 'btn-gold' }]); } function openNpc(id) { var n = (G.npcs || []).filter(function (x) { return x.id === id; })[0]; if (!n) return; var atts = D.ATTITUDES.map(function (a) { return [a, n.att[a] || 0]; }).filter(function (x) { return x[1] >= 5; }); var top = atts.slice().sort(function (a, b) { return b[1] - a[1]; })[0]; var rel = !n.met ? '你们还没正式见过面。' : (top ? '他对你:' + top[0] + '(' + top[1] + ')。' : '他对你没什么明显的态度。'); var html = '
' + '
' + esc(n.fullName) + '' + esc(D.realmNameOf(n, n.realmIdx)) + '' + (n.isQiyun ? '气运之子' : '') + '
' + '

' + esc(rel) + (n.met ? ' 羁绊:' + esc(D.BONDS[n.bond || 0]) : '') + '

' + '
' + kv2('势力', n.factionName) + kv2('年龄', n.age + ' 岁 / 寿元 ' + Math.round(n.lifeMax || 0)) + kv2('性格', n.personality) + kv2('目标', n.goal) + kv2('战力', n.power) + kv2('背叛概率', Math.round((n.betrayalBase || 0) * 100) + '%') + '
' + (n.motiveRevealed ? '

隐藏动机:' + esc(n.hiddenMotive) + '

' : '') + '
对你的态度
' + (atts.length ? atts.map(function (a) { return '
' + esc(a[0]) + '' + a[1] + '
'; }).join('') : '

暂时没有明显态度。

') + ((n.memory || []).length ? '
他记得的事
' + n.memory.slice(0, 6).map(function (m) { return '

· 第 ' + m.turn + ' 回合【' + esc(m.level) + '】' + esc(m.summary) + '

'; }).join('') : '') + '
'; modal(n.fullName, html, [{ label: '关闭', cls: 'btn-ghost' }]); } function openCustomSystem() { var base = D.systemById((WZ && WZ.systemId) || 'qi'); var src = (WZ && WZ.customSystem) || { name: '自创体系', desc: '', upper: '', ladder: base.ladder.map(function (r) { return [r[0], r[1]]; }) }; var html = '

自创体系只改名称与叙事:第 N 境=原体系第 N 境,战力同档,不会额外变强。

' + '
' + '
' + src.ladder.map(function (r, i) { return '
'; }).join('') + '
' + '
'; modal('自创修炼体系', html, [ { label: '保存并选用', cls: 'btn-gold', close: false, act: function () { var name = (document.getElementById('csName').value || '').trim() || '自创体系'; var ladder = []; for (var i = 0; i < 11; i++) { var nm = (document.getElementById('csR' + i).value || '').trim() || ('第' + (i + 1) + '境'); ladder.push([nm, '自创体系第 ' + (i + 1) + ' 境(战力对齐气道·' + D.systemById('qi').ladder[i][0] + ')。']); } var desc = (document.getElementById('csDesc').value || '').trim() || '你自己写下的一条路。名字是你定的,规矩也是你定的。'; D.saveCustomSystem({ name: name, desc: desc, ladder: ladder, upper: name + '上界' }); WZ.customSystem = { name: name, desc: desc, ladder: ladder, upper: name + '上界' }; WZ.systemId = 'custom'; WZ.systemTouched = true; closeModal(); renderStep(); toast('已选用自创体系:' + name, 'ok'); } }, { label: '取消', cls: 'btn-ghost' } ]); } document.addEventListener('click', function (e) { var t = e.target && e.target.closest ? e.target.closest('[data-gloss]') : null; if (t) { e.preventDefault(); openIdentity(); } }); function backToStart() { $('#game').classList.remove('on'); $('#startScreen').style.display = 'flex'; G = null; } /* ============================================================ SECTION: render-all ============================================================ */ function renderAll() { if (!G || !G.pc) return; if (G.pc.systemId) D.__activeSystem = G.pc.systemId; renderLeft(); renderTop(); renderTabs(); renderTabBody(); renderMobNav(); } /* ============================================================ SECTION: bindings ============================================================ */ /* ---------- 启动页:四种开档方式 ---------- */ var startMode = 'fullrandom'; document.querySelectorAll('.mode-row').forEach(function (c) { c.addEventListener('click', function () { startMode = c.getAttribute('data-mode'); openWizard(startMode); }); }); function openWizard(mode) { WZ = newWizard(mode); ensureSets(); /* 全随机:一键生成全部配置(预算受控,保证可开档),直接进入预览确认 */ if (mode === 'fullrandom') { var rr = DYNAMIC.buildFullRandom(WZ.pool); WZ.world = rr.world || WZ.sets.worlds[Math.floor(WZ.pool.rng() * WZ.sets.worlds.length)]; WZ.systemId = (WZ.world && WZ.world.defaultSystem) || 'qi'; WZ.origin = rr.origin; WZ.linggen = rr.linggen; WZ.tianzi = rr.tianzi; WZ.talents = (rr.talents || []).slice(); WZ.flaws = (rr.flaws || []).slice(); WZ.six = rr.six; WZ.goal = D.GOALS[Math.floor(WZ.pool.rng() * D.GOALS.length)]; WZ.daohao = ''; /* 跳到预览步,玩家可直接确认或回退微调 */ WZ.step = buildSteps('fullrandom').length - 1; } $('#startScreen').style.display = 'none'; $('#wizard').classList.add('on'); renderStep(); } $('#btnFull').addEventListener('click', function () { openWizard('fullrandom'); }); var btnCustomEl = document.getElementById('btnCustom'); if (btnCustomEl) btnCustomEl.addEventListener('click', function () { openWizard(startMode); }); $('#btnLoad').addEventListener('click', function () { var saves = getSaves(); if (!saves.length) { modal('续前世因缘', '

当前浏览器还没有任何存档。

你也可以粘贴一段天道存档码来续玩——在创角页退出后,或开局后点击右侧「存档」标签页即可读取。

', [{ label: '知道了', cls: 'btn-gold' }]); return; } var html = saves.map(function (s, i) { return '
' + esc(s.name) + ' ' + esc(s.realm) + '
' + '
第 ' + s.turn + ' 回合 | 大劫 ' + esc(s.stage) + ' | ' + esc(s.world) + ' | ' + esc(s.brief) + '
' + '
' + esc(s.time) + (s.auto ? ' · 自动存档' : '') + '
'; }).join(''); modal('续前世因缘', html + '
', [{ label: '取消', cls: 'btn-ghost' }, { label: '读取', cls: 'btn-gold', act: function () { var paste = $('#pasteCode') ? $('#pasteCode').value.trim() : ''; var code = paste || (selSave != null && saves[selSave] ? saves[selSave].code : null); if (!code) { toast('请选择一个存档或粘贴存档码', 'err'); return; } var g2 = E.Game.loadFromCode(code); if (g2 && g2.error) { toast('读取失败:' + g2.error, 'err'); return; } if (!g2 || !g2.pc) { toast('存档损坏或格式不符', 'err'); return; } G = g2; curRound = 0; selSave = null; $('#startScreen').style.display = 'none'; $('#game').classList.add('on'); $('#storyWrap').innerHTML = ''; var rnd = el('div', 'round'); rnd.appendChild(headRow('续前世因缘', '第 ' + G.turn + ' 回合')); rnd.appendChild(el('div', 'sysbox box-break', '

【读档成功】' + esc(G.pc.name) + ',' + esc(D.REALMS[G.pc.realmIdx].name) + '。

' + '

' + esc(G.worldBrief()) + '

' + '

铁律·绝对不撤销:读档不能撤销已发生的因果。你回到的是这个时间点,而不是它之前。

')); $('#storyWrap').appendChild(rnd); renderAll(); renderChoices(G.makeOptions()); toast('读档成功', 'ok'); } }]); var selSave = null; setTimeout(function () { document.querySelectorAll('#mBody .death-form').forEach(function (d) { d.addEventListener('click', function () { document.querySelectorAll('#mBody .death-form').forEach(function (x) { x.classList.remove('sel'); }); d.classList.add('sel'); selSave = parseInt(d.getAttribute('data-i'), 10); }); }); }, 0); }); $('#btnMontage').addEventListener('click', doMontage); $('#btnSave').addEventListener('click', function () { saveToSlot(); curTab = 'save'; renderTabs(); renderTabBody(); }); $('#btnMenu').addEventListener('click', showMenu); /* ---------- 移动端底部导航(5 格:道碑 / 史书 / 风闻 / 因果 / 更多) ---------- */ var MOB_NAV = [ { k: 'left', label: '道碑' }, { k: 'story', label: '史书' }, { k: 'tab:rumor', label: '风闻' }, { k: 'tab:karma', label: '因果' }, { k: 'more', label: '更多' } ]; function highlightMob(k) { var row = $('#mnRow'); if (!row) return; row.querySelectorAll('button').forEach(function (x) { x.classList.toggle('on', x.getAttribute('data-nav') === k); }); } function renderMobNav() { var row = $('#mnRow'); if (!row || row.dataset.built === '1') return; row.dataset.built = '1'; MOB_NAV.forEach(function (it) { var b = el('button', it.k === 'story' ? 'on' : '', esc(it.label)); b.setAttribute('data-nav', it.k); row.appendChild(b); }); row.addEventListener('click', function (e) { var b = e.target.closest('button[data-nav]'); if (!b) return; var k = b.getAttribute('data-nav'); if (k === 'more') { openTabSheet(); return; } highlightMob(k); if (k.indexOf('tab:') === 0) { curTab = k.slice(4); $('#game').setAttribute('data-mob', 'right'); renderTabs(); renderTabBody(); } else { $('#game').setAttribute('data-mob', k); } window.scrollTo({ top: 0, behavior: 'smooth' }); }); } function openTabSheet() { var html = '
' + TABS.map(function (t) { var unread = t.id === 'rumor' && G ? G.rumors.filter(function (r) { return !r.read; }).length : 0; return ''; }).join('') + '
'; modal('全部面板', html, [{ label: '关闭', cls: 'btn-ghost' }]); setTimeout(function () { document.querySelectorAll('.tab-sheet-item').forEach(function (b) { b.addEventListener('click', function () { curTab = b.getAttribute('data-tab'); highlightMob(['rumor', 'karma'].indexOf(curTab) >= 0 ? 'tab:' + curTab : 'more'); $('#game').setAttribute('data-mob', 'right'); renderTabs(); renderTabBody(); closeModal(); window.scrollTo({ top: 0, behavior: 'smooth' }); }); }); }, 0); } /* ---------- 回到抉择:手机上史书很长,随时能跳回选项 ---------- */ (function () { var fab = el('button', '', '↓ 抉择'); fab.id = 'toChoices'; fab.addEventListener('click', function () { var c = $('#choiceWrap'); if (c) c.scrollIntoView({ behavior: 'smooth', block: 'start' }); }); document.body.appendChild(fab); var onScroll = function () { var inGame = $('#game') && $('#game').classList.contains('on'); var isStory = $('#game') && $('#game').getAttribute('data-mob') === 'story'; var cw = $('#choiceWrap'); var cwTop = cw ? cw.getBoundingClientRect().top : 99999; /* 抉择区还看不见时才提示,看见了就收起,避免挡住选项 */ var show = inGame && isStory && window.innerWidth <= 980 && cwTop > window.innerHeight - 140; fab.classList.toggle('on', !!show); }; window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); window.__ddwjScrollFab = onScroll; })(); /* 深链:?play=1 直接全随机开局(方便分享/快速进入) */ if (/[?&]play=1/.test(location.search)) { setTimeout(function () { try { openWizard('fullrandom'); startGame(); } catch (e) { /* 启动失败则停留在首页 */ } }, 80); } /* 快捷键:数字键选择选项 */ document.addEventListener('keydown', function (e) { if (!G || !$('#game').classList.contains('on')) return; if (e.target.tagName === 'TEXTAREA' || e.target.tagName === 'INPUT' || e.target.tagName === 'SELECT') return; var n = parseInt(e.key, 10); if (n >= 1 && n <= curOptions.length) { if (curOptions[n - 1].free) toggleFreeInput(); else doChoice(n - 1, null); } }); })();
Meoo By Meoo 秒悟