Copy // MasterScript - Mafia
// ==UserScript==
// @name Mafia – Master Helper (rank-aware capacity, 2025-09-21)
// @namespace https://tampermonkey.net/
// @version 3.6
// @description Automates bust-out, market buy/sell, travel, crimes-first loop, car theft & kill-skill — now with rank-aware capacity detection (“Max X units/kg”) on both Booze and Narcotics pages.
// @author Godfather
// @match https://bnbmafia.io/*
// @grant none
// ==/UserScript==
/*──────────────────────── GLOBAL CONFIG & MENUS ───────────────────────*/
(function () {
'use strict';
const LS_KEY = 'bnbmafia_script_cfg';
/* item groups */
const BOOZE = ['Whiskey', 'Tequila', 'Cognac'];
const NARCO = ['Cocaine', 'Morphine', 'Opium', 'Heroin'];
/* preset function → returns {buyLimit,sellFloor} */
function preset(mode) {
const buyLimit = {};
const sellFloor = {};
if (mode === 'xp') { // “Get XP” preset
BOOZE.forEach(i => { buyLimit[i] = 4_000; sellFloor[i] = 4_000; });
NARCO.forEach(i => { buyLimit[i] = 10_000; sellFloor[i] = 10_000; });
} else { // “Make Money” preset
buyLimit['Cognac'] = 3_000; sellFloor['Cognac'] = 4_500;
buyLimit['Tequila'] = 3_500; sellFloor['Tequila'] = 5_000;
buyLimit['Whiskey'] = 2_800; sellFloor['Whiskey'] = 3_500;
buyLimit['Cocaine'] = 8_000; sellFloor['Cocaine'] = 10_000;
buyLimit['Opium'] = 7_000; sellFloor['Opium'] = 11_000;
buyLimit['Heroin'] = 8_000; sellFloor['Heroin'] = 11_000;
buyLimit['Morphine'] = 9_000; sellFloor['Morphine'] = 12_000;
}
return { buyLimit, sellFloor };
}
/* default cfg */
const defaultCfg = {
/* slot selections */
carIndex : 1,
crimeIndex : 1,
killIndex : 1,
/* timings */
redirectMinutes : 4,
clickDelaySec : 45,
/* misc */
travelVehicle : 'Airplane',
mode : 'money', // "money" | "xp"
enabledActivities: {
jail : true,
killskill : true,
travel : true,
market : true,
crimes : true,
nickcar : true
},
...preset('money')
};
/* restore stored cfg */
const stored = JSON.parse(localStorage.getItem(LS_KEY) || '{}');
const cfg = Object.assign({}, defaultCfg, stored);
cfg.enabledActivities = Object.assign({}, defaultCfg.enabledActivities, stored.enabledActivities);
/* ensure buy/sell reflect current mode */
const modeLimits = preset(cfg.mode);
cfg.buyLimit = modeLimits.buyLimit;
cfg.sellFloor = modeLimits.sellFloor;
/* expose */
window.BNBMAFIA_AUTOSCRIPT_CFG = cfg;
const saveCfg = () => localStorage.setItem(LS_KEY, JSON.stringify(cfg));
let reloadTimer = null;
const triggerReload = () => { if (!reloadTimer) reloadTimer = setTimeout(() => location.reload(), 300); };
/*────────── MAIN floating menu ──────────*/
function createMainMenu() {
const m = document.createElement('div');
Object.assign(m.style, {
position:'fixed', top:'5cm', right:'10px', zIndex:9999,
background:'rgba(0,0,0,0.88)', color:'#fff', padding:'10px',
borderRadius:'8px', fontFamily:'sans-serif', fontSize:'13px', lineHeight:'1.3em'
});
m.innerHTML = `
<label style="display:block;margin-bottom:4px;">
Redirect every:
<select id="redirSel">
<option value="1">1 min</option><option value="2">2 min</option><option value="3">3 min</option><option value="4">4 min</option><option value="5">5 min</option>
</select>
</label>
<label style="display:block;margin-bottom:4px;">
Click delay:
<select id="clickSel">
<option value="15">15 s</option><option value="30">30 s</option><option value="45">45 s</option><option value="60">60 s</option>
</select>
</label>
<label style="display:block;margin-bottom:4px;">
Travel vehicle:
<select id="travelSel">
<option>Airplane</option><option>Train</option><option>Car/Motorcycle</option>
</select>
</label>
<label style="display:block;margin-bottom:4px;">
Car-theft slot
<select id="carSel"><option>1</option><option>2</option><option>3</option><option>4</option></select>
</label>
<label style="display:block;margin-bottom:4px;">
Crime slot
<select id="crimeSel"><option>1</option><option>2</option><option>3</option><option>4</option></select>
</label>
<label style="display:block;margin-bottom:4px;">
Kill-skill slot
<select id="killSel"><option>1</option><option>2</option><option>3</option></select>
</label>
<hr style="margin:6px 0;border:0;border-top:1px solid #555;">
<label><input type="checkbox" id="actJail"> Bust-out</label><br>
<label><input type="checkbox" id="actKill"> Kill-skill</label><br>
<label><input type="checkbox" id="actTravel"> Travel</label><br>
<label><input type="checkbox" id="actMarket"> Market</label><br>
<label><input type="checkbox" id="actCrimes"> Crimes</label><br>
<label><input type="checkbox" id="actNick"> Car theft</label>
<hr style="margin:6px 0;border:0;border-top:1px solid #555;">
<label style="display:block;margin-bottom:4px;">
Price preset:
<select id="modeSel">
<option value="money">Make Money</option>
<option value="xp">Get XP</option>
</select>
</label>
<button id="btnFromCrime"
style="display:block;width:100%;margin-top:4px;padding:5px;border:1px solid #888;background:#222;color:#fff;border-radius:4px;">
Force Crimes
</button>
`;
document.body.appendChild(m);
/* Init values */
m.querySelector('#redirSel').value = cfg.redirectMinutes;
m.querySelector('#clickSel').value = cfg.clickDelaySec;
m.querySelector('#travelSel').value = cfg.travelVehicle;
m.querySelector('#carSel').value = cfg.carIndex;
m.querySelector('#crimeSel').value = cfg.crimeIndex;
m.querySelector('#killSel').value = cfg.killIndex;
m.querySelector('#modeSel').value = cfg.mode;
m.querySelector('#actJail').checked = cfg.enabledActivities.jail;
m.querySelector('#actKill').checked = cfg.enabledActivities.killskill;
m.querySelector('#actTravel').checked = cfg.enabledActivities.travel;
m.querySelector('#actMarket').checked = cfg.enabledActivities.market;
m.querySelector('#actCrimes').checked = cfg.enabledActivities.crimes;
m.querySelector('#actNick').checked = cfg.enabledActivities.nickcar;
/* Handlers */
m.querySelector('#redirSel').onchange = e => { cfg.redirectMinutes = +e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#clickSel').onchange = e => { cfg.clickDelaySec = +e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#travelSel').onchange = e => { cfg.travelVehicle = e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#carSel').onchange = e => { cfg.carIndex = +e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#crimeSel').onchange = e => { cfg.crimeIndex = +e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#killSel').onchange = e => { cfg.killIndex = +e.target.value; saveCfg(); triggerReload(); };
m.querySelector('#modeSel').onchange = e => {
cfg.mode = e.target.value;
Object.assign(cfg, preset(cfg.mode));
saveCfg(); triggerReload();
};
const map = {actJail:'jail', actKill:'killskill', actTravel:'travel', actMarket:'market', actCrimes:'crimes', actNick:'nickcar'};
Object.keys(map).forEach(id =>
m.querySelector('#'+id).onchange = e => { cfg.enabledActivities[map[id]] = e.target.checked; saveCfg(); triggerReload(); });
m.querySelector('#btnFromCrime').onclick = () => {
sessionStorage.setItem('BNBMAFIA_FORCE_CRIME', '1');
location.replace('/crimes');
};
}
(document.readyState === 'loading')
? window.addEventListener('DOMContentLoaded', createMainMenu)
: createMainMenu();
})();
/*──────────────────── SHARED HELPERS ───────────────────*/
(function () {
'use strict';
window.BNBMAFIA_COOLDOWN_ACTIVE = root => {
const m = /Next\s+[^:]+?:\s*([^\n]+)/i.exec(root?.textContent ?? '');
if (!m) return false;
return !/^(Now|0s?|0m?:?0s?)$/i.test(m[1].trim());
};
window.BNBMAFIA_OVERLAY_HIDDEN = () => {
const d = document.querySelector('div[aria-hidden="true"]');
return d ? getComputedStyle(d).opacity === '0' : false;
};
window.BNBMAFIA_ORDERED_ATTEMPTS = sel =>
[...document.querySelectorAll(`${sel} button`)]
.filter(b => /attempt\s+now/i.test(b.textContent) && !b.disabled)
.sort((a, b) => a.getBoundingClientRect().left - b.getBoundingClientRect().left);
})();
/* helper shortcuts */
const _cfgDelaySec = () => (window.BNBMAFIA_AUTOSCRIPT_CFG?.clickDelaySec || 45); // seconds
const _cfgRedirectMs = () => (window.BNBMAFIA_AUTOSCRIPT_CFG?.redirectMinutes || 4) * 60_000; // ms
/*──────────────────────────── MODULES ─────────────────────────────*/
/*================ AUTO BUST-OUT ================*/
(function () {
'use strict';
console.log('[Bust-out] module loaded');
const priority = ['Elite OGs','The Syndicate','Original Gangsters','Disturbed','GoodFellas'];
const num = t => parseInt(t.replace(/,/g,''),10)||0;
function go(){
if(!window.BNBMAFIA_OVERLAY_HIDDEN()) return;
if(window.BNBMAFIA_COOLDOWN_ACTIVE(document)) return;
let best=-1,btn=null;
document.querySelectorAll('div[class*="prisonerListItem"]').forEach(row=>{
const fam=row.querySelectorAll('a.MuiTypography-body1,p.MuiTypography-body1')[1]?.textContent.trim();
const buy=row.querySelector('button[class*="moneyCopyButton"]');
const bust=row.querySelector('button[class*="bustOutButton"]');
if(!priority.includes(fam)||!buy||!bust) return;
const price=num([...buy.childNodes].find(n=>n.nodeType===3).textContent);
if(price>best){best=price;btn=bust;}
});
if(btn){console.log(`[Bust-out] Busting for $${best.toLocaleString()}`);btn.click();}
}
setTimeout(go,_cfgDelaySec()*1_000);
})();
/*================ AUTO MARKET BUY/SELL (Booze + Narcotics) ================*/
(function () {
'use strict';
console.log('[Market] module loaded');
/* Force React input to accept programmatic values */
const reactSet=(input,val)=>{
const last=input.value;input.value=val;
input._valueTracker?.setValue(last);
input.dispatchEvent(new Event('input',{bubbles:true}));
};
/* Capacity detection */
const warehouseCap=rows=>{
/* 1) explicit “Max # units / kg” badge – any capitalisation, any whitespace */
const badge=[...document.querySelectorAll('*')].find(e=>/Max\s+\d+/i.test(e.textContent));
let max=parseInt((/Max\s+(\d+)/i.exec(badge?.textContent||'')||[])[1],10);
if(!max||isNaN(max)) max=40; // safe fallback
/* 2) subtract current holdings to get free capacity */
const totalHeld=rows.reduce((sum,r)=>{
const cell=[...r.children].find(td=>/holding/i.test(td.textContent)||td.getAttribute('data-title')?.match(/hold/i));
const h=parseInt((cell?.textContent||'').replace(/\D/g,''),10)||0;
return sum+h;
},0);
return Math.max(max-totalHeld,0);
};
function go(){
if(!window.BNBMAFIA_OVERLAY_HIDDEN()) return;
const table=document.querySelector('table.css-ov0lr2-table'); if(!table) return;
/* ----- column indexes are detected dynamically ----- */
let idxName=0, idxPrice=1, idxHold=2, idxAmt=3;
const header=[...table.querySelectorAll('thead th')].map(th=>th.textContent.trim().toLowerCase());
if(header.length){
idxName = header.findIndex(t=>t.startsWith('product'));
idxPrice = header.findIndex(t=>t.startsWith('price'));
idxHold = header.findIndex(t=>t.startsWith('hold'));
idxAmt = header.findIndex(t=>t.startsWith('amount'));
}
const {buyLimit, sellFloor}=window.BNBMAFIA_AUTOSCRIPT_CFG;
const rows=[...table.querySelectorAll('tbody tr:not(.css-cv5lsn-tableFooter)')];
/* ---- SELL first ---- */
for(const row of rows){
const cells=row.querySelectorAll('td');
const name =cells[idxName ]?.textContent.trim();
const price=parseInt(cells[idxPrice]?.textContent.replace(/\D/g,''),10)||0;
const qty =parseInt(cells[idxHold ]?.textContent.replace(/\D/g,''),10)||0;
const input=cells[idxAmt ]?.querySelector('input')||row.querySelector('input');
if(!sellFloor[name]||qty===0||price<sellFloor[name]) continue;
rows.forEach(r=>reactSet(r.querySelector('input'),'0'));
reactSet(input,qty.toString());
setTimeout(()=>document.querySelectorAll('button')
.forEach(b=>/^\s*sell\s*$/i.test(b.textContent)&&b.click()),200);
console.log(`[Market] Sold ${qty} ${name} @ $${price}`);
return;
}
/* ---- BUY ---- */
const freeCap=warehouseCap(rows); if(freeCap===0) return;
const options=rows.map(r=>{
const cells=r.querySelectorAll('td');
const name =cells[idxName ]?.textContent.trim();
const price=parseInt(cells[idxPrice]?.textContent.replace(/\D/g,''),10)||0;
return {name,price,input:cells[idxAmt]?.querySelector('input'),
ok:buyLimit[name]&&price<buyLimit[name]};
}).filter(o=>o.ok);
if(!options.length) return;
/* choose the item with the best profit margin */
const best=options.reduce((a,b)=>(sellFloor[b.name]-b.price)>(sellFloor[a.name]-a.price)?b:a);
rows.forEach(r=>reactSet(r.querySelector('input'),'0'));
reactSet(best.input,freeCap.toString());
setTimeout(()=>document.querySelectorAll('button')
.forEach(b=>/^\s*buy\s*$/i.test(b.textContent)&&b.click()),300);
console.log(`[Market] Bought ${freeCap} ${best.name} @ $${best.price}`);
}
setTimeout(go,_cfgDelaySec()*1_000);
})();
/*================ AUTO TRAVEL (random) ================*/
(function () {
'use strict';
console.log('[Travel] module loaded');
const POLL=500,MAX=30_000;
function randomTravel(){
if(window.BNBMAFIA_COOLDOWN_ACTIVE(document)) return false;
const vehicle=window.BNBMAFIA_AUTOSCRIPT_CFG.travelVehicle;
const btns=[...document.querySelectorAll('button.MuiButtonBase-root')]
.filter(b=>b.querySelector('p')?.textContent.trim()===vehicle&&!b.disabled);
if(!btns.length){console.log('[Travel] No enabled',vehicle);return false;}
btns[Math.random()*btns.length|0].click();
console.log('[Travel] Clicked',vehicle);
return true;
}
function confirm(){
const start=Date.now();
const id=setInterval(()=>{
const ok=[...document.querySelectorAll('button')].find(b=>/^\s*confirm\s*$/i.test(b.textContent)&&!b.disabled);
if(ok){ok.click();clearInterval(id);} else if(Date.now()-start>MAX) clearInterval(id);
},POLL);
}
setTimeout(()=>{if(randomTravel()) confirm();},_cfgDelaySec()*1_000);
})();
/*================ REDIRECT LOOP ================*/
(function () {
'use strict';
console.log('[Redirect] module loaded');
const route = [
{key:'crimes' ,url:'/crimes'},
{key:'jail' ,url:'/jail'},
{key:'nickcar' ,url:'/nickcar'},
{key:'travel' ,url:'/travel'},
{key:'crimes' ,url:'/crimes'},
{key:'killskill',url:'/killskill'},
{key:'market' ,url:'/booze/*'},
{key:'market' ,url:'/narcotics/*'}
];
const FIXUPS = [
[/^\/injail$/,'/jail']
];
let loopPos=parseInt(sessionStorage.getItem('BNB_LOOPPOS')||'0',10);
function go(){
FIXUPS.forEach(([re,replacement])=>{
if(re.test(location.pathname)) location.replace(replacement);
});
const cfg=window.BNBMAFIA_AUTOSCRIPT_CFG;
if(!cfg?.enabledActivities) return;
for(let step=0;step<route.length;step++){
loopPos=(loopPos+1)%route.length;
const next=route[loopPos];
if(cfg.enabledActivities[next.key]){
sessionStorage.setItem('BNB_LOOPPOS',loopPos);
if(!location.pathname.startsWith(next.url))
location.replace(next.url);
break;
}
}
}
setInterval(go,_cfgRedirectMs());
})();
/*================ AUTO CAR THEFT (Nick Car) ================*/
(function () {
'use strict';
console.log('[Car theft] module loaded');
function go(){
if(!window.BNBMAFIA_OVERLAY_HIDDEN()) return;
const btns=window.BNBMAFIA_ORDERED_ATTEMPTS('div.MuiBox-root[class*="nickcarListItem"]');
const idx=(window.BNBMAFIA_AUTOSCRIPT_CFG.carIndex||1)-1;
const btn=btns[idx]; if(!btn) return;
if(window.BNBMAFIA_COOLDOWN_ACTIVE(btn.closest('[class*="nickcarListItem"]'))) return;
const title=btn.closest('[class*="nickcarListItem"]')?.querySelector('p')?.textContent.trim()||`slot ${idx+1}`;
console.log(`[Car theft] Clicking “${title}” (slot ${idx+1})`);
btn.click();
}
setTimeout(go,_cfgDelaySec()*1_000);
})();
/*================ AUTO KILL-SKILL TRAINING ================*/
(function () {
'use strict';
console.log('[Kill-skill] module loaded');
function go(){
if(!window.BNBMAFIA_OVERLAY_HIDDEN()) return;
const items=document.querySelectorAll('div.MuiBox-root[class*="killSkillListItem"]');
const idx=(window.BNBMAFIA_AUTOSCRIPT_CFG.killIndex||1)-1;
const itm=items[idx]; if(!itm) return;
if(window.BNBMAFIA_COOLDOWN_ACTIVE(itm)) return;
const btn=itm.querySelector('button[class*="attemptButton"]:not([disabled])') || [...itm.querySelectorAll('button')].find(b=>/attempt\s*now/i.test(b.textContent)&&!b.disabled);
if(btn){
const title=itm.querySelector('p')?.textContent.trim()||'skill';
console.log('[Kill-skill] Training',title);
btn.click();
}
}
setTimeout(go,_cfgDelaySec()*1_000);
})();
/*================ AUTO CRIMES ================*/
(function () {
'use strict';
console.log('[Crimes] module loaded');
function go(){
if(!window.BNBMAFIA_OVERLAY_HIDDEN()) return;
const btns=window.BNBMAFIA_ORDERED_ATTEMPTS('div.MuiBox-root[class*="crimeListItem"]');
const idx=(window.BNBMAFIA_AUTOSCRIPT_CFG.crimeIndex||1)-1;
const btn=btns[idx]; if(!btn) return;
const card=btn.closest('div.MuiBox-root[class*="crimeListItem"]');
if(window.BNBMAFIA_COOLDOWN_ACTIVE(card)) return;
const title=card.querySelector('p')?.textContent.trim()||`slot ${idx+1}`;
console.log(`[Crimes] Clicking “${title}” (slot ${idx+1})`);
btn.click();
}
if(sessionStorage.getItem('BNBMAFIA_FORCE_CRIME')==='1'){
sessionStorage.removeItem('BNBMAFIA_FORCE_CRIME');
}
setTimeout(go,_cfgDelaySec()*1_000);
})();
/*================ GLOBAL CLICK THROTTLE ================*/
(function(){
'use strict';
const MIN=_cfgDelaySec()*1_000;let last=0;
const orig=HTMLElement.prototype.click;
HTMLElement.prototype.click=function(...a){
const now=Date.now(),delta=now-last;
if(this.matches('button')&&/^\s*confirm\s*$/i.test(this.textContent)) return orig.apply(this,a);
if(delta>=MIN){last=now;return orig.apply(this,a);}
};
})();