update: character allocation

This commit is contained in:
Vick Scarlet
2026-08-16 20:06:16 +08:00
committed by 神戸小鳥
parent f4204601ee
commit a0e3f1b355
10 changed files with 149 additions and 81 deletions
+60 -22
View File
@@ -1,8 +1,9 @@
import { useCallback } from 'react'
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
import { useConfig, useReplaced } from '.'
import { atom, useAtomValue, useSetAtom } from 'jotai'
import { useConfig, useReplaced, useIsClassic } from '.'
import type { Allocation } from '@remake/core'
import { keys, shuffle, random as frandom, type RNG } from '@remake/vitex'
import { keys, shuffle, zoneFit, random } from '@remake/vitex'
import type { RNG } from '@remake/vitex'
export type UserAllocation = Omit<Allocation, 'spirit'>
const init: UserAllocation = {
@@ -11,50 +12,86 @@ const init: UserAllocation = {
strength: 0,
money: 0,
}
export const baseAllocAtom = atom<UserAllocation>({ ...init })
export const allocAtom = atom<UserAllocation>({ ...init })
const alloced = (alloc: UserAllocation) =>
Object.values(alloc).reduce((a, b) => a + b, 0)
export const useAllocReset = () => {
const setBaseAlloc = useSetAtom(baseAllocAtom)
const setAlloc = useSetAtom(allocAtom)
return useCallback(() => setAlloc({ ...init }), [setAlloc])
return useCallback(() => {
setBaseAlloc({ ...init })
setAlloc({ ...init })
}, [setBaseAlloc, setAlloc])
}
export const useBaseAlloc = () => useAtomValue(baseAllocAtom)
export const useAlloc = () => {
const base = useAtomValue(baseAllocAtom)
const alloc = useAtomValue(allocAtom)
const final = {
charm: base.charm + alloc.charm,
intelligence: base.intelligence + alloc.intelligence,
strength: base.strength + alloc.strength,
money: base.money + alloc.money,
}
return { base, alloc, final }
}
export const useAlloc = () => useAtomValue(allocAtom)
export const usePoints = () => {
const { points } = useConfig()
const isClassic = useIsClassic()
const { additionalPoints } = useReplaced()
return Math.max(points + additionalPoints.points, 0)
const additional = additionalPoints.points
if (!isClassic) {
const base = useAtomValue(baseAllocAtom)
return { base: alloced(base), total: additional, additional }
}
const { points } = useConfig()
return { base: points, total: points + additional, additional }
}
export const useLeftPoints = () => {
const points = usePoints()
const alloc = useAtomValue(allocAtom)
return points - alloced(alloc)
const ca = alloced(alloc)
const left = points.total - ca
return { ...points, left, alloced: ca }
}
export const useAllocBefore = () => {
const { allocate } = useConfig()
const { total } = usePoints()
const isClassic = useIsClassic()
const isPositive = total >= 0
const limit = isClassic
? allocate
: Math.min(Math.ceil(Math.abs(total) / 2), allocate) *
(isPositive ? 1 : -1)
return { total, limit, isPositive, isClassic }
}
export const useAllocator = () => {
const { allocate } = useConfig()
const total = usePoints()
const [alloc, setAlloc] = useAtom(allocAtom)
const { total, limit } = useAllocBefore()
const alloc = useAlloc()
const setAlloc = useSetAtom(allocAtom)
const allocator = useCallback(
(key: keyof UserAllocation, value: number) => {
setAlloc(prev => {
const left = total - alloced(prev) + prev[key]
const max = Math.min(left, allocate)
const final = Math.max(Math.min(max, value), 0)
if (prev[key] === final) return prev
const last = prev[key]
const left = total - alloced(prev) + last
const max = zoneFit(left, [0, limit])
const final = zoneFit(value, [0, max])
if (last === final) return prev
return { ...prev, [key]: final }
})
},
[allocate, total, setAlloc],
[limit, total, setAlloc],
)
return [alloc, allocator] as const
}
export const usePointRandomizer = () => {
const { allocate } = useConfig()
const total = usePoints()
const { total, limit } = useAllocBefore()
const setAlloc = useSetAtom(allocAtom)
return useCallback(
(rng?: RNG) => {
@@ -63,15 +100,16 @@ export const usePointRandomizer = () => {
const alloc = { ...init }
while (suffled.length) {
const key = suffled.pop()!
const max = Math.min(allocate, left)
const min = Math.max(0, left - suffled.length * allocate)
const value = frandom(max, min, rng)
const n = suffled.length
const max = zoneFit(limit, [0, left])
const min = zoneFit(left - n * limit, [0, limit])
const value = random(max, min, rng)
alloc[key] = value
left -= value
}
setAlloc(alloc)
},
[allocate, total, setAlloc],
[total, limit, setAlloc],
)
}