afnm-types 0.6.55 → 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
@@ -18,14 +18,17 @@ export type DamageModifier = MultiplyDamageModifier | ReduceDamageModifier | Exp
18
18
  interface MultiplyDamageModifier {
19
19
  kind: 'multiply';
20
20
  value: number;
21
+ cantUpgrade?: boolean;
21
22
  }
22
23
  interface ReduceDamageModifier {
23
24
  kind: 'reduce';
24
25
  percent: number;
26
+ cantUpgrade?: boolean;
25
27
  }
26
28
  interface ExpressionDamageModifier {
27
29
  kind: 'expression';
28
30
  expression: string;
31
+ cantUpgrade?: boolean;
29
32
  }
30
33
  interface ChanceTechniqueCondition extends BaseTechniqueCondition {
31
34
  kind: 'chance';
@@ -54,6 +57,20 @@ interface InventoryItemTechniqueCondition extends BaseTechniqueCondition {
54
57
  count: number;
55
58
  mode: 'more' | 'less' | 'equal';
56
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
+ }
57
74
  export interface Buff {
58
75
  name: string;
59
76
  displayName?: Translatable;
@@ -105,6 +122,7 @@ export interface Buff {
105
122
  /** Block specific triggers from executing. Used to prevent effects like celestial rotation. */
106
123
  blockTriggerEffects?: {
107
124
  trigger: string;
125
+ condition?: TechniqueCondition;
108
126
  effects: BuffEffect[];
109
127
  }[];
110
128
  damageInterceptorEffects?: {
@@ -119,9 +137,10 @@ export interface Buff {
119
137
  amplifier: {
120
138
  kind: 'multiply';
121
139
  value: number;
140
+ cantUpgrade?: boolean;
122
141
  };
123
142
  effects?: BuffEffect[];
124
- appliesTo: ('damage' | 'barrier' | 'heal')[];
143
+ appliesTo: ('damage' | 'barrier' | 'heal' | 'tempHealth')[];
125
144
  }[];
126
145
  /** Amplifies buff creation. Modifies stack count when matching buffs are created on self. */
127
146
  buffAmplifierEffects?: {
@@ -131,6 +150,7 @@ export interface Buff {
131
150
  modifier: {
132
151
  kind: 'add' | 'multiply';
133
152
  value: number;
153
+ cantUpgrade?: boolean;
134
154
  };
135
155
  effects?: BuffEffect[];
136
156
  }[];
@@ -141,6 +161,12 @@ export interface Buff {
141
161
  stacks: number;
142
162
  stacksAreDays?: boolean;
143
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;
144
170
  buffType?: string;
145
171
  buffTypeTooltip?: string;
146
172
  endurePercent?: number;
@@ -152,6 +178,11 @@ export interface Buff {
152
178
  guardianIntercept?: {
153
179
  percent: Scaling;
154
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;
155
186
  };
156
187
  /** Runtime guardian HP — set automatically from guardianIntercept.maxHp at buff creation */
157
188
  guardianHp?: number;
@@ -317,7 +348,7 @@ export interface TransformationCombatImage {
317
348
  animateOnEntity?: boolean;
318
349
  }
319
350
  export type RepairRule = 'all' | 'lowestHealth' | 'highestHealth';
320
- export type BuffEffect = DamageEffect | DamageSelfEffect | HealEffect | BarrierEffect | CreateBuffSelfEffect | ConsumeBuffSelfEffect | CreateBuffTargetEffect | ConsumeBuffTargetEffect | NegateEffect | AddEffect | MultiplyEffect | MergeEffect | TriggerEffect | ModifyBuffGroupEffect | CleanseToxicityEffect | SetStateEffect | ConvertSelfEffect | RepairEffect | ConsumeInventoryItemEffect;
351
+ export type BuffEffect = DamageEffect | DamageSelfEffect | HealEffect | BarrierEffect | GiveTemporaryHealthEffect | CreateBuffSelfEffect | ConsumeBuffSelfEffect | CreateBuffTargetEffect | ConsumeBuffTargetEffect | NegateEffect | AddEffect | MultiplyEffect | MergeEffect | TriggerEffect | ModifyBuffGroupEffect | CleanseToxicityEffect | SetStateEffect | ConvertSelfEffect | RepairEffect | ConsumeInventoryItemEffect;
321
352
  interface BaseBuff {
322
353
  condition?: TechniqueCondition;
323
354
  triggerKey?: string;
@@ -325,6 +356,7 @@ interface BaseBuff {
325
356
  [key in CombatStatistic]: Scaling;
326
357
  }>;
327
358
  hidden?: boolean;
359
+ cantUpgrade?: boolean;
328
360
  }
329
361
  interface DamageEffect extends BaseBuff {
330
362
  kind: 'damage';
@@ -349,6 +381,12 @@ interface BarrierEffect extends BaseBuff {
349
381
  hits?: Scaling;
350
382
  targeting?: EffectTargeting;
351
383
  }
384
+ interface GiveTemporaryHealthEffect extends BaseBuff {
385
+ kind: 'temporaryHealth';
386
+ amount: Scaling;
387
+ hits?: Scaling;
388
+ targeting?: EffectTargeting;
389
+ }
352
390
  interface CreateBuffSelfEffect extends BaseBuff {
353
391
  kind: 'buffSelf';
354
392
  amount: Scaling;
@@ -363,6 +401,7 @@ interface ConsumeBuffSelfEffect extends BaseBuff {
363
401
  buff: Buff | string;
364
402
  silent?: boolean;
365
403
  hideBuff?: boolean;
404
+ targeting?: EffectTargeting;
366
405
  }
367
406
  interface CreateBuffTargetEffect extends BaseBuff {
368
407
  kind: 'buffTarget';
@@ -409,6 +448,9 @@ interface ModifyBuffGroupEffect extends BaseBuff {
409
448
  onTarget?: boolean;
410
449
  group: string;
411
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';
412
454
  }
413
455
  interface SetStateEffect extends BaseBuff {
414
456
  kind: 'setState';
@@ -331,7 +331,7 @@ export interface CharacterRelationshipDefinition {
331
331
  tooltip: Translatable;
332
332
  followCharacter?: FollowCharacterDefinition;
333
333
  dualCultivation?: DualCultivationDefinition;
334
- progressionEvent: {
334
+ progressionEvent?: {
335
335
  name: string;
336
336
  tooltip: Translatable;
337
337
  event: EventStep[];
@@ -3,7 +3,7 @@
3
3
  * Configuration constants for the translation extraction script
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.REQUIREMENT_STRINGS = exports.CONDITION_TEMPLATES = exports.CONDITION_WORDS = exports.HARDCODED_TEMPLATE_PATTERNS = exports.TIER_ONLY_MAPS = exports.STATIC_MAPS = exports.STATIC_ARRAY_NAMES = exports.TEXT_SHADOW = exports.STYLE_COLORS = exports.ELEMENTS = exports.ELEMENT_TO_NAME = exports.RARITIES = exports.RARITY_TO_TIER = exports.REALMS = exports.REALM_TO_NAME = exports.REALM_TO_TIER = exports.CODE_CHANGE_EXCLUDE_FILES = exports.CODE_CHANGE_EXCLUDE_PATTERNS = exports.EXCLUDE_PATTERNS = exports.NON_TRANSLATABLE_PROPERTIES = exports.MIN_STRING_LENGTH = void 0;
6
+ exports.REQUIREMENT_STRINGS = exports.CONDITION_TEMPLATES = exports.CONDITION_WORDS = exports.HARDCODED_TEMPLATE_PATTERNS = exports.TIER_ONLY_MAPS = exports.STATIC_MAPS = exports.STATIC_ARRAY_NAMES = exports.ENEMY_STANCE_NAMES = exports.TEXT_SHADOW = exports.STYLE_COLORS = exports.ELEMENTS = exports.ELEMENT_TO_NAME = exports.RARITIES = exports.RARITY_TO_TIER = exports.REALMS = exports.REALM_TO_NAME = exports.REALM_TO_TIER = exports.CODE_CHANGE_EXCLUDE_FILES = exports.CODE_CHANGE_EXCLUDE_PATTERNS = exports.EXCLUDE_PATTERNS = exports.NON_TRANSLATABLE_PROPERTIES = exports.MIN_STRING_LENGTH = void 0;
7
7
  exports.isTranslatableProperty = isTranslatableProperty;
8
8
  exports.isCamelCase = isCamelCase;
9
9
  exports.shouldExclude = shouldExclude;
@@ -512,6 +512,33 @@ exports.STYLE_COLORS = {
512
512
  num: '#ff877d',
513
513
  };
514
514
  exports.TEXT_SHADOW = 'textShadow: -1px 1px 0 #000, 1px 1px 0 #000, 1px -1px 0 #000, -1px -1px 0 #000;';
515
+ /** Internal stance name identifiers used by EnemyEntity definitions. Never player-facing. */
516
+ exports.ENEMY_STANCE_NAMES = new Set([
517
+ 'absorb', 'accelerate', 'aggressive', 'agitation', 'amplify', 'animate', 'ascension',
518
+ 'assault', 'assess', 'attack', 'attack1', 'attack2', 'attack3', 'attack4', 'attackBig',
519
+ 'barrier', 'barrierHater', 'barrierMit', 'bigBloat', 'blast', 'block', 'blood', 'blossom',
520
+ 'boil', 'bolt', 'buff', 'buffSelf', 'buffStance', 'buffTarget', 'build', 'burn',
521
+ 'burrowStrike', 'burst', 'cacophonyPhase', 'celestial', 'celestialradiance', 'chaosForge',
522
+ 'charge', 'cleave', 'cloud', 'collapse', 'compliance', 'constrict', 'consume', 'consuming',
523
+ 'control', 'corrupt', 'corrupted_swarm', 'counterattack', 'crownedascension',
524
+ 'crownedgathering', 'crownedradiance', 'crushing', 'damage', 'damageHeavy', 'debuff',
525
+ 'debuffHeal', 'debuffStance', 'defend', 'defending', 'defensive', 'defensiveHeavy',
526
+ 'defensiveStance', 'desertGuardian', 'desperate', 'destabilize', 'dissonancePhase', 'drain',
527
+ 'eclipse', 'emerald', 'endure', 'enhanced_attack', 'enhanced_attack1', 'enhanced_attack2',
528
+ 'enhanced_attack3', 'enhanced_block', 'enhanced_rend', 'escalation1', 'escalation2',
529
+ 'fieldSet', 'finale', 'first', 'firstRound', 'fist', 'float', 'focus', 'forging', 'fortify',
530
+ 'frenzy', 'gathering', 'gore', 'gossamerLight', 'gossamerShadow', 'gossamerVault', 'guard',
531
+ 'harm', 'harmonyPhase', 'heal', 'healDebuff', 'initializing', 'kick', 'lash', 'lethargy',
532
+ 'mend', 'meteor', 'mindlessAttack', 'moon', 'multihits', 'mystic', 'needle', 'offensiveStance',
533
+ 'opener', 'origin', 'overcharged', 'pause', 'peck', 'pierce', 'plumagegathering', 'power',
534
+ 'powerBuildUp', 'preparation', 'prepare', 'pressureAssault', 'pulse', 'punch', 'purge',
535
+ 'recklessness', 'rend', 'ruby', 'sandstorm', 'sap', 'sapphire', 'seal', 'setup', 'setup1',
536
+ 'setup2', 'setup3', 'shatter', 'shroudLight', 'shroudShadow', 'shroudVault', 'siphon', 'soar',
537
+ 'spin', 'stack', 'stacks', 'steal', 'sun', 'surge', 'sustain', 'swarm', 'swarmling',
538
+ 'swarmlord', 'touch', 'turtle', 'twisted_rampage', 'underground', 'unleash', 'unravel',
539
+ 'unstableFury', 'vaultBreak', 'venom', 'venomMaster', 'wail', 'weapon', 'weave',
540
+ 'weaveAttacker', 'weaveHealer', 'weaveLight', 'weaveProtector', 'weaveShadow', 'windDancer',
541
+ ]);
515
542
  /** Arrays that indicate static map iteration */
516
543
  exports.STATIC_ARRAY_NAMES = ['realms', 'techniqueElements'];
517
544
  /** Static maps that can be expanded */
@@ -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);
@@ -653,9 +665,10 @@ function extractFromFile(filePath) {
653
665
  // not player-facing text (e.g., "attack1", "enhanced_attack2", "stack", "power")
654
666
  // Exception: manual items have style/stances with player-facing names like "Defensive Focus"
655
667
  if (propName === 'name' &&
656
- nestedPath &&
657
- ((/\bstances\b/.test(nestedPath) && !/\bstyle\b/.test(nestedPath)) ||
658
- /\bmastery\b/.test(nestedPath))) {
668
+ ((nestedPath &&
669
+ ((/\bstances\b/.test(nestedPath) && !/\bstyle\b/.test(nestedPath)) ||
670
+ /\bmastery\b/.test(nestedPath))) ||
671
+ (typescript_1.default.isStringLiteral(node.initializer) && config_js_1.ENEMY_STANCE_NAMES.has(node.initializer.text)))) {
659
672
  typescript_1.default.forEachChild(node, visit);
660
673
  return;
661
674
  }
@@ -923,7 +936,12 @@ function extractFromFile(filePath) {
923
936
  }
924
937
  }
925
938
  }
926
- if (!isDirectExportedArray) {
939
+ // Skip arrays that are values of non-translatable properties (e.g., stances: ['attack1', ...])
940
+ const isInsideNonTranslatableProperty = parent &&
941
+ typescript_1.default.isPropertyAssignment(parent) &&
942
+ typescript_1.default.isIdentifier(parent.name) &&
943
+ !(0, config_js_1.isTranslatableProperty)(parent.name.text);
944
+ if (!isDirectExportedArray && !isInsideNonTranslatableProperty) {
927
945
  const stringElements = node.elements.filter((el) => typescript_1.default.isStringLiteral(el) || typescript_1.default.isNoSubstitutionTemplateLiteral(el));
928
946
  if (stringElements.length > 0) {
929
947
  const translatableStrings = stringElements
@@ -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;
@@ -0,0 +1,186 @@
1
+ import { Buff, Translatable } from '.';
2
+ import { BreakthroughState } from './breakthrough';
3
+ import { PlayerEntity, CombatEntity, EnemyEntity, CombatEffectTracking, EntityType } from './entity';
4
+ import { ArtefactTechnique, Item } from './item';
5
+ import { InventoryItemState } from './reduxState';
6
+ import { Technique } from './technique';
7
+ import { PhysicalStatistic, SocialStatistic } from './stat';
8
+ export interface CombatLogEffects {
9
+ source: string;
10
+ damage?: number;
11
+ barrier?: number;
12
+ healing?: number;
13
+ temporaryHealth?: number;
14
+ /** Delta toxicity: positive = gained, negative = cleansed */
15
+ toxicity?: number;
16
+ buffsCreated?: Record<string, number>;
17
+ buffsInflicted?: Record<string, number>;
18
+ buffsConsumed?: Record<string, number>;
19
+ }
20
+ /**
21
+ * Optional semantic metadata for structured analysis of log entries.
22
+ * Used by defeatAnalysis and other systems to avoid regex-based string parsing.
23
+ */
24
+ export interface CombatLogMeta {
25
+ /** Name of the technique or buff that was executed */
26
+ techniqueName?: string;
27
+ /** True when the technique failed to execute */
28
+ failed?: boolean;
29
+ /** The resource that was insufficient/excessive when a technique failed */
30
+ failedResource?: string;
31
+ /** True when this entry records a self-damage event */
32
+ selfDamage?: boolean;
33
+ /** Remaining HP of the target after this damage event */
34
+ remainingHp?: number;
35
+ /** True when this entry marks the end of a round */
36
+ roundEnd?: boolean;
37
+ /** True when this entry is a turn section header (Player's Turn, Enemy's Turn, etc.) */
38
+ turnHeader?: boolean;
39
+ }
40
+ export interface CombatEntitySnapshot {
41
+ hp: number;
42
+ maxHp: number;
43
+ barrier: number;
44
+ }
45
+ export interface CombatPartyMemberSnapshot extends CombatEntitySnapshot {
46
+ partyId?: string;
47
+ }
48
+ export interface CombatStateSnapshot {
49
+ player?: CombatEntitySnapshot;
50
+ enemy?: CombatEntitySnapshot;
51
+ playerParty?: CombatPartyMemberSnapshot[];
52
+ enemyParty?: CombatPartyMemberSnapshot[];
53
+ }
54
+ export interface CombatLogEntry {
55
+ path: string;
56
+ /** Which entity this log entry is about */
57
+ entity: EntityType;
58
+ /** UUID of the specific party member — only set when entity is PlayerParty or EnemyParty */
59
+ partyId?: string;
60
+ message: string;
61
+ effects?: CombatLogEffects;
62
+ meta?: CombatLogMeta;
63
+ /** Snapshot of HP/barrier for all combat entities at the moment this entry was created */
64
+ state?: CombatStateSnapshot;
65
+ }
66
+ export interface StanceTracking {
67
+ techniques: string[];
68
+ name: string;
69
+ count: number;
70
+ }
71
+ export interface PlayerStanceData {
72
+ playerStanceIndex: number;
73
+ usedPlayerStanceOpeners: boolean[];
74
+ lastPlayerStance: string;
75
+ lastCycleKey?: string;
76
+ }
77
+ export interface CurrentCombatState {
78
+ player: PlayerEntity | undefined;
79
+ playerState: CombatEntity | undefined;
80
+ breakthrough: BreakthroughState | undefined;
81
+ playerStanceData: PlayerStanceData | undefined;
82
+ enemies: EnemyEntity[];
83
+ foughtEnemies: EnemyEntity[];
84
+ enemyState: CombatEntity | undefined;
85
+ lastEnemyStance: string | undefined;
86
+ currentPhase: number;
87
+ allPhases: EnemyEntity[];
88
+ phaseTransitioning: boolean;
89
+ roundNum: number;
90
+ roundState: RoundState | undefined;
91
+ consumedPills: number;
92
+ noEnhancement?: boolean;
93
+ noCrit?: boolean;
94
+ trainingMode?: boolean;
95
+ isSpar?: boolean;
96
+ playerEffectTracking: Record<string, CombatEffectTracking>;
97
+ enemyEffectTracking: Record<string, CombatEffectTracking>;
98
+ stanceTracking: Record<string, StanceTracking>;
99
+ partyStanceTracking: Record<number, Record<string, StanceTracking>>;
100
+ pillTracking: Record<string, number>;
101
+ autoUseRowTracking: Record<number, number>;
102
+ inventoryItems?: InventoryItemState[];
103
+ loot: Item[];
104
+ kills: {
105
+ name: string;
106
+ displayName?: Translatable;
107
+ }[];
108
+ qi: number;
109
+ combatState: 'victory' | 'defeat' | undefined;
110
+ combatLog: CombatLogEntry[];
111
+ gameFlags: Record<string, number>;
112
+ precalculatedLoot: {
113
+ items: Item[];
114
+ qi: number;
115
+ }[];
116
+ lootBurstTriggered: boolean;
117
+ lootBurstQueue: {
118
+ id: string;
119
+ loot: Item[];
120
+ qi: number;
121
+ enemyPosition: {
122
+ x: number;
123
+ y: number;
124
+ };
125
+ playerPosition: {
126
+ x: number;
127
+ y: number;
128
+ };
129
+ }[];
130
+ previewCallbacks?: {
131
+ onBuffFailed: (buff: Buff) => void;
132
+ };
133
+ /** Permanent stat changes accumulated during combat to be applied to the player on exit. */
134
+ permanentStatChanges?: Partial<Record<PhysicalStatistic | SocialStatistic, number>>;
135
+ }
136
+ export interface RoundState {
137
+ player: EntityRoundState;
138
+ enemy: EntityRoundState;
139
+ playerArtefacts: ArtefactRoundState[];
140
+ enemyArtefacts: ArtefactRoundState[];
141
+ playerParty: EntityRoundState[];
142
+ enemyParty: EntityRoundState[];
143
+ roundQueue: RoundStep[];
144
+ delay: number;
145
+ }
146
+ export type RoundStep = PlayerRoundStep | PlayerArtefactRoundStep | PlayerPartyRoundStep | EnemyRoundStep | EnemyArtefactRoundStep | EnemyPartyRoundStep | BuffsRoundStep | BuffsRoundStartStep | EndRoundStep;
147
+ export interface PlayerRoundStep {
148
+ kind: 'player';
149
+ }
150
+ export interface PlayerArtefactRoundStep {
151
+ kind: 'playerArtefact';
152
+ index: number;
153
+ }
154
+ export interface PlayerPartyRoundStep {
155
+ kind: 'playerParty';
156
+ index: number;
157
+ }
158
+ export interface EnemyArtefactRoundStep {
159
+ kind: 'enemyArtefact';
160
+ index: number;
161
+ }
162
+ export interface EnemyPartyRoundStep {
163
+ kind: 'enemyParty';
164
+ index: number;
165
+ }
166
+ export interface EnemyRoundStep {
167
+ kind: 'enemy';
168
+ }
169
+ export interface BuffsRoundStep {
170
+ kind: 'buffs';
171
+ }
172
+ export interface BuffsRoundStartStep {
173
+ kind: 'buffsStart';
174
+ }
175
+ export interface EndRoundStep {
176
+ kind: 'end';
177
+ }
178
+ export interface EntityRoundState {
179
+ techniques: Technique[];
180
+ used: Technique[];
181
+ doneUltimate: boolean;
182
+ }
183
+ export interface ArtefactRoundState {
184
+ techniques: ArtefactTechnique[];
185
+ used: ArtefactTechnique[];
186
+ }
package/dist/combat.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/entity.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface CombatEffectTracking {
14
14
  damage: number;
15
15
  healing: number;
16
16
  barrier: number;
17
+ temphp: number;
17
18
  damageTaken: number;
18
19
  }
19
20
  export declare const entityTypes: readonly ["Player", "Lifeform", "Enemy", "PlayerParty", "EnemyParty", "System"];
@@ -332,6 +333,8 @@ export interface CombatEntity {
332
333
  partyId?: string;
333
334
  /** When true, critchance is forced to 0 for this entity (used in training ground) */
334
335
  noCrit?: boolean;
336
+ /** Maximum qi droplets for this entity (set during combat entity creation) */
337
+ maxqiDroplets?: number;
335
338
  /** Cached hash for getVariablesFromEntity. Cleared whenever stats or buffs mutate. */
336
339
  _cachedHash?: string;
337
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.55";
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.55";
18
+ export const GAME_VERSION = "0.6.57";
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './calendar';
8
8
  export * from './character';
9
9
  export * from './CharacterRequestEncounter';
10
10
  export * from './components';
11
+ export * from './combat';
11
12
  export * from './crafting';
12
13
  export * from './craftingBuff';
13
14
  export * from './craftingState';
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ export * from './calendar';
8
8
  export * from './character';
9
9
  export * from './CharacterRequestEncounter';
10
10
  export * from './components';
11
+ export * from './combat';
11
12
  export * from './crafting';
12
13
  export * from './craftingBuff';
13
14
  export * from './craftingState';
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 {};
@@ -1,5 +1,5 @@
1
1
  export type KeybindingCategory = 'general' | 'navigation' | 'ui' | 'world' | 'combat' | 'crafting' | 'dialogs' | 'gamepad';
2
- export type KeybindingAction = 'confirm' | 'cancel' | 'pause' | 'alternateConfirm' | 'moveUp' | 'moveDown' | 'moveLeft' | 'moveRight' | 'openInventory' | 'openQuests' | 'openCharacterStats' | 'openTechniques' | 'openCalendar' | 'openWorldMap' | 'combatSelectStance0' | 'combatSelectStance1' | 'combatSelectStance2' | 'combatSelectStance3' | 'combatSelectStance4' | 'combatSelectStance5' | 'combatSelectStance6' | 'combatSelectStance7' | 'combatSelectStance8' | 'combatSelectStance9' | 'combatToggleSpeed' | 'combatToggleLog' | 'combatShowStats' | 'combatAutoBattle' | 'combatUseItem' | 'combatCancel' | 'craftingAction1' | 'craftingAction2' | 'craftingAction3' | 'craftingAction4' | 'craftingAction5' | 'craftingAction6' | 'craftingAction7' | 'craftingAction8' | 'craftingAction9' | 'craftingAction10' | 'craftingAction11' | 'craftingAction12' | 'craftingAction13' | 'craftingAction14' | 'craftingAction15' | 'craftingAction16' | 'craftingAction17' | 'craftingAction18' | 'craftingAction19' | 'craftingAction20' | 'craftingAction21' | 'craftingAction22' | 'craftingAction23' | 'craftingAction24' | 'craftingAction25' | 'craftingAction26' | 'craftingAction27' | 'craftingAction28' | 'craftingAction29' | 'craftingAction30' | 'craftingAction31' | 'craftingAction32' | 'craftingAction33' | 'craftingAction34' | 'craftingAction35' | 'craftingAction36' | 'craftingAction37' | 'craftingAction38' | 'craftingAction39' | 'craftingAction40' | 'craftingAction41' | 'craftingAction42' | 'craftingAction43' | 'craftingAction44' | 'craftingAction45' | 'craftingAction46' | 'craftingAction47' | 'craftingAction48' | 'craftingAction49' | 'craftingAction50' | 'dialogChoice1' | 'dialogChoice2' | 'dialogChoice3' | 'dialogChoice4' | 'dialogChoice5' | 'dialogChoice6' | 'dialogChoice7' | 'dialogChoice8' | 'dialogChoice9' | 'gamepadConfirm' | 'gamepadCancel' | 'gamepadUp' | 'gamepadDown' | 'gamepadLeft' | 'gamepadRight';
2
+ export type KeybindingAction = 'confirm' | 'cancel' | 'pause' | 'alternateConfirm' | 'moveUp' | 'moveDown' | 'moveLeft' | 'moveRight' | 'openInventory' | 'openQuests' | 'openCharacterStats' | 'openTechniques' | 'openCalendar' | 'lockTooltip' | 'openWorldMap' | 'combatSelectStance0' | 'combatSelectStance1' | 'combatSelectStance2' | 'combatSelectStance3' | 'combatSelectStance4' | 'combatSelectStance5' | 'combatSelectStance6' | 'combatSelectStance7' | 'combatSelectStance8' | 'combatSelectStance9' | 'combatToggleSpeed' | 'combatToggleLog' | 'combatShowStats' | 'combatAutoBattle' | 'combatUseItem' | 'combatCancel' | 'craftingAction1' | 'craftingAction2' | 'craftingAction3' | 'craftingAction4' | 'craftingAction5' | 'craftingAction6' | 'craftingAction7' | 'craftingAction8' | 'craftingAction9' | 'craftingAction10' | 'craftingAction11' | 'craftingAction12' | 'craftingAction13' | 'craftingAction14' | 'craftingAction15' | 'craftingAction16' | 'craftingAction17' | 'craftingAction18' | 'craftingAction19' | 'craftingAction20' | 'craftingAction21' | 'craftingAction22' | 'craftingAction23' | 'craftingAction24' | 'craftingAction25' | 'craftingAction26' | 'craftingAction27' | 'craftingAction28' | 'craftingAction29' | 'craftingAction30' | 'craftingAction31' | 'craftingAction32' | 'craftingAction33' | 'craftingAction34' | 'craftingAction35' | 'craftingAction36' | 'craftingAction37' | 'craftingAction38' | 'craftingAction39' | 'craftingAction40' | 'craftingAction41' | 'craftingAction42' | 'craftingAction43' | 'craftingAction44' | 'craftingAction45' | 'craftingAction46' | 'craftingAction47' | 'craftingAction48' | 'craftingAction49' | 'craftingAction50' | 'dialogChoice1' | 'dialogChoice2' | 'dialogChoice3' | 'dialogChoice4' | 'dialogChoice5' | 'dialogChoice6' | 'dialogChoice7' | 'dialogChoice8' | 'dialogChoice9' | 'gamepadConfirm' | 'gamepadCancel' | 'gamepadUp' | 'gamepadDown' | 'gamepadLeft' | 'gamepadRight';
3
3
  export interface KeybindingDefinition {
4
4
  action: KeybindingAction | string;
5
5
  category: KeybindingCategory;
@@ -28,6 +28,7 @@ export declare const MODIFIER_PREFIXES: {
28
28
  readonly alt: "Alt+";
29
29
  readonly shift: "Shift+";
30
30
  };
31
+ export declare const baseKeyToCode: Record<string, string>;
31
32
  export declare function getBaseKeyFromEvent(event: KeyboardEvent): string;
32
33
  export declare function buildKeybindingString(key: string, modifiers: {
33
34
  ctrl?: boolean;