dankgrinder 8.103.0 → 8.107.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/grinder.js +64 -13
- package/package.json +1 -1
package/lib/grinder.js
CHANGED
|
@@ -670,6 +670,7 @@ class AccountWorker {
|
|
|
670
670
|
this._levelQuestActive = false;
|
|
671
671
|
this._levelQuestQueue = [];
|
|
672
672
|
this._levelQuestDone = new Set();
|
|
673
|
+
this._levelQuestProgressCache = new Map();
|
|
673
674
|
this._questBetOverride = null;
|
|
674
675
|
this._lastCommandMeta = null;
|
|
675
676
|
this._commandRunning = false; // prevents grinding commands from overlapping with quest commands
|
|
@@ -1558,6 +1559,11 @@ class AccountWorker {
|
|
|
1558
1559
|
if (lvMatch) {
|
|
1559
1560
|
const targetLv = parseInt(lvMatch[1]);
|
|
1560
1561
|
cmdResult.levelLocked = targetLv;
|
|
1562
|
+
const progress = this._parseLevelQuestProgress(targetLv, allDetectionText);
|
|
1563
|
+
if (progress) {
|
|
1564
|
+
cmdResult.levelQuestProgress = progress;
|
|
1565
|
+
this._mergeLevelQuestProgress(targetLv, progress);
|
|
1566
|
+
}
|
|
1561
1567
|
this.log('warn', `Command /${cmdName} requires Level ${targetLv} quests`);
|
|
1562
1568
|
}
|
|
1563
1569
|
}
|
|
@@ -1746,10 +1752,10 @@ class AccountWorker {
|
|
|
1746
1752
|
this._lastCommandMeta.nonPlay = true;
|
|
1747
1753
|
this._lastCommandMeta.levelLocked = targetLv;
|
|
1748
1754
|
this.log('warn', `Command /${cmdName} is LOCKED at Level ${targetLv} — starting quest unlock flow`);
|
|
1749
|
-
if (this._startLevelQuests(targetLv)) {
|
|
1755
|
+
if (this._startLevelQuests(targetLv, cmdResult.levelQuestProgress || null)) {
|
|
1750
1756
|
this.log('info', `[QUEST] Quest mode activated for Level ${targetLv} — grinding will resume after quests complete`);
|
|
1751
1757
|
} else {
|
|
1752
|
-
this.log('warn', `[QUEST] Level ${targetLv} quests already done or not defined —
|
|
1758
|
+
this.log('warn', `[QUEST] Level ${targetLv} quests already done or not defined — waiting for verification`);
|
|
1753
1759
|
}
|
|
1754
1760
|
// Don't count as success — skip normal post-command processing
|
|
1755
1761
|
return;
|
|
@@ -1924,11 +1930,56 @@ class AccountWorker {
|
|
|
1924
1930
|
],
|
|
1925
1931
|
};
|
|
1926
1932
|
|
|
1927
|
-
|
|
1933
|
+
_parseLevelQuestProgress(targetLevel, rawText) {
|
|
1934
|
+
if (targetLevel !== 5) return null;
|
|
1935
|
+
const text = String(rawText || '');
|
|
1936
|
+
const out = {};
|
|
1937
|
+
const re = /(\d[\d,]*)\s*\/\s*50,000[\s\S]{0,180}?<\/(slots|cointoss|snakeeyes):/gi;
|
|
1938
|
+
let m;
|
|
1939
|
+
while ((m = re.exec(text)) !== null) {
|
|
1940
|
+
const cur = parseInt(String(m[1] || '').replace(/,/g, ''), 10);
|
|
1941
|
+
const cmd = String(m[2] || '').toLowerCase();
|
|
1942
|
+
if (Number.isFinite(cur) && cmd) out[cmd] = Math.max(0, cur);
|
|
1943
|
+
}
|
|
1944
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
_mergeLevelQuestProgress(targetLevel, progressHint) {
|
|
1948
|
+
if (!progressHint || targetLevel !== 5) return;
|
|
1949
|
+
const prev = this._levelQuestProgressCache.get(targetLevel) || {};
|
|
1950
|
+
const merged = { ...prev };
|
|
1951
|
+
for (const [cmd, val] of Object.entries(progressHint)) {
|
|
1952
|
+
const n = Number(val);
|
|
1953
|
+
if (!Number.isFinite(n) || n < 0) continue;
|
|
1954
|
+
merged[cmd] = Math.max(merged[cmd] || 0, n);
|
|
1955
|
+
}
|
|
1956
|
+
this._levelQuestProgressCache.set(targetLevel, merged);
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
_startLevelQuests(targetLevel, progressHint = null) {
|
|
1928
1960
|
if (this._levelQuestDone.has(targetLevel)) return false;
|
|
1929
1961
|
const quests = AccountWorker.LEVEL_QUESTS[targetLevel];
|
|
1930
1962
|
if (!quests || quests.length === 0) return false;
|
|
1931
|
-
|
|
1963
|
+
|
|
1964
|
+
this._mergeLevelQuestProgress(targetLevel, progressHint);
|
|
1965
|
+
const cached = this._levelQuestProgressCache.get(targetLevel) || {};
|
|
1966
|
+
const seededQueue = quests
|
|
1967
|
+
.map(q => {
|
|
1968
|
+
const target = Number(q.loseTarget || 0);
|
|
1969
|
+
const seeded = target > 0 ? Math.min(target, Math.max(0, Number(cached[q.cmd] || 0))) : 0;
|
|
1970
|
+
return { ...q, level: targetLevel, _lostSoFar: seeded };
|
|
1971
|
+
})
|
|
1972
|
+
.filter(q => !(q.loseTarget && q._lostSoFar >= q.loseTarget));
|
|
1973
|
+
|
|
1974
|
+
if (seededQueue.length === 0) {
|
|
1975
|
+
this.log('info', `[QUEST] Level ${targetLevel} tasks already complete from progress cache — verifying unlock`);
|
|
1976
|
+
this._verifyLevelUnlock = targetLevel;
|
|
1977
|
+
this.setStatus('verifying level...');
|
|
1978
|
+
this.commandQueue = null;
|
|
1979
|
+
return false;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
this._levelQuestQueue = seededQueue;
|
|
1932
1983
|
this._levelQuestActive = true;
|
|
1933
1984
|
this._questBetOverride = null;
|
|
1934
1985
|
// Clear commandQueue so no stale grinding commands fire after quests finish
|
|
@@ -1936,7 +1987,10 @@ class AccountWorker {
|
|
|
1936
1987
|
this._commandRunning = false; // cancel any in-flight grinding command
|
|
1937
1988
|
this.log('info', `[QUEST] Level ${targetLevel} quests started — grinding PAUSED`);
|
|
1938
1989
|
const questList = this._levelQuestQueue.map(q => {
|
|
1939
|
-
if (q.loseTarget)
|
|
1990
|
+
if (q.loseTarget) {
|
|
1991
|
+
const rem = Math.max(0, q.loseTarget - (q._lostSoFar || 0));
|
|
1992
|
+
return `"${q.cmd}" lose ⏣${rem.toLocaleString()} more`;
|
|
1993
|
+
}
|
|
1940
1994
|
return `"${q.cmd}" x${q.times}`;
|
|
1941
1995
|
}).join(', ');
|
|
1942
1996
|
this.log('info', `[QUEST] Quests: ${questList}`);
|
|
@@ -2204,11 +2258,13 @@ class AccountWorker {
|
|
|
2204
2258
|
if (currentLv >= targetLv) {
|
|
2205
2259
|
this.log('success', `[QUEST] Level ${targetLv} verified ✓ — level unlocked!`);
|
|
2206
2260
|
this._level = currentLv;
|
|
2261
|
+
this._levelQuestProgressCache.delete(targetLv);
|
|
2207
2262
|
} else {
|
|
2208
2263
|
this.log('warn', `[QUEST] Level ${targetLv} NOT verified — still at ${currentLv}. Re-triggering quests.`);
|
|
2209
2264
|
// Re-trigger quests for this level
|
|
2210
2265
|
this._levelQuestDone.delete(targetLv);
|
|
2211
|
-
this.
|
|
2266
|
+
const cached = this._levelQuestProgressCache.get(targetLv) || null;
|
|
2267
|
+
this._startLevelQuests(targetLv, cached);
|
|
2212
2268
|
this.tickTimeout = setTimeout(() => this.tick(), 2000);
|
|
2213
2269
|
return;
|
|
2214
2270
|
}
|
|
@@ -2231,7 +2287,6 @@ class AccountWorker {
|
|
|
2231
2287
|
} else {
|
|
2232
2288
|
this._questBetOverride = quest.bet || null;
|
|
2233
2289
|
}
|
|
2234
|
-
const questBetUsed = this._questBetOverride;
|
|
2235
2290
|
const prefix = this.account.use_slash ? '/' : 'pls';
|
|
2236
2291
|
|
|
2237
2292
|
if (quest.loseTarget) {
|
|
@@ -2250,7 +2305,7 @@ class AccountWorker {
|
|
|
2250
2305
|
this._commandRunning = true;
|
|
2251
2306
|
this.busy = true;
|
|
2252
2307
|
await this.runCommand(quest.cmd, prefix);
|
|
2253
|
-
|
|
2308
|
+
const questMeta = this._lastCommandMeta || {};
|
|
2254
2309
|
this._commandRunning = false;
|
|
2255
2310
|
this.busy = false;
|
|
2256
2311
|
this._questBetOverride = null;
|
|
@@ -2270,13 +2325,9 @@ class AccountWorker {
|
|
|
2270
2325
|
quest._minBet = Math.max(quest._minBet || 1, questMeta.newMinBet);
|
|
2271
2326
|
}
|
|
2272
2327
|
|
|
2273
|
-
// Fallback only for actual played rounds where parsed/observed loss was zero.
|
|
2274
|
-
if (!nonPlay && lostThisRound === 0 && (questBetUsed || quest.bet)) {
|
|
2275
|
-
lostThisRound = questBetUsed || quest.bet;
|
|
2276
|
-
}
|
|
2277
|
-
|
|
2278
2328
|
if (!nonPlay) {
|
|
2279
2329
|
quest._lostSoFar = (quest._lostSoFar || 0) + lostThisRound;
|
|
2330
|
+
this._mergeLevelQuestProgress(quest.level, { [quest.cmd]: quest._lostSoFar });
|
|
2280
2331
|
}
|
|
2281
2332
|
|
|
2282
2333
|
this.log('info', `[QUEST] ${quest.cmd} — lost ⏣${quest._lostSoFar.toLocaleString()} / ⏣${quest.loseTarget.toLocaleString()}`);
|