dankgrinder 4.9.2 → 4.9.3

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.
@@ -349,10 +349,15 @@ async function runAdventure({ channel, waitForDankMemer, client }) {
349
349
 
350
350
  const menu = response.components[menuRowIdx]?.components[0];
351
351
  const options = menu?.options || [];
352
- if (options.length > 0 && menuRowIdx >= 0) {
353
- lastAdventureIndex = (lastAdventureIndex + 1) % options.length;
354
- const opt = options[lastAdventureIndex];
355
- LOG.info(`[adventure] Selecting [${lastAdventureIndex + 1}/${options.length}]: "${opt.label}"`);
352
+ const PREFERRED = ['space', 'out west'];
353
+ const preferred = options.filter(o =>
354
+ PREFERRED.some(kw => (o.label || '').toLowerCase().includes(kw) || (o.value || '').toLowerCase().includes(kw))
355
+ );
356
+ const pool = preferred.length > 0 ? preferred : options;
357
+
358
+ if (pool.length > 0 && menuRowIdx >= 0) {
359
+ const opt = pool[Math.floor(Math.random() * pool.length)];
360
+ LOG.info(`[adventure] Selecting: "${opt.label}" (from ${pool.length} options)`);
356
361
  try {
357
362
  const selectResult = await response.selectMenu(menuRowIdx, [opt.value]);
358
363
  if (selectResult) {
@@ -6,6 +6,7 @@
6
6
  const {
7
7
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
8
8
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
9
+ isCV2, ensureCV2,
9
10
  } = require('./utils');
10
11
 
11
12
  const SAFE_CRIME_OPTIONS = [
@@ -71,8 +72,9 @@ async function runCrime({ channel, waitForDankMemer, safeAnswers }) {
71
72
  return { result: `hold tight (${reason || 'unknown'})`, coins: 0, holdTightReason: reason };
72
73
  }
73
74
 
75
+ if (isCV2(response)) await ensureCV2(response);
74
76
  logMsg(response, 'crime');
75
- const buttons = getAllButtons(response);
77
+ let buttons = getAllButtons(response);
76
78
 
77
79
  if (buttons.length === 0) {
78
80
  const text = getFullText(response);
@@ -80,10 +82,15 @@ async function runCrime({ channel, waitForDankMemer, safeAnswers }) {
80
82
  return { result: text.substring(0, 60), coins: 0 };
81
83
  }
82
84
 
83
- const btn = pickSafeButton(buttons, safeAnswers);
85
+ let btn = pickSafeButton(buttons, safeAnswers);
84
86
  if (!btn) {
85
- LOG.warn('[crime] No safe button found');
86
- return { result: 'no safe option', coins: 0 };
87
+ const clickable = buttons.filter(b => !b.disabled);
88
+ btn = clickable.length > 0 ? clickable[Math.floor(Math.random() * clickable.length)] : null;
89
+ if (!btn) {
90
+ LOG.warn('[crime] No clickable button found');
91
+ return { result: 'no clickable option', coins: 0 };
92
+ }
93
+ LOG.info(`[crime] No safe match — picking random: "${btn.label}"`);
87
94
  }
88
95
 
89
96
  LOG.info(`[crime] Picking: "${btn.label}"`);
@@ -6,6 +6,7 @@
6
6
  const {
7
7
  LOG, c, getFullText, parseCoins, getAllButtons, safeClickButton,
8
8
  logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay,
9
+ isCV2, ensureCV2,
9
10
  } = require('./utils');
10
11
 
11
12
  const SAFE_SEARCH_LOCATIONS = [
@@ -74,8 +75,9 @@ async function runSearch({ channel, waitForDankMemer, safeAnswers }) {
74
75
  return { result: `hold tight (${reason || 'unknown'})`, coins: 0, holdTightReason: reason };
75
76
  }
76
77
 
78
+ if (isCV2(response)) await ensureCV2(response);
77
79
  logMsg(response, 'search');
78
- const buttons = getAllButtons(response);
80
+ let buttons = getAllButtons(response);
79
81
 
80
82
  if (buttons.length === 0) {
81
83
  const text = getFullText(response);
@@ -83,10 +85,15 @@ async function runSearch({ channel, waitForDankMemer, safeAnswers }) {
83
85
  return { result: text.substring(0, 60), coins: 0 };
84
86
  }
85
87
 
86
- const btn = pickSafeButton(buttons, safeAnswers);
88
+ let btn = pickSafeButton(buttons, safeAnswers);
87
89
  if (!btn) {
88
- LOG.warn('[search] No safe button found');
89
- return { result: 'no safe option', coins: 0 };
90
+ const clickable = buttons.filter(b => !b.disabled);
91
+ btn = clickable.length > 0 ? clickable[Math.floor(Math.random() * clickable.length)] : null;
92
+ if (!btn) {
93
+ LOG.warn('[search] No clickable button found');
94
+ return { result: 'no clickable option', coins: 0 };
95
+ }
96
+ LOG.info(`[search] No safe match — picking random: "${btn.label}"`);
90
97
  }
91
98
 
92
99
  LOG.info(`[search] Picking: "${btn.label}"`);
package/lib/grinder.js CHANGED
@@ -835,6 +835,7 @@ class AccountWorker {
835
835
 
836
836
  let wallet = 0;
837
837
  let bank = 0;
838
+ let matched = '';
838
839
 
839
840
  // CV2 format: <:Coin:ID> 3,272,896 and <:Bank:ID> 275,000 / 275,000
840
841
  const coinMatch = text.match(/<[a:]?:Coin:\d+>\s*([\d,]+)/i);
@@ -844,15 +845,18 @@ class AccountWorker {
844
845
  const walletMatch = text.match(/wallet[:\s]*\*{0,2}\s*[⏣💰]?\s*\*{0,2}\s*([\d,]+)/i);
845
846
  const bankTextMatch = text.match(/bank[:\s]*\*{0,2}\s*[⏣💰]?\s*\*{0,2}\s*([\d,]+)/i);
846
847
 
847
- // Fallback: justfollowed by number (pick largest)
848
- const coinSymMatch = text.match(/[⏣]\s*([\d,]+)/);
848
+ // Fallback: any numbers near or just plain numbers in CV2 text
849
+ const allNums = [...text.matchAll(/(?:⏣\s*)?(\d[\d,]*\d)/g)].map(m => parseInt(m[1].replace(/,/g, ''), 10)).filter(n => n > 0);
849
850
 
850
851
  if (coinMatch) {
851
852
  wallet = parseInt(coinMatch[1].replace(/,/g, ''), 10);
853
+ matched = 'cv2-emoji';
852
854
  } else if (walletMatch) {
853
855
  wallet = parseInt(walletMatch[1].replace(/,/g, ''), 10);
854
- } else if (coinSymMatch) {
855
- wallet = parseInt(coinSymMatch[1].replace(/,/g, ''), 10);
856
+ matched = 'legacy-wallet';
857
+ } else if (allNums.length > 0) {
858
+ wallet = Math.max(...allNums);
859
+ matched = 'fallback-nums';
856
860
  }
857
861
 
858
862
  if (bankEmojiMatch) {
@@ -861,9 +865,15 @@ class AccountWorker {
861
865
  bank = parseInt(bankTextMatch[1].replace(/,/g, ''), 10);
862
866
  }
863
867
 
868
+ if (wallet === 0 && bank === 0) {
869
+ this.log('warn', `Balance parse returned 0 — raw text: "${text.substring(0, 200)}"`);
870
+ // Don't overwrite a known-good balance with 0
871
+ if (this.stats.balance > 0 || this.stats.bankBalance > 0) return;
872
+ }
873
+
864
874
  this.stats.balance = wallet;
865
875
  this.stats.bankBalance = bank;
866
- this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset}`);
876
+ this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset} ${c.dim}(${matched || 'none'})${c.reset}`);
867
877
 
868
878
  // Store in Redis for persistence
869
879
  if (redis) {
@@ -901,7 +911,7 @@ class AccountWorker {
901
911
  case 'with max': cmdString = `${prefix} with max`; break;
902
912
  case 'blackjack': cmdString = `${prefix} bj ${bjBet}`; break;
903
913
  case 'cointoss': cmdString = `${prefix} cointoss ${gambBet}`; break;
904
- case 'roulette': cmdString = `${prefix} roulette ${gambBet} red`; break;
914
+ case 'roulette': cmdString = `${prefix} roulette ${gambBet} ${Math.random() < 0.5 ? 'red' : 'black'}`; break;
905
915
  case 'slots': cmdString = `${prefix} slots ${gambBet}`; break;
906
916
  case 'snakeeyes': cmdString = `${prefix} snakeeyes ${gambBet}`; break;
907
917
  case 'work shift': cmdString = `${prefix} work shift`; break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "4.9.2",
3
+ "version": "4.9.3",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"