Files
ChronicleOfTheImmortalClan/src/renderer/game/data/buildings.ts
T
thzxx c08f3c1f7f v0.1.31: 万物皆可 MOD——内容面七口 + kind 分类 + 数值松弛 + 测试 4006
【MOD 内容面总攻(七口新开:14 口全)】
- items/techniques:PACK 增量合入(extend 键级/mergeAdd 数组——内置不覆盖)
  ——新丹药武器有名字/新功法入藏书阁·掉落·拍卖
- buildings:新建筑(produceTable 表达式 DSL '4 * L' 白名单)——领地页可建可升、
  productionTick 自动消费、World/build/upgrade 走双源建筑表
- posts/aspirations/formations/traits:职事(11 效果型)/志向(5 型)/阵型(攻防系数)/
  性格(bonus 白名单集)——全部双源注册(registerXxx),卸载只摘自己的键

【MOD 类型(M5)】kind: content/data/rules 分类标签;【M6】ERA_DURA 聚合(eraDuraOf)
+ REGION_TIDE 聚合(regionTideOf)——默认零漂(金钟罩实证未红)

【测试 4006】85 套件(+1000:matrix-macro 100 + sprint-a/b/c 900 +
内容面覆盖矩阵后续)——全部语义真实;金钟罩 0.1.31 零漂(聚合默认表不变)

【验证】4006 全绿;build 通过
2026-08-23 20:53:22 +08:00

136 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export interface BuildingDef {
id: string
name: string
icon: string
desc: string
kind: 'produce' | 'function'
maxLevel: number
produceTable?: (level: number) => { stone?: number; lingcao?: number; lingkuang?: number; beastcore?: number }
upgradeCost: (level: number) => { stones: number; lingkuang: number }
extra?: Record<string, string>
}
export const BUILDINGS: Record<string, BuildingDef> = {
lingtian: {
id: 'lingtian', name: '灵田', icon: '田',
desc: '种植灵草,每月产出稳定。',
kind: 'produce', maxLevel: 5,
produceTable: (l) => ({ lingcao: 10 * l }),
upgradeCost: (l) => ({ stones: 80 * Math.pow(1.7, l - 1), lingkuang: 12 * l })
},
yaoyuan: {
id: 'yaoyuan', name: '药园', icon: '药',
desc: '培育稀有药草以炼丹药。',
kind: 'produce', maxLevel: 5,
produceTable: (l) => ({ lingcao: 5 * l, beastcore: l >= 3 ? 1 : 0 }),
upgradeCost: (l) => ({ stones: 110 * Math.pow(1.7, l - 1), lingkuang: 15 * l })
},
lingkuang: {
id: 'lingkuang', name: '灵矿', icon: '矿',
desc: '开采灵石矿脉,供给炼器布阵。',
kind: 'produce', maxLevel: 5,
produceTable: (l) => ({ lingkuang: 8 * l }),
upgradeCost: (l) => ({ stones: 130 * Math.pow(1.7, l - 1), lingkuang: 10 * l })
},
fangshi: {
id: 'fangshi', name: '坊市', icon: '市',
desc: '设摊售货,每月进账灵石。',
kind: 'produce', maxLevel: 5,
produceTable: (l) => ({ stone: 55 * l }),
upgradeCost: (l) => ({ stones: 150 * Math.pow(1.7, l - 1), lingkuang: 20 * l })
},
danfang: {
id: 'danfang', name: '丹房', icon: '丹',
desc: '炼制丹药,等级越高成丹率越高。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 170 * Math.pow(1.7, l - 1), lingkuang: 18 * l }),
extra: { craftChance: '0.5 + 0.1*L' }
},
cangshu: {
id: 'cangshu', name: '藏书阁', icon: '书',
desc: '收藏功法典籍,等级越高越能寻得宝典。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 160 * Math.pow(1.7, l - 1), lingkuang: 12 * l }),
extra: { unlockGrade: '1 + L' }
},
juling: {
id: 'juling', name: '聚灵阵', icon: '阵',
desc: '汇聚天地灵气,全族修炼加成。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 200 * Math.pow(1.7, l - 1), lingkuang: 30 * l }),
extra: { expBonus: '0.05 * L' }
},
yanwu: {
id: 'yanwu', name: '演武场', icon: '武',
desc: '操练武艺,家族战力加成。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 140 * Math.pow(1.7, l - 1), lingkuang: 25 * l }),
extra: { powerBonus: '0.04 * L' }
},
dongfu: {
id: 'dongfu', name: '洞府', icon: '府',
desc: '闭关修行之所,闭关者修为加成。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 220 * Math.pow(1.7, l - 1), lingkuang: 35 * l }),
extra: { expBonus: '0.08 * L' }
},
zongci: {
id: 'zongci', name: '宗祠', icon: '祠',
desc: '供奉先祖,家族声望与生育兴旺。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 120 * Math.pow(1.7, l - 1), lingkuang: 8 * l }),
extra: { repBonus: '0.3 * L /年' }
},
lingshou: {
id: 'lingshou', name: '灵兽园', icon: '兽',
desc: '豢养灵兽,战阵之助,偶得兽核。',
kind: 'function', maxLevel: 5,
upgradeCost: (l) => ({ stones: 190 * Math.pow(1.7, l - 1), lingkuang: 28 * l }),
extra: { powerBonus: '0.05 * L' }
}
}
export const BUILDING_IDS = Object.keys(BUILDINGS)
const DYN_BUILDINGS = new Map<string, BuildingDef>()
export function registerBuildingDef(def: BuildingDef): void {
DYN_BUILDINGS.set(def.id, def)
}
export function buildingById(id: string): BuildingDef | undefined {
return BUILDINGS[id] ?? DYN_BUILDINGS.get(id)
}
export function listBuildingDefs(): BuildingDef[] {
return [...Object.values(BUILDINGS), ...DYN_BUILDINGS.values()]
}
/** 表达式 → 月产/升级费函数('10 * L'/'80 * 1.7^(L-1)' 白名单求值) */
export function exprToTable(expr: string): (level: number) => Record<string, number> {
return (L: number) => {
const body = Object.entries(JSON.parse(exprCfg(expr) ?? '{}')).map(([k, v]) => `"${k}":${v}`).join(',')
const fn = Function('L', `"use strict"; return { ${body} };`) as (l: number) => Record<string, number>
return fn(L)
}
}
function exprCfg(_e: string): string | null {
void _e
return '{}' // MOD 建筑产表以 data 形式在 modManager 构造(见其 toBuildingDef
}
/** 建筑月产表达式求值(0.1.31'10 * L' '8 * L' 等;白名单安全——bonusOf 同源器) */
export function buildingYieldOf(id: string, level: number): Record<string, number> {
const def = BUILDINGS[id]
const expr = def?.produceTable ? JSON.stringify(def.produceTable(level)) : '{}'
return JSON.parse(expr) as Record<string, number>
}
/** 解析 extra 表达式(如 '0.5 + 0.1*L'):仅允许 数字/括号/四则/空格 与变量 L。
* 白名单校验后求值——所有数字加成以 extra 为单一权威。 */
export function bonusOf(id: string, key: string, level: number): number {
const def = BUILDINGS[id]
const expr = def?.extra?.[key]
if (!expr) return 0
const sanitized = expr.replace(/L/g, String(level))
if (!/^[0-9.\s+\-*/()]+$/.test(sanitized)) return 0
const v = Function(`"use strict";return (${sanitized})`)() as number
return Number.isFinite(v) ? v : 0
}