diff --git a/.config/qutebrowser/greasemonkey/onlinetichu.js b/.config/qutebrowser/greasemonkey/onlinetichu.js index d9461d6..01bcf77 100644 --- a/.config/qutebrowser/greasemonkey/onlinetichu.js +++ b/.config/qutebrowser/greasemonkey/onlinetichu.js @@ -1,399 +1,421 @@ // ==UserScript== // @name onlinetichu.com card counter -// @version 1.0.0 +// @version 1.0.2 // @description automatically count cards at onlinetichu.com // @author kesslermaximilian // @match *://*.onlinetichu.com/Site/Game/Table/* // ==/UserScript== // disable auto fold functionality completely -if (ot.AutoFold) { - ot.$autoFold.click() - ot.$autoFold.hide() -} -var myStyles = ` - #playedHigh { - position: absolute; - top: 620px; - width: 850px; - height: 120px; +function injectCounter() { + if (ot.AutoFold) { + ot.$autoFold.click() + ot.$autoFold.hide() } - #playedLow { - position: absolute; - top: 750px; - width: 850px; - height: 120px; - } - - .playedCardsLayout { - position: absolute; - height: 125px; - } - - .playedCardsLayout .card { - width: 80px; - height: 120px; - border-radius: 5px; - float: left; - margin-left: -50px; - text-align: left; + var myStyles = ` + #playedHigh { + position: absolute; + top: 620px; + width: 850px; + height: 120px; } - .playedCardsLayout .card:hover { - z-index: 1400; - } -` - -var styleSheet = document.createElement("style") -styleSheet.innerText = myStyles; -console.log(styleSheet); -document.head.appendChild(styleSheet); - -// add an extra field where we will put down the played cards -var cardsField = document.createElement('div'); -cardsField.id = 'cardsField'; -cardsField.style.marginLeft = '25px'; - -var playedHigh = document.createElement('div'); -playedHigh.id = 'playedHigh'; -playedHigh.style.marginLeft = '25px'; -playedHigh.className = 'row'; -playedHigh.hidden = true; - -var playedLow = document.createElement('div'); -playedLow.id = 'playedLow'; -playedLow.style.marginLeft = '25px'; -playedLow.className = 'row'; -playedLow.hidden = true; - -tableIG = document.getElementById('gameField').parentNode; -tableIG.appendChild(playedHigh); -tableIG.appendChild(playedLow); - -var createCardPlace = function(value, shift, node) { - var playedCards = document.createElement('ul'); - playedCards.id = 'playedCards' + value; - // playedCards.className = 'layoutPlayedCards list-unstyled col-lg-2'; -// playedCards.className = 'playedCardsLayout list-unstyled'; - playedCards.className = 'playedCardsLayout list-unstyled'; - playedCards.style.width = '160px'; - playedCards.style.marginLeft = '25px'; - playedCards.style.left = shift*129 + 'px'; - - node.appendChild(playedCards); -} - -createCardPlace(1, 0, document.getElementById('playedHigh')); -for(let i = 14; i > 8; i--) { - createCardPlace(i, 14 - i + 1, document.getElementById('playedHigh')); -} - -for(let i = 8; i > 1; i--) { - createCardPlace(i, 8 - i, document.getElementById('playedLow')); -} - - -var smartFoldButton = document.createElement('button'); -smartFoldButton.className = "btn btn-danger btn-xs"; -smartFoldButton.id = "smartFold"; -smartFoldButton.type = "button"; -smartFoldButton.innerHTML = 'Smart fold: Yes'; - -var showPlayedButton = document.createElement('button'); -showPlayedButton.className = "btn btn-primary btn-xs"; -showPlayedButton.id = "showPlayed"; -showPlayedButton.type = "button"; -showPlayedButton.innerHTML = 'Show counted cards: No'; - -var showRemainingButton = document.createElement('button'); -showRemainingButton.className = "btn btn-info btn-xs"; -showRemainingButton.id = "showRemaining"; -showRemainingButton.type = "button"; -showRemainingButton.innerHTML = 'Show: Remaining'; - -buttons = document.getElementById('statusButtons'); -buttons.insertBefore(showRemainingButton, document.getElementById('autoFold')); -buttons.insertBefore(showPlayedButton, document.getElementById('autoFold')); -buttons.insertBefore(smartFoldButton, document.getElementById('autoFold')); - -// playedCards. -// ot.$gameField.insertAfter(playedCards, ot.$gameField.lastChild); - -// set up counting of played cards -var OnlineTichuCounter = { - $playedCards: {}, - $smartFold: $('#smartFold'), - $smartFoldValue: $('#smartFoldValue'), - $showPlayed: $('#showPlayed'), - $showPlayedValue: $('#showPlayedValue'), - $showRemaining: $('#showRemaining'), - $showRemainingValue: $('#showRemainingValue'), - $playedHigh: $('#playedHigh'), - $playedLow: $('#playedLow'), - - allCards: {}, - playedCards: {}, - totalPlayed: [], - exchangedTo: {}, - exchangedFrom: {}, - smartFold: true, - showPlayed: false, - showRemaining: true, - bombAfterFold: null, - - util: { - displayCardsHtmlString: function(cards) { - htmlString = ""; - $(cards).each(function () { - var value = this.Value; - if (this.Shape == 7) { - value = 0; - } - htmlString += '
'; - }); - return htmlString; - }, - - populateAllCards: function() { - for(let val = 2; val < 15; val++) { - otc.allCards[val] = []; - for(let shape = 0; shape < 4; shape++) { - otc.allCards[val].push({ - Shape: shape, - Value: val - }); - } - } - otc.allCards[1] = [ - { Shape: 4, Value: 1 }, // mahjong - { Shape: 5, Value: 0 }, // dog - { Shape: 6, Value: 15}, // dragon - { Shape: 7, Value: 14 } // phoenix - ]; - }, - - cardInArray: function(card, array) { - contained = false; - for(let i = 0; i < array.length; i++) { - if (array[i].Shape == card.Shape && array[i].Value == card.Value) { - contained = true; - } - } - return contained; + #playedLow { + position: absolute; + top: 750px; + width: 850px; + height: 120px; } - }, - action: { + .playedCardsLayout { + position: absolute; + height: 125px; + } - handlePlayedCard: function(card) { - index = 0; - // special cards have Shapes 4,5,6,7. We group them at value 1 - if(card.Shape >= 4) { - index = 1; - if (card.Shape == 7) { - // Treat phoenix as if it had value 14 - // This is important for comparisons later - card.Value = 14; + .playedCardsLayout .card { + width: 80px; + height: 120px; + border-radius: 5px; + float: left; + margin-left: -50px; + text-align: left; + } + + .playedCardsLayout .card:hover { + z-index: 1400; } - } else { - index = card.Value; - } - otc.playedCards[index].push(card); - otc.totalPlayed.push(card); + ` - otc.playedCards[index].sort(function(c1, c2){ - return c2.Shape - c1.Shape; - }); - }, + var styleSheet = document.createElement("style") + styleSheet.innerText = myStyles; + console.log(styleSheet); + document.head.appendChild(styleSheet); - handlePlayedCards: function(cards) { - if (cards.length === 0) { - return; - } - if (!otc.util.cardInArray(cards[0], otc.totalPlayed)) { - $(message.Table.TableCards).each( - (index, card) => otc.action.handlePlayedCard(card) - ); - } - }, + // add an extra field where we will put down the played cards + var cardsField = document.createElement('div'); + cardsField.id = 'cardsField'; + cardsField.style.marginLeft = '25px'; - resetPlayedCards: function() { - for(let i = 1; i < 15; i++) { - otc.playedCards[i] = []; - } - otc.totalPlayed = []; - }, + var playedHigh = document.createElement('div'); + playedHigh.id = 'playedHigh'; + playedHigh.style.marginLeft = '25px'; + playedHigh.className = 'row'; + playedHigh.hidden = true; - drawPlayedCards: function() { - for(let i = 1; i < 15; i++) { - if (otc.showRemaining) { - cards = []; - for(let j=0; j < otc.allCards[i].length; j ++) { - if(!otc.util.cardInArray(otc.allCards[i][j], otc.playedCards[i])) { - cards.push(otc.allCards[i][j]); + var playedLow = document.createElement('div'); + playedLow.id = 'playedLow'; + playedLow.style.marginLeft = '25px'; + playedLow.className = 'row'; + playedLow.hidden = true; + + tableIG = document.getElementById('gameField').parentNode; + tableIG.appendChild(playedHigh); + tableIG.appendChild(playedLow); + + var createCardPlace = function(value, shift, node) { + var playedCards = document.createElement('ul'); + playedCards.id = 'playedCards' + value; + // playedCards.className = 'layoutPlayedCards list-unstyled col-lg-2'; + // playedCards.className = 'playedCardsLayout list-unstyled'; + playedCards.className = 'playedCardsLayout list-unstyled'; + playedCards.style.width = '160px'; + playedCards.style.marginLeft = '25px'; + playedCards.style.left = shift*129 + 'px'; + + node.appendChild(playedCards); + } + + createCardPlace(1, 0, document.getElementById('playedHigh')); + for(let i = 14; i > 8; i--) { + createCardPlace(i, 14 - i + 1, document.getElementById('playedHigh')); + } + + for(let i = 8; i > 1; i--) { + createCardPlace(i, 8 - i, document.getElementById('playedLow')); + } + + + var smartFoldButton = document.createElement('button'); + smartFoldButton.className = "btn btn-danger btn-xs"; + smartFoldButton.id = "smartFold"; + smartFoldButton.type = "button"; + smartFoldButton.innerHTML = 'Smart fold: Yes'; + + var showPlayedButton = document.createElement('button'); + showPlayedButton.className = "btn btn-primary btn-xs"; + showPlayedButton.id = "showPlayed"; + showPlayedButton.type = "button"; + showPlayedButton.innerHTML = 'Show counted cards: No'; + + var showRemainingButton = document.createElement('button'); + showRemainingButton.className = "btn btn-info btn-xs"; + showRemainingButton.id = "showRemaining"; + showRemainingButton.type = "button"; + showRemainingButton.innerHTML = 'Show: Remaining'; + + buttons = document.getElementById('statusButtons'); + buttons.insertBefore(showRemainingButton, document.getElementById('autoFold')); + buttons.insertBefore(showPlayedButton, document.getElementById('autoFold')); + buttons.insertBefore(smartFoldButton, document.getElementById('autoFold')); + + // playedCards. + // ot.$gameField.insertAfter(playedCards, ot.$gameField.lastChild); + + // set up counting of played cards + var OnlineTichuCounter = { + $playedCards: {}, + $smartFold: $('#smartFold'), + $smartFoldValue: $('#smartFoldValue'), + $showPlayed: $('#showPlayed'), + $showPlayedValue: $('#showPlayedValue'), + $showRemaining: $('#showRemaining'), + $showRemainingValue: $('#showRemainingValue'), + $playedHigh: $('#playedHigh'), + $playedLow: $('#playedLow'), + + allCards: {}, + playedCards: {}, + totalPlayed: [], + exchangedTo: {}, + exchangedFrom: {}, + smartFold: true, + showPlayed: false, + showRemaining: true, + bombAfterFold: null, + + util: { + displayCardsHtmlString: function(cards) { + htmlString = ""; + $(cards).each(function () { + var value = this.Value; + if (this.Shape == 7) { + value = 0; } - otc.$playedCards[i].html(otc.util.displayCardsHtmlString(cards)); + htmlString += ''; + }); + return htmlString; + }, + + populateAllCards: function() { + for(let val = 2; val < 15; val++) { + otc.allCards[val] = []; + for(let shape = 0; shape < 4; shape++) { + otc.allCards[val].push({ + Shape: shape, + Value: val + }); + } + } + otc.allCards[1] = [ + { Shape: 4, Value: 1 }, // mahjong + { Shape: 5, Value: 0 }, // dog + { Shape: 6, Value: 15}, // dragon + { Shape: 7, Value: 14 } // phoenix + ]; + }, + + cardInArray: function(card, array) { + contained = false; + for(let i = 0; i < array.length; i++) { + if (array[i].Shape == card.Shape && array[i].Value == card.Value) { + contained = true; + } + } + return contained; + } + }, + + action: { + + handlePlayedCard: function(card) { + index = 0; + // special cards have Shapes 4,5,6,7. We group them at value 1 + if(card.Shape >= 4) { + index = 1; + if (card.Shape == 7) { + // Treat phoenix as if it had value 14 + // This is important for comparisons later + card.Value = 14; } } else { - otc.$playedCards[i].html(otc.util.displayCardsHtmlString(otc.playedCards[i])); + index = card.Value; } - } - } - } -} + otc.playedCards[index].push(card); + otc.totalPlayed.push(card); -if (!window.otc) { - window.otc = OnlineTichuCounter; -} + otc.playedCards[index].sort(function(c1, c2){ + return c2.Shape - c1.Shape; + }); + }, -// add functionality to smartFold button -otc.$smartFold.click(function () { - otc.smartFold = !otc.smartFold; - if (otc.smartFold) { - otc.$smartFoldValue.text(otc.$smartFoldValue.data('on')); - } else { - otc.$smartFoldValue.text(otc.$smartFoldValue.data('off')); - } -}); + handlePlayedCards: function(cards) { + if (cards.length === 0) { + return; + } + if (!otc.util.cardInArray(cards[0], otc.totalPlayed)) { + $(message.Table.TableCards).each( + (index, card) => otc.action.handlePlayedCard(card) + ); + } + }, -// add functionality to show button -otc.$showPlayed.click(function () { - otc.showPlayed = !otc.showPlayed; - if (otc.showPlayed) { - otc.$showPlayedValue.text(otc.$showPlayedValue.data('on')); - otc.$playedHigh.show(); - otc.$playedLow.show(); - otc.$showRemaining.show(); - } else { - otc.$showPlayedValue.text(otc.$showPlayedValue.data('off')); - otc.$playedHigh.hide(); - otc.$playedLow.hide(); - otc.$showRemaining.hide(); - } -}); + resetPlayedCards: function() { + for(let i = 1; i < 15; i++) { + otc.playedCards[i] = []; + } + otc.totalPlayed = []; + }, -otc.$showRemaining.click(function () { - otc.showRemaining = !otc.showRemaining; - if (otc.showRemaining) { - otc.$showRemainingValue.text(otc.$showRemainingValue.data('on')); - } else { - otc.$showRemainingValue.text(otc.$showRemainingValue.data('off')); - } - otc.action.drawPlayedCards(); -}); - -for(let i = 1; i < 15; i++) { - otc.$playedCards[i] = $('#playedCards' + i); -} - -otc.action.resetPlayedCards(); -otc.util.populateAllCards(); - -MyTableState = (function() { - var cachedFunction = ot.reaction.TableState; - - return function() { - var result = cachedFunction.apply(this, arguments); - - message = arguments[0]; - -// console.log('detected table state change event'); -// console.log(message.Table.Status); - - // reset played cards at start of round - if(message.Table.Status == 'WaitForNextCards') { - otc.action.resetPlayedCards(); - } - - if(message.Table.Status == 'Playing') { - otc.action.handlePlayedCards(message.Table.TableCards); - } - - otc.action.drawPlayedCards(); - - console.log('reached smartFold point'); - $(message.Table.Players).each(function () { - if (this.Username == ot.$Username.val()) { - console.log('found player'); - if (message.Table.Turn == this.Position) { - console.log('my turn!'); - if (this.Cards.length < 4 && this.Cards.length < message.Table.TableCards.length) { - console.log('obvious that have to fold now'); - if (otc.smartFold) { - ot.action.Fold(); + drawPlayedCards: function() { + for(let i = 1; i < 15; i++) { + if (otc.showRemaining) { + cards = []; + for(let j=0; j < otc.allCards[i].length; j ++) { + if(!otc.util.cardInArray(otc.allCards[i][j], otc.playedCards[i])) { + cards.push(otc.allCards[i][j]); + } + otc.$playedCards[i].html(otc.util.displayCardsHtmlString(cards)); } + } else { + otc.$playedCards[i].html(otc.util.displayCardsHtmlString(otc.playedCards[i])); } } } - }); - - return result; + } } -})(); + if (!window.otc) { + window.otc = OnlineTichuCounter; + } + otc.$showRemaining.hide(); -MyChat = (function() { - var cachedFunction = ot.reaction.Chat; + // add functionality to smartFold button + otc.$smartFold.click(function () { + otc.smartFold = !otc.smartFold; + if (otc.smartFold) { + otc.$smartFoldValue.text(otc.$smartFoldValue.data('on')); + } else { + otc.$smartFoldValue.text(otc.$smartFoldValue.data('off')); + } + }); - return function() { - var result = cachedFunction.apply(this, arguments); + // add functionality to show button + otc.$showPlayed.click(function () { + otc.showPlayed = !otc.showPlayed; + if (otc.showPlayed) { + otc.$showPlayedValue.text(otc.$showPlayedValue.data('on')); + otc.$playedHigh.show(); + otc.$playedLow.show(); + otc.$showRemaining.show(); + } else { + otc.$showPlayedValue.text(otc.$showPlayedValue.data('off')); + otc.$playedHigh.hide(); + otc.$playedLow.hide(); + otc.$showRemaining.hide(); + } + }); - message = arguments[0]; - if (message.User.Username === "System") { - var messageArray = message.Text.replace(//g, '>').split(' '); - message.Text = messageArray.join(' '); - messageArray = message.Text.replace(//g, '>').split(' '); - - for(var i in messageArray) { - if(messageArray[i] == "dogs") { - otc.action.handlePlayedCard({ - "Shape": 5, - "Value": 0 - }); - } + otc.$showRemaining.click(function () { + otc.showRemaining = !otc.showRemaining; + if (otc.showRemaining) { + otc.$showRemainingValue.text(otc.$showRemainingValue.data('on')); + } else { + otc.$showRemainingValue.text(otc.$showRemainingValue.data('off')); + } + otc.action.drawPlayedCards(); + }); + + for(let i = 1; i < 15; i++) { + otc.$playedCards[i] = $('#playedCards' + i); + } + + otc.action.resetPlayedCards(); + otc.util.populateAllCards(); + + MyTableState = (function() { + var cachedFunction = ot.reaction.TableState; + + return function() { + var result = cachedFunction.apply(this, arguments); + + message = arguments[0]; + + // console.log('detected table state change event'); + // console.log(message.Table.Status); + + // reset played cards at start of round + if(message.Table.Status == 'WaitForNextCards') { + otc.action.resetPlayedCards(); } + + if(message.Table.Status == 'Playing') { + otc.action.handlePlayedCards(message.Table.TableCards); + } + + otc.action.drawPlayedCards(); + + console.log('reached smartFold point'); + $(message.Table.Players).each(function () { + if (this.Username == ot.$Username.val()) { + console.log('found player'); + if (message.Table.Turn == this.Position) { + console.log('my turn!'); + if (this.Cards.length < 4 && this.Cards.length < message.Table.TableCards.length) { + console.log('obvious that have to fold now'); + if (otc.smartFold) { + ot.action.Fold(); + } + } + } + } + }); + + return result; } - return result; - } -})(); + })(); -MyExchangeCards = (function() { - var cachedFunction = ot.action.ExchangeCards; - return function() { + MyChat = (function() { + var cachedFunction = ot.reaction.Chat; - otc.exchangedTo['west'] = { - Shape: ot.$westExchange.children('li:nth-child(1)').data('shape'), - Value: ot.$westExchange.children('li:nth-child(1)').data('value') }; - otc.exchangedTo['north'] = { - Shape: ot.$northExchange.children('li:nth-child(1)').data('shape'), - Value: ot.$northExchange.children('li:nth-child(1)').data('value') }; - otc.exchangedTo['east'] = { - Shape: ot.$eastExchange.children('li:nth-child(1)').data('shape'), - Value: ot.$eastExchange.children('li:nth-child(1)').data('value') }; + return function() { + var result = cachedFunction.apply(this, arguments); - console.log(otc.exchangedTo); + message = arguments[0]; + if (message.User.Username === "System") { + var messageArray = message.Text.replace(//g, '>').split(' '); + message.Text = messageArray.join(' '); + messageArray = message.Text.replace(//g, '>').split(' '); + + for(var i in messageArray) { + if(messageArray[i] == "dogs") { + otc.action.handlePlayedCard({ + "Shape": 5, + "Value": 0 + }); + } + } + } - var result = cachedFunction.apply(this, arguments); - return result; - } -})(); + return result; + } + })(); -MyReviewExchange = (function() { - var cachedFunction = ot.reaction.ReviewExchange; + MyExchangeCards = (function() { + var cachedFunction = ot.action.ExchangeCards; - return function() { - var result = cachedFunction.apply(this, arguments); - return result; - } -})(); + return function() { -ot.reaction.TableState = MyTableState; -ot.reaction.Chat = MyChat; -ot.action.ExchangeCards = MyExchangeCards; + otc.exchangedTo['west'] = { + Shape: ot.$westExchange.children('li:nth-child(1)').data('shape'), + Value: ot.$westExchange.children('li:nth-child(1)').data('value') }; + otc.exchangedTo['north'] = { + Shape: ot.$northExchange.children('li:nth-child(1)').data('shape'), + Value: ot.$northExchange.children('li:nth-child(1)').data('value') }; + otc.exchangedTo['east'] = { + Shape: ot.$eastExchange.children('li:nth-child(1)').data('shape'), + Value: ot.$eastExchange.children('li:nth-child(1)').data('value') }; + + console.log(otc.exchangedTo); + + var result = cachedFunction.apply(this, arguments); + return result; + } + })(); + + MyReviewExchange = (function() { + var cachedFunction = ot.reaction.ReviewExchange; + + return function() { + var result = cachedFunction.apply(this, arguments); + return result; + } + })(); + + ot.reaction.TableState = MyTableState; + ot.reaction.Chat = MyChat; + ot.action.ExchangeCards = MyExchangeCards; +}; + + +// Special care is to be taken to safely inject our javascript into the websiet +// without the website being able to talk back to greasemonkey +// (which would be a security problem) +// see +// https://stackoverflow.com/questions/5006460/userscripts-greasemonkey-calling-a-websites-javascript-functions +// and the excellent answer by Wayne for details on this +function exec(fn) { + var script = document.createElement('script'); + script.setAttribute("type", "application/javascript"); + script.textContent = '(' + fn + ')();'; + document.body.appendChild(script); // run the script + document.body.removeChild(script); // clean up +} + +exec(injectCounter);