{"action":"created","comment":{"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments/49699681","id":49699681,"diff_hunk":"@@ -0,0 +1,694 @@\n+/*\n+\tUNO Game for PS\n+\n+\tby sparkychild\n+*/\n+'use strict';\n+const deck = [\"R1\",\n+\t\"R2\",\n+\t\"R3\",\n+\t\"R4\",\n+\t\"R5\",\n+\t\"R6\",\n+\t\"R7\",\n+\t\"R8\",\n+\t\"R9\",\n+\t\"RS\",\n+\t\"RR\",\n+\t\"R+2\",\n+\t\"Z+4\",\n+\t\"Y1\",\n+\t\"Y2\",\n+\t\"Y3\",\n+\t\"Y4\",\n+\t\"Y5\",\n+\t\"Y6\",\n+\t\"Y7\",\n+\t\"Y8\",\n+\t\"Y9\",\n+\t\"YS\",\n+\t\"YR\",\n+\t\"Y+2\",\n+\t\"Z+4\",\n+\t\"G1\",\n+\t\"G2\",\n+\t\"G3\",\n+\t\"G4\",\n+\t\"G5\",\n+\t\"G6\",\n+\t\"G7\",\n+\t\"G8\",\n+\t\"G9\",\n+\t\"GS\",\n+\t\"GR\",\n+\t\"G+2\",\n+\t\"Z+4\",\n+\t\"B1\",\n+\t\"B2\",\n+\t\"B3\",\n+\t\"B4\",\n+\t\"B5\",\n+\t\"B6\",\n+\t\"B7\",\n+\t\"B8\",\n+\t\"B9\",\n+\t\"BS\",\n+\t\"BR\",\n+\t\"B+2\",\n+\t\"Z+4\",\n+\t\"R1\",\n+\t\"R2\",\n+\t\"R3\",\n+\t\"R4\",\n+\t\"R5\",\n+\t\"R6\",\n+\t\"R7\",\n+\t\"R8\",\n+\t\"R9\",\n+\t\"RS\",\n+\t\"RR\",\n+\t\"R+2\",\n+\t\"ZW\",\n+\t\"R0\",\n+\t\"Y1\",\n+\t\"Y2\",\n+\t\"Y3\",\n+\t\"Y4\",\n+\t\"Y5\",\n+\t\"Y6\",\n+\t\"Y7\",\n+\t\"Y8\",\n+\t\"Y9\",\n+\t\"YS\",\n+\t\"YR\",\n+\t\"Y+2\",\n+\t\"ZW\",\n+\t\"Y0\",\n+\t\"G1\",\n+\t\"G2\",\n+\t\"G3\",\n+\t\"G4\",\n+\t\"G5\",\n+\t\"G6\",\n+\t\"G7\",\n+\t\"G8\",\n+\t\"G9\",\n+\t\"GS\",\n+\t\"GR\",\n+\t\"G+2\",\n+\t\"ZW\",\n+\t\"G0\",\n+\t\"B1\",\n+\t\"B2\",\n+\t\"B3\",\n+\t\"B4\",\n+\t\"B5\",\n+\t\"B6\",\n+\t\"B7\",\n+\t\"B8\",\n+\t\"B9\",\n+\t\"BS\",\n+\t\"BR\",\n+\t\"B+2\",\n+\t\"ZW\",\n+\t\"B0\",\n+];\n+//declare html for DRAW and PASS button.\n+const drawButton = '<center><button style=\"background: black; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 56px ; border-radius: 5px , auto\" name=\"send\" value=\"/uno draw\"><font color=\"white\">Draw</font></button></center>';\n+const passButton = '<center><button style=\"background: red; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 56px ; border-radius: 5px , auto\" name=\"send\" value=\"/uno pass\"><font color=\"white\">PASS</font></button></center>';\n+\n+//get colour for html'd text and backgrounds\n+function getColour(colour, background) {\n+\tif (!background && colour === \"Y\") return \"orange\";\n+\tlet colourTable = {\n+\t\t\"R\": \"red\",\n+\t\t\"Y\": \"yellow\",\n+\t\t\"B\": \"blue\",\n+\t\t\"G\": \"green\",\n+\t\t\"Z\": \"black\",\n+\t};\n+\treturn colourTable[colour];\n+}\n+\n+//build html button for the card\n+function buildCard(id, notClickable) {\n+\tlet colour = getColour(id.charAt(0), true);\n+\tlet value = id.slice(1);\n+\tlet fontColour = colour === \"yellow\" ? \"black\" : \"white\";\n+\tlet command = \"/uno play \" + id;\n+\tlet clickable = notClickable ? \">\" : \"name=\\\"send\\\" value=\\\"\" + command + \"\\\">\";\n+\tlet title = \"title=\\\"\" + getCardName(id) + \"\\\"\";\n+\tlet buttonFace = value === \"W\" ? '<img src=\"https://www.script-tutorials.com/demos/317/thumb.png\" height=\"27\" width=\"27\">' : '<font color=\"' + fontColour + \"\\\" size=6>\" + value + \"</font>\";\n+\tlet button = \"<button \" + title + \" style=\\\"background: \" + colour + \"; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; height: 80px ; width: 56px ; border-radius: 5px , auto\\\"\" + clickable + buttonFace + \"</button>\";\n+\treturn button;\n+}\n+\n+//build an display of multiple cards\n+function buildHand(array, notClickable) {\n+\tlet hand = [];\n+\tarray.sort().forEach(function (c) {\n+\t\thand.push(buildCard(c, notClickable));\n+\t});\n+\treturn hand.join(\"&nbsp;\");\n+}\n+\n+\n+function initDeck(playerCount) {\n+\tplayerCount = Math.ceil(playerCount / 7);\n+\tlet tDeck = [];\n+\tfor (let i = 0; i < playerCount; i++) {\n+\t\ttDeck = tDeck.concat(deck);\n+\t}\n+\treturn tDeck;\n+}\n+\n+function shuffleDeck(dArray) {\n+\tlet tDeck = [];\n+\tlet reiterations = dArray.length;\n+\tfor (let i = 0; i < reiterations; i++) {\n+\t\tlet rand = ~~(dArray.length * Math.random());\n+\t\ttDeck.push(dArray[rand]);\n+\t\tdArray.splice(rand, 1);\n+\t}\n+\treturn tDeck;\n+}\n+\n+function getCardName(id, colour) {\n+\tlet type = {\n+\t\t\"R\": \"Red\",\n+\t\t\"Y\": \"Yellow\",\n+\t\t\"B\": \"Blue\",\n+\t\t\"G\": \"Green\",\n+\t\t\"Z\": \"Wild\",\n+\t};\n+\tlet value = {\n+\t\t\"1\": \" 1\",\n+\t\t\"2\": \" 2\",\n+\t\t\"3\": \" 3\",\n+\t\t\"4\": \" 4\",\n+\t\t\"5\": \" 5\",\n+\t\t\"6\": \" 6\",\n+\t\t\"7\": \" 7\",\n+\t\t\"8\": \" 8\",\n+\t\t\"9\": \" 9\",\n+\t\t\"0\": \" 0\",\n+\t\t\"R\": \" Reverse\",\n+\t\t\"S\": \" Skip\",\n+\t\t\"+2\": \" Draw Two\",\n+\t\t\"+4\": \" Draw Four\",\n+\t\t\"W\": \"card\",\n+\t};\n+\tif (colour) return \"<font color=\\\"\" + type[id.charAt(0)].toLowerCase().replace(\"yellow\", \"orange\") + \"\\\">\" + type[id.charAt(0)] + value[id.slice(1)] + \"</font>\";\n+\treturn type[id.charAt(0)] + value[id.slice(1)];\n+}\n+\n+\n+function buildGameScreen(uhtmlid, top, roomid, hand, message, change, pass) {\n+\tlet html = (message ? \"|uhtmlchange|\" + uhtmlid : \"|uhtml|\" + uhtmlid) + \"|\";\n+\t//make top card not clickable\n+\tlet topCard = \"<center>\" + buildCard(top, true) + \"</center>\";\n+\tif (change) {\n+\t\ttopCard += \"<br><center>Colour changed to: <font color=\\\"\" + getColour(change) + \"\\\">\" + getColour(change, true) + \"</font></center>\";\n+\t}\n+\tlet yourHand = buildHand(hand);\n+\tmessage = message ? \"<font color=\\\"red\\\"><b>\" + message + \"</b></font>\" : \"\";\n+\treturn html + \"<table border=1 style=\\\"border-collapse: collapse;\\\"><tr><td>&nbsp;<b>Top Card</b>&nbsp;</td><td>&nbsp;<b>Your Hand</b>&nbsp;</td></tr>\" + \"<tr><td>\" + topCard + \"</td><td>\" + yourHand + \"</td></tr><tr><td>\" + (pass ? passButton : drawButton) + \"</td><td>\" + message + \"</td></tr></table>\";\n+}\n+\n+//for wildcards that summon a colour change\n+function getColourChange(buffer, hand, uhtmlid) {\n+\treturn \"|uhtmlchange|\" + uhtmlid + \"|<table border=1 style=\\\"border-collapse: collapse;\\\"><tr><td>Choose which colour to change to:<br>\" + '<button style=\"background: red; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 80px ; border-radius: 5px , auto\" name=\"send\" value=\"' + buffer + ' R\"><font color=\"white\" size=4>Red</font></button></center>' + '<button style=\"background: yellow; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 80px ; border-radius: 5px , auto\" name=\"send\" value=\"' + buffer + ' Y\"><font color=\"black\" size=4>Yellow</font></button></center>' + '<button style=\"background: blue; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 80px ; border-radius: 5px , auto\" name=\"send\" value=\"' + buffer + ' B\"><font color=\"white\" size=4>Blue</font></button></center>' + '<button style=\"background: green; border: 2px solid rgba(33 , 68 , 72 , 0.59) ; width: 80px ; border-radius: 5px , auto\" name=\"send\" value=\"' + buffer + ' G\"><font color=\"white\" size=4>Green</font></button></td></tr>' + '<tr><td>Your Cards: <br>' + buildHand(hand, true) + '</td></tr></table>';\n+}\n+\n+function getUserName(id) {\n+\treturn Users(id) ? Users(id).name : id;\n+}\n+\n+class Game {\n+\tconstructor(room, playerCap) {\n+\t\tif (!room.unoGameId) {\n+\t\t\troom.unoGameId = 0;\n+\t\t}\n+\t\troom.unoGameId++;\n+\t\tthis.room = room;\n+\t\tthis.id = 0;\n+\t\tthis.top = null;\n+\t\tthis.discard = [];\n+\t\tthis.deck = null;\n+\t\t//for player order\n+\t\tthis.list = [];\n+\t\tthis.data = {};\n+\t\tthis.joinedIps = {};\n+\t\tthis.player = null;\n+\t\tthis.gameid = \"uno\";\n+\t\tthis.started = false;\n+\t\tthis.timer = null;\n+\t\tthis.lastDraw = null;\n+\t\tthis.colourChange = null;\n+\t\tthis.uhtmlChange = null;\n+\t\tthis.playerCap = playerCap ? playerCap : null;\n+\t}\n+\n+\tinit() {\n+\t\tthis.room.add(\"|uhtml|new\" + this.room.unoGameId + \"|<div class=\\\"broadcast-green\\\"><center><img src=\\\"http://www.theboardgamefamily.com/wp-content/uploads/2010/12/uno-mobile-game1.jpg\\\" height=150 width=160><br><font color=white><b>A new game of UNO is starting</b></font><br><button style=\\\"height: 25px ; width: 50px ;\\\" name=\\\"send\\\" value=\\\"/uno join\\\">Join</button></center></div>\");\n+\t}\n+\n+\tjoin(user) {\n+\t\tif (this.started) return false;\n+\t\tlet ip = user.latestIp;\n+\t\tlet userid = user.userid;\n+\n+\t\tif (this.playerCap && this.list.length >= this.playerCap) {\n+\t\t\treturn user.sendTo(this.room, \"The game is already full.\");\n+\t\t}\n+\n+\t\tif (userid in this.data || ip in this.joinedIps) {\n+\t\t\treturn user.sendTo(this.room, \"You have already have an alt joined.\");\n+\t\t}\n+\n+\t\tthis.list.push(userid);\n+\t\t//init empty hand\n+\t\tthis.data[userid] = [];\n+\t\tthis.joinedIps[ip] = 1;\n+\t\t//make join messages clear away after game starts\n+\t\tthis.room.add(\"|uhtml|init\" + this.room.unoGameId + \"|\" + user.name + \" has joined the game.\");\n+\t}\n+\n+\tstart(user) {\n+\t\tif (this.started) return false;\n+\t\tif (this.list.length < 2) return user.sendTo(this.room, \"There aren't enough players!\");\n+\t\tthis.started = true;\n+\t\tthis.room.add(\"The game has started!\");\n+\t\t//hide the start message\n+\t\tthis.room.add(\"|uhtmlchange|new\" + this.room.unoGameId + \"|<div class=\\\"infobox\\\">The game has started.</div>\");\n+\t\t//get first player\n+\t\tthis.player = this.list[~~(Math.random() * this.list.length)];\n+\t\tthis.room.add(\"The first player is: \" + getUserName(this.player) + \".\");\n+\n+\t\t//create the deck\n+\t\tthis.deck = shuffleDeck(initDeck(this.list.length));\n+\n+\t\t//deal the cards\n+\t\tthis.list.forEach(function (u) {\n+\t\t\tthis.giveCard(u, 7);\n+\t\t}.bind(this));\n+\n+\t\t//get the top card and put it into discard pile\n+\t\twhile (!this.top || this.top.charAt(0) === \"Z\") {\n+\t\t\tthis.top = this.deck.shift();\n+\t\t\tthis.discard.push(this.top);\n+\t\t}\n+\t\t//declare the top card\n+\t\tthis.room.add(\"|uhtml|\" + this.room.unoGameId + \"card\" + this.id + \"|\" + \"The top card is \" + buildCard(this.top, true));\n+\t\tthis.uhtmlChange = \"|uhtmlchange|\" + this.room.unoGameId + \"card\" + this.id + \"|The top card is <b>\" + getCardName(this.top, true) + \"</b>.\";\n+\n+\t\tthis.applyEffects();\n+\n+\t\tthis.initNextTurn();\n+\t}\n+\n+\tgiveCard(userid, number, display) {\n+\t\tif (!number) number = 1;\n+\t\tlet newCards = [];\n+\t\tfor (let i = 0; i < number; i++) {\n+\t\t\tlet newCard = this.deck.shift();\n+\t\t\tthis.data[userid].push(newCard);\n+\t\t\tnewCards.push(newCard);\n+\t\t\t//shuffle deck if deck is empty\n+\t\t\tif (this.deck.length === 0) {\n+\t\t\t\tif (this.discard.length === 0) {\n+\t\t\t\t\t//if no cards in discard pile, add a new deck.\n+\t\t\t\t\tthis.discard = initDeck(1);\n+\t\t\t\t}\n+\t\t\t\t//shuffle discard pile to create new deck for drawing\n+\t\t\t\tthis.deck = shuffleDeck(this.discard);\n+\t\t\t}\n+\t\t}\n+\t\tif (display && Users(userid)) {\n+\t\t\treturn Users(userid).sendTo(this.room, \"|raw|You have drawn the following card(s): \" + buildHand(newCards, true));\n+\t\t}\n+\t\t//only for draw 1\n+\t\tif (newCards.length === 1) return newCards[0];\n+\t}\n+\n+\tgetNextPlayer(number) {\n+\t\t//make list run over if it's at the last player\n+\t\tlet playerList = this.list.concat(this.list);\n+\t\t//get index of current player\n+\t\tlet index = playerList.indexOf(this.player);\n+\t\t//apply next player\n+\t\tthis.player = playerList[index + (number || 1)];\n+\t}\n+\n+\tapplyEffects() {\n+\t\tlet effect = this.top.slice(1);\n+\t\tswitch (effect) {\n+\t\tcase \"R\":\n+\t\t\t//reverse; turn the array of players upside down.\n+\t\t\tthis.list = this.list.reverse();\n+\t\t\tthis.room.add(\"The direction has been reversed!\");\n+\t\t\tif (this.id === 0) {\n+\t\t\t\tthis.getNextPlayer();\n+\t\t\t\tbreak;\n+\t\t\t} else if (this.list.length === 2) {\n+\t\t\t\t//skip back to the player that played the card\n+\t\t\t\tthis.getNextPlayer();\n+\t\t\t} else {\n+\t\t\t\t//skip back two slots to the player before the user who played the card\n+\t\t\t\tthis.getNextPlayer(2);\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase \"S\":\n+\t\t\tthis.room.add(getUserName(this.player) + \" has turn has been skipped!\");\n+\t\t\t//skip the player and move on to the next;\n+\t\t\tthis.getNextPlayer();\n+\t\t\tbreak;\n+\t\tcase \"+2\":\n+\t\t\tthis.room.add(getUserName(this.player) + \" has turn has been skipped, and is forced to draw 2 cards!\");\n+\t\t\t//give 2 cards\n+\t\t\tthis.giveCard(this.player, 2, true);\n+\t\t\t//skip the player\n+\t\t\tthis.getNextPlayer();\n+\t\t\tbreak;\n+\t\tcase \"+4\":\n+\t\t\tthis.room.add(getUserName(this.player) + \" has turn has been skipped, and is forced to draw 4 cards!\");\n+\t\t\t//give 4 cards\n+\t\t\tthis.giveCard(this.player, 4, true);\n+\t\t\t//skip the player\n+\t\t\tthis.getNextPlayer();\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tvalidatePlay(user, card) {\n+\t\t//returning false means there are no issues;\n+\t\t//otherwise this will return a error message which will be displayed to the user when it builds the next control screen.\n+\t\tlet hand = this.data[user.userid];\n+\t\tif (this.lastDraw && card !== this.lastDraw) {\n+\t\t\treturn \"You must play the last card you drew! (\" + getCardName(this.lastDraw) + \")\";\n+\t\t}\n+\t\tif (hand.indexOf(card) === -1) return \"You do not have that card!\";\n+\t\tlet currentColour = this.colourChange || this.top.charAt(0);\n+\t\tlet currentValue = this.top.slice(1);\n+\t\t//verify that the player has no cards of the same colour in their hand\n+\t\tif (card === \"Z+4\") {\n+\t\t\tfor (let i = 0; i < hand.length; i++) {\n+\t\t\t\tif (hand[i].charAt(0) === currentColour) return \"You cannot play this when you still have a card with the same colour as the top card.\";\n+\t\t\t}\n+\t\t\treturn false;\n+\t\t}\n+\t\t//wild cards can be played anytime\n+\t\tif (card === \"ZW\") return false;\n+\t\t//check if the card is either the same value or the same colour\n+\t\tif (card.charAt(0) === currentColour || card.slice(1) === currentValue) return false;\n+\t\treturn \"The card has to either match the top card's colour or face value.\";\n+\t}\n+\n+\tplay(user, card, change) {\n+\t\t//check if it's that players turn\n+\t\tif (this.player !== user.userid) return;\n+\t\t//check validity of play and send error message\n+\t\tlet issues = this.validatePlay(user, card);\n+\t\tif (issues) {\n+\t\t\treturn this.sendGameScreen(user, issues);\n+\t\t}\n+\t\tthis.colourChange = null;\n+\t\tthis.clearTimer();\n+\t\t//shrink last turn's card\n+\t\tthis.room.add(this.uhtmlChange);\n+\t\tthis.clearGameScreen(user);\n+\n+\t\t//clear last draw\n+\t\tthis.lastDraw = null;\n+\n+\t\t//announce the card and the change\n+\t\tthis.room.add(\"|uhtml|\" + this.room.unoGameId + \"card\" + this.id + \"|\" + user.name + \" played \" + buildCard(card, true));\n+\t\tthis.uhtmlChange = \"|uhtmlchange|\" + this.room.unoGameId + \"card\" + this.id + \"|\" + user.name + \" played <b>\" + getCardName(card, true) + \"</b>.\";\n+\n+\t\t//move card onto top and discard pile\n+\t\tthis.top = card;\n+\t\tthis.discard.push(card);\n+\n+\t\t//remove the card from the players hand\n+\t\tthis.data[user.userid].splice(this.data[user.userid].indexOf(card), 1);\n+\n+\t\t//count cards\n+\t\tif (change) {\n+\t\t\tthis.colourChange = change;\n+\t\t\tlet fontColour = getColour(change);\n+\t\t\tthis.room.add(\"|raw|<font color=\\\"\" + fontColour + \"\\\">The colour was changed to <b>\" + getColour(change, true).toUpperCase() + \"</b>.</font>\");\n+\t\t}\n+\t\t//move to next player\n+\t\tthis.getNextPlayer();\n+\t\tthis.room.update();\n+\n+\t\t//apply the effects of the current card to the next player in queue.\n+\t\tthis.applyEffects();\n+\t\tif (this.data[user.userid].length === 1) {\n+\t\t\t//do a uno thing\n+\t\t\tthis.uno = user.userid;\n+\t\t\tlet userButton = \"<center><button style=\\\"height: 75px ; width: 200px ;\\\" name=\\\"send\\\" value=\\\"/uno uno\\\">UNO!</button></center>\";\n+\t\t\tuser.sendTo(this.room.id, \"|uhtml|\" + this.room.unoGameId + \"uno\" + this.id + \"|\" + userButton);\n+\t\t\t//send individual button to all the other players\n+\t\t\tlet opponentButton = \"<center><button style=\\\"height: 75px ; width: 200px ;\\\" name=\\\"send\\\" value=\\\"/uno uno\\\">Make \" + user.name + \" draw 2 cards! </button></center>\";\n+\t\t\tfor (let u in this.data) {\n+\t\t\t\tif (!Users(u) || u === user.userid) continue;\n+\t\t\t\tUsers(u).sendTo(this.room.id, \"|uhtml|\" + this.room.unoGameId + \"uno\" + this.id + \"|\" + opponentButton);\n+\t\t\t}\n+\t\t\treturn;\n+\t\t} else if (this.data[user.userid].length === 0) {\n+\t\t\treturn this.end(user.name);\n+\t\t}\n+\t\t//start next turn\n+\t\tthis.initNextTurn();\n+\t}\n+\n+\tdraw(user) {\n+\t\tif (this.player !== user.userid || this.lastDraw) return;\n+\t\tthis.lastDraw = this.giveCard(user.userid, 1);\n+\t\t//clean up last display\n+\t\tthis.clearGameScreen(user);\n+\t\tthis.sendGameScreen(user, \"You have drawn a \" + getCardName(this.lastDraw) + \".\");\n+\t\tthis.room.add(user.name + \" has drawn a card.\");\n+\t\tthis.room.update();\n+\t}\n+\n+\tpass(user) {\n+\t\tif (this.player !== user.userid || !this.lastDraw) return;\n+\t\tthis.room.add(user.name + \" has passed.\");\n+\t\tthis.room.add(this.uhtmlChange);\n+\t\tthis.clearGameScreen(user);\n+\t\tthis.clearTimer();\n+\t\tthis.getNextPlayer();\n+\t\tthis.id++;\n+\t\tthis.lastDraw = null;\n+\t\tthis.initNextTurn();\n+\t}\n+\n+\tsendGameScreen(user, message) {\n+\t\tlet display = buildGameScreen(this.room.unoGameId + \"display\" + this.id, this.top, this.room.id, this.data[user.userid], message ? message : \"\", this.colourChange, this.lastDraw ? 1 : 0);\n+\t\tuser.sendTo(this.room, display);\n+\t}\n+\n+\tclearGameScreen(user) {\n+\t\tuser.sendTo(this.room, \"|uhtmlchange|\" + this.room.unoGameId + \"display\" + this.id + \"|\");\n+\t}\n+\n+\tclearTimer() {\n+\t\tclearTimeout(this.timer);\n+\t}\n+\n+\trunDQ() {\n+\t\t//set a disqualification timer for 90 seconds\n+\t\tthis.timer = setTimeout(function () {\n+\t\t\tthis.disqualify(this.player);\n+\t\t}.bind(this), 90000);\n+\t}\n+\n+\tinitNextTurn() {\n+\t\tthis.room.add(getUserName(this.player) + \"'s turn.\");\n+\t\tthis.room.update();\n+\t\tthis.id++;\n+\t\tlet user = Users.get(this.player);\n+\t\tif (!user) this.disqualify(this.player);\n+\t\tthis.sendGameScreen(user);\n+\t\tthis.runDQ();\n+\t}\n+\n+\tdisqualify(userid) {\n+\t\t//if there are still players in the game.\n+\t\tif (this.list.length > 2) {\n+\t\t\t//if current player is the one being disqualify move on to next player.\n+\t\t\tif (!this.removePlayer(userid)) return true;\n+\t\t\tif (userid === this.player) {\n+\t\t\t\tif (Users.get(userid)) {\n+\t\t\t\t\tthis.clearGameScreen(Users.get(userid));\n+\t\t\t\t\tthis.room.add(this.uhtmlChange);\n+\t\t\t\t}\n+\t\t\t\tthis.clearTimer();\n+\t\t\t\tthis.room.add(getUserName(userid) + \" has been disqualified.\");\n+\t\t\t\tthis.getNextPlayer();\n+\t\t\t\tthis.initNextTurn();\n+\t\t\t\treturn true;\n+\t\t\t}\n+\t\t\tthis.room.add(getUserName(userid) + \" has been disqualified.\");\n+\t\t\treturn true;\n+\t\t} else {\n+\t\t\tif (this.removePlayer(userid)) {\n+\t\t\t\tthis.room.add(getUserName(userid) + \" has been disqualified.\");\n+\t\t\t\tthis.end(this.list[0]);\n+\t\t\t\treturn false;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tremovePlayer(userid) {\n+\t\tif (this.list.indexOf(userid) === -1) return false;\n+\t\tthis.list.splice(this.list.indexOf(userid), 1);\n+\t\tdelete this.data[userid];\n+\t\treturn true;\n+\t}\n+\n+\tparseUNO(user) {\n+\t\tif (!this.uno) return false;\n+\t\tif (user.userid === this.uno) {\n+\t\t\tthis.room.add(\"|raw|<b>UNO!</b>\");\n+\t\t\tthis.room.add(\"|uhtmlchange|\" + this.room.unoGameId + \"uno\" + this.id + \"|\" + getUserName(this.uno) + \" is safe!\");\n+\t\t\tthis.room.update();\n+\t\t\tthis.uno = false;\n+\t\t\tthis.initNextTurn();\n+\t\t} else if (this.list.indexOf(user.userid) > -1) {\n+\t\t\tthis.room.add(\"|raw|\" + getUserName(this.uno) + \"  was caught for not saying UNO and is forced to draw 2 cards!\");\n+\t\t\tthis.room.add(\"|uhtmlchange|\" + this.room.unoGameId + \"uno\" + this.id + \"|\" + getUserName(this.uno) + \" was caught!\");\n+\t\t\tthis.giveCard(this.uno, 2, true);\n+\t\t\tthis.uno = false;\n+\t\t\tthis.initNextTurn();\n+\t\t}\n+\t}\n+\n+\tend(winner) {\n+\t\t//hide the start message\n+\t\tthis.clearTimer();\n+\t\tif (this.player && Users.get(this.player)) {\n+\t\t\tthis.clearGameScreen(Users.get(this.player));\n+\t\t}\n+\t\tif (this.uhtmlChange) this.room.add(this.uhtmlChange);\n+\t\tthis.room.add(\"|uhtmlchange|new\" + this.room.unoGameId + \"|<div class=\\\"infobox\\\">The game has ended.</div>\");\n+\t\tif (!winner) {\n+\t\t\tthis.room.add(\"The game of UNO was forcibly ended.\");\n+\t\t} else {\n+\t\t\tthis.room.add(\"Congratulations to \" + getUserName(winner) + \" for winning the game of UNO!\");\n+\t\t}\n+\t\tthis.room.update();\n+\t\tdelete this.room.game;\n+\t}\n+}\n+\n+exports.commands = {\n+\tuno: {\n+\t\tnew: function (target, room, user) {\n+\t\t\tif (!this.can(\"announce\", null, room)) return false;\n+\t\t\tif (room.unoDisabled) return this.errorReply(\"UNO is currently disabled in this room.\");\n+\t\t\tlet cap = target ? parseInt(target, 10) : null;\n+\t\t\tif (room.game) return this.errorReply(\"There is already a game in progress in this room.\");\n+\t\t\tif (cap && cap < 2) return this.errorReply(\"The player cap has to be at least 2.\");\n+\n+\t\t\troom.game = new Game(room, cap);\n+\t\t\t//start message;\n+\t\t\troom.game.init();\n+\t\t},\n+\t\tjoin: function (target, room, user) {\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.join(user);\n+\t\t},\n+\t\tstart: function (target, room, user) {\n+\t\t\tif (!this.can(\"announce\", null, room)) return false;\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.start(user);\n+\t\t},\n+\t\tend: function (target, room, user) {\n+\t\t\tif (!this.can(\"announce\", null, room)) return false;\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.end();\n+\t\t},\n+\t\tleave: function (target, room, user) {\n+\t\t\tif (room.game && room.game.gameid === \"uno\" && !room.game.started) {\n+\t\t\t\tlet success = room.game.removePlayer(user.userid);\n+\t\t\t\tif (!success) return user.sendTo(this.room, \"You have not signed up for the game.\");\n+\t\t\t\tlet ip = user.latestIp;\n+\t\t\t\tdelete room.game.joinedIps[ip];\n+\t\t\t\troom.add(\"|uhtml|init\" + room.unoGameId + \"|\" + user.name + \" has left the game.\");\n+\t\t\t}\n+\t\t},\n+\t\tplay: function (target, room, user) {\n+\t\t\tif (!room.game || room.game.gameid !== \"uno\") return false;\n+\t\t\tif (!target) return this.parse(\"/help uno play\");\n+\t\t\tlet params = target.split(\" \");\n+\t\t\tlet card = params.shift();\n+\t\t\tlet change = null;\n+\t\t\tif (card.charAt(0) === \"Z\" && [\"R\", \"Y\", \"B\", \"G\"].indexOf(params[0]) > -1) {\n+\t\t\t\tchange = params[0];\n+\t\t\t} else if (card.charAt(0) === \"Z\") {\n+\t\t\t\tlet uhtmlid = room.unoGameId + \"display\" + room.game.id;\n+\t\t\t\treturn user.sendTo(room, getColourChange(\"/uno play \" + card, room.game.data[user.userid], uhtmlid));\n+\t\t\t}\n+\t\t\troom.game.play(user, card, change);\n+\t\t},\n+\t\tdraw: function (target, room, user) {\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.draw(user);\n+\t\t},\n+\t\tpass: function (target, room, user) {\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.pass(user);\n+\t\t},\n+\t\tdq: function (target, room, user) {\n+\t\t\tif (!this.can(\"announce\", null, room)) return false;\n+\t\t\tif (!target) return this.parse(\"/help uno dq\");\n+\t\t\tif (room.game && room.game.gameid === \"uno\") room.game.disqualify(toId(target));\n+\t\t},\n+\t\tdqhelp: [\"/uno dq [user] - disqualifies a user from the game.\"],\n+\t\tdisplay: function (target, room, user) {\n+\t\t\tif (!room.game || room.game.gameid !== \"uno\" || user.userid !== room.game.player) return false;\n+\t\t\troom.game.clearGameScreen(user);\n+\t\t\troom.game.id++;\n+\t\t\troom.game.sendGameScreen(user);\n+\t\t},\n+\t\tuno: function (target, room, user) {\n+\t\t\tif (room.game && room.game.gameid === \"uno\" && room.game.started) {\n+\t\t\t\troom.game.parseUNO(user);\n+\t\t\t}\n+\t\t},\n+\t\tenable: function (target, room, user) {\n+\t\t\tif (!this.can('tournamentsmanagement', null, room)) return;","path":"chat-plugins/uno.js","position":658,"original_position":658,"commit_id":"98221cf51e5979953a5587a4cb40a2c034282e55","original_commit_id":"98221cf51e5979953a5587a4cb40a2c034282e55","user":{"login":"Zarel","id":551184,"avatar_url":"https://avatars.githubusercontent.com/u/551184?v=3","gravatar_id":"","url":"https://api.github.com/users/Zarel","html_url":"https://github.com/Zarel","followers_url":"https://api.github.com/users/Zarel/followers","following_url":"https://api.github.com/users/Zarel/following{/other_user}","gists_url":"https://api.github.com/users/Zarel/gists{/gist_id}","starred_url":"https://api.github.com/users/Zarel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zarel/subscriptions","organizations_url":"https://api.github.com/users/Zarel/orgs","repos_url":"https://api.github.com/users/Zarel/repos","events_url":"https://api.github.com/users/Zarel/events{/privacy}","received_events_url":"https://api.github.com/users/Zarel/received_events","type":"User","site_admin":false},"body":"We might want to rename it `gamesmanagement`","created_at":"2016-01-14T08:50:32Z","updated_at":"2016-01-14T08:50:32Z","html_url":"https://github.com/Zarel/Pokemon-Showdown/pull/2374#discussion_r49699681","pull_request_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374","_links":{"self":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments/49699681"},"html":{"href":"https://github.com/Zarel/Pokemon-Showdown/pull/2374#discussion_r49699681"},"pull_request":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374"}}},"pull_request":{"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374","id":55924042,"html_url":"https://github.com/Zarel/Pokemon-Showdown/pull/2374","diff_url":"https://github.com/Zarel/Pokemon-Showdown/pull/2374.diff","patch_url":"https://github.com/Zarel/Pokemon-Showdown/pull/2374.patch","issue_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/2374","number":2374,"state":"open","locked":false,"title":"UNO game for PS","user":{"login":"sparkychild","id":7757825,"avatar_url":"https://avatars.githubusercontent.com/u/7757825?v=3","gravatar_id":"","url":"https://api.github.com/users/sparkychild","html_url":"https://github.com/sparkychild","followers_url":"https://api.github.com/users/sparkychild/followers","following_url":"https://api.github.com/users/sparkychild/following{/other_user}","gists_url":"https://api.github.com/users/sparkychild/gists{/gist_id}","starred_url":"https://api.github.com/users/sparkychild/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sparkychild/subscriptions","organizations_url":"https://api.github.com/users/sparkychild/orgs","repos_url":"https://api.github.com/users/sparkychild/repos","events_url":"https://api.github.com/users/sparkychild/events{/privacy}","received_events_url":"https://api.github.com/users/sparkychild/received_events","type":"User","site_admin":false},"body":"A \"visually oriented\" UNO game for chatrooms.  All cards are buttons which you press to play a card.   It's designed to be as not spammy as possible so many things hide themselves after the turn is over.\r\n \r\n(probably will have to do a heck of a job with travis)","created_at":"2016-01-13T16:52:47Z","updated_at":"2016-01-14T08:50:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9e3d0c433657c4ef0544b919d8f514ab49d4d850","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374/commits","review_comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374/comments","review_comment_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/2374/comments","statuses_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/98221cf51e5979953a5587a4cb40a2c034282e55","head":{"label":"sparkychild:patch-6","ref":"patch-6","sha":"98221cf51e5979953a5587a4cb40a2c034282e55","user":{"login":"sparkychild","id":7757825,"avatar_url":"https://avatars.githubusercontent.com/u/7757825?v=3","gravatar_id":"","url":"https://api.github.com/users/sparkychild","html_url":"https://github.com/sparkychild","followers_url":"https://api.github.com/users/sparkychild/followers","following_url":"https://api.github.com/users/sparkychild/following{/other_user}","gists_url":"https://api.github.com/users/sparkychild/gists{/gist_id}","starred_url":"https://api.github.com/users/sparkychild/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sparkychild/subscriptions","organizations_url":"https://api.github.com/users/sparkychild/orgs","repos_url":"https://api.github.com/users/sparkychild/repos","events_url":"https://api.github.com/users/sparkychild/events{/privacy}","received_events_url":"https://api.github.com/users/sparkychild/received_events","type":"User","site_admin":false},"repo":{"id":44936858,"name":"Pokemon-Showdown","full_name":"sparkychild/Pokemon-Showdown","owner":{"login":"sparkychild","id":7757825,"avatar_url":"https://avatars.githubusercontent.com/u/7757825?v=3","gravatar_id":"","url":"https://api.github.com/users/sparkychild","html_url":"https://github.com/sparkychild","followers_url":"https://api.github.com/users/sparkychild/followers","following_url":"https://api.github.com/users/sparkychild/following{/other_user}","gists_url":"https://api.github.com/users/sparkychild/gists{/gist_id}","starred_url":"https://api.github.com/users/sparkychild/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sparkychild/subscriptions","organizations_url":"https://api.github.com/users/sparkychild/orgs","repos_url":"https://api.github.com/users/sparkychild/repos","events_url":"https://api.github.com/users/sparkychild/events{/privacy}","received_events_url":"https://api.github.com/users/sparkychild/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sparkychild/Pokemon-Showdown","description":"Pokémon battle simulator.","fork":true,"url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown","forks_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/forks","keys_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/teams","hooks_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/hooks","issue_events_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/issues/events{/number}","events_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/events","assignees_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/assignees{/user}","branches_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/branches{/branch}","tags_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/tags","blobs_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/git/refs{/sha}","trees_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/statuses/{sha}","languages_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/languages","stargazers_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/stargazers","contributors_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/contributors","subscribers_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/subscribers","subscription_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/subscription","commits_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/commits{/sha}","git_commits_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/git/commits{/sha}","comments_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/comments{/number}","issue_comment_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/issues/comments{/number}","contents_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/contents/{+path}","compare_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/merges","archive_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/downloads","issues_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/issues{/number}","pulls_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/pulls{/number}","milestones_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/milestones{/number}","notifications_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/labels{/name}","releases_url":"https://api.github.com/repos/sparkychild/Pokemon-Showdown/releases{/id}","created_at":"2015-10-26T00:36:46Z","updated_at":"2015-10-26T00:36:54Z","pushed_at":"2016-01-13T17:28:34Z","git_url":"git://github.com/sparkychild/Pokemon-Showdown.git","ssh_url":"git@github.com:sparkychild/Pokemon-Showdown.git","clone_url":"https://github.com/sparkychild/Pokemon-Showdown.git","svn_url":"https://github.com/sparkychild/Pokemon-Showdown","homepage":"http://pokemonshowdown.com","size":34160,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Zarel:master","ref":"master","sha":"bdafe6c490d0007ac63d62ed804996e99f7592e9","user":{"login":"Zarel","id":551184,"avatar_url":"https://avatars.githubusercontent.com/u/551184?v=3","gravatar_id":"","url":"https://api.github.com/users/Zarel","html_url":"https://github.com/Zarel","followers_url":"https://api.github.com/users/Zarel/followers","following_url":"https://api.github.com/users/Zarel/following{/other_user}","gists_url":"https://api.github.com/users/Zarel/gists{/gist_id}","starred_url":"https://api.github.com/users/Zarel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zarel/subscriptions","organizations_url":"https://api.github.com/users/Zarel/orgs","repos_url":"https://api.github.com/users/Zarel/repos","events_url":"https://api.github.com/users/Zarel/events{/privacy}","received_events_url":"https://api.github.com/users/Zarel/received_events","type":"User","site_admin":false},"repo":{"id":3038446,"name":"Pokemon-Showdown","full_name":"Zarel/Pokemon-Showdown","owner":{"login":"Zarel","id":551184,"avatar_url":"https://avatars.githubusercontent.com/u/551184?v=3","gravatar_id":"","url":"https://api.github.com/users/Zarel","html_url":"https://github.com/Zarel","followers_url":"https://api.github.com/users/Zarel/followers","following_url":"https://api.github.com/users/Zarel/following{/other_user}","gists_url":"https://api.github.com/users/Zarel/gists{/gist_id}","starred_url":"https://api.github.com/users/Zarel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zarel/subscriptions","organizations_url":"https://api.github.com/users/Zarel/orgs","repos_url":"https://api.github.com/users/Zarel/repos","events_url":"https://api.github.com/users/Zarel/events{/privacy}","received_events_url":"https://api.github.com/users/Zarel/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Zarel/Pokemon-Showdown","description":"Pokémon battle simulator.","fork":false,"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown","forks_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/forks","keys_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/teams","hooks_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/hooks","issue_events_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/events{/number}","events_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/events","assignees_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/assignees{/user}","branches_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/branches{/branch}","tags_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/tags","blobs_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/refs{/sha}","trees_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/{sha}","languages_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/languages","stargazers_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/stargazers","contributors_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/contributors","subscribers_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/subscribers","subscription_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/subscription","commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/commits{/sha}","git_commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/commits{/sha}","comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/comments{/number}","issue_comment_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/comments{/number}","contents_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/contents/{+path}","compare_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/merges","archive_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/downloads","issues_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues{/number}","pulls_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls{/number}","milestones_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/milestones{/number}","notifications_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/labels{/name}","releases_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/releases{/id}","created_at":"2011-12-23T04:52:33Z","updated_at":"2016-01-14T02:33:10Z","pushed_at":"2016-01-14T08:24:19Z","git_url":"git://github.com/Zarel/Pokemon-Showdown.git","ssh_url":"git@github.com:Zarel/Pokemon-Showdown.git","clone_url":"https://github.com/Zarel/Pokemon-Showdown.git","svn_url":"https://github.com/Zarel/Pokemon-Showdown","homepage":"http://pokemonshowdown.com","size":70592,"stargazers_count":673,"watchers_count":673,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":838,"mirror_url":null,"open_issues_count":29,"forks":838,"open_issues":29,"watchers":673,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374"},"html":{"href":"https://github.com/Zarel/Pokemon-Showdown/pull/2374"},"issue":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/2374"},"comments":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/2374/comments"},"review_comments":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374/comments"},"review_comment":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/2374/commits"},"statuses":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/98221cf51e5979953a5587a4cb40a2c034282e55"}}}}