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.
Files changed (195) hide show
  1. package/dist/Clan.d.ts +128 -0
  2. package/dist/Clan.js +300 -0
  3. package/dist/Copier.d.ts +9 -0
  4. package/dist/Copier.js +15 -0
  5. package/dist/Dungeon.d.ts +45 -0
  6. package/dist/Dungeon.js +115 -0
  7. package/dist/Kmail.d.ts +133 -0
  8. package/dist/Kmail.js +259 -0
  9. package/dist/actions/ActionSource.d.ts +131 -0
  10. package/dist/actions/ActionSource.js +178 -0
  11. package/dist/actions/Banish.d.ts +16 -0
  12. package/dist/actions/Banish.js +121 -0
  13. package/dist/actions/FreeKill.d.ts +16 -0
  14. package/dist/actions/FreeKill.js +94 -0
  15. package/dist/actions/FreeRun.d.ts +16 -0
  16. package/dist/actions/FreeRun.js +81 -0
  17. package/dist/actions/index.d.ts +4 -0
  18. package/dist/actions/index.js +4 -0
  19. package/dist/ascend.d.ts +83 -0
  20. package/dist/ascend.js +268 -0
  21. package/dist/challengePaths/2014/HeavyRains.d.ts +22 -0
  22. package/dist/challengePaths/2014/HeavyRains.js +75 -0
  23. package/dist/challengePaths/2015/CommunityService.d.ts +125 -0
  24. package/dist/challengePaths/2015/CommunityService.js +334 -0
  25. package/dist/challengePaths/2016/NuclearAutumn.d.ts +13 -0
  26. package/dist/challengePaths/2016/NuclearAutumn.js +21 -0
  27. package/dist/challengePaths/index.d.ts +4 -0
  28. package/dist/challengePaths/index.js +4 -0
  29. package/dist/combat.d.ts +414 -0
  30. package/dist/combat.js +711 -0
  31. package/dist/console.d.ts +12 -0
  32. package/dist/console.js +14 -0
  33. package/dist/counter.d.ts +22 -0
  34. package/dist/counter.js +37 -0
  35. package/dist/diet/index.d.ts +80 -0
  36. package/dist/diet/index.js +680 -0
  37. package/dist/diet/knapsack.d.ts +8 -0
  38. package/dist/diet/knapsack.js +128 -0
  39. package/dist/index.d.ts +29 -0
  40. package/dist/index.js +26 -0
  41. package/dist/lib.d.ts +507 -0
  42. package/dist/lib.js +970 -0
  43. package/dist/logger.d.ts +35 -0
  44. package/dist/logger.js +62 -0
  45. package/dist/maximize.d.ts +122 -0
  46. package/dist/maximize.js +531 -0
  47. package/dist/modifier.d.ts +41 -0
  48. package/dist/modifier.js +160 -0
  49. package/dist/modifierTypes.d.ts +16 -0
  50. package/dist/modifierTypes.js +9 -0
  51. package/dist/mood.d.ts +105 -0
  52. package/dist/mood.js +349 -0
  53. package/dist/moonSign.d.ts +13 -0
  54. package/dist/moonSign.js +25 -0
  55. package/dist/overlappingNames.d.ts +3 -0
  56. package/dist/overlappingNames.js +42 -0
  57. package/dist/property.d.ts +222 -0
  58. package/dist/property.js +385 -0
  59. package/dist/propertyTypes.d.ts +19 -0
  60. package/dist/propertyTypes.js +10 -0
  61. package/dist/propertyTyping.d.ts +65 -0
  62. package/dist/propertyTyping.js +91 -0
  63. package/dist/resources/2007/CandyHearts.d.ts +9 -0
  64. package/dist/resources/2007/CandyHearts.js +24 -0
  65. package/dist/resources/2008/DivineFavors.d.ts +9 -0
  66. package/dist/resources/2008/DivineFavors.js +27 -0
  67. package/dist/resources/2008/Stickers.d.ts +49 -0
  68. package/dist/resources/2008/Stickers.js +84 -0
  69. package/dist/resources/2009/Bandersnatch.d.ts +56 -0
  70. package/dist/resources/2009/Bandersnatch.js +93 -0
  71. package/dist/resources/2009/LoveSongs.d.ts +9 -0
  72. package/dist/resources/2009/LoveSongs.js +24 -0
  73. package/dist/resources/2009/SpookyPutty.d.ts +31 -0
  74. package/dist/resources/2009/SpookyPutty.js +49 -0
  75. package/dist/resources/2010/Brickos.d.ts +9 -0
  76. package/dist/resources/2010/Brickos.js +21 -0
  77. package/dist/resources/2010/CrownOfThrones.d.ts +68 -0
  78. package/dist/resources/2010/CrownOfThrones.js +418 -0
  79. package/dist/resources/2010/LookingGlass.d.ts +29 -0
  80. package/dist/resources/2010/LookingGlass.js +89 -0
  81. package/dist/resources/2011/Gygaxian.d.ts +9 -0
  82. package/dist/resources/2011/Gygaxian.js +24 -0
  83. package/dist/resources/2011/ObtuseAngel.d.ts +33 -0
  84. package/dist/resources/2011/ObtuseAngel.js +51 -0
  85. package/dist/resources/2011/StompingBoots.d.ts +37 -0
  86. package/dist/resources/2011/StompingBoots.js +57 -0
  87. package/dist/resources/2012/RainDoh.d.ts +25 -0
  88. package/dist/resources/2012/RainDoh.js +37 -0
  89. package/dist/resources/2012/ReagnimatedGnome.d.ts +31 -0
  90. package/dist/resources/2012/ReagnimatedGnome.js +46 -0
  91. package/dist/resources/2012/Resolutions.d.ts +9 -0
  92. package/dist/resources/2012/Resolutions.js +28 -0
  93. package/dist/resources/2013/Florist.d.ts +81 -0
  94. package/dist/resources/2013/Florist.js +245 -0
  95. package/dist/resources/2013/JungMan.d.ts +33 -0
  96. package/dist/resources/2013/JungMan.js +69 -0
  97. package/dist/resources/2013/PulledTaffy.d.ts +9 -0
  98. package/dist/resources/2013/PulledTaffy.js +33 -0
  99. package/dist/resources/2014/CrimboShrub.d.ts +42 -0
  100. package/dist/resources/2014/CrimboShrub.js +89 -0
  101. package/dist/resources/2014/DNALab.d.ts +56 -0
  102. package/dist/resources/2014/DNALab.js +162 -0
  103. package/dist/resources/2014/WinterGarden.d.ts +23 -0
  104. package/dist/resources/2014/WinterGarden.js +35 -0
  105. package/dist/resources/2015/BarrelShrine.d.ts +8 -0
  106. package/dist/resources/2015/BarrelShrine.js +25 -0
  107. package/dist/resources/2015/ChateauMantegna.d.ts +52 -0
  108. package/dist/resources/2015/ChateauMantegna.js +99 -0
  109. package/dist/resources/2015/DeckOfEveryCard.d.ts +29 -0
  110. package/dist/resources/2015/DeckOfEveryCard.js +122 -0
  111. package/dist/resources/2015/Dinseylandfill.d.ts +89 -0
  112. package/dist/resources/2015/Dinseylandfill.js +205 -0
  113. package/dist/resources/2015/MayoClinic.d.ts +23 -0
  114. package/dist/resources/2015/MayoClinic.js +49 -0
  115. package/dist/resources/2016/GingerBread.d.ts +32 -0
  116. package/dist/resources/2016/GingerBread.js +73 -0
  117. package/dist/resources/2016/SourceTerminal.d.ts +181 -0
  118. package/dist/resources/2016/SourceTerminal.js +275 -0
  119. package/dist/resources/2016/Witchess.d.ts +17 -0
  120. package/dist/resources/2016/Witchess.js +47 -0
  121. package/dist/resources/2017/AsdonMartin.d.ts +59 -0
  122. package/dist/resources/2017/AsdonMartin.js +238 -0
  123. package/dist/resources/2017/Horsery.d.ts +19 -0
  124. package/dist/resources/2017/Horsery.js +42 -0
  125. package/dist/resources/2017/MummingTrunk.d.ts +8 -0
  126. package/dist/resources/2017/MummingTrunk.js +33 -0
  127. package/dist/resources/2017/Pantogram.d.ts +92 -0
  128. package/dist/resources/2017/Pantogram.js +174 -0
  129. package/dist/resources/2017/Robortender.d.ts +30 -0
  130. package/dist/resources/2017/Robortender.js +90 -0
  131. package/dist/resources/2017/Spacegate.d.ts +86 -0
  132. package/dist/resources/2017/Spacegate.js +178 -0
  133. package/dist/resources/2017/TunnelOfLove.d.ts +39 -0
  134. package/dist/resources/2017/TunnelOfLove.js +120 -0
  135. package/dist/resources/2018/LatteLoversMembersMug.d.ts +392 -0
  136. package/dist/resources/2018/LatteLoversMembersMug.js +303 -0
  137. package/dist/resources/2018/SongBoom.d.ts +33 -0
  138. package/dist/resources/2018/SongBoom.js +55 -0
  139. package/dist/resources/2019/BeachComb.d.ts +72 -0
  140. package/dist/resources/2019/BeachComb.js +118 -0
  141. package/dist/resources/2019/CampAway.d.ts +39 -0
  142. package/dist/resources/2019/CampAway.js +72 -0
  143. package/dist/resources/2019/Snapper.d.ts +33 -0
  144. package/dist/resources/2019/Snapper.js +73 -0
  145. package/dist/resources/2020/Cartography.d.ts +16 -0
  146. package/dist/resources/2020/Cartography.js +48 -0
  147. package/dist/resources/2020/Guzzlr.d.ts +160 -0
  148. package/dist/resources/2020/Guzzlr.js +275 -0
  149. package/dist/resources/2020/RetroCape.d.ts +51 -0
  150. package/dist/resources/2020/RetroCape.js +115 -0
  151. package/dist/resources/2021/CrystalBall.d.ts +14 -0
  152. package/dist/resources/2021/CrystalBall.js +41 -0
  153. package/dist/resources/2021/DaylightShavings.d.ts +40 -0
  154. package/dist/resources/2021/DaylightShavings.js +74 -0
  155. package/dist/resources/2022/AutumnAton.d.ts +78 -0
  156. package/dist/resources/2022/AutumnAton.js +182 -0
  157. package/dist/resources/2022/CombatLoversLocket.d.ts +44 -0
  158. package/dist/resources/2022/CombatLoversLocket.js +82 -0
  159. package/dist/resources/2022/GreyGoose.d.ts +59 -0
  160. package/dist/resources/2022/GreyGoose.js +90 -0
  161. package/dist/resources/2022/JuneCleaver.d.ts +47 -0
  162. package/dist/resources/2022/JuneCleaver.js +69 -0
  163. package/dist/resources/2022/TrainSet.d.ts +146 -0
  164. package/dist/resources/2022/TrainSet.js +228 -0
  165. package/dist/resources/2023/AugustScepter.d.ts +25 -0
  166. package/dist/resources/2023/AugustScepter.js +40 -0
  167. package/dist/resources/2023/BurningLeaves.d.ts +25 -0
  168. package/dist/resources/2023/BurningLeaves.js +74 -0
  169. package/dist/resources/2023/CinchoDeMayo.d.ts +25 -0
  170. package/dist/resources/2023/CinchoDeMayo.js +45 -0
  171. package/dist/resources/2023/ClosedCircuitPayphone.d.ts +80 -0
  172. package/dist/resources/2023/ClosedCircuitPayphone.js +129 -0
  173. package/dist/resources/2023/CursedMonkeyPaw.d.ts +46 -0
  174. package/dist/resources/2023/CursedMonkeyPaw.js +113 -0
  175. package/dist/resources/2024/AprilingBandHelmet.d.ts +57 -0
  176. package/dist/resources/2024/AprilingBandHelmet.js +118 -0
  177. package/dist/resources/2024/ChestMimic.d.ts +42 -0
  178. package/dist/resources/2024/ChestMimic.js +125 -0
  179. package/dist/resources/LibramSummon.d.ts +18 -0
  180. package/dist/resources/LibramSummon.js +74 -0
  181. package/dist/resources/index.d.ts +54 -0
  182. package/dist/resources/index.js +54 -0
  183. package/dist/resources/putty-likes.d.ts +21 -0
  184. package/dist/resources/putty-likes.js +33 -0
  185. package/dist/session.d.ts +169 -0
  186. package/dist/session.js +284 -0
  187. package/dist/since.d.ts +51 -0
  188. package/dist/since.js +108 -0
  189. package/dist/template-string.d.ts +324 -0
  190. package/dist/template-string.js +265 -0
  191. package/dist/url.d.ts +35 -0
  192. package/dist/url.js +67 -0
  193. package/dist/utils.d.ts +178 -0
  194. package/dist/utils.js +255 -0
  195. package/package.json +2 -2
@@ -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
+ }