update: core support rng

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent 9a0065c1e8
commit 2f91709d1e
2 changed files with 28 additions and 16 deletions
+13 -5
View File
@@ -19,13 +19,17 @@ export { pull } from '@/talent'
import { replacement, additionalPoints } from '@/talent' import { replacement, additionalPoints } from '@/talent'
import type { ReplacementResult, AdditionalPoints } from '@/talent' import type { ReplacementResult, AdditionalPoints } from '@/talent'
import type { RNG } from '@remake/vitex'
export interface TalentsPickedResult { export interface TalentsPickedResult {
talents: ReplacementResult talents: ReplacementResult
additionalPoints: AdditionalPoints additionalPoints: AdditionalPoints
} }
export function talentsPicked(talents: Iterable<Talent['id']>) { export function talentsPicked(
const r = replacement(talents) talents: Iterable<Talent['id']>,
rng?: RNG,
): TalentsPickedResult {
const r = replacement(talents, rng)
const ap = additionalPoints(r.talents) const ap = additionalPoints(r.talents)
return { talents: r, additionalPoints: ap } return { talents: r, additionalPoints: ap }
} }
@@ -63,16 +67,20 @@ export interface NextResult {
end: boolean end: boolean
} }
export function next(state: GameState, profile: ProfileState): NextResult { export function next(
state: GameState,
profile: ProfileState,
rng?: RNG,
): NextResult {
let s = produce(state, draft => { let s = produce(state, draft => {
draft.props = propsEffect(state.props, { age: 1 }) draft.props = propsEffect(state.props, { age: 1 })
}) })
const age = s.props.current.age const age = s.props.current.age
const tr = talentTrigger(s, profile) const tr = talentTrigger(s, profile, rng)
const events = ages const events = ages
.get(age)! .get(age)!
.event.filter(([e]) => eventCheck(e, tr.state, profile)) .event.filter(([e]) => eventCheck(e, tr.state, profile))
const event = pickWeight(events)! const event = pickWeight(events, rng)!
const er = eventTrigger(event, tr.state, profile) const er = eventTrigger(event, tr.state, profile)
const ar = achievementTrigger('TRAJECTORY', er.state, profile) const ar = achievementTrigger('TRAJECTORY', er.state, profile)
const end = ar.state.life < 1 const end = ar.state.life < 1
+15 -11
View File
@@ -4,7 +4,7 @@ import type { Properties } from '@/state'
import type { GameState, ProfileState } from '@/state' import type { GameState, ProfileState } from '@/state'
import { propsEffect, createFlatState } from './state' import { propsEffect, createFlatState } from './state'
import { check } from '@remake/condition' import { check } from '@remake/condition'
import { pick, pickWeight } from '@remake/vitex' import { pick, pickWeight, type RNG } from '@remake/vitex'
import { produce } from 'immer' import { produce } from 'immer'
import type { TriggerResult } from '@/game' import type { TriggerResult } from '@/game'
@@ -64,7 +64,7 @@ export interface PullOptions {
rate: RateOptions rate: RateOptions
} }
export function pull(options: PullOptions, profile: ProfileState) { export function pull(options: PullOptions, profile: ProfileState, rng?: RNG) {
const rate = Array.from( const rate = Array.from(
talentRateWithAddition(options.rate, profile).entries(), talentRateWithAddition(options.rate, profile).entries(),
) )
@@ -72,10 +72,10 @@ export function pull(options: PullOptions, profile: ProfileState) {
if (profile.lockedTalent) result.push(profile.lockedTalent) if (profile.lockedTalent) result.push(profile.lockedTalent)
const map = new Map(Grades.map(g => [g, new Set(GradeMap.get(g))])) const map = new Map(Grades.map(g => [g, new Set(GradeMap.get(g))]))
for (let i = options.count - result.length; i > 0; i--) { for (let i = options.count - result.length; i > 0; i--) {
const grade = pickWeight(rate)! ?? 0 const grade = pickWeight(rate, rng)! ?? 0
const set = map.get(grade)! const set = map.get(grade)!
if (set.size === 0) continue if (set.size === 0) continue
const id = pick(Array.from(set))! const id = pick(Array.from(set), rng)!
result.push(id) result.push(id)
set.delete(id) set.delete(id)
} }
@@ -100,23 +100,23 @@ export function exclude(talent: Talent['id'], list: Iterable<Talent['id']>) {
return null return null
} }
function chainReplace(t: Talent['id'], ts: Set<Talent['id']>) { function chainReplace(t: Talent['id'], ts: Set<Talent['id']>, rng?: RNG) {
const { replacement: r } = talents.get(t)! const { replacement: r } = talents.get(t)!
if (!r) return null if (!r) return null
let picked: Talent['id'] | null = null let picked: Talent['id'] | null = null
if (r.talent) { if (r.talent) {
const filtered = r.talent.filter(([id]) => exclude(id, ts) == null) const filtered = r.talent.filter(([id]) => exclude(id, ts) == null)
picked = pickWeight(filtered) picked = pickWeight(filtered, rng)
} else if (r.grade) { } else if (r.grade) {
const filtered = GradeMap.get(r.grade)!.filter( const filtered = GradeMap.get(r.grade)!.filter(
id => exclude(id, ts) == null, id => exclude(id, ts) == null,
) )
picked = pick(filtered) picked = pick(filtered, rng)
} }
if (!picked) return null if (!picked) return null
const nts = new Set(ts) const nts = new Set(ts)
nts.add(picked) nts.add(picked)
const next = chainReplace(picked, nts) as Talent['id'][] | null const next = chainReplace(picked, nts, rng) as Talent['id'][] | null
if (next) return [picked, ...next] if (next) return [picked, ...next]
return [picked] return [picked]
} }
@@ -126,11 +126,14 @@ export interface ReplacementResult {
chains: Map<Talent['id'], Talent['id'][]> chains: Map<Talent['id'], Talent['id'][]>
} }
export function replacement(list: Iterable<Talent['id']>): ReplacementResult { export function replacement(
list: Iterable<Talent['id']>,
rng?: RNG,
): ReplacementResult {
const set = new Set(list) const set = new Set(list)
const chains = new Map() as ReplacementResult['chains'] const chains = new Map() as ReplacementResult['chains']
for (const talent of list) { for (const talent of list) {
const chain = chainReplace(talent, set) const chain = chainReplace(talent, set, rng)
if (!chain) continue if (!chain) continue
chains.set(talent, chain) chains.set(talent, chain)
chain.forEach(t => set.add(t)) chain.forEach(t => set.add(t))
@@ -173,6 +176,7 @@ const EffectRandomProperties = [
export function trigger( export function trigger(
state: GameState, state: GameState,
profile: ProfileState, profile: ProfileState,
rng?: RNG,
): TriggerResult<Talent['id']> { ): TriggerResult<Talent['id']> {
const flatState = createFlatState(state, profile) const flatState = createFlatState(state, profile)
const triggers: Talent['id'][] = [] const triggers: Talent['id'][] = []
@@ -196,7 +200,7 @@ export function trigger(
if (effect.MNY) pe.money = effect.MNY if (effect.MNY) pe.money = effect.MNY
if (effect.SPR) pe.spirit = effect.SPR if (effect.SPR) pe.spirit = effect.SPR
if (effect.RND) { if (effect.RND) {
const key = pick(EffectRandomProperties)! const key = pick(EffectRandomProperties, rng)!
pe[key] = (pe[key] ?? 0) || effect.RND pe[key] = (pe[key] ?? 0) || effect.RND
} }
draft.props = propsEffect(draft.props, pe) draft.props = propsEffect(draft.props, pe)