mirror of
https://github.com/VickScarlet/lifeRestart.git
synced 2026-08-28 17:26:47 +08:00
update: hooks, web
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
"type": "module",
|
||||
"version": "3.0.0",
|
||||
"author": "Vick Scarlet <vick@syaro.io>",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "bun test"
|
||||
@@ -15,5 +16,17 @@
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "../../package.json"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"import": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
},
|
||||
"./*": {
|
||||
"types": "./src/*.ts",
|
||||
"import": "./src/*.ts",
|
||||
"default": "./src/*.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { expect, test, describe } from 'bun:test'
|
||||
import { createState } from './state'
|
||||
import { trigger } from './achievement'
|
||||
import { AchievementOpportunity } from '@remake/data'
|
||||
import { enableMapSet } from 'immer'
|
||||
enableMapSet()
|
||||
|
||||
@@ -20,7 +21,11 @@ describe('Achievement', () => {
|
||||
|
||||
test('trigger [times:500]', () => {
|
||||
const p = { ...profile, times: 500 }
|
||||
const result = trigger('END', createState(allocation, []), p)
|
||||
const result = trigger(
|
||||
AchievementOpportunity.End,
|
||||
createState(allocation, []),
|
||||
p,
|
||||
)
|
||||
expect(result.state.achievements).toContain(101) // 既视感
|
||||
expect(result.state.achievements).toContain(102) // 孟婆愁
|
||||
expect(result.state.achievements).toContain(103) // 所有人都是我
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import type {
|
||||
Achievement,
|
||||
AchievementOpportunity,
|
||||
} from '@remake/data/achievement'
|
||||
import achievements from '@remake/data/achievement'
|
||||
import type { GameState, ProfileState } from '@/state'
|
||||
import type { Achievement, AchievementOpportunity } from '@remake/data'
|
||||
import { achievements } from '@remake/data'
|
||||
import type { GameState, ProfileState } from './state'
|
||||
import { createFlatState } from './state'
|
||||
import { check } from '@remake/condition'
|
||||
import { produce } from 'immer'
|
||||
import type { TriggerResult } from '@/game'
|
||||
import type { TriggerResult } from './game'
|
||||
|
||||
const OpportunityMap = Map.groupBy(
|
||||
achievements.keys(),
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Event } from '@remake/data/event'
|
||||
import events from '@remake/data/event'
|
||||
import type { Properties } from '@/state'
|
||||
import type { GameState, ProfileState } from '@/state'
|
||||
import { propsEffect, createFlatState } from '@/state'
|
||||
import type { Properties } from './state'
|
||||
import type { GameState, ProfileState } from './state'
|
||||
import { propsEffect, createFlatState } from './state'
|
||||
import { check as checkCondition } from '@remake/condition'
|
||||
import { produce } from 'immer'
|
||||
import type { TriggerResult } from '@/game'
|
||||
import type { TriggerResult } from './game'
|
||||
|
||||
export function check(
|
||||
event: Event['id'],
|
||||
@@ -30,7 +30,7 @@ export function trigger(
|
||||
draft.events.add(eventId)
|
||||
if (!effect) return
|
||||
if (effect.LIF) draft.life += effect.LIF
|
||||
const pe = {} as Partial<Properties>
|
||||
const pe: Partial<Properties> = {}
|
||||
if (effect.CHR) pe.charm = effect.CHR
|
||||
if (effect.INT) pe.intelligence = effect.INT
|
||||
if (effect.STR) pe.strength = effect.STR
|
||||
|
||||
+26
-39
@@ -1,26 +1,23 @@
|
||||
import ages from '@remake/data/age'
|
||||
import { propsEffect } from '@/state'
|
||||
import { enableMapSet, produce } from 'immer'
|
||||
import type { Achievement, Event, Talent } from '@remake/data'
|
||||
import { ages, AchievementOpportunity as Ao } from '@remake/data'
|
||||
import type { Allocation, GameState, ProfileState } from './state'
|
||||
import { createState, nextProfile, propsEffect } from './state'
|
||||
import { summary as stateSummary } from './state'
|
||||
import type { PullOptions, ReplacementResult } from './talent'
|
||||
import type { AdditionalPoint, AdditionalPoints } from './talent'
|
||||
import { pull, exclude, replacement, additionalPoints } from './talent'
|
||||
import { trigger as ttr } from './talent'
|
||||
import { trigger as atr } from './achievement'
|
||||
import { trigger as etr, check as ec } from './event'
|
||||
import type { RNG } from '@remake/vitex'
|
||||
import { pickWeight } from '@remake/vitex'
|
||||
import { produce, enableMapSet } from 'immer'
|
||||
enableMapSet()
|
||||
|
||||
export type * as achievement from '@/achievement'
|
||||
export type * as event from '@/event'
|
||||
export type * as talent from '@/talent'
|
||||
export type * as state from '@/state'
|
||||
import type { GameState, ProfileState } from '@/state'
|
||||
export type { GameState, ProfileState }
|
||||
export interface TriggerResult<T> {
|
||||
state: GameState
|
||||
triggers: T[]
|
||||
}
|
||||
|
||||
export { pull } from '@/talent'
|
||||
// export { summary, nextProfile } from '@/state'
|
||||
|
||||
import { replacement, additionalPoints } from '@/talent'
|
||||
import type { ReplacementResult, AdditionalPoints } from '@/talent'
|
||||
import type { RNG } from '@remake/vitex'
|
||||
|
||||
export interface TalentsPickedResult {
|
||||
talents: ReplacementResult
|
||||
additionalPoints: AdditionalPoints
|
||||
@@ -34,8 +31,6 @@ export function talentsPicked(
|
||||
return { talents: r, additionalPoints: ap }
|
||||
}
|
||||
|
||||
import { createState } from '@/state'
|
||||
|
||||
export interface StartResult {
|
||||
state: GameState
|
||||
achievements: Achievement['id'][]
|
||||
@@ -45,19 +40,9 @@ export function start(
|
||||
...args: Parameters<typeof createState>
|
||||
): StartResult {
|
||||
const state = createState(...args)
|
||||
const ar = achievementTrigger('START', state, profile)
|
||||
const ar = atr(Ao.Start, state, profile)
|
||||
return { state: ar.state, achievements: ar.triggers }
|
||||
}
|
||||
|
||||
import type { Achievement } from '@remake/data/achievement'
|
||||
import type { Event } from '@remake/data/event'
|
||||
import type { Talent } from '@remake/data/talent'
|
||||
import { trigger as achievementTrigger } from '@/achievement'
|
||||
import { trigger as eventTrigger } from '@/event'
|
||||
import { trigger as talentTrigger } from '@/talent'
|
||||
import { check as eventCheck } from '@/event'
|
||||
import { pickWeight } from '@remake/vitex'
|
||||
|
||||
export interface NextResult {
|
||||
state: GameState
|
||||
age: number
|
||||
@@ -76,13 +61,13 @@ export function next(
|
||||
draft.props = propsEffect(state.props, { age: 1 })
|
||||
})
|
||||
const age = s.props.current.age
|
||||
const tr = talentTrigger(s, profile, rng)
|
||||
const tr = ttr(s, profile, rng)
|
||||
const events = ages
|
||||
.get(age)!
|
||||
.event.filter(([e]) => eventCheck(e, tr.state, profile))
|
||||
.event.filter(([e]) => ec(e, tr.state, profile))
|
||||
const event = pickWeight(events, rng)!
|
||||
const er = eventTrigger(event, tr.state, profile)
|
||||
const ar = achievementTrigger('TRAJECTORY', er.state, profile)
|
||||
const er = etr(event, tr.state, profile)
|
||||
const ar = atr(Ao.Trajectory, er.state, profile)
|
||||
const end = ar.state.life < 1
|
||||
return {
|
||||
state: ar.state,
|
||||
@@ -94,8 +79,6 @@ export function next(
|
||||
}
|
||||
}
|
||||
|
||||
import { summary as stateSummary } from '@/state'
|
||||
|
||||
export interface SummaryResult {
|
||||
state: GameState
|
||||
summary: number
|
||||
@@ -105,12 +88,11 @@ export function summary(
|
||||
state: GameState,
|
||||
profile: ProfileState,
|
||||
): SummaryResult {
|
||||
const ar = achievementTrigger('SUMMARY', state, profile)
|
||||
const ar = atr(Ao.Summary, state, profile)
|
||||
const s = stateSummary(ar.state)
|
||||
return { state: ar.state, summary: s, achievements: ar.triggers }
|
||||
}
|
||||
|
||||
import { nextProfile } from '@/state'
|
||||
export interface EndResult {
|
||||
profile: ProfileState
|
||||
achievements: Achievement['id'][]
|
||||
@@ -121,7 +103,12 @@ export function end(
|
||||
profile: ProfileState,
|
||||
lockedTalent?: Talent['id'],
|
||||
) {
|
||||
const ar = achievementTrigger('END', state, profile)
|
||||
const ar = atr(Ao.End, state, profile)
|
||||
const p = nextProfile(profile, ar.state, lockedTalent)
|
||||
return { profile: p, achievements: ar.triggers }
|
||||
}
|
||||
|
||||
export { pull, exclude }
|
||||
export type { GameState, ProfileState, Allocation, RNG }
|
||||
export type { PullOptions, ReplacementResult }
|
||||
export type { AdditionalPoint, AdditionalPoints }
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from '@/game'
|
||||
export * from './game'
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { expect, test, describe } from 'bun:test'
|
||||
import { parse, type ConditionNode } from '@remake/condition'
|
||||
|
||||
import achievements from '@remake/data/achievement'
|
||||
import events from '@remake/data/event'
|
||||
import talents from '@remake/data/talent'
|
||||
|
||||
import { achievements, events, talents } from '@remake/data'
|
||||
import type { GameState, ProfileState, Properties } from './state'
|
||||
import { createFlatState, createHLProperties, propsEffect } from './state'
|
||||
import { SupportedFlatStateKeys } from './state'
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { Talent } from '@remake/data/talent'
|
||||
import type { Event } from '@remake/data/event'
|
||||
import type { Achievement } from '@remake/data/achievement'
|
||||
import type { Achievement, Event, Talent } from '@remake/data'
|
||||
import { produce } from 'immer'
|
||||
import { sum } from '@remake/vitex'
|
||||
import { sum, keys } from '@remake/vitex'
|
||||
|
||||
/** 基础的属性 */
|
||||
export interface Properties {
|
||||
@@ -112,7 +110,7 @@ type FlatMapper<Key extends FlatStateKey> = (
|
||||
state: FlatTarget,
|
||||
) => FlatState[Key]
|
||||
|
||||
const FlatMappers = {
|
||||
const FlatMappers: { [Key in FlatStateKey]: FlatMapper<Key> } = {
|
||||
AGE: state => state.game.props.current.age,
|
||||
CHR: state => state.game.props.current.charm,
|
||||
INT: state => state.game.props.current.intelligence,
|
||||
@@ -139,9 +137,9 @@ const FlatMappers = {
|
||||
ATLT: state => state.profile.talents,
|
||||
AACH: state => state.profile.achievements,
|
||||
SUM: ({ game }) => summary(game),
|
||||
} as { [Key in FlatStateKey]: FlatMapper<Key> }
|
||||
}
|
||||
|
||||
export const SupportedFlatStateKeys = new Set(Object.keys(FlatMappers))
|
||||
export const SupportedFlatStateKeys = new Set(keys(FlatMappers))
|
||||
|
||||
const flatStateHandle = {
|
||||
get<Key extends FlatStateKey>(target: FlatTarget, prop: Key) {
|
||||
@@ -175,7 +173,7 @@ export function propsEffect(hlp: HLProperties, effect: Partial<Properties>) {
|
||||
export function highestProperties(a: Properties, b?: Properties): Properties {
|
||||
if (!b) return { ...a }
|
||||
const result = {} as Properties
|
||||
for (const key of Object.keys(a) as (keyof Properties)[]) {
|
||||
for (const key of keys(a)) {
|
||||
result[key] = Math.max(a[key], b[key])
|
||||
}
|
||||
return result
|
||||
@@ -184,7 +182,7 @@ export function highestProperties(a: Properties, b?: Properties): Properties {
|
||||
export function lowestProperties(a: Properties, b?: Properties): Properties {
|
||||
if (!b) return { ...a }
|
||||
const result = {} as Properties
|
||||
for (const key of Object.keys(a) as (keyof Properties)[]) {
|
||||
for (const key of keys(a)) {
|
||||
result[key] = Math.min(a[key], b[key])
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -2,8 +2,7 @@ import { expect, test, describe } from 'bun:test'
|
||||
import type { ProfileState } from './state'
|
||||
import type { PullOptions } from './talent'
|
||||
import { pull, exclude, additionalPoints, replacement } from './talent'
|
||||
import { createState } from './state'
|
||||
import talents from '@remake/data/talent'
|
||||
import { talents } from '@remake/data'
|
||||
import { produce } from 'immer'
|
||||
import { enableMapSet } from 'immer'
|
||||
enableMapSet()
|
||||
|
||||
+10
-10
@@ -1,12 +1,12 @@
|
||||
import type { Talent, TalentGrade } from '@remake/data/talent'
|
||||
import talents from '@remake/data/talent'
|
||||
import type { Properties } from '@/state'
|
||||
import type { GameState, ProfileState } from '@/state'
|
||||
import type { Talent, TalentGrade } from '@remake/data'
|
||||
import { talents } from '@remake/data'
|
||||
import type { Properties } from './state'
|
||||
import type { GameState, ProfileState } from './state'
|
||||
import { propsEffect, createFlatState } from './state'
|
||||
import { check } from '@remake/condition'
|
||||
import { pick, pickWeight, type RNG } from '@remake/vitex'
|
||||
import { produce } from 'immer'
|
||||
import type { TriggerResult } from '@/game'
|
||||
import type { TriggerResult } from './game'
|
||||
|
||||
const Grades: TalentGrade[] = [0, 1, 2, 3] as const
|
||||
const GradeMap = Map.groupBy(
|
||||
@@ -16,10 +16,6 @@ const GradeMap = Map.groupBy(
|
||||
|
||||
export const count = talents.size
|
||||
|
||||
export function get(talent: number) {
|
||||
return talents.get(talent)
|
||||
}
|
||||
|
||||
export type PullRate = Map<TalentGrade, number>
|
||||
export type PullRateAddition = {
|
||||
mode: 'add' | 'multiply'
|
||||
@@ -64,7 +60,11 @@ export interface PullOptions {
|
||||
rate: RateOptions
|
||||
}
|
||||
|
||||
export function pull(options: PullOptions, profile: ProfileState, rng?: RNG) {
|
||||
export function pull(
|
||||
options: PullOptions,
|
||||
profile: ProfileState,
|
||||
rng?: RNG,
|
||||
): Talent['id'][] {
|
||||
const rate = Array.from(
|
||||
talentRateWithAddition(options.rate, profile).entries(),
|
||||
)
|
||||
|
||||
@@ -1,32 +1,4 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"types": ["bun"],
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noPropertyAccessFromIndexSignature": false,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["**/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user