Files
ChronicleOfTheImmortalClan/src/renderer/game/engine/sim/Market.ts
T
thzxx ea9f5c9c5d v0.1.17: 天下为市——世界真炉膛(市场实体化+NPC博弈+灾年持续)
【A 市场实体化(真库存循环)】
- 世界呼吸:池月供给 × 潮汐span - 常驻需求(worldSupplyRate 2% vs worldDemandRate 1.5%)
- NPC 上桌:def.sells/buys 逐月入池出池——池浅采不到→power-15%,池深抛货→市场暖意
- 玩家交易回写:buy 浅池价涨/sell 盈池价跌(tradeSettle 0.35 份额粒度);池深<35% 断供拒单(12% 是枯井)
- marketPrice 统一走 marketMultFor;本地 POOL_BASE/TECH 复刻清除(worldsim-data 单源)

【B 世界格局博弈】
- 战争伤骨:劫掠胜负回写 power(败-18%/胜+6%)+ dead 字段 raidCount/warCooldownYear 启用
- 社交回响:赠礼回礼(30% 灵石/30% 灵草)+ power 微涨;联姻/和约/结盟皆涨 power
- NPC 关系网:relationsWithOthers 填实(同风格亲30~55/异风格隙-35~15)+ 年首±5 漂移;世仇<-50 年首互攻(败方-18%)
- 灾年共苦:灾年 NPC 贸易 ×0.7;tide 对供给 ±0.3 弹性
- 灾年持续 6 月渐退;灾起/灾散快讯(kind 标记)

【UI】
- 天下面板:池深百分比(含断供阈值 tooltip)/本族天下排位/灾年余月
- 快讯响应化:行情见顶抛售5/见底吃进5/灾年救济(50灵石→关系8)
- MarketPanel 法帖价格改 techniquePrice()(硬编码清除)

【测试】994 全绿(38 套件,新增世界炉膛 8 例);金钟罩 0.1.17 基线固化
2026-08-23 14:24:23 +08:00

67 lines
2.6 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.
import type { World } from '../runtime/World'
import { pack } from '../../data/registry'
import { traitBonuses } from '../runtime/pcgen'
import { WorldSim } from './WorldSim'
export function marketPrice(w: World, itemId: string): number {
const item = pack().items[itemId]
if (!item) return 0
const base = item.basePrice
const fam = w.state.family
const mult = typeof fam.flag['priceMult'] === 'number' ? (fam.flag['priceMult'] as number) : 1
const mood = fam.reputation >= 40 ? 1.06 : fam.reputation >= 20 ? 1.02 : 0.98
// 世界行情乘子(唯一读口:worldSim.marketMultFor;无 sim 时 1
const simMult = w.state.worldSim ? new WorldSim(w).marketMultFor(itemId) : 1
// 利己(priceMult)与信誉修正
const sellers = w.aliveMembers().filter((c) => traitBonuses(c).priceMult > 0).length
const liarPct = Math.min(0.2, sellers * 0.04)
return Math.max(1, Math.round(base * mult * mood * simMult * (1 - liarPct)))
}
export function buyItem(w: World, itemId: string, count: number): boolean {
const fam = w.state.family
if (!pack().items[itemId]) return false
const sim = w.state.worldSim ? new WorldSim(w) : null
// 断供告急:池深低于下限时拒单(零库存市场无货可买;世界生产与 NPC 供给会回填)
if (sim && sim.poolDepthOf(itemId) < WORLDSIM.tradeFloorPct && w.state.totalTicks > 12) return false
const total = marketPrice(w, itemId) * count
if (total > fam.stones) return false
fam.stones -= total
fam.inventory[itemId] = (fam.inventory[itemId] ?? 0) + count
sim?.tradeSettle(itemId, -count)
return true
}
export function sellItem(w: World, itemId: string, count: number): boolean {
const fam = w.state.family
if (!pack().items[itemId]) return false
const have = fam.inventory[itemId] ?? 0
if (have < count) return false
fam.inventory[itemId] = have - count
fam.stones += marketPrice(w, itemId) * count
if (w.state.worldSim) new WorldSim(w).tradeSettle(itemId, count)
return true
}
export function buyTechnique(w: World, techId: string, price: number): boolean {
const fam = w.state.family
if (fam.techniques.includes(techId)) return false
if (fam.stones < price) return false
fam.stones -= price
fam.techniques.push(techId)
return true
}
export function techniquePrice(techId: string): number {
return TECH_GRADE_BASE[techId] ?? 200
}
import { TECHNIQUES } from '../../data/techniques'
import { WORLDSIM } from './worldsim-data'
const TECHNIQUE_GRADE_PRICE: Record<number, number> = { 1: 120, 2: 300, 3: 700, 4: 1600 }
const TECH_GRADE_BASE: Record<string, number> = Object.fromEntries(
TECHNIQUES.map((t) => [t.id, TECHNIQUE_GRADE_PRICE[t.grade] ?? 300])
)