c.tianPoints -= it.cost; var res = { ok: true, item: it, txt: '' }; switch (it.id) { case 'trib': pc.tribSkip = (pc.tribSkip || 0) + 1; pc.tribMult *= 1.2; res.txt = '下一次突破不降天劫。但你欠天道的这一次,会在下一次连本带利收回来(天劫强度 +20%)。'; break; case 'monitor': { if (pc.monitor <= 0) { pc.tianPoints += it.cost; return { ok: false, msg: '你现在是 L0,没什么可降的。' }; } pc.monitor--; pc.monitorGrace = this.turn + 30; res.txt = '天道暂时不看你(→' + D.MONITOR[pc.monitor].lv + ')。三十回合内若再犯禁忌,直接跳两级——它记得你耍过它。'; break; } case 'wash': { var ks = this.karmas.filter(function (k) { return k.status === 'active' && k.strength > 3; }); if (!ks.length) { pc.tianPoints += it.cost; return { ok: false, msg: '没有需要压制的因果线。' }; } var k = ks.sort(function (a, b) { return b.strength - a.strength; })[0]; k.strength = 1; k.washed = true; res.txt = '【' + k.name + '】强度压到 1。它不会消失,只是暂时不疼——而你很清楚它会回来。'; break; } case 'chance': pc.forceSuccess = (pc.forceSuccess || 0) + 1; res.txt = '下一次掷骰强制成功。但这次机缘会有人来抢,且抢的人比你强。'; break; case 'life': pc.lifeMax += 20; res.txt = '寿元 +20 年。垫进来的是谁的时间,你不会知道,也不该去查。'; break; case 'heal': { var ts = D.INJURY_TYPES.filter(function (t) { return pc.injury[t] > 0; }); if (!ts.length) { pc.tianPoints += it.cost; return { ok: false, msg: '你身上没有道伤可清。' }; } var t2 = ts.sort(function (a, b) { return pc.injury[b] - pc.injury[a]; })[0]; pc.injury[t2]--; /* 代价转移 */ var others = D.INJURY_TYPES.filter(function (x) { return x !== t2; }); var to = others[Math.floor(Math.random() * others.length)]; pc.injury[to] = E.clamp((pc.injury[to] || 0) + 1, 0, 5); pc.combat = this.calcPower(pc); res.txt = t2 + '道伤降一级(→' + D.INJURY_LEVELS[pc.injury[t2]] + ')。降下来的那部分没有消失,它转移到了' + to + '(→' + D.INJURY_LEVELS[pc.injury[to]] + ')。'; break; } case 'clean': { if (pc.pollution <= 0) { pc.tianPoints += it.cost; return { ok: false, msg: '你的道心是干净的,没什么可净化。' }; } var before = pc.pollution; pc.pollution--; pc.cleanDebt = (pc.cleanDebt || 0) + 1; res.txt = '道心从「' + D.POLLUTION[before].name + '」退到「' + D.POLLUTION[pc.pollution].name + '」。被清掉的东西记着你,它会回来。'; break; } case 'reveal': { var hid = this.karmas.filter(function (k) { return !k.realRevealed && k.surface; }); if (!hid.length) { pc.tianPoints += it.cost; return { ok: false, msg: '没有被隐藏的因果线了。' }; } var hk = hid[Math.floor(Math.random() * hid.length)]; hk.realRevealed = true; hk.surface = null; res.txt = '【' + hk.name + '】的真相:' + (hk.desc || '它比你以为的更近,也更旧。') + ' 知道之后就回不去了。'; break; } case 'escape': pc.autoEscape = (pc.autoEscape || 0) + 1; res.txt = '下一次致命危机你会活下来。活下来的方式可能不好看。'; break; case 'dao': { var keys = Object.keys(pc.bp || {}); if (!keys.length) { pc.tianPoints += it.cost; return { ok: false, msg: '你还没有任何道途可以推。' }; } var top = keys.sort(function (a, b) { return pc.bp[b] - pc.bp[a]; })[0]; pc.bpStage[top] = Math.min(5, (pc.bpStage[top] || 0) + 1); pc.bpHollow = (pc.bpHollow || 0) + 1; res.txt = '【' + top + '】阶跃推到' + D.BP_STAGE_NAMES[pc.bpStage[top] - 1] + '。跳过的积累不会补回来——境界是虚的,你自己知道。'; break; } case 'ascend': pc.forcedAscend = true; res.txt = '你跳过了四项证道条件。天道认为这是欺诈。它会认账,因为它必须认账——但它会用别的方式找回平衡。'; break; case 'six': { var key = extra || '根骨'; var fr = this.forgeSix(key); if (!fr.ok) { pc.tianPoints += it.cost; return { ok: false, msg: fr.msg }; } res.txt = fr.msg; break; } } return res; }; /* ============================================================ SECTION: curses 命途缺陷周期性发作 ============================================================ */ Game.prototype.activeFlaws = function () { var pc = this.pc; pc.flaws = pc.flaws || []; var out = []; pc.flaws.forEach(function (f) { out.push(f); }); /* 出身自带缺陷 */ if (pc.origin && pc.origin.flaw) { var fd = D.FLAWS.filter(function (x) { return x.id === pc.origin.flaw; })[0]; if (fd && !out.some(function (x) { return x.id === fd.id; })) out.push(fd); } /* 天赋中的负面 */ (pc.talents || []).forEach(function (t) { if (t.cost < 0 && !out.some(function (x) { return x.id === t.id; })) { out.push({ id: t.id, name: t.name, desc: t.desc, fx: {} }); } }); return out; }; Game.prototype.curseTick = function () { var pc = this.pc, r = this.rng; var flaws = this.activeFlaws(); var out = []; flaws.forEach(function (f) { var fx = f.fx || {}; if (!fx.curse) return; var bank = D.CURSE_EVENTS[fx.curse]; if (!bank || !bank.length) return; /* 周期性发作概率 */ var rate = { blood: 0.16, countdown: 0.22, lonestar: 0.12, blind: 0.14, mute: 0.12, onearm: 0.1, amnesia: 0.13, wanted: 0.2, debt: 0.18, nemeses: 0.17, sickly: 0.16, impure: 0.1, ugly: 0.1, heartdemon: 0.2, karmahole: 0.15, jealous: 0.14, nameless: 0.08, slave: 0.16, medicine: 0.15, scapegoat: 0.16, nofire: 0.1, yinborn: 0.15, possessed: 0.18, daodebt: 0.2, luckdebt: 0.14, numb: 0.12, marked: 0.18, cracked: 0.16 }[fx.curse] || 0.1; /* 周期性强制发作 */ if (fx.curse === 'blood' && this.turn % 8 === 0) rate = 1; if (fx.curse === 'debt' && this.turn > 0 && this.turn % 20 === 0) rate = 1; if (fx.curse === 'daodebt' && this.turn % 50 === 0 && this.turn > 0) rate = 1; if (fx.curse === 'countdown' && this.turn % 20 === 0) rate = 1; if (r() >= rate) return; var txt = bank[Math.floor(r() * bank.length)]; var effects = []; switch (fx.curse) { case 'blood': pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.25)); pc.pollution = E.clamp(pc.pollution + (r() < 0.3 ? 1 : 0), 0, 4); effects.push('气血 -25%'); break; case 'countdown': pc.age += 1; effects.push('寿元 -1 年'); break; case 'lonestar': { var near = this.npcs.filter(function (n) { return n.alive && n.met && (n.bond || 0) >= 2; }); if (near.length) { var v = near[Math.floor(r() * near.length)]; this.npcDeathCheck(v, '孤星命格所致——不是你的错,但你在场'); effects.push(v.fullName + ' 出事了'); this.pendingDeathNote = this.deathNarrative(v); } break; } case 'wanted': { var d = this.dice(0.4, { attr: '气运' }); if (d.result === 'fail' || d.result === 'greatfail') { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.3)); pc.money = Math.max(0, pc.money * 0.7); effects.push('被截住,气血 -30%,灵石被搜走三成'); } else effects.push('你提前察觉了,绕开了'); break; } case 'debt': { var debt = (fx.debt || 3000) * (1 + Math.floor(this.turn / 20) * 0.2); if (pc.money >= debt) { pc.money -= debt; effects.push('被迫还了 ' + Math.round(debt) + ' 灵石'); } else { this.addInjury('肉身', Math.min(5, pc.injury['肉身'] + 1), '还不上债'); pc.reputation = E.clamp(pc.reputation - 8, -100, 100); effects.push('还不上,他们用了别的方式收'); } break; } case 'nemeses': { var alive = this.npcs.filter(function (n) { return n.alive; }); if (alive.length) { var foe = alive.sort(function (a, b) { return b.power - a.power; })[Math.floor(r() * Math.min(3, alive.length))]; this.npcAttitude(foe, '仇恨', 45, '宿敌'); foe.nemesis = true; effects.push(foe.fullName + ' 到了(战力 ' + foe.power + ',你 ' + pc.combat + ')'); this.pendingAmbush = foe; } break; } case 'sickly': pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.15)); effects.push('气血 -15%'); break; case 'heartdemon': { if (r() < 0.5) { pc.burstTurns = (pc.burstTurns || 0) + 2; effects.push('心魔接管,接下来两回合战力 ×2'); } else { pc.pollution = E.clamp(pc.pollution + 1, 0, 4); effects.push('污染 +1 阶'); } break; } case 'karmahole': { var nk = D.KARMA_POOL[Math.floor(r() * D.KARMA_POOL.length)]; this.karmas.push({ id: 'kh' + this.turn, name: nk.name, level: nk.level, power: Math.round(nk.power * 1.5), strength: Math.round(nk.power * 1.5), trigger: nk.trigger, endings: nk.endings, desc: nk.desc, realRevealed: true, status: 'active', createdTurn: this.turn, unbreakable: true }); effects.push('新增不可斩断因果:' + nk.name); break; } case 'jealous': { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.2)); this.addInjury('肉身', Math.min(5, pc.injury['肉身'] + 1), '无妄天劫'); effects.push('无妄之劫,气血 -20%,肉身道伤 +1'); break; } case 'slave': { var d2 = this.dice(0.45, { attr: '心性' }); if (d2.result === 'fail' || d2.result === 'greatfail') { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.35)); this.addInjury('神魂', Math.min(5, pc.injury['神魂'] + 1), '契约反噬'); effects.push('抗命失败,契约反噬'); } else effects.push('你抗住了这一次,但契约会再来'); break; } case 'medicine': { pc.money += Math.round(300 + r() * 900); pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.2)); effects.push('被人抽了血,换了一笔灵石'); break; } case 'possessed': { pc.possessedTurn = this.turn; var acts = ['他杀了一个人,用的是你的手', '他去见了某个你不认识的人,谈了很久', '他把你的东西送给了别人', '他把你藏起来的秘密说出去了']; effects.push(acts[Math.floor(r() * acts.length)]); pc.reputation = E.clamp(pc.reputation - 12, -100, 100); if (r() < 0.4) { var an = this.npcs.filter(function (n) { return n.alive; })[0]; if (an) { this.npcAttitude(an, '仇恨', 60, '残识接管期间做的事'); effects.push(an.fullName + ' 现在恨你,且理由充分'); } } break; } case 'daodebt': { var td = this.dice(0.4, { attr: '心性' }); if (td.result === 'fail' || td.result === 'greatfail') { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.4)); this.addInjury('道基', Math.min(5, pc.injury['道基'] + 1), '天道催收'); effects.push('催收失败,道基受损'); } else effects.push('你扛过了这次催收。本金没动。'); break; } case 'luckdebt': pc.money = Math.max(0, pc.money * 0.9); effects.push('又损失了一点东西,说不清是什么'); break; case 'numb': if (pc.hp < pc.hpMax * 0.3 && r() < 0.5) { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.15)); effects.push('你才发现伤口有多深'); } break; case 'amnesia': { if (r() < 0.35) { var p = this.npcs.filter(function (n) { return n.alive; })[Math.floor(r() * Math.max(1, this.npcs.filter(function (n) { return n.alive; }).length))]; if (p) { this.npcRemember(p, '过往', '他自称是你师父,而你完全不认识他', '关系待定', '因果级'); p.claimsPast = true; effects.push(p.fullName + ' 自称认识你'); this.pendingPast = p; } } break; } case 'blind': case 'mute': case 'onearm': case 'impure': case 'ugly': case 'nofire': case 'yinborn': case 'nameless': case 'scapegoat': effects.push('这个缺陷今天又拦了你一次'); if (r() < 0.3) { pc.energy = Math.max(0, pc.energy - 15); } break; case 'marked': { /* 被天道标记:监察缓慢累积,突破时天劫必至 */ if (r() < 0.4 && pc.monitor < 5) { var mm = this.raiseMonitor(pc.monitor + 1, '被天道标记'); if (mm.raised) effects.push('天道监察升至 ' + D.MONITOR[mm.to].lv + '(成功率 -' + Math.round(mm.to ? D.MONITOR[mm.to].pen * 100 : 0) + '%)'); } else effects.push('你被记了一笔。这一笔暂时没结算,但它记下了。'); break; } case 'cracked': { /* 道基残缺:道蕴从裂缝漏损,偶有异力渗出 */ var leak = Math.round(Math.min(pc.daoyun, 8 + r() * 20)); pc.daoyun = Math.max(0, pc.daoyun - leak); if (r() < 0.2) { pc.daoyun += leak * 2; effects.push('裂缝里渗出一点不属于你的力量,道蕴 +' + leak + '(净得)'); } else effects.push('道蕴从裂缝漏掉 ' + leak + ' 点'); break; } } out.push({ flaw: f.name, curse: fx.curse, txt: txt, effects: effects }); }, this); return out; }; /* ============================================================ SECTION: options-ext 扩展行动类别(极度自由) ============================================================ */ var _origMakeOptions = Game.prototype.makeOptions; Game.prototype.makeOptions = function (scene) { var opts = _origMakeOptions.call(this, scene); if (scene === 'opening') return opts; /* 防止同一类行动连续出现:玩家不该连着三回合被问"要不要建势力" */ if (this._lastAct && opts.length > 3) { var filtered = opts.filter(function (o) { return o.act !== this._lastAct || o.free; }, this); if (filtered.length >= 3) opts = filtered; } var r = this.rng, pc = this.pc; var free = opts.pop(); /* 摘出自由输入项,最后再放回 */ var R = function (risk) { return { '低': 'low', '中': 'mid', '高': 'high', '必死': 'dead', '未知': 'unk' }[risk] || 'mid'; }; var extra = []; /* 作恶 */ if (r() < 0.55) { var targets = ['一个落单的散修', '一队没有护卫的商队', '一座只剩老人孩子的村子', '一个受了重伤正在疗伤的人']; extra.push({ id: 'evil', text: '去做一件天道不喜欢的事:' + targets[Math.floor(r() * targets.length)] + ',把他们的东西拿过来', risk: '中', gain: ['资源', '修为'], cost: ['因果', '道心污染', '天道监察'], act: 'evil', riskCls: R('中'), tag: '支线行动', evil: true }); } /* 建立势力:需要冷却与一点本钱,不能每回合都来一次 */ if (r() < 0.5 && (!this._foundAt || this.turn - this._foundAt > 6)) { extra.push({ id: 'found', text: '开始建立属于自己的势力:招人、立规矩、占一处地盘,从此有人以你的话为准', risk: '中', gain: ['人脉', '资源', '道心'], cost: ['时间', '因果', '资源'], act: 'found', riskCls: R('中'), tag: '主线抉择', main: true }); } /* 躺平 */ if (r() < 0.45) { extra.push({ id: 'idle', text: '什么都不做:找个角落待着,看这一天过去,让世界自己转', risk: '低', gain: ['道心', '安全'], cost: ['时间', '寿元'], act: 'idle', riskCls: R('低'), tag: '支线行动' }); } /* 天道点交易:核心机制,始终可达(承受道伤/污染/寿元等本就不需要先有缺陷) */ if (r() < 0.4 || (pc.tianPoints || 0) > 0 || (this.activeFlaws && this.activeFlaws().length)) { extra.push({ id: 'tian', text: '与天道做一笔交易:用自己身上的一部分(道伤、污染、寿元、名声、羁绊、百艺)换天道点,再用天道点买抵消天劫、降监察、洗因果、续命', risk: '未知', gain: ['天道点'], cost: ['道伤', '道心污染', '寿元', '因果'], act: 'tian', riskCls: R('未知'), tag: '支线行动' }); } /* 极端:主动引发大事件 */ if (r() < 0.2) { extra.push({ id: 'provoke', text: '主动引爆一件大事:把那条你已经知道的大事件预告公开,让所有人提前入场', main: true, risk: '高', gain: ['情报', '人脉', '道心'], cost: ['因果', '道伤', '天道监察'], act: 'provoke', riskCls: R('高'), tag: '主线抉择' }); } /* 远行:换一块天地。灵石是路费,时间是税,因果是随行的行李 */ if (this.pc.plane === 'lower' && r() < 0.4 && D.START_WORLDS && D.START_WORLDS.length > 1) { var others = D.START_WORLDS.filter(function (w) { return w.id !== pc.world.id; }); var destW0 = others[Math.floor(r() * others.length)]; extra.push({ id: 'travel', text: '远行:离开' + pc.world.name + ',往' + destW0.name + '去(' + destW0.tag + ',灵气×' + destW0.qi + ')', risk: '中', gain: ['情报', '资源'], cost: ['时间', '灵石', '因果'], act: 'travel', dest: destW0.id, riskCls: R('中'), tag: '支线行动' }); } /* 飞升:此界已容不下你 */ var planeIsUpper = this.pc.plane && this.pc.plane.indexOf('upper:') === 0; if (this.pc.plane === 'lower' && this.pc.realmIdx >= 8) { extra.push({ id: 'ascend', text: '飞升:此界已容不下你,破开界壁去上界', main: true, risk: '高', gain: ['道心', '修为', '因果'], cost: ['道伤', '寿元', '因果'], act: 'ascend', riskCls: R('高'), tag: '主线抉择' }); } else if (planeIsUpper && this.pc.realmIdx >= 10) { extra.push({ id: 'ascend', text: '飞升:从上界再进一步,往太虚之上的位面去', main: true, risk: '必死', gain: ['道心', '因果'], cost: ['道伤', '寿元', '因果'], act: 'ascend', riskCls: 'dead', tag: '主线抉择' }); } /* 随机插入 1~2 个 */ extra.sort(function () { return r() - 0.5; }); var insert = extra.slice(0, 2); /* 保证总数不超过 5(含自由输入) */ var keep = opts.slice(0, Math.max(2, 4 - insert.length)); var out = keep.concat(insert); out.push(free); return out; }; /* ============================================================ SECTION: doaction-ext 扩展行为执行 ============================================================ */ var _origDoAction = Game.prototype.doAction; Game.prototype.doAction = function (opt, freeText) { var act = opt && opt.act; this._lastAct = act; if (act === 'found') this._foundAt = this.turn; if (['evil', 'found', 'idle', 'tian', 'provoke', 'travel', 'ascend'].indexOf(act) < 0) { var res0 = _origDoAction.call(this, opt, freeText); this._applyCurseTick(res0); return res0; } /* 扩展行为:先执行,再走通用回合流程 */ var pc = this.pc, r = this.rng; var parts = [], settle = { karma: [], npc: [], world: [], daoyun: 0, injury: [], bp: [], arts: [] }; var kind = 'social', mainTxt = '', costTxt = '', baideObj = null; if (act === 'evil') { kind = 'battle'; var d = this.dice(0.6, { attr: '气运' }); var victim = ['一个落单的散修', '一队商队', '一座村子', '一个伤者'][Math.floor(r() * 4)]; var got = 0; if (d.result === 'great' || d.result === 'ok') { got = Math.round((200 + r() * 1500) * (1 + this.stage * 0.15)); pc.money += got; mainTxt = '你动手了。' + victim + '没能阻止你——' + (d.result === 'great' ? '他们甚至没能看清你的脸。' : '他们看清了你的脸,这会比较麻烦。'); mainTxt += ' 你拿走了 ' + got + ' 灵石和一些别的东西。'; this.addBp('杀', d.result === 'great' ? 3.0 : 2.2, '作恶'); settle.bp.push('杀 行为 +' + (d.result === 'great' ? 3.0 : 2.2) + ' BP(重大抉择级)'); } else if (d.result === 'barely') { got = Math.round(80 + r() * 300); pc.money += got; pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.2)); mainTxt = '你做成了,但做得不干净。有人跑了,或者有人记住了你。你只拿到 ' + got + ' 灵石。'; this.addBp('杀', 1.8, '作恶'); } else { pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * (d.result === 'greatfail' ? 0.55 : 0.3))); this.addInjury('肉身', Math.min(5, pc.injury['肉身'] + 1), '作恶失手'); mainTxt = d.result === 'greatfail' ? '你失手了,而且失手得很彻底。' + victim + '里有一个人比你想的强得多。你现在在跑,跑的时候还在流血。' : '没做成。' + victim + '反抗了,反抗得比你预料的激烈。你退出来的时候少了点东西。'; settle.injury.push('肉身道伤 → ' + D.INJURY_LEVELS[pc.injury['肉身']]); } /* 必然代价(代价守恒) */ pc.pollution = E.clamp(pc.pollution + 1, 0, 4); pc.reputation = E.clamp(pc.reputation - (d.result === 'great' ? 10 : 18), -100, 100); var mk = this.raiseMonitor(Math.max(1, pc.monitor), '作恶'); if (mk.raised) parts.push({ cls: 'monitor', html: '
【天道监察 → ' + D.MONITOR[mk.to].lv + '】' + mk.txt + '
' }); var nk = D.KARMA_POOL.filter(function (k) { return ['血海深仇', '夺宝之恨', '未救之人', '一起做过坏事', '见证者'].indexOf(k.name) >= 0; }); var kk = nk[Math.floor(r() * nk.length)]; this.karmas.push({ id: 'ev' + this.turn, name: kk.name, level: kk.level, power: kk.power, strength: Math.max(3, Math.round(kk.power * 0.8)), trigger: '你抢了不该抢的', endings: kk.endings, desc: kk.desc, realRevealed: true, status: 'active', createdTurn: this.turn }); settle.karma.push('新增因果:' + kk.name + '(' + kk.level + ')'); settle.injury.push('道心污染 → ' + D.POLLUTION[pc.pollution].name); costTxt = this.addCost(2, '作恶'); settle.world.push('声誉 ' + pc.reputation + ' | 灵石 +' + got); baideObj = '手上还没干的血'; /* 口碑传播:恶名也是名 */ parts.push({ cls: 'sys', html: '【口碑网】这件事会传开。传开的速度取决于' + victim + '里有没有人活着走出去,以及活着的人认识多少人。
' }); pc.energy = Math.max(0, pc.energy - 35); } else if (act === 'found') { kind = 'social'; var followers = this.npcs.filter(function (n) { return n.alive && n.met && ((n.att['敬畏'] || 0) >= 30 || (n.att['感恩'] || 0) >= 30 || (n.att['利用'] || 0) >= 40); }); if (followers.length < 1) { mainTxt = '你想立起来一点东西,但没人跟你。不是他们看不起你,是他们各自都有自己要活的方式。招人这件事,比你想象的更需要本钱。'; parts.push({ cls: 'sys', html: '建立势力需要至少一位愿意跟你的人。先去见人、去救人、去让人怕你。
' }); } else { var cost = Math.min(pc.money, 500); pc.money -= cost; var d2 = this.dice(0.5 + followers.length * 0.06, { attr: '魅力' }); if (d2.result === 'great' || d2.result === 'ok' || d2.result === 'barely') { var base = this.place(); this.myForce = this.myForce || { name: null, base: base, members: [], rules: [], turn: this.turn, power: 0 }; var f0 = followers[Math.floor(r() * followers.length)]; if (this.myForce.members.indexOf(f0.id) < 0) this.myForce.members.push(f0.id); if (!this.myForce.name) { var pre = D.TITLE_PRE[Math.floor(r() * D.TITLE_PRE.length)]; var post = ['堂', '社', '会', '盟', '阁', '司', '局', '寨'][Math.floor(r() * 8)]; this.myForce.name = pre + post; } this.myForce.power += 10 + Math.round(f0.power * 0.02); this.myForce.rules.push(['不许问为什么', '账目公开', '叛者不留', '弱者先走', '不碰凡人'][Math.floor(r() * 5)]); mainTxt = '你在' + base + '立起了「' + this.myForce.name + '」。第一批人只有 ' + this.myForce.members.length + ' 个,规矩定了 ' + this.myForce.rules.length + ' 条。' + '立规矩的那天没人反对,这比有人反对更让人不安。'; mainTxt += ' 花掉 ' + cost + ' 灵石。'; f0.factionName = this.myForce.name; this.addBp('谋', 3.0, '建立势力'); settle.bp.push('谋 行为 +3.0 BP(重大抉择级)'); settle.world.push('新势力「' + this.myForce.name + '」成立于' + base + ',成员 ' + this.myForce.members.length + ' 人'); /* 其他势力会注意到 */ var notice = this.factions[Math.floor(r() * this.factions.length)]; if (notice) { notice.relation['myforce'] = -20; mainTxt += '【天道点交易】当前持有 ' + (pc.tianPoints || 0) + ' 点。请在右侧「天道点」面板中选择承受什么、兑换什么。天道不劝你,也不拦你——它只是记账。
' }); this.pendingTianPanel = true; pc.energy = Math.max(0, pc.energy - 10); baideObj = '自己那双开始习惯这件事的手'; } else if (act === 'provoke') { kind = 'weird'; var be = this.bigEvents.filter(function (e) { return !e.done; })[0]; if (!be) { mainTxt = '你想引爆一件大事,但手上没有可用的引子。你知道的还不够多。'; } else { var d3 = this.dice(0.4, { attr: '悟性' }); be.turn = Math.max(this.turn + 1, Math.round(be.turn * 0.5)); mainTxt = '你把那件事说了出去。说得很有技巧,让三方都以为是另外两方说的。'; if (d3.result === 'great') { mainTxt += '【天道监察 → ' + D.MONITOR[m2.to].lv + '】' + m2.txt + '
' }); pc.hp = Math.max(1, pc.hp - Math.round(pc.hpMax * 0.25)); this.addCost(3, '操纵局势失败'); costTxt = this.addCost(3, '操纵局势失败'); } } pc.energy = Math.max(0, pc.energy - 40); baideObj = '那句说出去就收不回来的话'; } /* ---- 通用回合收尾 ---- */ this.turn++; pc.timeLeft = 3; if (pc.age >= pc.lifeMax && !this.over) { this.die('寿元耗尽'); } if (pc.hp <= 0 && !this.over) { if ((pc.autoEscape || 0) > 0) { pc.autoEscape--; pc.hp = Math.round(pc.hpMax * 0.2); parts.push({ cls: 'break', html: '【必定逃脱】你本该死在这里。有什么东西把你拽了出去,拽的方式不好看,但你活着。
' }); } else this.die('重伤不治'); } var ticks = this.worldTick(); if (this.turn % 10 === 0) { var rm = N.makeRumor(this); this.rumors.unshift(rm); var big = N.makeBigForecast(this); this.rumors.unshift(big); this.bigEvents.push({ id: 'bep' + this.turn, kind: big.eventType, turn: big.dueTurn, desc: big.text, done: false, weight: big.weight }); this.bigEvents.sort(function (a, b) { return a.turn - b.turn; }); var priceReason = this.updatePrices(); var compress = this.compressMemory(); var rumorPush = [big, rm]; } var dueF = this.checkForeshadow(); this.advanceStage(); this.checkBigEvents(); var stageUp = this.takeStages(), bigFired = this.takeBigEvents(); this.decayMemory(); var decayLog = this.decayBp(); var daoTitle = this.grantDaoTitle(); pc.energy = Math.min(pc.energyMax, pc.energy + 12); /* 余炽线 */ var ember = null; if (kind === 'battle' || (stageUp && stageUp.length) || (bigFired && bigFired.length)) { this.emberDue = 1 + Math.floor(r() * 3); this.highStreak = 0; } else this.highStreak++; if (this.emberDue > 0) { ember = N.ember(this, this.emberDue); this.emberDue--; } if (this.highStreak >= 3 && this.emberDue === 0) { ember = N.ember(this, 1); this.highStreak = 0; } if (!settle.world.length && ticks.length) settle.world.push('世界 TICK:' + ticks.length + ' 件后台事件'); this.settlements.unshift({ turn: this.turn, s: settle }); if (this.settlements.length > 300) { this.settleArchive = this.settleArchive || []; this.settlements.splice(300).forEach(function (rec) { var bits = []; ['karma', 'npc', 'world', 'injury', 'bp', 'arts'].forEach(function (k) { if (rec.s[k] && rec.s[k].length) bits.push(rec.s[k].length + '项'); }); this.settleArchive.unshift({ turn: rec.turn, brief: bits.join(',') || '无显著变化' }); }, this); this.settleArchive = this.settleArchive.slice(0, 2000); } /* 岁月史书 */ var ctx = { kind: kind, subject: null, place: pc.lastPlace || (pc.lastPlace = this.place()), timeStr: ['子时', '丑时', '寅时', '卯时', '辰时', '黄昏', '入夜', '五更'][this.turn % 8], sensePool: this.sensePool(), usedSenses: this.usedSenses, goldenCache: this.goldenCache, rng_i: this.turn * 17 + 3, baideObj: baideObj, resultTxt: mainTxt ? mainTxt.replace(/') : null, costTxt: costTxt, blank: null, echo: ticks.filter(function (t) { return !t.hidden; }).slice(0, 2).map(function (t) { return t.text; }).join(' '), event: null }; var ch = N.chronicle(ctx); var res = { turn: this.turn, parts: parts, settlement: settle, options: [], ticks: ticks, chronicle: ch, ember: ember, stageUp: stageUp, bigFired: bigFired, dueForesight: dueF, compress: compress, decayLog: decayLog, daoTitle: daoTitle, priceReason: priceReason, rumorPush: rumorPush, over: this.over, deathForms: this.over ? D.DEATH_FORMS : null, showTian: !!this.pendingTianPanel }; this.pendingTianPanel = false; res.parts.push({ cls: 'chronicle', html: ch.html }); if (ember) res.parts.push({ cls: 'ember', html: ember }); if (stageUp && stageUp.length) stageUp.forEach(function (s) { res.parts.push({ cls: 'stage', html: '
【大劫推进·' + s.name + '】
' + s.desc + '
' }); }); if (bigFired && bigFired.length) { var self = this; bigFired.forEach(function (e) { res.parts.push({ cls: 'world', html: N.worldNarrative(self, e) }); }); } if (daoTitle) res.parts.push({ cls: 'title', html: '【道号凝结】「' + daoTitle.title + '」已录入万古道碑。
' + daoTitle.deed + '
【伏笔到期】' + f.text + '
' }); }); this._applyCurseTick(res); res.options = this.over ? [] : this.makeOptions(); return res; }; /* 缺陷发作注入到任意回合结果 */ Game.prototype._applyCurseTick = function (res) { if (!res || !this.pc) return; var curses = this.curseTick(); if (!curses.length) return; res.curses = curses; var html = curses.map(function (c) { return '【' + c.flaw + '·发作】' + c.txt + (c.effects.length ? '
' + c.effects.map(function (e) { return '· ' + e; }).join('
') + '' : '') + '
' + this.pendingDeathNote + '
' }); this.pendingDeathNote = null; } if (this.pendingAmbush) { var foe = this.pendingAmbush; this.pendingAmbush = null; res.parts.push({ cls: 'threat', html: '【宿敌临门】' + foe.fullName + ' 就在外面。战力 ' + foe.power + ',你 ' + this.pc.combat + '。你可以打、可以跑、也可以试着谈——他可能听,也可能不听。
' }); res.ambush = foe.id; } if (this.pendingPast) { var p = this.pendingPast; this.pendingPast = null; res.parts.push({ cls: 'foresight', html: '【过去找上门】' + p.fullName + ' 说认识你。他说得很具体,具体到你无法用"认错人了"打发他。
' }); } if (this.pc.hp <= 0 && !this.over) { if ((this.pc.autoEscape || 0) > 0) { this.pc.autoEscape--; this.pc.hp = Math.round(this.pc.hpMax * 0.2); res.parts.push({ cls: 'break', html: '【必定逃脱】你本该死在这里。你活着,方式不好看。
' }); } else { this.die('死于命途缺陷'); res.over = true; res.deathForms = D.DEATH_FORMS; } } }; /* ============================================================ SECTION: openfile-ext 开档时挂载缺陷与天道点 ============================================================ */ var _origOpenFile = Game.prototype.openFile; Game.prototype.openFile = function (cfg) { var o = _origOpenFile.call(this, cfg); var pc = this.pc; pc.tianPoints = 0; pc.flaws = (cfg.flaws || []).map(function (f) { return { id: f.id, name: f.name, desc: f.desc, fx: f.fx || {} }; }); /* 缺陷效果落地 */ pc.flaws.forEach(function (f) { var fx = f.fx || {}; if (fx.pollution) pc.pollution = Math.max(pc.pollution, fx.pollution); if (fx.monitor) pc.monitor = Math.max(pc.monitor, fx.monitor); if (fx.life) pc.lifeMax = Math.min(pc.lifeMax, fx.life); if (fx.cultMult) pc.cultMult *= fx.cultMult; if (fx.breakMult) pc.breakMult *= fx.breakMult; if (fx.tribMult) pc.tribMult *= fx.tribMult; if (fx.powerMult) pc.powerMult = (pc.powerMult || 1) * fx.powerMult; if (fx.hpMult) pc.hpMult = (pc.hpMult || 1) * fx.hpMult; if (fx.luckFlat) pc.luckFlat = (pc.luckFlat || 0) + fx.luckFlat; if (fx.luckMult) pc.luckMult = (pc.luckMult || 1) * fx.luckMult; if (fx.bondCap != null) pc.bondCap = Math.min(pc.bondCap, fx.bondCap + 1); if (fx.charmMin) pc.six['魅力'] = Math.min(pc.six['魅力'], fx.charmMin); if (fx.injury) pc.injury[fx.injury[0]] = Math.max(pc.injury[fx.injury[0]] || 0, fx.injury[1]); if (fx.daoBonus) pc.daoBonus = (pc.daoBonus || 0) + fx.daoBonus; if (fx.mindShield) pc.mindShield = true; if (fx.evilRep) pc.reputation = (pc.reputation || 0) - fx.evilRep * 0.5; if (fx.reputation) pc.reputation = (pc.reputation || 0) + fx.reputation; if (fx.debt) pc.debt = (pc.debt || 0) + fx.debt; if (fx.nemeses) { /* 生成宿敌 */ var self = this; for (var i = 0; i < fx.nemeses && i < this.npcs.length; i++) { var cand = this.npcs.filter(function (n) { return n.alive && !n.nemesis; }); if (!cand.length) break; var foe = cand[Math.floor(Math.random() * cand.length)]; foe.nemesis = true; foe.met = false; this.npcAttitude(foe, '仇恨', 70, '宿敌(开局即存在)'); } } if (fx.pastDue) { this.foreshadow.push({ id: 'past' + this.turn, text: '你的过去会找上门', level: '因果级', trigger: '某个自称认识你的人出现', dueTurn: 15 + Math.floor(Math.random() * 30), createdTurn: 0, resolved: false }); } }, this); /* 出身/天赋自带缺陷合并 */ if (pc.origin && pc.origin.flaw) { var of = D.FLAWS.filter(function (x) { return x.id === pc.origin.flaw; })[0]; if (of && !pc.flaws.some(function (f) { return f.id === of.id; })) { pc.flaws.push({ id: of.id, name: of.name, desc: of.desc, fx: of.fx || {} }); } } (pc.talents || []).forEach(function (t) { if (t.cost >= 0) return; if (!pc.flaws.some(function (f) { return f.id === t.id; })) pc.flaws.push({ id: t.id, name: t.name, desc: t.desc, fx: t.effect || {} }); }); /* 灵根负面效果 */ if (pc.linggen) { if (pc.linggen.pollution) pc.pollution = Math.max(pc.pollution, pc.linggen.pollution); if (pc.linggen.tribMult) pc.tribMult *= pc.linggen.tribMult; if (pc.linggen.breakMult) pc.breakMult *= pc.linggen.breakMult; if (pc.linggen.hpMult) pc.hpMult = (pc.hpMult || 1) * pc.linggen.hpMult; if (pc.linggen.daoInjury) for (var dk in pc.linggen.daoInjury) pc.injury[dk] = Math.max(pc.injury[dk] || 0, pc.linggen.daoInjury[dk]); if (pc.linggen.karma) { var lk = D.KARMA_POOL.filter(function (k) { return k.name === pc.linggen.karma; })[0]; if (lk && !this.karmas.some(function (k) { return k.name === lk.name; })) { this.karmas.push({ id: 'lg' + lk.id, name: lk.name, level: lk.level, power: lk.power, strength: lk.power, trigger: lk.trigger, endings: lk.endings, desc: lk.desc, surface: lk.hidden ? this._surfaceMask(lk) : null, realRevealed: !lk.hidden, status: 'active', createdTurn: 0 }); } } } /* 出身声誉/缺陷 */ if (pc.origin) { if (pc.origin.grant && pc.origin.grant.reputation) pc.reputation = (pc.reputation || 0) + pc.origin.grant.reputation; if (pc.origin.polarity === 'neg') pc.reputation = (pc.reputation || 0) - 5; } /* 天赋扩展效果 */ (pc.talents || []).forEach(function (t) { var e = t.effect || {}; if (e.hpMult) pc.hpMult = (pc.hpMult || 1) * e.hpMult; if (e.powerFlat) pc.powerFlat = (pc.powerFlat || 0) + e.powerFlat; if (e.pollutionHalf) pc.pollutionHalf = true; if (e.desperateHalf) pc.desperateHalf = true; if (e.talkBonus) pc.talkBonus = (pc.talkBonus || 0) + e.talkBonus; if (e.tradeBonus) pc.tradeBonus = (pc.tradeBonus || 0) + e.tradeBonus; if (e.artBonus) { pc.artBonus = pc.artBonus || {}; if (typeof e.artBonus === 'number') pc.artBonus[t.effect.art || 'all'] = (pc.artBonus[t.effect.art || 'all'] || 0) + e.artBonus; else for (var ak in e.artBonus) pc.artBonus[ak] = (pc.artBonus[ak] || 0) + e.artBonus[ak]; } if (e.bpMult) { pc.bpMult = pc.bpMult || {}; for (var bk in e.bpMult) pc.bpMult[bk] = (pc.bpMult[bk] || 1) * e.bpMult[bk]; } if (e.reputation) pc.reputation = (pc.reputation || 0) + e.reputation; if (e.startRealm) { /* 已在基础流程处理 */ } if (e.wantedBy) { pc.wantedBy = true; } if (e.bondCap) pc.bondCap = Math.min(pc.bondCap, e.bondCap); if (e.dao && !pc.daoBias) pc.daoBias = e.dao; }); /* 应用体质倍率 */ if (pc.hpMult) { pc.hpMax = Math.round(pc.hpMax * pc.hpMult); pc.hp = pc.hpMax; } if (pc.powerFlat) pc.powerFlatBonus = pc.powerFlat; pc.combat = this.calcPower(pc); /* 缺陷写入开档信息 */ o.flaws = pc.flaws.slice(); return o; }; /* 战力计算叠加天赋/缺陷修正 */ var _origCalcPower = Game.prototype.calcPower; Game.prototype.calcPower = function (pc) { var p = _origCalcPower.call(this, pc); if (pc.powerMult) p *= pc.powerMult; if (pc.powerFlatBonus) p *= (1 + pc.powerFlatBonus); if (pc.burstTurns > 0) p *= 2; if (pc.bpHollow) p *= (1 - pc.bpHollow * 0.04); return Math.max(1, Math.round(p)); }; /* 掷骰支持强制成功 / 气运倍率 / 缺陷惩罚 */ var _origDice = Game.prototype.dice; Game.prototype.dice = function (baseRate, opts) { var d = _origDice.call(this, baseRate, opts); var pc = this.pc; if (pc.luckMult) d.rate = E.clamp(d.rate * pc.luckMult, 0.02, 0.98); if (pc.flaws && pc.flaws.some(function (f) { return f.fx && f.fx.curse === 'luckdebt'; })) d.rate = E.clamp(d.rate * 0.88, 0.02, 0.98); if ((pc.forceSuccess || 0) > 0) { pc.forceSuccess--; d.result = 'great'; d.forced = true; } return d; }; /* 突破支持抵消天劫 */ var _origBreak = Game.prototype.tryBreakthrough; Game.prototype.tryBreakthrough = function () { var pc = this.pc; if ((pc.tribSkip || 0) > 0) { pc.tribSkip--; var savedNoTrib = pc.noTrib; pc.noTrib = true; var r = _origBreak.call(this); pc.noTrib = savedNoTrib; if (r && r.txt) r.txt = '【天道点·抵消天劫】' + r.txt + '