afnm-types 0.6.43 → 0.6.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/buff.d.ts CHANGED
@@ -4,6 +4,14 @@ import { CombatStatistic, Scaling } from './stat';
4
4
  import { DamageType } from './DamageType';
5
5
  import type { CombatEntity } from './entity';
6
6
  export type TechniqueCondition = ChanceTechniqueCondition | BuffTechniqueCondition | HpTechniqueCondition | ConditionTechniqueCondition | InventoryItemTechniqueCondition;
7
+ interface BaseTechniqueCondition {
8
+ /**
9
+ * When true, triggered effects (triggeredBuffEffects) on this buff will still
10
+ * run even when this condition fails. The condition still blocks normal
11
+ * onTechniqueEffects and onRoundEffects.
12
+ */
13
+ allowTriggers?: boolean;
14
+ }
7
15
  export type DamageModifier = MultiplyDamageModifier | ReduceDamageModifier | ExpressionDamageModifier;
8
16
  interface MultiplyDamageModifier {
9
17
  kind: 'multiply';
@@ -17,28 +25,28 @@ interface ExpressionDamageModifier {
17
25
  kind: 'expression';
18
26
  expression: string;
19
27
  }
20
- interface ChanceTechniqueCondition {
28
+ interface ChanceTechniqueCondition extends BaseTechniqueCondition {
21
29
  kind: 'chance';
22
30
  percentage: number;
23
31
  }
24
- interface BuffTechniqueCondition {
32
+ interface BuffTechniqueCondition extends BaseTechniqueCondition {
25
33
  kind: 'buff';
26
34
  buff: Buff | 'self';
27
35
  count: number;
28
36
  mode: 'more' | 'less' | 'equal';
29
37
  hideBuff?: boolean;
30
38
  }
31
- interface HpTechniqueCondition {
39
+ interface HpTechniqueCondition extends BaseTechniqueCondition {
32
40
  kind: 'hp';
33
41
  percentage: number;
34
42
  mode: 'more' | 'less' | 'equal';
35
43
  }
36
- interface ConditionTechniqueCondition {
44
+ interface ConditionTechniqueCondition extends BaseTechniqueCondition {
37
45
  kind: 'condition';
38
46
  condition: string;
39
47
  tooltip?: string;
40
48
  }
41
- interface InventoryItemTechniqueCondition {
49
+ interface InventoryItemTechniqueCondition extends BaseTechniqueCondition {
42
50
  kind: 'inventoryItem';
43
51
  itemName: string;
44
52
  count: number;
@@ -4,7 +4,7 @@ import { OverridableComponent } from '@mui/material/OverridableComponent';
4
4
  import { Buff } from './buff';
5
5
  import { EnemyEntity } from './entity';
6
6
  import { EventStep } from './event';
7
- import { Item, ItemDesc, ItemKind, MountItem } from './item';
7
+ import { Item, ItemKind, MountItem } from './item';
8
8
  import { Realm, RealmProgress } from './realm';
9
9
  import { IntimateTrait } from './dualCultivation';
10
10
  export interface Character {
@@ -16,6 +16,7 @@ export interface Character {
16
16
  condition: string;
17
17
  definitions: CharacterDefinition[];
18
18
  relationship?: CharacterRelationshipDefinition[];
19
+ relationshipPaths?: Record<string, CharacterRelationshipDefinition[]>;
19
20
  followInteraction?: FollowCharacterDefinition;
20
21
  portrait: string;
21
22
  image: string;
@@ -128,6 +129,7 @@ export interface CharacterState {
128
129
  sparCooldown: number;
129
130
  approval: number;
130
131
  relationshipIndex: number;
132
+ relationshipPath?: string;
131
133
  seenRelationshipProgressEvent: boolean;
132
134
  giftedKeys: string[];
133
135
  challengeCooldown: number;
@@ -171,9 +173,12 @@ export interface GiftCharacterInteraction extends BaseCharacterInteraction {
171
173
  introSteps: EventStep[];
172
174
  item: string;
173
175
  amount: number;
174
- alternates?: ItemDesc[];
175
176
  acceptSteps: EventStep[];
176
177
  declineSteps: EventStep[];
178
+ improvedItem?: string;
179
+ improvedAcceptSteps?: EventStep[];
180
+ veryImprovedItem?: string;
181
+ veryImprovedAcceptSteps?: EventStep[];
177
182
  }
178
183
  export interface CraftingCharacterInteraction extends BaseCharacterInteraction {
179
184
  itemKinds: ItemKind[];
@@ -37,6 +37,16 @@ export type GameCloseButtonFC = React.ForwardRefRenderFunction<HTMLButtonElement
37
37
  clickSfx?: SoundEffectName;
38
38
  onClose?: () => void;
39
39
  }, 'children'>>;
40
+ export type GameButtonExoticFC = React.ForwardRefExoticComponent<React.PropsWithoutRef<ButtonProps & {
41
+ keybinding?: string;
42
+ keyPriority?: number;
43
+ fancyBorder?: boolean;
44
+ keyContext?: string;
45
+ }> & React.RefAttributes<HTMLButtonElement>>;
46
+ export type GameIconButtonExoticFC = React.ForwardRefExoticComponent<React.PropsWithoutRef<IconButtonProps & {
47
+ hoverSfx?: SoundEffectName;
48
+ clickSfx?: SoundEffectName;
49
+ }> & React.RefAttributes<HTMLButtonElement>>;
40
50
  export interface BackgroundImageProps {
41
51
  image: string;
42
52
  screenEffect: ScreenEffectType;
@@ -17,6 +17,7 @@ export declare const craftingConditionToColour: Record<CraftingCondition, string
17
17
  export declare const craftingConditionToIcon: Record<CraftingCondition, OverridableComponent<SvgIconTypeMap<{}, 'svg'>>>;
18
18
  export interface RecipeConditionEffect {
19
19
  name: string;
20
+ displayName?: Translatable;
20
21
  colour: string;
21
22
  conditionEffects: Record<CraftingCondition, {
22
23
  tooltip: Translatable;
@@ -39,9 +39,16 @@ export interface CraftingEffectTracking {
39
39
  stabilitySpend: number;
40
40
  stabilityRestore: number;
41
41
  }
42
+ export interface ChanceAttempt {
43
+ p: number;
44
+ success: boolean;
45
+ }
42
46
  export interface ActionTracking {
43
47
  name: string;
44
48
  count: number;
49
+ chanceTrials: number;
50
+ chanceSuccesses: number;
51
+ attempts: ChanceAttempt[];
45
52
  }
46
53
  export interface ProgressState {
47
54
  completion: number;
package/dist/entity.d.ts CHANGED
@@ -310,6 +310,8 @@ export interface CombatEntity {
310
310
  partyMemberIndex?: number;
311
311
  /** UUID assigned at creation — only present on PlayerParty and EnemyParty entities */
312
312
  partyId?: string;
313
+ /** When true, critchance is forced to 0 for this entity (used in training ground) */
314
+ noCrit?: boolean;
313
315
  }
314
316
  export type StanceRule = SingleStance | RandomStance;
315
317
  export interface SingleStance {
package/dist/event.d.ts CHANGED
@@ -23,6 +23,7 @@ export interface TriggeredEvent {
23
23
  };
24
24
  usesCooldown?: boolean;
25
25
  minLocationCharacters?: number;
26
+ requiredLocationCharacters?: string[];
26
27
  }
27
28
  export interface GameEvent {
28
29
  location: string;
@@ -32,7 +33,7 @@ export interface GameEvent {
32
33
  value: number;
33
34
  }[];
34
35
  }
35
- export type EventStep = TextStep | SpeechStep | CombatStep | CraftingStep | ChoiceStep | ConditionalStep | SetFlagStep | ExitStep | CreateBuffStep | ConsumeBuffStep | ChangeLocationStep | AddItemStep | RemoveItemStep | AddQuestStep | ChangeMoneyStep | ChangeFavourStep | AddDestinyStep | ChangeReputationStep | QiStep | UnlockLocationStep | ClearCharacterStep | SetCharacterStep | LabelStep | GotoLabelStep | UnlockCraftingTechniqueStep | TalkToCharacterStep | TradeWithCharacterStep | CraftWithCharacterStep | FightCharacterStep | MarkBeatCharacterStep | MarkDidEncounterStep | ChangeHpStep | PassTimeStep | ReportAnalyticsStep | ApprovalStep | ProgressRelationshipStep | MarkGiftedStep | UpdateCharacterDefinitionStep | AuctionStep | MarkCalendarEventCompleteStep | AddMultipleItemStep | AdvanceMysticalRegionStep | CraftSkillStep | TournamentStep | TeamUpStep | AddFollowerStep | ClearTeamUpStep | UnlockAltarStep | DropItemStep | SetAltarCooldownStep | CompressCoreStep | ChangeScreenStep | UnlockTechniqueStep | UnlockAuctionTechniqueStep | AddRecipeStep | AddManualStep | LearnNpcStancesStep | ReplaceItemStep | DualCultivationStep | ChangeBGMStep | ClearChangeBGMStep | AddGuildApprovalStep | AdvanceGuildRankStep | OverridePlayerRealmStep | SetAidBreakthroughCooldownStep | StoneCuttingStep | GiveItemStep | ChangePhysicalStatStep | ChangeSocialStatStep;
36
+ export type EventStep = TextStep | SpeechStep | CombatStep | CraftingStep | ChoiceStep | ConditionalStep | SetFlagStep | ExitStep | CreateBuffStep | ConsumeBuffStep | ChangeLocationStep | AddItemStep | RemoveItemStep | AddQuestStep | ChangeMoneyStep | ChangeFavourStep | AddDestinyStep | ChangeReputationStep | QiStep | UnlockLocationStep | ClearCharacterStep | SetCharacterStep | LabelStep | GotoLabelStep | UnlockCraftingTechniqueStep | TalkToCharacterStep | TradeWithCharacterStep | CraftWithCharacterStep | FightCharacterStep | MarkBeatCharacterStep | MarkDidEncounterStep | ChangeHpStep | PassTimeStep | ReportAnalyticsStep | ApprovalStep | ProgressRelationshipStep | MarkGiftedStep | UpdateCharacterDefinitionStep | AuctionStep | MarkCalendarEventCompleteStep | AddMultipleItemStep | AdvanceMysticalRegionStep | CraftSkillStep | TournamentStep | TeamUpStep | AddFollowerStep | BreakPartyStep | ClearTeamUpStep | UnlockAltarStep | DropItemStep | SetAltarCooldownStep | CompressCoreStep | ChangeScreenStep | UnlockTechniqueStep | UnlockAuctionTechniqueStep | AddRecipeStep | AddManualStep | LearnNpcStancesStep | ReplaceItemStep | DualCultivationStep | ChangeBGMStep | ClearChangeBGMStep | AddGuildApprovalStep | AdvanceGuildRankStep | OverridePlayerRealmStep | SetAidBreakthroughCooldownStep | StoneCuttingStep | GiveItemStep | ChangePhysicalStatStep | ChangeSocialStatStep | SelectRelationshipPathStep;
36
37
  export interface TextStep {
37
38
  kind: 'text';
38
39
  condition?: string;
@@ -87,7 +88,7 @@ export type EventChoiceCondition = RealmCondition | PhysicalStatisticCondition |
87
88
  export interface RealmCondition {
88
89
  kind: 'realm';
89
90
  realm: Realm;
90
- mode?: 'more' | 'exact' | 'less';
91
+ mode?: 'more' | 'exact' | 'less' | 'lessOrEqual';
91
92
  }
92
93
  interface PhysicalStatisticCondition {
93
94
  kind: 'physicalStatistic';
@@ -369,6 +370,12 @@ export interface ProgressRelationshipStep {
369
370
  condition?: string;
370
371
  character: string;
371
372
  }
373
+ export interface SelectRelationshipPathStep {
374
+ kind: 'selectRelationshipPath';
375
+ condition?: string;
376
+ character: string;
377
+ path: string;
378
+ }
372
379
  export interface UpdateCharacterDefinitionStep {
373
380
  kind: 'updateCharacterDefinition';
374
381
  condition?: string;
@@ -433,6 +440,10 @@ export interface AddFollowerStep {
433
440
  character: string;
434
441
  followDef: FollowCharacterDefinition | undefined;
435
442
  }
443
+ export interface BreakPartyStep {
444
+ kind: 'breakParty';
445
+ condition?: string;
446
+ }
436
447
  export interface ClearTeamUpStep {
437
448
  kind: 'clearTeamUp';
438
449
  condition?: string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The current game version, injected at compile time from package.json.
3
+ * Mod authors can use this as the `gameVersion` field in `getMetadata()`.
4
+ *
5
+ * @example
6
+ * import { GAME_VERSION } from 'afnm-types';
7
+ *
8
+ * export function getMetadata() {
9
+ * return {
10
+ * name: 'My Mod',
11
+ * version: '1.0.0',
12
+ * description: 'My awesome mod',
13
+ * author: { name: 'Me' },
14
+ * gameVersion: GAME_VERSION,
15
+ * };
16
+ * }
17
+ */
18
+ export declare const GAME_VERSION: string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The current game version, injected at compile time from package.json.
3
+ * Mod authors can use this as the `gameVersion` field in `getMetadata()`.
4
+ *
5
+ * @example
6
+ * import { GAME_VERSION } from 'afnm-types';
7
+ *
8
+ * export function getMetadata() {
9
+ * return {
10
+ * name: 'My Mod',
11
+ * version: '1.0.0',
12
+ * description: 'My awesome mod',
13
+ * author: { name: 'Me' },
14
+ * gameVersion: GAME_VERSION,
15
+ * };
16
+ * }
17
+ */
18
+ export const GAME_VERSION = typeof __GAME_VERSION__ !== 'undefined' ? __GAME_VERSION__ : '';
package/dist/index.d.ts CHANGED
@@ -32,3 +32,4 @@ export * from './tournament';
32
32
  export * from './CharacterRequestEncounter';
33
33
  export * from './QuestionAnswer';
34
34
  export * from './RecipeDifficulty';
35
+ export type { RootState } from './reduxState';
package/dist/item.d.ts CHANGED
@@ -12,7 +12,7 @@ import { Realm, RealmProgress } from './realm';
12
12
  import { RecipeDifficulty } from './RecipeDifficulty';
13
13
  import { CombatStatsMap, CraftingStatsMap, PhysicalStatistic, Scaling, SocialStatistic } from './stat';
14
14
  import { Technique, TechniqueEffect } from './technique';
15
- export declare const itemKinds: readonly ["clothing", "talisman", "artefact", "mount", "cauldron", "flame", "upgrade", "fruit", "elixir", "recipe", "technique", "action", "transport_seal", "enchantment", "pill", "reagent", "concoction", "consumable", "recuperation", "formation", "breakthrough", "pillar_shard", "material", "flare", "mystical_key", "condensation_art", "blueprint", "trophy", "treasure", "token", "life_essence", "device", "manual"];
15
+ export declare const itemKinds: readonly ["clothing", "talisman", "artefact", "mount", "cauldron", "flame", "upgrade", "fruit", "elixir", "recipe", "technique", "action", "transport_seal", "enchantment", "pill", "reagent", "concoction", "consumable", "recuperation", "formation", "breakthrough", "pillar_shard", "material", "flare", "mystical_key", "condensation_art", "blueprint", "trophy", "treasure", "token", "life_essence", "device", "manual", "pillar_pattern"];
16
16
  export type ItemKind = (typeof itemKinds)[number];
17
17
  export declare const itemKindToName: {
18
18
  [key in ItemKind]: string;
@@ -25,7 +25,7 @@ export type ItemCostMap = {
25
25
  };
26
26
  export declare const buyItemCostMap: ItemCostMap;
27
27
  export declare const sellItemCostMap: ItemCostMap;
28
- export type Item = TechniqueItem | TechniqueCrystalItem | TechniqueShardItem | TechniqueEnhancementDust | TransportSealItem | SpiritFruitItem | RecipeItem | ElixirItem | TreasureItem | CraftingItem | ClothingItem | TalismanItem | ArtefactItem | PillItem | ConcoctionItem | CombatItem | CauldronItem | FlameItem | BreakthroughItem | RecuperationItem | MountItem | FlareItem | CraftingTechniqueItem | EnchantmentItem | MysticalKeyItem | CondensationArtItem | FormationItem | PillarShardItem | TrophyItem | BlueprintItem | TokenItem | UpgradeItem | CraftingReagentItem | LifeEssenceItem | DeviceItem | ManualItem;
28
+ export type Item = TechniqueItem | TechniqueCrystalItem | TechniqueShardItem | TechniqueEnhancementDust | TransportSealItem | SpiritFruitItem | RecipeItem | ElixirItem | TreasureItem | CraftingItem | ClothingItem | TalismanItem | ArtefactItem | PillItem | ConcoctionItem | CombatItem | CauldronItem | FlameItem | BreakthroughItem | RecuperationItem | MountItem | FlareItem | CraftingTechniqueItem | EnchantmentItem | MysticalKeyItem | CondensationArtItem | FormationItem | PillarShardItem | TrophyItem | BlueprintItem | TokenItem | UpgradeItem | CraftingReagentItem | LifeEssenceItem | DeviceItem | ManualItem | PillarPatternItem;
29
29
  interface ItemBase {
30
30
  kind: ItemKind;
31
31
  name: string;
@@ -450,6 +450,9 @@ export interface PillarShardItem extends ItemBase {
450
450
  maxInstances?: number;
451
451
  variants?: PillarShardVariant[];
452
452
  stability?: number;
453
+ portal?: {
454
+ type: 'entrance' | 'exit';
455
+ };
453
456
  inputs?: {
454
457
  left?: number;
455
458
  right?: number;
@@ -491,4 +494,21 @@ export interface LifeEssenceItem extends ItemBase {
491
494
  techniques: Technique[];
492
495
  }[];
493
496
  }
497
+ export interface PillarPatternItem extends ItemBase {
498
+ kind: 'pillar_pattern';
499
+ shards: {
500
+ name: string;
501
+ pos: {
502
+ x: number;
503
+ y: number;
504
+ rotation: number;
505
+ };
506
+ overrideInput?: {
507
+ top?: number;
508
+ bottom?: number;
509
+ left?: number;
510
+ right?: number;
511
+ };
512
+ }[];
513
+ }
494
514
  export {};
package/dist/item.js CHANGED
@@ -32,6 +32,7 @@ export const itemKinds = [
32
32
  'life_essence',
33
33
  'device',
34
34
  'manual',
35
+ 'pillar_pattern',
35
36
  ];
36
37
  export const itemKindToName = {
37
38
  clothing: 'Clothing',
@@ -67,6 +68,7 @@ export const itemKindToName = {
67
68
  life_essence: 'Life Essence',
68
69
  device: 'Device',
69
70
  manual: 'Manual',
71
+ pillar_pattern: 'Pillar Pattern',
70
72
  };
71
73
  export const itemKindPluralToName = {
72
74
  clothing: 'Clothing',
@@ -102,6 +104,7 @@ export const itemKindPluralToName = {
102
104
  life_essence: 'Life Essences',
103
105
  device: 'Devices',
104
106
  manual: 'Manuals',
107
+ pillar_pattern: 'Pillar Patterns',
105
108
  };
106
109
  export const buyItemCostMap = {
107
110
  technique: 3000,
@@ -137,6 +140,7 @@ export const buyItemCostMap = {
137
140
  life_essence: 5000,
138
141
  device: 2500,
139
142
  manual: 15000,
143
+ pillar_pattern: 3000,
140
144
  };
141
145
  export const sellItemCostMap = {
142
146
  technique: 400,
@@ -172,6 +176,7 @@ export const sellItemCostMap = {
172
176
  life_essence: 1000,
173
177
  device: 600,
174
178
  manual: 0,
179
+ pillar_pattern: 500,
175
180
  };
176
181
  export const pillKindToName = {
177
182
  combat: 'Combat Pill',
@@ -37,4 +37,5 @@ export const itemTypeToHarmonyType = {
37
37
  upgrade: 'forge',
38
38
  life_essence: 'resonance',
39
39
  manual: 'resonance',
40
+ pillar_pattern: 'resonance',
40
41
  };
@@ -96,6 +96,27 @@ export interface LocationEvent {
96
96
  min: number;
97
97
  max: number;
98
98
  };
99
+ /**
100
+ * Marks this event as part of the global pity pool.
101
+ *
102
+ * **Pity counter**: All pity events share a single global attempt counter
103
+ * (`globalSpecialEventPity` flag). Each exploration where at least one pity
104
+ * event was eligible but none fired increments the counter; any pity event
105
+ * firing resets it to zero. The event's rarity weight is multiplied by
106
+ * min(1 + counter × 0.1, 5) — reaching 5× base weight after roughly 40
107
+ * consecutive failed attempts.
108
+ *
109
+ * **Exclusivity multiplier**: Before the pity counter is applied, each pity
110
+ * event receives a player-specific multiplier drawn from a fixed odds list
111
+ * (e.g. [10×, 8×, 4×, 2×, 1×]). The list is shuffled per-player using a
112
+ * hash of their name, so every player has the same distribution of chances
113
+ * but with different events in each tier. This guarantees every player
114
+ * stumbles into at least one exclusive event easily while having to actively
115
+ * seek out others. A floor of 1 weight slot is always kept so the pity
116
+ * counter can still accumulate and eventually guarantee the event for every
117
+ * player.
118
+ */
119
+ pity?: true;
99
120
  }
100
121
  export interface LocationMapEvent {
101
122
  event: EventStep[];
package/dist/mod.d.ts CHANGED
@@ -16,6 +16,7 @@ import { Guild } from './guild';
16
16
  import { Crop } from './herbField';
17
17
  import { Enchantment, EnchantmentDesc, Item, ItemDesc, ManualItem, RecipeItem, UncutStonePool } from './item';
18
18
  import { ConditionalLink, ExplorationLink, GameLocation, LocationBuilding, LocationEnemy, LocationEvent, LocationMapEvent, SectMission, CraftingMission } from './location';
19
+ import { Rarity } from './rarity';
19
20
  import { MineChamber } from './mine';
20
21
  import { Quest } from './quest';
21
22
  import { Realm, RealmProgress } from './realm';
@@ -33,7 +34,7 @@ import { ItemKind } from './item';
33
34
  import { SoundEffectName } from './audio';
34
35
  import { ScreenEffectType } from './ScreenEffectType';
35
36
  import { RootState } from './reduxState';
36
- import { GameButtonFC, GameDialogFC, GameIconButtonFC, MemoBackgroundImageFC } from './components';
37
+ import { GameDialogFC, GameButtonExoticFC, GameIconButtonExoticFC, MemoBackgroundImageFC } from './components';
37
38
  import { PuppetType } from './trainingGround';
38
39
  import { TechniqueElement } from './element';
39
40
  import { AlternativeStart } from './alternativeStart';
@@ -79,10 +80,20 @@ export interface ModMetadata {
79
80
  author: {
80
81
  name: string;
81
82
  };
83
+ /** The game version this mod was compiled against. Set this to GAME_VERSION imported from afnm-types. */
84
+ gameVersion?: string;
82
85
  }
83
86
  export interface ModReduxAPI {
87
+ /**
88
+ * Whether a save file is currently loaded. Use this to gate save-specific settings.
89
+ * When false, useSelector will log errors and return undefined — use api.hasSave
90
+ * to show global settings only (e.g. difficulty presets) vs save-specific settings
91
+ * (e.g. per-save toggles that read/write to the Redux store).
92
+ */
93
+ hasSave: boolean;
84
94
  /**
85
95
  * Hook to access the Redux store state. Works like React Redux's useSelector.
96
+ * Only works when hasSave is true — logs a console error and returns undefined otherwise.
86
97
  * @param selector - Function that extracts data from the RootState
87
98
  * @returns The selected data from the store
88
99
  * @example
@@ -263,11 +274,35 @@ export interface ModReduxAPI {
263
274
  backgroundImage: string;
264
275
  screenEffect: ScreenEffectType;
265
276
  }) => void;
277
+ /**
278
+ * Execute a crafting technique during an active crafting session.
279
+ * Has the same effect as clicking the technique button in the crafting UI.
280
+ * Should only be called while a crafting session is active.
281
+ * @param technique - The fully resolved CraftingTechnique to execute
282
+ * @example
283
+ * const technique = api.craftingTechniqueFromKnown(knownTechnique);
284
+ * executeCraftingTechnique(technique);
285
+ */
286
+ executeCraftingTechnique: (technique: CraftingTechnique) => void;
287
+ /**
288
+ * Preview the result of executing a crafting technique without modifying game state.
289
+ * Deep-clones the provided CraftingState, runs the technique on the copy, and returns
290
+ * the resulting CraftingState. No Redux actions are dispatched.
291
+ * @param technique - The fully resolved CraftingTechnique to preview
292
+ * @param state - The current CraftingState (e.g. from useSelector(s => s.crafting))
293
+ * @returns A new CraftingState reflecting the outcome of executing the technique
294
+ * @example
295
+ * const craftingState = api.useSelector(state => state.crafting);
296
+ * const technique = api.craftingTechniqueFromKnown(knownTechnique);
297
+ * const preview = previewCraftingTechnique(technique, craftingState);
298
+ * console.log('Completion after:', preview.progressState?.completion);
299
+ */
300
+ previewCraftingTechnique: (technique: CraftingTechnique, state: CraftingState) => CraftingState;
266
301
  };
267
302
  components: {
268
303
  GameDialog: GameDialogFC;
269
- GameButton: GameButtonFC;
270
- GameIconButton: GameIconButtonFC;
304
+ GameButton: GameButtonExoticFC;
305
+ GameIconButton: GameIconButtonExoticFC;
271
306
  BackgroundImage: MemoBackgroundImageFC;
272
307
  PlayerComponent: React.FC;
273
308
  };
@@ -592,6 +627,17 @@ export interface ModAPI {
592
627
  * addCraftingMissionsToLocation('Crafting Hall', [window.modAPI.utils.createCraftingMission(...)]);
593
628
  */
594
629
  addCraftingMissionsToLocation: (location: string, missions: CraftingMission[]) => void;
630
+ /**
631
+ * Add a quest to a location's request board.
632
+ * @param quest - Quest to add
633
+ * @param realm - Realm tier this quest appears for
634
+ * @param rarity - Rarity of the quest
635
+ * @param condition - Condition expression for availability (e.g. '1' for always available)
636
+ * @param location - Location key (must have a request board building)
637
+ * @example
638
+ * addQuestToRequestBoard(myQuest, 'qiCondensation', 'qitouched', '1', 'Liang Tiao Village');
639
+ */
640
+ addQuestToRequestBoard: (quest: Quest, realm: Realm, rarity: Rarity, condition: string, location: string) => void;
595
641
  /**
596
642
  * Add a manual to the Manual Pagoda.
597
643
  * @param manual - Manual configuration
@@ -881,6 +927,26 @@ export interface ModAPI {
881
927
  * });
882
928
  */
883
929
  registerOptionsUI: (component: ModOptionsFC) => void;
930
+ /**
931
+ * Set a value in the global mod flags file.
932
+ * Global flags persist across all saves and are injected into game flags automatically.
933
+ * Use this to store mod data that is not tied to a specific save file.
934
+ * @param flag - Flag name (will be stored as-is)
935
+ * @param value - Numeric value to store
936
+ * @example
937
+ * setGlobalFlag('myMod_unlocked', 1);
938
+ * setGlobalFlag('myMod_highScore', 42);
939
+ */
940
+ setGlobalFlag: (flag: string, value: number) => void;
941
+ /**
942
+ * Get all current global mod flags.
943
+ * Returns the full string->number map that is persisted in the global mod flags file.
944
+ * @returns Record of all global mod flags
945
+ * @example
946
+ * const flags = getGlobalFlags();
947
+ * const highScore = flags['myMod_highScore'] ?? 0;
948
+ */
949
+ getGlobalFlags: () => Record<string, number>;
884
950
  };
885
951
  utils: {
886
952
  /**
@@ -1687,6 +1753,54 @@ export interface ModAPI {
1687
1753
  * @returns Whether the condition is met
1688
1754
  */
1689
1755
  evaluateCraftingCondition: (condition: CraftingTechniqueCondition, entity: CraftingEntity, variables: Record<string, number>, selfStacks: number, progress: ProgressState, state: CraftingState) => boolean;
1756
+ /**
1757
+ * Calculate the final Qi (pool) and Stability costs for a crafting technique after
1758
+ * all modifiers are applied: condition effects, buff cost-percentage modifiers, and
1759
+ * mastery reductions already baked into the technique.
1760
+ *
1761
+ * Pass the technique through `craftingTechniqueFromKnown` first so that mastery
1762
+ * cost reductions (mastery kinds: 'poolcost' / 'stabilitycost') are already reflected
1763
+ * as reduced `poolCost` / `stabilityCost` values on the technique object.
1764
+ *
1765
+ * Rounding matches the game engine:
1766
+ * - Pool cost: Math.floor at each condition step, then Math.floor on buff modifier.
1767
+ * - Stability cost: Math.ceil on buff modifier, then Math.floor at each condition step.
1768
+ *
1769
+ * @param technique - Fully resolved crafting technique.
1770
+ * @param entity - Current crafting entity (buffs, stats).
1771
+ * @param recipe - Recipe stats (condition effect tables).
1772
+ * @param progress - Current crafting progress (active condition, harmony, etc.).
1773
+ * @returns Final pool (Qi) and stability costs as non-negative integers.
1774
+ * @example
1775
+ * const technique = craftingTechniqueFromKnown(knownTechnique);
1776
+ * const { poolCost, stabilityCost } = getActionCost(technique, entity, recipeStats, progress);
1777
+ */
1778
+ getActionCost: (technique: CraftingTechnique, entity: CraftingEntity, recipe: CraftingRecipeStats, progress: ProgressState) => {
1779
+ poolCost: number;
1780
+ stabilityCost: number;
1781
+ };
1782
+ /**
1783
+ * Predict the next crafting condition that will be added to the condition queue.
1784
+ * This is the same function the game engine calls each turn to extend the preview window.
1785
+ *
1786
+ * The result is probabilistic — calling it multiple times with identical inputs can
1787
+ * return different values. Use it to simulate condition sequences or build UI previews.
1788
+ *
1789
+ * @param progress - Current crafting progress state.
1790
+ * @returns The predicted next CraftingCondition.
1791
+ * @example
1792
+ * const next = getNextCondition(progress);
1793
+ * console.log('Upcoming condition:', next);
1794
+ */
1795
+ getNextCondition: (progress: ProgressState) => CraftingCondition;
1796
+ /**
1797
+ * Stable non-localized identifier for the Completion Bonus buff.
1798
+ * Use this constant when filtering or inspecting entity buffs so that your mod
1799
+ * code is not coupled to the raw string literal.
1800
+ * @example
1801
+ * const bonusStacks = entity.buffs.find(b => b.name === completionBonusBuffName)?.stacks ?? 0;
1802
+ */
1803
+ completionBonusBuffName: string;
1690
1804
  };
1691
1805
  hooks: {
1692
1806
  /**
@@ -1718,14 +1832,14 @@ export interface ModAPI {
1718
1832
  * Hook to add events after combat completion.
1719
1833
  * @param interceptor - Function returning additional event steps
1720
1834
  * @example
1721
- * onCompleteCombat((step, victory, playerState, enemies, flags) => {
1835
+ * onCompleteCombat((step, victory, playerState, enemies, droppedItems, flags) => {
1722
1836
  * if (victory && playerState.stats.hp < 10) {
1723
1837
  * return [{ type: 'text', text: 'That was close!' }];
1724
1838
  * }
1725
1839
  * return [];
1726
1840
  * });
1727
1841
  */
1728
- onCompleteCombat: (interceptor: (eventStep: CombatStep | FightCharacterStep, victory: boolean, playerCombatState: CombatEntity, foughtEnemies: EnemyEntity[], gameFlags: Record<string, number>) => EventStep[]) => void;
1842
+ onCompleteCombat: (interceptor: (eventStep: CombatStep | FightCharacterStep, victory: boolean, playerCombatState: CombatEntity, foughtEnemies: EnemyEntity[], droppedItems: Item[], gameFlags: Record<string, number>) => EventStep[]) => void;
1729
1843
  /**
1730
1844
  * Hook to add events after tournament completion.
1731
1845
  * @param interceptor - Function returning additional event steps
@@ -77,6 +77,7 @@ export interface CombatState {
77
77
  enemies: EnemyEntity[];
78
78
  enemyState: CombatEntity | undefined;
79
79
  noEnhancement?: boolean;
80
+ noCrit?: boolean;
80
81
  trainingMode?: boolean;
81
82
  combatTitle?: string;
82
83
  customBgm?: string[];
@@ -121,6 +122,11 @@ export interface MonthState {
121
122
  flaresSpent: number;
122
123
  schoolUsage?: Record<string, number>;
123
124
  techniqueUsage?: Record<string, number>;
125
+ craftingChanceTracking?: Record<string, {
126
+ total: number;
127
+ success: number;
128
+ fail: number;
129
+ }>;
124
130
  };
125
131
  }
126
132
  export interface QuestState {
package/dist/stat.d.ts CHANGED
@@ -55,7 +55,7 @@ export declare const physicalStatToDescription: {
55
55
  };
56
56
  export declare const reputationDescription = "Reputation affects a factions attitude towards you. High reputation reduces prices, unlocks quests, and allows the purchase of valuable items.";
57
57
  export declare const reputationPerTier = 5;
58
- export declare const reputationTiers: readonly ["neutral", "friendly", "respected", "honoured", "revered", "exalted", "wary", "disliked", "hated", "reviled"];
58
+ export declare const reputationTiers: readonly ["neutral", "friendly", "respected", "honoured", "revered", "exalted"];
59
59
  export type ReputationTier = (typeof reputationTiers)[number];
60
60
  export declare const reputationTierToReputation: Record<ReputationTier, number>;
61
61
  export declare const reputationTierToName: Record<ReputationTier, string>;
package/dist/stat.js CHANGED
@@ -300,10 +300,6 @@ export const reputationTiers = [
300
300
  'honoured',
301
301
  'revered',
302
302
  'exalted',
303
- 'wary',
304
- 'disliked',
305
- 'hated',
306
- 'reviled',
307
303
  ];
308
304
  export const reputationTierToReputation = {
309
305
  neutral: 0,
@@ -312,10 +308,6 @@ export const reputationTierToReputation = {
312
308
  honoured: reputationPerTier * 3,
313
309
  revered: reputationPerTier * 4,
314
310
  exalted: reputationPerTier * 5,
315
- wary: -reputationPerTier,
316
- disliked: -reputationPerTier * 2,
317
- hated: -reputationPerTier * 3,
318
- reviled: -reputationPerTier * 4,
319
311
  };
320
312
  export const reputationTierToName = {
321
313
  neutral: 'Neutral (-)',
@@ -324,10 +316,6 @@ export const reputationTierToName = {
324
316
  honoured: 'Honoured (III)',
325
317
  revered: 'Revered (IV)',
326
318
  exalted: 'Exalted (V)',
327
- wary: 'Wary (I-)',
328
- disliked: 'Disliked (II-)',
329
- hated: 'Hated (III-)',
330
- reviled: 'Reviled (IV-)',
331
319
  };
332
320
  export const reputationTierToNameOnly = {
333
321
  neutral: 'Neutral',
@@ -336,8 +324,4 @@ export const reputationTierToNameOnly = {
336
324
  honoured: 'Honoured',
337
325
  revered: 'Revered',
338
326
  exalted: 'Exalted',
339
- wary: 'Wary',
340
- disliked: 'Disliked',
341
- hated: 'Hated',
342
- reviled: 'Reviled',
343
327
  };
@@ -109,7 +109,7 @@ interface ConsumeTargetTechniqueEffect extends BaseTechniqueEffect {
109
109
  amount: Scaling;
110
110
  hideBuff?: boolean;
111
111
  }
112
- interface DamageTechniqueEffect extends BaseTechniqueEffect {
112
+ export interface DamageTechniqueEffect extends BaseTechniqueEffect {
113
113
  kind: 'damage';
114
114
  amount: Scaling;
115
115
  hits?: Scaling;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afnm-types",
3
- "version": "0.6.43",
3
+ "version": "0.6.45",
4
4
  "description": "Type definitions for Ascend From Nine Mountains",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",