libram 0.6.10 → 0.6.13

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.
@@ -58,6 +58,7 @@ export declare type ActionConstraints = {
58
58
  * A combat-based action resource in the game (e.g. a free run or free kill).
59
59
  */
60
60
  export declare class ActionSource {
61
+ static defaultPriceFunction: (item: Item) => number;
61
62
  source: Item | Skill | Familiar | Array<Item | Skill | Familiar>;
62
63
  potential: () => number;
63
64
  macro: Macro;
@@ -1,4 +1,4 @@
1
- import { useFamiliar } from "kolmafia";
1
+ import { mallPrice, useFamiliar } from "kolmafia";
2
2
  import { Macro } from "../combat";
3
3
  import { Requirement } from "../maximize";
4
4
  import { sum } from "../utils";
@@ -30,6 +30,7 @@ function mergeConstraints(...allConstraints) {
30
30
  * A combat-based action resource in the game (e.g. a free run or free kill).
31
31
  */
32
32
  export class ActionSource {
33
+ static defaultPriceFunction = (item) => mallPrice(item) > 0 ? mallPrice(item) : Infinity;
33
34
  source;
34
35
  potential; // Infinity: unlimited
35
36
  macro;
@@ -140,10 +141,10 @@ function filterAction(action, constraints) {
140
141
  * @returns Available action source satisfying constraints, or null.
141
142
  */
142
143
  export function findActionSource(actions, constraints = {}) {
143
- return (actions
144
- .filter((actions) => filterAction(actions, constraints))
145
- .sort((a, b) => a.cost() - b.cost())
146
- .find((action) => action) ?? null);
144
+ const validActions = actions.filter((actions) => filterAction(actions, constraints));
145
+ return validActions.length
146
+ ? validActions.reduce((a, b) => (a.cost() > b.cost() ? a : b))
147
+ : null;
147
148
  }
148
149
  /**
149
150
  * Count available action sources subject to constraints. Note that, if
@@ -1,4 +1,4 @@
1
- import { mallPrice, myLightning, restoreMp, retrieveItem, use } from "kolmafia";
1
+ import { myLightning, restoreMp, retrieveItem, use } from "kolmafia";
2
2
  import { Macro } from "../combat";
3
3
  import { have } from "../lib";
4
4
  import { Requirement } from "../maximize";
@@ -37,17 +37,17 @@ const freeKillSources = [
37
37
  // Expensive limited sources
38
38
  new ActionSource($item `powdered madness`, () => 5 - get("_powderedMadnessUses"), Macro.item($item `powdered madness`), {
39
39
  preparation: () => retrieveItem($item `powdered madness`),
40
- cost: () => mallPrice($item `powdered madness`),
40
+ cost: () => ActionSource.defaultPriceFunction($item `powdered madness`),
41
41
  }),
42
42
  new ActionSource($familiar `Puck Man`, () => (have($familiar `Puck Man`) ? 20 - get("_powerPillUses") : 0), Macro.item($item `power pill`), {
43
43
  familiar: () => $familiar `Puck Man`,
44
44
  preparation: () => retrieveItem($item `power pill`),
45
- cost: () => mallPrice($item `power pill`),
45
+ cost: () => ActionSource.defaultPriceFunction($item `power pill`),
46
46
  }),
47
47
  new ActionSource($familiar `Ms. Puck Man`, () => (have($familiar `Ms. Puck Man`) ? 20 - get("_powerPillUses") : 0), Macro.item($item `power pill`), {
48
48
  familiar: () => $familiar `Ms. Puck Man`,
49
49
  preparation: () => retrieveItem($item `power pill`),
50
- cost: () => mallPrice($item `power pill`),
50
+ cost: () => ActionSource.defaultPriceFunction($item `power pill`),
51
51
  }),
52
52
  // Expensive unlimited sources
53
53
  new ActionSource($skill `Shocking Lick`, () => Infinity, Macro.skill($skill `Shocking Lick`), {
@@ -58,11 +58,11 @@ const freeKillSources = [
58
58
  }
59
59
  return get("shockingLickCharges") > 0;
60
60
  },
61
- cost: () => mallPrice($item `battery (AAA)`) * 4,
61
+ cost: () => ActionSource.defaultPriceFunction($item `battery (AAA)`) * 4,
62
62
  }),
63
63
  ...$items `Daily Affirmation: Think Win-Lose, superduperheated metal`.map((item) => new ActionSource(item, () => Infinity, Macro.item(item), {
64
64
  preparation: () => retrieveItem(item),
65
- cost: () => mallPrice(item),
65
+ cost: () => ActionSource.defaultPriceFunction(item),
66
66
  })),
67
67
  ];
68
68
  /**
@@ -1,4 +1,4 @@
1
- import { cliExecute, mallPrice, myTurncount, restoreMp, retrieveItem, visitUrl, } from "kolmafia";
1
+ import { cliExecute, myTurncount, restoreMp, retrieveItem, visitUrl, } from "kolmafia";
2
2
  import { Macro } from "../combat";
3
3
  import { ensureEffect, getFoldGroup, getSongCount, getSongLimit, have, } from "../lib";
4
4
  import { Requirement } from "../maximize";
@@ -108,16 +108,16 @@ const freeRunSources = [
108
108
  }),
109
109
  new ActionSource($item `peppermint parasol`, () => Math.max(0, 3 - get("_navelRunaways")), Macro.item($item `peppermint parasol`), {
110
110
  preparation: () => retrieveItem($item `peppermint parasol`),
111
- cost: () => Math.min(mallPrice($item `peppermint sprout`) * 5, mallPrice($item `peppermint parasol`)) / 10, // Breaks after 10 successful runaways.
111
+ cost: () => Math.min(ActionSource.defaultPriceFunction($item `peppermint sprout`) * 5, ActionSource.defaultPriceFunction($item `peppermint parasol`)) / 10, // Breaks after 10 successful runaways.
112
112
  }),
113
113
  new ActionSource($item `human musk`, () => Math.max(0, 3 - get("_humanMuskUses")), Macro.item($item `human musk`), {
114
114
  preparation: () => retrieveItem($item `human musk`),
115
- cost: () => mallPrice($item `human musk`),
115
+ cost: () => ActionSource.defaultPriceFunction($item `human musk`),
116
116
  }),
117
117
  // Expensive unlimited sources
118
118
  ...$items `Louder Than Bomb, divine champagne popper, tennis ball`.map((item) => new ActionSource(item, () => Infinity, Macro.item(item), {
119
119
  preparation: () => retrieveItem(item),
120
- cost: () => mallPrice(item),
120
+ cost: () => ActionSource.defaultPriceFunction(item),
121
121
  })),
122
122
  ];
123
123
  /**
package/dist/ascend.d.ts CHANGED
@@ -7,6 +7,10 @@ export declare enum Lifestyle {
7
7
  normal = 2,
8
8
  hardcore = 3
9
9
  }
10
+ export declare class AscendError extends Error {
11
+ cause?: Skill | Item | Class | Path;
12
+ constructor(cause?: Skill | Item | Class | Path);
13
+ }
10
14
  declare type MoonSign = number | "mongoose" | "wallaby" | "vole" | "platypus" | "opossum" | "marmot" | "wombat" | "blender" | "packrat" | "degrassi" | "degrassi knoll" | "friendly degrassi knoll" | "knoll" | "canada" | "canadia" | "little canadia" | "gnomads" | "gnomish" | "gnomish gnomads camp";
11
15
  /**
12
16
  * Hops the gash, perming no skills
package/dist/ascend.js CHANGED
@@ -1,4 +1,4 @@
1
- import { containsText, eudoraItem, getCampground, getWorkshed, Item, toInt, use, visitUrl, xpath, haveSkill, } from "kolmafia";
1
+ import { Skill, Class, containsText, eudoraItem, getCampground, getWorkshed, Item, toInt, use, visitUrl, xpath, haveSkill, } from "kolmafia";
2
2
  import { ChateauMantegna } from "./resources";
3
3
  import { $item, $items, $stat } from "./template-string";
4
4
  export var Lifestyle;
@@ -8,6 +8,32 @@ export var Lifestyle;
8
8
  Lifestyle[Lifestyle["normal"] = 2] = "normal";
9
9
  Lifestyle[Lifestyle["hardcore"] = 3] = "hardcore";
10
10
  })(Lifestyle || (Lifestyle = {}));
11
+ export class AscendError extends Error {
12
+ cause;
13
+ constructor(cause) {
14
+ if (!cause) {
15
+ super("Failed to ascend--do you have a pending trade offer?");
16
+ }
17
+ else if (cause instanceof Skill) {
18
+ const reason = cause.permable
19
+ ? haveSkill(cause)
20
+ ? "invalid for mysterious reasons"
21
+ : "not a skill you currently know"
22
+ : "unpermable";
23
+ super(`Skill ${cause} is ${reason}!`);
24
+ }
25
+ else if (cause instanceof Item) {
26
+ super(`Invalid astral item: ${cause}!`);
27
+ }
28
+ else if (cause instanceof Class) {
29
+ super(`Invalid class ${cause} for this path!`);
30
+ }
31
+ else {
32
+ super(`Invalid path ${cause}!`);
33
+ }
34
+ this.cause = cause;
35
+ }
36
+ }
11
37
  function toMoonId(moon, playerClass) {
12
38
  if (typeof moon === "number")
13
39
  return moon;
@@ -70,32 +96,32 @@ function toMoonId(moon, playerClass) {
70
96
  */
71
97
  export function ascend(path, playerClass, lifestyle, moon, consumable = $item `astral six-pack`, pet = undefined, permSkills = undefined) {
72
98
  if (!path.classes.includes(playerClass)) {
73
- throw new Error(`Invalid class ${playerClass} for this path`);
99
+ throw new AscendError(playerClass);
74
100
  }
75
101
  if (path.id < 0)
76
- throw new Error(`Invalid path ID ${path.id}`);
102
+ throw new AscendError(path);
77
103
  const moonId = toMoonId(moon, playerClass);
78
104
  if (moonId < 1 || moonId > 9)
79
105
  throw new Error(`Invalid moon ${moon}`);
80
106
  if (consumable &&
81
107
  !$items `astral six-pack, astral hot dog dinner, [10882]carton of astral energy drinks`.includes(consumable)) {
82
- throw new Error(`Invalid consumable ${consumable}!`);
108
+ throw new AscendError(consumable);
83
109
  }
84
110
  if (pet &&
85
111
  !$items `astral bludgeon, astral shield, astral chapeau, astral bracer, astral longbow, astral shorts, astral mace, astral ring, astral statuette, astral pistol, astral mask, astral pet sweater, astral shirt, astral belt`.includes(pet)) {
86
- throw new Error(`Invalid astral item ${pet}!`);
112
+ throw new AscendError(pet);
87
113
  }
88
114
  const illegalSkill = permSkills
89
115
  ? Array.from(permSkills.keys()).find((skill) => !skill.permable || !haveSkill(skill))
90
116
  : undefined;
91
117
  if (illegalSkill) {
92
- throw new Error(`Invalid skill ${illegalSkill}!`);
118
+ throw new AscendError(illegalSkill);
93
119
  }
94
120
  if (!containsText(visitUrl("charpane.php"), "Astral Spirit")) {
95
121
  visitUrl("ascend.php?action=ascend&confirm=on&confirm2=on");
96
122
  }
97
123
  if (!containsText(visitUrl("charpane.php"), "Astral Spirit")) {
98
- throw new Error("Failed to ascend.");
124
+ throw new AscendError();
99
125
  }
100
126
  visitUrl("afterlife.php?action=pearlygates");
101
127
  if (consumable) {
@@ -14,7 +14,9 @@ const statCommunityServicePredictor = (stat) => {
14
14
  return () => 60 -
15
15
  Math.floor((1 / 30) *
16
16
  (myBuffedstat(stat) -
17
- myBasestat(thralls.get(stat) === myThrall() ? $stat `mysticality` : stat)));
17
+ myBasestat(thralls.get(stat) === myThrall() && !have($effect `Expert Oiliness`)
18
+ ? $stat `mysticality`
19
+ : stat)));
18
20
  };
19
21
  const visitCouncil = () => visitUrl("council.php");
20
22
  export default class CommunityService {
@@ -223,7 +225,8 @@ export default class CommunityService {
223
225
  }, new Requirement(["Spell Damage", "Spell Damage Percent"], {}));
224
226
  static Noncombat = new CommunityService(8, "Non-Combat", "Be a Living Statue", () => {
225
227
  const noncombatRate = -1 * getModifier("Combat Rate");
226
- return 60 - 3 * Math.floor(noncombatRate / 5);
228
+ const unsoftcappedRate = noncombatRate > 25 ? 25 + (noncombatRate - 25) * 5 : noncombatRate;
229
+ return 60 - 3 * Math.floor(unsoftcappedRate / 5);
227
230
  }, new Requirement(["-combat"], {}));
228
231
  static BoozeDrop = new CommunityService(9, "Item Drop", "Make Margaritas", () => {
229
232
  const mummingCostume = MummingTrunk.currentCostumes().get(myFamiliar());
package/dist/lib.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /** @module GeneralLibrary */
2
2
  import "core-js/modules/es.object.entries";
3
3
  import "core-js/features/array/flat";
4
- import { Effect, Familiar, Item, Location, Monster, Servant, Skill, Thrall } from "kolmafia";
4
+ import { Effect, Element, Familiar, Item, Location, Monster, Servant, Skill, Thrall } from "kolmafia";
5
5
  /**
6
6
  * Returns the current maximum Accordion Thief songs the player can have in their head
7
7
  *
@@ -269,3 +269,14 @@ export declare function findLeprechaunMultiplier(familiar: Familiar): number;
269
269
  export declare function findFairyMultiplier(familiar: Familiar): number;
270
270
  export declare const holidayWanderers: Map<string, Monster[]>;
271
271
  export declare function getTodaysHolidayWanderers(): Monster[];
272
+ /**
273
+ * Determines & returns whether or not we can safely call visitUrl(), based on whether we're in a fight, multi-fight, choice, etc
274
+ */
275
+ export declare function canVisitUrl(): boolean;
276
+ /**
277
+ * Calculate damage taken from a specific element after factoring in resistance
278
+ * @param baseDamage
279
+ * @param element
280
+ * @returns damage after factoring in resistances
281
+ */
282
+ export declare function damageTakenByElement(baseDamage: number, element: Element): number;
package/dist/lib.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /** @module GeneralLibrary */
2
2
  import "core-js/modules/es.object.entries";
3
3
  import "core-js/features/array/flat";
4
- import { appearanceRates, autosellPrice, availableAmount, booleanModifier, cliExecute, Effect, Familiar, fullnessLimit, getCampground, getCounters, getPlayerId, getPlayerName, getRelated, haveEffect, haveFamiliar, haveServant, haveSkill, holiday, inebrietyLimit, Item, Location, mallPrice, Monster, myEffects, myFamiliar, myFullness, myInebriety, myPath, mySpleenUse, myThrall, myTurncount, numericModifier, Servant, Skill, spleenLimit, Thrall, toItem, toSkill, totalTurnsPlayed, } from "kolmafia";
4
+ import { appearanceRates, autosellPrice, availableAmount, booleanModifier, choiceFollowsFight, cliExecute, currentRound, Effect, elementalResistance, Familiar, fullnessLimit, getCampground, getCounters, getPlayerId, getPlayerName, getRelated, handlingChoice, haveEffect, haveFamiliar, haveServant, haveSkill, holiday, inebrietyLimit, inMultiFight, Item, Location, mallPrice, Monster, myEffects, myFamiliar, myFullness, myInebriety, myPath, mySpleenUse, myThrall, myTurncount, numericModifier, Servant, Skill, spleenLimit, Thrall, toItem, toSkill, totalTurnsPlayed, } from "kolmafia";
5
5
  import { get } from "./property";
6
6
  import { $class, $familiar, $item, $items, $monsters, $skill, } from "./template-string";
7
7
  import { chunk } from "./utils";
@@ -548,3 +548,24 @@ export function getTodaysHolidayWanderers() {
548
548
  .map((holiday) => holidayWanderers.get(holiday) ?? [])
549
549
  .flat();
550
550
  }
551
+ /**
552
+ * Determines & returns whether or not we can safely call visitUrl(), based on whether we're in a fight, multi-fight, choice, etc
553
+ */
554
+ export function canVisitUrl() {
555
+ return !(currentRound() ||
556
+ inMultiFight() ||
557
+ choiceFollowsFight() ||
558
+ handlingChoice());
559
+ }
560
+ /**
561
+ * Calculate damage taken from a specific element after factoring in resistance
562
+ * @param baseDamage
563
+ * @param element
564
+ * @returns damage after factoring in resistances
565
+ */
566
+ export function damageTakenByElement(baseDamage, element) {
567
+ if (baseDamage < 0)
568
+ return 1;
569
+ const res = elementalResistance(element);
570
+ return Math.max(1, Math.ceil(baseDamage - (baseDamage * res) / 100));
571
+ }
package/dist/mood.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import "core-js/modules/es.object.values";
2
2
  import { Effect, Item, Skill } from "kolmafia";
3
3
  export declare abstract class MpSource {
4
- usesRemaining(): number | null;
4
+ usesRemaining(): number;
5
5
  abstract availableMpMin(): number;
6
6
  availableMpMax(): number;
7
7
  abstract execute(): void;
@@ -9,13 +9,14 @@ export declare abstract class MpSource {
9
9
  export declare class OscusSoda extends MpSource {
10
10
  static instance: OscusSoda;
11
11
  available(): boolean;
12
- usesRemaining(): number | null;
12
+ usesRemaining(): number;
13
13
  availableMpMin(): number;
14
14
  availableMpMax(): number;
15
15
  execute(): void;
16
16
  }
17
17
  export declare class MagicalSausages extends MpSource {
18
18
  static instance: MagicalSausages;
19
+ available(): boolean;
19
20
  usesRemaining(): number;
20
21
  availableMpMin(): number;
21
22
  execute(): void;
package/dist/mood.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "core-js/modules/es.object.values";
2
- import { availableAmount, buy, cliExecute, eat, effectModifier, haveEffect, haveSkill, hpCost, itemAmount, mallPrice, mpCost, myHp, myMaxmp, myMp, numericModifier, retrieveItem, toEffect, toSkill, turnsPerCast, use, useSkill, } from "kolmafia";
2
+ import { availableAmount, buy, cliExecute, eat, effectModifier, haveEffect, haveSkill, hpCost, mallPrice, mpCost, myHp, myMaxmp, myMp, numericModifier, retrieveItem, toEffect, toSkill, turnsPerCast, use, useSkill, } from "kolmafia";
3
3
  import { getActiveSongs, have, isSong } from "./lib";
4
4
  import { get } from "./property";
5
5
  import { AsdonMartin } from "./resources";
@@ -7,7 +7,7 @@ import { $item, $skill } from "./template-string";
7
7
  import { clamp, sum } from "./utils";
8
8
  export class MpSource {
9
9
  usesRemaining() {
10
- return null;
10
+ return 0;
11
11
  }
12
12
  availableMpMax() {
13
13
  return this.availableMpMin();
@@ -22,10 +22,10 @@ export class OscusSoda extends MpSource {
22
22
  return get("oscusSodaUsed") ? 0 : 1;
23
23
  }
24
24
  availableMpMin() {
25
- return this.available() ? 200 : 0;
25
+ return this.available() && this.usesRemaining() > 0 ? 200 : 0;
26
26
  }
27
27
  availableMpMax() {
28
- return this.available() ? 300 : 0;
28
+ return this.available() && this.usesRemaining() > 0 ? 300 : 0;
29
29
  }
30
30
  execute() {
31
31
  use($item `Oscus's neverending soda`);
@@ -33,22 +33,26 @@ export class OscusSoda extends MpSource {
33
33
  }
34
34
  export class MagicalSausages extends MpSource {
35
35
  static instance = new MagicalSausages();
36
+ available() {
37
+ return have($item `Kramco Sausage-o-Matic™`);
38
+ }
36
39
  usesRemaining() {
37
- return have($item `Kramco Sausage-o-Matic™`)
38
- ? 23 - get("_sausagesEaten")
40
+ const maxSausages = availableAmount($item `magical sausage`) +
41
+ availableAmount($item `magical sausage casing`);
42
+ return this.available()
43
+ ? clamp(23 - get("_sausagesEaten"), 0, maxSausages)
39
44
  : 0;
40
45
  }
41
46
  availableMpMin() {
42
- const maxSausages = Math.min(this.usesRemaining(), itemAmount($item `magical sausage`) +
43
- itemAmount($item `magical sausage casing`));
44
- return Math.min(myMaxmp(), 999) * maxSausages;
47
+ return this.available()
48
+ ? Math.min(myMaxmp(), 999) * this.usesRemaining()
49
+ : 0;
45
50
  }
46
51
  execute() {
47
52
  const mpSpaceAvailable = myMaxmp() - myMp();
48
53
  if (mpSpaceAvailable < 700)
49
54
  return;
50
- const maxSausages = Math.min(this.usesRemaining(), itemAmount($item `magical sausage`) +
51
- itemAmount($item `magical sausage casing`), Math.floor((myMaxmp() - myMp()) / Math.min(myMaxmp() - myMp(), 999)));
55
+ const maxSausages = Math.min(this.usesRemaining(), Math.floor((myMaxmp() - myMp()) / Math.min(myMaxmp() - myMp(), 999)));
52
56
  retrieveItem(maxSausages, $item `magical sausage`);
53
57
  eat(maxSausages, $item `magical sausage`);
54
58
  }
@@ -102,10 +106,10 @@ class SkillMoodElement extends MoodElement {
102
106
  }
103
107
  else {
104
108
  const cost = mpCost(this.skill);
105
- maxCasts = Math.floor(myMp() / cost);
109
+ maxCasts = Math.floor(Math.min(mood.availableMp(), myMp()) / cost);
106
110
  if (maxCasts === 0) {
107
111
  mood.moreMp(cost);
108
- maxCasts = Math.floor(myMp() / cost);
112
+ maxCasts = Math.floor(Math.min(mood.availableMp(), myMp()) / cost);
109
113
  }
110
114
  }
111
115
  const casts = clamp(remainingCasts, 0, Math.min(100, maxCasts));
@@ -236,9 +240,10 @@ export class Mood {
236
240
  return (sum(this.options.mpSources, (mpSource) => mpSource.availableMpMin()) + Math.max(myMp() - this.options.reserveMp, 0));
237
241
  }
238
242
  moreMp(minimumTarget) {
243
+ if (myMp() >= minimumTarget)
244
+ return;
239
245
  for (const mpSource of this.options.mpSources) {
240
- const usesRemaining = mpSource.usesRemaining();
241
- if (usesRemaining !== null && usesRemaining > 0) {
246
+ if (mpSource.usesRemaining() > 0) {
242
247
  mpSource.execute();
243
248
  if (myMp() >= minimumTarget)
244
249
  break;
@@ -315,6 +320,7 @@ export class Mood {
315
320
  }
316
321
  completeSuccess = element.execute(this, elementTurns) && completeSuccess;
317
322
  }
323
+ this.moreMp(this.options.reserveMp);
318
324
  return completeSuccess;
319
325
  }
320
326
  }
@@ -93,6 +93,12 @@ export declare class PropertiesManager {
93
93
  setChoices(choicesToSet: {
94
94
  [choice: number]: number | string;
95
95
  }): void;
96
+ /**
97
+ * Sets a single choice adventure property to the given value, storing the old value.
98
+ * @param choiceToSet The number of the choice adventure to set the property for.
99
+ * @param value The value to assign to that choice adventure.
100
+ */
101
+ setChoice(choiceToSet: number, value: number | string): void;
96
102
  /**
97
103
  * Resets the given properties to their original stored value. Does not delete entries from the manager.
98
104
  * @param properties Collection of properties to reset.
@@ -125,5 +131,36 @@ export declare class PropertiesManager {
125
131
  * @returns Whether we needed to change the property.
126
132
  */
127
133
  setMaximumValue(property: NumericProperty, value: number): boolean;
134
+ /**
135
+ * Creates a new PropertiesManager with identical stored values to this one.
136
+ * @returns A new PropertiesManager, with identical stored values to this one.
137
+ */
138
+ clone(): PropertiesManager;
139
+ /**
140
+ * Clamps a numeric property, modulating it up or down to fit within a specified range
141
+ * @param property The numeric property to clamp
142
+ * @param min The lower bound for what we want the property to be allowed to be.
143
+ * @param max The upper bound for what we want the property to be allowed to be.
144
+ * @returns Whether we ended up changing the property or not.
145
+ */
146
+ clamp(property: NumericProperty, min: number, max: number): boolean;
147
+ /**
148
+ * Determines whether this PropertiesManager has identical stored values to another.
149
+ * @param other The PropertiesManager to compare to this one.
150
+ * @returns Whether their StoredValues are identical.
151
+ */
152
+ equals(other: PropertiesManager): boolean;
153
+ /**
154
+ * Merges a PropertiesManager onto this one, letting the input win in the event that both PropertiesManagers have a value stored.
155
+ * @param other The PropertiesManager to be merged onto this one.
156
+ * @returns A new PropertiesManager with stored values from both its parents.
157
+ */
158
+ merge(other: PropertiesManager): PropertiesManager;
159
+ /**
160
+ * Merges an arbitrary collection of PropertiesManagers, letting the rightmost PropertiesManager win in the event of verlap.
161
+ * @param mergees The PropertiesManagers to merge together.
162
+ * @returns A PropertiesManager that is just an amalgam of all the constituents.
163
+ */
164
+ static merge(...mergees: PropertiesManager[]): PropertiesManager;
128
165
  }
129
166
  export {};
package/dist/property.js CHANGED
@@ -153,6 +153,14 @@ export class PropertiesManager {
153
153
  choiceValue,
154
154
  ])));
155
155
  }
156
+ /**
157
+ * Sets a single choice adventure property to the given value, storing the old value.
158
+ * @param choiceToSet The number of the choice adventure to set the property for.
159
+ * @param value The value to assign to that choice adventure.
160
+ */
161
+ setChoice(choiceToSet, value) {
162
+ this.setChoices({ [choiceToSet]: value });
163
+ }
156
164
  /**
157
165
  * Resets the given properties to their original stored value. Does not delete entries from the manager.
158
166
  * @param properties Collection of properties to reset.
@@ -214,4 +222,64 @@ export class PropertiesManager {
214
222
  }
215
223
  return false;
216
224
  }
225
+ /**
226
+ * Creates a new PropertiesManager with identical stored values to this one.
227
+ * @returns A new PropertiesManager, with identical stored values to this one.
228
+ */
229
+ clone() {
230
+ const newGuy = new PropertiesManager();
231
+ newGuy.properties = this.storedValues;
232
+ return newGuy;
233
+ }
234
+ /**
235
+ * Clamps a numeric property, modulating it up or down to fit within a specified range
236
+ * @param property The numeric property to clamp
237
+ * @param min The lower bound for what we want the property to be allowed to be.
238
+ * @param max The upper bound for what we want the property to be allowed to be.
239
+ * @returns Whether we ended up changing the property or not.
240
+ */
241
+ clamp(property, min, max) {
242
+ if (max < min)
243
+ return false;
244
+ const start = get(property);
245
+ this.setMinimumValue(property, min);
246
+ this.setMaximumValue(property, max);
247
+ return start !== get(property);
248
+ }
249
+ /**
250
+ * Determines whether this PropertiesManager has identical stored values to another.
251
+ * @param other The PropertiesManager to compare to this one.
252
+ * @returns Whether their StoredValues are identical.
253
+ */
254
+ equals(other) {
255
+ const thisProps = Object.entries(this.storedValues);
256
+ const otherProps = new Map(Object.entries(other.storedValues));
257
+ if (thisProps.length !== otherProps.size)
258
+ return false;
259
+ for (const [propertyName, propertyValue] of thisProps) {
260
+ if (otherProps.get(propertyName) === propertyValue)
261
+ return false;
262
+ }
263
+ return true;
264
+ }
265
+ /**
266
+ * Merges a PropertiesManager onto this one, letting the input win in the event that both PropertiesManagers have a value stored.
267
+ * @param other The PropertiesManager to be merged onto this one.
268
+ * @returns A new PropertiesManager with stored values from both its parents.
269
+ */
270
+ merge(other) {
271
+ const newGuy = new PropertiesManager();
272
+ newGuy.properties = { ...this.properties, ...other.properties };
273
+ return newGuy;
274
+ }
275
+ /**
276
+ * Merges an arbitrary collection of PropertiesManagers, letting the rightmost PropertiesManager win in the event of verlap.
277
+ * @param mergees The PropertiesManagers to merge together.
278
+ * @returns A PropertiesManager that is just an amalgam of all the constituents.
279
+ */
280
+ static merge(...mergees) {
281
+ if (mergees.length === 0)
282
+ return new PropertiesManager();
283
+ return mergees.reduce((a, b) => a.merge(b));
284
+ }
217
285
  }