libram 0.8.28 → 0.8.29
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/Clan.d.ts +128 -0
- package/dist/Clan.js +300 -0
- package/dist/Copier.d.ts +9 -0
- package/dist/Copier.js +15 -0
- package/dist/Dungeon.d.ts +45 -0
- package/dist/Dungeon.js +115 -0
- package/dist/Kmail.d.ts +133 -0
- package/dist/Kmail.js +259 -0
- package/dist/actions/ActionSource.d.ts +131 -0
- package/dist/actions/ActionSource.js +178 -0
- package/dist/actions/Banish.d.ts +16 -0
- package/dist/actions/Banish.js +121 -0
- package/dist/actions/FreeKill.d.ts +16 -0
- package/dist/actions/FreeKill.js +94 -0
- package/dist/actions/FreeRun.d.ts +16 -0
- package/dist/actions/FreeRun.js +81 -0
- package/dist/actions/index.d.ts +4 -0
- package/dist/actions/index.js +4 -0
- package/dist/ascend.d.ts +83 -0
- package/dist/ascend.js +268 -0
- package/dist/challengePaths/2014/HeavyRains.d.ts +22 -0
- package/dist/challengePaths/2014/HeavyRains.js +75 -0
- package/dist/challengePaths/2015/CommunityService.d.ts +125 -0
- package/dist/challengePaths/2015/CommunityService.js +334 -0
- package/dist/challengePaths/2016/NuclearAutumn.d.ts +13 -0
- package/dist/challengePaths/2016/NuclearAutumn.js +21 -0
- package/dist/challengePaths/index.d.ts +4 -0
- package/dist/challengePaths/index.js +4 -0
- package/dist/combat.d.ts +414 -0
- package/dist/combat.js +711 -0
- package/dist/console.d.ts +12 -0
- package/dist/console.js +14 -0
- package/dist/counter.d.ts +22 -0
- package/dist/counter.js +37 -0
- package/dist/diet/index.d.ts +80 -0
- package/dist/diet/index.js +680 -0
- package/dist/diet/knapsack.d.ts +8 -0
- package/dist/diet/knapsack.js +128 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +26 -0
- package/dist/lib.d.ts +507 -0
- package/dist/lib.js +970 -0
- package/dist/logger.d.ts +35 -0
- package/dist/logger.js +62 -0
- package/dist/maximize.d.ts +122 -0
- package/dist/maximize.js +531 -0
- package/dist/modifier.d.ts +41 -0
- package/dist/modifier.js +160 -0
- package/dist/modifierTypes.d.ts +16 -0
- package/dist/modifierTypes.js +9 -0
- package/dist/mood.d.ts +105 -0
- package/dist/mood.js +349 -0
- package/dist/moonSign.d.ts +13 -0
- package/dist/moonSign.js +25 -0
- package/dist/overlappingNames.d.ts +3 -0
- package/dist/overlappingNames.js +42 -0
- package/dist/property.d.ts +222 -0
- package/dist/property.js +385 -0
- package/dist/propertyTypes.d.ts +19 -0
- package/dist/propertyTypes.js +10 -0
- package/dist/propertyTyping.d.ts +65 -0
- package/dist/propertyTyping.js +91 -0
- package/dist/resources/2007/CandyHearts.d.ts +9 -0
- package/dist/resources/2007/CandyHearts.js +24 -0
- package/dist/resources/2008/DivineFavors.d.ts +9 -0
- package/dist/resources/2008/DivineFavors.js +27 -0
- package/dist/resources/2008/Stickers.d.ts +49 -0
- package/dist/resources/2008/Stickers.js +84 -0
- package/dist/resources/2009/Bandersnatch.d.ts +56 -0
- package/dist/resources/2009/Bandersnatch.js +93 -0
- package/dist/resources/2009/LoveSongs.d.ts +9 -0
- package/dist/resources/2009/LoveSongs.js +24 -0
- package/dist/resources/2009/SpookyPutty.d.ts +31 -0
- package/dist/resources/2009/SpookyPutty.js +49 -0
- package/dist/resources/2010/Brickos.d.ts +9 -0
- package/dist/resources/2010/Brickos.js +21 -0
- package/dist/resources/2010/CrownOfThrones.d.ts +68 -0
- package/dist/resources/2010/CrownOfThrones.js +418 -0
- package/dist/resources/2010/LookingGlass.d.ts +29 -0
- package/dist/resources/2010/LookingGlass.js +89 -0
- package/dist/resources/2011/Gygaxian.d.ts +9 -0
- package/dist/resources/2011/Gygaxian.js +24 -0
- package/dist/resources/2011/ObtuseAngel.d.ts +33 -0
- package/dist/resources/2011/ObtuseAngel.js +51 -0
- package/dist/resources/2011/StompingBoots.d.ts +37 -0
- package/dist/resources/2011/StompingBoots.js +57 -0
- package/dist/resources/2012/RainDoh.d.ts +25 -0
- package/dist/resources/2012/RainDoh.js +37 -0
- package/dist/resources/2012/ReagnimatedGnome.d.ts +31 -0
- package/dist/resources/2012/ReagnimatedGnome.js +46 -0
- package/dist/resources/2012/Resolutions.d.ts +9 -0
- package/dist/resources/2012/Resolutions.js +28 -0
- package/dist/resources/2013/Florist.d.ts +81 -0
- package/dist/resources/2013/Florist.js +245 -0
- package/dist/resources/2013/JungMan.d.ts +33 -0
- package/dist/resources/2013/JungMan.js +69 -0
- package/dist/resources/2013/PulledTaffy.d.ts +9 -0
- package/dist/resources/2013/PulledTaffy.js +33 -0
- package/dist/resources/2014/CrimboShrub.d.ts +42 -0
- package/dist/resources/2014/CrimboShrub.js +89 -0
- package/dist/resources/2014/DNALab.d.ts +56 -0
- package/dist/resources/2014/DNALab.js +162 -0
- package/dist/resources/2014/WinterGarden.d.ts +23 -0
- package/dist/resources/2014/WinterGarden.js +35 -0
- package/dist/resources/2015/BarrelShrine.d.ts +8 -0
- package/dist/resources/2015/BarrelShrine.js +25 -0
- package/dist/resources/2015/ChateauMantegna.d.ts +52 -0
- package/dist/resources/2015/ChateauMantegna.js +99 -0
- package/dist/resources/2015/DeckOfEveryCard.d.ts +29 -0
- package/dist/resources/2015/DeckOfEveryCard.js +122 -0
- package/dist/resources/2015/Dinseylandfill.d.ts +89 -0
- package/dist/resources/2015/Dinseylandfill.js +205 -0
- package/dist/resources/2015/MayoClinic.d.ts +23 -0
- package/dist/resources/2015/MayoClinic.js +49 -0
- package/dist/resources/2016/GingerBread.d.ts +32 -0
- package/dist/resources/2016/GingerBread.js +73 -0
- package/dist/resources/2016/SourceTerminal.d.ts +181 -0
- package/dist/resources/2016/SourceTerminal.js +275 -0
- package/dist/resources/2016/Witchess.d.ts +17 -0
- package/dist/resources/2016/Witchess.js +47 -0
- package/dist/resources/2017/AsdonMartin.d.ts +59 -0
- package/dist/resources/2017/AsdonMartin.js +238 -0
- package/dist/resources/2017/Horsery.d.ts +19 -0
- package/dist/resources/2017/Horsery.js +42 -0
- package/dist/resources/2017/MummingTrunk.d.ts +8 -0
- package/dist/resources/2017/MummingTrunk.js +33 -0
- package/dist/resources/2017/Pantogram.d.ts +92 -0
- package/dist/resources/2017/Pantogram.js +174 -0
- package/dist/resources/2017/Robortender.d.ts +30 -0
- package/dist/resources/2017/Robortender.js +90 -0
- package/dist/resources/2017/Spacegate.d.ts +86 -0
- package/dist/resources/2017/Spacegate.js +178 -0
- package/dist/resources/2017/TunnelOfLove.d.ts +39 -0
- package/dist/resources/2017/TunnelOfLove.js +120 -0
- package/dist/resources/2018/LatteLoversMembersMug.d.ts +392 -0
- package/dist/resources/2018/LatteLoversMembersMug.js +303 -0
- package/dist/resources/2018/SongBoom.d.ts +33 -0
- package/dist/resources/2018/SongBoom.js +55 -0
- package/dist/resources/2019/BeachComb.d.ts +72 -0
- package/dist/resources/2019/BeachComb.js +118 -0
- package/dist/resources/2019/CampAway.d.ts +39 -0
- package/dist/resources/2019/CampAway.js +72 -0
- package/dist/resources/2019/Snapper.d.ts +33 -0
- package/dist/resources/2019/Snapper.js +73 -0
- package/dist/resources/2020/Cartography.d.ts +16 -0
- package/dist/resources/2020/Cartography.js +48 -0
- package/dist/resources/2020/Guzzlr.d.ts +160 -0
- package/dist/resources/2020/Guzzlr.js +275 -0
- package/dist/resources/2020/RetroCape.d.ts +51 -0
- package/dist/resources/2020/RetroCape.js +115 -0
- package/dist/resources/2021/CrystalBall.d.ts +14 -0
- package/dist/resources/2021/CrystalBall.js +41 -0
- package/dist/resources/2021/DaylightShavings.d.ts +40 -0
- package/dist/resources/2021/DaylightShavings.js +74 -0
- package/dist/resources/2022/AutumnAton.d.ts +78 -0
- package/dist/resources/2022/AutumnAton.js +182 -0
- package/dist/resources/2022/CombatLoversLocket.d.ts +44 -0
- package/dist/resources/2022/CombatLoversLocket.js +82 -0
- package/dist/resources/2022/GreyGoose.d.ts +59 -0
- package/dist/resources/2022/GreyGoose.js +90 -0
- package/dist/resources/2022/JuneCleaver.d.ts +47 -0
- package/dist/resources/2022/JuneCleaver.js +69 -0
- package/dist/resources/2022/TrainSet.d.ts +146 -0
- package/dist/resources/2022/TrainSet.js +228 -0
- package/dist/resources/2023/AugustScepter.d.ts +25 -0
- package/dist/resources/2023/AugustScepter.js +40 -0
- package/dist/resources/2023/BurningLeaves.d.ts +25 -0
- package/dist/resources/2023/BurningLeaves.js +74 -0
- package/dist/resources/2023/CinchoDeMayo.d.ts +25 -0
- package/dist/resources/2023/CinchoDeMayo.js +45 -0
- package/dist/resources/2023/ClosedCircuitPayphone.d.ts +80 -0
- package/dist/resources/2023/ClosedCircuitPayphone.js +129 -0
- package/dist/resources/2023/CursedMonkeyPaw.d.ts +46 -0
- package/dist/resources/2023/CursedMonkeyPaw.js +113 -0
- package/dist/resources/2024/AprilingBandHelmet.d.ts +57 -0
- package/dist/resources/2024/AprilingBandHelmet.js +118 -0
- package/dist/resources/2024/ChestMimic.d.ts +42 -0
- package/dist/resources/2024/ChestMimic.js +125 -0
- package/dist/resources/LibramSummon.d.ts +18 -0
- package/dist/resources/LibramSummon.js +74 -0
- package/dist/resources/index.d.ts +54 -0
- package/dist/resources/index.js +54 -0
- package/dist/resources/putty-likes.d.ts +21 -0
- package/dist/resources/putty-likes.js +33 -0
- package/dist/session.d.ts +169 -0
- package/dist/session.js +284 -0
- package/dist/since.d.ts +51 -0
- package/dist/since.js +108 -0
- package/dist/template-string.d.ts +324 -0
- package/dist/template-string.js +265 -0
- package/dist/url.d.ts +35 -0
- package/dist/url.js +67 -0
- package/dist/utils.d.ts +178 -0
- package/dist/utils.js +255 -0
- package/package.json +2 -2
package/dist/Kmail.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Item } from "kolmafia";
|
|
2
|
+
declare type RawKmail = {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
fromid: string;
|
|
6
|
+
azunixtime: string;
|
|
7
|
+
message: string;
|
|
8
|
+
fromname: string;
|
|
9
|
+
localtime: string;
|
|
10
|
+
};
|
|
11
|
+
export default class Kmail {
|
|
12
|
+
readonly id: number;
|
|
13
|
+
readonly date: Date;
|
|
14
|
+
readonly type: "normal" | "giftshop";
|
|
15
|
+
readonly senderId: number;
|
|
16
|
+
readonly senderName: string;
|
|
17
|
+
readonly rawMessage: string;
|
|
18
|
+
private _parsedMessageParts;
|
|
19
|
+
/**
|
|
20
|
+
* Parses a kmail from KoL's native format
|
|
21
|
+
*
|
|
22
|
+
* @param rawKmail Kmail in the format supplies by api.php
|
|
23
|
+
* @returns Parsed kmail
|
|
24
|
+
*/
|
|
25
|
+
static parse(rawKmail: RawKmail): Kmail;
|
|
26
|
+
/**
|
|
27
|
+
* Returns all of the player's kmails
|
|
28
|
+
*
|
|
29
|
+
* @param count Number of kmails to fetch
|
|
30
|
+
* @returns Parsed kmails
|
|
31
|
+
*/
|
|
32
|
+
static inbox(count?: number): Kmail[];
|
|
33
|
+
/**
|
|
34
|
+
* Bulk delete kmails
|
|
35
|
+
*
|
|
36
|
+
* @param kmails Kmails to delete
|
|
37
|
+
* @returns Number of kmails deleted
|
|
38
|
+
*/
|
|
39
|
+
static delete(kmails: Kmail[]): number;
|
|
40
|
+
private static _genericSend;
|
|
41
|
+
/**
|
|
42
|
+
* Sends a kmail to a player
|
|
43
|
+
*
|
|
44
|
+
* Sends multiple kmails if more than 11 unique item types are attached.
|
|
45
|
+
* Ignores any ungiftable items.
|
|
46
|
+
* Sends a gift package to players in run
|
|
47
|
+
*
|
|
48
|
+
* @param to The player name or id to receive the kmail
|
|
49
|
+
* @param message The text contents of the message
|
|
50
|
+
* @param items The items to be attached
|
|
51
|
+
* @param meat The quantity of meat to be attached
|
|
52
|
+
* @returns True if the kmail was successfully sent
|
|
53
|
+
*/
|
|
54
|
+
static send(to: string | number, message?: string, items?: Map<Item, number> | Item[], meat?: number): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Sends a gift to a player
|
|
57
|
+
*
|
|
58
|
+
* Sends multiple kmails if more than 3 unique item types are attached.
|
|
59
|
+
* Ignores any ungiftable items.
|
|
60
|
+
*
|
|
61
|
+
* @param to The player name or id to receive the gift
|
|
62
|
+
* @param message Message to send
|
|
63
|
+
* @param items The items to be attached
|
|
64
|
+
* @param meat The quantity of meat to be attached
|
|
65
|
+
* @param insideNote The note on the inside of the gift
|
|
66
|
+
* @returns True if the gift was successfully sent
|
|
67
|
+
*/
|
|
68
|
+
static gift(to: string | number, message?: string, items?: Map<Item, number> | Item[], meat?: number, insideNote?: string): boolean;
|
|
69
|
+
private constructor();
|
|
70
|
+
/**
|
|
71
|
+
* Delete the kmail
|
|
72
|
+
*
|
|
73
|
+
* @returns Whether the kmail was deleted
|
|
74
|
+
*/
|
|
75
|
+
delete(): boolean;
|
|
76
|
+
private get _messageParts();
|
|
77
|
+
private _parseMessageParts;
|
|
78
|
+
/**
|
|
79
|
+
* Get message contents without any HTML from items or meat
|
|
80
|
+
*
|
|
81
|
+
* @returns Cleaned message contents
|
|
82
|
+
*/
|
|
83
|
+
get message(): string;
|
|
84
|
+
/**
|
|
85
|
+
* Get the note on the outside of the gift. If the kmail is not a gift,
|
|
86
|
+
* this will be the entire message.
|
|
87
|
+
*
|
|
88
|
+
* @returns Note on the outside of the gift, or the entire message for non-gifts
|
|
89
|
+
*/
|
|
90
|
+
get outsideNote(): string;
|
|
91
|
+
/**
|
|
92
|
+
* Get the note on the inside of the gift
|
|
93
|
+
*
|
|
94
|
+
* @returns Note on the inside of the gift
|
|
95
|
+
*/
|
|
96
|
+
get insideNote(): string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Get items attached to the kmail
|
|
99
|
+
*
|
|
100
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
101
|
+
*/
|
|
102
|
+
items(): Map<Item, number>;
|
|
103
|
+
/**
|
|
104
|
+
* Get items attached to the outside of the gift, which should be
|
|
105
|
+
* just the gift wrapper for giftshop items, and all items for normal kmails
|
|
106
|
+
*
|
|
107
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
108
|
+
*/
|
|
109
|
+
outsideItems(): Map<Item, number>;
|
|
110
|
+
/**
|
|
111
|
+
* Get items attached to the inside of the gift
|
|
112
|
+
*
|
|
113
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
114
|
+
*/
|
|
115
|
+
insideItems(): Map<Item, number>;
|
|
116
|
+
/**
|
|
117
|
+
* Get meat attached to the kmail
|
|
118
|
+
*
|
|
119
|
+
* @returns Meat attached to the kmail
|
|
120
|
+
*/
|
|
121
|
+
meat(): number;
|
|
122
|
+
/**
|
|
123
|
+
* Reply to kmail
|
|
124
|
+
*
|
|
125
|
+
* @param message Message with which to reply
|
|
126
|
+
* @param items Items to send
|
|
127
|
+
* @param meat Meat to send
|
|
128
|
+
* @see Kmail.send
|
|
129
|
+
* @returns True if the kmail was successfully sent
|
|
130
|
+
*/
|
|
131
|
+
reply(message?: string, items?: Map<Item, number> | Item[], meat?: number): boolean;
|
|
132
|
+
}
|
|
133
|
+
export {};
|
package/dist/Kmail.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { decode as decodeEntities } from "html-entities";
|
|
2
|
+
import { extractMeat, isGiftable, visitUrl } from "kolmafia";
|
|
3
|
+
import { extractItems } from "./lib";
|
|
4
|
+
import { combineQuery, EMPTY_VALUE, fetchUrl } from "./url";
|
|
5
|
+
import { arrayToCountedMap, chunk } from "./utils";
|
|
6
|
+
export default class Kmail {
|
|
7
|
+
id;
|
|
8
|
+
date;
|
|
9
|
+
type;
|
|
10
|
+
senderId;
|
|
11
|
+
senderName;
|
|
12
|
+
rawMessage;
|
|
13
|
+
_parsedMessageParts;
|
|
14
|
+
/**
|
|
15
|
+
* Parses a kmail from KoL's native format
|
|
16
|
+
*
|
|
17
|
+
* @param rawKmail Kmail in the format supplies by api.php
|
|
18
|
+
* @returns Parsed kmail
|
|
19
|
+
*/
|
|
20
|
+
static parse(rawKmail) {
|
|
21
|
+
return new Kmail(rawKmail);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns all of the player's kmails
|
|
25
|
+
*
|
|
26
|
+
* @param count Number of kmails to fetch
|
|
27
|
+
* @returns Parsed kmails
|
|
28
|
+
*/
|
|
29
|
+
static inbox(count = 100) {
|
|
30
|
+
return JSON.parse(visitUrl(`api.php?what=kmail&for=libram&count=${count}`)).map(Kmail.parse);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Bulk delete kmails
|
|
34
|
+
*
|
|
35
|
+
* @param kmails Kmails to delete
|
|
36
|
+
* @returns Number of kmails deleted
|
|
37
|
+
*/
|
|
38
|
+
static delete(kmails) {
|
|
39
|
+
const results = fetchUrl("messages.php", [
|
|
40
|
+
["the_action", "delete"],
|
|
41
|
+
["box", "Inbox"],
|
|
42
|
+
["pwd", EMPTY_VALUE],
|
|
43
|
+
...kmails.map((k) => [`sel${k.id}`, "on"]),
|
|
44
|
+
]);
|
|
45
|
+
return Number(results.match(/<td>(\d) messages? deleted.<\/td>/)?.[1] ?? 0);
|
|
46
|
+
}
|
|
47
|
+
static _genericSend(to, message, items, meat, chunkSize, constructUrl, successString) {
|
|
48
|
+
let m = meat;
|
|
49
|
+
const sendableItems = [...arrayToCountedMap(items).entries()].filter(([item]) => isGiftable(item));
|
|
50
|
+
let result = true;
|
|
51
|
+
const chunks = chunk(sendableItems, chunkSize);
|
|
52
|
+
// Split the items to be sent into chunks of max 11 item types
|
|
53
|
+
for (const c of chunks.length > 0 ? chunks : [null]) {
|
|
54
|
+
const itemsQuery = {};
|
|
55
|
+
if (c !== null) {
|
|
56
|
+
c.forEach(([item, quantity], i) => {
|
|
57
|
+
itemsQuery[`whichitem${i + 1}`] = item.id;
|
|
58
|
+
itemsQuery[`howmany${i + 1}`] = quantity;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const { path, query } = constructUrl({
|
|
62
|
+
meat: m,
|
|
63
|
+
chunkSize: c?.length ?? 0,
|
|
64
|
+
});
|
|
65
|
+
const r = fetchUrl(path, combineQuery(query, itemsQuery));
|
|
66
|
+
if (r.includes("That player cannot receive Meat or items")) {
|
|
67
|
+
return Kmail.gift(to, message, items, meat);
|
|
68
|
+
}
|
|
69
|
+
// Make sure we don't send the same batch of meat with every chunk
|
|
70
|
+
m = 0;
|
|
71
|
+
result &&= r.includes(successString);
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sends a kmail to a player
|
|
77
|
+
*
|
|
78
|
+
* Sends multiple kmails if more than 11 unique item types are attached.
|
|
79
|
+
* Ignores any ungiftable items.
|
|
80
|
+
* Sends a gift package to players in run
|
|
81
|
+
*
|
|
82
|
+
* @param to The player name or id to receive the kmail
|
|
83
|
+
* @param message The text contents of the message
|
|
84
|
+
* @param items The items to be attached
|
|
85
|
+
* @param meat The quantity of meat to be attached
|
|
86
|
+
* @returns True if the kmail was successfully sent
|
|
87
|
+
*/
|
|
88
|
+
static send(to, message = "", items = [], meat = 0) {
|
|
89
|
+
return Kmail._genericSend(to, message, items, meat, 11, ({ meat }) => ({
|
|
90
|
+
path: "sendmessage.php",
|
|
91
|
+
query: {
|
|
92
|
+
action: "send",
|
|
93
|
+
pwd: EMPTY_VALUE,
|
|
94
|
+
towho: to,
|
|
95
|
+
message,
|
|
96
|
+
sendmeat: meat,
|
|
97
|
+
},
|
|
98
|
+
}), ">Message sent.</");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Sends a gift to a player
|
|
102
|
+
*
|
|
103
|
+
* Sends multiple kmails if more than 3 unique item types are attached.
|
|
104
|
+
* Ignores any ungiftable items.
|
|
105
|
+
*
|
|
106
|
+
* @param to The player name or id to receive the gift
|
|
107
|
+
* @param message Message to send
|
|
108
|
+
* @param items The items to be attached
|
|
109
|
+
* @param meat The quantity of meat to be attached
|
|
110
|
+
* @param insideNote The note on the inside of the gift
|
|
111
|
+
* @returns True if the gift was successfully sent
|
|
112
|
+
*/
|
|
113
|
+
static gift(to, message = "", items = [], meat = 0, insideNote = "") {
|
|
114
|
+
return Kmail._genericSend(to, message, items, meat, 3, ({ meat, chunkSize }) => ({
|
|
115
|
+
path: `town_sendgift.php`,
|
|
116
|
+
query: {
|
|
117
|
+
action: "Yep.",
|
|
118
|
+
pwd: EMPTY_VALUE,
|
|
119
|
+
fromwhere: 0,
|
|
120
|
+
note: message,
|
|
121
|
+
insidenote: insideNote,
|
|
122
|
+
towho: to,
|
|
123
|
+
whichpackage: chunkSize,
|
|
124
|
+
sendmeat: meat,
|
|
125
|
+
},
|
|
126
|
+
}), ">Package sent.</");
|
|
127
|
+
}
|
|
128
|
+
constructor(rawKmail) {
|
|
129
|
+
this.id = Number(rawKmail.id);
|
|
130
|
+
this.date = new Date(Number(rawKmail.azunixtime) * 1000);
|
|
131
|
+
this.type = rawKmail.type;
|
|
132
|
+
this.senderId = Number(rawKmail.fromid);
|
|
133
|
+
this.senderName = rawKmail.fromname;
|
|
134
|
+
this.rawMessage = rawKmail.message;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Delete the kmail
|
|
138
|
+
*
|
|
139
|
+
* @returns Whether the kmail was deleted
|
|
140
|
+
*/
|
|
141
|
+
delete() {
|
|
142
|
+
return Kmail.delete([this]) === 1;
|
|
143
|
+
}
|
|
144
|
+
get _messageParts() {
|
|
145
|
+
return (this._parsedMessageParts ??= this._parseMessageParts());
|
|
146
|
+
}
|
|
147
|
+
_parseMessageParts() {
|
|
148
|
+
let text = this.rawMessage;
|
|
149
|
+
let insideText;
|
|
150
|
+
if (this.type === "normal") {
|
|
151
|
+
// strip potential valentine
|
|
152
|
+
if (text.startsWith("<center>")) {
|
|
153
|
+
const endIdx = text.indexOf("</center>");
|
|
154
|
+
text = text.slice(endIdx + 9);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (this.type === "giftshop") {
|
|
158
|
+
[text, insideText] = text.split("<p>Inside Note:<p>");
|
|
159
|
+
}
|
|
160
|
+
const split = (s) => {
|
|
161
|
+
const idx = s.indexOf("<");
|
|
162
|
+
if (idx === -1)
|
|
163
|
+
return [s];
|
|
164
|
+
return [s.slice(0, idx), s.slice(idx)];
|
|
165
|
+
};
|
|
166
|
+
const [outsideNote, outsideAttachments = null] = split(text);
|
|
167
|
+
const [insideNote = null, insideAttachments = null] = insideText !== undefined ? split(insideText) : [];
|
|
168
|
+
return {
|
|
169
|
+
outsideNote: decodeEntities(outsideNote),
|
|
170
|
+
outsideAttachments,
|
|
171
|
+
insideNote: insideNote && decodeEntities(insideNote),
|
|
172
|
+
insideAttachments,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get message contents without any HTML from items or meat
|
|
177
|
+
*
|
|
178
|
+
* @returns Cleaned message contents
|
|
179
|
+
*/
|
|
180
|
+
get message() {
|
|
181
|
+
const { outsideNote, insideNote } = this._messageParts;
|
|
182
|
+
if (insideNote !== null) {
|
|
183
|
+
return `${outsideNote}\n\nInside Note:\n${insideNote}`;
|
|
184
|
+
}
|
|
185
|
+
return outsideNote;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Get the note on the outside of the gift. If the kmail is not a gift,
|
|
189
|
+
* this will be the entire message.
|
|
190
|
+
*
|
|
191
|
+
* @returns Note on the outside of the gift, or the entire message for non-gifts
|
|
192
|
+
*/
|
|
193
|
+
get outsideNote() {
|
|
194
|
+
return this._messageParts.outsideNote;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get the note on the inside of the gift
|
|
198
|
+
*
|
|
199
|
+
* @returns Note on the inside of the gift
|
|
200
|
+
*/
|
|
201
|
+
get insideNote() {
|
|
202
|
+
return this._messageParts.insideNote;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get items attached to the kmail
|
|
206
|
+
*
|
|
207
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
208
|
+
*/
|
|
209
|
+
items() {
|
|
210
|
+
const { outsideAttachments, insideAttachments } = this._messageParts;
|
|
211
|
+
return extractItems(`${outsideAttachments}${insideAttachments}`);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get items attached to the outside of the gift, which should be
|
|
215
|
+
* just the gift wrapper for giftshop items, and all items for normal kmails
|
|
216
|
+
*
|
|
217
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
218
|
+
*/
|
|
219
|
+
outsideItems() {
|
|
220
|
+
const { outsideAttachments } = this._messageParts;
|
|
221
|
+
if (!outsideAttachments)
|
|
222
|
+
return new Map();
|
|
223
|
+
return extractItems(outsideAttachments);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get items attached to the inside of the gift
|
|
227
|
+
*
|
|
228
|
+
* @returns Map of items attached to the kmail and their quantities
|
|
229
|
+
*/
|
|
230
|
+
insideItems() {
|
|
231
|
+
const { insideAttachments } = this._messageParts;
|
|
232
|
+
if (!insideAttachments)
|
|
233
|
+
return new Map();
|
|
234
|
+
return extractItems(insideAttachments);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get meat attached to the kmail
|
|
238
|
+
*
|
|
239
|
+
* @returns Meat attached to the kmail
|
|
240
|
+
*/
|
|
241
|
+
meat() {
|
|
242
|
+
const { outsideAttachments, insideAttachments } = this._messageParts;
|
|
243
|
+
if (!outsideAttachments && !insideAttachments)
|
|
244
|
+
return 0;
|
|
245
|
+
return extractMeat(`${outsideAttachments}${insideAttachments}`);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Reply to kmail
|
|
249
|
+
*
|
|
250
|
+
* @param message Message with which to reply
|
|
251
|
+
* @param items Items to send
|
|
252
|
+
* @param meat Meat to send
|
|
253
|
+
* @see Kmail.send
|
|
254
|
+
* @returns True if the kmail was successfully sent
|
|
255
|
+
*/
|
|
256
|
+
reply(message = "", items = [], meat = 0) {
|
|
257
|
+
return Kmail.send(this.senderId, message, items, meat);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Familiar, Item, Skill } from "kolmafia";
|
|
2
|
+
import { Macro } from "../combat";
|
|
3
|
+
import { Requirement } from "../maximize";
|
|
4
|
+
export declare type FindActionSourceConstraints = {
|
|
5
|
+
/**
|
|
6
|
+
* Function returning true if we only accept familiar-based actions.
|
|
7
|
+
*/
|
|
8
|
+
requireFamiliar?: () => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Function returning true if we only accept sources that are unlimited.
|
|
11
|
+
*/
|
|
12
|
+
requireUnlimited?: () => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Function returning whether to disallow actions requiring familiar change.
|
|
15
|
+
*/
|
|
16
|
+
noFamiliar?: () => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Function returning whether to disallow actions requiring equipment change.
|
|
19
|
+
*/
|
|
20
|
+
noRequirements?: () => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Function returning whether to disallow actions requiring preparation.
|
|
23
|
+
*/
|
|
24
|
+
noPreparation?: () => boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Function returning maximum cost of allowed actions. If undefined, allow
|
|
27
|
+
* only actions that cost nothing.
|
|
28
|
+
*/
|
|
29
|
+
maximumCost?: () => number;
|
|
30
|
+
/**
|
|
31
|
+
* Function allowing for custom logic if an action should be allowed.
|
|
32
|
+
* If undefined, allow all actions to be considered by other constraints.
|
|
33
|
+
*
|
|
34
|
+
* @param action The action that is being considered.
|
|
35
|
+
* @returns True if the action should be allowed.
|
|
36
|
+
*/
|
|
37
|
+
allowedAction?: (action: ActionSource) => boolean;
|
|
38
|
+
};
|
|
39
|
+
export declare type ActionConstraints = {
|
|
40
|
+
/**
|
|
41
|
+
* Equipment requirements to have this action available.
|
|
42
|
+
*/
|
|
43
|
+
equipmentRequirements?: () => Requirement;
|
|
44
|
+
/**
|
|
45
|
+
* Familiar required to be in use to have this action available.
|
|
46
|
+
*/
|
|
47
|
+
familiar?: () => Familiar;
|
|
48
|
+
/**
|
|
49
|
+
* Miscellaneous preparation to ensure this action is available.
|
|
50
|
+
*/
|
|
51
|
+
preparation?: () => boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Cost in meat per usage of this action.
|
|
54
|
+
*/
|
|
55
|
+
cost?: () => number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* A combat-based action resource in the game (e.g. a free run or free kill).
|
|
59
|
+
*/
|
|
60
|
+
export declare class ActionSource {
|
|
61
|
+
static defaultPriceFunction: (item: Item) => number;
|
|
62
|
+
source: Item | Skill | Familiar | Array<Item | Skill | Familiar>;
|
|
63
|
+
potential: () => number;
|
|
64
|
+
macro: Macro;
|
|
65
|
+
constraints: ActionConstraints;
|
|
66
|
+
/**
|
|
67
|
+
* @param source Source(s) of the action (e.g. item, skill, or familiar needed).
|
|
68
|
+
* @param potential Function returning how many times this action can be used.
|
|
69
|
+
* @param macro Macro to execute this action in combat.
|
|
70
|
+
* @param constraints Constraints required for this action to be available.
|
|
71
|
+
*/
|
|
72
|
+
constructor(source: Item | Skill | Familiar | Array<Item | Skill | Familiar>, potential: () => number, macro: Macro, constraints?: ActionConstraints);
|
|
73
|
+
/**
|
|
74
|
+
* @returns Name of the action source.
|
|
75
|
+
*/
|
|
76
|
+
name(): string;
|
|
77
|
+
/**
|
|
78
|
+
* @returns Whether the action is available.
|
|
79
|
+
*/
|
|
80
|
+
available(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* @returns Cost in meat per usage of the action.
|
|
83
|
+
*/
|
|
84
|
+
cost(): number;
|
|
85
|
+
/**
|
|
86
|
+
* @returns Whether the action costs 0 meat to use.
|
|
87
|
+
*/
|
|
88
|
+
isFree(): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* @returns Whether unlimited uses of the action are available.
|
|
91
|
+
*/
|
|
92
|
+
isUnlimited(): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Create a compound action source with merged constraints.
|
|
95
|
+
*
|
|
96
|
+
* @param others Other actions to have available.
|
|
97
|
+
* @returns Merged constraints, or null if they are inconsistent.
|
|
98
|
+
*/
|
|
99
|
+
merge(...others: ActionSource[]): ActionSource | null;
|
|
100
|
+
/**
|
|
101
|
+
* Perform all preparation necessary to make this action available.
|
|
102
|
+
*
|
|
103
|
+
* @param otherRequirements Any other equipment requirements.
|
|
104
|
+
* @returns Whether preparation succeeded.
|
|
105
|
+
*/
|
|
106
|
+
prepare(otherRequirements?: Requirement): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Perform all preparation necessary to make this action available.
|
|
109
|
+
* Throws an error if preparation fails.
|
|
110
|
+
*
|
|
111
|
+
* @param otherRequirements Any other equipment requirements.
|
|
112
|
+
*/
|
|
113
|
+
ensure(otherRequirements?: Requirement): void;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Find an available action source subject to constraints.
|
|
117
|
+
*
|
|
118
|
+
* @param actions Action source list.
|
|
119
|
+
* @param constraints Preexisting constraints that restrict possible sources.
|
|
120
|
+
* @returns Available action source satisfying constraints, or null.
|
|
121
|
+
*/
|
|
122
|
+
export declare function findActionSource(actions: ActionSource[], constraints?: FindActionSourceConstraints): ActionSource | null;
|
|
123
|
+
/**
|
|
124
|
+
* Count available action sources subject to constraints. Note that, if
|
|
125
|
+
* constraints.maximumCost is high enough, this will return Infinity.
|
|
126
|
+
*
|
|
127
|
+
* @param actions Action source list.
|
|
128
|
+
* @param constraints Preexisting constraints that restrict possible sources.
|
|
129
|
+
* @returns Count of available action sources.
|
|
130
|
+
*/
|
|
131
|
+
export declare function actionSourcesAvailable(actions: ActionSource[], constraints?: FindActionSourceConstraints): number;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { mallPrice, useFamiliar } from "kolmafia";
|
|
2
|
+
import { Macro } from "../combat";
|
|
3
|
+
import { Requirement } from "../maximize";
|
|
4
|
+
import { sum, flat } from "../utils";
|
|
5
|
+
/**
|
|
6
|
+
* Merge a set of constraints into one
|
|
7
|
+
*
|
|
8
|
+
* @param allConstraints Constraints to mege
|
|
9
|
+
* @returns Merged constraints
|
|
10
|
+
*/
|
|
11
|
+
function mergeConstraints(...allConstraints) {
|
|
12
|
+
const familiars = allConstraints
|
|
13
|
+
.map((constraints) => constraints.familiar)
|
|
14
|
+
.filter(Boolean);
|
|
15
|
+
if (familiars.length > 1) {
|
|
16
|
+
// Inconsistent requirements.
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const familiar = familiars.find((familiar) => familiar);
|
|
20
|
+
return {
|
|
21
|
+
equipmentRequirements: () => Requirement.merge([
|
|
22
|
+
...allConstraints.map((constraints) => constraints.equipmentRequirements?.() ?? new Requirement([], {})),
|
|
23
|
+
]),
|
|
24
|
+
preparation: () => {
|
|
25
|
+
let success = true;
|
|
26
|
+
for (const constraints of allConstraints) {
|
|
27
|
+
success =
|
|
28
|
+
success && (!constraints.preparation || constraints.preparation());
|
|
29
|
+
}
|
|
30
|
+
return success;
|
|
31
|
+
},
|
|
32
|
+
...(familiar ? { familiar } : {}),
|
|
33
|
+
cost: () => sum(allConstraints, (constraints) => constraints.cost?.() ?? 0),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A combat-based action resource in the game (e.g. a free run or free kill).
|
|
38
|
+
*/
|
|
39
|
+
export class ActionSource {
|
|
40
|
+
static defaultPriceFunction = (item) => mallPrice(item) > 0 ? mallPrice(item) : Infinity;
|
|
41
|
+
source;
|
|
42
|
+
potential; // Infinity: unlimited
|
|
43
|
+
macro;
|
|
44
|
+
constraints;
|
|
45
|
+
/**
|
|
46
|
+
* @param source Source(s) of the action (e.g. item, skill, or familiar needed).
|
|
47
|
+
* @param potential Function returning how many times this action can be used.
|
|
48
|
+
* @param macro Macro to execute this action in combat.
|
|
49
|
+
* @param constraints Constraints required for this action to be available.
|
|
50
|
+
*/
|
|
51
|
+
constructor(source, potential, macro, constraints = {}) {
|
|
52
|
+
this.source = source;
|
|
53
|
+
this.potential = potential;
|
|
54
|
+
this.macro = macro;
|
|
55
|
+
this.constraints = constraints;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @returns Name of the action source.
|
|
59
|
+
*/
|
|
60
|
+
name() {
|
|
61
|
+
return this.source.toString();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* @returns Whether the action is available.
|
|
65
|
+
*/
|
|
66
|
+
available() {
|
|
67
|
+
return this.potential() > 0;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* @returns Cost in meat per usage of the action.
|
|
71
|
+
*/
|
|
72
|
+
cost() {
|
|
73
|
+
return this.constraints.cost ? this.constraints.cost() : 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @returns Whether the action costs 0 meat to use.
|
|
77
|
+
*/
|
|
78
|
+
isFree() {
|
|
79
|
+
return !this.cost || this.cost() === 0;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @returns Whether unlimited uses of the action are available.
|
|
83
|
+
*/
|
|
84
|
+
isUnlimited() {
|
|
85
|
+
return this.potential() === Infinity;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a compound action source with merged constraints.
|
|
89
|
+
*
|
|
90
|
+
* @param others Other actions to have available.
|
|
91
|
+
* @returns Merged constraints, or null if they are inconsistent.
|
|
92
|
+
*/
|
|
93
|
+
merge(...others) {
|
|
94
|
+
const actions = [this, ...others];
|
|
95
|
+
const constraints = mergeConstraints(...actions.map((action) => action.constraints));
|
|
96
|
+
if (constraints === null) {
|
|
97
|
+
// Inconsistent constraints - no path forward here.
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return new ActionSource([...flat(actions.map((action) => action.source))], () => sum(actions, (action) => action.potential()), Macro.step(...actions.map((action) => action.macro)), constraints);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Perform all preparation necessary to make this action available.
|
|
104
|
+
*
|
|
105
|
+
* @param otherRequirements Any other equipment requirements.
|
|
106
|
+
* @returns Whether preparation succeeded.
|
|
107
|
+
*/
|
|
108
|
+
prepare(otherRequirements) {
|
|
109
|
+
if (this.constraints.familiar?.()) {
|
|
110
|
+
if (!useFamiliar(this.constraints.familiar()))
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if (this.constraints.equipmentRequirements) {
|
|
114
|
+
const requirement = otherRequirements
|
|
115
|
+
? otherRequirements.merge(this.constraints.equipmentRequirements())
|
|
116
|
+
: this.constraints.equipmentRequirements();
|
|
117
|
+
if (!requirement.maximize())
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (this.constraints.preparation)
|
|
121
|
+
return this.constraints.preparation();
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Perform all preparation necessary to make this action available.
|
|
126
|
+
* Throws an error if preparation fails.
|
|
127
|
+
*
|
|
128
|
+
* @param otherRequirements Any other equipment requirements.
|
|
129
|
+
*/
|
|
130
|
+
ensure(otherRequirements) {
|
|
131
|
+
if (!this.prepare(otherRequirements)) {
|
|
132
|
+
throw new Error(`Failed to prepare action ${this.name()}.`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* See if a supplied action meets a set of constraints
|
|
138
|
+
*
|
|
139
|
+
* @param action Action to test
|
|
140
|
+
* @param constraints Constraints to apply
|
|
141
|
+
* @returns Whether action meets constraints
|
|
142
|
+
*/
|
|
143
|
+
function filterAction(action, constraints) {
|
|
144
|
+
return (action.available() &&
|
|
145
|
+
(constraints.allowedAction === undefined ||
|
|
146
|
+
constraints.allowedAction(action)) &&
|
|
147
|
+
!(constraints.requireFamiliar?.() && !action.constraints.familiar) &&
|
|
148
|
+
!(constraints.requireUnlimited?.() && !action.isUnlimited()) &&
|
|
149
|
+
!(constraints.noFamiliar?.() && action.constraints.familiar) &&
|
|
150
|
+
!(constraints.noRequirements?.() && action.constraints.equipmentRequirements) &&
|
|
151
|
+
!(constraints.noPreparation?.() && action.constraints.preparation) &&
|
|
152
|
+
action.cost() <= (constraints.maximumCost?.() ?? 0));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Find an available action source subject to constraints.
|
|
156
|
+
*
|
|
157
|
+
* @param actions Action source list.
|
|
158
|
+
* @param constraints Preexisting constraints that restrict possible sources.
|
|
159
|
+
* @returns Available action source satisfying constraints, or null.
|
|
160
|
+
*/
|
|
161
|
+
export function findActionSource(actions, constraints = {}) {
|
|
162
|
+
const validActions = actions.filter((actions) => filterAction(actions, constraints));
|
|
163
|
+
if (validActions.length < 1)
|
|
164
|
+
return null;
|
|
165
|
+
return validActions.reduce((a, b) => (a.cost() <= b.cost() ? a : b));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Count available action sources subject to constraints. Note that, if
|
|
169
|
+
* constraints.maximumCost is high enough, this will return Infinity.
|
|
170
|
+
*
|
|
171
|
+
* @param actions Action source list.
|
|
172
|
+
* @param constraints Preexisting constraints that restrict possible sources.
|
|
173
|
+
* @returns Count of available action sources.
|
|
174
|
+
*/
|
|
175
|
+
export function actionSourcesAvailable(actions, constraints = {}) {
|
|
176
|
+
// TODO: This will overcount if any Actions share a counter
|
|
177
|
+
return sum(actions.filter((action) => filterAction(action, constraints ?? {})), (action) => action.potential());
|
|
178
|
+
}
|