【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 基线固化
67 lines
2.6 KiB
TypeScript
67 lines
2.6 KiB
TypeScript
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])
|
||
)
|