dankgrinder 5.3.0 → 5.10.0
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/lib/commands/dig.js +14 -6
- package/lib/commands/hunt.js +37 -30
- package/lib/commands/shop.js +11 -3
- package/lib/commands/utils.js +15 -3
- package/lib/grinder.js +2 -1
- package/package.json +1 -1
package/lib/commands/dig.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
7
|
LOG, c, getFullText, parseCoins, logMsg, isHoldTight, getHoldTightReason, sleep, needsItem,
|
|
8
|
+
isCV2, ensureCV2, stripAnsi,
|
|
8
9
|
} = require('./utils');
|
|
9
10
|
const { buyItem } = require('./shop');
|
|
10
11
|
|
|
@@ -33,13 +34,19 @@ async function runDig({ channel, waitForDankMemer, client }) {
|
|
|
33
34
|
return { result: `hold tight (${reason || 'unknown'})`, coins: 0, holdTightReason: reason };
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
if (isCV2(response)) await ensureCV2(response);
|
|
36
38
|
logMsg(response, 'dig');
|
|
37
39
|
const text = getFullText(response);
|
|
38
|
-
const
|
|
40
|
+
const cleanText = stripAnsi(text).replace(/\s+/g, ' ').trim();
|
|
41
|
+
const textLower = cleanText.toLowerCase();
|
|
42
|
+
const missing = needsItem(cleanText);
|
|
43
|
+
|
|
44
|
+
const shovelMissing = missing === 'shovel'
|
|
45
|
+
|| /(?:don['’]?t have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?shovel/.test(textLower)
|
|
46
|
+
|| (textLower.includes('following items') && textLower.includes('shovel'));
|
|
39
47
|
|
|
40
48
|
// Check if we need a shovel
|
|
41
|
-
if (
|
|
42
|
-
textLower.includes('need') && textLower.includes('shovel')) {
|
|
49
|
+
if (shovelMissing) {
|
|
43
50
|
LOG.warn('[dig] No shovel! Attempting to buy...');
|
|
44
51
|
|
|
45
52
|
const bought = await buyItem({
|
|
@@ -57,6 +64,7 @@ async function runDig({ channel, waitForDankMemer, client }) {
|
|
|
57
64
|
await channel.send('pls dig');
|
|
58
65
|
const r2 = await waitForDankMemer(10000);
|
|
59
66
|
if (r2) {
|
|
67
|
+
if (isCV2(r2)) await ensureCV2(r2);
|
|
60
68
|
logMsg(r2, 'dig-retry');
|
|
61
69
|
const t2 = getFullText(r2);
|
|
62
70
|
const coins = parseCoins(t2);
|
|
@@ -64,19 +72,19 @@ async function runDig({ channel, waitForDankMemer, client }) {
|
|
|
64
72
|
LOG.coin(`[dig] ${c.green}+⏣ ${coins.toLocaleString()}${c.reset}`);
|
|
65
73
|
return { result: `dig → +⏣ ${coins.toLocaleString()}`, coins };
|
|
66
74
|
}
|
|
67
|
-
return { result: t2.substring(0, 60), coins: 0 };
|
|
75
|
+
return { result: stripAnsi(t2).replace(/\s+/g, ' ').trim().substring(0, 60), coins: 0 };
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
return { result: 'need shovel (buy failed)', coins: 0 };
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
const coins = parseCoins(
|
|
81
|
+
const coins = parseCoins(cleanText);
|
|
74
82
|
if (coins > 0) {
|
|
75
83
|
LOG.coin(`[dig] ${c.green}+⏣ ${coins.toLocaleString()}${c.reset}`);
|
|
76
84
|
return { result: `dig → +⏣ ${coins.toLocaleString()}`, coins };
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
return { result:
|
|
87
|
+
return { result: cleanText.substring(0, 60) || 'done', coins: 0 };
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
module.exports = { runDig };
|
package/lib/commands/hunt.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
7
|
LOG, c, getFullText, parseCoins, logMsg, isHoldTight, getHoldTightReason, sleep, needsItem,
|
|
8
|
+
isCV2, ensureCV2, stripAnsi,
|
|
8
9
|
} = require('./utils');
|
|
9
10
|
const { buyItem } = require('./shop');
|
|
10
11
|
|
|
@@ -33,53 +34,59 @@ async function runHunt({ channel, waitForDankMemer, client }) {
|
|
|
33
34
|
return { result: `hold tight (${reason || 'unknown'})`, coins: 0, needsRifle: false, holdTightReason: reason };
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
if (isCV2(response)) await ensureCV2(response);
|
|
36
38
|
logMsg(response, 'hunt');
|
|
37
39
|
const text = getFullText(response);
|
|
38
|
-
const
|
|
40
|
+
const cleanText = stripAnsi(text).replace(/\s+/g, ' ').trim();
|
|
41
|
+
const textLower = cleanText.toLowerCase();
|
|
42
|
+
const missing = needsItem(cleanText);
|
|
43
|
+
|
|
44
|
+
const rifleMissing = missing === 'hunting rifle'
|
|
45
|
+
|| /(?:don['’]?t have|do not have|need|needs|requires?|missing|must have|you need|lack)\s+(?:a\s+)?(?:hunting\s+)?rifle/.test(textLower)
|
|
46
|
+
|| ((textLower.includes('following items') || textLower.includes('missing items')) && textLower.includes('rifle'));
|
|
39
47
|
|
|
40
48
|
// Check if we need a rifle
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
LOG.warn('[hunt] No rifle! Attempting to buy...');
|
|
49
|
+
if (rifleMissing) {
|
|
50
|
+
LOG.warn('[hunt] No rifle! Attempting to buy...');
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
const bought = await buyItem({
|
|
53
|
+
channel, waitForDankMemer, client,
|
|
54
|
+
itemName: 'Hunting Rifle',
|
|
55
|
+
quantity: 1,
|
|
56
|
+
});
|
|
50
57
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
if (bought) {
|
|
59
|
+
LOG.success('[hunt] Rifle purchased! Re-running hunt...');
|
|
60
|
+
// Drain stale shop messages
|
|
61
|
+
while (await waitForDankMemer(1500)) { /* drain */ }
|
|
62
|
+
await sleep(1000);
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
return { result: t2.substring(0, 60), coins: 0, needsRifle: false };
|
|
64
|
+
await channel.send('pls hunt');
|
|
65
|
+
const r2 = await waitForDankMemer(10000);
|
|
66
|
+
if (r2) {
|
|
67
|
+
if (isCV2(r2)) await ensureCV2(r2);
|
|
68
|
+
logMsg(r2, 'hunt-retry');
|
|
69
|
+
const t2 = getFullText(r2);
|
|
70
|
+
const c2 = parseCoins(t2);
|
|
71
|
+
if (c2 > 0) {
|
|
72
|
+
LOG.coin(`[hunt] ${c.green}+⏣ ${c2.toLocaleString()}${c.reset}`);
|
|
73
|
+
return { result: `hunt → +⏣ ${c2.toLocaleString()}`, coins: c2, needsRifle: false };
|
|
68
74
|
}
|
|
69
|
-
return { result: '
|
|
75
|
+
return { result: stripAnsi(t2).replace(/\s+/g, ' ').trim().substring(0, 60), coins: 0, needsRifle: false };
|
|
70
76
|
}
|
|
71
|
-
|
|
72
|
-
return { result: 'need rifle (buy failed)', coins: 0, needsRifle: true };
|
|
77
|
+
return { result: 'no response after rifle buy', coins: 0, needsRifle: false };
|
|
73
78
|
}
|
|
79
|
+
|
|
80
|
+
return { result: 'need rifle (buy failed)', coins: 0, needsRifle: true };
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
const coins = parseCoins(
|
|
83
|
+
const coins = parseCoins(cleanText);
|
|
77
84
|
if (coins > 0) {
|
|
78
85
|
LOG.coin(`[hunt] ${c.green}+⏣ ${coins.toLocaleString()}${c.reset}`);
|
|
79
86
|
return { result: `hunt → +⏣ ${coins.toLocaleString()}`, coins, needsRifle: false };
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
return { result:
|
|
89
|
+
return { result: cleanText.substring(0, 60) || 'done', coins: 0, needsRifle: false };
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
module.exports = { runHunt };
|
package/lib/commands/shop.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
const {
|
|
17
17
|
LOG, c, sleep, humanDelay, getFullText,
|
|
18
18
|
getAllButtons, findSelectMenuOption,
|
|
19
|
-
logMsg, isHoldTight,
|
|
19
|
+
logMsg, isHoldTight, isCV2, ensureCV2,
|
|
20
20
|
} = require('./utils');
|
|
21
21
|
const { LRUCache, Trie } = require('../structures');
|
|
22
22
|
|
|
@@ -100,6 +100,8 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
|
|
|
100
100
|
return false;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
if (isCV2(response)) await ensureCV2(response);
|
|
104
|
+
|
|
103
105
|
logMsg(response, 'shop');
|
|
104
106
|
|
|
105
107
|
// Step 2: Switch shop tab if needed (e.g. Fishing Shop for fishing pole)
|
|
@@ -129,6 +131,7 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
|
|
|
129
131
|
);
|
|
130
132
|
if (result) {
|
|
131
133
|
response = result;
|
|
134
|
+
if (isCV2(response)) await ensureCV2(response);
|
|
132
135
|
LOG.success(`Switched to ${targetTab}`);
|
|
133
136
|
}
|
|
134
137
|
await sleep(300);
|
|
@@ -141,9 +144,14 @@ async function buyItem({ channel, waitForDankMemer, itemName, quantity = 1, clie
|
|
|
141
144
|
|
|
142
145
|
// Step 3: Find the Buy button for our item
|
|
143
146
|
const allBtns = getAllButtons(response);
|
|
147
|
+
const normalizedSearch = String(searchTerm || '').toLowerCase().replace(/\s+/g, '');
|
|
148
|
+
const normalizedKey = String(key || '').toLowerCase().replace(/\s+/g, '');
|
|
144
149
|
const buyBtn = allBtns.find(b => {
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
const label = String(b.label || '').toLowerCase();
|
|
151
|
+
const id = String(b.customId || b.custom_id || '').toLowerCase().replace(/\s+/g, '');
|
|
152
|
+
return label.includes(searchTerm)
|
|
153
|
+
|| (normalizedSearch && id.includes(normalizedSearch))
|
|
154
|
+
|| (normalizedKey && id.includes(normalizedKey));
|
|
147
155
|
});
|
|
148
156
|
|
|
149
157
|
if (!buyBtn) {
|
package/lib/commands/utils.js
CHANGED
|
@@ -512,7 +512,7 @@ async function clickCV2Button(msg, customId) {
|
|
|
512
512
|
// This is the same algorithm used by `fgrep` for multi-pattern search.
|
|
513
513
|
const itemDetector = new AhoCorasick();
|
|
514
514
|
const ITEM_PATTERN_MAP = [
|
|
515
|
-
{ item: 'shovel', patterns: ["don't have a shovel", 'need a shovel', 'you need a shovel'] },
|
|
515
|
+
{ item: 'shovel', patterns: ["don't have a shovel", "don't own a shovel", 'need a shovel', 'you need a shovel', 'requires a shovel', 'missing shovel'] },
|
|
516
516
|
{ item: 'fishing pole', patterns: ["don't have a fishing", 'need a fishing', 'you need a fishing pole'] },
|
|
517
517
|
{ item: 'hunting rifle', patterns: ["don't have a hunting rifle", 'need a hunting rifle', 'you need a rifle'] },
|
|
518
518
|
{ item: 'adventure ticket', patterns: ["don't have a ticket", "don't have an adventure", 'need a ticket', 'need an adventure ticket'] },
|
|
@@ -523,14 +523,26 @@ for (const { item, patterns } of ITEM_PATTERN_MAP) {
|
|
|
523
523
|
for (const p of patterns) itemDetector.addPattern(p, item);
|
|
524
524
|
}
|
|
525
525
|
itemDetector.addPattern('need following items', '__multi__');
|
|
526
|
+
itemDetector.addPattern('need the following items', '__multi__');
|
|
527
|
+
itemDetector.addPattern('you need the following items', '__multi__');
|
|
526
528
|
itemDetector.addPattern('missing items', '__multi__');
|
|
527
529
|
itemDetector.build();
|
|
528
530
|
|
|
529
531
|
function needsItem(text) {
|
|
530
|
-
const
|
|
532
|
+
const normalized = String(text || '')
|
|
533
|
+
.toLowerCase()
|
|
534
|
+
.normalize('NFKC')
|
|
535
|
+
.replace(/[’‘`´]/g, "'")
|
|
536
|
+
.replace(/\bdon'?t\b/g, "don't");
|
|
537
|
+
|
|
538
|
+
const match = itemDetector.hasAny(normalized);
|
|
531
539
|
if (!match) return null;
|
|
532
540
|
if (match === '__multi__') {
|
|
533
|
-
const lower =
|
|
541
|
+
const lower = normalized;
|
|
542
|
+
if (lower.includes('shovel')) return 'shovel';
|
|
543
|
+
if (lower.includes('fishing pole') || lower.includes('fishing')) return 'fishing pole';
|
|
544
|
+
if (lower.includes('hunting rifle') || lower.includes('rifle')) return 'hunting rifle';
|
|
545
|
+
if (lower.includes('adventure ticket') || lower.includes('ticket')) return 'adventure ticket';
|
|
534
546
|
if (lower.includes('keyboard')) return 'keyboard';
|
|
535
547
|
if (lower.includes('mouse')) return 'mouse';
|
|
536
548
|
return null;
|
package/lib/grinder.js
CHANGED
|
@@ -2199,11 +2199,12 @@ class AccountWorker {
|
|
|
2199
2199
|
return new Promise((resolve) => {
|
|
2200
2200
|
this.client.on('ready', async () => {
|
|
2201
2201
|
this.username = this.client.user.tag || this.username;
|
|
2202
|
+
this.avatarUrl = this.client.user.displayAvatarURL?.({ format: 'png', dynamic: true, size: 128 }) || null;
|
|
2202
2203
|
try {
|
|
2203
2204
|
await fetch(`${API_URL}/api/grinder/status`, {
|
|
2204
2205
|
method: 'POST',
|
|
2205
2206
|
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
|
2206
|
-
body: JSON.stringify({ account_id: this.account.id, discord_username: this.username }),
|
|
2207
|
+
body: JSON.stringify({ account_id: this.account.id, discord_username: this.username, avatar_url: this.avatarUrl }),
|
|
2207
2208
|
});
|
|
2208
2209
|
} catch { /* silent */ }
|
|
2209
2210
|
|