libram 0.5.4 → 0.5.5
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/actions/ActionSource.js +6 -3
- package/dist/actions/FreeRun.js +10 -12
- package/dist/resources/2009/Bandersnatch.d.ts +2 -2
- package/dist/resources/2009/Bandersnatch.js +2 -2
- package/dist/resources/2011/StompingBoots.d.ts +44 -0
- package/dist/resources/2011/StompingBoots.js +63 -0
- package/dist/resources/2017/AsdonMartin.js +49 -10
- package/dist/resources/index.d.ts +2 -1
- package/dist/resources/index.js +2 -1
- package/package.json +1 -1
|
@@ -3,7 +3,9 @@ import { Macro } from "../combat";
|
|
|
3
3
|
import { Requirement } from "../maximize";
|
|
4
4
|
import { sum } from "../utils";
|
|
5
5
|
function mergeConstraints(...allConstraints) {
|
|
6
|
-
const familiars = allConstraints
|
|
6
|
+
const familiars = allConstraints
|
|
7
|
+
.map((constraints) => constraints.familiar)
|
|
8
|
+
.filter((familiar) => familiar);
|
|
7
9
|
if (familiars.length > 1) {
|
|
8
10
|
// Inconsistent requirements.
|
|
9
11
|
return null;
|
|
@@ -20,7 +22,7 @@ function mergeConstraints(...allConstraints) {
|
|
|
20
22
|
}
|
|
21
23
|
return success;
|
|
22
24
|
},
|
|
23
|
-
familiar: familiars
|
|
25
|
+
familiar: familiars.find((familiar) => familiar),
|
|
24
26
|
cost: () => sum(allConstraints, (constraints) => constraints.cost?.() ?? 0),
|
|
25
27
|
};
|
|
26
28
|
}
|
|
@@ -138,7 +140,8 @@ function filterAction(action, constraints) {
|
|
|
138
140
|
export function findActionSource(actions, constraints = {}) {
|
|
139
141
|
return (actions
|
|
140
142
|
.filter((actions) => filterAction(actions, constraints))
|
|
141
|
-
.sort((a, b) => a.cost() - b.cost())
|
|
143
|
+
.sort((a, b) => a.cost() - b.cost())
|
|
144
|
+
.find((action) => action) ?? null);
|
|
142
145
|
}
|
|
143
146
|
/**
|
|
144
147
|
* Count available action sources subject to constraints. Note that, if
|
package/dist/actions/FreeRun.js
CHANGED
|
@@ -3,14 +3,16 @@ import { Macro } from "../combat";
|
|
|
3
3
|
import { ensureEffect, getFoldGroup, getSongCount, getSongLimit, have, } from "../lib";
|
|
4
4
|
import { Requirement } from "../maximize";
|
|
5
5
|
import { get } from "../property";
|
|
6
|
-
import { $effect, $
|
|
6
|
+
import { $effect, $item, $items, $skill } from "../template-string";
|
|
7
7
|
import { ActionSource, findActionSource, } from "./ActionSource";
|
|
8
8
|
import * as Bandersnatch from "../resources/2009/Bandersnatch";
|
|
9
|
+
import * as StompingBoots from "../resources/2011/StompingBoots";
|
|
9
10
|
import * as AsdonMartin from "../resources/2017/AsdonMartin";
|
|
10
11
|
// Value of _lastCombatStarted the last time we updated scrapbook charges.
|
|
11
12
|
let scrapbookChargesLastUpdated = get("_lastCombatStarted");
|
|
12
13
|
// Free unlimited source every 30 turns.
|
|
13
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
|
|
14
16
|
const asdonMartinSource = new ActionSource($skill `Asdon Martin: Spring-Loaded Front Bumper`, () => {
|
|
15
17
|
if (!AsdonMartin.installed())
|
|
16
18
|
return 0;
|
|
@@ -21,29 +23,25 @@ const asdonMartinSource = new ActionSource($skill `Asdon Martin: Spring-Loaded F
|
|
|
21
23
|
if (bumperIndex === -1)
|
|
22
24
|
return 1;
|
|
23
25
|
return myTurncount() - parseInt(banishes[bumperIndex + 1]) > 30 ? 1 : 0;
|
|
24
|
-
}, Macro.
|
|
26
|
+
}, Macro.trySkill($skill `Asdon Martin: Spring-Loaded Front Bumper`), {
|
|
25
27
|
preparation: () => AsdonMartin.fillTo(50),
|
|
26
28
|
});
|
|
27
29
|
const freeRunSources = [
|
|
28
30
|
// Free limited sources
|
|
29
|
-
new ActionSource(
|
|
30
|
-
(
|
|
31
|
-
Bandersnatch.getRemainingRunaways()
|
|
32
|
-
? 0
|
|
31
|
+
new ActionSource(Bandersnatch.familiar, () => (have($effect `Ode to Booze`) || getSongCount() < getSongLimit()) &&
|
|
32
|
+
Bandersnatch.couldRunaway()
|
|
33
|
+
? Bandersnatch.getRemainingRunaways()
|
|
33
34
|
: 0, Macro.step("runaway"), {
|
|
34
35
|
equipmentRequirements: () => new Requirement(["Familiar Weight"], {}),
|
|
35
36
|
preparation: () => {
|
|
36
37
|
ensureEffect($effect `Ode to Booze`);
|
|
37
38
|
return have($effect `Ode to Booze`);
|
|
38
39
|
},
|
|
39
|
-
familiar: () =>
|
|
40
|
+
familiar: () => Bandersnatch.familiar,
|
|
40
41
|
}),
|
|
41
|
-
new ActionSource(
|
|
42
|
-
Bandersnatch.getRemainingRunaways() > 0
|
|
43
|
-
? 0
|
|
44
|
-
: 0, Macro.step("runaway"), {
|
|
42
|
+
new ActionSource(StompingBoots.familiar, () => StompingBoots.couldRunaway() ? StompingBoots.getRemainingRunaways() : 0, Macro.step("runaway"), {
|
|
45
43
|
equipmentRequirements: () => new Requirement(["Familiar Weight"], {}),
|
|
46
|
-
familiar: () =>
|
|
44
|
+
familiar: () => StompingBoots.familiar,
|
|
47
45
|
}),
|
|
48
46
|
new ActionSource($skill `Snokebomb`, () => (have($skill `Snokebomb`) ? 3 - get("_snokebombUsed") : 0), Macro.skill($skill `Snokebomb`), {
|
|
49
47
|
preparation: () => restoreMp(50),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const familiar: Familiar;
|
|
2
2
|
/**
|
|
3
3
|
* Returns true if the player has the Frumious Bandersnatch in their
|
|
4
|
-
*
|
|
4
|
+
* terrarium
|
|
5
5
|
*/
|
|
6
6
|
export declare function have(): boolean;
|
|
7
7
|
/**
|
|
@@ -38,7 +38,7 @@ export declare function canRunaway(): boolean;
|
|
|
38
38
|
/**
|
|
39
39
|
* Prepare a Bandersnatch runaway.
|
|
40
40
|
*
|
|
41
|
-
* This will cast Ode to Booze and
|
|
41
|
+
* This will cast Ode to Booze and take your Bandersnatch with you.
|
|
42
42
|
* If any of those steps fail, it will return false.
|
|
43
43
|
*
|
|
44
44
|
* @param songsToRemove Ordered list of songs that could be shrugged to make room for Ode to Booze
|
|
@@ -5,7 +5,7 @@ import { have as _have, canRememberSong, getActiveSongs, isCurrentFamiliar, unef
|
|
|
5
5
|
export const familiar = $familiar `Frumious Bandersnatch`;
|
|
6
6
|
/**
|
|
7
7
|
* Returns true if the player has the Frumious Bandersnatch in their
|
|
8
|
-
*
|
|
8
|
+
* terrarium
|
|
9
9
|
*/
|
|
10
10
|
export function have() {
|
|
11
11
|
return _have(familiar);
|
|
@@ -57,7 +57,7 @@ export function canRunaway() {
|
|
|
57
57
|
/**
|
|
58
58
|
* Prepare a Bandersnatch runaway.
|
|
59
59
|
*
|
|
60
|
-
* This will cast Ode to Booze and
|
|
60
|
+
* This will cast Ode to Booze and take your Bandersnatch with you.
|
|
61
61
|
* If any of those steps fail, it will return false.
|
|
62
62
|
*
|
|
63
63
|
* @param songsToRemove Ordered list of songs that could be shrugged to make room for Ode to Booze
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const familiar: Familiar;
|
|
2
|
+
/**
|
|
3
|
+
* Returns true if the player has the Pair of Stomping Boots in their
|
|
4
|
+
* terrarium
|
|
5
|
+
*/
|
|
6
|
+
export declare function have(): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Returns the number of free runaways that have already been used
|
|
9
|
+
* @see Bandersnatch with which the Stomping Boots shares a counter
|
|
10
|
+
*/
|
|
11
|
+
export declare function getRunaways(): number;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the total number of free runaways that the player can
|
|
14
|
+
* get from their Stomping Boots
|
|
15
|
+
*
|
|
16
|
+
* @param considerWeightAdjustment Include familiar weight modifiers
|
|
17
|
+
*/
|
|
18
|
+
export declare function getMaxRunaways(considerWeightAdjustment?: boolean): number;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the number of remaining free runaways the player can
|
|
21
|
+
* get from their Stomping Boots
|
|
22
|
+
*
|
|
23
|
+
* @param considerWeightAdjustment
|
|
24
|
+
*/
|
|
25
|
+
export declare function getRemainingRunaways(considerWeightAdjustment?: boolean): number;
|
|
26
|
+
/**
|
|
27
|
+
* Returns true if the player could use their Stomping Boots to
|
|
28
|
+
* get a free run in theory
|
|
29
|
+
*
|
|
30
|
+
* @param considerWeightAdjustment Include familiar weight modifiers
|
|
31
|
+
*/
|
|
32
|
+
export declare function couldRunaway(considerWeightAdjustment?: boolean): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Returns true if the player can use their Stomping Boots to get a
|
|
35
|
+
* free run right now
|
|
36
|
+
*/
|
|
37
|
+
export declare function canRunaway(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Prepare a Stomping Boots runaway.
|
|
40
|
+
*
|
|
41
|
+
* This will take your Stomping Boots with you.
|
|
42
|
+
* If any of those steps fail, it will return false.
|
|
43
|
+
*/
|
|
44
|
+
export declare function prepareRunaway(): boolean;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { familiarWeight, useFamiliar, weightAdjustment } from "kolmafia";
|
|
2
|
+
import { get } from "../../property";
|
|
3
|
+
import { $familiar } from "../../template-string";
|
|
4
|
+
import { have as _have, isCurrentFamiliar } from "../../lib";
|
|
5
|
+
export const familiar = $familiar `Pair of Stomping Boots`;
|
|
6
|
+
/**
|
|
7
|
+
* Returns true if the player has the Pair of Stomping Boots in their
|
|
8
|
+
* terrarium
|
|
9
|
+
*/
|
|
10
|
+
export function have() {
|
|
11
|
+
return _have(familiar);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns the number of free runaways that have already been used
|
|
15
|
+
* @see Bandersnatch with which the Stomping Boots shares a counter
|
|
16
|
+
*/
|
|
17
|
+
export function getRunaways() {
|
|
18
|
+
return get("_banderRunaways");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns the total number of free runaways that the player can
|
|
22
|
+
* get from their Stomping Boots
|
|
23
|
+
*
|
|
24
|
+
* @param considerWeightAdjustment Include familiar weight modifiers
|
|
25
|
+
*/
|
|
26
|
+
export function getMaxRunaways(considerWeightAdjustment = true) {
|
|
27
|
+
const weightBuffs = considerWeightAdjustment ? weightAdjustment() : 0;
|
|
28
|
+
return Math.floor((familiarWeight(familiar) + weightBuffs) / 5);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the number of remaining free runaways the player can
|
|
32
|
+
* get from their Stomping Boots
|
|
33
|
+
*
|
|
34
|
+
* @param considerWeightAdjustment
|
|
35
|
+
*/
|
|
36
|
+
export function getRemainingRunaways(considerWeightAdjustment = true) {
|
|
37
|
+
return Math.max(0, getMaxRunaways(considerWeightAdjustment) - getRunaways());
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Returns true if the player could use their Stomping Boots to
|
|
41
|
+
* get a free run in theory
|
|
42
|
+
*
|
|
43
|
+
* @param considerWeightAdjustment Include familiar weight modifiers
|
|
44
|
+
*/
|
|
45
|
+
export function couldRunaway(considerWeightAdjustment = true) {
|
|
46
|
+
return have() && getRemainingRunaways(considerWeightAdjustment) > 0;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Returns true if the player can use their Stomping Boots to get a
|
|
50
|
+
* free run right now
|
|
51
|
+
*/
|
|
52
|
+
export function canRunaway() {
|
|
53
|
+
return isCurrentFamiliar(familiar) && couldRunaway();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Prepare a Stomping Boots runaway.
|
|
57
|
+
*
|
|
58
|
+
* This will take your Stomping Boots with you.
|
|
59
|
+
* If any of those steps fail, it will return false.
|
|
60
|
+
*/
|
|
61
|
+
export function prepareRunaway() {
|
|
62
|
+
return useFamiliar(familiar);
|
|
63
|
+
}
|
|
@@ -2,6 +2,12 @@ import "core-js/modules/es.object.values";
|
|
|
2
2
|
import { canInteract, cliExecute, getFuel, getWorkshed, haveEffect, historicalAge, historicalPrice, isNpcItem, mallPrice, mallPrices, retrieveItem, toInt, visitUrl, } from "kolmafia";
|
|
3
3
|
import { getAverageAdventures, have as haveItem } from "../../lib";
|
|
4
4
|
import { $effect, $item, $items } from "../../template-string";
|
|
5
|
+
var PriceAge;
|
|
6
|
+
(function (PriceAge) {
|
|
7
|
+
PriceAge[PriceAge["HISTORICAL"] = 0] = "HISTORICAL";
|
|
8
|
+
PriceAge[PriceAge["RECENT"] = 1] = "RECENT";
|
|
9
|
+
PriceAge[PriceAge["TODAY"] = 2] = "TODAY";
|
|
10
|
+
})(PriceAge || (PriceAge = {}));
|
|
5
11
|
/**
|
|
6
12
|
* Returns whether or not we have the Asdon installed in the workshed at present.
|
|
7
13
|
*/
|
|
@@ -18,13 +24,34 @@ const fuelSkiplist = $items `cup of "tea", thermos of "whiskey", Lucky Lindy, Be
|
|
|
18
24
|
function priceTooOld(item) {
|
|
19
25
|
return historicalPrice(item) === 0 || historicalAge(item) >= 7;
|
|
20
26
|
}
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
// Return mall max if historicalPrice returns -1.
|
|
28
|
+
function historicalPriceOrMax(item) {
|
|
29
|
+
const historical = historicalPrice(item);
|
|
30
|
+
return historical < 0 ? 999999999 : historical;
|
|
31
|
+
}
|
|
32
|
+
// Return mall max if mallPrice returns -1.
|
|
33
|
+
function mallPriceOrMax(item) {
|
|
34
|
+
const mall = mallPrice(item);
|
|
35
|
+
return mall < 0 ? 999999999 : mall;
|
|
36
|
+
}
|
|
37
|
+
function price(item, priceAge) {
|
|
38
|
+
switch (priceAge) {
|
|
39
|
+
case PriceAge.HISTORICAL: {
|
|
40
|
+
const historical = historicalPriceOrMax(item);
|
|
41
|
+
return historical === 0 ? mallPriceOrMax(item) : historical;
|
|
42
|
+
}
|
|
43
|
+
case PriceAge.RECENT:
|
|
44
|
+
return priceTooOld(item)
|
|
45
|
+
? mallPriceOrMax(item)
|
|
46
|
+
: historicalPriceOrMax(item);
|
|
47
|
+
case PriceAge.TODAY:
|
|
48
|
+
return mallPriceOrMax(item);
|
|
49
|
+
}
|
|
23
50
|
}
|
|
24
51
|
// Efficiency in meat per fuel.
|
|
25
|
-
function
|
|
52
|
+
function calculateFuelUnitCost(it, targetUnits, priceAge = PriceAge.RECENT) {
|
|
26
53
|
const units = getAverageAdventures(it);
|
|
27
|
-
return
|
|
54
|
+
return price(it, priceAge) / Math.min(targetUnits, units);
|
|
28
55
|
}
|
|
29
56
|
function isFuelItem(it) {
|
|
30
57
|
return (!isNpcItem(it) &&
|
|
@@ -34,21 +61,33 @@ function isFuelItem(it) {
|
|
|
34
61
|
it.discardable &&
|
|
35
62
|
!fuelSkiplist.includes(it));
|
|
36
63
|
}
|
|
37
|
-
const potentialFuel = $items ``.filter(isFuelItem);
|
|
38
64
|
function getBestFuel(targetUnits) {
|
|
39
|
-
|
|
65
|
+
// Three stages.
|
|
66
|
+
// 1. Filter to reasonable items using historical cost (within 5x of historical best).
|
|
67
|
+
const allFuel = $items ``.filter(isFuelItem);
|
|
68
|
+
if (allFuel.filter((item) => historicalPrice(item) === 0).length > 100) {
|
|
69
|
+
mallPrices("food");
|
|
70
|
+
mallPrices("booze");
|
|
71
|
+
}
|
|
72
|
+
const keyHistorical = (item) => calculateFuelUnitCost(item, targetUnits, PriceAge.HISTORICAL);
|
|
73
|
+
allFuel.sort((x, y) => keyHistorical(x) - keyHistorical(y));
|
|
74
|
+
const bestUnitCost = keyHistorical(allFuel[0]);
|
|
75
|
+
const firstBadIndex = allFuel.findIndex((item) => keyHistorical(item) > 5 * bestUnitCost);
|
|
76
|
+
const potentialFuel = firstBadIndex > 0 ? allFuel.slice(0, firstBadIndex) : allFuel;
|
|
77
|
+
// 2. Filter to top 10 candidates using prices at most a week old.
|
|
78
|
+
if (potentialFuel.filter((item) => priceTooOld(item)).length > 100) {
|
|
40
79
|
mallPrices("food");
|
|
41
80
|
mallPrices("booze");
|
|
42
81
|
}
|
|
43
82
|
const key1 = (item) => -getAverageAdventures(item);
|
|
44
|
-
const key2 = (item) =>
|
|
83
|
+
const key2 = (item) => calculateFuelUnitCost(item, targetUnits, PriceAge.RECENT);
|
|
45
84
|
potentialFuel.sort((x, y) => key1(x) - key1(y));
|
|
46
85
|
potentialFuel.sort((x, y) => key2(x) - key2(y));
|
|
47
|
-
//
|
|
86
|
+
// 3. Find result using precise price for those top candidates.
|
|
48
87
|
const candidates = potentialFuel.slice(0, 10);
|
|
49
|
-
const key3 = (item) =>
|
|
88
|
+
const key3 = (item) => calculateFuelUnitCost(item, targetUnits, PriceAge.TODAY);
|
|
50
89
|
candidates.sort((x, y) => key3(x) - key3(y));
|
|
51
|
-
if (
|
|
90
|
+
if (calculateFuelUnitCost(candidates[0], targetUnits, PriceAge.TODAY) > 100) {
|
|
52
91
|
throw new Error("Could not identify any fuel with efficiency better than 100 meat per fuel. " +
|
|
53
92
|
"This means something went wrong.");
|
|
54
93
|
}
|
|
@@ -15,9 +15,10 @@ import * as Snapper from "./2019/Snapper";
|
|
|
15
15
|
import * as SongBoom from "./2018/SongBoom";
|
|
16
16
|
import * as SourceTerminal from "./2016/SourceTerminal";
|
|
17
17
|
import * as SpookyPutty from "./2009/SpookyPutty";
|
|
18
|
+
import * as StompingBoots from "./2011/StompingBoots";
|
|
18
19
|
import * as TunnelOfLove from "./2017/TunnelOfLove";
|
|
19
20
|
import * as WinterGarden from "./2014/WinterGarden";
|
|
20
21
|
import * as Witchess from "./2016/Witchess";
|
|
21
|
-
export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal,
|
|
22
|
+
export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, Snapper, SongBoom, SourceTerminal, SpookyPutty, StompingBoots, TunnelOfLove, WinterGarden, Witchess, };
|
|
22
23
|
export * from "./putty-likes";
|
|
23
24
|
export * from "./LibramSummon";
|
package/dist/resources/index.js
CHANGED
|
@@ -15,9 +15,10 @@ import * as Snapper from "./2019/Snapper";
|
|
|
15
15
|
import * as SongBoom from "./2018/SongBoom";
|
|
16
16
|
import * as SourceTerminal from "./2016/SourceTerminal";
|
|
17
17
|
import * as SpookyPutty from "./2009/SpookyPutty";
|
|
18
|
+
import * as StompingBoots from "./2011/StompingBoots";
|
|
18
19
|
import * as TunnelOfLove from "./2017/TunnelOfLove";
|
|
19
20
|
import * as WinterGarden from "./2014/WinterGarden";
|
|
20
21
|
import * as Witchess from "./2016/Witchess";
|
|
21
|
-
export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, SongBoom, SourceTerminal,
|
|
22
|
+
export { AsdonMartin, Bandersnatch, BeachComb, ChateauMantegna, CrownOfThrones, CrystalBall, DNALab, FloristFriar, Guzzlr, Latte, MayoClinic, ObtuseAngel, RainDoh, Snapper, SongBoom, SourceTerminal, SpookyPutty, StompingBoots, TunnelOfLove, WinterGarden, Witchess, };
|
|
22
23
|
export * from "./putty-likes";
|
|
23
24
|
export * from "./LibramSummon";
|