v0.1.23: 生灭千秋 + 插件生态化第一课(1027 全绿)
【世界模型:世界会死人也会新生】 - 家族生灭:declineYears(power<58+景气<38 连续8年)→ 覆灭(最强邻分食+史官广播)+ 新贵补位(6%/年,乱世×2) —— NPC 永远四家铁打的现状终结;玩家补刀(raid×0.82)可加速衰亡 - npcById 双源可空(静态+动态注册表;不再 throw——15 处消费者防御化) - purgeNpc 全局清理(raidCD/事件队列/恩怨网/distress/动态 def) - 秘境产出回池(loot 20% 经 tradeSettle 回流)——资源循环最后单向封口 - WorldSnapshot 只读摘要门面(UI/史书消费,零行为变更) - 潮汐长波(10 年正弦 ±0.08 叠加,灵潮三十年河东) 【插件生态化(0.1.8 后第一次大进化)】 - 持久化:GameState.plugins 落盘 + PLUGIN_REGISTRY 读档重装(engineFromSnapshot 真实路径验证) - plugin-public.ts 公共导出面(第三方单入口+纪律) - 双闸:能力卡随插件启停联动;池自动回滚 - 契约补完:Proxy 追踪(池/卡/pack 自动回滚)+ onUninstall 真调 + 能力卡入 World 实例(防跨档泄漏) - SettingsPanel 启停按钮/依赖详情;demo 与 tests 去重(发现并修复:npcById 双源静态源未绑定——全局 NPC 停滞回归) 【测试】1027 全绿(44 套件):dynasty-plugin 7 例(覆灭/新贵/回池/快照/持久化/双闸/自动回滚); 金钟罩 0.1.23 基线固化;build 通过
This commit is contained in:
@@ -166,6 +166,7 @@ export function resolveRaid(
|
||||
): EncounterResult {
|
||||
const npc = w.state.npcFamilies[npcId]
|
||||
const def = npcById(npcId)
|
||||
if (!def) return { win: false, draw: true, lines: ['此族已散。'], loot: undefined, losses: [] }
|
||||
// 宗主实力分层:power 由年度成长+换代驱动,劫掠强度随之浮动(0.5↔1.8)
|
||||
const npcPower = npc.power ?? 60
|
||||
const strength = Math.min(1.8, Math.max(0.5, 0.5 + (npcPower / 120) * 0.5))
|
||||
@@ -193,7 +194,7 @@ export function resolveRaid(
|
||||
w.state.family.reputation += 6
|
||||
// B5:战争伤骨——败方 power 重挫,次年不再来犯(warCooldownYear/raidCount 启用)
|
||||
w.emitFx('blade', `raid:${npcId}`)
|
||||
npc.power = Math.max(40, Math.round(npc.power * 0.82))
|
||||
npc.power = Math.max(52, Math.round(npc.power * 0.82))
|
||||
npc.raidCount = (npc.raidCount ?? 0) + 1
|
||||
npc.warCooldownYear = w.state.year
|
||||
// 1-3 蝴蝶效应:玩家重创名声——邻家对败者关系趋冷
|
||||
|
||||
@@ -36,6 +36,7 @@ export function yearGrowth(w: World): void {
|
||||
const s = w.state
|
||||
for (const npc of Object.values(s.npcFamilies)) {
|
||||
const def = npcById(npc.id)
|
||||
if (!def) continue
|
||||
const [a, b] = def.powerGrowth
|
||||
npc.power += w.rng.int(a, b)
|
||||
if (npc.allied) {
|
||||
|
||||
@@ -29,6 +29,7 @@ export function dynamicEventFor(id: string, w?: World): EventDef | undefined {
|
||||
if (id.startsWith('ev-raid-')) {
|
||||
const npcId = id.replace('ev-raid-', '')
|
||||
const npc = npcById(npcId)
|
||||
if (!npc) return undefined // 该族已散(覆灭/附庸)——事件自然消亡
|
||||
return {
|
||||
id,
|
||||
name: `${npc.name}来犯`,
|
||||
|
||||
@@ -70,6 +70,15 @@ export function missionTick(w: World): void {
|
||||
m.result = 'success'
|
||||
releaseSquad(w, m)
|
||||
const total = rollWarbooty(w, def.completionLoot, qiRatioOf(w, def.id))
|
||||
// 0.1.23 秘境回池:探得之物近 2 成回流人间(负反馈世界侧供给)
|
||||
if (w.state.worldSim) {
|
||||
const sim = new WorldSim(w)
|
||||
for (const [k, v] of Object.entries(total)) {
|
||||
if (k === 'tech') continue
|
||||
const bleed = Math.max(1, Math.round((v as number) * 0.2))
|
||||
sim.tradeSettle(k === 'stones' ? 'lingkuang' : k, bleed)
|
||||
}
|
||||
}
|
||||
m.log.push(`凯旋而归,清点战利:${lootText(total)}。`)
|
||||
const survivors = squadOf(w, m).filter((c) => c.alive).map((c) => c.name).join('、')
|
||||
w.chronicle(
|
||||
|
||||
Reference in New Issue
Block a user