libram 0.6.5 → 0.6.8
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 +1 -4
- package/dist/Clan.js +15 -60
- package/dist/Kmail.js +1 -3
- package/dist/Path.d.ts +1 -0
- package/dist/Path.js +2 -0
- package/dist/ascend.d.ts +3 -2
- package/dist/ascend.js +16 -10
- package/dist/challengePaths/2015/CommunityService.d.ts +33 -33
- package/dist/challengePaths/2015/CommunityService.js +118 -104
- package/dist/challengePaths/index.d.ts +1 -1
- package/dist/challengePaths/index.js +1 -1
- package/dist/combat.js +1 -3
- package/dist/console.d.ts +12 -4
- package/dist/console.js +0 -1
- package/dist/diet/index.js +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/mood.d.ts +1 -1
- package/dist/mood.js +9 -5
- package/dist/propertyTypes.d.ts +4 -4
- package/dist/propertyTypes.js +4 -4
- package/dist/resources/2010/CrownOfThrones.js +1 -1
- package/dist/resources/2017/AsdonMartin.d.ts +11 -4
- package/dist/resources/2017/AsdonMartin.js +39 -6
- package/dist/resources/2017/MummingTrunk.d.ts +7 -0
- package/dist/resources/2017/MummingTrunk.js +26 -0
- package/dist/resources/2019/Snapper.js +1 -1
- package/dist/resources/2020/RetroCape.d.ts +48 -0
- package/dist/resources/2020/RetroCape.js +111 -0
- package/dist/resources/2022/CombatLoversLocket.d.ts +36 -0
- package/dist/resources/2022/CombatLoversLocket.js +73 -0
- package/dist/resources/index.d.ts +4 -1
- package/dist/resources/index.js +4 -1
- package/package.json +15 -13
package/dist/Clan.d.ts
CHANGED
|
@@ -4,10 +4,6 @@ export interface Rank {
|
|
|
4
4
|
degree: number;
|
|
5
5
|
id: number;
|
|
6
6
|
}
|
|
7
|
-
export declare class ClanError extends Error {
|
|
8
|
-
reason?: Error;
|
|
9
|
-
constructor(message: string, reason?: Error);
|
|
10
|
-
}
|
|
11
7
|
export declare class Clan {
|
|
12
8
|
readonly id: number;
|
|
13
9
|
readonly name: string;
|
|
@@ -43,6 +39,7 @@ export declare class Clan {
|
|
|
43
39
|
*/
|
|
44
40
|
static getWhitelisted(): Clan[];
|
|
45
41
|
private constructor();
|
|
42
|
+
private _check;
|
|
46
43
|
/**
|
|
47
44
|
* Join clan
|
|
48
45
|
*/
|
package/dist/Clan.js
CHANGED
|
@@ -1,39 +1,7 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
1
|
import { availableAmount, cliExecute, getClanId, getClanName, getPlayerId, Monster, putStash, refreshStash, retrieveItem, stashAmount, takeStash, visitUrl, xpath, } from "kolmafia";
|
|
8
2
|
import { getFoldGroup } from "./lib";
|
|
9
3
|
import logger from "./logger";
|
|
10
4
|
import { arrayToCountedMap, countedMapToArray, countedMapToString, notNull, parseNumber, } from "./utils";
|
|
11
|
-
export class ClanError extends Error {
|
|
12
|
-
reason;
|
|
13
|
-
constructor(message, reason) {
|
|
14
|
-
super(message);
|
|
15
|
-
this.reason = reason;
|
|
16
|
-
Object.setPrototypeOf(this, ClanError.prototype);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
// It would be fantastic to have this function properly typed
|
|
20
|
-
// But until someone can work out how to do it, it gets the
|
|
21
|
-
// comment blocks of shame
|
|
22
|
-
/* eslint-disable */
|
|
23
|
-
function validate(target, propertyName, descriptor) {
|
|
24
|
-
if (!descriptor?.value)
|
|
25
|
-
return;
|
|
26
|
-
const method = descriptor.value;
|
|
27
|
-
// @ts-ignore
|
|
28
|
-
descriptor.value = function (...args) {
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
if (this.id !== getClanId()) {
|
|
31
|
-
throw new Error("You are no longer a member of this clan");
|
|
32
|
-
}
|
|
33
|
-
return method.apply(this, args);
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/* eslint-enable */
|
|
37
5
|
const clanIdCache = {};
|
|
38
6
|
const toPlayerId = (player) => typeof player === "string" ? getPlayerId(player) : player;
|
|
39
7
|
const LOG_FAX_PATTERN = /(\d{2}\/\d{2}\/\d{2}, \d{2}:\d{2}(?:AM|PM): )<a [^>]+>([^<]+)<\/a>(?: faxed in a (?<monster>.*?))<br>/;
|
|
@@ -146,11 +114,16 @@ export class Clan {
|
|
|
146
114
|
this.id = id;
|
|
147
115
|
this.name = name;
|
|
148
116
|
}
|
|
117
|
+
_check() {
|
|
118
|
+
if (this.id !== getClanId()) {
|
|
119
|
+
throw new Error("You are no longer a member of this clan");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
149
122
|
/**
|
|
150
123
|
* Join clan
|
|
151
124
|
*/
|
|
152
125
|
join() {
|
|
153
|
-
return Clan.
|
|
126
|
+
return Clan.join(this.id);
|
|
154
127
|
}
|
|
155
128
|
check() {
|
|
156
129
|
return visitUrl("clan_hall.php").includes(`<b>${this.name}</b>`);
|
|
@@ -159,6 +132,7 @@ export class Clan {
|
|
|
159
132
|
* Return the monster that is currently in the current clan's fax machine if any
|
|
160
133
|
*/
|
|
161
134
|
getCurrentFax() {
|
|
135
|
+
this._check();
|
|
162
136
|
const logs = visitUrl("clan_log.php");
|
|
163
137
|
const lastFax = logs.match(LOG_FAX_PATTERN);
|
|
164
138
|
if (!lastFax)
|
|
@@ -172,6 +146,7 @@ export class Clan {
|
|
|
172
146
|
* List available ranks (name, degree and id) from the current clan
|
|
173
147
|
*/
|
|
174
148
|
getRanks() {
|
|
149
|
+
this._check();
|
|
175
150
|
const page = visitUrl("clan_whitelist.php");
|
|
176
151
|
return xpath(page, '//select[@name="level"]//option')
|
|
177
152
|
.map((option) => {
|
|
@@ -197,6 +172,7 @@ export class Clan {
|
|
|
197
172
|
* @param title Title to give the player. If not provided, will be blank
|
|
198
173
|
*/
|
|
199
174
|
addPlayerToWhitelist(player, rankName, title = "") {
|
|
175
|
+
this._check();
|
|
200
176
|
const playerId = toPlayerId(player);
|
|
201
177
|
const ranks = this.getRanks();
|
|
202
178
|
const rank = rankName
|
|
@@ -213,6 +189,7 @@ export class Clan {
|
|
|
213
189
|
* @param player Player id or name
|
|
214
190
|
*/
|
|
215
191
|
removePlayerFromWhitelist(player) {
|
|
192
|
+
this._check();
|
|
216
193
|
const playerId = toPlayerId(player);
|
|
217
194
|
const result = visitUrl(`clan_whitelist.php?action=updatewl&pwd&who=${playerId}&remove=Remove`);
|
|
218
195
|
return result.includes("Whitelist updated.");
|
|
@@ -221,6 +198,7 @@ export class Clan {
|
|
|
221
198
|
* Return the amount of meat in the current clan's coffer.
|
|
222
199
|
*/
|
|
223
200
|
getMeatInCoffer() {
|
|
201
|
+
this._check();
|
|
224
202
|
const page = visitUrl("clan_stash.php");
|
|
225
203
|
const [, meat] = page.match(/Your <b>Clan Coffer<\/b> contains ([\d,]+) Meat./) || ["0", "0"];
|
|
226
204
|
return parseNumber(meat);
|
|
@@ -230,10 +208,12 @@ export class Clan {
|
|
|
230
208
|
* @param amount Amount of meat to put in coffer
|
|
231
209
|
*/
|
|
232
210
|
putMeatInCoffer(amount) {
|
|
211
|
+
this._check();
|
|
233
212
|
const result = visitUrl(`clan_stash.php?pwd&action=contribute&howmuch=${amount}`);
|
|
234
213
|
return result.includes("You contributed");
|
|
235
214
|
}
|
|
236
215
|
take(items) {
|
|
216
|
+
this._check();
|
|
237
217
|
const map = arrayToCountedMap(items);
|
|
238
218
|
map.forEach((quantity, item) => {
|
|
239
219
|
let needed = Math.max(0, quantity - availableAmount(item));
|
|
@@ -271,6 +251,7 @@ export class Clan {
|
|
|
271
251
|
return Array.isArray(items) ? countedMapToArray(map) : map;
|
|
272
252
|
}
|
|
273
253
|
put(items) {
|
|
254
|
+
this._check();
|
|
274
255
|
const map = arrayToCountedMap(items);
|
|
275
256
|
if (!this.check())
|
|
276
257
|
throw new Error(`Wanted to return ${countedMapToString(map)} to ${this.name} but KoLmafia's clan data is out of sync`);
|
|
@@ -284,34 +265,8 @@ export class Clan {
|
|
|
284
265
|
}
|
|
285
266
|
withStash(items, callback // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
286
267
|
) {
|
|
268
|
+
this._check();
|
|
287
269
|
const map = arrayToCountedMap(items);
|
|
288
270
|
return Clan._withStash(() => this.take(map), (borrowed) => this.put(borrowed), callback);
|
|
289
271
|
}
|
|
290
272
|
}
|
|
291
|
-
__decorate([
|
|
292
|
-
validate
|
|
293
|
-
], Clan.prototype, "getCurrentFax", null);
|
|
294
|
-
__decorate([
|
|
295
|
-
validate
|
|
296
|
-
], Clan.prototype, "getRanks", null);
|
|
297
|
-
__decorate([
|
|
298
|
-
validate
|
|
299
|
-
], Clan.prototype, "addPlayerToWhitelist", null);
|
|
300
|
-
__decorate([
|
|
301
|
-
validate
|
|
302
|
-
], Clan.prototype, "removePlayerFromWhitelist", null);
|
|
303
|
-
__decorate([
|
|
304
|
-
validate
|
|
305
|
-
], Clan.prototype, "getMeatInCoffer", null);
|
|
306
|
-
__decorate([
|
|
307
|
-
validate
|
|
308
|
-
], Clan.prototype, "putMeatInCoffer", null);
|
|
309
|
-
__decorate([
|
|
310
|
-
validate
|
|
311
|
-
], Clan.prototype, "take", null);
|
|
312
|
-
__decorate([
|
|
313
|
-
validate
|
|
314
|
-
], Clan.prototype, "put", null);
|
|
315
|
-
__decorate([
|
|
316
|
-
validate
|
|
317
|
-
], Clan.prototype, "withStash", null);
|
package/dist/Kmail.js
CHANGED
|
@@ -40,9 +40,7 @@ export default class Kmail {
|
|
|
40
40
|
}
|
|
41
41
|
static _genericSend(to, message, items, meat, chunkSize, constructUrl, successString) {
|
|
42
42
|
let m = meat;
|
|
43
|
-
const sendableItems = [
|
|
44
|
-
...arrayToCountedMap(items).entries(),
|
|
45
|
-
].filter(([item]) => isGiftable(item));
|
|
43
|
+
const sendableItems = [...arrayToCountedMap(items).entries()].filter(([item]) => isGiftable(item));
|
|
46
44
|
let result = true;
|
|
47
45
|
const chunks = chunk(sendableItems, chunkSize);
|
|
48
46
|
// Split the items to be sent into chunks of max 11 item types
|
package/dist/Path.d.ts
CHANGED
package/dist/Path.js
CHANGED
|
@@ -75,4 +75,6 @@ export const Paths = {
|
|
|
75
75
|
YouRobot: new Path("You, Robot", 41, false, false, true, 0, 0, 0),
|
|
76
76
|
QuantumTerrarium: new Path("Quantum Terrarium", 42, true, true, false),
|
|
77
77
|
Wildfire: new Path("Wildfire", 43),
|
|
78
|
+
GreyYou: new Path("Grey You", 44, false, true, true, 0, 0, 0, // eslint-disable-next-line libram/verify-constants
|
|
79
|
+
$classes `Grey Goo`),
|
|
78
80
|
};
|
package/dist/ascend.d.ts
CHANGED
|
@@ -28,10 +28,10 @@ declare type Eudora = typeof eudorae[number];
|
|
|
28
28
|
* Sets up various iotms you may want to use in the coming ascension
|
|
29
29
|
* @param ascensionItems.workshed Workshed to switch to.
|
|
30
30
|
* @param ascensionItems.garden Garden to switch to.
|
|
31
|
-
* @param ascensionItems An object potentially containing your workshed, garden, and eudora, all as
|
|
31
|
+
* @param ascensionItems An object potentially containing your workshed, garden, chateau, and eudora, all as strings
|
|
32
32
|
* @param throwOnFail If true, this will throw an error when it fails to switch something
|
|
33
33
|
*/
|
|
34
|
-
export declare function prepareAscension({ workshed, garden, eudora, chateau, }?: {
|
|
34
|
+
export declare function prepareAscension({ workshed, garden, eudora, chateau, throwOnFail, }?: {
|
|
35
35
|
workshed?: Workshed;
|
|
36
36
|
garden?: Garden;
|
|
37
37
|
eudora?: Eudora;
|
|
@@ -40,5 +40,6 @@ export declare function prepareAscension({ workshed, garden, eudora, chateau, }?
|
|
|
40
40
|
ceiling?: Ceiling;
|
|
41
41
|
nightstand?: Nightstand;
|
|
42
42
|
};
|
|
43
|
+
throwOnFail?: boolean;
|
|
43
44
|
}): void;
|
|
44
45
|
export {};
|
package/dist/ascend.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { containsText, eudoraItem, getCampground, getWorkshed, Item, toInt,
|
|
1
|
+
import { containsText, eudoraItem, getCampground, getWorkshed, Item, toInt, use, visitUrl, xpath, } from "kolmafia";
|
|
2
2
|
import { ChateauMantegna } from "./resources";
|
|
3
3
|
import { $item, $items, $stat } from "./template-string";
|
|
4
4
|
export var Lifestyle;
|
|
@@ -135,45 +135,51 @@ const eudorae = [
|
|
|
135
135
|
* Sets up various iotms you may want to use in the coming ascension
|
|
136
136
|
* @param ascensionItems.workshed Workshed to switch to.
|
|
137
137
|
* @param ascensionItems.garden Garden to switch to.
|
|
138
|
-
* @param ascensionItems An object potentially containing your workshed, garden, and eudora, all as
|
|
138
|
+
* @param ascensionItems An object potentially containing your workshed, garden, chateau, and eudora, all as strings
|
|
139
139
|
* @param throwOnFail If true, this will throw an error when it fails to switch something
|
|
140
140
|
*/
|
|
141
|
-
export function prepareAscension({ workshed, garden, eudora, chateau, } = {}) {
|
|
142
|
-
|
|
141
|
+
export function prepareAscension({ workshed, garden, eudora, chateau, throwOnFail, } = {}) {
|
|
142
|
+
throwOnFail = throwOnFail ?? true;
|
|
143
|
+
if (workshed && getWorkshed() !== Item.get(workshed)) {
|
|
143
144
|
use(Item.get(workshed));
|
|
145
|
+
if (getWorkshed().name !== workshed && throwOnFail) {
|
|
146
|
+
throw new Error(`Failed to switch workshed to ${workshed}; it is currently still ${getWorkshed()}.`);
|
|
147
|
+
}
|
|
144
148
|
}
|
|
145
149
|
if (garden && !Object.getOwnPropertyNames(getCampground()).includes(garden)) {
|
|
146
150
|
use(Item.get(garden));
|
|
147
|
-
if (!Object.getOwnPropertyNames(getCampground()).includes(garden)
|
|
151
|
+
if (!Object.getOwnPropertyNames(getCampground()).includes(garden) &&
|
|
152
|
+
throwOnFail) {
|
|
148
153
|
throw new Error(`We really thought we changed your garden to a ${garden}, but Mafia is saying otherwise.`);
|
|
149
154
|
}
|
|
150
155
|
}
|
|
151
156
|
if (eudora && eudoraItem().name !== eudora) {
|
|
152
157
|
const eudoraNumber = 1 + eudorae.indexOf(eudora);
|
|
153
|
-
if (!xpath(visitUrl("account.php?tab=correspondence"), `//select[@name="whichpenpal"]/option/@value`).includes(eudoraNumber.toString())
|
|
158
|
+
if (!xpath(visitUrl("account.php?tab=correspondence"), `//select[@name="whichpenpal"]/option/@value`).includes(eudoraNumber.toString()) &&
|
|
159
|
+
throwOnFail) {
|
|
154
160
|
throw new Error(`I'm sorry buddy, but you don't seem to be subscribed to ${eudora}. Which makes it REALLY hard to correspond with them.`);
|
|
155
161
|
}
|
|
156
162
|
else {
|
|
157
163
|
visitUrl(`account.php?actions[]=whichpenpal&whichpenpal=${eudoraNumber}&action=Update`, true);
|
|
158
164
|
}
|
|
159
|
-
if (eudoraItem() !==
|
|
165
|
+
if (eudoraItem() !== Item.get(eudora) && throwOnFail) {
|
|
160
166
|
throw new Error(`We really thought we changed your eudora to a ${eudora}, but Mafia is saying otherwise.`);
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
169
|
if (chateau && ChateauMantegna.have()) {
|
|
164
170
|
const { desk, ceiling, nightstand } = chateau;
|
|
165
171
|
if (ceiling && ChateauMantegna.getCeiling() !== ceiling) {
|
|
166
|
-
if (!ChateauMantegna.changeCeiling(ceiling)) {
|
|
172
|
+
if (!ChateauMantegna.changeCeiling(ceiling) && throwOnFail) {
|
|
167
173
|
throw new Error(`We tried, but were unable to change your chateau ceiling to ${ceiling}. Probably.`);
|
|
168
174
|
}
|
|
169
175
|
}
|
|
170
176
|
if (desk && ChateauMantegna.getDesk() !== desk) {
|
|
171
|
-
if (!ChateauMantegna.changeDesk(desk)) {
|
|
177
|
+
if (!ChateauMantegna.changeDesk(desk) && throwOnFail) {
|
|
172
178
|
throw new Error(`We tried, but were unable to change your chateau desk to ${desk}. Probably.`);
|
|
173
179
|
}
|
|
174
180
|
}
|
|
175
181
|
if (nightstand && ChateauMantegna.getNightstand() !== nightstand) {
|
|
176
|
-
if (!ChateauMantegna.changeNightstand(nightstand)) {
|
|
182
|
+
if (!ChateauMantegna.changeNightstand(nightstand) && throwOnFail) {
|
|
177
183
|
throw new Error(`We tried, but were unable to change your chateau nightstand to ${nightstand}. Probably.`);
|
|
178
184
|
}
|
|
179
185
|
}
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import { Requirement } from "../../maximize";
|
|
2
|
-
|
|
3
|
-
* A log of the predicted turns, actual turns, and duration of each CS test performed.
|
|
4
|
-
*/
|
|
5
|
-
export declare const log: {
|
|
6
|
-
[index: string]: {
|
|
7
|
-
predictedTurns: number;
|
|
8
|
-
turnCost: number;
|
|
9
|
-
seconds: number;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
declare class Test {
|
|
2
|
+
export default class CommunityService {
|
|
13
3
|
private choice;
|
|
14
4
|
private property;
|
|
15
5
|
private predictor;
|
|
@@ -21,7 +11,7 @@ declare class Test {
|
|
|
21
11
|
* @param predictor A function that returns an estimate for the number of turns that the test will take given your character's current state.
|
|
22
12
|
* @param maximizeRequirements A Requirement object, if applicable, that aligns with the things needed to maximize for this particular test.
|
|
23
13
|
*/
|
|
24
|
-
constructor(
|
|
14
|
+
private constructor();
|
|
25
15
|
/**
|
|
26
16
|
* @returns The id number of the test, used primarily in runChoice.
|
|
27
17
|
*/
|
|
@@ -54,32 +44,42 @@ declare class Test {
|
|
|
54
44
|
do(): boolean;
|
|
55
45
|
/**
|
|
56
46
|
* Wrapper function that prepares for a test and then completes it, adding time and turn details to the log.
|
|
57
|
-
* @param prepare A function that does all necessary preparations for this CS test, including choosing your outfit.
|
|
47
|
+
* @param prepare A function that does all necessary preparations for this CS test, including choosing your outfit. Optionally returns the number of turns you expect to spend preparing for the test.
|
|
58
48
|
* @param beCertain Whether we should check council.php instead of mafia to determine whether the test is complete.
|
|
59
|
-
* @
|
|
49
|
+
* @param maxTurns We will run the test iff the predicted turns is less than or equal to this parameter.
|
|
50
|
+
* @returns "completed", "failed", or "already completed".
|
|
60
51
|
*/
|
|
61
|
-
run
|
|
52
|
+
run(prepare: () => void | number, beCertain?: boolean, maxTurns?: number): "completed" | "failed" | "already completed";
|
|
62
53
|
/**
|
|
63
54
|
* Checks council.php to verify that a test is complete; more reliable than isDone, but requires an additional pagehit.
|
|
64
55
|
* @returns Whether council.php suggests that the test is complete.
|
|
65
56
|
*/
|
|
66
57
|
verifyIsDone(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* A log of the predicted turns, actual turns, and duration of each CS test performed.
|
|
60
|
+
*/
|
|
61
|
+
static log: {
|
|
62
|
+
[index: string]: {
|
|
63
|
+
predictedTurns: number;
|
|
64
|
+
turnCost: number;
|
|
65
|
+
seconds: number;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Prints turncount and time details of the test in question.
|
|
70
|
+
* @param colour The colour (or color) you'd like the log to be printed in.
|
|
71
|
+
*/
|
|
72
|
+
static printLog(colour?: string): void;
|
|
73
|
+
static HP: CommunityService;
|
|
74
|
+
static Muscle: CommunityService;
|
|
75
|
+
static Mysticality: CommunityService;
|
|
76
|
+
static Moxie: CommunityService;
|
|
77
|
+
static FamiliarWeight: CommunityService;
|
|
78
|
+
static WeaponDamage: CommunityService;
|
|
79
|
+
static SpellDamage: CommunityService;
|
|
80
|
+
static Noncombat: CommunityService;
|
|
81
|
+
static BoozeDrop: CommunityService;
|
|
82
|
+
static HotRes: CommunityService;
|
|
83
|
+
static CoilWire: CommunityService;
|
|
84
|
+
static donate: () => void;
|
|
67
85
|
}
|
|
68
|
-
export declare const HP: Test;
|
|
69
|
-
export declare const Muscle: Test;
|
|
70
|
-
export declare const Mysticality: Test;
|
|
71
|
-
export declare const Moxie: Test;
|
|
72
|
-
export declare const FamiliarWeight: Test;
|
|
73
|
-
export declare const WeaponDamage: Test;
|
|
74
|
-
export declare const SpellDamage: Test;
|
|
75
|
-
export declare const Noncombat: Test;
|
|
76
|
-
export declare const BoozeDrop: Test;
|
|
77
|
-
export declare const HotRes: Test;
|
|
78
|
-
export declare const CoilWire: Test;
|
|
79
|
-
/**
|
|
80
|
-
* Prints turncount and time details of the test in question.
|
|
81
|
-
* @param colour The colour (or color) you'd like the log to be printed in.
|
|
82
|
-
*/
|
|
83
|
-
export declare function printLog(colour?: string): void;
|
|
84
|
-
export declare const donate: () => void;
|
|
85
|
-
export {};
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import { equippedItem, familiarWeight, getPower, haveEquipped, myBasestat, myBuffedstat,
|
|
1
|
+
import { equippedItem, familiarWeight, getPower, haveEquipped, myBasestat, myBuffedstat, myFamiliar, myMaxhp, myThrall, myTurncount, numericModifier, print, runChoice, toSlot, visitUrl, weightAdjustment, } from "kolmafia";
|
|
2
2
|
import { have } from "../../lib";
|
|
3
3
|
import { Requirement } from "../../maximize";
|
|
4
4
|
import { get as getModifier } from "../../modifier";
|
|
5
5
|
import { get } from "../../property";
|
|
6
|
-
import {
|
|
7
|
-
import { $
|
|
6
|
+
import { MummingTrunk } from "../../resources";
|
|
7
|
+
import { $effect, $familiar, $item, $items, $slot, $stat, $thrall, } from "../../template-string";
|
|
8
8
|
import { sum } from "../../utils";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
const thralls = new Map([
|
|
10
|
+
[$stat `muscle`, $thrall `Elbow Macaroni`],
|
|
11
|
+
[$stat `moxie`, $thrall `Penne Dreadful`],
|
|
12
|
+
]);
|
|
13
|
+
const statCommunityServicePredictor = (stat) => {
|
|
14
|
+
return () => 60 -
|
|
15
|
+
Math.floor((1 / 30) *
|
|
16
|
+
(myBuffedstat(stat) -
|
|
17
|
+
myBasestat(thralls.get(stat) === myThrall() ? $stat `mysticality` : stat)));
|
|
18
|
+
};
|
|
19
|
+
export default class CommunityService {
|
|
14
20
|
choice;
|
|
15
21
|
property;
|
|
16
22
|
predictor;
|
|
@@ -22,7 +28,7 @@ class Test {
|
|
|
22
28
|
* @param predictor A function that returns an estimate for the number of turns that the test will take given your character's current state.
|
|
23
29
|
* @param maximizeRequirements A Requirement object, if applicable, that aligns with the things needed to maximize for this particular test.
|
|
24
30
|
*/
|
|
25
|
-
constructor(id, property, predictor, maximizeRequirements
|
|
31
|
+
constructor(id, property, predictor, maximizeRequirements) {
|
|
26
32
|
this.choice = id;
|
|
27
33
|
this.property = property;
|
|
28
34
|
this.predictor = predictor;
|
|
@@ -71,37 +77,45 @@ class Test {
|
|
|
71
77
|
* @returns Whether mafia believes the test is complete at the end of this function.
|
|
72
78
|
*/
|
|
73
79
|
do() {
|
|
80
|
+
if (get("csServicesPerformed").trim().length === 0)
|
|
81
|
+
visitUrl("council.php");
|
|
74
82
|
visitUrl("council.php");
|
|
75
83
|
runChoice(this.choice);
|
|
76
84
|
return this.isDone();
|
|
77
85
|
}
|
|
78
86
|
/**
|
|
79
87
|
* Wrapper function that prepares for a test and then completes it, adding time and turn details to the log.
|
|
80
|
-
* @param prepare A function that does all necessary preparations for this CS test, including choosing your outfit.
|
|
88
|
+
* @param prepare A function that does all necessary preparations for this CS test, including choosing your outfit. Optionally returns the number of turns you expect to spend preparing for the test.
|
|
81
89
|
* @param beCertain Whether we should check council.php instead of mafia to determine whether the test is complete.
|
|
82
|
-
* @
|
|
90
|
+
* @param maxTurns We will run the test iff the predicted turns is less than or equal to this parameter.
|
|
91
|
+
* @returns "completed", "failed", or "already completed".
|
|
83
92
|
*/
|
|
84
|
-
run(prepare, beCertain = false) {
|
|
93
|
+
run(prepare, beCertain = false, maxTurns = Infinity) {
|
|
85
94
|
const finishedFunction = () => beCertain ? this.verifyIsDone() : this.isDone();
|
|
86
95
|
if (finishedFunction())
|
|
87
|
-
return
|
|
96
|
+
return "already completed";
|
|
88
97
|
const startTime = Date.now();
|
|
89
98
|
const startTurns = myTurncount();
|
|
99
|
+
let additionalTurns;
|
|
90
100
|
try {
|
|
91
|
-
|
|
101
|
+
additionalTurns = prepare() ?? 0;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return "failed";
|
|
92
105
|
}
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
const prediction = this.predictor();
|
|
107
|
+
if (prediction <= maxTurns) {
|
|
95
108
|
this.do();
|
|
96
|
-
|
|
97
|
-
|
|
109
|
+
}
|
|
110
|
+
if (finishedFunction()) {
|
|
111
|
+
CommunityService.log[this.property] = {
|
|
112
|
+
predictedTurns: prediction + additionalTurns,
|
|
98
113
|
turnCost: myTurncount() - startTurns,
|
|
99
114
|
seconds: (Date.now() - startTime) / 1000,
|
|
100
115
|
};
|
|
101
|
-
|
|
102
|
-
log[this.property] = loggedTest;
|
|
103
|
-
}
|
|
116
|
+
return "completed";
|
|
104
117
|
}
|
|
118
|
+
return "failed";
|
|
105
119
|
}
|
|
106
120
|
/**
|
|
107
121
|
* Checks council.php to verify that a test is complete; more reliable than isDone, but requires an additional pagehit.
|
|
@@ -110,88 +124,88 @@ class Test {
|
|
|
110
124
|
verifyIsDone() {
|
|
111
125
|
return !visitUrl("council.php").includes(`<input type=hidden name=option value=${this.choice}>`);
|
|
112
126
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export const Mysticality = new Test(3, "Build Playground Mazes", statTestPredictor($stat `Mysticality`), new Requirement(["Mysticality"], {}));
|
|
130
|
-
export const Moxie = new Test(4, "Feed Conspirators", statTestPredictor($stat `Moxie`), new Requirement(["Moxie"], {}));
|
|
131
|
-
export const FamiliarWeight = new Test(5, "Breed More Collies", () => 60 - Math.floor((familiarWeight(myFamiliar()) + weightAdjustment()) / 5), new Requirement(["Familiar Weight"], {}));
|
|
132
|
-
export const WeaponDamage = new Test(6, "Reduce Gazelle Population", () => {
|
|
133
|
-
const weaponPower = getPower(equippedItem($slot `weapon`));
|
|
134
|
-
const offhandPower = toSlot(equippedItem($slot `off-hand`)) === $slot `weapon`
|
|
135
|
-
? getPower(equippedItem($slot `off-hand`))
|
|
136
|
-
: 0;
|
|
137
|
-
const familiarPower = toSlot(equippedItem($slot `familiar`)) === $slot `weapon`
|
|
138
|
-
? getPower(equippedItem($slot `familiar`))
|
|
139
|
-
: 0;
|
|
140
|
-
const songDamage = SongBoom.song() === "These Fists Were Made for Punchin'" ? myLevel() : 0;
|
|
141
|
-
// mafia does not currently count swagger
|
|
142
|
-
const multiplier = have($effect `Bow-Legged Swagger`) ? 2 : 1;
|
|
143
|
-
return (60 -
|
|
144
|
-
Math.floor((multiplier *
|
|
145
|
-
(getModifier("Weapon Damage") -
|
|
146
|
-
0.15 * (weaponPower + offhandPower + familiarPower) -
|
|
147
|
-
songDamage)) /
|
|
148
|
-
50 +
|
|
149
|
-
0.001) -
|
|
150
|
-
Math.floor((multiplier * getModifier("Weapon Damage Percent")) / 50 + 0.001));
|
|
151
|
-
}, new Requirement(["Weapon Damage", "Weapon Damage Percent"], {}));
|
|
152
|
-
export const SpellDamage = new Test(7, "Make Sausage", () => {
|
|
153
|
-
const dragonfishDamage = myFamiliar() === $familiar `Magic Dragonfish`
|
|
154
|
-
? numericModifier($familiar `Magic Dragonfish`, "Spell Damage Percent", familiarWeight($familiar `Magic Dragonfish`) + weightAdjustment(), $item `none`)
|
|
155
|
-
: 0;
|
|
156
|
-
return (60 -
|
|
157
|
-
Math.floor(getModifier("Spell Damage") / 50 + 0.001) -
|
|
158
|
-
Math.floor((getModifier("Spell Damage Percent") - dragonfishDamage) / 50 + 0.001));
|
|
159
|
-
}, new Requirement(["Spell Damage", "Spell Damage Percent"], {}));
|
|
160
|
-
export const Noncombat = new Test(8, "Be a Living Statue", () => {
|
|
161
|
-
const noncombatRate = -1 * getModifier("Combat Rate");
|
|
162
|
-
const unsoftcappedRate = noncombatRate > 25 ? 25 + (noncombatRate - 25) * 5 : noncombatRate;
|
|
163
|
-
return 60 - 3 * Math.floor(unsoftcappedRate / 5);
|
|
164
|
-
}, new Requirement(["-combat"], {}));
|
|
165
|
-
export const BoozeDrop = new Test(9, "Make Margaritas", () => {
|
|
166
|
-
const familiarItemDrop = numericModifier(myFamiliar(), "Item Drop", familiarWeight(myFamiliar()) + weightAdjustment(), equippedItem($slot `familiar`));
|
|
167
|
-
//Champagne doubling does NOT count for CS, so we undouble
|
|
168
|
-
const multiplier = haveEquipped($item `broken champagne bottle`) &&
|
|
169
|
-
get("garbageChampagneCharge") > 0
|
|
170
|
-
? 0.5
|
|
171
|
-
: 1;
|
|
172
|
-
return (60 -
|
|
173
|
-
multiplier *
|
|
174
|
-
Math.floor((getModifier("Item Drop") - familiarItemDrop) / 30 + 0.001) -
|
|
175
|
-
Math.floor(getModifier("Booze Drop") / 15 + 0.001));
|
|
176
|
-
}, new Requirement(["Item Drop", "2 Booze Drop"], {
|
|
177
|
-
preventEquip: $items `broken champagne bottle`,
|
|
178
|
-
}));
|
|
179
|
-
export const HotRes = new Test(10, "Clean Steam Tunnels", () => 60 - getModifier("Hot Resistance"), new Requirement(["Hot Resistance"], {}));
|
|
180
|
-
export const CoilWire = new Test(11, "Coil Wire", () => 60, null);
|
|
181
|
-
/**
|
|
182
|
-
* Prints turncount and time details of the test in question.
|
|
183
|
-
* @param colour The colour (or color) you'd like the log to be printed in.
|
|
184
|
-
*/
|
|
185
|
-
export function printLog(colour = "blue") {
|
|
186
|
-
const logEntries = Object.entries(log);
|
|
187
|
-
for (const [testName, testEntry] of logEntries) {
|
|
188
|
-
const { predictedTurns, turnCost, seconds } = testEntry;
|
|
189
|
-
print(`We predicted the ${testName} test would take ${predictedTurns} turns, ${predictedTurns === turnCost ? "and" : "but"} it took ${turnCost} turns`, colour);
|
|
190
|
-
print(`${testName} took ${seconds} seconds`, colour);
|
|
127
|
+
/**
|
|
128
|
+
* A log of the predicted turns, actual turns, and duration of each CS test performed.
|
|
129
|
+
*/
|
|
130
|
+
static log = {};
|
|
131
|
+
/**
|
|
132
|
+
* Prints turncount and time details of the test in question.
|
|
133
|
+
* @param colour The colour (or color) you'd like the log to be printed in.
|
|
134
|
+
*/
|
|
135
|
+
static printLog(colour = "blue") {
|
|
136
|
+
const logEntries = Object.entries(CommunityService.log);
|
|
137
|
+
for (const [testName, testEntry] of logEntries) {
|
|
138
|
+
const { predictedTurns, turnCost, seconds } = testEntry;
|
|
139
|
+
print(`We predicted the ${testName} test would take ${predictedTurns} turns, ${predictedTurns === turnCost ? "and" : "but"} it took ${turnCost} turns`, colour);
|
|
140
|
+
print(`${testName} took ${seconds} seconds`, colour);
|
|
141
|
+
}
|
|
142
|
+
print(`All together, you have spent ${sum(logEntries, ([, testEntry]) => testEntry.seconds)} seconds during this Community Service run`, colour);
|
|
191
143
|
}
|
|
192
|
-
|
|
144
|
+
// Below, we have the tests themselves.
|
|
145
|
+
static HP = new CommunityService(1, "Donate Blood", () => 60 - Math.floor((myMaxhp() - myBuffedstat($stat `muscle`) - 3) / 30), new Requirement(["HP"], {}));
|
|
146
|
+
static Muscle = new CommunityService(2, "Feed The Children", statCommunityServicePredictor($stat `Muscle`), new Requirement(["Muscle"], {}));
|
|
147
|
+
static Mysticality = new CommunityService(3, "Build Playground Mazes", statCommunityServicePredictor($stat `Mysticality`), new Requirement(["Mysticality"], {}));
|
|
148
|
+
static Moxie = new CommunityService(4, "Feed Conspirators", statCommunityServicePredictor($stat `Moxie`), new Requirement(["Moxie"], {}));
|
|
149
|
+
static FamiliarWeight = new CommunityService(5, "Breed More Collies", () => 60 - Math.floor((familiarWeight(myFamiliar()) + weightAdjustment()) / 5), new Requirement(["Familiar Weight"], {}));
|
|
150
|
+
static WeaponDamage = new CommunityService(6, "Reduce Gazelle Population", () => {
|
|
151
|
+
const weaponPower = getPower(equippedItem($slot `weapon`));
|
|
152
|
+
const offhandPower = toSlot(equippedItem($slot `off-hand`)) === $slot `weapon`
|
|
153
|
+
? getPower(equippedItem($slot `off-hand`))
|
|
154
|
+
: 0;
|
|
155
|
+
const familiarPower = toSlot(equippedItem($slot `familiar`)) === $slot `weapon`
|
|
156
|
+
? getPower(equippedItem($slot `familiar`))
|
|
157
|
+
: 0;
|
|
158
|
+
// mafia does not currently count swagger
|
|
159
|
+
const multiplier = have($effect `Bow-Legged Swagger`) ? 2 : 1;
|
|
160
|
+
// We add 0.001 because the floor function sometimes introduces weird rounding errors
|
|
161
|
+
return (60 -
|
|
162
|
+
Math.floor((multiplier *
|
|
163
|
+
(getModifier("Weapon Damage") -
|
|
164
|
+
0.15 * (weaponPower + offhandPower + familiarPower))) /
|
|
165
|
+
50 +
|
|
166
|
+
0.001) -
|
|
167
|
+
Math.floor((multiplier * getModifier("Weapon Damage Percent")) / 50 + 0.001));
|
|
168
|
+
}, new Requirement(["Weapon Damage", "Weapon Damage Percent"], {}));
|
|
169
|
+
static SpellDamage = new CommunityService(7, "Make Sausage", () => {
|
|
170
|
+
const dragonfishDamage = myFamiliar() === $familiar `Magic Dragonfish`
|
|
171
|
+
? numericModifier($familiar `Magic Dragonfish`, "Spell Damage Percent", familiarWeight($familiar `Magic Dragonfish`) + weightAdjustment(), $item `none`)
|
|
172
|
+
: 0;
|
|
173
|
+
// We add 0.001 because the floor function sometimes introduces weird rounding errors
|
|
174
|
+
return (60 -
|
|
175
|
+
Math.floor(getModifier("Spell Damage") / 50 + 0.001) -
|
|
176
|
+
Math.floor((getModifier("Spell Damage Percent") - dragonfishDamage) / 50 + 0.001));
|
|
177
|
+
}, new Requirement(["Spell Damage", "Spell Damage Percent"], {}));
|
|
178
|
+
static Noncombat = new CommunityService(8, "Be a Living Statue", () => {
|
|
179
|
+
const noncombatRate = -1 * getModifier("Combat Rate");
|
|
180
|
+
const unsoftcappedRate = noncombatRate > 25 ? 25 + (noncombatRate - 25) * 5 : noncombatRate;
|
|
181
|
+
return 60 - 3 * Math.floor(unsoftcappedRate / 5);
|
|
182
|
+
}, new Requirement(["-combat"], {}));
|
|
183
|
+
static BoozeDrop = new CommunityService(9, "Make Margaritas", () => {
|
|
184
|
+
const mummingCostume = MummingTrunk.currentCostumes().get(myFamiliar());
|
|
185
|
+
const mummingBuff = mummingCostume && mummingCostume[0] === "Item Drop"
|
|
186
|
+
? mummingCostume[1]
|
|
187
|
+
: 0;
|
|
188
|
+
const familiarItemDrop = numericModifier(myFamiliar(), "Item Drop", familiarWeight(myFamiliar()) + weightAdjustment(), equippedItem($slot `familiar`)) +
|
|
189
|
+
mummingBuff -
|
|
190
|
+
numericModifier(equippedItem($slot `familiar`), "Item Drop");
|
|
191
|
+
const familiarBoozeDrop = numericModifier(myFamiliar(), "Booze Drop", familiarWeight(myFamiliar()) + weightAdjustment(), equippedItem($slot `familiar`)) - numericModifier(equippedItem($slot `familiar`), "Booze Drop");
|
|
192
|
+
// Champagne doubling does NOT count for CS, so we undouble
|
|
193
|
+
const multiplier = haveEquipped($item `broken champagne bottle`) &&
|
|
194
|
+
get("garbageChampagneCharge") > 0
|
|
195
|
+
? 0.5
|
|
196
|
+
: 1;
|
|
197
|
+
// We add 0.001 because the floor function sometimes introduces weird rounding errors
|
|
198
|
+
return (60 -
|
|
199
|
+
Math.floor((multiplier * (getModifier("Item Drop") - familiarItemDrop)) / 30 +
|
|
200
|
+
0.001) -
|
|
201
|
+
Math.floor((getModifier("Booze Drop") - familiarBoozeDrop) / 15 + 0.001));
|
|
202
|
+
}, new Requirement(["Item Drop", "2 Booze Drop"], {
|
|
203
|
+
preventEquip: $items `broken champagne bottle`,
|
|
204
|
+
}));
|
|
205
|
+
static HotRes = new CommunityService(10, "Clean Steam Tunnels", () => 60 - getModifier("Hot Resistance"), new Requirement(["Hot Resistance"], {}));
|
|
206
|
+
static CoilWire = new CommunityService(11, "Coil Wire", () => 60, new Requirement([], {}));
|
|
207
|
+
static donate = () => {
|
|
208
|
+
visitUrl("council.php");
|
|
209
|
+
visitUrl("choice.php?whichchoice=1089&option=30");
|
|
210
|
+
};
|
|
193
211
|
}
|
|
194
|
-
export const donate = () => {
|
|
195
|
-
visitUrl("council.php");
|
|
196
|
-
runChoice(30);
|
|
197
|
-
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CommunityService from "./2015/CommunityService";
|
|
2
2
|
export { CommunityService };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CommunityService from "./2015/CommunityService";
|
|
2
2
|
export { CommunityService };
|