afnm-types 0.6.56 → 0.6.57

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/auction.d.ts CHANGED
@@ -18,6 +18,7 @@ export interface AuctionItemDef {
18
18
  condition: string;
19
19
  countOverride?: number;
20
20
  countMultiplier?: number;
21
+ costMultiplier?: number;
21
22
  }
22
23
  export interface AuctionCharacter {
23
24
  name: string;
package/dist/buff.d.ts CHANGED
@@ -57,6 +57,20 @@ interface InventoryItemTechniqueCondition extends BaseTechniqueCondition {
57
57
  count: number;
58
58
  mode: 'more' | 'less' | 'equal';
59
59
  }
60
+ /**
61
+ * Configures how a buff lives outside combat. Buffs without a `persistence`
62
+ * field are combat or event scoped only.
63
+ */
64
+ export interface BuffPersistence {
65
+ /**
66
+ * When combat ends, the surviving stack count of this buff on the player is
67
+ * written back into `player.monthBuffs`. Existing entries are replaced, not
68
+ * additively merged. Stacks of zero or below remove the buff.
69
+ */
70
+ persistAfterCombat?: boolean;
71
+ /** Stacks of this buff lost at the end of every month. */
72
+ decayPerMonth?: number;
73
+ }
60
74
  export interface Buff {
61
75
  name: string;
62
76
  displayName?: Translatable;
@@ -108,6 +122,7 @@ export interface Buff {
108
122
  /** Block specific triggers from executing. Used to prevent effects like celestial rotation. */
109
123
  blockTriggerEffects?: {
110
124
  trigger: string;
125
+ condition?: TechniqueCondition;
111
126
  effects: BuffEffect[];
112
127
  }[];
113
128
  damageInterceptorEffects?: {
@@ -122,6 +137,7 @@ export interface Buff {
122
137
  amplifier: {
123
138
  kind: 'multiply';
124
139
  value: number;
140
+ cantUpgrade?: boolean;
125
141
  };
126
142
  effects?: BuffEffect[];
127
143
  appliesTo: ('damage' | 'barrier' | 'heal' | 'tempHealth')[];
@@ -134,6 +150,7 @@ export interface Buff {
134
150
  modifier: {
135
151
  kind: 'add' | 'multiply';
136
152
  value: number;
153
+ cantUpgrade?: boolean;
137
154
  };
138
155
  effects?: BuffEffect[];
139
156
  }[];
@@ -144,6 +161,12 @@ export interface Buff {
144
161
  stacks: number;
145
162
  stacksAreDays?: boolean;
146
163
  stacksAreMonths?: boolean;
164
+ /**
165
+ * Marks the buff as carrying state on the player between events. When set,
166
+ * the buff opts out of the default daily monthBuffs decay (which treats
167
+ * stacks as days remaining) and follows the rules in this object instead.
168
+ */
169
+ persistence?: BuffPersistence;
147
170
  buffType?: string;
148
171
  buffTypeTooltip?: string;
149
172
  endurePercent?: number;
@@ -155,6 +178,11 @@ export interface Buff {
155
178
  guardianIntercept?: {
156
179
  percent: Scaling;
157
180
  maxHp: Scaling;
181
+ /** How re-application of the guardian buff combines with existing guardian HP.
182
+ * 'refresh' (default): maxHp = max(old, new); hp = maxHp (fully heal).
183
+ * 'extend': hp = oldHp + newMaxHp; maxHp = max(oldMaxHp, hp). Adds onto current and extends the cap. */
184
+ refreshMode?: 'refresh' | 'extend';
185
+ canUpgrade?: boolean;
158
186
  };
159
187
  /** Runtime guardian HP — set automatically from guardianIntercept.maxHp at buff creation */
160
188
  guardianHp?: number;
@@ -328,6 +356,7 @@ interface BaseBuff {
328
356
  [key in CombatStatistic]: Scaling;
329
357
  }>;
330
358
  hidden?: boolean;
359
+ cantUpgrade?: boolean;
331
360
  }
332
361
  interface DamageEffect extends BaseBuff {
333
362
  kind: 'damage';
@@ -372,6 +401,7 @@ interface ConsumeBuffSelfEffect extends BaseBuff {
372
401
  buff: Buff | string;
373
402
  silent?: boolean;
374
403
  hideBuff?: boolean;
404
+ targeting?: EffectTargeting;
375
405
  }
376
406
  interface CreateBuffTargetEffect extends BaseBuff {
377
407
  kind: 'buffTarget';
@@ -418,6 +448,9 @@ interface ModifyBuffGroupEffect extends BaseBuff {
418
448
  onTarget?: boolean;
419
449
  group: string;
420
450
  amount: Scaling;
451
+ /** Defaults to 'all'. 'highest'/'lowest' restrict the effect to a single matching buff
452
+ * chosen by stack count. */
453
+ mode?: 'all' | 'highest' | 'lowest';
421
454
  }
422
455
  interface SetStateEffect extends BaseBuff {
423
456
  kind: 'setState';
@@ -537,6 +537,18 @@ function extractFromFile(filePath) {
537
537
  });
538
538
  }
539
539
  }
540
+ else if (typescript_1.default.isBinaryExpression(arg) && arg.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
541
+ // String concatenation with + is supported - try to resolve it
542
+ const resolved = (0, template_processor_js_1.tryResolveBinaryExpression)(arg, sourceFile, filePath);
543
+ if (resolved !== null && resolved.trim().length > 0) {
544
+ results.push({
545
+ text: resolved,
546
+ file: filePath,
547
+ line: (0, template_processor_js_1.getLineNumber)(sourceFile, node.getStart()),
548
+ context: `${funcName}-call`,
549
+ });
550
+ }
551
+ }
540
552
  else if (typescript_1.default.isTemplateExpression(arg)) {
541
553
  const templateText = arg.getText(sourceFile);
542
554
  const processed = (0, template_processor_js_1.processTemplateExpression)(arg, sourceFile, filePath);
@@ -1037,20 +1037,31 @@ function buildTranslationLookup(langData) {
1037
1037
  function loadExistingLanguageFiles() {
1038
1038
  const languageFiles = new Map();
1039
1039
  const translationsDir = path_1.default.join('src', 'translations');
1040
- // List of language codes to look for
1041
- const languages = ['zh', 'de', 'fr', 'es', 'ru'];
1042
- for (const lang of languages) {
1043
- const langPath = path_1.default.join(translationsDir, `${lang}.json`);
1044
- if (fs_1.default.existsSync(langPath)) {
1045
- try {
1046
- const data = JSON.parse(fs_1.default.readFileSync(langPath, 'utf-8'));
1047
- languageFiles.set(lang, data);
1048
- console.log(` Loaded existing translations from ${lang}.json`);
1049
- }
1050
- catch (error) {
1051
- const message = error instanceof Error ? error.message : String(error);
1052
- console.warn(` Warning: Failed to parse ${lang}.json: ${message}`);
1053
- }
1040
+ // Discover languages by scanning the translations directory rather than maintaining
1041
+ // a hardcoded list (which silently dropped ja/ko/vi/fi/pl/pt-BR/th/zh-CN/zh-TW).
1042
+ // Filenames are <lang>.json; non-language files in this dir are explicitly excluded.
1043
+ const NON_LANGUAGE_FILES = new Set([
1044
+ 'template.json',
1045
+ 'debug.json',
1046
+ 'custom-strings.json',
1047
+ 'technique-tooltip-templates.json',
1048
+ ]);
1049
+ const entries = fs_1.default.readdirSync(translationsDir);
1050
+ for (const file of entries) {
1051
+ if (!file.endsWith('.json'))
1052
+ continue;
1053
+ if (NON_LANGUAGE_FILES.has(file))
1054
+ continue;
1055
+ const lang = file.replace(/\.json$/, '');
1056
+ const langPath = path_1.default.join(translationsDir, file);
1057
+ try {
1058
+ const data = JSON.parse(fs_1.default.readFileSync(langPath, 'utf-8'));
1059
+ languageFiles.set(lang, data);
1060
+ console.log(` Loaded existing translations from ${lang}.json`);
1061
+ }
1062
+ catch (error) {
1063
+ const message = error instanceof Error ? error.message : String(error);
1064
+ console.warn(` Warning: Failed to parse ${lang}.json: ${message}`);
1054
1065
  }
1055
1066
  }
1056
1067
  return languageFiles;
package/dist/entity.d.ts CHANGED
@@ -333,6 +333,8 @@ export interface CombatEntity {
333
333
  partyId?: string;
334
334
  /** When true, critchance is forced to 0 for this entity (used in training ground) */
335
335
  noCrit?: boolean;
336
+ /** Maximum qi droplets for this entity (set during combat entity creation) */
337
+ maxqiDroplets?: number;
336
338
  /** Cached hash for getVariablesFromEntity. Cleared whenever stats or buffs mutate. */
337
339
  _cachedHash?: string;
338
340
  }
package/dist/event.d.ts CHANGED
@@ -464,6 +464,10 @@ export interface SetAidBreakthroughCooldownStep extends BaseEventStep {
464
464
  export interface StoneCuttingStep extends BaseEventStep {
465
465
  kind: 'stoneCutting';
466
466
  realm: Realm;
467
+ /** Percentage discount to apply to stone cutting costs (0-100), evaluated as expression */
468
+ discountPercentage?: string;
469
+ /** Number of stones the player can cut for free, evaluated as expression */
470
+ freeCount?: string;
467
471
  }
468
472
  export interface GiveItemStep extends BaseEventStep {
469
473
  kind: 'giveItem';
@@ -15,4 +15,4 @@
15
15
  * };
16
16
  * }
17
17
  */
18
- export declare const GAME_VERSION = "0.6.56";
18
+ export declare const GAME_VERSION = "0.6.57";
@@ -15,4 +15,4 @@
15
15
  * };
16
16
  * }
17
17
  */
18
- export const GAME_VERSION = "0.6.56";
18
+ export const GAME_VERSION = "0.6.57";
package/dist/item.d.ts CHANGED
@@ -12,7 +12,7 @@ import type { Realm, RealmProgress } from './realm';
12
12
  import type { RecipeDifficulty } from './RecipeDifficulty';
13
13
  import type { CombatStatistic, CombatStatsMap, CraftingStatistic, CraftingStatsMap, PhysicalStatistic, Scaling, SocialStatistic } from './stat';
14
14
  import type { Technique, TechniqueEffect } from './technique';
15
- import { DelveRoom } from './soulShardDelve';
15
+ import { DelveRoomConfig } from './soulShardDelve';
16
16
  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", "local_map"];
17
17
  export type ItemKind = (typeof itemKinds)[number];
18
18
  export declare const itemKindToName: {
@@ -43,6 +43,13 @@ interface ItemBase {
43
43
  qualityTier?: number;
44
44
  hiddenPotential?: number;
45
45
  minimumPotential?: number;
46
+ corruption?: ItemCorruption;
47
+ }
48
+ export interface ItemCorruption {
49
+ name: Translatable;
50
+ debuff: Buff;
51
+ threshold: number;
52
+ countPerCombat: number;
46
53
  }
47
54
  export interface ItemDesc {
48
55
  name: string;
@@ -223,6 +230,14 @@ export interface CombatItem extends ItemBase {
223
230
  export interface ConsumablePillItem extends BasePillItem {
224
231
  pillKind: 'consumable';
225
232
  max: number;
233
+ /**
234
+ * Optional shared consumption group. When set, the player can consume at most `groupCap`
235
+ * pills total across every pill that names the same `consumptionGroup`, in addition to
236
+ * each pill's individual `max` limit.
237
+ */
238
+ consumptionGroup?: string;
239
+ /** Lifetime cap for the entire consumption group. Required when `consumptionGroup` is set. */
240
+ groupCap?: number;
226
241
  physicalStats: Partial<Record<PhysicalStatistic, number>>;
227
242
  socialStats: Partial<Record<SocialStatistic, number>>;
228
243
  rawStats?: Partial<Record<CombatStatistic | CraftingStatistic, Scaling>>;
@@ -454,9 +469,9 @@ export interface PillarShardVariant {
454
469
  }
455
470
  export interface PillarShardItem extends ItemBase {
456
471
  kind: 'pillar_shard';
457
- tooltip: Translatable;
472
+ tooltip?: Translatable;
458
473
  maxInstances?: number;
459
- delveRoomConfig?: DelveRoom;
474
+ delveRoomConfig?: DelveRoomConfig;
460
475
  variants?: PillarShardVariant[];
461
476
  stability?: number;
462
477
  portal?: {
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { AppDispatch } from '../store';
3
+ import type { BreakthroughState } from './breakthrough';
4
+ import type { SoundEffectName } from './audio';
5
+ import type { Item } from './item';
6
+ import type { PlayerEntity } from './entity';
7
+ import type { InventoryState } from './reduxState';
8
+ interface OpenItem {
9
+ item: Item;
10
+ data: unknown;
11
+ onComplete: () => void;
12
+ }
13
+ export interface ItemActionContext {
14
+ item: Item;
15
+ player: PlayerEntity;
16
+ inventory: InventoryState;
17
+ breakthrough: BreakthroughState;
18
+ flags: Record<string, number | string | boolean>;
19
+ dispatch: AppDispatch;
20
+ setResult: (result: ReactNode) => void;
21
+ setClicked: (clicked: boolean) => void;
22
+ setOpenItem?: (openItem: OpenItem) => void;
23
+ setDoEnchant?: (doEnchant: boolean) => void;
24
+ setDoUpgrade?: (doUpgrade: boolean) => void;
25
+ setDoAppearanceChange?: (doAppearanceChange: boolean) => void;
26
+ playSfx: (sound: SoundEffectName) => void;
27
+ usageRestricted: boolean;
28
+ }
29
+ export interface ItemActionResult {
30
+ buttons: ReactNode[];
31
+ }
32
+ export type ItemActionHandler = (context: ItemActionContext) => ItemActionResult;
33
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -146,8 +146,8 @@ export interface CraftingMission {
146
146
  condition: string;
147
147
  }
148
148
  export declare const exploresPerUnlock = 3;
149
- export type BuildingType = 'cultivation' | 'manual' | 'crafting' | 'mission' | 'craftingHall' | 'healer' | 'market' | 'favourExchange' | 'vault' | 'custom' | 'herbField' | 'mine' | 'recipe' | 'requestBoard' | 'compendium' | 'mysticalRegion' | 'expedition' | 'trainingGround' | 'library' | 'house' | 'altar' | 'research' | 'reforge' | 'guild' | 'tenThousandFlames' | 'soulShardDelve' | 'enchantmentShop' | 'challengeBoard' | 'modBuilding';
150
- export type LocationBuilding = CultivationBuilding | ManualBuilding | CraftingBuilding | MissionBuilding | CraftingHallBuilding | HealerBuilding | MarketBuilding | VaultBuilding | FavourExchangeBuilding | CustomBuilding | HerbFieldBuilding | MineBuilding | RecipeLibraryBuilding | RequestBoardBuilding | CompendiumBuilding | MysticalRegionBuilding | TrainingGroundBuilding | LibraryBuilding | HouseBuilding | CompressionAltarBuilding | ResearchBuilding | ReforgeBuilding | GuildBuilding | TenThousandFlamesBuilding | SoulShardDelveBuilding | EnchantmentShopBuilding | ChallengeBoardBuilding | ModBuilding;
149
+ export type BuildingType = 'cultivation' | 'manual' | 'crafting' | 'mission' | 'craftingHall' | 'healer' | 'market' | 'favourExchange' | 'vault' | 'custom' | 'herbField' | 'mine' | 'recipe' | 'requestBoard' | 'compendium' | 'mysticalRegion' | 'expedition' | 'trainingGround' | 'library' | 'house' | 'altar' | 'research' | 'reforge' | 'guild' | 'tenThousandFlames' | 'soulShardDelve' | 'enchantmentShop' | 'challengeBoard' | 'jadeCutter' | 'modBuilding';
150
+ export type LocationBuilding = CultivationBuilding | ManualBuilding | CraftingBuilding | MissionBuilding | CraftingHallBuilding | HealerBuilding | MarketBuilding | VaultBuilding | FavourExchangeBuilding | CustomBuilding | HerbFieldBuilding | MineBuilding | RecipeLibraryBuilding | RequestBoardBuilding | CompendiumBuilding | MysticalRegionBuilding | TrainingGroundBuilding | LibraryBuilding | HouseBuilding | CompressionAltarBuilding | ResearchBuilding | ReforgeBuilding | GuildBuilding | TenThousandFlamesBuilding | SoulShardDelveBuilding | EnchantmentShopBuilding | ChallengeBoardBuilding | JadeCutterBuilding | ModBuilding;
151
151
  export type LocationBuildingState = MissionBuildingState | CraftingHallBuildingState | ShopBuildingState | RequestBoardBuildingState | HouseBuildingState | CompressionAltarBuildingState;
152
152
  interface BuildingBase {
153
153
  kind: BuildingType;
@@ -200,6 +200,10 @@ export interface CraftingHallBuildingState {
200
200
  export interface HealerBuilding extends BuildingBase {
201
201
  kind: 'healer';
202
202
  }
203
+ export interface JadeCutterBuilding extends BuildingBase {
204
+ kind: 'jadeCutter';
205
+ reputationName: string;
206
+ }
203
207
  export interface ShopItem extends ItemDesc {
204
208
  stacks: number;
205
209
  reputation?: ReputationTier;
@@ -234,6 +238,8 @@ export interface HerbFieldBuilding extends BuildingBase {
234
238
  }
235
239
  export interface MineBuilding extends BuildingBase {
236
240
  kind: 'mine';
241
+ /** Identifier of the MineConfig that backs this building. */
242
+ mineId: string;
237
243
  }
238
244
  export interface RecipeLibraryBuilding extends BuildingBase {
239
245
  kind: 'recipe';
package/dist/location.js CHANGED
@@ -28,5 +28,6 @@ export const buildingTypeToName = {
28
28
  soulShardDelve: 'Soul Shard',
29
29
  enchantmentShop: 'Enchantment Shop',
30
30
  challengeBoard: 'Challenge Board',
31
+ jadeCutter: 'Jade Cutter',
31
32
  modBuilding: '',
32
33
  };
@@ -0,0 +1,8 @@
1
+ import { Realm } from './realm';
2
+ export interface Manual {
3
+ name: string;
4
+ icon: string;
5
+ realm: Realm;
6
+ techniques: string[];
7
+ stance: string[];
8
+ }
package/dist/manual.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,62 @@
1
+ import type { Buff } from './buff';
2
+ import type { EnemyEntity } from './entity';
3
+ import type { FlareItem } from './item';
4
+ import type { MineChamber } from './mine';
5
+ import type { Realm, RealmProgress } from './realm';
6
+ import type { Translatable } from './translatable';
7
+ export interface MineStratum {
8
+ realm: Realm;
9
+ progress: RealmProgress;
10
+ }
11
+ export interface MineConfig {
12
+ /** Stable identifier used as the redux key for this mine's state. */
13
+ id: string;
14
+ /** Title shown on the mine chart dialog. */
15
+ chartTitle: Translatable;
16
+ /** Location name written into events that originate inside this mine. */
17
+ locationName: string;
18
+ /** Per-realm/progress chamber pools. */
19
+ chambers: {
20
+ [key in Realm]?: {
21
+ [key in RealmProgress]?: MineChamber[];
22
+ };
23
+ };
24
+ /** Per-realm pathing-monster pools used in inter-chamber combat. */
25
+ pathingMonsters: {
26
+ [key in Realm]?: EnemyEntity[];
27
+ };
28
+ /**
29
+ * Strata in depth order (top → bottom). The y/9 stratum index uses this
30
+ * directly, so the first entry is the surface stratum.
31
+ */
32
+ depthStrata: MineStratum[];
33
+ /**
34
+ * Optional sickness buff applied per delve. Stack count scales with the
35
+ * stratum's distance from the surface (same rule as Shadow Sickness:
36
+ * stratumIndex+1, minus 1 for the very first sub-stratum).
37
+ */
38
+ sicknessBuff?: Buff;
39
+ /** Game flag tracking the highest sickness-stack count ever applied. */
40
+ sicknessFlag?: string;
41
+ /**
42
+ * Stacks of `sicknessBuff` applied per delve. Receives the chamber's
43
+ * realm/progress so configs can scale by depth.
44
+ */
45
+ sicknessStacks?: (realm: Realm, progress: RealmProgress) => number;
46
+ /** Game flag tracking the deepest stratum the player has reached. */
47
+ depthFlag: string;
48
+ /** Flare item consumed when delving into a chamber. */
49
+ flareItem: FlareItem;
50
+ /** Combat intro flavor text used when fighting through corridors. */
51
+ combatIntroText: string;
52
+ /** Victory flavor text after pathing combat. */
53
+ combatVictoryText: string;
54
+ /** Defeat flavor text after pathing combat. */
55
+ combatDefeatText: string;
56
+ /** Music cue name (resolved against musicMap in AppRouter). */
57
+ music: string;
58
+ /** Ambience cue name (resolved against ambienceMap in AppRouter). */
59
+ ambience: string;
60
+ }
61
+ export declare const getMineStratumIndex: (y: number) => number;
62
+ export declare const getMineStratumAt: (config: MineConfig, y: number) => MineStratum | undefined;
@@ -0,0 +1,4 @@
1
+ export const getMineStratumIndex = (y) => Math.floor(y / 9);
2
+ export const getMineStratumAt = (config, y) => {
3
+ return config.depthStrata[getMineStratumIndex(y)];
4
+ };
package/dist/mod.d.ts CHANGED
@@ -7,9 +7,8 @@ import type { Background } from './background';
7
7
  import type { Breakthrough } from './breakthrough';
8
8
  import type { Buff } from './buff';
9
9
  import type { BreakthroughState } from './breakthrough';
10
- import type { CharactersState } from './reduxState';
11
10
  import type { CalendarEvent } from './calendar';
12
- import type { Character } from './character';
11
+ import type { Character, CharacterDefinition, CharacterRelationship, CharacterRelationshipDefinition, CharacterState, CompanionCharacterDefinition, GiftCharacterInteraction } from './character';
13
12
  import type { CraftingTechnique, CraftingRecipeStats } from './craftingTechnique';
14
13
  import type { RecipeConditionEffect } from './crafting';
15
14
  import type { Destiny } from './destiny';
@@ -36,7 +35,7 @@ import type { CraftingCondition, HarmonyTypeConfig, RecipeHarmonyType } from './
36
35
  import type { ItemKind } from './item';
37
36
  import type { SoundEffectName } from './audio';
38
37
  import type { ScreenEffectType } from './ScreenEffectType';
39
- import type { RootState } from './reduxState';
38
+ import type { RootState, CharactersState, InventoryState, FallenStarState } from './reduxState';
40
39
  import type { GameDialogFC, GameButtonExoticFC, GameIconButtonExoticFC, MemoBackgroundImageFC, GameTooltipFC, GameTooltipBoxFC, TooltipLineFC } from './components';
41
40
  import type { PuppetType } from './trainingGround';
42
41
  import type { TechniqueElement } from './element';
@@ -1449,6 +1448,15 @@ export interface ModAPI {
1449
1448
  * const maxQi = getMaxQi('coreFormation', 'Late');
1450
1449
  */
1451
1450
  getMaxQi: (realm: Realm, realmProgress: RealmProgress) => number;
1451
+ /**
1452
+ * Calculate the maximum Qi Droplets the player can hold based on their condensation art and breakthrough state.
1453
+ * @param player - The player entity with realm and stats
1454
+ * @param breakthrough - The current breakthrough state including condensation art and vessel
1455
+ * @returns Maximum number of Qi Droplets the player can hold (0 if no vessel)
1456
+ * @example
1457
+ * const maxDroplets = utils.getMaxQiDroplets(player, breakthrough);
1458
+ */
1459
+ getMaxQiDroplets: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
1452
1460
  /**
1453
1461
  * Scale a numeric reward amount to a value appropriate for the player's realm and progress.
1454
1462
  * @param base - Base reward amount
@@ -1712,6 +1720,32 @@ export interface ModAPI {
1712
1720
  * const combatEntity = createEnemyCombatEntity(myEnemy, {});
1713
1721
  */
1714
1722
  createEnemyCombatEntity: (enemy: EnemyEntity, gameFlags: Record<string, number>) => CombatEntity;
1723
+ /**
1724
+ * Create a full CombatEntity from a player for combat tooltips and calculations.
1725
+ * Applies breakthrough stats, scaling, destines, and mod hooks.
1726
+ * @param player - Player entity definition
1727
+ * @param breakthrough - Current breakthrough state
1728
+ * @param gameFlags - (Optional) Current game flags
1729
+ * @returns Fully resolved combat entity
1730
+ * @example
1731
+ * const combatEntity = createPlayerCombatEntity(player, breakthrough, {});
1732
+ */
1733
+ createPlayerCombatEntity: (player: PlayerEntity, breakthrough: BreakthroughState, gameFlags?: Record<string, number>) => CombatEntity;
1734
+ /**
1735
+ * Create a full CraftingEntity from a player for crafting tooltips and calculations.
1736
+ * Applies breakthrough stats, crafting skill, characters, and mod hooks.
1737
+ * @param player - Player entity definition
1738
+ * @param breakthrough - Current breakthrough state
1739
+ * @param characters - (Optional) Characters state for companion bonuses
1740
+ * @param options - (Optional) Options such as noCompanionBuff
1741
+ * @param gameFlags - (Optional) Current game flags
1742
+ * @returns Fully resolved crafting entity
1743
+ * @example
1744
+ * const craftingEntity = createPlayerCraftingEntity(player, breakthrough);
1745
+ */
1746
+ createPlayerCraftingEntity: (player: PlayerEntity, breakthrough: BreakthroughState, characters?: CharactersState, options?: {
1747
+ noCompanionBuff?: boolean;
1748
+ }, gameFlags?: Record<string, number>) => CraftingEntity;
1715
1749
  /**
1716
1750
  * Convert a BattleLength enum value to a numeric time-to-kill multiplier.
1717
1751
  * @param battleLength - Battle length setting
@@ -1767,14 +1801,13 @@ export interface ModAPI {
1767
1801
  * @param defenderDefense - Defender's defense stat
1768
1802
  * @param defenderDr - Defender's damage reduction (0-1)
1769
1803
  * @param defenderDefenseFactor - Defense scaling factor
1770
- * @param maxReduction - Maximum damage reduction cap
1771
1804
  * @param defenderVulnerability - Vulnerability percentage
1772
1805
  * @param realm - Combat realm
1773
1806
  * @param realmProgress - Realm progress
1774
1807
  * @param defenderProtection - Defender's protection stat
1775
1808
  * @returns Final damage value
1776
1809
  */
1777
- calculateDamage: (attackPower: number, defenderDefense: number, defenderDr: number, defenderDefenseFactor: number, maxReduction: number, defenderVulnerability: number, realm: Realm, realmProgress: RealmProgress, defenderProtection: number, cultivatorResistance: number) => number;
1810
+ calculateDamage: (attackPower: number, defenderDefense: number, defenderDr: number, defenderDefenseFactor: number, defenderVulnerability: number, realm: Realm, realmProgress: RealmProgress, defenderProtection: number, cultivatorResistance: number) => number;
1778
1811
  /**
1779
1812
  * Format a number for display (e.g. 1000 -> "1,000").
1780
1813
  * @param number - Number to format
@@ -2112,6 +2145,381 @@ export interface ModAPI {
2112
2145
  * @returns true if a save is currently loaded and game state is available, false otherwise.
2113
2146
  */
2114
2147
  getHasSaveLoaded: () => boolean;
2148
+ /**
2149
+ * Shuffle an array into a new random order.
2150
+ * @param array - Array to shuffle
2151
+ * @returns A new shuffled array (original is not mutated)
2152
+ * @example
2153
+ * const shuffled = shuffleArray([1, 2, 3, 4, 5]);
2154
+ */
2155
+ shuffleArray: <T>(array: T[]) => T[];
2156
+ /**
2157
+ * Get a random integer between min and max (inclusive).
2158
+ * @param min - Minimum value (inclusive)
2159
+ * @param max - Maximum value (inclusive)
2160
+ * @returns Random integer
2161
+ * @example
2162
+ * const roll = randomInt(1, 100);
2163
+ */
2164
+ randomInt: (min: number, max: number) => number;
2165
+ /**
2166
+ * Capitalize the first letter of a string.
2167
+ * @param str - String to capitalize
2168
+ * @returns String with first letter uppercased
2169
+ * @example
2170
+ * capitalise('hello'); // 'Hello'
2171
+ */
2172
+ capitalise: (str: string) => string;
2173
+ /**
2174
+ * Generate a random Chinese-style name (surname + forename).
2175
+ * @param sex - Optional gender bias: 'male', 'female', or undefined for random
2176
+ * @returns Object with forename and surname strings
2177
+ * @example
2178
+ * const { forename, surname } = generateChineseName('female');
2179
+ */
2180
+ generateChineseName: (sex?: 'male' | 'female') => {
2181
+ forename: string;
2182
+ surname: string;
2183
+ };
2184
+ /**
2185
+ * Get the combat stats of a character as an EnemyEntity.
2186
+ * Useful for using character stats in custom combat encounters.
2187
+ * @param character - The character definition
2188
+ * @param characterData - The characters redux state
2189
+ * @param flags - Current game flags
2190
+ * @returns EnemyEntity built from the character's current stats
2191
+ * @example
2192
+ * const characterEntity = getCharacterStats(character, charactersState, flags);
2193
+ * api.actions.startCombat([characterEntity], []);
2194
+ */
2195
+ getCharacterStats: (character: Character, characterData: CharactersState, flags: Record<string, number>) => EnemyEntity;
2196
+ /**
2197
+ * Get all active destinies for a player (applying upgradable destiny deduplication).
2198
+ * @param player - The player entity
2199
+ * @returns Array of active Destiny objects
2200
+ * @example
2201
+ * const destinies = getDestinies(player);
2202
+ * for (const destiny of destinies) { ... }
2203
+ */
2204
+ getDestinies: (player: PlayerEntity) => Destiny[];
2205
+ /**
2206
+ * Calculate the player's total mastery points from dantian, month buffs, mount, clothing, and condensation art.
2207
+ * @param player - The player entity
2208
+ * @param breakthrough - The current breakthrough state
2209
+ * @returns Total mastery points available
2210
+ */
2211
+ getMasteryPoints: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2212
+ /**
2213
+ * Get the player's total lifespan including destiny bonuses.
2214
+ * @param player - The player entity
2215
+ * @param breakthrough - The current breakthrough state
2216
+ * @returns Total lifespan value
2217
+ */
2218
+ getLifeSpan: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2219
+ /**
2220
+ * Convert a battlesense stat value to its bonus amount.
2221
+ * @param battlesense - The raw battlesense stat value
2222
+ * @returns Bonus value (ceil(battlesense / 5))
2223
+ * @example
2224
+ * getBattlesenseBonus(25); // 5
2225
+ */
2226
+ getBattlesenseBonus: (battlesense: number) => number;
2227
+ /**
2228
+ * Calculate combat power from its component buckets.
2229
+ * @param buckets - Power breakdown: basePower, enhancement, buffPower, affinityMult, boostMult, masteryMult
2230
+ * @returns Total calculated power
2231
+ */
2232
+ calculatePower: (buckets: {
2233
+ basePower: number;
2234
+ enhancement: number;
2235
+ buffPower: number;
2236
+ affinityMult: number;
2237
+ boostMult: number;
2238
+ masteryMult: number;
2239
+ }) => number;
2240
+ /**
2241
+ * Calculate raw qi absorption value for a player.
2242
+ * @param player - The player entity
2243
+ * @param breakthrough - The current breakthrough state
2244
+ * @returns Raw qi absorption value
2245
+ */
2246
+ getQiAbsorption: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2247
+ /**
2248
+ * Calculate the qi absorption multiplier (how fast the player gains qi per tick).
2249
+ * @param player - The player entity
2250
+ * @param breakthrough - The current breakthrough state
2251
+ * @returns Absorption multiplier (e.g. 1.2 = 20% faster)
2252
+ */
2253
+ getQiAbsorptionMultiplier: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2254
+ /**
2255
+ * Calculate a mount's speed stat for a given realm and progress.
2256
+ * @param realm - Cultivation realm
2257
+ * @param realmProgress - Realm progress
2258
+ * @param mult - Speed multiplier from the mount item
2259
+ * @returns Mount speed value
2260
+ */
2261
+ getMountSpeed: (realm: Realm, realmProgress: RealmProgress, mult: number) => number;
2262
+ /**
2263
+ * Calculate the player's raw move speed value from mount, buffs, and condensation art enchantments.
2264
+ * @param player - The player entity
2265
+ * @param breakthrough - The current breakthrough state
2266
+ * @returns Raw move speed value
2267
+ */
2268
+ getMoveSpeed: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2269
+ /**
2270
+ * Calculate the player's travel time multiplier from their move speed.
2271
+ * Lower values mean faster travel. No mount is a significant penalty.
2272
+ * @param player - The player entity
2273
+ * @param breakthrough - The current breakthrough state
2274
+ * @returns Travel time multiplier (e.g. 0.8 = 20% faster travel)
2275
+ */
2276
+ getMoveSpeedMultiplier: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2277
+ /**
2278
+ * Get a human-readable move speed string (e.g. "+20" or "-10").
2279
+ * @param player - The player entity
2280
+ * @param breakthrough - The current breakthrough state
2281
+ * @returns Formatted speed string
2282
+ */
2283
+ getReadableMoveSpeed: (player: PlayerEntity, breakthrough: BreakthroughState) => string;
2284
+ /**
2285
+ * Get the exploration bonus from the player's equipped mount.
2286
+ * This is an additive bonus — a bonus of 1 means 1 explore counts as 2.
2287
+ * @param player - The player entity
2288
+ * @returns Exploration bonus count
2289
+ */
2290
+ getExplorationBonus: (player: PlayerEntity) => number;
2291
+ /**
2292
+ * Get the total exploration amount per explore action (base 1 + any bonuses).
2293
+ * @param player - The player entity
2294
+ * @returns Total exploration amount per action
2295
+ */
2296
+ getExplorationAmount: (player: PlayerEntity) => number;
2297
+ /**
2298
+ * Get the number of qi droplets produced per condensation action.
2299
+ * @param player - The player entity
2300
+ * @param breakthrough - The current breakthrough state
2301
+ * @returns Number of droplets produced (0 if no vessel equipped)
2302
+ */
2303
+ getDropletProduction: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2304
+ /**
2305
+ * Calculate the effective toxicity of a pill before rounding.
2306
+ * Applies toxicity resistance and realm-based scaling penalty.
2307
+ * Use Math.ceil() in combat contexts and Math.floor() in crafting contexts.
2308
+ * @param pill - Pill descriptor with toxicity and realm
2309
+ * @param playerRealm - Player's current realm
2310
+ * @param toxMultiplier - Player's toxicity resistance multiplier (1 = no resistance)
2311
+ * @returns Effective toxicity before rounding
2312
+ */
2313
+ getEffectivePillToxicity: (pill: {
2314
+ toxicity: number;
2315
+ realm: Realm | 'any';
2316
+ }, playerRealm: Realm, toxMultiplier: number) => number;
2317
+ /**
2318
+ * Get the additional toxicity multiplier when a player of consumerRealm takes a pill for pillRealm.
2319
+ * Each realm above the consumer's realm adds 30% extra toxicity. Returns 0 for same or lower realm pills.
2320
+ * @param consumerRealm - Player's current realm
2321
+ * @param pillRealm - Realm the pill is intended for
2322
+ * @returns Penalty multiplier (e.g. 0.3 = 30% extra toxicity per realm above)
2323
+ */
2324
+ getPillRealmPenalty: (consumerRealm: Realm, pillRealm: Realm) => number;
2325
+ /**
2326
+ * Get the expected physical stat value for a given realm.
2327
+ * This is the base stat number before scaling.
2328
+ * @param realm - Cultivation realm
2329
+ * @returns Base physical stat number
2330
+ */
2331
+ getExpectedPhysicalStat: (realm: Realm) => number;
2332
+ /**
2333
+ * Get a scaled stat value for a given realm, progress and stat multiplier.
2334
+ * Used to derive expected hp, power, defense etc. for enemies/items.
2335
+ * @param realm - Cultivation realm
2336
+ * @param progress - Realm progress
2337
+ * @param statMultiplier - Multiplier for the specific stat (e.g. expectedHpPerFlesh)
2338
+ * @returns Scaled stat value
2339
+ */
2340
+ getScaledStat: (realm: Realm, progress: RealmProgress, statMultiplier: number) => number;
2341
+ /**
2342
+ * Check whether two items match exactly (name, enchantment kind, enchantment rarity, quality tier, hidden potential).
2343
+ * @param a - First item descriptor
2344
+ * @param b - Second item descriptor
2345
+ * @returns True if they match
2346
+ */
2347
+ itemsMatch: (a: ItemDesc | null | undefined, b: ItemDesc | null | undefined) => boolean;
2348
+ /**
2349
+ * Generate a unique string key for an item based on all identifying properties.
2350
+ * Useful for Map keys and quick comparisons.
2351
+ * @param item - Item descriptor
2352
+ * @returns Unique key string
2353
+ */
2354
+ getItemKey: (item: ItemDesc) => string;
2355
+ /**
2356
+ * Find an item in an inventory array that exactly matches the desired item and has stacks > 0.
2357
+ * @param desiredItem - Item descriptor to search for
2358
+ * @param inventory - Array of inventory item states to search through
2359
+ * @returns Matching inventory item or undefined
2360
+ */
2361
+ findMatchingItem: (desiredItem: ItemDesc, inventory: {
2362
+ name: string;
2363
+ stacks: number;
2364
+ enchantment?: EnchantmentDesc;
2365
+ qualityTier?: number;
2366
+ hiddenPotential?: number;
2367
+ }[]) => {
2368
+ name: string;
2369
+ stacks: number;
2370
+ enchantment?: EnchantmentDesc;
2371
+ qualityTier?: number;
2372
+ hiddenPotential?: number;
2373
+ } | undefined;
2374
+ /**
2375
+ * Compare two items for sorting purposes (techniques by subkind, enchantments by target, others alphabetically).
2376
+ * @param a - First item
2377
+ * @param b - Second item
2378
+ * @returns Negative if a < b, positive if a > b, 0 if equal
2379
+ */
2380
+ compareItem: (a: Item, b: Item) => number;
2381
+ /**
2382
+ * Group items into realm-sorted buckets for list display.
2383
+ * @param items - Items to group
2384
+ * @param playerRealm - Player's current realm (items with realm 'any' appear here)
2385
+ * @param categoryFilter - Filter by item kind or 'all'
2386
+ * @param getValue - Optional sort-by-value function (descending); defaults to kind/rarity/name order
2387
+ * @returns Object with sorted items array and group metadata
2388
+ */
2389
+ groupItems: (items: Item[], playerRealm: Realm, categoryFilter: 'all' | ItemKind, getValue?: (item: Item) => number) => {
2390
+ items: Item[];
2391
+ groups: {
2392
+ realm: Realm;
2393
+ count: number;
2394
+ }[];
2395
+ };
2396
+ /**
2397
+ * Group items into realm-sorted rows for grid display.
2398
+ * @param items - Items to group
2399
+ * @param itemsPerRow - How many items fit per row
2400
+ * @param playerRealm - Player's current realm
2401
+ * @param categoryFilter - Filter by item kind, 'all', or 'favourites'
2402
+ * @param favoritedItems - Set of item keys for favourites filter
2403
+ * @returns Object with rows and group metadata
2404
+ */
2405
+ groupItemsGrid: (items: Item[], itemsPerRow: number, playerRealm: Realm, categoryFilter: 'all' | 'favourites' | ItemKind, favoritedItems?: Set<string>) => {
2406
+ rows: Item[][];
2407
+ groups: {
2408
+ realm: Realm;
2409
+ count: number;
2410
+ }[];
2411
+ };
2412
+ /**
2413
+ * Group recipe items into realm-sorted buckets for list display.
2414
+ * @param items - Recipe items to group
2415
+ * @param playerRealm - Player's current realm
2416
+ * @param categoryFilter - Filter by item kind, 'all', 'pinned', or 'pinned-upgrades'
2417
+ * @param pinned - Optional array of pinned recipe names
2418
+ * @returns Object with sorted items array and group metadata
2419
+ */
2420
+ groupRecipes: (items: RecipeItem[], playerRealm: Realm, categoryFilter: 'all' | 'pinned' | 'pinned-upgrades' | ItemKind, pinned?: string[]) => {
2421
+ items: RecipeItem[];
2422
+ groups: {
2423
+ realm: Realm;
2424
+ count: number;
2425
+ }[];
2426
+ };
2427
+ /**
2428
+ * Get the relationship category for a character based on their definition and state.
2429
+ * @param def - Character definition (enemy/neutral/companion)
2430
+ * @param relDef - Current relationship definition (from getRelationshipArray), if any
2431
+ * @returns CharacterRelationship: 'Hostile', 'Neutral', or 'Friendly'
2432
+ */
2433
+ getCharacterRelationship: (def: CharacterDefinition, relDef: CharacterRelationshipDefinition | undefined) => CharacterRelationship;
2434
+ /**
2435
+ * Get the active relationship definition array for a character, accounting for relationship path branching.
2436
+ * @param character - The character definition
2437
+ * @param stateOrCharactersState - Either the full CharactersState or a single CharacterState
2438
+ * @returns Array of CharacterRelationshipDefinition entries
2439
+ */
2440
+ getRelationshipArray: (character: Character, stateOrCharactersState: CharactersState | CharacterState) => CharacterRelationshipDefinition[];
2441
+ /**
2442
+ * Get the current active relationship definition for a character.
2443
+ * @param character - The character definition
2444
+ * @param stateOrCharactersState - Either the full CharactersState or a single CharacterState
2445
+ * @returns The current CharacterRelationshipDefinition, or undefined if character has no data
2446
+ */
2447
+ getCurrentRelDef: (character: Character, stateOrCharactersState: CharactersState | CharacterState) => CharacterRelationshipDefinition | undefined;
2448
+ /**
2449
+ * Get the gift interaction available for a character at the current location.
2450
+ * @param def - The companion character definition
2451
+ * @param data - The character's current state data
2452
+ * @param location - The current location name
2453
+ * @param flags - Current game flags
2454
+ * @returns The applicable GiftCharacterInteraction, or undefined if none available
2455
+ */
2456
+ getGiftInteraction: (def: CompanionCharacterDefinition, data: CharacterState, location: string, flags: Record<string, number>) => GiftCharacterInteraction | undefined;
2457
+ /**
2458
+ * Get the current location of a character based on their state and the player's position.
2459
+ * @param character - The character definition
2460
+ * @param state - The character's current state
2461
+ * @param flags - Current game flags
2462
+ * @param isFollowing - Whether the character is following the player
2463
+ * @param currentPlayerLocation - The player's current location name
2464
+ * @param starData - The fallen star state (for star-based character locations)
2465
+ * @returns Location name string
2466
+ */
2467
+ getCharacterLocation: (character: Character, state: CharacterState, flags: Record<string, number>, isFollowing: boolean, currentPlayerLocation: string, starData: FallenStarState) => string;
2468
+ /**
2469
+ * Get the qi condense efficiency multiplier for a player.
2470
+ * Higher values mean condensation costs less qi.
2471
+ * @param player - The player entity
2472
+ * @param breakthrough - The current breakthrough state
2473
+ * @returns Efficiency multiplier (e.g. 1.2 = 20% more efficient)
2474
+ */
2475
+ getQiCondenseMultiplier: (player: PlayerEntity, breakthrough: BreakthroughState) => number;
2476
+ /**
2477
+ * Calculate the qi, money, and hp cost of a single condensation action.
2478
+ * @param player - The player entity
2479
+ * @param breakthrough - The current breakthrough state
2480
+ * @returns Object with qi, money, and hp costs
2481
+ */
2482
+ getCondensationCost: (player: PlayerEntity, breakthrough: BreakthroughState) => {
2483
+ qi: number;
2484
+ money: number;
2485
+ hp: number;
2486
+ };
2487
+ /**
2488
+ * Check whether the player can currently perform a condensation action.
2489
+ * @param player - The player entity
2490
+ * @param breakthrough - The current breakthrough state
2491
+ * @param inventory - The current inventory state (for money check)
2492
+ * @returns True if condensation can be performed
2493
+ */
2494
+ canCondense: (player: PlayerEntity, breakthrough: BreakthroughState, inventory: InventoryState) => boolean;
2495
+ /**
2496
+ * Discover all unlocked locations reachable from active root locations.
2497
+ * Traverses the location graph following exploration and conditional links.
2498
+ * @param flags - The current game flags
2499
+ * @param unlocked - Array to populate with discovered locations (mutated in place)
2500
+ */
2501
+ discoverUnlockedLocations: (flags: Record<string, number>, unlocked: GameLocation[]) => void;
2502
+ /**
2503
+ * Get the flag name used to track whether an exploration link has been unlocked.
2504
+ * @param location - The parent location
2505
+ * @param child - The exploration link
2506
+ * @returns Flag name string
2507
+ */
2508
+ getExplorationUnlockFlag: (location: GameLocation, child: ExplorationLink) => string;
2509
+ /**
2510
+ * Convert a PlayerEntity into an EnemyEntity that can be used in combat.
2511
+ * Builds stance/rotation data from the player's stored stances and techniques.
2512
+ * @param player - The player entity
2513
+ * @param noEnhancement - If true, strips enhancement from all techniques (for fair mirror matches)
2514
+ * @param breakthrough - The current breakthrough state
2515
+ * @returns An EnemyEntity representing the player as an opponent
2516
+ */
2517
+ playerToEnemyEntity: (player: PlayerEntity, noEnhancement: boolean, breakthrough: BreakthroughState) => EnemyEntity;
2518
+ /**
2519
+ * The highest realm the player can normally reach through standard progression.
2520
+ * Currently 'pillarCreation'. Use this to cap realm-scaled calculations.
2521
+ */
2522
+ maxRealm: Realm;
2115
2523
  };
2116
2524
  hooks: {
2117
2525
  /**
@@ -220,7 +220,7 @@ export interface LocationHerbFieldState {
220
220
  export interface HerbFieldState {
221
221
  locations: Record<string, LocationHerbFieldState>;
222
222
  }
223
- export interface MineSliceState {
223
+ export interface PerMineState {
224
224
  tiles: {
225
225
  [key: string]: MineTile;
226
226
  };
@@ -229,8 +229,15 @@ export interface MineSliceState {
229
229
  seed?: number;
230
230
  placedUniqueChambers?: string[];
231
231
  }
232
+ export interface MineSliceState {
233
+ mines: {
234
+ [mineId: string]: PerMineState;
235
+ };
236
+ }
232
237
  export interface MineViewportState {
233
- mineViewport: Viewport | undefined;
238
+ viewports: {
239
+ [mineId: string]: Viewport | undefined;
240
+ };
234
241
  }
235
242
  export interface WorldMapViewportState {
236
243
  mapViewport: Viewport | undefined;
@@ -312,6 +319,12 @@ export interface StoneCuttingState {
312
319
  gainedItems: ItemDesc[];
313
320
  /** Snapshot of entire event state when stone cutting started, restored on completion */
314
321
  eventStateSnapshot?: GameEventState;
322
+ /** Percentage discount to apply to stone cutting costs (0-100) */
323
+ discountPercentage?: number;
324
+ /** Number of stones the player can cut for free */
325
+ freeCount?: number;
326
+ /** How many free stones have been used */
327
+ stonesBoughtForFree?: number;
315
328
  }
316
329
  export interface FallenStarState {
317
330
  activeSites: Record<string, FallenStarData>;
@@ -369,6 +382,16 @@ export interface HistoryItem {
369
382
  character?: string;
370
383
  buff?: Buff;
371
384
  items?: ItemDesc[];
385
+ money?: number;
386
+ favour?: number;
387
+ reputation?: {
388
+ name: string;
389
+ amount: number;
390
+ };
391
+ approval?: {
392
+ character: string;
393
+ amount: number;
394
+ };
372
395
  destiny?: string;
373
396
  quest?: string;
374
397
  craftingTechnique?: string;
@@ -55,6 +55,39 @@ export interface DelveRoom {
55
55
  description: string;
56
56
  stages: DelveRoomStage[];
57
57
  }
58
+ /** Identifies the runtime behavior for a single step in a serialized DelveRoomConfig.
59
+ * Each kind is bound to a builder in `buildDelveRoom` that produces the live `DelveRoomStage`. */
60
+ export type CombatDelveRoomStepKind = 'mobCombat' | 'swarmCombat' | 'eliteCombat' | 'reinforcementCombat' | 'augmentedEliteCombat' | 'dualCombat' | 'tetheredCombat' | 'penaltyCombat';
61
+ export type DelveRoomStepKind = CombatDelveRoomStepKind | 'reward' | 'blessing' | 'curse';
62
+ interface BaseDelveRoomStepConfig {
63
+ kind: DelveRoomStepKind;
64
+ }
65
+ export interface CombatStepConfig extends BaseDelveRoomStepConfig {
66
+ kind: CombatDelveRoomStepKind;
67
+ }
68
+ export interface RewardStepConfig extends BaseDelveRoomStepConfig {
69
+ kind: 'reward';
70
+ pool: string;
71
+ increasedRarity: boolean;
72
+ }
73
+ export interface BlessingStepConfig extends BaseDelveRoomStepConfig {
74
+ kind: 'blessing';
75
+ count: number;
76
+ }
77
+ export interface CurseStepConfig extends BaseDelveRoomStepConfig {
78
+ kind: 'curse';
79
+ count: number;
80
+ }
81
+ export type DelveRoomStepConfig = CombatStepConfig | RewardStepConfig | BlessingStepConfig | CurseStepConfig;
82
+ /** Pure-data, serializable description of a delve room. Lives on items. Functions
83
+ * (such as enemy builders) are NOT stored here; they are looked up by step kind
84
+ * via `buildDelveRoom`. */
85
+ export interface DelveRoomConfig {
86
+ id: string;
87
+ displayName: Translatable;
88
+ description: string;
89
+ steps: DelveRoomStepConfig[];
90
+ }
58
91
  /** A pre-placed cell in the soul shard grid (source, fixed node, or fixed routing shard). */
59
92
  export interface FixedGridCell {
60
93
  inputs?: {
package/dist/stat.d.ts CHANGED
@@ -80,4 +80,5 @@ export interface Scaling {
80
80
  upgradeKey?: string;
81
81
  buff?: Buff;
82
82
  increment?: number;
83
+ cantUpgrade?: boolean;
83
84
  }
package/dist/stat.js CHANGED
@@ -192,7 +192,7 @@ export const combatStatToDescription = {
192
192
  cloudBoost: '',
193
193
  bloodBoost: '',
194
194
  celestialBoost: '',
195
- barrierMitigation: 'Controls how efficiently your barrier absorbs damage. Barrier always blocks damage first before health is lost.',
195
+ barrierMitigation: 'Controls how efficiently your barrier absorbs damage, with diminishing returns. Barrier always blocks damage first before health is lost.',
196
196
  qiDroplets: '',
197
197
  fistAffinity: '',
198
198
  blossomAffinity: '',
@@ -88,6 +88,7 @@ interface ConsumeSelfTechniqueEffect extends BaseTechniqueEffect {
88
88
  buff: Buff;
89
89
  amount: Scaling;
90
90
  hideBuff?: boolean;
91
+ targeting?: EffectTargeting;
91
92
  }
92
93
  interface ConvertSelfTechniqueEffect extends BaseTechniqueEffect {
93
94
  kind: 'convertSelf';
@@ -153,6 +154,9 @@ interface ModifyBuffGroupEffect extends BaseTechniqueEffect {
153
154
  onTarget?: boolean;
154
155
  group: string;
155
156
  amount: Scaling;
157
+ /** Defaults to 'all'. 'highest'/'lowest' restrict the effect to a single matching buff
158
+ * chosen by stack count. */
159
+ mode?: 'all' | 'highest' | 'lowest';
156
160
  }
157
161
  interface TriggerEffect extends BaseTechniqueEffect {
158
162
  kind: 'trigger';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Type Tests - These files ensure type compatibility across the codebase
3
+ * If any of these fail to compile, it means we have a type mismatch
4
+ */
5
+ import type { RootState as StoreRootState } from '../store';
6
+ import type { RootState as TypesRootState } from './reduxState';
7
+ type TestExactMatch = StoreRootState extends TypesRootState ? TypesRootState extends StoreRootState ? true : false : false;
8
+ export type RootStateIsConsistent = TestExactMatch;
9
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "afnm-types",
3
- "version": "0.6.56",
3
+ "version": "0.6.57",
4
4
  "description": "Type definitions for Ascend From Nine Mountains",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",