libram 0.4.5 → 0.4.9

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.
@@ -1,4 +1,5 @@
1
1
  import { floristAvailable, getFloristPlants, myLocation, visitUrl, } from "kolmafia";
2
+ import { mergeModifiers } from "../../modifier";
2
3
  import { get } from "../../property";
3
4
  class Flower {
4
5
  name;
@@ -13,16 +14,25 @@ class Flower {
13
14
  this.modifier = modifier;
14
15
  this.territorial = territorial;
15
16
  }
16
- plantNamesInZone(location = myLocation()) {
17
- return getFloristPlants()[location.toString()];
17
+ static plantNamesInZone(location = myLocation()) {
18
+ return getFloristPlants()[location.toString()] ?? null;
18
19
  }
19
- plantsInZone(location = myLocation()) {
20
- return this.plantNamesInZone(location)
20
+ static plantsInZone(location = myLocation()) {
21
+ return (this.plantNamesInZone(location)
21
22
  ?.map((flowerName) => toFlower(flowerName))
22
- .filter((flower) => flower !== undefined);
23
+ .filter((flower) => flower !== undefined) ?? null);
24
+ }
25
+ static modifiersInZone(location = myLocation()) {
26
+ const plants = this.plantsInZone(location);
27
+ if (!plants)
28
+ return {};
29
+ const modifiers = plants
30
+ .map((plant) => plant.modifier)
31
+ .map((modifier) => (typeof modifier === "string" ? {} : modifier));
32
+ return mergeModifiers(...modifiers);
23
33
  }
24
34
  isPlantedHere(location = myLocation()) {
25
- const plantedHere = this.plantNamesInZone(location)?.includes(this.name);
35
+ const plantedHere = Flower.plantNamesInZone(location)?.includes(this.name);
26
36
  return plantedHere !== undefined && plantedHere;
27
37
  }
28
38
  available(location = myLocation()) {
@@ -33,7 +43,7 @@ class Flower {
33
43
  dig() {
34
44
  if (!this.isPlantedHere())
35
45
  return false;
36
- const flowers = this.plantNamesInZone();
46
+ const flowers = Flower.plantNamesInZone();
37
47
  if (!flowers || !flowers[2])
38
48
  return false;
39
49
  const plantNumber = getFloristPlants()[myLocation().toString()].indexOf(this.name);
@@ -70,46 +80,98 @@ export function flowersAvailableFor(location = myLocation()) {
70
80
  export function isFull(location = myLocation()) {
71
81
  return flowersIn(location).length === 3;
72
82
  }
73
- export const RabidDogwood = new Flower("Rabid Dogwood", 1, "outdoor", "+30 Monster Level", true);
74
- export const Rutabeggar = new Flower("Rutabeggar", 2, "outdoor", "+25 Item Drop", true);
75
- export const RadishRadish = new Flower("Rad-ish Radish", 3, "outdoor", "+5 Moxie Experience", true);
76
- export const Artichoker = new Flower("Artichoker", 4, "outdoor", "Delevels enemies");
77
- export const SmokeRa = new Flower("Smoke-ra", 5, "outdoor", "Blocks attacks");
78
- export const SkunkCabbage = new Flower("Skunk Cabbage", 6, "outdoor", "Stench damage");
79
- export const DeadlyCinnamon = new Flower("Deadly Cinnamon", 7, "outdoor", "Hot damage");
80
- export const CeleryStalker = new Flower("Celery Stalker", 8, "outdoor", "Spooky damage");
81
- export const LettuceSpray = new Flower("Lettus Spray", 9, "outdoor", "Restores HP");
82
- export const SeltzerWatercress = new Flower("Seltzer Watercress", 10, "outdoor", "Restores MP");
83
- export const WarLily = new Flower("War Lily", 11, "indoor", "+30 Monster Level", true);
84
- export const StealingMagnolia = new Flower("Stealing Magnolia", 12, "indoor", "+25 Item Drop", true);
85
- export const CannedSpinach = new Flower("Canned Spinach", 13, "indoor", "+5 Muscle Experience", true);
86
- export const Impatiens = new Flower("Impatiens", 14, "indoor", "+25 Initiative");
83
+ export const RabidDogwood = new Flower("Rabid Dogwood", 1, "outdoor", {
84
+ "Monster Level": 30,
85
+ }, true);
86
+ export const Rutabeggar = new Flower("Rutabeggar", 2, "outdoor", {
87
+ "Item Drop": 25,
88
+ }, true);
89
+ export const RadishRadish = new Flower("Rad-ish Radish", 3, "outdoor", { "Moxie Experience": 5 }, true);
90
+ export const Artichoker = new Flower("Artichoker", 4, "outdoor", "Delevels Enemy");
91
+ export const SmokeRa = new Flower("Smoke-ra", 5, "outdoor", "Blocks Attacks");
92
+ export const SkunkCabbage = new Flower("Skunk Cabbage", 6, "outdoor", {
93
+ "Stench Damage": 12.5,
94
+ });
95
+ export const DeadlyCinnamon = new Flower("Deadly Cinnamon", 7, "outdoor", {
96
+ "Hot Damage": 12.5,
97
+ });
98
+ export const CeleryStalker = new Flower("Celery Stalker", 8, "outdoor", {
99
+ "Spooky Damage": 12.5,
100
+ });
101
+ export const LettuceSpray = new Flower("Lettus Spray", 9, "outdoor", {
102
+ "HP Regen Min": 10,
103
+ "HP Regen Max": 29,
104
+ });
105
+ export const SeltzerWatercress = new Flower("Seltzer Watercress", 10, "outdoor", { "MP Regen Min": 5, "MP Regen Max": 15 });
106
+ export const WarLily = new Flower("War Lily", 11, "indoor", { "Monster Level": 30 }, true);
107
+ export const StealingMagnolia = new Flower("Stealing Magnolia", 12, "indoor", { "Item Drop": 25 }, true);
108
+ export const CannedSpinach = new Flower("Canned Spinach", 13, "indoor", { "Muscle Experience": 5 }, true);
109
+ export const Impatiens = new Flower("Impatiens", 14, "indoor", {
110
+ Initiative: 25,
111
+ });
87
112
  export const SpiderPlant = new Flower("Spider Plant", 15, "indoor", "Poison");
88
- export const RedFern = new Flower("Red Fern", 16, "indoor", "Delevels enemies");
89
- export const BamBoo = new Flower("Bam BOO!", 17, "indoor", "Spooky damage");
90
- export const ArcticMoss = new Flower("Arctic Moss", 18, "indoor", "Cold damage");
91
- export const AloeGuvnor = new Flower("Aloe Guv'nor", 19, "indoor", "Restores HP");
92
- export const PitcherPlant = new Flower("Pitcher Plant", 20, "indoor", "Restores MP");
93
- export const BlusteryPuffball = new Flower("Blustery Puffball", 21, "underground", "+30 Monster Level", true);
94
- export const HornOfPlenty = new Flower("Horn of Plenty", 22, "underground", "+25 Item Drop", true);
95
- export const WizardsWig = new Flower("Wizard's Wig", 23, "underground", "+5 Mysticality Experience", true);
96
- export const ShuffleTruffle = new Flower("Shuffle Truffle", 24, "underground", "+25 Initiative");
97
- export const DisLichen = new Flower("Dis Lichen", 25, "underground", "Delevels enemies");
98
- export const LooseMorels = new Flower("Loose Morels", 26, "underground", "Sleaze damage");
99
- export const FoulToadstool = new Flower("Foul Toadstool", 27, "underground", "Stench damage");
100
- export const Chillterelle = new Flower("Chillterelle", 28, "underground", "Cold damage");
101
- export const Portlybella = new Flower("Portlybella", 29, "underground", "Retores HP");
102
- export const MaxHeadshroom = new Flower("Max Headshroom", 30, "underground", "Restores MP");
103
- export const Spankton = new Flower("Spankton", 31, "underwater", "Delevels enemies", true);
104
- export const Kelptomaniac = new Flower("Kelptomaniac", 32, "underwater", "+40 Item Drop", true);
105
- export const Crookweed = new Flower("Crookweed", 33, "underwater", "+60 Meat Drop", true);
106
- export const ElectricEelgrass = new Flower("Electric Eelgrass", 34, "underwater", "Blocks attacks");
107
- export const Duckweed = new Flower("Duckweed", 35, "underwater", "Protects once");
108
- export const OrcaOrchid = new Flower("Orca Orchid", 36, "underwater", "Physical damage");
109
- export const Sargassum = new Flower("Sargassum", 37, "underwater", "Stench damage");
110
- export const SubSeaRose = new Flower("Sub-Sea Rose", 38, "underwater", "Cold damage");
111
- export const Snori = new Flower("Snori", 39, "underwater", "Restores HP, Restores MP");
112
- export const UpSeaDaisy = new Flower("Up Sea Daisy", 40, "underwater", "+30 Experience");
113
+ export const RedFern = new Flower("Red Fern", 16, "indoor", "Delevels Enemy");
114
+ export const BamBoo = new Flower("Bam BOO!", 17, "indoor", {
115
+ "Spooky Damage": 12.5,
116
+ });
117
+ export const ArcticMoss = new Flower("Arctic Moss", 18, "indoor", {
118
+ "Cold Damage": 12.5,
119
+ });
120
+ export const AloeGuvnor = new Flower("Aloe Guv'nor", 19, "indoor", {
121
+ "HP Regen Min": 10,
122
+ "HP Regen Max": 30,
123
+ });
124
+ export const PitcherPlant = new Flower("Pitcher Plant", 20, "indoor", {
125
+ "MP Regen Min": 5,
126
+ "MP Regen Max": 15,
127
+ });
128
+ export const BlusteryPuffball = new Flower("Blustery Puffball", 21, "underground", { "Monster Level": 30 }, true);
129
+ export const HornOfPlenty = new Flower("Horn of Plenty", 22, "underground", { "Item Drop": 25 }, true);
130
+ export const WizardsWig = new Flower("Wizard's Wig", 23, "underground", { "Mysticality Experience": 5 }, true);
131
+ export const ShuffleTruffle = new Flower("Shuffle Truffle", 24, "underground", {
132
+ Initiative: 25,
133
+ });
134
+ export const DisLichen = new Flower("Dis Lichen", 25, "underground", "Delevels Enemy");
135
+ export const LooseMorels = new Flower("Loose Morels", 26, "underground", {
136
+ "Sleaze Damage": 12.5,
137
+ });
138
+ export const FoulToadstool = new Flower("Foul Toadstool", 27, "underground", {
139
+ "Stench Damage": 12.5,
140
+ });
141
+ export const Chillterelle = new Flower("Chillterelle", 28, "underground", {
142
+ "Cold Damage": 12.5,
143
+ });
144
+ export const Portlybella = new Flower("Portlybella", 29, "underground", {
145
+ "HP Regen Min": 10,
146
+ "HP Regen Max": 30,
147
+ });
148
+ export const MaxHeadshroom = new Flower("Max Headshroom", 30, "underground", {
149
+ "MP Regen Min": 5,
150
+ "MP Regen Max": 15,
151
+ });
152
+ export const Spankton = new Flower("Spankton", 31, "underwater", "Delevels Enemy", true);
153
+ export const Kelptomaniac = new Flower("Kelptomaniac", 32, "underwater", { "Item Drop": 40 }, true);
154
+ export const Crookweed = new Flower("Crookweed", 33, "underwater", { "Meat Drop": 60 }, true);
155
+ export const ElectricEelgrass = new Flower("Electric Eelgrass", 34, "underwater", "Blocks Attacks");
156
+ export const Duckweed = new Flower("Duckweed", 35, "underwater", "Blocks Attacks");
157
+ export const OrcaOrchid = new Flower("Orca Orchid", 36, "underwater", {
158
+ "Weapon Damage": 12.5,
159
+ });
160
+ export const Sargassum = new Flower("Sargassum", 37, "underwater", {
161
+ "Stench Damage": 12.5,
162
+ });
163
+ export const SubSeaRose = new Flower("Sub-Sea Rose", 38, "underwater", {
164
+ "Cold Damage": 12.5,
165
+ });
166
+ export const Snori = new Flower("Snori", 39, "underwater", {
167
+ "HP Regen Min": 20,
168
+ "HP Regen Max": 30,
169
+ "MP Regen Min": 10,
170
+ "MP Regen Max": 20,
171
+ });
172
+ export const UpSeaDaisy = new Flower("Up Sea Daisy", 40, "underwater", {
173
+ Experience: 30,
174
+ });
113
175
  export const all = Object.freeze([
114
176
  RabidDogwood,
115
177
  Rutabeggar,
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Returns whether or not we have the Asdon installed in the workshed at present.
3
+ */
4
+ export declare function installed(): boolean;
5
+ /**
6
+ * Returns true if we have the Asdon or if it's installed.
7
+ */
8
+ export declare function have(): boolean;
1
9
  /**
2
10
  * Fill your Asdon Martin to the given fuel level in the cheapest way possible
3
11
  * @param targetUnits Fuel level to attempt to reach.
@@ -1,13 +1,29 @@
1
- import { cliExecute, getFuel, haveEffect, historicalPrice, isNpcItem, mallPrice, retrieveItem, toInt, visitUrl, } from "kolmafia";
2
- import { getAverageAdventures } from "../../lib";
3
- import { $effect, $items } from "../../template-string";
1
+ import { cliExecute, getFuel, getWorkshed, haveEffect, historicalAge, historicalPrice, isNpcItem, mallPrice, mallPrices, retrieveItem, toInt, visitUrl, } from "kolmafia";
2
+ import { getAverageAdventures, have as haveItem } from "../../lib";
3
+ import { $effect, $item, $items } from "../../template-string";
4
+ /**
5
+ * Returns whether or not we have the Asdon installed in the workshed at present.
6
+ */
7
+ export function installed() {
8
+ return getWorkshed() === $item `Asdon Martin keyfob`;
9
+ }
10
+ /**
11
+ * Returns true if we have the Asdon or if it's installed.
12
+ */
13
+ export function have() {
14
+ return installed() || haveItem($item `Asdon Martin keyfob`);
15
+ }
4
16
  const fuelSkiplist = $items `cup of "tea", thermos of "whiskey", Lucky Lindy, Bee's Knees, Sockdollager, Ish Kabibble, Hot Socks, Phonus Balonus, Flivver, Sloppy Jalopy, glass of "milk"`;
17
+ function priceTooOld(item) {
18
+ return historicalPrice(item) === 0 || historicalAge(item) >= 7;
19
+ }
5
20
  function price(item) {
6
- return historicalPrice(item) === 0 ? mallPrice(item) : historicalPrice(item);
21
+ return priceTooOld(item) ? mallPrice(item) : historicalPrice(item);
7
22
  }
8
- function calculateFuelEfficiency(it, targetUnits) {
23
+ // Efficiency in meat per fuel.
24
+ function calculateFuelEfficiency(it, targetUnits, usePrecisePrice = false) {
9
25
  const units = getAverageAdventures(it);
10
- return price(it) / Math.min(targetUnits, units);
26
+ return ((usePrecisePrice ? price(it) : mallPrice(it)) / Math.min(targetUnits, units));
11
27
  }
12
28
  function isFuelItem(it) {
13
29
  return (!isNpcItem(it) &&
@@ -19,11 +35,23 @@ function isFuelItem(it) {
19
35
  }
20
36
  const potentialFuel = $items ``.filter(isFuelItem);
21
37
  function getBestFuel(targetUnits) {
38
+ if (potentialFuel.filter(priceTooOld).length > 100) {
39
+ mallPrices("food");
40
+ mallPrices("booze");
41
+ }
22
42
  const key1 = (item) => -getAverageAdventures(item);
23
43
  const key2 = (item) => calculateFuelEfficiency(item, targetUnits);
24
44
  potentialFuel.sort((x, y) => key1(x) - key1(y));
25
45
  potentialFuel.sort((x, y) => key2(x) - key2(y));
26
- return potentialFuel[0];
46
+ // Get precise price for the top candidates.
47
+ const candidates = potentialFuel.slice(0, 10);
48
+ const key3 = (item) => calculateFuelEfficiency(item, targetUnits, true);
49
+ candidates.sort((x, y) => key3(x) - key3(y));
50
+ if (calculateFuelEfficiency(candidates[0], targetUnits, true) > 100) {
51
+ throw new Error("Could not identify any fuel with efficiency better than 100 meat per fuel. " +
52
+ "This means something went wrong.");
53
+ }
54
+ return candidates[0];
27
55
  }
28
56
  function insertFuel(it, quantity = 1) {
29
57
  const result = visitUrl(`campground.php?action=fuelconvertor&pwd&qty=${quantity}&iid=${toInt(it)}&go=Convert%21`);
@@ -35,6 +63,8 @@ function insertFuel(it, quantity = 1) {
35
63
  * @returns Whether we succeeded at filling to the target fuel level.
36
64
  */
37
65
  export function fillTo(targetUnits) {
66
+ if (!installed())
67
+ return false;
38
68
  while (getFuel() < targetUnits) {
39
69
  const remaining = targetUnits - getFuel();
40
70
  const fuel = getBestFuel(remaining);
@@ -69,6 +99,8 @@ export const Driving = {
69
99
  export function drive(style, turns = 1) {
70
100
  if (!Object.values(Driving).includes(style))
71
101
  return false;
102
+ if (!installed())
103
+ return false;
72
104
  if (haveEffect(style) >= turns)
73
105
  return true;
74
106
  const fuelNeeded = 37 * Math.ceil((turns - haveEffect(style)) / 30);
@@ -0,0 +1,3 @@
1
+ export declare function have(): boolean;
2
+ export declare function sniffedMonster(): Monster | null;
3
+ export declare function refillsRemaining(): number;
@@ -0,0 +1,13 @@
1
+ import { getCounter } from "kolmafia";
2
+ import { have as haveItem } from "../../lib";
3
+ import { get } from "../../property";
4
+ import { $item } from "../../template-string";
5
+ export function have() {
6
+ return haveItem($item `latte lovers member's mug`);
7
+ }
8
+ export function sniffedMonster() {
9
+ return getCounter("Latte Monster") !== -1 ? get("_latteMonster") : null;
10
+ }
11
+ export function refillsRemaining() {
12
+ return 3 - get("_latteRefillsUsed");
13
+ }
@@ -89,4 +89,6 @@ export declare function havePlatinumBooze(): boolean;
89
89
  export declare function haveBooze(): boolean;
90
90
  export declare const ingredientToPlatinumCocktail: Map<Item, Item>;
91
91
  export declare const platinumCocktailToIngredient: Map<Item, Item>;
92
- export declare function getCheapestPlatinumCocktail(): Item;
92
+ export declare function getCheapestPlatinumCocktail(freeCraft?: boolean): Item;
93
+ export declare function turnsLeftOnQuest(useShoes?: boolean): number;
94
+ export declare function expectedReward(usePants?: boolean): number;
@@ -174,6 +174,33 @@ export const ingredientToPlatinumCocktail = new Map([
174
174
  [$item `Dish of Clarified Butter`, $item `Buttery Boy`],
175
175
  ]);
176
176
  export const platinumCocktailToIngredient = invertMap(ingredientToPlatinumCocktail);
177
- export function getCheapestPlatinumCocktail() {
178
- return (maxBy(Array.from(ingredientToPlatinumCocktail), (ingredientAndCocktail) => mallPrice(ingredientAndCocktail[0])) ?? [$item `Dish of Clarified Butter`, $item `Buttery Boy`])[1];
177
+ export function getCheapestPlatinumCocktail(freeCraft = true) {
178
+ const defaultCocktail = [$item `Dish of Clarified Butter`, $item `Buttery Boy`];
179
+ if (freeCraft) {
180
+ return (maxBy(Array.from(ingredientToPlatinumCocktail), (ingredientAndCocktail) => Math.min(...ingredientAndCocktail.map((item) => mallPrice(item)))) ?? defaultCocktail)[1];
181
+ }
182
+ else {
183
+ return (maxBy(Array.from(ingredientToPlatinumCocktail), (ingredientAndCocktail) => mallPrice(ingredientAndCocktail[1])) ?? defaultCocktail)[1];
184
+ }
185
+ }
186
+ export function turnsLeftOnQuest(useShoes = false) {
187
+ const progressPerTurn = useShoes
188
+ ? Math.floor((10 - get("_guzzlrDeliveries")) * 1.5)
189
+ : 10 - get("_guzzlrDeliveries");
190
+ return Math.ceil((100 - get("guzzlrDeliveryProgress")) / progressPerTurn);
191
+ }
192
+ export function expectedReward(usePants = false) {
193
+ switch (getTier()) {
194
+ case "platinum":
195
+ // 20-25
196
+ return 22.5 + (usePants ? 5 : 0);
197
+ case "gold":
198
+ // 5-7
199
+ return 6 + (usePants ? 3 : 0);
200
+ case "bronze":
201
+ // 2-4
202
+ return 3 + (usePants ? 3 : 0);
203
+ default:
204
+ return 0;
205
+ }
179
206
  }
@@ -0,0 +1 @@
1
+ export declare function currentPredictions(withFree?: boolean): Map<Location, Monster>;
@@ -0,0 +1,15 @@
1
+ import { myTurncount, toLocation, toMonster } from "kolmafia";
2
+ import { get } from "../../property";
3
+ const parsedProp = () => get("crystalBallPredictions")
4
+ .split("|")
5
+ .map((element) => element.split(":"))
6
+ .map(([turncount, location, monster]) => [parseInt(turncount), toLocation(location), toMonster(monster)]);
7
+ export function currentPredictions(withFree = true) {
8
+ const predictions = parsedProp();
9
+ const freeCondition = (predictedTurns, turns) => predictedTurns === turns;
10
+ const nonFreeCondition = (predictedTurns, turns) => predictedTurns + 1 === turns;
11
+ return new Map(predictions
12
+ .filter(([turncount]) => nonFreeCondition(turncount, myTurncount()) ||
13
+ (withFree && freeCondition(turncount, myTurncount())))
14
+ .map(([, location, monster]) => [location, monster]));
15
+ }
@@ -3,9 +3,11 @@ import * as Bandersnatch from "./2009/Bandersnatch";
3
3
  import * as BeachComb from "./2019/BeachComb";
4
4
  import * as ChateauMantegna from "./2015/ChateauMantegna";
5
5
  import * as CrownOfThrones from "./2010/CrownOfThrones";
6
+ import * as CrystalBall from "./2021/CrystalBall";
6
7
  import * as DNALab from "./2014/DNALab";
7
8
  import * as FloristFriar from "./2013/Florist";
8
9
  import * as Guzzlr from "./2020/Guzzlr";
10
+ import * as Latte from "./2018/LatteLoversMembersMug";
9
11
  import * as MayoClinic from "./2015/MayoClinic";
10
12
  import * as ObtuseAngel from "./2011/ObtuseAngel";
11
13
  import * as RainDoh from "./2012/RainDoh";
@@ -16,6 +18,6 @@ import * as SpookyPutty from "./2009/SpookyPutty";
16
18
  import * as TunnelOfLove from "./2017/TunnelOfLove";
17
19
  import * as WinterGarden from "./2014/WinterGarden";
18
20
  import * as Witchess from "./2016/Witchess";
19
- export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, DNALab, FloristFriar, Guzzlr, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal, Snapper, SpookyPutty, TunnelOfLove, WinterGarden, Witchess, };
21
+ export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal, Snapper, SpookyPutty, TunnelOfLove, WinterGarden, Witchess, };
20
22
  export * from "./putty-likes";
21
23
  export * from "./LibramSummon";
@@ -3,9 +3,11 @@ import * as Bandersnatch from "./2009/Bandersnatch";
3
3
  import * as BeachComb from "./2019/BeachComb";
4
4
  import * as ChateauMantegna from "./2015/ChateauMantegna";
5
5
  import * as CrownOfThrones from "./2010/CrownOfThrones";
6
+ import * as CrystalBall from "./2021/CrystalBall";
6
7
  import * as DNALab from "./2014/DNALab";
7
8
  import * as FloristFriar from "./2013/Florist";
8
9
  import * as Guzzlr from "./2020/Guzzlr";
10
+ import * as Latte from "./2018/LatteLoversMembersMug";
9
11
  import * as MayoClinic from "./2015/MayoClinic";
10
12
  import * as ObtuseAngel from "./2011/ObtuseAngel";
11
13
  import * as RainDoh from "./2012/RainDoh";
@@ -16,6 +18,6 @@ import * as SpookyPutty from "./2009/SpookyPutty";
16
18
  import * as TunnelOfLove from "./2017/TunnelOfLove";
17
19
  import * as WinterGarden from "./2014/WinterGarden";
18
20
  import * as Witchess from "./2016/Witchess";
19
- export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, DNALab, FloristFriar, Guzzlr, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal, Snapper, SpookyPutty, TunnelOfLove, WinterGarden, Witchess, };
21
+ export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal, Snapper, SpookyPutty, TunnelOfLove, WinterGarden, Witchess, };
20
22
  export * from "./putty-likes";
21
23
  export * from "./LibramSummon";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libram",
3
- "version": "0.4.5",
3
+ "version": "0.4.9",
4
4
  "description": "JavaScript helper library for KoLmafia",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/dist/Dungeon.d.ts DELETED
@@ -1,37 +0,0 @@
1
- export default class Dungeon {
2
- name: string;
3
- loot: Item[];
4
- openAction: string;
5
- closeAction: string;
6
- openCost: number;
7
- openImage: string;
8
- closedImage: string;
9
- /**
10
- * Creates dungeon object for managing clan dungeons
11
- * @param name Name of the dungeon in question
12
- * @param loot Distributable loot dropped by bosses in dungeon
13
- * @param openAction String action used in form submission to open dungeon
14
- * @param closeAction String action used in form submission to close dungeon
15
- * @param openCost Meat cost of opening dungeon
16
- * @param openImage Image text to search clan_basement.php for to check if dungeon is open
17
- * @param closedImage Image text to search clan_basement.php for to check if dungeon is closed
18
- */
19
- constructor(name: string, loot: Item[], openAction: string, closeAction: string, openCost: number, openImage: string, closedImage: string);
20
- /**
21
- * Distributes loot from given dungeon
22
- * @param idOrName The player you're trying to distribute to, either as a username or a player ID. Defaults to self.
23
- * @param loot The loot you're looking to distribute, specific to this dungeon
24
- * @param distributeAllOfAGivenItem For items that you can get multiple of in a dungeon. When true, this will give everything of that ilk to your chosen player.
25
- */
26
- distribute(idOrName?: number | string, loot?: Item | Item[], distributeAllOfAGivenItem?: boolean): void;
27
- close(): boolean;
28
- /**
29
- * Opens clan dungeon and, if relevant, pays meat to do so
30
- * @param paymentPolicy "None", "All", or "Difference". Difference pays into the stash the exact amount needed to open the dungeon.
31
- */
32
- open(paymentPolicy?: "None" | "All" | "Difference"): boolean;
33
- static all(): Dungeon[];
34
- }
35
- export declare const Hobopolis: Dungeon;
36
- export declare const SlimeTube: Dungeon;
37
- export declare const Dreadsylvania: Dungeon;
package/dist/Dungeon.js DELETED
@@ -1,87 +0,0 @@
1
- import { getClanName, myId, toItem, visitUrl, xpath } from "kolmafia";
2
- import { Clan } from "./Clan";
3
- import { getPlayerFromIdOrName } from "./lib";
4
- import { $items } from "./template-string";
5
- export default class Dungeon {
6
- /**
7
- * Creates dungeon object for managing clan dungeons
8
- * @param name Name of the dungeon in question
9
- * @param loot Distributable loot dropped by bosses in dungeon
10
- * @param openAction String action used in form submission to open dungeon
11
- * @param closeAction String action used in form submission to close dungeon
12
- * @param openCost Meat cost of opening dungeon
13
- * @param openImage Image text to search clan_basement.php for to check if dungeon is open
14
- * @param closedImage Image text to search clan_basement.php for to check if dungeon is closed
15
- */
16
- constructor(name, loot, openAction, closeAction, openCost, openImage, closedImage) {
17
- this.name = name;
18
- this.loot = loot;
19
- this.openAction = openAction;
20
- this.closeAction = closeAction;
21
- this.openCost = openCost;
22
- this.openImage = openImage;
23
- this.closedImage = closedImage;
24
- }
25
- /**
26
- * Distributes loot from given dungeon
27
- * @param idOrName The player you're trying to distribute to, either as a username or a player ID. Defaults to self.
28
- * @param loot The loot you're looking to distribute, specific to this dungeon
29
- * @param distributeAllOfAGivenItem For items that you can get multiple of in a dungeon. When true, this will give everything of that ilk to your chosen player.
30
- */
31
- distribute(idOrName = myId(), loot = this.loot, distributeAllOfAGivenItem = true) {
32
- const player = getPlayerFromIdOrName(idOrName);
33
- const lootList = Array.isArray(loot) ? loot : [loot];
34
- const badLoot = lootList.find((lootItem) => !this.loot.includes(lootItem));
35
- if (badLoot) {
36
- throw new Error(`${badLoot} is not a valid piece of dungeon loot`);
37
- }
38
- const pageText = visitUrl("clan_basement.php");
39
- if (!pageText.match(player.name)) {
40
- throw new Error(`${player.name} cannot be distributed loot from ${getClanName()}`);
41
- }
42
- const itemNames = xpath(pageText, "//tr/td[2]/b/text()");
43
- const whichLoots = xpath(pageText, '//form[@action="clan_basement.php"]//input[@type="hidden"][@name="whichloot"]/@value');
44
- itemNames.forEach((itemName, index) => {
45
- if (lootList.includes(toItem(itemName))) {
46
- visitUrl(`clan_basement.php?whichloot=${whichLoots[index]}&recipient=${player.id}`);
47
- if (!distributeAllOfAGivenItem)
48
- lootList.slice(lootList.indexOf(toItem(itemName)));
49
- }
50
- });
51
- }
52
- close() {
53
- visitUrl(`clan_basement.php?action=${this.closeAction}&confirm=true`, true);
54
- const pageText = visitUrl("clan_basement.php");
55
- return pageText.includes(this.closedImage);
56
- }
57
- /**
58
- * Opens clan dungeon and, if relevant, pays meat to do so
59
- * @param paymentPolicy "None", "All", or "Difference". Difference pays into the stash the exact amount needed to open the dungeon.
60
- */
61
- open(paymentPolicy = "Difference") {
62
- const pageText = visitUrl("clan_basement.php");
63
- if (pageText.includes(this.openImage))
64
- return true;
65
- const clan = Clan.get();
66
- if (paymentPolicy === "All") {
67
- clan.putMeatInCoffer(this.openCost);
68
- }
69
- else {
70
- const stashMeat = clan.getMeatInCoffer();
71
- const payDifference = this.openCost - stashMeat;
72
- if (payDifference > 0) {
73
- if (paymentPolicy === "None")
74
- return false;
75
- clan.putMeatInCoffer(payDifference);
76
- }
77
- }
78
- visitUrl(`clan_basement.php?action=${this.openAction}`, true);
79
- return visitUrl("clan_basement.php").includes(this.openImage);
80
- }
81
- static all() {
82
- return [Hobopolis, SlimeTube, Dreadsylvania];
83
- }
84
- }
85
- export const Hobopolis = new Dungeon("Hobopolis", $items `Ol' Scratch's ash can, Ol' Scratch's ol' britches, Ol' Scratch's stovepipe hat, Ol' Scratch's infernal pitchfork, Ol' Scratch's manacles, Ol' Scratch's stove door, Frosty's carrot, Frosty's nailbat, Frosty's old silk hat, Frosty's arm, Frosty's iceball, Frosty's snowball sack, Oscus's dumpster waders, Oscus's pelt, Wand of Oscus, Oscus's flypaper pants, Oscus's garbage can lid, Oscus's neverending soda, Zombo's grievous greaves, Zombo's shield, Zombo's skullcap, Zombo's empty eye, Zombo's shoulder blade, Zombo's skull ring, Chester's bag of candy, Chester's cutoffs, Chester's moustache, Chester's Aquarius medallion, Chester's muscle shirt, Chester's sunglasses, Hodgman's bow tie, Hodgman's porkpie hat, Hodgman's lobsterskin pants, Hodgman's almanac, Hodgman's lucky sock, Hodgman's metal detector, Hodgman's varcolac paw, Hodgman's harmonica, Hodgman's garbage sticker, Hodgman's cane, Hodgman's whackin' stick, Hodgman's disgusting technicolor overcoat, Hodgman's imaginary hamster`, "cleansewer", "floodsewer", 1000000, "opengrate.gif", "sewergrate.gif");
86
- export const SlimeTube = new Dungeon("The Slime Tube", $items `slime-soaked brain, slime-soaked hypophysis, slime-soaked sweat gland, squirming Slime larva, caustic slime nodule, caustic slime nodule, hardened slime belt, hardened slime hat, hardened slime pants`, "cleanspot", "sealtube", 250000, "slimehole.gif", "greasespot.gif");
87
- export const Dreadsylvania = new Dungeon("Dreadsylvania", $items `Great Wolf's headband, Great Wolf's right paw, Great Wolf's left paw, Great Wolf's lice, Great Wolf's rocket launcher, Great Wolf's beastly trousers, Drapes-You-Regally, Warms-Your-Tush, Covers-Your-Head, Protects-Your-Junk, Quiets-Your-Steps, Helps-You-Sleep, Mayor Ghost's khakis, Mayor Ghost's cloak, Mayor Ghost's toupee, Mayor Ghost's scissors, Mayor Ghost's sash, Mayor Ghost's gavel, zombie mariachi hat, zombie accordion, zombie mariachi pants, HOA regulation book, HOA zombie eyes, HOA citation pad, Unkillable Skeleton's skullcap, Unkillable Skeleton's shinguards, Unkillable Skeleton's breastplate, Unkillable Skeleton's shield, Unkillable Skeleton's sawsword, Unkillable Skeleton's restless leg, skull capacitor, Thunkula's drinking cap, Drunkula's silky pants, Drunkula's cape, Drunkula's ring of haze, Drunkula's wineglass, Drunkula's bell, bottle of Bloodweiser, bottle of Bloodweiser, bottle of Bloodweiser, bottle of Bloodweiser, electric Kool-Aid, electric Kool-Aid, electric Kool-Aid, electric Kool-Aid, ghost pepper, ghost pepper, ghost pepper, ghost pepper, Gets-You-Drunk, Gets-You-Drunk, Gets-You-Drunk, Gets-You-Drunk, wriggling severed nose, wriggling severed nose, wriggling severed nose, wriggling severed nose, Hunger™ Sauce, Hunger™ Sauce, Hunger™ Sauce, Hunger™ Sauce`, "translatemap", "foldmap", 1000000, "dvmap.gif", "foldmap.gif");
@@ -1,24 +0,0 @@
1
- export declare class RingBuffer<T> {
2
- #private;
3
- constructor(maxLength: number);
4
- /**
5
- * Get length of structure.
6
- */
7
- get length(): number;
8
- /**
9
- * Get maximium length of structure.
10
- */
11
- get maxSize(): number;
12
- entries(): T[];
13
- /**
14
- * Get element at index {index}.
15
- * @param index Index to check.
16
- */
17
- get(index: number): T | undefined;
18
- /**
19
- * Insert a value and evict last value if buffer is full.
20
- * @param value Value to insert.
21
- * @returns Evicted element and index of inserted value.
22
- */
23
- insert(value: T): [T | undefined, number];
24
- }