refactor: use dictionary for tiny activatable state

This commit is contained in:
Lukas Obermann
2024-01-08 13:57:48 +01:00
parent fa155d388d
commit 0e92425793
10 changed files with 77 additions and 32 deletions
@@ -100,12 +100,17 @@ export const selectAdventurePointsSpentOnLiturgicalChants = createSelector(
sumRatedMaps,
)
const sumTinyActivatables = (tinyActivatables: TinyActivatable[]): SpentAdventurePoints => ({
general: count(tinyActivatables, isTinyActivatableActive),
bound: 0,
})
/**
* Returns the adventure points spent on cantrips.
*/
export const selectAdventurePointsSpentOnCantrips = createSelector(
selectDynamicCantrips,
(cantrips): SpentAdventurePoints => ({ general: cantrips?.length ?? 0, bound: 0 }),
sumTinyActivatables,
)
/**
@@ -113,7 +118,7 @@ export const selectAdventurePointsSpentOnCantrips = createSelector(
*/
export const selectAdventurePointsSpentOnBlessings = createSelector(
selectDynamicBlessings,
(blessings): SpentAdventurePoints => ({ general: blessings?.length ?? 0, bound: 0 }),
sumTinyActivatables,
)
/**
@@ -14,7 +14,10 @@ import {
} from "../slices/databaseSlice.ts"
import { createSelector } from "@reduxjs/toolkit"
import { getOptions } from "../../shared/domain/activatable/activatableEntry.ts"
import {
getOptions,
isTinyActivatableActive,
} from "../../shared/domain/activatable/activatableEntry.ts"
import {
AdvantageIdentifier,
KarmaSpecialAbilityIdentifier,
@@ -89,7 +92,7 @@ export const selectVisibleBlessings = createSelector(
): [active: DisplayedActiveBlessing[], inactive: DisplayedActiveBlessing[]] =>
partition(
Object.values(staticBlessings).map(blessing => ({ kind: "blessing", static: blessing })),
staticBlessing => dynamicBlessings.includes(staticBlessing.static.id),
staticBlessing => isTinyActivatableActive(getDynamicBlessingById(staticBlessing.static.id)),
),
)
+3 -2
View File
@@ -1,9 +1,10 @@
import { createSimpleActivatableSlice } from "./simpleActivatableSlice.ts"
import { createTinyActivatableSlice } from "./tinyActivatableSlice.ts"
// eslint-disable-next-line jsdoc/require-jsdoc
export const {
actions: { addAction: addBlessing, removeAction: removeBlessing },
reducer: blessingsReducer,
} = createSimpleActivatableSlice({
} = createTinyActivatableSlice({
namespace: "blessings",
entityName: "Blessing",
getState: state => state.blessings,
+2 -2
View File
@@ -1,10 +1,10 @@
import { createSimpleActivatableSlice } from "./simpleActivatableSlice.ts"
import { createTinyActivatableSlice } from "./tinyActivatableSlice.ts"
// eslint-disable-next-line jsdoc/require-jsdoc
export const {
actions: { addAction: addCantrip, removeAction: removeCantrip },
reducer: cantripsReducer,
} = createSimpleActivatableSlice({
} = createTinyActivatableSlice({
namespace: "cantrips",
entityName: "Cantrip",
getState: state => state.cantrips,
+12 -2
View File
@@ -167,7 +167,12 @@ const staticInitialState: Omit<CharacterState, "dateCreated" | "dateLastModified
close: {},
ranged: {},
},
cantrips: [1],
cantrips: {
1: {
id: 1,
active: true,
},
},
spells: {
1: {
id: 1,
@@ -205,7 +210,12 @@ const staticInitialState: Omit<CharacterState, "dateCreated" | "dateLastModified
geodeRituals: {},
zibiljaRituals: {},
},
blessings: [1],
blessings: {
1: {
id: 1,
active: true,
},
},
liturgicalChants: {
1: {
id: 1,
@@ -1,12 +1,12 @@
import { ActionCreatorWithPayload, AnyAction, Draft, createAction } from "@reduxjs/toolkit"
import { TinyActivatableSet } from "../../shared/domain/activatable/activatableEntry.ts"
import { TinyActivatableMap } from "../../shared/domain/activatable/activatableEntry.ts"
import { Reducer, createImmerReducer } from "../../shared/utils/redux.ts"
import { CharacterState } from "./characterSlice.ts"
/**
* Functions for working with simple activatable entries.
*/
export type SimpleActivatableSlice<N extends string, E extends string> = {
export type TinyActivatableSlice<N extends string, E extends string> = {
/**
* The actions that can be dispatched to modify the state.
*/
@@ -31,11 +31,11 @@ export type SimpleActivatableSlice<N extends string, E extends string> = {
/**
* Creates a slice for a map of simple activatable entries.
*/
export const createSimpleActivatableSlice = <N extends string, E extends string>(config: {
export const createTinyActivatableSlice = <N extends string, E extends string>(config: {
namespace: N
entityName: E
getState: (state: Draft<CharacterState>) => Draft<TinyActivatableSet>
}): SimpleActivatableSlice<N, E> => {
getState: (state: Draft<CharacterState>) => Draft<TinyActivatableMap>
}): TinyActivatableSlice<N, E> => {
const addAction = createAction<number, `${N}/add${E}`>(
`${config.namespace}/add${config.entityName}`,
)
@@ -46,12 +46,15 @@ export const createSimpleActivatableSlice = <N extends string, E extends string>
const reducer = createImmerReducer((state: Draft<CharacterState>, action) => {
const focusedState = config.getState(state)
if (addAction.match(action)) {
if (!focusedState.includes(action.payload)) {
focusedState.push(action.payload)
if (!Object.hasOwn(focusedState, action.payload)) {
focusedState[action.payload] = {
id: action.payload,
active: true,
}
}
} else if (removeAction.match(action)) {
if (focusedState.includes(action.payload)) {
focusedState.splice(focusedState.indexOf(action.payload), 1)
if (Object.hasOwn(focusedState, action.payload)) {
delete focusedState[action.payload]
}
}
})
@@ -4,9 +4,25 @@ import { isNotNullish } from "../../utils/nullable.ts"
import { assertExhaustive } from "../../utils/typeSafety.ts"
/**
* A simple set of activated activatable identifiers.
* An activated activatable identifier.
*/
export type TinyActivatableSet = number[]
export type TinyActivatable = {
id: number
active: true
}
/**
* A simple map of activated activatable identifiers.
*/
export type TinyActivatableMap = {
[id: number]: TinyActivatable
}
/**
* Returns if a given tiny activatable entry is active.
*/
export const isTinyActivatableActive = (activatable: TinyActivatable | undefined): boolean =>
activatable?.active ?? false
/**
* An activatable entry.
+3 -3
View File
@@ -1,4 +1,4 @@
import { ActivatableMap, TinyActivatableSet } from "./activatable/activatableEntry.ts"
import { ActivatableMap, TinyActivatableMap } from "./activatable/activatableEntry.ts"
import { Color } from "./color.ts"
import { Energy, EnergyWithBuyBack } from "./energy.ts"
import { Pact } from "./pact.ts"
@@ -324,7 +324,7 @@ export type Character = {
ranged: RatedMap
}
cantrips: TinyActivatableSet
cantrips: TinyActivatableMap
spells: ActivatableRatedWithEnhancementsMap
rituals: ActivatableRatedWithEnhancementsMap
@@ -340,7 +340,7 @@ export type Character = {
zibiljaRituals: ActivatableRatedMap
}
blessings: TinyActivatableSet
blessings: TinyActivatableMap
liturgicalChants: ActivatableRatedWithEnhancementsMap
ceremonies: ActivatableRatedWithEnhancementsMap
+10 -4
View File
@@ -15,8 +15,13 @@ import { MagicalMelody } from "optolith-database-schema/types/magicalActions/Mag
import { ZibiljaRitual } from "optolith-database-schema/types/magicalActions/ZibiljaRitual"
import { isNotNullish } from "../../utils/nullable.ts"
import { assertExhaustive } from "../../utils/typeSafety.ts"
import { Activatable, TinyActivatableSet } from "../activatable/activatableEntry.ts"
import {
Activatable,
TinyActivatable,
isTinyActivatableActive,
} from "../activatable/activatableEntry.ts"
import { FilterApplyingRatedDependencies } from "../dependencies/filterApplyingDependencies.ts"
import { GetById } from "../getTypes.ts"
import { getHighestAttributeValue } from "./attribute.ts"
import {
ActivatableRated,
@@ -201,12 +206,13 @@ export type DisplayedActiveSpellwork =
* Filters the given list of active cantrips by tradition.
*/
export const getVisibleActiveCantrips = (
staticCantrips: Record<number, Cantrip>,
dynamicCantrips: TinyActivatableSet,
getStaticCantripById: GetById.Static.Cantrip,
dynamicCantrips: TinyActivatable[],
getIsUnfamiliar: (id: number) => boolean,
): DisplayedActiveCantrip[] =>
dynamicCantrips
.map(id => staticCantrips[id])
.filter(isTinyActivatableActive)
.map(dynamicCantrip => getStaticCantripById(dynamicCantrip.id))
.filter(isNotNullish)
.map(staticCantrip => ({
kind: "cantrip",
+5 -4
View File
@@ -14,9 +14,9 @@ import { PublicationRefs } from "optolith-database-schema/types/source/_Publicat
import { assertExhaustive } from "../../utils/typeSafety.ts"
import {
Activatable,
TinyActivatableSet,
firstLevel,
getFirstOptionOfType,
isTinyActivatableActive,
} from "../activatable/activatableEntry.ts"
import { CombinedActiveMagicalTradition } from "../activatable/magicalTradition.ts"
import {
@@ -24,6 +24,7 @@ import {
compareImprovementCost,
fromRaw,
} from "../adventurePoints/improvementCost.ts"
import { GetById } from "../getTypes.ts"
import { MagicalTraditionIdentifier } from "../identifier.ts"
import { checkPrerequisitesOfSpellwork } from "../prerequisites/fullPrerequisiteValidationForType.ts"
import {
@@ -171,8 +172,8 @@ export type DisplayedInactiveSpellwork =
* Filters the given list of inactive cantrips by tradition.
*/
export const getVisibleInactiveCantrips = (
staticCantrips: Record<number, Cantrip>,
dynamicCantrips: TinyActivatableSet,
staticCantrips: Cantrip[],
getDynamicCantripById: GetById.Dynamic.Cantrip,
activeTraditions: CombinedActiveMagicalTradition[],
getIsEntryAvailable: (src: PublicationRefs) => boolean,
getIsUnfamiliar: (id: number) => boolean,
@@ -182,7 +183,7 @@ export const getVisibleInactiveCantrips = (
: Object.values(staticCantrips)
.filter(
cantrip =>
!dynamicCantrips.includes(cantrip.id) &&
!isTinyActivatableActive(getDynamicCantripById(cantrip.id)) &&
getIsEntryAvailable(cantrip.src) &&
(cantrip.note?.tag !== "Exclusive" ||
// if the cantrip is exclusive to specific tradition, at least one of the