import type { World } from '../World' import { Character } from '../../../types/domain' import { produceOffspring } from './cultivation' import { yearGrowth } from './diplomacy' import { MALE_GIVEN, FEMALE_GIVEN } from '../../kernel/names' import { aspirationById } from '../../../data/aspirations' export function yearStartMarriage(w: World): void { yearGrowth(w) const s = w.state const fam = s.family const zongci = fam.buildings['zongci'] ?? 0 const birthBase = 0.6 + zongci * 0.04 + (fam.difficulty === 'easy' ? 0.06 : fam.difficulty === 'hard' ? -0.06 : 0) const couples = buildCouples(w) // 族内夫妇 for (const couple of couples.internal) { const [a, b] = couple const father = a.gender === 'male' ? a : b const mother = a.gender === 'male' ? b : a const fatherAge = w.ageOf(father) const motherAge = w.ageOf(mother) if (fatherAge < 18 || fatherAge > 52 || motherAge < 16 || motherAge > 46) continue const offspringBonus = Object.values(s.members) .filter((m) => m.alive && aspirationById(m.aspiration)?.effect.type === 'offspring') .length * 0.05 const p = birthBase * (0.75 + mother.physique * 0.05) + offspringBonus if (!w.rng.chance(p)) continue const gen = Math.max(father.generation, mother.generation) + 1 const first = produceOffspring(w, { father, mother, generation: gen, bornYear: s.year, surname: fam.surname }) w.addMember(first, father, mother) let note = `${fam.surname}氏新增一员,名唤${first.name},生年 ${s.year}。` if (w.rng.chance(0.06)) { const twin = produceOffspring(w, { father, mother, generation: gen, bornYear: s.year, surname: fam.surname }) w.addMember(twin, father, mother) w.state.yearStats.births += 1 note += ` 双生之喜!双子名唤${twin.name}。` } w.chronicle('birth', note, first.id, true) w.state.yearStats.births += 1 w.log('good', `${fam.surname}家诞下新丁:${first.name}。`) } // 联姻外孙来投(男方娶亲:妻室携子来归;或女儿携子回门) for (const member of Object.values(s.members)) { if (!member.alive || !member.spouseHouse) continue const age = w.ageOf(member) if (age < 18 || age > 44) continue if (!w.rng.chance(0.15)) continue const gen = member.generation + 1 const house = member.spouseHouse const child = produceOffspring(w, { father: null, mother: null, generation: gen, bornYear: s.year, surname: fam.surname }) child.spouseHouse = house w.addMember(child) w.chronicle('birth', `${member.name}自${house}携幼子归庄,名唤${child.name}。`, child.id, true) w.state.yearStats.births += 1 w.log('info', `${member.name} 领着小辈回门投亲。`) } // 媒人撮合族内婚(含续弦与再醮) const isWidowed = (c: Character): boolean => { if (!c.spouseId) return false const sp = w.state.members[c.spouseId] return !!sp && !sp.alive } const men = w .aliveMembers() .filter((c) => c.gender === 'male' && c.state !== 'expedition' && (isWidowed(c) || !c.spouseId)) .filter((c) => { const age = w.ageOf(c) return age >= 18 && age <= 48 }) const women = w .aliveMembers() .filter((c) => c.gender === 'female' && c.state !== 'expedition' && (isWidowed(c) || !c.spouseId)) .filter((c) => { const age = w.ageOf(c) return age >= 16 && age <= 42 }) for (const m of men) { if (w.rng.chance(0.55) && women.length > 0) { const candidate = women.filter( (x) => !(x.fatherId && x.fatherId === m.fatherId) && !(x.motherId && x.motherId === m.motherId) && x !== m && !x.children.includes(m.id) && !m.children.includes(x.id) ) if (candidate.length === 0) continue const bride = w.rng.pick(candidate) m.spouseId = bride.id bride.spouseId = m.id w.chronicle('marriage', `${m.name}与${bride.name}缔结连理。`, m.id, true) w.log('info', `${m.name} 与 ${bride.name} 成婚。`) const idx = women.indexOf(bride) if (idx >= 0) women.splice(idx, 1) } } fam.generation = Math.max( fam.generation, ...Object.values(s.members).filter((c) => c.alive).map((c) => c.generation) ) } function buildCouples(w: World): { internal: [Character, Character][]; cross: Character[] } { const internal: [Character, Character][] = [] const cross: Character[] = [] for (const member of Object.values(w.state.members)) { if (!member.alive || !member.spouseId) continue const spouse = w.state.members[member.spouseId] if (!spouse?.alive) continue const key = [member.id, spouse.id].sort().join('|') if (internal.some(([a, b]) => [a.id, b.id].sort().join('|') === key)) continue internal.push([member, spouse]) } for (const member of Object.values(w.state.members)) { if (member.alive && member.spouseHouse) cross.push(member) } return { internal, cross } }