654 lines
21 KiB
JavaScript
654 lines
21 KiB
JavaScript
// ==UserScript==
|
|
// @name onlinetichu.com card counter
|
|
// @version 1.2.3
|
|
// @description automatically count cards at onlinetichu.com
|
|
// @match *://*.onlinetichu.com/Site/Game/Table/*
|
|
// @author Maximilian Keßler
|
|
// @namespace https://gitlab.com/kesslermaximilian/onlinetichu-counter
|
|
// @license MIT
|
|
// ==/UserScript==
|
|
|
|
// disable auto fold functionality completely
|
|
function injectCounter() {
|
|
if (ot.AutoFold) {
|
|
ot.$autoFold.click()
|
|
ot.$autoFold.hide()
|
|
}
|
|
|
|
var myStyles = `
|
|
#playedHigh {
|
|
position: absolute;
|
|
top: 45px;
|
|
left: 5px;
|
|
width: 935px;
|
|
height: 120px;
|
|
}
|
|
|
|
#playedLow {
|
|
position: absolute;
|
|
top: 170px;
|
|
left: 5px;
|
|
width: 935px;
|
|
height: 120px;
|
|
}
|
|
|
|
#counterField {
|
|
position: absolute;
|
|
width: 945px;
|
|
height: 300px;
|
|
top: 635px;
|
|
border: 1px solid black;
|
|
box-shadow: 1px 1px 1px #555;
|
|
background: #88CC00;
|
|
}
|
|
|
|
#controlBar {
|
|
position: absolute;
|
|
min-height: 32px;
|
|
width: 925px;
|
|
top: 5px;
|
|
left: 5px;
|
|
border-radius: 20px;
|
|
background: #000000;
|
|
}
|
|
|
|
#controlButtonsLeft {
|
|
position: absolute;
|
|
top: 4px;
|
|
left: 15px;
|
|
}
|
|
|
|
#controlButtonsRight {
|
|
position: absolute;
|
|
top: 4px;
|
|
right: 15px;
|
|
}
|
|
|
|
.playedCardsLayout {
|
|
position: absolute;
|
|
height: 125px;
|
|
}
|
|
|
|
.playedCardsLayout .card {
|
|
width: 80px;
|
|
height: 120px;
|
|
border-radius: 5px;
|
|
float: left;
|
|
margin-left: -50px;
|
|
text-align: left;
|
|
box-shadow: 2px 2px 5px #555;
|
|
border: 1px solid #000000;
|
|
}
|
|
|
|
.playedCardsLayout .card:hover {
|
|
z-index: 1400;
|
|
}
|
|
`
|
|
|
|
var styleSheet = document.createElement("style")
|
|
styleSheet.innerText = myStyles;
|
|
console.log(styleSheet);
|
|
document.head.appendChild(styleSheet);
|
|
|
|
var controlBar = document.createElement('div');
|
|
controlBar.id = 'controlBar';
|
|
|
|
var controlButtonsLeft = document.createElement('div');
|
|
controlButtonsLeft.className = 'btn-group';
|
|
controlButtonsLeft.id = 'controlButtonsLeft';
|
|
|
|
var controlButtonsRight = document.createElement('div');
|
|
controlButtonsRight.className = 'btn-group';
|
|
controlButtonsRight.id = 'controlButtonsRight';
|
|
|
|
var davidProtectionButton = document.createElement('button');
|
|
davidProtectionButton.className = "btn btn-success btn-xs";
|
|
davidProtectionButton.id = "davidProtection";
|
|
davidProtectionButton.type = "button";
|
|
davidProtectionButton.innerHTML = 'David protection: <span id="davidProtectionValue" data-on="On" data-off="Off">Off</span>';
|
|
|
|
var autoWishButton = document.createElement('button');
|
|
autoWishButton.className = "btn btn-info btn-xs";
|
|
autoWishButton.id = "autoWish";
|
|
autoWishButton.type = "button";
|
|
autoWishButton.innerHTML = 'Auto Wish: <span id="autoWishValue" data-on="On" data-off="Off">Off</span>';
|
|
|
|
var showRemainingButton = document.createElement('button');
|
|
showRemainingButton.className = "btn btn-info btn-xs";
|
|
showRemainingButton.id = "showRemaining";
|
|
showRemainingButton.type = "button";
|
|
showRemainingButton.innerHTML = 'Show: <span id="showRemainingValue" data-on="Remaining" data-off="Played">Remaining</span>';
|
|
|
|
var showCountedCardsButton = document.createElement('button');
|
|
showCountedCardsButton.className = "btn btn-success btn-xs";
|
|
showCountedCardsButton.id = "showCountedCards";
|
|
showCountedCardsButton.type = "button";
|
|
showCountedCardsButton.innerHTML = 'Show cards: <span id="showCountedCardsValue" data-on="Yes" data-off="No">No</span>';
|
|
|
|
controlButtonsRight.appendChild(showRemainingButton);
|
|
controlButtonsRight.appendChild(showCountedCardsButton);
|
|
controlButtonsLeft.appendChild(davidProtectionButton);
|
|
controlButtonsLeft.appendChild(autoWishButton);
|
|
|
|
controlBar.appendChild(controlButtonsLeft);
|
|
controlBar.appendChild(controlButtonsRight);
|
|
|
|
var counterField = document.createElement("div");
|
|
counterField.id = 'counterField';
|
|
counterField.appendChild(controlBar);
|
|
|
|
// 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;
|
|
|
|
counterField.appendChild(playedHigh);
|
|
counterField.appendChild(playedLow);
|
|
|
|
tableIG = document.getElementById('gameField').parentNode;
|
|
tableIG.appendChild(counterField);
|
|
|
|
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*127 + '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: <span id="smartFoldValue" data-on="On" data-off="Off">On</span>';
|
|
|
|
var showCardCounterButton = document.createElement('button');
|
|
showCardCounterButton.className = "btn btn-primary btn-xs";
|
|
showCardCounterButton.id = "showCardCounter";
|
|
showCardCounterButton.type = "button";
|
|
showCardCounterButton.innerHTML = 'Card Counter: <span id="showCardCounterValue" data-on="On" data-off="Off">No</span>';
|
|
|
|
buttons = document.getElementById('statusButtons');
|
|
buttons.insertBefore(showCardCounterButton, 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'),
|
|
$showCardCounter: $('#showCardCounter'),
|
|
$showCardCounterValue: $('#showCardCounterValue'),
|
|
$showRemaining: $('#showRemaining'),
|
|
$showRemainingValue: $('#showRemainingValue'),
|
|
$showCountedCards: $('#showCountedCards'),
|
|
$showCountedCardsValue: $('#showCountedCardsValue'),
|
|
$davidProtection: $('#davidProtection'),
|
|
$autoWishValue: $('#autoWishValue'),
|
|
$autoWish: $('#autoWish'),
|
|
$davidProtectionValue: $('#davidProtectionValue'),
|
|
$playedHigh: $('#playedHigh'),
|
|
$playedLow: $('#playedLow'),
|
|
$counterField: $('#counterField'),
|
|
|
|
// dynamic game state
|
|
allCards: {},
|
|
playedCards: {},
|
|
totalPlayed: [],
|
|
exchangedTo: {},
|
|
exchangedFrom: {},
|
|
handCardShuffle: [],
|
|
|
|
// config values, triggered with buttons
|
|
smartFold: true,
|
|
showCardCounter: false,
|
|
showRemaining: true,
|
|
showCountedCards: false,
|
|
davidProtection: false,
|
|
autoWish: false,
|
|
shuffleCards: true,
|
|
|
|
// dynamic feature state
|
|
davidProtectionTriggered: true,
|
|
bombAfterFold: null, // to implement
|
|
|
|
util: {
|
|
displayCardsHtmlString: function(cards) {
|
|
htmlString = "";
|
|
$(cards).each(function () {
|
|
var value = this.Value;
|
|
if (this.Shape == 7) {
|
|
value = 0;
|
|
}
|
|
htmlString += '<li id="c' + this.Shape + '-' + value
|
|
+ '" class="card c' + this.Shape + '-' + value
|
|
+ '" data-shape="' + this.Shape + '" data-value="'
|
|
+ value + '"></li>';
|
|
});
|
|
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;
|
|
},
|
|
|
|
extractInt: function(text) {
|
|
num = /\d+(m|k)?/.exec(text)[0];
|
|
if (num.includes('k')) {
|
|
return 1000 * parseInt(num.split('k')[0]);
|
|
} else if (num.includes('m')) {
|
|
return 1000000 * parseInt(num.split('m')[0]);
|
|
}
|
|
return parseInt(num);
|
|
},
|
|
|
|
extractFloat: function(text) {
|
|
num = /\d+(\.\d+)?/.exec(text)[0];
|
|
return parseFloat(num);
|
|
},
|
|
|
|
getStats: function(user) {
|
|
$.get('https://www.onlinetichu.com/Site/Profiles/User/' + user, null, function(text){
|
|
statsNav = $(text).find('#nav-statistics');
|
|
wbox1 = statsNav.children()[1];
|
|
|
|
c1 = wbox1.children[0].children[0].children[1].children;
|
|
c2 = wbox1.children[0].children[0].children[2].children;
|
|
|
|
|
|
var generalStats = {
|
|
level: otc.util.extractInt( c1[0].innerText),
|
|
nextLevelIn: otc.util.extractFloat( c1[1].innerText),
|
|
rating: otc.util.extractInt( c1[2].innerText),
|
|
games: otc.util.extractFloat( c1[3].innerText),
|
|
wins: otc.util.extractFloat( c1[4].innerText.split("-")[0]),
|
|
defeats: otc.util.extractFloat( c1[4].innerText.split("-")[1]),
|
|
winningPercentage: otc.util.extractFloat( c1[5].innerText),
|
|
goldGames: otc.util.extractFloat( c1[6].innerText),
|
|
goldWins: otc.util.extractFloat( c1[7].innerText.split("-")[0]),
|
|
goldDefeats: otc.util.extractFloat( c1[7].innerText.split("-")[1]),
|
|
goldWinningPercentage: otc.util.extractFloat( c1[8].innerText),
|
|
points: otc.util.extractInt( c1[9].innerText),
|
|
rounds: otc.util.extractInt( c1[10].innerText),
|
|
oneTwo: otc.util.extractInt( c1[11].innerText),
|
|
grandTichuPercentage: otc.util.extractFloat( c2[0].innerText),
|
|
grandTichuCalled: otc.util.extractInt( c2[1].innerText),
|
|
grandTichuSuccesful: otc.util.extractInt( c2[2].innerText),
|
|
tichuPercentage: otc.util.extractFloat( c2[3].innerText),
|
|
tichuCalled: otc.util.extractInt( c2[4].innerText),
|
|
tichuSuccesful: otc.util.extractInt( c2[5].innerText),
|
|
tournaments: otc.util.extractInt( c2[6].innerText),
|
|
tournamentsFirstAward: otc.util.extractInt( c2[7].innerText),
|
|
tournamentsSecondAward: otc.util.extractInt( c2[8].innerText),
|
|
abandonments: otc.util.extractInt( c2[9].innerText)
|
|
};
|
|
console.log(generalStats);
|
|
});
|
|
}
|
|
},
|
|
|
|
action: {
|
|
|
|
selectAutoWish: function() {
|
|
if (otc.exchangedTo['east'] == null) {
|
|
return;
|
|
}
|
|
val = 0;
|
|
if (otc.exchangedTo['east'].Shape < 4 ) {
|
|
val = otc.exchangedTo['east'].Value;
|
|
} else if (otc.exchangedTo['east'].Shape == 5) {
|
|
val = 14; // wish for ace by default if we gave a dog to the right
|
|
}
|
|
button = document.getElementById("askCard_" + val);
|
|
button.click();
|
|
},
|
|
|
|
deSelectAutoWish: function() {
|
|
button = document.getElementById("askCard_0");
|
|
button.click();
|
|
},
|
|
|
|
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 {
|
|
index = card.Value;
|
|
}
|
|
otc.playedCards[index].push(card);
|
|
otc.totalPlayed.push(card);
|
|
|
|
otc.playedCards[index].sort(function(c1, c2){
|
|
return c2.Shape - c1.Shape;
|
|
});
|
|
},
|
|
|
|
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)
|
|
);
|
|
}
|
|
},
|
|
|
|
reset: function() {
|
|
for(let i = 1; i < 15; i++) {
|
|
otc.playedCards[i] = [];
|
|
}
|
|
dirs = ['east', 'north', 'west'];
|
|
for (i in dirs) {
|
|
otc.exchangedTo[dirs[i]] = null;
|
|
otc.exchangedFrom[dirs[i]] = null;
|
|
}
|
|
otc.totalPlayed = [];
|
|
otc.handCardShuffle = [];
|
|
},
|
|
|
|
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]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!window.otc) {
|
|
window.otc = OnlineTichuCounter;
|
|
}
|
|
|
|
otc.$counterField.hide();
|
|
|
|
// 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'));
|
|
}
|
|
});
|
|
|
|
// add functionality to show button
|
|
otc.$showCardCounter.click(function () {
|
|
otc.showCardCounter = !otc.showCardCounter;
|
|
if (otc.showCardCounter) {
|
|
otc.$showCardCounterValue.text(otc.$showCardCounterValue.data('on'));
|
|
otc.$counterField.show();
|
|
} else {
|
|
otc.$showCardCounterValue.text(otc.$showCardCounterValue.data('off'));
|
|
otc.$counterField.hide();
|
|
}
|
|
});
|
|
|
|
otc.$showCountedCards.click(function () {
|
|
otc.showCountedCards = !otc.showCountedCards;
|
|
if (otc.showCountedCards) {
|
|
otc.$showCountedCardsValue.text(otc.$showCountedCardsValue.data('on'));
|
|
otc.$playedHigh.show();
|
|
otc.$playedLow.show();
|
|
} else {
|
|
otc.$showCountedCardsValue.text(otc.$showCountedCardsValue.data('off'));
|
|
otc.$playedHigh.hide();
|
|
otc.$playedLow.hide();
|
|
}
|
|
});
|
|
|
|
otc.$davidProtection.click(function () {
|
|
otc.davidProtection = !otc.davidProtection;
|
|
if (otc.davidProtection) {
|
|
otc.$davidProtectionValue.text(otc.$davidProtectionValue.data('on'));
|
|
} else {
|
|
otc.$davidProtectionValue.text(otc.$davidProtectionValue.data('off'));
|
|
}
|
|
});
|
|
|
|
otc.$autoWish.click(function () {
|
|
otc.autoWish = !otc.autoWish;
|
|
if (otc.autoWish) {
|
|
otc.$autoWishValue.text(otc.$autoWishValue.data('on'));
|
|
otc.action.selectAutoWish();
|
|
} else {
|
|
otc.$autoWishValue.text(otc.$autoWishValue.data('off'));
|
|
otc.action.deSelectAutoWish();
|
|
}
|
|
});
|
|
|
|
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.reset();
|
|
otc.util.populateAllCards();
|
|
|
|
// overwrite functionality of fold button
|
|
ot.$fold.unbind();
|
|
ot.$fold.hide().click(function () {
|
|
if (otc.davidProtection) {
|
|
if(ot.$passCards().length != 0 && !otc.davidProtectionTriggered) {
|
|
console.log('david protection triggered');
|
|
ot.$gameMessage.text("Selected cards detected. Press again to fold!");
|
|
ot.HorizontalAlign(ot.$gameMessage);
|
|
otc.davidProtectionTriggered = true;
|
|
return;
|
|
}
|
|
}
|
|
ot.action.Fold();
|
|
otc.davidProtectionTriggered = false;
|
|
$(this).hide();
|
|
});
|
|
|
|
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.totalPlayed.length != 0) {
|
|
otc.action.reset();
|
|
}
|
|
|
|
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) {
|
|
if (otc.smartFold) {
|
|
if(this.MustFold) {
|
|
ot.action.Fold();
|
|
console.log('smart fold activated');
|
|
} else {
|
|
console.log('prevented bug by not smartfolding');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
MyChat = (function() {
|
|
var cachedFunction = ot.reaction.Chat;
|
|
|
|
return function() {
|
|
var result = cachedFunction.apply(this, arguments);
|
|
|
|
message = arguments[0];
|
|
if (message.User.Username === "System") {
|
|
var messageArray = message.Text.replace(/</g, '<').replace(/>/g, '>').split(' ');
|
|
message.Text = messageArray.join(' ');
|
|
messageArray = message.Text.replace(/</g, '<').replace(/>/g, '>').split(' ');
|
|
|
|
for(var i in messageArray) {
|
|
if(messageArray[i] == "dogs") {
|
|
otc.action.handlePlayedCard({
|
|
"Shape": 5,
|
|
"Value": 0
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
})();
|
|
|
|
MyExchangeCards = (function() {
|
|
var cachedFunction = ot.action.ExchangeCards;
|
|
|
|
return function() {
|
|
|
|
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);
|
|
|
|
if(otc.autoWish) {
|
|
otc.action.selectAutoWish();
|
|
} else {
|
|
otc.action.deSelectAutoWish();
|
|
}
|
|
|
|
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 website
|
|
// 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);
|