# BoobyLegends Economic Helper This is intended as a helper to find trends in the Booby Legends game. I intend to built a [Discord Bot Interface](DiscordBot.md) to let us share in our guild. ## Running Executables ### Gather Marketing Data This will gather marketing data every 15 minutes, and build an average for each day in UTC timezone. ```bash python3 gatherMarket.py ``` ## Classes There are some main components written as python classes. ### Market Loads the current Market values for cards. You can initialize the Market List like this: ```python from market import Market m=Market() m.fetchData() m.show() ``` Show a filtered Market Page with cards you alreqady have Crystalized removed. ```python from market import Market m=Market() m.fetchData() m.filterMarketCards(False) #After doing stuff... m.closePage() ``` ### Player Loads the current Player values for cards. To get stock values, a "config.json" file must be in the folder with a "cookie" defined to have the player's login. I got my cookie by using the "EditThisCookie" plugin for Chrome. The config file should looks omething like this. ```json { "cookie": { "name":"wordpress_logged_in_f129834928365fbaer348384348y23423uy2323", "value":"keymasterofgozer%8ksojhelFM88efn98709cvaSneOVWEUVn9dvs9eVASEvjSEv8ksojhelFM88efn98709cvaSneOVWEUVn9dvs9eVASEvjSEv8ksojhelFM88efn98709cvaSneOVW" } } ``` You can initialize your Player list like this: ```python from player import Player p=Player() p.fetchData() p.show() ``` Get a List of non-crystal remaining Cards to collect ```python from player import Player p=Player() p.fetchData() p.show(fields=['name','level','stock'],filter='stock != "CRYSTAL"') ``` ### Market Data ```python from db import MarketDB, hist, plot hist(2) plot(2) ``` ### Javascript clips for console use to do things on pages. #### Player Page ##### javascript to filter Player Page for salable cards ```javascript sellThreshold = {}; sellThreshold["2000"] = 10000; sellThreshold["350"] = 195; sellThreshold["250"] = 126; sellThreshold["200"] = 87; sellThreshold["150"] = 110; sellThreshold["115"] = 80; sellThreshold["75"] = 32; sellThreshold["50"] = 25; sellThreshold["40"] = 32; sellThreshold["20"] = 22; sellThreshold["15"] = 12; sellThreshold["10"] = 8; sellThreshold["4"] = 9; sellThreshold["3"] = 4; sellThreshold["2"] = 4; sellThreshold["1"] = 4; clist=[]; for (var i = 0; i < 153; i++) {clist.push(0);} let market = document.createElement('div'); market.id = 'market'; market.innerHTML=await (await fetch('https://play.boobylegends.com/market/')).text(); marketCards=market.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < marketCards.length; i++) { try{ cardNum = parseInt(marketCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); price = parseInt(marketCards.item(i).getElementsByClassName('cost')[0].innerText.trim()); clist[cardNum]=price; }catch(err){console.log('error on '+cardNum.toString());} }; cards=document.getElementsByClassName('wrapper-card'); for (var i = 0; i < cards.length; i++) { cardNum = parseInt(cards.item(i).getElementsByClassName('pornstar-number')[0].outerText); cardVal = parseInt(cards.item(i).getElementsByClassName('score-card')[0].outerText); price = clist[cardNum]; var cardNB = cards.item(i).getElementsByClassName('card-nb')[0]; if (cardNB){try{ stock = parseInt(cards.item(i).getElementsByClassName('nb-label')[0].outerText.trim()); var fuzed = cards.item(i).getElementsByClassName('nb-name')[0]; if (fuzed){stock = stock + 1;} HTMLText = "Price: " + price; var priceDiv = cardNB.getElementsByClassName('Price')[0]; if (priceDiv){priceDiv.innerText = HTMLText;} else{ let qty = document.createElement('div'); qty.classList.add('Price'); qty.innerText = HTMLText; cardNB.appendChild(qty); } }catch(err){stock=0;}}else{ stock=0; } if (stock<2){ cards.item(i).style.setProperty('Display','None'); } if (price 0){ HTMLText = " +" + numForSale[cardNum]; }else{HTMLText=""} var cardNB = cards.item(i).getElementsByClassName('card-nb')[0]; if (cardNB){try{ var priceDiv = cardNB.getElementsByClassName('Price')[0]; if (priceDiv){priceDiv.innerText = HTMLText;} else{ let qty = document.createElement('div'); qty.classList.add('Price'); qty.innerText = HTMLText; cardNB.appendChild(qty); } }catch(err){stock=0;}}else{ stock=0; } } //Player page show number cards for sale ``` ##### javascript to show only cards for sale ```javascript numForSale=[]; for (var i = 0; i < 153; i++) {numForSale.push(0);} let marketSelling = document.createElement('div'); marketSelling.id = 'market'; marketSelling.innerHTML=await (await fetch('https://play.boobylegends.com/market/?tab=selling')).text(); marketCards=marketSelling.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < marketCards.length; i++) { try{ cardNum = parseInt(marketCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); price = parseInt(marketCards.item(i).getElementsByClassName('cost')[0].innerText.trim()); numForSale[cardNum]=numForSale[cardNum]+1; }catch(err){console.log('error on '+cardNum.toString());} }; cards=document.getElementsByClassName('wrapper-card'); for (var i = 0; i < cards.length; i++) { cardNum = parseInt(cards.item(i).getElementsByClassName('pornstar-number')[0].outerText); cardVal = parseInt(cards.item(i).getElementsByClassName('score-card')[0].outerText); if (numForSale[cardNum] > 0){ HTMLText = " +" + numForSale[cardNum]; }else{HTMLText=""; cards.item(i).style.setProperty('Display','None');} var cardNB = cards.item(i).getElementsByClassName('card-nb')[0]; if (cardNB){try{ var priceDiv = cardNB.getElementsByClassName('Price')[0]; if (priceDiv){priceDiv.innerText = HTMLText;} else{ let qty = document.createElement('div'); qty.classList.add('Price'); qty.innerText = HTMLText; cardNB.appendChild(qty); } }catch(err){stock=0;}}else{ stock=0; } } //Player page show only cards for sale ``` #### Market Page ##### javascript to filter Market for needed cards ```javascript playerStock=[]; for (var i = 0; i < 153; i++) {x={};x["extra"]=0;x["status"]="NORMAL";playerStock.push(x);} let player = document.createElement('div'); player.id = 'player'; player.innerHTML=await (await fetch('https://play.boobylegends.com/player/')).text(); playerCards=player.getElementsByClassName('wrapper-card'); for (var i = 0; i < playerCards.length; i++) { stock = {}; stock["extra"]=0; stock["status"]="NORMAL"; try{ cardNum = parseInt(playerCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); var cardNB = playerCards.item(i).getElementsByClassName('card-nb')[0]; if (cardNB){ try{ cnt = parseInt(cardNB.getElementsByClassName('nb-label')[0].outerText.trim()); }catch(err){cnt=0;} stock["extra"]=cnt-1; try{ var fuzed = cardNB.getElementsByClassName('nb-name')[0].outerText.trim(); if (fuzed){ stock["extra"] = stock["extra"] + 1; stock["status"]= fuzed; } }catch(err){console.log('No Status, or Normal Card : '+cardNum.toString());} playerStock[cardNum]=stock; } }catch(err){console.log('Error on Card : '+cardNum.toString());} }; cards=document.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < cards.length; i++) { cardNum = cards.item(i).getElementsByClassName('pornstar-number')[0].outerText; if (playerStock[cardNum].status != "NORMAL"){ HTMLText=playerStock[cardNum].status + " +" }else{HTMLText=""} HTMLText = "Stock: " + HTMLText + playerStock[cardNum].extra; innerCard = cards.item(i).getElementsByClassName('inner-market-card')[0]; var stock = innerCard.getElementsByClassName('Stock')[0]; if (stock){stock.innerText = HTMLText} else { let qty = document.createElement('div'); qty.classList.add('Stock'); qty.innerText = HTMLText; innerCard.appendChild(qty); } if (playerStock[cardNum].status == 'CRYSTAL'){ cards.item(i).style.setProperty('Display','None'); } } //filter Market for needed cards ``` ##### javascript to filter Market for good buys for needed cards ```javascript buyThreshold = {}; buyThreshold["2000"] = 1000; buyThreshold["350"] = 200; buyThreshold["250"] = 100; buyThreshold["200"] = 75; buyThreshold["150"] = 85; buyThreshold["115"] = 60; buyThreshold["75"] = 25; buyThreshold["50"] = 18; buyThreshold["40"] = 25; buyThreshold["20"] = 13; buyThreshold["15"] = 7; buyThreshold["10"] = 5; buyThreshold["4"] = 4; buyThreshold["3"] = 2; buyThreshold["2"] = 1; buyThreshold["1"] = 1; playerStock=[]; for (var i = 0; i < 153; i++) {x={};x["extra"]=0;x["status"]="NORMAL";playerStock.push(x);} let player = document.createElement('div'); player.id = 'player'; player.innerHTML=await (await fetch('https://play.boobylegends.com/player/')).text(); playerCards=player.getElementsByClassName('wrapper-card'); for (var i = 0; i < playerCards.length; i++) { stock = {}; stock["extra"]=0; stock["status"]="NORMAL"; try{ cardNum = parseInt(playerCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); var cardNB = playerCards.item(i).getElementsByClassName('card-nb')[0]; if (cardNB){ try{ cnt = parseInt(cardNB.getElementsByClassName('nb-label')[0].outerText.trim()); }catch(err){cnt=0;} stock["extra"]=cnt-1; try{ var fuzed = cardNB.getElementsByClassName('nb-name')[0].outerText.trim(); if (fuzed){ stock["extra"] = stock["extra"] + 1; stock["status"]= fuzed; } }catch(err){console.log('No Status, or Normal Card : '+cardNum.toString());} playerStock[cardNum]=stock; } }catch(err){console.log('Error on Card : '+i.toString());} }; cards=document.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < cards.length; i++) { cardNum = cards.item(i).getElementsByClassName('pornstar-number')[0].outerText; cardVal = parseInt(cards.item(i).getElementsByClassName('score-card')[0].outerText); cardCost = parseInt(cards.item(i).getElementsByClassName('cost')[0].outerText); cardPPG = cardVal/cardCost; try{ if (playerStock[cardNum].status != "NORMAL"){ HTMLText=playerStock[cardNum].status + " +" }else{HTMLText=""} HTMLText = "Stock: " + HTMLText + playerStock[cardNum].extra; HTMLText = HTMLText+"
"+ "Points/:
" + cardPPG.toFixed(2); innerCard = cards.item(i).getElementsByClassName('inner-market-card')[0]; var extraInfo = innerCard.getElementsByClassName('extraInfo')[0]; if (extraInfo){extraInfo.innerHTML = HTMLText} else { let extraInfoDiv = document.createElement('div'); extraInfoDiv.classList.add('extraInfo'); extraInfoDiv.innerHTML = HTMLText; extraInfoDiv.setAttribute("align", "center"); innerCard.appendChild(extraInfoDiv); } if (playerStock[cardNum].status == 'CRYSTAL'){ cards.item(i).style.setProperty('Display','None'); } /*if (cardPPG < 2){ cards.item(i).style.setProperty('Display','None'); }*/ /*if (cardCost > buyThreshold[cardVal.valueOf()]){ cards.item(i).style.setProperty('Display','None'); }*/ if ((cardCost > buyThreshold[cardVal.valueOf()])&&(cardPPG < 2)){ cards.item(i).style.setProperty('Display','None'); } }catch(err){console.log('Error on Card : '+i.toString());} } //filter Market for good buys for needed cards ``` ##### javascript to filter Market for uncrystalized cards ```javascript clist=[]; for (var i = 0; i < 153; i++) {clist.push(0);} let player = document.createElement('div'); player.id = 'player'; player.innerHTML=await (await fetch('https://play.boobylegends.com/player/')).text(); playerCards=player.getElementsByClassName('wrapper-card'); for (var i = 0; i < playerCards.length; i++) { try{ cardNum = parseInt(playerCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); stock = playerCards.item(i).getElementsByClassName('card-nb')[0].innerText.trim(); clist[cardNum]=stock; }catch(err){console.log('hi');} }; cards=document.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < cards.length; i++) { cardNum = cards.item(i).getElementsByClassName('pornstar-number')[0].outerText; HTMLText = "Stock: " + clist[cardNum]; innerCard = cards.item(i).getElementsByClassName('inner-market-card')[0]; var stock = innerCard.getElementsByClassName('Stock')[0]; if (stock){stock.innerText = HTMLText} else { let qty = document.createElement('div'); qty.classList.add('Stock'); qty.innerText = HTMLText; innerCard.appendChild(qty); } if (clist[cardNum].toString().includes('CRYSTAL')){ cards.item(i).style.setProperty('Display','None'); } } //filter Market for uncrystalized cards ``` ##### javascript to filter Market for good value cards ```javascript playerStock=[]; for (var i = 0; i < 153; i++) {playerStock.push(0);} let player = document.createElement('div'); player.id = 'player'; player.innerHTML=await (await fetch('https://play.boobylegends.com/player/')).text(); playerCards=player.getElementsByClassName('wrapper-card'); for (var i = 0; i < playerCards.length; i++) { try{ cardNum = parseInt(playerCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); stock = playerCards.item(i).getElementsByClassName('card-nb')[0].innerText.trim(); playerStock[cardNum]=stock; }catch(err){console.log('hi');} }; cards=document.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < cards.length; i++) { cardNum = cards.item(i).getElementsByClassName('pornstar-number')[0].outerText; cardVal = parseInt(cards.item(i).getElementsByClassName('score-card')[0].outerText); cardCost = parseInt(cards.item(i).getElementsByClassName('cost')[0].outerText); cardPPG = cardVal/cardCost; HTMLText = "Stock: " + playerStock[cardNum]+"
"+ "Points/:
" + cardPPG.toFixed(2); innerCard = cards.item(i).getElementsByClassName('inner-market-card')[0]; var PPG = innerCard.getElementsByClassName('PPG')[0]; if (PPG){PPG.innerHTML = HTMLText} else { let extraInfoDiv = document.createElement('div'); extraInfoDiv.classList.add('PPG'); extraInfoDiv.innerHTML = HTMLText; extraInfoDiv.setAttribute("align", "center"); innerCard.appendChild(extraInfoDiv); } if (cardPPG < 2.5){ cards.item(i).style.setProperty('Display','None'); } } //filter Market for good value cards ``` #### Market Selling Page ##### javascript to show overbid cards for sale ```javascript sellThreshold = {}; sellThreshold["2000"] = 10000; sellThreshold["350"] = 195; sellThreshold["250"] = 126; sellThreshold["200"] = 87; sellThreshold["150"] = 110; sellThreshold["115"] = 80; sellThreshold["75"] = 32; sellThreshold["50"] = 25; sellThreshold["40"] = 32; sellThreshold["20"] = 22; sellThreshold["15"] = 12; sellThreshold["10"] = 8; sellThreshold["4"] = 9; sellThreshold["3"] = 4; sellThreshold["2"] = 4; sellThreshold["1"] = 4; clist=[]; for (var i = 0; i < 153; i++) {clist.push(0);} let market = document.createElement('div'); market.id = 'market'; market.innerHTML=await (await fetch('https://play.boobylegends.com/market/')).text(); marketCards=market.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < marketCards.length; i++) { try{ cardNum = parseInt(marketCards.item(i).getElementsByClassName('pornstar-number')[0].innerText); price = parseInt(marketCards.item(i).getElementsByClassName('cost')[0].innerText.trim()); clist[cardNum]=price; }catch(err){console.log('error on '+cardNum.toString());} }; cards=document.getElementsByClassName('wrapper-market-card'); for (var i = 0; i < cards.length; i++) { cardNum = cards.item(i).getElementsByClassName('pornstar-number')[0].outerText; cardVal = parseInt(cards.item(i).getElementsByClassName('score-card')[0].outerText); cardCost = parseInt(cards.item(i).getElementsByClassName('cost')[0].outerText); cardPPG = cardVal/cardCost; HTMLText = "Current Bid: "+clist[cardNum].toString()+"
Threshold: "+sellThreshold[cardVal.toString()]; innerCard = cards.item(i).getElementsByClassName('inner-market-card')[0]; var PPG = innerCard.getElementsByClassName('PPG')[0]; if (PPG){PPG.innerHTML = HTMLText} else { let qty = document.createElement('div'); qty.classList.add('PPG'); qty.innerHTML = HTMLText; qty.setAttribute("align", "center"); innerCard.appendChild(qty); } if (cardCost <= clist[cardNum]){ cards.item(i).style.setProperty('Display','None'); } if (clist[cardNum] < sellThreshold[cardVal.toString()]){ //cards.item(i).style.setProperty('Display','None'); } } //Market page show overbid cards for sale ```