- 指婚/续弦:成员详情可主动找人结亲(血亲自动排除、鳏寡可再醮) - 装备 UI:法宝从府库装备/替换,战力实时反馈 - 御敌点将:劫掠事件可自选迎战阵容(默认 Top4 可改) - 宗祠祭祖:每两年一次,灵石150 → 声望+6/全族修为小升 - 回档时间轴:每季快照列表,一键回卷(回卷前自动保当前档) - 战报匣子:史书页全文战报留存可翻阅 - 年度族簿纸笺:每年初弹收支/人丁/战力简报 - 媒人提示条 + 寻衅一年冷却 + 出生率与劫掠频率微调 - 单测 19→29(storage mock roundtrip/回档/指婚血亲/祭祖/寻衅/装备/账本)
196 lines
5.4 KiB
TypeScript
196 lines
5.4 KiB
TypeScript
import { Character, GameState, NpcFamilyState, RealmMajor } from '../types/domain'
|
|
import { Rng, seedToRng } from '../core/rng'
|
|
import { randomSurname, MALE_GIVEN, FEMALE_GIVEN } from '../core/names'
|
|
import { newCharacter } from './pcgen'
|
|
import { NPCS } from '../data/npcs'
|
|
import { World } from './world'
|
|
|
|
export interface NewGameOptions {
|
|
seed: string
|
|
surname: string
|
|
familyName: string
|
|
motto: string
|
|
difficulty: 'easy' | 'normal' | 'hard'
|
|
}
|
|
|
|
export function createWorldState(opts: NewGameOptions): GameState {
|
|
const rng = new Rng(seedToRng(opts.seed))
|
|
const surname = opts.surname.trim() || randomSurname(rng)
|
|
const familyName = opts.familyName.trim() || `${surname}家`
|
|
const diff = opts.difficulty
|
|
const stones = diff === 'easy' ? 1200 : diff === 'normal' ? 800 : 550
|
|
const npcStrength = diff === 'easy' ? 0.9 : diff === 'normal' ? 1 : 1.15
|
|
|
|
const state: GameState = {
|
|
schemaVersion: 1,
|
|
seed: opts.seed,
|
|
rng: rng.getState(),
|
|
year: 1,
|
|
month: 1,
|
|
seq: 0,
|
|
family: {
|
|
surname,
|
|
name: familyName,
|
|
motto: opts.motto.trim() || '耕读传家,术法继世',
|
|
crest: '#c9a227',
|
|
estate: '青云庄',
|
|
yearFounded: 1,
|
|
generation: 1,
|
|
reputation: 5,
|
|
stones,
|
|
inventory: {
|
|
lingcao: 60,
|
|
lingkuang: 30,
|
|
beastcore: 0,
|
|
'pill-qiyuan': 2,
|
|
'pill-ningyuan': 1
|
|
},
|
|
buildings: { lingtian: 1, zongci: 1 },
|
|
techniques: ['t-qinglian', 't-houtu'],
|
|
missionIds: [],
|
|
headId: '',
|
|
difficulty: diff,
|
|
flag: { priceMult: 1, tenants: 0, headBless: 0 }
|
|
},
|
|
members: {},
|
|
npcFamilies: Object.fromEntries(
|
|
NPCS.map((n) => [
|
|
n.id,
|
|
{
|
|
id: n.id,
|
|
name: n.name,
|
|
region: n.region,
|
|
power: Math.round(n.initialPower * npcStrength),
|
|
relation: 0,
|
|
allied: false,
|
|
raidCount: 0
|
|
} as NpcFamilyState
|
|
])
|
|
),
|
|
missions: [],
|
|
chronicle: [],
|
|
battles: [],
|
|
eventQueue: [],
|
|
completedEvents: [],
|
|
flags: {},
|
|
totalTicks: 0,
|
|
finance: { accum: 0 },
|
|
yearStats: { births: 0, deaths: 0 },
|
|
yearlyReports: []
|
|
}
|
|
|
|
const w = new World(state, [])
|
|
const male1: string = rng.pick(MALE_GIVEN)
|
|
const female1: string = rng.pick(FEMALE_GIVEN)
|
|
|
|
const head: Character = newCharacter(rng, {
|
|
name: `${surname}${male1}`,
|
|
gender: 'male',
|
|
generation: 1,
|
|
bornYear: 1 - 35,
|
|
age: 35,
|
|
realm: { major: 'qi', minor: 4 },
|
|
isHead: true,
|
|
isFounder: true,
|
|
fortuneBase: 7
|
|
})
|
|
head.realmProgress = 40
|
|
head.techniqueId = 't-qinglian'
|
|
head.traits = ['tiangan', 'shensui']
|
|
|
|
const wife: Character = newCharacter(rng, {
|
|
name: `${surname}${female1}`,
|
|
gender: 'female',
|
|
generation: 1,
|
|
bornYear: 1 - 33,
|
|
age: 33,
|
|
realm: { major: 'qi', minor: 2 },
|
|
fortuneBase: 6
|
|
})
|
|
wife.realmProgress = 55
|
|
head.spouseId = 'x2'
|
|
wife.spouseId = 'x1'
|
|
head.children = ['x3', 'x5']
|
|
|
|
const elderBrother: Character = newCharacter(rng, {
|
|
name: `${surname}${rng.pick(MALE_GIVEN)}`,
|
|
gender: 'male',
|
|
generation: 2,
|
|
bornYear: 1 - 16,
|
|
age: 16,
|
|
realm: { major: 'qi', minor: 1 },
|
|
father: head,
|
|
mother: wife
|
|
})
|
|
elderBrother.realmProgress = 20
|
|
elderBrother.techniqueId = 't-houtu'
|
|
elderBrother.fatherId = 'x1'
|
|
elderBrother.motherId = 'x2'
|
|
|
|
const sister: Character = newCharacter(rng, {
|
|
name: `${surname}${rng.pick(FEMALE_GIVEN)}`,
|
|
gender: 'female',
|
|
generation: 2,
|
|
bornYear: 1 - 12,
|
|
age: 12,
|
|
realm: { major: 'mortal', minor: 0 },
|
|
father: head,
|
|
mother: wife
|
|
})
|
|
sister.fatherId = 'x1'
|
|
sister.motherId = 'x2'
|
|
|
|
const uncle: Character = newCharacter(rng, {
|
|
name: `${surname}${rng.pick(MALE_GIVEN)}`,
|
|
gender: 'male',
|
|
generation: 1,
|
|
bornYear: 1 - 45,
|
|
age: 45,
|
|
realm: { major: 'qi', minor: 6 },
|
|
fortuneBase: 6
|
|
})
|
|
uncle.realmProgress = 30
|
|
uncle.techniqueId = 't-houtu'
|
|
uncle.traits = ['xinheng', 'shensui']
|
|
uncle.id = 'x4'
|
|
uncle.spouseHouse = 'sihai王氏'
|
|
uncle.children = []
|
|
|
|
head.id = 'x1'
|
|
wife.id = 'x2'
|
|
elderBrother.id = 'x3'
|
|
sister.id = 'x5'
|
|
wife.children = ['x3', 'x5']
|
|
|
|
state.members = { x1: head, x2: wife, x3: elderBrother, x4: uncle, x5: sister }
|
|
state.family.headId = 'x1'
|
|
state.seq = 10
|
|
|
|
w.chronicle('misc', `${surname}氏一族定居山阴,立${familyName}。庄主${head.name},年方三十五。`, head.id, true)
|
|
w.log('info', `青云庄立,${familyName}始兴。`)
|
|
return state
|
|
}
|
|
|
|
export function findInheritor(world: World): Character | undefined {
|
|
const alive = world.aliveMembers()
|
|
if (alive.length === 0) return undefined
|
|
const head = world.state.members[world.state.family.headId]
|
|
const candidates = alive.filter((c) => c.id !== head?.id)
|
|
if (candidates.length === 0) return undefined
|
|
const byBlood = candidates
|
|
.filter((c) => (head && head.children.includes(c.id)) || (c.fatherId === head?.id))
|
|
.sort((a, b) => world.ageOf(b) - world.ageOf(a))
|
|
if (byBlood.length > 0) return byBlood[0]
|
|
const byRealm = [...candidates].sort((a, b) => {
|
|
const ra = realmRank(a.realm)
|
|
const rb = realmRank(b.realm)
|
|
return rb - ra || b.charm - a.charm || world.ageOf(b) - world.ageOf(a)
|
|
})
|
|
return byRealm[0]
|
|
}
|
|
|
|
function realmRank(realm: { major: RealmMajor; minor: number }): number {
|
|
const order: RealmMajor[] = ['mortal', 'qi', 'foundation', 'core', 'nascent', 'spirit']
|
|
return order.indexOf(realm.major) * 10 + realm.minor
|
|
}
|