libram 0.8.18 → 0.8.21

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.
@@ -11,7 +11,7 @@ import { sum, flat } from "../utils";
11
11
  function mergeConstraints(...allConstraints) {
12
12
  const familiars = allConstraints
13
13
  .map((constraints) => constraints.familiar)
14
- .filter((familiar) => familiar);
14
+ .filter(Boolean);
15
15
  if (familiars.length > 1) {
16
16
  // Inconsistent requirements.
17
17
  return null;
@@ -0,0 +1,16 @@
1
+ import { ActionSource, FindActionSourceConstraints } from "./ActionSource";
2
+ /**
3
+ * Find an available banish source subject to constraints.
4
+ *
5
+ * @param constraints Preexisting constraints that restrict possible sources.
6
+ * @returns Banish source satisfying constraints, or null.
7
+ */
8
+ export declare function tryFindBanish(constraints?: FindActionSourceConstraints): ActionSource | null;
9
+ /**
10
+ * Ensure an available banish source subject to constraints.
11
+ * Throws an error if no source can be found.
12
+ *
13
+ * @param constraints Preexisting constraints that restrict possible sources.
14
+ * @returns Banish source satisfying constraints.
15
+ */
16
+ export declare function ensureBanish(constraints?: FindActionSourceConstraints): ActionSource;
@@ -0,0 +1,121 @@
1
+ import { canEquip, cliExecute, myTurncount, restoreMp, retrieveItem, visitUrl, } from "kolmafia";
2
+ import { Macro } from "../combat";
3
+ import { getFoldGroup, have } from "../lib";
4
+ import { Requirement } from "../maximize";
5
+ import { get } from "../property";
6
+ import * as AsdonMartin from "../resources/2017/AsdonMartin";
7
+ import { $item, $items, $skill } from "../template-string";
8
+ import { ActionSource, findActionSource, } from "./ActionSource";
9
+ // Value of _lastCombatStarted the last time we updated scrapbook charges.
10
+ let scrapbookChargesLastUpdated = get("_lastCombatStarted");
11
+ // Free unlimited source every 30 turns.
12
+ // Does not work on special monsters so needs a backup, see tryFindFreeRun.
13
+ // banishedMonsters isn't updated if the banish succeeds on an unbanishable monster
14
+ const asdonMartinSource = new ActionSource($skill `Asdon Martin: Spring-Loaded Front Bumper`, () => {
15
+ if (!AsdonMartin.installed())
16
+ return 0;
17
+ const banishes = get("banishedMonsters").split(":");
18
+ const bumperIndex = banishes
19
+ .map((string) => string.toLowerCase())
20
+ .indexOf("spring-loaded front bumper");
21
+ if (bumperIndex === -1)
22
+ return 1;
23
+ return myTurncount() - parseInt(banishes[bumperIndex + 1]) > 30 ? 1 : 0;
24
+ }, Macro.trySkill($skill `Asdon Martin: Spring-Loaded Front Bumper`), {
25
+ preparation: () => AsdonMartin.fillTo(50),
26
+ });
27
+ const banishSources = [
28
+ // Free limited sources
29
+ new ActionSource($skill `Snokebomb`, () => (have($skill `Snokebomb`) ? 3 - get("_snokebombUsed") : 0), Macro.skill($skill `Snokebomb`), {
30
+ preparation: () => restoreMp(50),
31
+ }),
32
+ new ActionSource($skill `Emotionally Chipped`, () => (have($skill `Emotionally Chipped`) ? 3 - get("_feelHatredUsed") : 0), Macro.skill($skill `Feel Hatred`)),
33
+ new ActionSource($item `Kremlin's Greatest Briefcase`, () => have($item `Kremlin's Greatest Briefcase`)
34
+ ? 3 - get("_kgbTranquilizerDartUses")
35
+ : 0, Macro.skill($skill `KGB tranquilizer dart`), {
36
+ equipmentRequirements: () => new Requirement([], {
37
+ forceEquip: $items `Kremlin's Greatest Briefcase`,
38
+ }),
39
+ }),
40
+ new ActionSource($item `latte lovers member's mug`, () => have($item `latte lovers member's mug`) && !get("_latteBanishUsed")
41
+ ? 1
42
+ : 0, Macro.skill($skill `Throw Latte on Opponent`), {
43
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `latte lovers member's mug` }),
44
+ }),
45
+ new ActionSource($item `Lil' Doctor™ bag`, () => (have($item `Lil' Doctor™ bag`) ? 3 - get("_reflexHammerUsed") : 0), Macro.skill($skill `Reflex Hammer`), {
46
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `Lil' Doctor™ bag` }),
47
+ }),
48
+ new ActionSource($item `mafia middle finger ring`, () => have($item `mafia middle finger ring`) &&
49
+ canEquip($item `mafia middle finger ring`) &&
50
+ !get("_mafiaMiddleFingerRingUsed")
51
+ ? 1
52
+ : 0, Macro.skill($skill `Show them your ring`), {
53
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `mafia middle finger ring` }),
54
+ }),
55
+ new ActionSource($item `V for Vivala mask`, () => have($item `V for Vivala mask`) && !get("_vmaskBanisherUsed") ? 1 : 0, Macro.skill($skill `Creepy Grin`), {
56
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `V for Vivala mask` }),
57
+ preparation: () => restoreMp(30),
58
+ }),
59
+ new ActionSource($item `stinky cheese eye`, () => getFoldGroup($item `stinky cheese eye`).some((item) => have(item)) &&
60
+ !get("_stinkyCheeseBanisherUsed")
61
+ ? 1
62
+ : 0, Macro.skill($skill `Give Your Opponent the Stinkeye`), {
63
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `stinky cheese eye` }),
64
+ preparation: () => {
65
+ if (!have($item `stinky cheese eye`)) {
66
+ cliExecute(`fold stinky cheese eye`);
67
+ }
68
+ return have($item `stinky cheese eye`);
69
+ },
70
+ }),
71
+ new ActionSource($skill `Show your boring familiar pictures`, () => {
72
+ if (have($item `familiar scrapbook`)) {
73
+ if (scrapbookChargesLastUpdated !== get("_lastCombatStarted")) {
74
+ visitUrl("desc_item.php?whichitem=463063785");
75
+ scrapbookChargesLastUpdated = get("_lastCombatStarted");
76
+ }
77
+ return Math.floor(get("scrapbookCharges") / 100);
78
+ }
79
+ return 0;
80
+ }, Macro.skill($skill `Show your boring familiar pictures`), {
81
+ equipmentRequirements: () => new Requirement([], { forceEquip: $items `familiar scrapbook` }),
82
+ }),
83
+ new ActionSource($item `human musk`, () => Math.max(0, 3 - get("_humanMuskUses")), Macro.item($item `human musk`), {
84
+ preparation: () => retrieveItem($item `human musk`),
85
+ cost: () => ActionSource.defaultPriceFunction($item `human musk`),
86
+ }),
87
+ // Expensive unlimited sources
88
+ ...$items `Louder Than Bomb, divine champagne popper, tennis ball`.map((item) => new ActionSource(item, () => Infinity, Macro.item(item), {
89
+ preparation: () => retrieveItem(item),
90
+ cost: () => ActionSource.defaultPriceFunction(item),
91
+ })),
92
+ ];
93
+ /**
94
+ * Find an available banish source subject to constraints.
95
+ *
96
+ * @param constraints Preexisting constraints that restrict possible sources.
97
+ * @returns Banish source satisfying constraints, or null.
98
+ */
99
+ export function tryFindBanish(constraints) {
100
+ let source = findActionSource(banishSources, constraints);
101
+ // Always try to use Asdon Martin: Spring-Loaded Front Bumper first,
102
+ // but only if another source has been found.
103
+ if (source && asdonMartinSource.available()) {
104
+ source = asdonMartinSource.merge(source);
105
+ }
106
+ return source;
107
+ }
108
+ /**
109
+ * Ensure an available banish source subject to constraints.
110
+ * Throws an error if no source can be found.
111
+ *
112
+ * @param constraints Preexisting constraints that restrict possible sources.
113
+ * @returns Banish source satisfying constraints.
114
+ */
115
+ export function ensureBanish(constraints) {
116
+ const source = tryFindBanish(constraints);
117
+ if (!source) {
118
+ throw new Error("Failed to ensure Banish source");
119
+ }
120
+ return source;
121
+ }
@@ -1,31 +1,14 @@
1
- import { canEquip, cliExecute, myTurncount, restoreMp, retrieveItem, visitUrl, } from "kolmafia";
1
+ import { retrieveItem } from "kolmafia";
2
2
  import { Macro } from "../combat";
3
- import { ensureEffect, getFoldGroup, getSongCount, getSongLimit, have, } from "../lib";
3
+ import { ensureEffect, getSongCount, getSongLimit, have } from "../lib";
4
4
  import { Requirement } from "../maximize";
5
5
  import { get } from "../property";
6
6
  import * as Bandersnatch from "../resources/2009/Bandersnatch";
7
7
  import * as StompingBoots from "../resources/2011/StompingBoots";
8
- import * as AsdonMartin from "../resources/2017/AsdonMartin";
9
- import { $effect, $familiar, $item, $items, $skill } from "../template-string";
8
+ import { $effect, $familiar, $item, $items } from "../template-string";
10
9
  import { ActionSource, findActionSource, } from "./ActionSource";
11
- // Value of _lastCombatStarted the last time we updated scrapbook charges.
12
- let scrapbookChargesLastUpdated = get("_lastCombatStarted");
13
- // Free unlimited source every 30 turns.
14
- // Does not work on special monsters so needs a backup, see tryFindFreeRun.
15
- // banishedMonsters isn't updated if the free run succeeds on an unbanishable monster
16
- const asdonMartinSource = new ActionSource($skill `Asdon Martin: Spring-Loaded Front Bumper`, () => {
17
- if (!AsdonMartin.installed())
18
- return 0;
19
- const banishes = get("banishedMonsters").split(":");
20
- const bumperIndex = banishes
21
- .map((string) => string.toLowerCase())
22
- .indexOf("spring-loaded front bumper");
23
- if (bumperIndex === -1)
24
- return 1;
25
- return myTurncount() - parseInt(banishes[bumperIndex + 1]) > 30 ? 1 : 0;
26
- }, Macro.trySkill($skill `Asdon Martin: Spring-Loaded Front Bumper`), {
27
- preparation: () => AsdonMartin.fillTo(50),
28
- });
10
+ // eslint-disable-next-line libram/verify-constants
11
+ const EVERYTHING_LOOKS_GREEN = $effect `Everything Looks Green`;
29
12
  const freeRunSources = [
30
13
  // Free limited sources
31
14
  new ActionSource($familiar `Frumious Bandersnatch`, () => (have($effect `Ode to Booze`) || getSongCount() < getSongLimit()) &&
@@ -43,48 +26,6 @@ const freeRunSources = [
43
26
  equipmentRequirements: () => new Requirement(["Familiar Weight"], {}),
44
27
  familiar: () => $familiar `Pair of Stomping Boots`,
45
28
  }),
46
- new ActionSource($skill `Snokebomb`, () => (have($skill `Snokebomb`) ? 3 - get("_snokebombUsed") : 0), Macro.skill($skill `Snokebomb`), {
47
- preparation: () => restoreMp(50),
48
- }),
49
- new ActionSource($skill `Emotionally Chipped`, () => (have($skill `Emotionally Chipped`) ? 3 - get("_feelHatredUsed") : 0), Macro.skill($skill `Feel Hatred`)),
50
- new ActionSource($item `Kremlin's Greatest Briefcase`, () => have($item `Kremlin's Greatest Briefcase`)
51
- ? 3 - get("_kgbTranquilizerDartUses")
52
- : 0, Macro.skill($skill `KGB tranquilizer dart`), {
53
- equipmentRequirements: () => new Requirement([], {
54
- forceEquip: $items `Kremlin's Greatest Briefcase`,
55
- }),
56
- }),
57
- new ActionSource($item `latte lovers member's mug`, () => have($item `latte lovers member's mug`) && !get("_latteBanishUsed")
58
- ? 1
59
- : 0, Macro.skill($skill `Throw Latte on Opponent`), {
60
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `latte lovers member's mug` }),
61
- }),
62
- new ActionSource($item `Lil' Doctor™ bag`, () => (have($item `Lil' Doctor™ bag`) ? 3 - get("_reflexHammerUsed") : 0), Macro.skill($skill `Reflex Hammer`), {
63
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `Lil' Doctor™ bag` }),
64
- }),
65
- new ActionSource($item `mafia middle finger ring`, () => have($item `mafia middle finger ring`) &&
66
- canEquip($item `mafia middle finger ring`) &&
67
- !get("_mafiaMiddleFingerRingUsed")
68
- ? 1
69
- : 0, Macro.skill($skill `Show them your ring`), {
70
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `mafia middle finger ring` }),
71
- }),
72
- new ActionSource($item `V for Vivala mask`, () => have($item `V for Vivala mask`) && !get("_vmaskBanisherUsed") ? 1 : 0, Macro.skill($skill `Creepy Grin`), {
73
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `V for Vivala mask` }),
74
- preparation: () => restoreMp(30),
75
- }),
76
- new ActionSource($item `stinky cheese eye`, () => getFoldGroup($item `stinky cheese eye`).some((item) => have(item)) &&
77
- !get("_stinkyCheeseBanisherUsed")
78
- ? 1
79
- : 0, Macro.skill($skill `Give Your Opponent the Stinkeye`), {
80
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `stinky cheese eye` }),
81
- preparation: () => {
82
- if (!have($item `stinky cheese eye`)) {
83
- cliExecute(`fold stinky cheese eye`);
84
- }
85
- return have($item `stinky cheese eye`);
86
- },
87
- }),
88
29
  new ActionSource($item `navel ring of navel gazing`, () => have($item `navel ring of navel gazing`)
89
30
  ? Math.max(0, 3 - get("_navelRunaways"))
90
31
  : 0, Macro.step("runaway"), {
@@ -95,31 +36,20 @@ const freeRunSources = [
95
36
  : 0, Macro.step("runaway"), {
96
37
  equipmentRequirements: () => new Requirement([], { forceEquip: $items `Greatest American Pants` }),
97
38
  }),
98
- new ActionSource($skill `Show your boring familiar pictures`, () => {
99
- if (have($item `familiar scrapbook`)) {
100
- if (scrapbookChargesLastUpdated !== get("_lastCombatStarted")) {
101
- visitUrl("desc_item.php?whichitem=463063785");
102
- scrapbookChargesLastUpdated = get("_lastCombatStarted");
103
- }
104
- return Math.floor(get("scrapbookCharges") / 100);
105
- }
106
- return 0;
107
- }, Macro.skill($skill `Show your boring familiar pictures`), {
108
- equipmentRequirements: () => new Requirement([], { forceEquip: $items `familiar scrapbook` }),
109
- }),
110
39
  new ActionSource($item `peppermint parasol`, () => Math.max(0, 3 - get("_navelRunaways")), Macro.item($item `peppermint parasol`), {
111
40
  preparation: () => retrieveItem($item `peppermint parasol`),
112
41
  cost: () => Math.min(ActionSource.defaultPriceFunction($item `peppermint sprout`) * 5, ActionSource.defaultPriceFunction($item `peppermint parasol`)) / 10, // Breaks after 10 successful runaways.
113
42
  }),
114
- new ActionSource($item `human musk`, () => Math.max(0, 3 - get("_humanMuskUses")), Macro.item($item `human musk`), {
115
- preparation: () => retrieveItem($item `human musk`),
116
- cost: () => ActionSource.defaultPriceFunction($item `human musk`),
117
- }),
118
- // Expensive unlimited sources
119
- ...$items `Louder Than Bomb, divine champagne popper, tennis ball`.map((item) => new ActionSource(item, () => Infinity, Macro.item(item), {
43
+ // unlimited items that trigger everything looks green
44
+ ...$items `green smoke bomb, tattered scrap of paper, GOTO, T.U.R.D.S. Key`.map((item) => new ActionSource(item, () => (have(EVERYTHING_LOOKS_GREEN) ? 0 : 1), Macro.item(item), {
120
45
  preparation: () => retrieveItem(item),
121
46
  cost: () => ActionSource.defaultPriceFunction(item),
122
47
  })),
48
+ // limited quest items
49
+ ...$items `fish-oil smoke bomb, giant eraser`.map((item) => new ActionSource(item, () => (!have(item) ? 0 : 1), Macro.item(item), {
50
+ preparation: () => have(item),
51
+ cost: () => 0,
52
+ })),
123
53
  ];
124
54
  /**
125
55
  * Find an available free run source subject to constraints.
@@ -128,12 +58,7 @@ const freeRunSources = [
128
58
  * @returns Free run source satisfying constraints, or null.
129
59
  */
130
60
  export function tryFindFreeRun(constraints) {
131
- let source = findActionSource(freeRunSources, constraints);
132
- // Always try to use Asdon Martin: Spring-Loaded Front Bumper first,
133
- // but only if another source has been found.
134
- if (source && asdonMartinSource.available()) {
135
- source = asdonMartinSource.merge(source);
136
- }
61
+ const source = findActionSource(freeRunSources, constraints);
137
62
  return source;
138
63
  }
139
64
  /**
package/dist/ascend.js CHANGED
@@ -182,7 +182,8 @@ export function ascend(options) {
182
182
  consumable: $item `astral six-pack`,
183
183
  pet: $item `none`,
184
184
  };
185
- const { path, playerClass, lifestyle, kolGender, moon, consumable, pet, permOptions, } = { ...DEFAULT_OPTIONS, ...options };
185
+ const prunedOptions = Object.fromEntries(Object.entries(options).filter(([, value]) => value));
186
+ const { path, playerClass, lifestyle, kolGender, moon, consumable, pet, permOptions, } = { ...DEFAULT_OPTIONS, ...prunedOptions };
186
187
  if (playerClass.path !== (path.avatar ? path : Path.none)) {
187
188
  throw new AscendError(playerClass);
188
189
  }
package/dist/combat.js CHANGED
@@ -158,7 +158,7 @@ export class Macro {
158
158
  */
159
159
  step(...nextSteps) {
160
160
  const nextStepsStrings = [].concat(...nextSteps.map((x) => (x instanceof Macro ? x.components : [x])));
161
- this.components.push(...nextStepsStrings.filter((s) => s.length > 0));
161
+ this.components.push(...nextStepsStrings.filter(Boolean));
162
162
  return this;
163
163
  }
164
164
  /**
@@ -132,6 +132,28 @@ export class MenuItem {
132
132
  { maximum: get("deepDishOfLegendEaten") ? 0 : 1 },
133
133
  ],
134
134
  [$item `Pizza of Legend`, { maximum: get("pizzaOfLegendEaten") ? 0 : 1 }],
135
+ [
136
+ $item `jar of fermented pickle juice`,
137
+ { maximum: get("_pickleJuiceDrunk") ? 0 : 1 },
138
+ ],
139
+ [
140
+ $item `extra-greasy slider`,
141
+ { maximum: get("_extraGreasySliderEaten") ? 0 : 1 },
142
+ ],
143
+ [$item `voodoo snuff`, { maximum: get("_voodooSnuffUsed") ? 0 : 1 }],
144
+ [
145
+ $item `Ol' Scratch's salad fork`,
146
+ { maximum: get("_saladForkUsed") ? 0 : 1 },
147
+ ],
148
+ [$item `Frosty's frosty mug`, { maximum: get("_frostyMugUsed") ? 0 : 1 }],
149
+ [
150
+ $item `tin cup of mulligan stew`,
151
+ { maximum: get("_mulliganStewEaten") ? 0 : 1 },
152
+ ],
153
+ [
154
+ $item `Hodgman's blanket`,
155
+ { maximum: get("_hodgmansBlanketDrunk") ? 0 : 1 },
156
+ ],
135
157
  ]);
136
158
  }
137
159
  /**
package/dist/lib.d.ts CHANGED
@@ -402,9 +402,51 @@ export declare function realmAvailable(identifier: RealmType): boolean;
402
402
  * @param realm the realm type to consider
403
403
  * @returns The currency for the given zone
404
404
  */
405
- export declare function realmCurrency(realm: RealmType): Item | undefined;
405
+ export declare function realmCurrency(realm: RealmType): Item | null;
406
406
  /**
407
407
  * Compute which Lucky Gold Ring currencies are currently available
408
408
  * @returns a list of currently available currencies
409
409
  */
410
410
  export declare function lgrCurrencies(): Item[];
411
+ declare const ACCOUNT_COMBAT_FLAGS: readonly ["aabosses", "wowbar", "bothcombatinterf", "compactmanuel", "eternalmrj", "disablelovebugs"];
412
+ /**
413
+ * Different flags you can set on your account for how to handle combat:
414
+ * aabosses refers to the flag that lets autoattack trigger against special monsters
415
+ * wowbar refers to the flag to use the Combat Action Bar
416
+ * bothcombatinterf refers to the flag to use both the CAB
417
+ * compactmanuel refers to the flag to display monster manuel data horizontally
418
+ * eternalmrg refers to the flag to enable endless factoid delight
419
+ * disablelovebugs disables love bugs
420
+ */
421
+ export declare type AccountCombatFlag = typeof ACCOUNT_COMBAT_FLAGS[number];
422
+ /**
423
+ * Get the current value of all of your account's combat setting flags
424
+ * @param flags An array of the flags you want to get, defaults to all of them
425
+ * @returns An array of objects that contain the flags and their values as booleans
426
+ */
427
+ export declare function getCombatFlags(flags?: AccountCombatFlag[]): {
428
+ flag: AccountCombatFlag;
429
+ value: boolean;
430
+ }[];
431
+ /**
432
+ * Sets the given combat setting flags on your account
433
+ *
434
+ * @param flags A spread array of objects that contain a flag and its desired value; these look like the return value of `getCombatFlags`
435
+ * @returns the result of the associated `visitUrl` call
436
+ */
437
+ export declare function setCombatFlags(...flags: {
438
+ flag: AccountCombatFlag;
439
+ value: boolean;
440
+ }[]): string;
441
+ /**
442
+ * Perform a given action with certain combat setting flags set, returning them to their initial values if possible
443
+ *
444
+ * @param action The action you want to do with the given combat setting flags
445
+ * @param flags A spread array of objects that contain a combat setting flag and its desired value; these look like the return value of `getCombatFlags`
446
+ * @returns The result of the action
447
+ */
448
+ export declare function withCombatFlags<T>(action: () => T, ...flags: {
449
+ flag: AccountCombatFlag;
450
+ value: boolean;
451
+ }[]): T;
452
+ export {};
package/dist/lib.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /** @module GeneralLibrary */
2
- import { appearanceRates, autosellPrice, availableAmount, booleanModifier, choiceFollowsFight, cliExecute, currentRound, Effect, elementalResistance, equip, equippedItem, Familiar, fullnessLimit, getCampground, getCounters, getPlayerId, getPlayerName, getRelated, handlingChoice, haveEffect, haveFamiliar, haveServant, haveSkill, holiday, inebrietyLimit, inMultiFight, Item, Location, mallPrice, Monster, myClass, myEffects, myFamiliar, myFullness, myInebriety, myPath, myPrimestat, mySpleenUse, myThrall, myTurncount, numericModifier, Path, Servant, Skill, Slot, spleenLimit, Thrall, todayToString, toItem, toSkill, totalTurnsPlayed, visitUrl, } from "kolmafia";
2
+ import { appearanceRates, autosellPrice, availableAmount, booleanModifier, choiceFollowsFight, cliExecute, currentRound, Effect, elementalResistance, equip, equippedItem, Familiar, fullnessLimit, getCampground, getCounters, getPlayerId, getPlayerName, getRelated, handlingChoice, haveEffect, haveFamiliar, haveServant, haveSkill, holiday, inebrietyLimit, inMultiFight, Item, Location, mallPrice, Monster, myClass, myEffects, myFamiliar, myFullness, myInebriety, myPath, myPrimestat, mySpleenUse, myThrall, myTurncount, numericModifier, Path, Servant, Skill, Slot, spleenLimit, Thrall, todayToString, toItem, toSkill, totalTurnsPlayed, visitUrl, xpath, } from "kolmafia";
3
3
  import logger from "./logger";
4
4
  import { get } from "./property";
5
5
  import { $class, $effect, $element, $familiar, $item, $items, $monsters, $skill, $stat, } from "./template-string";
6
- import { makeByXFunction, chunk, flat } from "./utils";
6
+ import { makeByXFunction, chunk, flat, notNull } from "./utils";
7
7
  /**
8
8
  * Determines the current maximum Accordion Thief songs the player can have in their head
9
9
  *
@@ -834,6 +834,8 @@ export function realmCurrency(realm) {
834
834
  return $item `Volcoino`;
835
835
  case "fantasy":
836
836
  return $item `Rubee™`;
837
+ default:
838
+ return null;
837
839
  }
838
840
  }
839
841
  /**
@@ -845,5 +847,57 @@ export function lgrCurrencies() {
845
847
  .filter((realm) => realmAvailable(realm) &&
846
848
  !(realm === "hot" && get("_luckyGoldRingVolcoino")))
847
849
  .map(realmCurrency)
848
- .filter((i) => !!i);
850
+ .filter(notNull);
851
+ }
852
+ const ACCOUNT_COMBAT_FLAGS = [
853
+ "aabosses",
854
+ "wowbar",
855
+ "bothcombatinterf",
856
+ "compactmanuel",
857
+ "eternalmrj",
858
+ "disablelovebugs",
859
+ ];
860
+ /**
861
+ * Get the current value of all of your account's combat setting flags
862
+ * @param flags An array of the flags you want to get, defaults to all of them
863
+ * @returns An array of objects that contain the flags and their values as booleans
864
+ */
865
+ export function getCombatFlags(flags = [...ACCOUNT_COMBAT_FLAGS]) {
866
+ const accountPage = visitUrl("account.php?tab=combat");
867
+ return flags.map((flag) => ({
868
+ flag,
869
+ value: xpath(accountPage, `//*[@id="opt_flag_${flag}"]/label/input[@type='checkbox']@checked`)[0] === "checked",
870
+ }));
871
+ }
872
+ /**
873
+ * Sets the given combat setting flags on your account
874
+ *
875
+ * @param flags A spread array of objects that contain a flag and its desired value; these look like the return value of `getCombatFlags`
876
+ * @returns the result of the associated `visitUrl` call
877
+ */
878
+ export function setCombatFlags(...flags) {
879
+ return visitUrl(`account.php?${([
880
+ ...flat(flags.map(({ flag, value }) => [
881
+ `actions[]=flag_${flag}`,
882
+ `flag_${flag}=${Number(value)}`,
883
+ ])),
884
+ "action=Update",
885
+ ].join("&"),
886
+ true)}`);
887
+ }
888
+ /**
889
+ * Perform a given action with certain combat setting flags set, returning them to their initial values if possible
890
+ *
891
+ * @param action The action you want to do with the given combat setting flags
892
+ * @param flags A spread array of objects that contain a combat setting flag and its desired value; these look like the return value of `getCombatFlags`
893
+ * @returns The result of the action
894
+ */
895
+ export function withCombatFlags(action, ...flags) {
896
+ const initialValues = getCombatFlags(flags.map(({ flag }) => flag));
897
+ try {
898
+ return action();
899
+ }
900
+ finally {
901
+ setCombatFlags(...initialValues);
902
+ }
849
903
  }