initial commit of poker game
This commit is contained in:
8
game-server/app/components/botComponent.js
Normal file
8
game-server/app/components/botComponent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var BotService = require('../services/botService');
|
||||
|
||||
module.exports = function(app, opts){
|
||||
var service = new BotService(app, opts);
|
||||
app.set('botService', service, true);
|
||||
service.name = '__bot__';
|
||||
return service;
|
||||
};
|
8
game-server/app/components/stateComponent.js
Normal file
8
game-server/app/components/stateComponent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var BotService = require('../services/stateService');
|
||||
|
||||
module.exports = function(app, opts){
|
||||
var service = new StateService(app, opts);
|
||||
app.set('stateService', service, true);
|
||||
service.name = '__state__';
|
||||
return service;
|
||||
};
|
8
game-server/app/components/tableComponent.js
Normal file
8
game-server/app/components/tableComponent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var TableService = require('../services/tableService');
|
||||
|
||||
module.exports = function(app, opts){
|
||||
var service = new TableService(app, opts);
|
||||
app.set('tableService', service, true);
|
||||
service.name = '__table__';
|
||||
return service;
|
||||
};
|
83
game-server/app/game/game.js
Normal file
83
game-server/app/game/game.js
Normal file
@@ -0,0 +1,83 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var uuid = require('node-uuid');
|
||||
|
||||
|
||||
|
||||
module.exports = Game = function(smallBlind, bigBlind){
|
||||
this.id = uuid.v1();
|
||||
this.smallBlind = smallBlind;
|
||||
this.bigBlind = bigBlind;
|
||||
this.pot = 0;
|
||||
this.roundName = 'Deal'; //Start the first round
|
||||
this.betName = 'bet'; //bet,raise,re-raise,cap
|
||||
this.bets = [];
|
||||
this.roundBets = [];
|
||||
this.deck = [];
|
||||
this.board = [];
|
||||
fillDeck(this.deck);
|
||||
}
|
||||
|
||||
function fillDeck(deck){
|
||||
deck.push('AS');
|
||||
deck.push('KS');
|
||||
deck.push('QS');
|
||||
deck.push('JS');
|
||||
deck.push('TS');
|
||||
deck.push('9S');
|
||||
deck.push('8S');
|
||||
deck.push('7S');
|
||||
deck.push('6S');
|
||||
deck.push('5S');
|
||||
deck.push('4S');
|
||||
deck.push('3S');
|
||||
deck.push('2S');
|
||||
deck.push('AH');
|
||||
deck.push('KH');
|
||||
deck.push('QH');
|
||||
deck.push('JH');
|
||||
deck.push('TH');
|
||||
deck.push('9H');
|
||||
deck.push('8H');
|
||||
deck.push('7H');
|
||||
deck.push('6H');
|
||||
deck.push('5H');
|
||||
deck.push('4H');
|
||||
deck.push('3H');
|
||||
deck.push('2H');
|
||||
deck.push('AD');
|
||||
deck.push('KD');
|
||||
deck.push('QD');
|
||||
deck.push('JD');
|
||||
deck.push('TD');
|
||||
deck.push('9D');
|
||||
deck.push('8D');
|
||||
deck.push('7D');
|
||||
deck.push('6D');
|
||||
deck.push('5D');
|
||||
deck.push('4D');
|
||||
deck.push('3D');
|
||||
deck.push('2D');
|
||||
deck.push('AC');
|
||||
deck.push('KC');
|
||||
deck.push('QC');
|
||||
deck.push('JC');
|
||||
deck.push('TC');
|
||||
deck.push('9C');
|
||||
deck.push('8C');
|
||||
deck.push('7C');
|
||||
deck.push('6C');
|
||||
deck.push('5C');
|
||||
deck.push('4C');
|
||||
deck.push('3C');
|
||||
deck.push('2C');
|
||||
|
||||
//Shuffle the deck array with Fisher-Yates
|
||||
var i, j, tempi, tempj;
|
||||
for(i=0;i< deck.length;i+=1){
|
||||
j = Math.floor(Math.random() * (i + 1));
|
||||
tempi = deck[i];
|
||||
tempj = deck[j];
|
||||
deck[i] = tempj;
|
||||
deck[j] = tempi;
|
||||
}
|
||||
}
|
446
game-server/app/game/hand.js
Normal file
446
game-server/app/game/hand.js
Normal file
@@ -0,0 +1,446 @@
|
||||
module.exports = Hand = function(cards){
|
||||
this.cards = cards;
|
||||
var result = rankHandInt({
|
||||
cards : cards
|
||||
});
|
||||
this.rank = result.rank;
|
||||
this.message = result.message;
|
||||
return this;
|
||||
}
|
||||
|
||||
function rankHandInt(hand){
|
||||
var rank, message, handRanks, handSuits, ranks, suits, cards, result, i;
|
||||
rank = 0.0000;
|
||||
message = '';
|
||||
handRanks = [];
|
||||
handSuits = [];
|
||||
|
||||
for(i=0;i< hand.cards.length;i+=1){
|
||||
handRanks[i] = hand.cards[i].substr(0, 1);
|
||||
handSuits[i] = hand.cards[i].substr(1, 1);
|
||||
}
|
||||
|
||||
ranks = handRanks.sort().toString().replace(/\W/g, "");
|
||||
suits = handSuits.sort().toString().replace(/\W/g, "");
|
||||
cards = hand.cards.toString();
|
||||
|
||||
//Four of a kind
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('AAAA') > -1){rank = 292 + rankKickers(ranks.replace('AAAA', ''), 1); }
|
||||
if(ranks.indexOf('KKKK') > -1 && rank === 0){rank = 291 + rankKickers(ranks.replace('KKKK', ''), 1); }
|
||||
if(ranks.indexOf('QQQQ') > -1 && rank === 0){rank = 290 + rankKickers(ranks.replace('QQQQ', ''), 1); }
|
||||
if(ranks.indexOf('JJJJ') > -1 && rank === 0){rank = 289 + rankKickers(ranks.replace('JJJJ', ''), 1); }
|
||||
if(ranks.indexOf('TTTT') > -1 && rank === 0){rank = 288 + rankKickers(ranks.replace('TTTT', ''), 1); }
|
||||
if(ranks.indexOf('9999') > -1 && rank === 0){rank = 287 + rankKickers(ranks.replace('9999', ''), 1); }
|
||||
if(ranks.indexOf('8888') > -1 && rank === 0){rank = 286 + rankKickers(ranks.replace('8888', ''), 1); }
|
||||
if(ranks.indexOf('7777') > -1 && rank === 0){rank = 285 + rankKickers(ranks.replace('7777', ''), 1); }
|
||||
if(ranks.indexOf('6666') > -1 && rank === 0){rank = 284 + rankKickers(ranks.replace('6666', ''), 1); }
|
||||
if(ranks.indexOf('5555') > -1 && rank === 0){rank = 283 + rankKickers(ranks.replace('5555', ''), 1); }
|
||||
if(ranks.indexOf('4444') > -1 && rank === 0){rank = 282 + rankKickers(ranks.replace('4444', ''), 1); }
|
||||
if(ranks.indexOf('3333') > -1 && rank === 0){rank = 281 + rankKickers(ranks.replace('3333', ''), 1); }
|
||||
if(ranks.indexOf('2222') > -1 && rank === 0){rank = 280 + rankKickers(ranks.replace('2222', ''), 1); }
|
||||
if(rank !== 0){message = 'Four of a kind'; }
|
||||
}
|
||||
|
||||
//Full House
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('KK') > -1){rank = 279; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 278; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 277; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 276; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 275; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 274; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 273; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 272; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 271; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 270; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 269; }
|
||||
if(ranks.indexOf('AAA') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 268; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 267; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 266; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 265; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 264; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 263; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 262; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 261; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 260; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 259; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 258; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 257; }
|
||||
if(ranks.indexOf('KKK') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 256; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 255; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 254; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 253; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 252; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 251; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 250; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 249; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 248; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 247; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 246; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 245; }
|
||||
if(ranks.indexOf('QQQ') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 244; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 243; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 242; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 241; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 240; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 239; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 238; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 237; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 236; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 235; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 234; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 233; }
|
||||
if(ranks.indexOf('JJJ') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 232; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 231; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 230; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 229; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 228; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 227; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 226; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 225; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 224; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 223; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 222; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 221; }
|
||||
if(ranks.indexOf('TTT') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 220; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 219; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 218; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 217; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 216; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 215; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 214; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 213; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 212; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 211; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 210; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 209; }
|
||||
if(ranks.indexOf('999') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 208; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 207; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 206; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 205; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 204; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 203; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 202; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 201; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 200; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 199; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 198; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 197; }
|
||||
if(ranks.indexOf('888') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 196; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 195; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 194; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 193; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 192; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 191; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 190; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 189; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 188; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 187; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 186; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 185; }
|
||||
if(ranks.indexOf('777') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 184; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 183; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 182; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 181; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 180; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 179; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 178; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 177; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 176; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 175; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 174; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 173; }
|
||||
if(ranks.indexOf('666') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 172; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 171; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 170; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 169; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 168; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 167; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 166; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 165; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 164; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 163; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 162; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 161; }
|
||||
if(ranks.indexOf('555') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 160; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 159; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 158; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 157; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 156; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 155; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 154; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 153; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 152; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 151; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 150; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 149; }
|
||||
if(ranks.indexOf('444') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 148; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 147; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 146; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 145; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 144; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 143; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 142; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 141; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 140; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 139; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 138; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 137; }
|
||||
if(ranks.indexOf('333') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 136; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('AA') > -1 && rank === 0){rank = 135; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('KK') > -1 && rank === 0){rank = 134; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 133; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 132; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 131; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 130; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 129; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 128; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 127; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 126; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 125; }
|
||||
if(ranks.indexOf('222') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 124; }
|
||||
if(rank !== 0){message = 'Full House'; }
|
||||
}
|
||||
|
||||
//Flush
|
||||
if(rank === 0){
|
||||
if(suits.indexOf('CCCCC') > -1 || suits.indexOf('DDDDD') > -1 || suits.indexOf('HHHHH') > -1 || suits.indexOf('SSSSS') > -1){rank = 123; message = 'Flush';}
|
||||
|
||||
//Straight flush
|
||||
if(cards.indexOf('TC') > -1 && cards.indexOf('JC') > -1 && cards.indexOf('QC') > -1 && cards.indexOf('KC') > -1 && cards.indexOf('AC') > -1 && rank === 123){rank = 302; message = 'Straight Flush';}
|
||||
if(cards.indexOf('TD') > -1 && cards.indexOf('JD') > -1 && cards.indexOf('QD') > -1 && cards.indexOf('KD') > -1 && cards.indexOf('AD') > -1 && rank === 123){rank = 302; message = 'Straight Flush';}
|
||||
if(cards.indexOf('TH') > -1 && cards.indexOf('JH') > -1 && cards.indexOf('QH') > -1 && cards.indexOf('KH') > -1 && cards.indexOf('AH') > -1 && rank === 123){rank = 302; message = 'Straight Flush';}
|
||||
if(cards.indexOf('TS') > -1 && cards.indexOf('JS') > -1 && cards.indexOf('QS') > -1 && cards.indexOf('KS') > -1 && cards.indexOf('AS') > -1 && rank === 123){rank = 302; message = 'Straight Flush';}
|
||||
if(cards.indexOf('9C') > -1 && cards.indexOf('TC') > -1 && cards.indexOf('JC') > -1 && cards.indexOf('QC') > -1 && cards.indexOf('KC') > -1 && rank === 123){rank = 301; message = 'Straight Flush';}
|
||||
if(cards.indexOf('9D') > -1 && cards.indexOf('TD') > -1 && cards.indexOf('JD') > -1 && cards.indexOf('QD') > -1 && cards.indexOf('KD') > -1 && rank === 123){rank = 301; message = 'Straight Flush';}
|
||||
if(cards.indexOf('9H') > -1 && cards.indexOf('TH') > -1 && cards.indexOf('JH') > -1 && cards.indexOf('QH') > -1 && cards.indexOf('KH') > -1 && rank === 123){rank = 301; message = 'Straight Flush';}
|
||||
if(cards.indexOf('9S') > -1 && cards.indexOf('TS') > -1 && cards.indexOf('JS') > -1 && cards.indexOf('QS') > -1 && cards.indexOf('KS') > -1 && rank === 123){rank = 301; message = 'Straight Flush';}
|
||||
if(cards.indexOf('8C') > -1 && cards.indexOf('9C') > -1 && cards.indexOf('TC') > -1 && cards.indexOf('JC') > -1 && cards.indexOf('QC') > -1 && rank === 123){rank = 300; message = 'Straight Flush';}
|
||||
if(cards.indexOf('8D') > -1 && cards.indexOf('9D') > -1 && cards.indexOf('TD') > -1 && cards.indexOf('JD') > -1 && cards.indexOf('QD') > -1 && rank === 123){rank = 300; message = 'Straight Flush';}
|
||||
if(cards.indexOf('8H') > -1 && cards.indexOf('9H') > -1 && cards.indexOf('TH') > -1 && cards.indexOf('JH') > -1 && cards.indexOf('QH') > -1 && rank === 123){rank = 300; message = 'Straight Flush';}
|
||||
if(cards.indexOf('8S') > -1 && cards.indexOf('9S') > -1 && cards.indexOf('TS') > -1 && cards.indexOf('JS') > -1 && cards.indexOf('QS') > -1 && rank === 123){rank = 300; message = 'Straight Flush';}
|
||||
if(cards.indexOf('7C') > -1 && cards.indexOf('8C') > -1 && cards.indexOf('9C') > -1 && cards.indexOf('TC') > -1 && cards.indexOf('JC') > -1 && rank === 123){rank = 299; message = 'Straight Flush';}
|
||||
if(cards.indexOf('7D') > -1 && cards.indexOf('8D') > -1 && cards.indexOf('9D') > -1 && cards.indexOf('TD') > -1 && cards.indexOf('JD') > -1 && rank === 123){rank = 299; message = 'Straight Flush';}
|
||||
if(cards.indexOf('7H') > -1 && cards.indexOf('8H') > -1 && cards.indexOf('9H') > -1 && cards.indexOf('TH') > -1 && cards.indexOf('JH') > -1 && rank === 123){rank = 299; message = 'Straight Flush';}
|
||||
if(cards.indexOf('7S') > -1 && cards.indexOf('8S') > -1 && cards.indexOf('9S') > -1 && cards.indexOf('TS') > -1 && cards.indexOf('JS') > -1 && rank === 123){rank = 299; message = 'Straight Flush';}
|
||||
if(cards.indexOf('6C') > -1 && cards.indexOf('7C') > -1 && cards.indexOf('8C') > -1 && cards.indexOf('9C') > -1 && cards.indexOf('TC') > -1 && rank === 123){rank = 298; message = 'Straight Flush';}
|
||||
if(cards.indexOf('6D') > -1 && cards.indexOf('7D') > -1 && cards.indexOf('8D') > -1 && cards.indexOf('9D') > -1 && cards.indexOf('TD') > -1 && rank === 123){rank = 298; message = 'Straight Flush';}
|
||||
if(cards.indexOf('6H') > -1 && cards.indexOf('7H') > -1 && cards.indexOf('8H') > -1 && cards.indexOf('9H') > -1 && cards.indexOf('TH') > -1 && rank === 123){rank = 298; message = 'Straight Flush';}
|
||||
if(cards.indexOf('6S') > -1 && cards.indexOf('7S') > -1 && cards.indexOf('8S') > -1 && cards.indexOf('9S') > -1 && cards.indexOf('TS') > -1 && rank === 123){rank = 298; message = 'Straight Flush';}
|
||||
if(cards.indexOf('5C') > -1 && cards.indexOf('6C') > -1 && cards.indexOf('7C') > -1 && cards.indexOf('8C') > -1 && cards.indexOf('9C') > -1 && rank === 123){rank = 297; message = 'Straight Flush';}
|
||||
if(cards.indexOf('5D') > -1 && cards.indexOf('6D') > -1 && cards.indexOf('7D') > -1 && cards.indexOf('8D') > -1 && cards.indexOf('9D') > -1 && rank === 123){rank = 297; message = 'Straight Flush';}
|
||||
if(cards.indexOf('5H') > -1 && cards.indexOf('6H') > -1 && cards.indexOf('7H') > -1 && cards.indexOf('8H') > -1 && cards.indexOf('9H') > -1 && rank === 123){rank = 297; message = 'Straight Flush';}
|
||||
if(cards.indexOf('5S') > -1 && cards.indexOf('6S') > -1 && cards.indexOf('7S') > -1 && cards.indexOf('8S') > -1 && cards.indexOf('9S') > -1 && rank === 123){rank = 297; message = 'Straight Flush';}
|
||||
if(cards.indexOf('4C') > -1 && cards.indexOf('5C') > -1 && cards.indexOf('6C') > -1 && cards.indexOf('7C') > -1 && cards.indexOf('8C') > -1 && rank === 123){rank = 296; message = 'Straight Flush';}
|
||||
if(cards.indexOf('4D') > -1 && cards.indexOf('5D') > -1 && cards.indexOf('6D') > -1 && cards.indexOf('7D') > -1 && cards.indexOf('8D') > -1 && rank === 123){rank = 296; message = 'Straight Flush';}
|
||||
if(cards.indexOf('4H') > -1 && cards.indexOf('5H') > -1 && cards.indexOf('6H') > -1 && cards.indexOf('7H') > -1 && cards.indexOf('8H') > -1 && rank === 123){rank = 296; message = 'Straight Flush';}
|
||||
if(cards.indexOf('4S') > -1 && cards.indexOf('5S') > -1 && cards.indexOf('6S') > -1 && cards.indexOf('7S') > -1 && cards.indexOf('8S') > -1 && rank === 123){rank = 296; message = 'Straight Flush';}
|
||||
if(cards.indexOf('3C') > -1 && cards.indexOf('4C') > -1 && cards.indexOf('5C') > -1 && cards.indexOf('6C') > -1 && cards.indexOf('7C') > -1 && rank === 123){rank = 295; message = 'Straight Flush';}
|
||||
if(cards.indexOf('3D') > -1 && cards.indexOf('4D') > -1 && cards.indexOf('5D') > -1 && cards.indexOf('6D') > -1 && cards.indexOf('7D') > -1 && rank === 123){rank = 295; message = 'Straight Flush';}
|
||||
if(cards.indexOf('3H') > -1 && cards.indexOf('4H') > -1 && cards.indexOf('5H') > -1 && cards.indexOf('6H') > -1 && cards.indexOf('7H') > -1 && rank === 123){rank = 295; message = 'Straight Flush';}
|
||||
if(cards.indexOf('3S') > -1 && cards.indexOf('4S') > -1 && cards.indexOf('5S') > -1 && cards.indexOf('6S') > -1 && cards.indexOf('7S') > -1 && rank === 123){rank = 295; message = 'Straight Flush';}
|
||||
if(cards.indexOf('2C') > -1 && cards.indexOf('3C') > -1 && cards.indexOf('4C') > -1 && cards.indexOf('5C') > -1 && cards.indexOf('6C') > -1 && rank === 123){rank = 294; message = 'Straight Flush';}
|
||||
if(cards.indexOf('2D') > -1 && cards.indexOf('3D') > -1 && cards.indexOf('4D') > -1 && cards.indexOf('5D') > -1 && cards.indexOf('6D') > -1 && rank === 123){rank = 294; message = 'Straight Flush';}
|
||||
if(cards.indexOf('2H') > -1 && cards.indexOf('3H') > -1 && cards.indexOf('4H') > -1 && cards.indexOf('5H') > -1 && cards.indexOf('6H') > -1 && rank === 123){rank = 294; message = 'Straight Flush';}
|
||||
if(cards.indexOf('2S') > -1 && cards.indexOf('3S') > -1 && cards.indexOf('4S') > -1 && cards.indexOf('5S') > -1 && cards.indexOf('6S') > -1 && rank === 123){rank = 294; message = 'Straight Flush';}
|
||||
if(cards.indexOf('AC') > -1 && cards.indexOf('2C') > -1 && cards.indexOf('3C') > -1 && cards.indexOf('4C') > -1 && cards.indexOf('5C') > -1 && rank === 123){rank = 293; message = 'Straight Flush';}
|
||||
if(cards.indexOf('AS') > -1 && cards.indexOf('2S') > -1 && cards.indexOf('3S') > -1 && cards.indexOf('4S') > -1 && cards.indexOf('5S') > -1 && rank === 123){rank = 293; message = 'Straight Flush';}
|
||||
if(cards.indexOf('AH') > -1 && cards.indexOf('2H') > -1 && cards.indexOf('3H') > -1 && cards.indexOf('4H') > -1 && cards.indexOf('5H') > -1 && rank === 123){rank = 293; message = 'Straight Flush';}
|
||||
if(cards.indexOf('AD') > -1 && cards.indexOf('2D') > -1 && cards.indexOf('3D') > -1 && cards.indexOf('4D') > -1 && cards.indexOf('5D') > -1 && rank === 123){rank = 293; message = 'Straight Flush';}
|
||||
if(rank === 123){rank = rank + rankKickers(ranks, 5);}
|
||||
|
||||
}
|
||||
|
||||
//Straight
|
||||
if(rank === 0){
|
||||
if(cards.indexOf('T') > -1 && cards.indexOf('J') > -1 && cards.indexOf('Q') > -1 && cards.indexOf('K') > -1 && cards.indexOf('A') > -1){rank = 122; }
|
||||
if(cards.indexOf('9') > -1 && cards.indexOf('T') > -1 && cards.indexOf('J') > -1 && cards.indexOf('Q') > -1 && cards.indexOf('K') > -1 && rank === 0){rank = 121; }
|
||||
if(cards.indexOf('8') > -1 && cards.indexOf('9') > -1 && cards.indexOf('T') > -1 && cards.indexOf('J') > -1 && cards.indexOf('Q') > -1 && rank === 0){rank = 120; }
|
||||
if(cards.indexOf('7') > -1 && cards.indexOf('8') > -1 && cards.indexOf('9') > -1 && cards.indexOf('T') > -1 && cards.indexOf('J') > -1 && rank === 0){rank = 119; }
|
||||
if(cards.indexOf('6') > -1 && cards.indexOf('7') > -1 && cards.indexOf('8') > -1 && cards.indexOf('9') > -1 && cards.indexOf('T') > -1 && rank === 0){rank = 118; }
|
||||
if(cards.indexOf('5') > -1 && cards.indexOf('6') > -1 && cards.indexOf('7') > -1 && cards.indexOf('8') > -1 && cards.indexOf('9') > -1 && rank === 0){rank = 117; }
|
||||
if(cards.indexOf('4') > -1 && cards.indexOf('5') > -1 && cards.indexOf('6') > -1 && cards.indexOf('7') > -1 && cards.indexOf('8') > -1 && rank === 0){rank = 116; }
|
||||
if(cards.indexOf('3') > -1 && cards.indexOf('4') > -1 && cards.indexOf('5') > -1 && cards.indexOf('6') > -1 && cards.indexOf('7') > -1 && rank === 0){rank = 115; }
|
||||
if(cards.indexOf('2') > -1 && cards.indexOf('3') > -1 && cards.indexOf('4') > -1 && cards.indexOf('5') > -1 && cards.indexOf('6') > -1 && rank === 0){rank = 114; }
|
||||
if(cards.indexOf('A') > -1 && cards.indexOf('2') > -1 && cards.indexOf('3') > -1 && cards.indexOf('4') > -1 && cards.indexOf('5') > -1 && rank === 0){rank = 113; }
|
||||
if(rank !== 0){message = 'Straight'; }
|
||||
}
|
||||
|
||||
//Three of a kind
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('AAA') > -1){rank = 112 + rankKickers(ranks.replace('AAA', ''), 2); }
|
||||
if(ranks.indexOf('KKK') > -1 && rank === 0){rank = 111 + rankKickers(ranks.replace('KKK', ''), 2); }
|
||||
if(ranks.indexOf('QQQ') > -1 && rank === 0){rank = 110 + rankKickers(ranks.replace('QQQ', ''), 2); }
|
||||
if(ranks.indexOf('JJJ') > -1 && rank === 0){rank = 109 + rankKickers(ranks.replace('JJJ', ''), 2); }
|
||||
if(ranks.indexOf('TTT') > -1 && rank === 0){rank = 108 + rankKickers(ranks.replace('TTT', ''), 2); }
|
||||
if(ranks.indexOf('999') > -1 && rank === 0){rank = 107 + rankKickers(ranks.replace('999', ''), 2); }
|
||||
if(ranks.indexOf('888') > -1 && rank === 0){rank = 106 + rankKickers(ranks.replace('888', ''), 2); }
|
||||
if(ranks.indexOf('777') > -1 && rank === 0){rank = 105 + rankKickers(ranks.replace('777', ''), 2); }
|
||||
if(ranks.indexOf('666') > -1 && rank === 0){rank = 104 + rankKickers(ranks.replace('666', ''), 2); }
|
||||
if(ranks.indexOf('555') > -1 && rank === 0){rank = 103 + rankKickers(ranks.replace('555', ''), 2); }
|
||||
if(ranks.indexOf('444') > -1 && rank === 0){rank = 102 + rankKickers(ranks.replace('444', ''), 2); }
|
||||
if(ranks.indexOf('333') > -1 && rank === 0){rank = 101 + rankKickers(ranks.replace('333', ''), 2); }
|
||||
if(ranks.indexOf('222') > -1 && rank === 0){rank = 100 + rankKickers(ranks.replace('222', ''), 2); }
|
||||
if(rank !== 0){message = 'Three of a Kind'; }
|
||||
}
|
||||
|
||||
//Two pair
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('KK') > -1){rank = 99 + rankKickers(ranks.replace('AA', '').replace('KK', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 98 + rankKickers(ranks.replace('AA', '').replace('QQ', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 97 + rankKickers(ranks.replace('AA', '').replace('JJ', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 96 + rankKickers(ranks.replace('AA', '').replace('TT', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 95 + rankKickers(ranks.replace('AA', '').replace('99', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 94 + rankKickers(ranks.replace('AA', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 93 + rankKickers(ranks.replace('AA', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 92 + rankKickers(ranks.replace('AA', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 91 + rankKickers(ranks.replace('AA', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 90 + rankKickers(ranks.replace('AA', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 89 + rankKickers(ranks.replace('AA', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('AA') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 88 + rankKickers(ranks.replace('AA', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('QQ') > -1 && rank === 0){rank = 87 + rankKickers(ranks.replace('KK', '').replace('QQ', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 86 + rankKickers(ranks.replace('KK', '').replace('JJ', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 85 + rankKickers(ranks.replace('KK', '').replace('TT', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 84 + rankKickers(ranks.replace('KK', '').replace('99', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 83 + rankKickers(ranks.replace('KK', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 82 + rankKickers(ranks.replace('KK', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 81 + rankKickers(ranks.replace('KK', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 80 + rankKickers(ranks.replace('KK', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 79 + rankKickers(ranks.replace('KK', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 78 + rankKickers(ranks.replace('KK', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('KK') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 77 + rankKickers(ranks.replace('KK', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('JJ') > -1 && rank === 0){rank = 76 + rankKickers(ranks.replace('QQ', '').replace('JJ', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 75 + rankKickers(ranks.replace('QQ', '').replace('TT', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 74 + rankKickers(ranks.replace('QQ', '').replace('99', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 73 + rankKickers(ranks.replace('QQ', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 72 + rankKickers(ranks.replace('QQ', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 71 + rankKickers(ranks.replace('QQ', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 70 + rankKickers(ranks.replace('QQ', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 69 + rankKickers(ranks.replace('QQ', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 68 + rankKickers(ranks.replace('QQ', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('QQ') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 67 + rankKickers(ranks.replace('QQ', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('TT') > -1 && rank === 0){rank = 66 + rankKickers(ranks.replace('JJ', '').replace('TT', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 65 + rankKickers(ranks.replace('JJ', '').replace('99', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 64 + rankKickers(ranks.replace('JJ', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 63 + rankKickers(ranks.replace('JJ', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 62 + rankKickers(ranks.replace('JJ', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 61 + rankKickers(ranks.replace('JJ', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 60 + rankKickers(ranks.replace('JJ', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 59 + rankKickers(ranks.replace('JJ', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('JJ') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 58 + rankKickers(ranks.replace('JJ', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('99') > -1 && rank === 0){rank = 57 + rankKickers(ranks.replace('TT', '').replace('99', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 56 + rankKickers(ranks.replace('TT', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 55 + rankKickers(ranks.replace('TT', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 54 + rankKickers(ranks.replace('TT', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 53 + rankKickers(ranks.replace('TT', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 52 + rankKickers(ranks.replace('TT', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 51 + rankKickers(ranks.replace('TT', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('TT') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 50 + rankKickers(ranks.replace('TT', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('88') > -1 && rank === 0){rank = 49 + rankKickers(ranks.replace('99', '').replace('88', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 48 + rankKickers(ranks.replace('99', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 47 + rankKickers(ranks.replace('99', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 46 + rankKickers(ranks.replace('99', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 45 + rankKickers(ranks.replace('99', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 44 + rankKickers(ranks.replace('99', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('99') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 43 + rankKickers(ranks.replace('99', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('77') > -1 && rank === 0){rank = 42 + rankKickers(ranks.replace('88', '').replace('77', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 41 + rankKickers(ranks.replace('88', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 40 + rankKickers(ranks.replace('88', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 39 + rankKickers(ranks.replace('88', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 38 + rankKickers(ranks.replace('88', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('88') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 37 + rankKickers(ranks.replace('88', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('77') > -1 && ranks.indexOf('66') > -1 && rank === 0){rank = 36 + rankKickers(ranks.replace('77', '').replace('66', ''), 1); }
|
||||
if(ranks.indexOf('77') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 35 + rankKickers(ranks.replace('77', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('77') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 34 + rankKickers(ranks.replace('77', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('77') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 33 + rankKickers(ranks.replace('77', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('77') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 32 + rankKickers(ranks.replace('77', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('66') > -1 && ranks.indexOf('55') > -1 && rank === 0){rank = 31 + rankKickers(ranks.replace('66', '').replace('55', ''), 1); }
|
||||
if(ranks.indexOf('66') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 30 + rankKickers(ranks.replace('66', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('66') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 29 + rankKickers(ranks.replace('66', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('66') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 28 + rankKickers(ranks.replace('66', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('55') > -1 && ranks.indexOf('44') > -1 && rank === 0){rank = 27 + rankKickers(ranks.replace('55', '').replace('44', ''), 1); }
|
||||
if(ranks.indexOf('55') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 26 + rankKickers(ranks.replace('55', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('55') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 25 + rankKickers(ranks.replace('55', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('44') > -1 && ranks.indexOf('33') > -1 && rank === 0){rank = 24 + rankKickers(ranks.replace('44', '').replace('33', ''), 1); }
|
||||
if(ranks.indexOf('44') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 23 + rankKickers(ranks.replace('44', '').replace('22', ''), 1); }
|
||||
if(ranks.indexOf('33') > -1 && ranks.indexOf('22') > -1 && rank === 0){rank = 22 + rankKickers(ranks.replace('33', '').replace('22', ''), 1); }
|
||||
if(rank !== 0){message = 'Two Pair'; }
|
||||
}
|
||||
|
||||
//One Pair
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('AA') > -1){rank = 21 + rankKickers(ranks.replace('AA', ''), 3); }
|
||||
if(ranks.indexOf('KK') > -1 && rank === 0){rank = 20 + rankKickers(ranks.replace('KK', ''), 3); }
|
||||
if(ranks.indexOf('QQ') > -1 && rank === 0){rank = 19 + rankKickers(ranks.replace('QQ', ''), 3); }
|
||||
if(ranks.indexOf('JJ') > -1 && rank === 0){rank = 18 + rankKickers(ranks.replace('JJ', ''), 3); }
|
||||
if(ranks.indexOf('TT') > -1 && rank === 0){rank = 17 + rankKickers(ranks.replace('TT', ''), 3); }
|
||||
if(ranks.indexOf('99') > -1 && rank === 0){rank = 16 + rankKickers(ranks.replace('99', ''), 3); }
|
||||
if(ranks.indexOf('88') > -1 && rank === 0){rank = 15 + rankKickers(ranks.replace('88', ''), 3); }
|
||||
if(ranks.indexOf('77') > -1 && rank === 0){rank = 14 + rankKickers(ranks.replace('77', ''), 3); }
|
||||
if(ranks.indexOf('66') > -1 && rank === 0){rank = 13 + rankKickers(ranks.replace('66', ''), 3); }
|
||||
if(ranks.indexOf('55') > -1 && rank === 0){rank = 12 + rankKickers(ranks.replace('55', ''), 3); }
|
||||
if(ranks.indexOf('44') > -1 && rank === 0){rank = 11 + rankKickers(ranks.replace('44', ''), 3); }
|
||||
if(ranks.indexOf('33') > -1 && rank === 0){rank = 10 + rankKickers(ranks.replace('33', ''), 3); }
|
||||
if(ranks.indexOf('22') > -1 && rank === 0){rank = 9 + rankKickers(ranks.replace('22', ''), 3); }
|
||||
if(rank !== 0){message = 'Pair'; }
|
||||
}
|
||||
|
||||
//High Card
|
||||
if(rank === 0){
|
||||
if(ranks.indexOf('A') > -1){rank = 8 + rankKickers(ranks.replace('A', ''), 4); }
|
||||
if(ranks.indexOf('K') > -1 && rank === 0){rank = 7 + rankKickers(ranks.replace('K', ''), 4); }
|
||||
if(ranks.indexOf('Q') > -1 && rank === 0){rank = 6 + rankKickers(ranks.replace('Q', ''), 4); }
|
||||
if(ranks.indexOf('J') > -1 && rank === 0){rank = 5 + rankKickers(ranks.replace('J', ''), 4); }
|
||||
if(ranks.indexOf('T') > -1 && rank === 0){rank = 4 + rankKickers(ranks.replace('T', ''), 4); }
|
||||
if(ranks.indexOf('9') > -1 && rank === 0){rank = 3 + rankKickers(ranks.replace('9', ''), 4); }
|
||||
if(ranks.indexOf('8') > -1 && rank === 0){rank = 2 + rankKickers(ranks.replace('8', ''), 4); }
|
||||
if(ranks.indexOf('7') > -1 && rank === 0){rank = 1 + rankKickers(ranks.replace('7', ''), 4); }
|
||||
if(rank !== 0){message = 'High Card'; }
|
||||
}
|
||||
|
||||
return {
|
||||
rank : rank,
|
||||
message : message
|
||||
}
|
||||
}
|
||||
|
||||
function rankKickers(ranks, noOfCards){
|
||||
var i, kickerRank, myRanks, rank;
|
||||
kickerRank = 0.0000;
|
||||
myRanks = [];
|
||||
rank = '';
|
||||
for(i=0;i<= ranks.length;i+=1){
|
||||
rank = ranks.substr(i, 1);
|
||||
if(rank === 'A'){myRanks.push(0.2048); }
|
||||
if(rank === 'K'){myRanks.push(0.1024); }
|
||||
if(rank === 'Q'){myRanks.push(0.0512); }
|
||||
if(rank === 'J'){myRanks.push(0.0256); }
|
||||
if(rank === 'T'){myRanks.push(0.0128); }
|
||||
if(rank === '9'){myRanks.push(0.0064); }
|
||||
if(rank === '8'){myRanks.push(0.0032); }
|
||||
if(rank === '7'){myRanks.push(0.0016); }
|
||||
if(rank === '6'){myRanks.push(0.0008); }
|
||||
if(rank === '5'){myRanks.push(0.0004); }
|
||||
if(rank === '4'){myRanks.push(0.0002); }
|
||||
if(rank === '3'){myRanks.push(0.0001); }
|
||||
if(rank === '2'){myRanks.push(0.0000); }
|
||||
}
|
||||
myRanks.sort(function(a, b){
|
||||
return b - a;
|
||||
});
|
||||
for(i=0;i< noOfCards;i+=1){
|
||||
kickerRank += myRanks[i];
|
||||
}
|
||||
return kickerRank;
|
||||
}
|
||||
|
||||
function rankHands(hands){
|
||||
var x, myResult;
|
||||
for(x = 0; x < hands.length; x += 1){
|
||||
myResult = rankHandInt(hands[x]);
|
||||
hands[x].rank = myResult.rank;
|
||||
hands[x].message = myResult.message;
|
||||
}
|
||||
return hands;
|
||||
}
|
470
game-server/app/game/player.js
Normal file
470
game-server/app/game/player.js
Normal file
@@ -0,0 +1,470 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var Hand = require('./hand');
|
||||
|
||||
|
||||
module.exports = Player = function(playerName, chips, uid, table){
|
||||
this.playerName = playerName;
|
||||
this.id = uid;
|
||||
this.chips = chips;
|
||||
this.folded = false;
|
||||
this.allIn = false;
|
||||
this.talked = false;
|
||||
this.table = table; //Circular reference to allow reference back to parent object.
|
||||
this.cards = [];
|
||||
}
|
||||
|
||||
Player.prototype.GetChips = function(cash){
|
||||
this.chips += cash;
|
||||
};
|
||||
|
||||
Player.prototype.Check = function(){
|
||||
var checkAllow, v, i;
|
||||
checkAllow = true;
|
||||
for(v=0;v<this.table.game.bets.length;v += 1){
|
||||
if(this.table.game.bets[v] !== 0){
|
||||
checkAllow = false;
|
||||
}
|
||||
}
|
||||
if(checkAllow){
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
this.table.game.bets[i] = 0;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "check", playerName: this.playerName};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('check-not-allowed by '+this.id);
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.Fold = function(){
|
||||
var i, bet;
|
||||
//Move any current bet into the pot
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this.id === this.table.players[i].id){
|
||||
bet = parseInt(this.table.game.bets[i], 10);
|
||||
this.table.game.roundBets[i] += bet;
|
||||
this.table.game.bets[i] = 0;
|
||||
this.table.game.pot += bet;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
//Mark the player as folded
|
||||
this.folded = true;
|
||||
this.turnBet = {action: "fold", playerName: this.playerName};
|
||||
this.table.actions.push(this.turnBet);
|
||||
// attempt to progress the game
|
||||
progress(this.table);
|
||||
};
|
||||
|
||||
Player.prototype.Bet = function(bet){
|
||||
var i = this.getIndex();
|
||||
var maxBet = getMaxBet(this.table.game.bets);
|
||||
var totalBet = bet + maxBet;
|
||||
var currentBet = this.table.game.bets[i];
|
||||
if((currentBet + this.chips) > totalBet){
|
||||
this.table.players[i].chips -= (totalBet - currentBet);
|
||||
this.table.game.bets[i] = totalBet; // this.table.game.bets[i] += totalBet;
|
||||
this.talked = true;
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "bet", playerName: this.playerName, amount: totalBet};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('forced-all-in: '+this.id);
|
||||
this.AllIn();
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.getIndex = function(){
|
||||
var index;
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
Player.prototype.Call = function(){
|
||||
var maxBet, i;
|
||||
// console.log('bets', this.table.game.bets);
|
||||
maxBet = getMaxBet(this.table.game.bets);
|
||||
if(this.chips > maxBet){
|
||||
// console.log('higher chips', this.chips, maxBet);
|
||||
//Match the highest bet
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
if(this.table.game.bets[i] >= 0){
|
||||
this.chips += this.table.game.bets[i];
|
||||
}
|
||||
this.chips -= maxBet;
|
||||
this.table.game.bets[i] = maxBet;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "call", playerName: this.playerName, amount: maxBet};
|
||||
this.table.actions.push(this.turnBet);
|
||||
progress(this.table);
|
||||
}else{
|
||||
logger.debug('forced-all-in: '+this.id);
|
||||
this.AllIn();
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.AllIn = function(){
|
||||
var i, allInValue=0;
|
||||
for(i=0;i< this.table.players.length;i+=1){
|
||||
if(this === this.table.players[i]){
|
||||
if(this.table.players[i].chips !== 0){
|
||||
allInValue = this.table.players[i].chips;
|
||||
this.table.game.bets[i] += this.table.players[i].chips;
|
||||
this.table.players[i].chips = 0;
|
||||
|
||||
this.allIn = true;
|
||||
this.talked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to progress the game
|
||||
this.turnBet = {action: "allin", playerName: this.playerName, amount: allInValue};
|
||||
this.table.actions.push(this.turnBet);
|
||||
|
||||
progress(this.table);
|
||||
};
|
||||
|
||||
function progress(table){
|
||||
var i, j, cards, hand;
|
||||
if(table.game){
|
||||
table.eventEmitter.emit("turnEnd");
|
||||
table.stopTimer();
|
||||
if(checkForEndOfGame(table)){
|
||||
//Move all bets to the pot
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.pot += parseInt(table.game.bets[i], 10);
|
||||
table.game.roundBets[i] += parseInt(table.game.bets[i], 10);
|
||||
}
|
||||
completeGame(table);
|
||||
return;
|
||||
}
|
||||
if(checkForEndOfRound(table) === true){
|
||||
//Move all bets to the pot
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.pot += parseInt(table.game.bets[i], 10);
|
||||
table.game.roundBets[i] += parseInt(table.game.bets[i], 10);
|
||||
}
|
||||
if(table.game.roundName === 'River'){
|
||||
completeGame(table);
|
||||
return;
|
||||
}else if(table.game.roundName === 'Turn'){
|
||||
table.game.roundName = 'River';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
table.game.board.push(table.game.deck.pop()); //Turn a card
|
||||
//table.game.bets.splice(0,table.game.bets.length-1);
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}else if(table.game.roundName === 'Flop'){
|
||||
table.game.roundName = 'Turn';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
table.game.board.push(table.game.deck.pop()); //Turn a card
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}else if(table.game.roundName === 'Deal'){
|
||||
table.game.roundName = 'Flop';
|
||||
table.game.deck.pop(); //Burn a card
|
||||
for(i=0;i< 3;i+=1){ //Turn three cards
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
//table.game.bets.splice(0,table.game.bets.length-1);
|
||||
for(i=0;i< table.game.bets.length;i+=1){
|
||||
table.game.bets[i] = 0;
|
||||
}
|
||||
for(i=0;i< table.players.length;i+=1){
|
||||
table.players[i].talked = false;
|
||||
}
|
||||
table.eventEmitter.emit( "deal" );
|
||||
}
|
||||
table.currentPlayer = getNextAvailablePlayer(table, table.startIndex, table.players.length);
|
||||
if(typeof table.currentPlayer !== 'number' && table.game.roundName !== 'GameEnd'){
|
||||
console.log('ALL IN GAME');
|
||||
completeBoard(table);
|
||||
return progress(table);
|
||||
}
|
||||
}
|
||||
table.eventEmitter.emit("turnStart");
|
||||
}
|
||||
}
|
||||
|
||||
function completeGame(table){
|
||||
table.game.roundName = 'GameEnd';
|
||||
table.game.bets.splice(0, table.game.bets.length);
|
||||
//Evaluate each hand
|
||||
for(j = 0; j < table.players.length; j += 1){
|
||||
cards = table.players[j].cards.concat(table.game.board);
|
||||
table.players[j].hand = new Hand(cards);
|
||||
}
|
||||
console.log('checkForWinner', table);
|
||||
checkForWinner(table);
|
||||
table.eventEmitter.emit('gameOver');
|
||||
}
|
||||
|
||||
function completeBoard(table){
|
||||
var i;
|
||||
if(table.game.board.length == 0){
|
||||
table.game.deck.pop();
|
||||
for(i=0;i<3;i+=1){
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
}
|
||||
if(table.game.board.length == 3){
|
||||
table.game.deck.pop();
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
if(table.game.board.length == 4){
|
||||
table.game.deck.pop();
|
||||
table.game.board.push(table.game.deck.pop());
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxBet(bets){
|
||||
var maxBet, i;
|
||||
maxBet = 0;
|
||||
for(i=0;i< bets.length;i+=1){
|
||||
if(bets[i] > maxBet){
|
||||
maxBet = bets[i];
|
||||
}
|
||||
}
|
||||
return maxBet;
|
||||
}
|
||||
|
||||
function checkForEndOfGame(table){
|
||||
var notFolded = [], allInPlayer = [], actionablePlayer = [], i;
|
||||
for(i = 0; i < table.players.length;i+=1){
|
||||
if(table.players[i].folded === false){
|
||||
notFolded.push(i);
|
||||
}
|
||||
if(table.players[i].allIn === true){
|
||||
allInPlayer.push(i);
|
||||
}
|
||||
if(table.players[i].folded === false && table.players[i].allIn === false){
|
||||
actionablePlayer.push(i);
|
||||
}
|
||||
}
|
||||
if(allInPlayer.length > 1){
|
||||
completeBoard(table);
|
||||
}
|
||||
return (notFolded.length === 1 || actionablePlayer.length === 0);
|
||||
}
|
||||
|
||||
function checkForEndOfRound(table){
|
||||
var endOfRound = true;
|
||||
var nextPlayer = getNextAvailablePlayer(table, (table.currentPlayer + 1), table.players.length);
|
||||
if(typeof nextPlayer === 'number'){
|
||||
table.currentPlayer = nextPlayer;
|
||||
endOfRound = false;
|
||||
}
|
||||
return endOfRound;
|
||||
}
|
||||
|
||||
function getNextAvailablePlayer(table, playerIndex, len, ctr){
|
||||
ctr = ctr || 0;
|
||||
var maxBet = getMaxBet(table.game.bets);
|
||||
var nextPlayer;
|
||||
if(playerIndex === len){
|
||||
playerIndex = 0;
|
||||
}
|
||||
if(table.players[playerIndex].folded === false && (table.players[playerIndex].talked === false || table.game.bets[playerIndex] !== maxBet) && table.players[playerIndex].allIn === false){
|
||||
nextPlayer = playerIndex;
|
||||
}
|
||||
ctr += 1;
|
||||
playerIndex += 1;
|
||||
if(typeof nextPlayer !== 'number' && ctr !== len){
|
||||
nextPlayer = getNextAvailablePlayer(table, playerIndex, len, ctr);
|
||||
}
|
||||
return nextPlayer;
|
||||
}
|
||||
|
||||
function checkForAllInPlayer(table, winners){
|
||||
var i, allInPlayer;
|
||||
allInPlayer = [];
|
||||
for(i=0;i< winners.length;i+=1){
|
||||
if(table.players[winners[i]].allIn === true){
|
||||
allInPlayer.push(winners[i]);
|
||||
}
|
||||
}
|
||||
return allInPlayer;
|
||||
}
|
||||
|
||||
function checkForWinner(table){
|
||||
var i, j, k, l, maxRank, notFolded, winners, part, prize, allInPlayer, minBets, roundEnd;
|
||||
//Identify winner(s)
|
||||
winners = [];
|
||||
notFolded = [];
|
||||
maxRank = 0.000;
|
||||
for(k = 0; k < table.players.length; k += 1){
|
||||
if(table.players[k].folded === false){
|
||||
notFolded.push(k);
|
||||
}
|
||||
if(table.players[k].hand.rank === maxRank && table.players[k].folded === false){
|
||||
winners.push(k);
|
||||
}
|
||||
if(table.players[k].hand.rank > maxRank && table.players[k].folded === false){
|
||||
maxRank = table.players[k].hand.rank;
|
||||
winners.splice(0, winners.length);
|
||||
winners.push(k);
|
||||
}
|
||||
}
|
||||
// handle mid-round fold
|
||||
if(winners.length === 0 && notFolded.length == 1){
|
||||
console.log('mid round fold');
|
||||
winners.push(notFolded[0]);
|
||||
}
|
||||
part = 0;
|
||||
prize = 0;
|
||||
console.log('roundBets', table.game.roundBets);
|
||||
allInPlayer = checkForAllInPlayer(table, winners);
|
||||
if(allInPlayer.length > 0){
|
||||
minBets = table.game.roundBets[winners[0]];
|
||||
for(j = 1; j < allInPlayer.length; j += 1){
|
||||
if(table.game.roundBets[winners[j]] !== 0 && table.game.roundBets[winners[j]] < minBets){
|
||||
minBets = table.game.roundBets[winners[j]];
|
||||
}
|
||||
}
|
||||
part = parseInt(minBets, 10);
|
||||
}else{
|
||||
part = parseInt(table.game.roundBets[winners[0]], 10);
|
||||
}
|
||||
console.log('part', part);
|
||||
for(l = 0; l < table.game.roundBets.length; l += 1){
|
||||
// handle user leave
|
||||
// console.log('more than 1 player', table.players.length > 1 && (table.players.length - table.playersToRemove.length > 1));
|
||||
if(table.game.roundBets[l] > part){
|
||||
prize += part;
|
||||
table.game.roundBets[l] -= part;
|
||||
}else{
|
||||
prize += table.game.roundBets[l];
|
||||
table.game.roundBets[l] = 0;
|
||||
}
|
||||
}
|
||||
console.log('prize', prize);
|
||||
console.log('winners', winners);
|
||||
|
||||
if(prize > 0){
|
||||
var remainder = prize % winners.length;
|
||||
var winnerHands = [];
|
||||
var highestIndex;
|
||||
var winnerPrize = Math.floor(prize / winners.length);
|
||||
if(remainder !== 0){
|
||||
console.log('chip remainder of '+remainder);
|
||||
for(i=0;i<winners.length;++i){
|
||||
winnerHands.push(table.players[winners[i]].cards);
|
||||
}
|
||||
highestIndex = getOddChipWinner(winnerHands);
|
||||
}
|
||||
|
||||
for(i=0;i<winners.length;++i){
|
||||
var winningPlayer = table.players[winners[i]];
|
||||
if(i === highestIndex){
|
||||
winnerPrize += remainder;
|
||||
console.log('player '+winningPlayer.playerName+' gets the remaining '+remainder+' chips');
|
||||
}
|
||||
winningPlayer.chips += winnerPrize;
|
||||
if(table.game.roundBets[winners[i]] === 0){
|
||||
winningPlayer.folded = true;
|
||||
table.gameWinners.push({
|
||||
playerName: winningPlayer.playerName,
|
||||
id: winningPlayer.id,
|
||||
amount: winnerPrize,
|
||||
hand: winningPlayer.hand,
|
||||
chips: winningPlayer.chips
|
||||
});
|
||||
}
|
||||
logger.debug('player '+table.players[winners[i]].playerName+'('+table.players[winners[i]].id+') wins '+winnerPrize+' chips');
|
||||
if(i === highestIndex)
|
||||
winnerPrize -= remainder;
|
||||
}
|
||||
}
|
||||
roundEnd = true;
|
||||
console.log('roundBets', table.game.roundBets);
|
||||
for(l = 0; l < table.game.roundBets.length;l+=1){
|
||||
if(table.game.roundBets[l] !== 0){
|
||||
roundEnd = false;
|
||||
}
|
||||
}
|
||||
if(roundEnd === false){
|
||||
checkForWinner(table);
|
||||
}
|
||||
}
|
||||
|
||||
function checkForBankrupt(table){
|
||||
var i;
|
||||
for(i=0;i<table.players.length;i+= 1){
|
||||
if(table.players[i].chips === 0){
|
||||
table.gameLosers.push(table.players[i]);
|
||||
logger.debug('player '+table.players[i].playerName+'('+table.players[i].id+') went bankrupt');
|
||||
// table.players.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getOddChipWinner(hands){
|
||||
var i, highestIndex, highestAmt = 0;
|
||||
console.log('getOddChipWinner', hands);
|
||||
for(i=0;i<hands.length;++i){
|
||||
var hand = hands[i];
|
||||
var rank1 = getCardRank(hand[0]);
|
||||
var rank2 = getCardRank(hand[1]);
|
||||
if(highestAmt < rank1){
|
||||
highestAmt = rank1;
|
||||
highestIndex = i;
|
||||
}
|
||||
if(highestAmt < rank2){
|
||||
highestAmt = rank2;
|
||||
highestIndex = i;
|
||||
}
|
||||
}
|
||||
console.log('odd chip owner result: '+highestIndex+' '+highestAmt);
|
||||
return highestIndex;
|
||||
}
|
||||
|
||||
function getCardRank(card){
|
||||
var rank = 0;
|
||||
switch(card[0]){
|
||||
case 'A': rank += 130; break;
|
||||
case 'K': rank += 120; break;
|
||||
case 'Q': rank += 110; break;
|
||||
case 'J': rank += 100; break;
|
||||
case 'T': rank += 90; break;
|
||||
case '9': rank += 80; break;
|
||||
case '8': rank += 70; break;
|
||||
case '7': rank += 60; break;
|
||||
case '6': rank += 50; break;
|
||||
case '5': rank += 40; break;
|
||||
case '4': rank += 30; break;
|
||||
case '3': rank += 20; break;
|
||||
case '2': rank += 10; break;
|
||||
}
|
||||
switch(card[1]){
|
||||
case 'S': rank += 4; break;
|
||||
case 'H': rank += 3; break;
|
||||
case 'D': rank += 2; break;
|
||||
case 'C': rank += 1; break;
|
||||
}
|
||||
return rank;
|
||||
}
|
203
game-server/app/game/table.js
Normal file
203
game-server/app/game/table.js
Normal file
@@ -0,0 +1,203 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var events = require('events');
|
||||
var Game = require('./game');
|
||||
var Player = require('./player');
|
||||
var GAME_SETTINGS = require('../../config/gameSettings.json');
|
||||
|
||||
/**
|
||||
* Table object handles table logic while it is stored in memory.
|
||||
*
|
||||
* @param {number} smallBlind small blind
|
||||
* @param {number} bigBlind big blind
|
||||
* @param {number} minPlayers minimum number of players before game can be started
|
||||
* @param {number} maxPlayers maximum number of players before game can be started
|
||||
* @param {number} minBuyIn minimum buy in
|
||||
* @param {number} maxBuyIn maximum buy in
|
||||
* @param {string} gameMode type of game
|
||||
* @param {object} table instance of a table
|
||||
*
|
||||
*/
|
||||
module.exports = Table = function(smallBlind, bigBlind, minPlayers, maxPlayers, minBuyIn, maxBuyIn, gameMode, table){
|
||||
this.smallBlind = smallBlind;
|
||||
this.bigBlind = bigBlind;
|
||||
this.minPlayers = minPlayers;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.players = [];
|
||||
this.dealer = 0; //Track the dealer position between games
|
||||
this.minBuyIn = minBuyIn;
|
||||
this.maxBuyIn = maxBuyIn;
|
||||
this.previousPlayers = [];
|
||||
this.playersToRemove = [];
|
||||
this.playersToAdd = [];
|
||||
this.eventEmitter = new events.EventEmitter();
|
||||
this.turnBet = {};
|
||||
this.gameWinners = [];
|
||||
this.gameLosers = [];
|
||||
this.actions = [];
|
||||
this.members = [];
|
||||
this.active = false;
|
||||
this.gameMode = gameMode;
|
||||
this.instance = table;
|
||||
//Validate acceptable value ranges.
|
||||
var err;
|
||||
if(minPlayers < 2){ //require at least two players to start a game.
|
||||
err = new Error(101, 'Parameter [minPlayers] must be a postive integer of a minimum value of 2.');
|
||||
}else if(maxPlayers > 10){ //hard limit of 10 players at a table.
|
||||
err = new Error(102, 'Parameter [maxPlayers] must be a positive integer less than or equal to 10.');
|
||||
}else if(minPlayers > maxPlayers){ //Without this we can never start a game!
|
||||
err = new Error(103, 'Parameter [minPlayers] must be less than or equal to [maxPlayers].');
|
||||
}
|
||||
if(err){
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
Table.prototype.initNewGame = function(){
|
||||
var i;
|
||||
this.instance.state = 'JOIN';
|
||||
this.dealer += 1;
|
||||
if(this.dealer >= this.players.length){
|
||||
this.dealer = 0;
|
||||
}
|
||||
delete this.game;
|
||||
this.previousPlayers = [];
|
||||
// add existing players and remove players who left or are bankrupt
|
||||
for(i=0;i<this.players.length;++i){
|
||||
this.previousPlayers.push(this.players[i]);
|
||||
if(this.playersToRemove.indexOf(i) === -1){
|
||||
this.AddPlayer(this.players[i].playerName, this.players[i].chips, this.players[i].id);
|
||||
}
|
||||
}
|
||||
this.players = [];
|
||||
this.playersToRemove = [];
|
||||
this.actions = [];
|
||||
this.eventEmitter.emit('gameInit');
|
||||
};
|
||||
|
||||
Table.prototype.StartGame = function(){
|
||||
//If there is no current game and we have enough players, start a new game.
|
||||
this.instance.state = 'IN_PROGRESS';
|
||||
this.active = true;
|
||||
if(!this.game){
|
||||
this.game = new Game(this.smallBlind, this.bigBlind);
|
||||
this.NewRound();
|
||||
}
|
||||
};
|
||||
|
||||
Table.prototype.AddPlayer = function(playerName, chips, uid){
|
||||
if(chips >= this.minBuyIn && chips <= this.maxBuyIn){
|
||||
var player = new Player(playerName, chips, uid, this);
|
||||
this.playersToAdd.push(player);
|
||||
}
|
||||
};
|
||||
Table.prototype.removePlayer = function(pid){
|
||||
for(var i in this.players ){
|
||||
if(this.players[i].id === pid){
|
||||
this.playersToRemove.push( parseInt(i) );
|
||||
this.players[i].Fold();
|
||||
}
|
||||
}
|
||||
for(var i in this.playersToAdd ){
|
||||
if(this.playersToAdd[i].id === pid){
|
||||
this.playersToAdd.splice(i, 1);
|
||||
}
|
||||
}
|
||||
for(var i in this.members ){
|
||||
if(this.members[i].id === pid){
|
||||
this.members.splice(i, 1);
|
||||
}
|
||||
}
|
||||
for(var i in this.previousPlayers){
|
||||
if(this.previousPlayers[i].id === pid){
|
||||
this.previousPlayers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.eventEmitter.emit("playerLeft");
|
||||
}
|
||||
Table.prototype.NewRound = function(){
|
||||
var removeIndex = 0;
|
||||
for(var i in this.playersToAdd){
|
||||
// if(removeIndex < this.playersToRemove.length){
|
||||
// var index = this.playersToRemove[removeIndex];
|
||||
// this.players[index] = this.playersToAdd[i];
|
||||
// removeIndex += 1;
|
||||
// }else{
|
||||
// this.players.push(this.playersToAdd[i]);
|
||||
// }
|
||||
this.players.push(this.playersToAdd[i]);
|
||||
}
|
||||
this.playersToRemove = [];
|
||||
this.playersToAdd = [];
|
||||
this.gameWinners = [];
|
||||
this.gameLosers = [];
|
||||
|
||||
|
||||
var i, smallBlind, bigBlind;
|
||||
//Deal 2 cards to each player
|
||||
for(i=0;i< this.players.length;i+=1){
|
||||
this.players[i].cards.push(this.game.deck.pop());
|
||||
this.players[i].cards.push(this.game.deck.pop());
|
||||
this.game.bets[i] = 0;
|
||||
this.game.roundBets[i] = 0;
|
||||
}
|
||||
//Identify Small and Big Blind player indexes
|
||||
smallBlind = this.dealer + 1;
|
||||
if(smallBlind >= this.players.length){
|
||||
smallBlind = 0;
|
||||
}
|
||||
bigBlind = smallBlind + 1;
|
||||
if(bigBlind >= this.players.length){
|
||||
bigBlind = 0;
|
||||
}
|
||||
this.currentPlayer = bigBlind + 1;
|
||||
if(this.currentPlayer >= this.players.length){
|
||||
this.currentPlayer = 0;
|
||||
}
|
||||
this.startIndex = this.currentPlayer;
|
||||
//Force Blind Bets
|
||||
this.players[smallBlind].chips -= this.smallBlind;
|
||||
this.players[bigBlind].chips -= this.bigBlind;
|
||||
this.game.bets[smallBlind] = this.smallBlind;
|
||||
this.game.bets[bigBlind] = this.bigBlind;
|
||||
this.game.blinds = [smallBlind, bigBlind];
|
||||
|
||||
this.eventEmitter.emit("newRound");
|
||||
};
|
||||
|
||||
Table.prototype.startTimer = function(){
|
||||
var me = this;
|
||||
me.stopTimer();
|
||||
me._countdown = setTimeout(function(){
|
||||
if(!me.active){
|
||||
return;
|
||||
}
|
||||
console.log('timer ended. executing move.');
|
||||
if(me.game.bets[me.currentPlayer] < getMaxBet(me.game.bets)){
|
||||
me.players[me.currentPlayer].Fold();
|
||||
}else{
|
||||
me.players[me.currentPlayer].Call();
|
||||
}
|
||||
me.instance.tableService.handleGameState(me.instance.id, function(e){
|
||||
if(e){
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}, (GAME_SETTINGS.gameMode[this.gameMode].timeout * 1000));
|
||||
};
|
||||
|
||||
Table.prototype.stopTimer = function(){
|
||||
if(this._countdown){
|
||||
clearTimeout(this._countdown);
|
||||
}
|
||||
};
|
||||
|
||||
function getMaxBet(bets){
|
||||
var maxBet, i;
|
||||
maxBet = 0;
|
||||
for(i=0;i< bets.length;i+=1){
|
||||
if(bets[i] > maxBet){
|
||||
maxBet = bets[i];
|
||||
}
|
||||
}
|
||||
return maxBet;
|
||||
}
|
42
game-server/app/module/timeReport.js
Normal file
42
game-server/app/module/timeReport.js
Normal file
@@ -0,0 +1,42 @@
|
||||
module.exports = function(opts) {
|
||||
return new Module(opts);
|
||||
}
|
||||
|
||||
var testMsg = 'a default message';
|
||||
|
||||
var moduleId = "timeReport";
|
||||
module.exports.moduleId = moduleId;
|
||||
|
||||
var Module = function(opts) {
|
||||
this.app = opts.app;
|
||||
this.type = opts.type || 'pull';
|
||||
this.interval = opts.interval || 5;
|
||||
}
|
||||
|
||||
Module.prototype.monitorHandler = function(agent, msg, cb) {
|
||||
console.log(this.app.getServerId() + '' + msg);
|
||||
var serverId = agent.id;
|
||||
var time = new Date(). toString();
|
||||
|
||||
agent.notify(moduleId, {serverId: serverId, time: time});
|
||||
}
|
||||
|
||||
Module.prototype.masterHandler = function(agent, msg) {
|
||||
if(! msg) {
|
||||
agent.notifyAll(moduleId, testMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(msg);
|
||||
var timeData = agent.get(moduleId);
|
||||
if(! timeData) {
|
||||
timeData = {};
|
||||
agent.set(moduleId, timeData);
|
||||
}
|
||||
timeData[msg.serverId] = msg.time;
|
||||
}
|
||||
|
||||
|
||||
Module.prototype.clientHandler = function(agent, msg, cb) {
|
||||
cb(null, agent.get(moduleId));
|
||||
}
|
103
game-server/app/persistence/tables.js
Normal file
103
game-server/app/persistence/tables.js
Normal file
@@ -0,0 +1,103 @@
|
||||
var uuid = require('node-uuid');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
|
||||
var TableStore = module.exports = {
|
||||
store : './localstore/tables.json',
|
||||
entity : 'tables',
|
||||
create : function(obj, cb){
|
||||
var me = this;
|
||||
me.persist({
|
||||
id : obj.id || uuid.v1(),
|
||||
tid : obj.tid,
|
||||
smallBlind : obj.smallBlind,
|
||||
bigBlind : obj.bigBlind,
|
||||
minBuyIn : obj.minBuyIn,
|
||||
maxBuyIn : obj.maxBuyIn,
|
||||
minPlayers : obj.minPlayers,
|
||||
maxPlayers : obj.maxPlayers,
|
||||
gameMode : obj.gameMode,
|
||||
board : obj.board,
|
||||
creator : obj.creator,
|
||||
players : obj.players || [],
|
||||
actions : obj.actions || [],
|
||||
gameWinners : obj.gameWinners || [],
|
||||
created : Date.now()
|
||||
}, function(e, table){
|
||||
if(e){
|
||||
cb(e);
|
||||
}else{
|
||||
// console.log('TableStore: table created - ', table);
|
||||
cb(null, table);
|
||||
}
|
||||
});
|
||||
},
|
||||
set : function(obj, cb){
|
||||
var me = this;
|
||||
me.persist(obj, function(e, table){
|
||||
if(e){
|
||||
cb(e);
|
||||
}else{
|
||||
// console.log('TableStore: table modified - ', table);
|
||||
cb(null, table);
|
||||
}
|
||||
});
|
||||
},
|
||||
getByAttr : function(key, val, cb){
|
||||
var matches = [], matched;
|
||||
this.retrieve(function(e, entities){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
if(key == '*' && val == '*'){
|
||||
cb(null, entities);
|
||||
}else{
|
||||
for(var entity in entities){
|
||||
if(util.isArray(key)){
|
||||
matched = true;
|
||||
for(var i=key.length;i--;){
|
||||
if(entities[entity][key[i]] != val[i]){
|
||||
matched = false;
|
||||
}
|
||||
}
|
||||
if(matched){
|
||||
matches.push(entities[entity]);
|
||||
}
|
||||
}else if(entities[entity][key] == val){
|
||||
matches.push(entities[entity]);
|
||||
}
|
||||
}
|
||||
cb(null, matches.length == 0 ? null : (matches.length == 1 ? matches[0] : matches));
|
||||
}
|
||||
});
|
||||
},
|
||||
persist : function(row, cb){
|
||||
var me = this;
|
||||
me.retrieve(function(e, entities){
|
||||
entities[row.id] = entities[row.id] || {};
|
||||
for(var key in row){
|
||||
entities[row.id][key] = row[key];
|
||||
}
|
||||
fs.writeFile(me.store, JSON.stringify(entities, undefined, 4), function(e2){
|
||||
if(e2){
|
||||
return cb('error writing file: ' + e2);
|
||||
}else{
|
||||
cb(null, entities[row.id]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
retrieve : function(cb){
|
||||
fs.readFile(this.store, 'utf8', function(e, content){
|
||||
if(e){
|
||||
return cb('error loading file: ' + e);
|
||||
}
|
||||
if(content.trim().length == 0){
|
||||
content = {};
|
||||
}else{
|
||||
content = JSON.parse(content);
|
||||
}
|
||||
cb(null, content);
|
||||
});
|
||||
}
|
||||
};
|
132
game-server/app/persistence/users.js
Normal file
132
game-server/app/persistence/users.js
Normal file
@@ -0,0 +1,132 @@
|
||||
var uuid = require('node-uuid');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
|
||||
var UserStore = module.exports = {
|
||||
store : './localstore/users.json',
|
||||
entity : 'users',
|
||||
create : function(obj, callback){
|
||||
var me = this;
|
||||
me.getByAttr('username', obj.username, false, function(e, existingUser){
|
||||
if(existingUser){
|
||||
callback('user-exists', existingUser);
|
||||
}else{
|
||||
var id = uuid.v1();
|
||||
me.persist({
|
||||
id : id,
|
||||
username : obj.username,
|
||||
password : obj.password,
|
||||
email : obj.email,
|
||||
chips : obj.chips,
|
||||
wins : 0,
|
||||
largestWin : 0,
|
||||
friends : [],
|
||||
created : Date.now()
|
||||
}, function(e, user){
|
||||
if(e){
|
||||
callback(e);
|
||||
}else{
|
||||
callback(null, user);
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
set : function(obj, cb){
|
||||
var me = this;
|
||||
me.persist(obj, function(e, entity){
|
||||
if(e){
|
||||
cb(e);
|
||||
}else{
|
||||
cb(null, safetyFilter(entity));
|
||||
}
|
||||
});
|
||||
},
|
||||
getByAttr : function(key, val, opts, cb){
|
||||
var matches = [], matched;
|
||||
opts = opts || {};
|
||||
this.retrieve(function(e, entities){
|
||||
if(e){
|
||||
return cb(e, []);
|
||||
}
|
||||
for(var entity in entities){
|
||||
if(util.isArray(key)){
|
||||
matched = true;
|
||||
for(var i=key.length;i--;){
|
||||
if(entities[entity][key[i]] != val[i]){
|
||||
matched = false;
|
||||
}
|
||||
}
|
||||
if(matched){
|
||||
matches.push(opts.getFullEntity ? entities[entity] : safetyFilter(entities[entity]));
|
||||
}
|
||||
}else if(entities[entity][key] == val || (key == '*' && val == '*')){
|
||||
matches.push(opts.getFullEntity ? entities[entity] : safetyFilter(entities[entity]));
|
||||
}
|
||||
}
|
||||
matches = opts.getArray ? matches : (matches.length == 0 ? null : (matches.length == 1 ? matches[0] : matches));
|
||||
cb(null, matches);
|
||||
});
|
||||
},
|
||||
getByIds : function(ary, cb){
|
||||
var matches = [];
|
||||
this.retrieve(function(e, entities){
|
||||
if(e){
|
||||
return cb(e, []);
|
||||
}
|
||||
for(var entity in entities){
|
||||
if(ary.indexOf(entities[entity].id) != -1){
|
||||
matches.push(safetyFilter(entities[entity]));
|
||||
}
|
||||
}
|
||||
cb(null, matches);
|
||||
});
|
||||
},
|
||||
persist : function(row, cb){
|
||||
var me = this;
|
||||
me.retrieve(function(e, entities){
|
||||
entities[row.id] = entities[row.id] || {};
|
||||
for(var key in row){
|
||||
entities[row.id][key] = row[key];
|
||||
}
|
||||
fs.writeFile(me.store, JSON.stringify(entities, undefined, 4), function(e2){
|
||||
if(e2){
|
||||
return cb('error writing file: ' + e2);
|
||||
}else{
|
||||
cb(null, entities[row.id]);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
retrieve : function(cb){
|
||||
fs.readFile(this.store, 'utf8', function(e, content){
|
||||
if(e){
|
||||
return cb('error loading file: ' + e);
|
||||
}
|
||||
if(content.trim().length == 0){
|
||||
content = {};
|
||||
}else{
|
||||
try{
|
||||
content = JSON.parse(content);
|
||||
}catch(e){
|
||||
console.log('parseerror');
|
||||
content = content.slice(0, - 1);
|
||||
content = JSON.parse(content);
|
||||
}
|
||||
}
|
||||
cb(null, content);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function safetyFilter(obj){
|
||||
return {
|
||||
id : obj.id,
|
||||
username : obj.username,
|
||||
email : obj.email,
|
||||
chips : obj.chips,
|
||||
wins : obj.wins,
|
||||
largestWin : obj.largestWin,
|
||||
created : obj.created
|
||||
}
|
||||
}
|
90
game-server/app/servers/chat/handler/chatHandler.js
Normal file
90
game-server/app/servers/chat/handler/chatHandler.js
Normal file
@@ -0,0 +1,90 @@
|
||||
var UserStore = require('../../../persistence/users');
|
||||
var dispatcher = require('../../../util/dispatcher');
|
||||
|
||||
module.exports = function(app){
|
||||
return new Handler(app, app.get('chatService'));
|
||||
};
|
||||
var Handler = function(app, chatService){
|
||||
this.app = app;
|
||||
this.chatService = chatService;
|
||||
};
|
||||
var handler = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Send messages to users in the channel
|
||||
*
|
||||
* @param {Object} msg message from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next stemp callback
|
||||
*
|
||||
*/
|
||||
handler.sendMessage = function(msg, session, next){
|
||||
var me = this;
|
||||
var tid = session.get('tid');
|
||||
var channelService = this.app.get('channelService');
|
||||
UserStore.getByAttr('id', session.uid, false, function(e, user){
|
||||
if(!user){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : 'user-not-exist'
|
||||
});
|
||||
return;
|
||||
}
|
||||
// target is all users
|
||||
if(msg.target == 'table'){
|
||||
var channel = channelService.getChannel(tid, true);
|
||||
msg.target = '*';
|
||||
channel.pushMessage({
|
||||
route : 'onChat',
|
||||
msg : msg.content,
|
||||
username : user.username,
|
||||
target : msg.target
|
||||
});
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
}else{
|
||||
// target is specific user
|
||||
me.chatService.pushByPlayerName(msg.target, {
|
||||
username : user.username,
|
||||
msg : msg.content
|
||||
}, function(e){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get friend list
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.getFriends = function(msg, session, next){
|
||||
this.chatService.getFriendList(session.uid, function(e, friends){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route,
|
||||
friends : friends
|
||||
});
|
||||
});
|
||||
};
|
48
game-server/app/servers/chat/remote/chatRemote.js
Normal file
48
game-server/app/servers/chat/remote/chatRemote.js
Normal file
@@ -0,0 +1,48 @@
|
||||
module.exports = function(app){
|
||||
return new ChatRemote(app, app.get('chatService'));
|
||||
};
|
||||
|
||||
var ChatRemote = function(app, chatService){
|
||||
this.app = app;
|
||||
this.chatService = chatService;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add player into channel
|
||||
*/
|
||||
ChatRemote.prototype.addToChannel = function(uid, cid, cb){
|
||||
this.chatService.addToChannel(uid, cid, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add player record
|
||||
*/
|
||||
ChatRemote.prototype.add = function(uid, cid, cb){
|
||||
this.chatService.add(uid, cid, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get members in a channel
|
||||
*/
|
||||
ChatRemote.prototype.getMembers = function(cid, cb){
|
||||
this.chatService.getMembers(cid, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* leave Channel
|
||||
* uid
|
||||
* cid
|
||||
*/
|
||||
ChatRemote.prototype.leave = function(uid, cid, cb){
|
||||
this.chatService.leave(uid, cid);
|
||||
cb();
|
||||
};
|
||||
|
||||
/**
|
||||
* kick out user
|
||||
*
|
||||
*/
|
||||
ChatRemote.prototype.disconnect = function(uid, cb){
|
||||
this.chatService.disconnect(uid);
|
||||
cb();
|
||||
};
|
101
game-server/app/servers/connector/handler/entryHandler.js
Normal file
101
game-server/app/servers/connector/handler/entryHandler.js
Normal file
@@ -0,0 +1,101 @@
|
||||
var logger = require('pomelo-logger').getLogger('con-log', __filename);
|
||||
|
||||
module.exports = function(app){
|
||||
return new Handler(app);
|
||||
};
|
||||
var Handler = function(app){
|
||||
this.app = app;
|
||||
};
|
||||
var handler = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Register user.
|
||||
*
|
||||
* @param {Object} msg request message
|
||||
* @param {Object} session current session object
|
||||
* @param {Function} next next step callback
|
||||
*/
|
||||
handler.register = function(msg, session, next){
|
||||
this.app.rpc.game.authRemote.register(session, msg, function(e, user){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}else{
|
||||
next(null, {
|
||||
code : 201
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Connect to the server
|
||||
*
|
||||
* @param {Object} msg request message
|
||||
* @param {Object} session current session object
|
||||
* @param {Function} next next step callback
|
||||
*/
|
||||
handler.connect = function(msg, session, next){
|
||||
var me = this;
|
||||
var sessionService = me.app.get('sessionService');
|
||||
me.app.rpc.game.authRemote.auth(session, msg, function(e, user, token){
|
||||
if(!user){
|
||||
next(null, {
|
||||
code : 401,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
// duplicate log in
|
||||
if(!! sessionService.getByUid(user.id)){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'duplicate-session'
|
||||
});
|
||||
}
|
||||
session.bind(user.id, function(e){
|
||||
if(e){
|
||||
console.error('error-binding-user', e);
|
||||
}
|
||||
session.set('username', user.username);
|
||||
session.on('closed', onUserLeave.bind(null, me.app));
|
||||
session.pushAll(function(e){
|
||||
if(e){
|
||||
console.error('set username for session service failed! error is : %j', e.stack);
|
||||
}
|
||||
});
|
||||
// add user to chat service
|
||||
me.app.rpc.chat.chatRemote.add(session, session.uid, function(e){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
token : token,
|
||||
user : user
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
/**
|
||||
* User log out handler
|
||||
*
|
||||
* @param {Object} app current application
|
||||
* @param {Object} session current session object
|
||||
*
|
||||
*/
|
||||
var onUserLeave = function(app, session){
|
||||
if(!session || !session.uid || !session.get('tid')){
|
||||
return;
|
||||
}
|
||||
if(session.get('tid')){
|
||||
app.rpc.chat.chatRemote.disconnect(session, session.uid, function(){});
|
||||
app.rpc.game.tableRemote.removeMember(session, session.uid, app.get('serverId'), session.get('tid'), function(){});
|
||||
}
|
||||
};
|
22
game-server/app/servers/game/filter/abuseFilter.js
Normal file
22
game-server/app/servers/game/filter/abuseFilter.js
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
module.exports = function(){
|
||||
return new Filter();
|
||||
};
|
||||
|
||||
var Filter = function(){};
|
||||
|
||||
Filter.prototype.before = function (msg, session, next){
|
||||
if(msg.content && msg.content.indexOf ('fuck') !== -1){
|
||||
session.__abuse__ = true;
|
||||
msg.content = msg.content.replace ('fuck', '****');
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
Filter.prototype.after = function (err, msg, session, resp, next){
|
||||
if(session.__abuse__){
|
||||
var user_info = session.uid.split ('*');
|
||||
console.log ('abuse:' + user_info[0] + "at room" + user_info[1]);
|
||||
}
|
||||
next(err);
|
||||
};
|
245
game-server/app/servers/game/handler/tableHandler.js
Normal file
245
game-server/app/servers/game/handler/tableHandler.js
Normal file
@@ -0,0 +1,245 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
|
||||
module.exports = function(app){
|
||||
return new Handler(app);
|
||||
};
|
||||
var Handler = function(app){
|
||||
this.app = app;
|
||||
};
|
||||
var handler = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Get tables
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.getTables = function(msg, session, next){
|
||||
var tableService = this.app.get('tableService');
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route,
|
||||
tables : tableService.getTables()
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create table
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.createTable = function(msg, session, next){
|
||||
if(session.get('tid')){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : 'already-in-table'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.app.get('tableService').createTable(session.uid, msg, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Join table
|
||||
*
|
||||
* @param {Object} msg table parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.joinTable = function(msg, session, next){
|
||||
var me = this;
|
||||
var tableService = this.app.get('tableService');
|
||||
var table = tableService.getTable(msg.tid);
|
||||
if(!msg.tid || !table){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : 'invalid-table'
|
||||
});
|
||||
return;
|
||||
}
|
||||
session.set('tid', msg.tid);
|
||||
session.pushAll(function(err){
|
||||
if(err){
|
||||
logger.error('set tid for session service failed! error is : %j', err.stack);
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : 'server-error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
var tid = session.get('tid');
|
||||
me.app.rpc.chat.chatRemote.addToChannel(session, session.uid, tid, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
tableService.addMember(tid, session.uid, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Leave table
|
||||
*
|
||||
* @param {Object} msg table parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.leaveTable = function(msg, session, next){
|
||||
var me = this;
|
||||
var tid = session.get('tid');
|
||||
if(!tid){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'not-table-member'
|
||||
});
|
||||
}
|
||||
me.app.rpc.chat.chatRemote.leave(session, session.uid, tid, function(e){});
|
||||
session.set('tid', undefined);
|
||||
session.pushAll(function(e){
|
||||
if(e){
|
||||
logger.error('unset tid for session service failed! error is : %j', e.stack);
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'server-error'
|
||||
});
|
||||
}
|
||||
me.app.get('tableService').removeMember(tid, session.uid, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Join game
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.joinGame = function(msg, session, next){
|
||||
this.app.get('tableService').addPlayer(session.get('tid'), session.uid, msg.buyIn, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
return;
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start game
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.startGame = function(msg, session, next){
|
||||
this.app.get('tableService').startGame(session.get('tid'), function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform an action on your turn
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.execute = function(msg, session, next){
|
||||
this.app.get('tableService').performAction(session.get('tid'), session.uid, msg, function(e){
|
||||
if(e){
|
||||
next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform an action on your turn
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.removeBots = function(msg, session, next){
|
||||
var botService = this.app.get('botService');
|
||||
botService.removeAllBots(session.get('tid'), true);
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
188
game-server/app/servers/game/handler/userHandler.js
Normal file
188
game-server/app/servers/game/handler/userHandler.js
Normal file
@@ -0,0 +1,188 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var UserStore = require('../../../persistence/users');
|
||||
|
||||
module.exports = function(app){
|
||||
return new Handler(app);
|
||||
};
|
||||
var Handler = function(app){
|
||||
this.app = app;
|
||||
};
|
||||
var handler = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Get users matching the criteria
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.getUsers = function(msg, session, next){
|
||||
if(!msg.name && !msg.val && !session.uid){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'invalid-input'
|
||||
});
|
||||
}
|
||||
var searchId = (msg.name == 'id' || msg.name == 'username' || msg.name == 'email') ? msg.name : 'id';
|
||||
var searchVal = typeof msg.val === 'string' ? msg.val : session.uid;
|
||||
UserStore.getByAttr(searchId, searchVal, {
|
||||
getArray : true
|
||||
}, function(e, matches){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route,
|
||||
matches : matches
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update user profile
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.setProfile = function(msg, session, next){
|
||||
if(!session.uid){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'invalid-session'
|
||||
});
|
||||
}
|
||||
UserStore.getByAttr('id', session.uid, false, function(e, user){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
var userObj = {
|
||||
id : user.id
|
||||
};
|
||||
if(msg.email){
|
||||
userObj.email = msg.email.trim();
|
||||
}
|
||||
UserStore.set(userObj, function(e, updatedUser){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update user password
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.setPassword = function(msg, session, next){
|
||||
if(!session.uid || !msg.oldpassword || !msg.password){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'invalid-input'
|
||||
});
|
||||
}
|
||||
UserStore.getByAttr(['id', 'password'], [session.uid, msg.oldpassword], false, function(e, user){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
var userObj = {
|
||||
id : user.id,
|
||||
password : msg.password.trim()
|
||||
};
|
||||
UserStore.set(userObj, function(e, updatedUser){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a friend to friend list
|
||||
*
|
||||
* @param {Object} msg game parameters from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next step callback
|
||||
*
|
||||
*/
|
||||
handler.addFriend = function(msg, session, next){
|
||||
if(!session.uid){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : 'invalid-session'
|
||||
});
|
||||
}
|
||||
if(!msg.friend){
|
||||
return next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
}
|
||||
UserStore.getByAttr('id', session.uid, {
|
||||
getFullEntity : true
|
||||
}, function(e, user){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
UserStore.getByAttr('id', msg.friend, false, function(e, friend){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
user.friends.push({
|
||||
id : friend.id,
|
||||
username : friend.username
|
||||
});
|
||||
UserStore.set({
|
||||
id : user.id,
|
||||
friends : user.friends
|
||||
}, function(e, updatedUser){
|
||||
if(e){
|
||||
return next(null, {
|
||||
code : 500,
|
||||
error : e
|
||||
});
|
||||
}
|
||||
next(null, {
|
||||
code : 200,
|
||||
route : msg.route
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
82
game-server/app/servers/game/remote/authRemote.js
Normal file
82
game-server/app/servers/game/remote/authRemote.js
Normal file
@@ -0,0 +1,82 @@
|
||||
var UserStore = require('../../../persistence/users');
|
||||
var tokenService = require('../../../../../shared/token');
|
||||
var SESSION_CONFIG = require('../../../../../shared/config/session.json');
|
||||
|
||||
module.exports = function(app){
|
||||
return new Remote(app);
|
||||
};
|
||||
var Remote = function(app){
|
||||
this.app = app;
|
||||
};
|
||||
var remote = Remote.prototype;
|
||||
|
||||
/**
|
||||
* Register user.
|
||||
*
|
||||
* @param {object} userObj object containing userObj.user and userObj.pass
|
||||
* @param {Function} cb
|
||||
* @return {Void}
|
||||
*/
|
||||
remote.register = function(userObj, cb){
|
||||
UserStore.create({
|
||||
username : userObj.username,
|
||||
password : userObj.password,
|
||||
email : userObj.email,
|
||||
chips : 100000
|
||||
}, function(e, user){
|
||||
if(e){
|
||||
cb(e);
|
||||
}else{
|
||||
cb(null, user);
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Auth via user/pass or token, and check for expiry.
|
||||
*
|
||||
* @param {object|string} input token or object containing username and password
|
||||
* @param {Function} cb
|
||||
* @return {Void}
|
||||
*/
|
||||
remote.auth = function(input, cb){
|
||||
if(typeof input === 'string'){
|
||||
var res = tokenService.parse(input, SESSION_CONFIG.secret);
|
||||
if(!res){
|
||||
cb('invalid-token');
|
||||
return;
|
||||
}
|
||||
if(!checkExpire(res, SESSION_CONFIG.expire)){
|
||||
cb('token-expired');
|
||||
return;
|
||||
}
|
||||
UserStore.getByAttr('id', res.uid, false, function(e, user){
|
||||
if(e){
|
||||
cb('invalid-user');
|
||||
return;
|
||||
}
|
||||
cb(null, user);
|
||||
});
|
||||
}else{
|
||||
UserStore.getByAttr(['username', 'password'], [input.username, input.password], false, function(e, user){
|
||||
if(!user){
|
||||
cb('invalid-user');
|
||||
}else{
|
||||
cb(null, user, tokenService.create(user.id, Date.now(), SESSION_CONFIG.secret));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Check the token whether expire.
|
||||
*
|
||||
* @param {Object} token token info
|
||||
* @param {Number} expire expire time
|
||||
* @return {Boolean} true for not expire and false for expire
|
||||
*/
|
||||
var checkExpire = function(token, expire){
|
||||
if(expire < 0){
|
||||
// negative expire means never expire
|
||||
return true;
|
||||
}
|
||||
return (Date.now() - token.timestamp) < expire;
|
||||
};
|
22
game-server/app/servers/game/remote/tableRemote.js
Normal file
22
game-server/app/servers/game/remote/tableRemote.js
Normal file
@@ -0,0 +1,22 @@
|
||||
module.exports = function(app){
|
||||
return new Remote(app);
|
||||
};
|
||||
var Remote = function(app){
|
||||
this.app = app;
|
||||
this.tableService = app.get('tableService');
|
||||
};
|
||||
var remote = Remote.prototype;
|
||||
|
||||
/**
|
||||
* Remove member/player from table
|
||||
*
|
||||
* @param {string} uid user id
|
||||
* @param {string} sid server id
|
||||
* @param {string} tid channel id
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
remote.removeMember = function(uid, sid, tid, cb){
|
||||
this.tableService.removeMember(tid, uid, cb);
|
||||
};
|
||||
|
37
game-server/app/servers/gate/handler/gateHandler.js
Normal file
37
game-server/app/servers/gate/handler/gateHandler.js
Normal file
@@ -0,0 +1,37 @@
|
||||
var dispatcher = require('../../../util/dispatcher');
|
||||
|
||||
module.exports = function(app){
|
||||
return new Handler(app);
|
||||
};
|
||||
|
||||
var Handler = function(app){
|
||||
this.app = app;
|
||||
};
|
||||
|
||||
var handler = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Gate handler that dispatch user to connectors.
|
||||
*
|
||||
* @param {Object} msg message from client
|
||||
* @param {Object} session
|
||||
* @param {Function} next next stemp callback
|
||||
*
|
||||
*/
|
||||
handler.queryEntry = function(msg, session, next){
|
||||
// get all connectors
|
||||
var connectors = this.app.getServersByType('connector');
|
||||
if(!connectors || connectors.length === 0){
|
||||
next(null, {
|
||||
code : 500
|
||||
});
|
||||
return;
|
||||
}
|
||||
// select connector
|
||||
var res = dispatcher.dispatch(1, connectors);
|
||||
next(null, {
|
||||
code : 200,
|
||||
host : res.host,
|
||||
port : res.clientPort
|
||||
});
|
||||
};
|
388
game-server/app/services/botService.js
Normal file
388
game-server/app/services/botService.js
Normal file
@@ -0,0 +1,388 @@
|
||||
var BOT_CONFIG = require('../../config/bots.json');
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var UserStore = require('../../app/persistence/users');
|
||||
Hand = require('hoyle').Hand;
|
||||
|
||||
|
||||
var BotService = function(app){
|
||||
this.app = app;
|
||||
this.channelService = app.get('channelService');
|
||||
this.tableService = app.get('tableService');
|
||||
this.tableInstance = {};
|
||||
this.tableInstanceActive = {};
|
||||
this.bots = {};
|
||||
this.config = BOT_CONFIG.config;
|
||||
};
|
||||
|
||||
module.exports = BotService;
|
||||
|
||||
BotService.prototype.start = function(cb){
|
||||
var me = this;
|
||||
if(!me.config.enabled){
|
||||
return cb();
|
||||
}
|
||||
me.registerBots(BOT_CONFIG.bots, function(){
|
||||
logger.info('all bots registered');
|
||||
me.checkAvailability();
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
BotService.prototype.registerBots = function(bots, cb){
|
||||
var me = this, i = 0;
|
||||
if(!bots.length){
|
||||
cb();
|
||||
}
|
||||
function createIfNotExist(){
|
||||
bots[i].chips = 100000;
|
||||
UserStore.create(bots[i], function(e, user){
|
||||
me.bots[user.id] = user;
|
||||
me.bots[user.id].available = true;
|
||||
if(++i == bots.length){
|
||||
return cb();
|
||||
}
|
||||
createIfNotExist();
|
||||
});
|
||||
}
|
||||
createIfNotExist();
|
||||
};
|
||||
|
||||
BotService.prototype.checkAvailability = function(){
|
||||
var me = this;
|
||||
setInterval(function(){
|
||||
var bot = me.getAvailableBot();
|
||||
var table = me.getAvailableTable();
|
||||
if(bot && table && (!me.config.minBots || me.config.minBots > me.getActiveBots()) && !me.config.banBots){
|
||||
me.joinGame(bot, table);
|
||||
}
|
||||
}, (1000 * getRandomInt(me.config.joinInterval.min, (me.config.joinInterval.max))));
|
||||
};
|
||||
|
||||
BotService.prototype.getById = function(id){
|
||||
return this.bots[id];
|
||||
};
|
||||
|
||||
BotService.prototype.getAvailableBot = function(){
|
||||
var bot;
|
||||
for(var i in this.bots){
|
||||
if(this.bots[i].available){
|
||||
bot = this.bots[i];
|
||||
}
|
||||
}
|
||||
return bot;
|
||||
};
|
||||
|
||||
BotService.prototype.getActiveBots = function(){
|
||||
var ctr = 0;
|
||||
for(var i in this.bots){
|
||||
if(!this.bots[i].available){
|
||||
ctr += 1;
|
||||
}
|
||||
}
|
||||
return ctr;
|
||||
};
|
||||
|
||||
BotService.prototype.getAvailableTable = function(){
|
||||
var table;
|
||||
for(var i in this.tableService.tables){
|
||||
if(!this.tableInstanceActive[i] && (this.tableService.tables[i].state == 'JOIN' && this.tableService.tables[i].table.playersToAdd.length < this.tableService.tables[i].table.maxPlayers) ||
|
||||
(this.tableService.tables[i].state == 'IN_PROGRESS' && (this.tableService.tables[i].table.playersToAdd + this.tableService.tables[i].table.players.length) < this.tableService.tables[i].table.maxPlayers)){
|
||||
table = this.tableService.tables[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
};
|
||||
|
||||
BotService.prototype.joinGame = function(bot, table){
|
||||
var me = this;
|
||||
me.tableService.addPlayer(table.id, bot.id, me.config.buyIn || 1000, function(e){
|
||||
if(e){
|
||||
return logger.error('bot error joining game', e);
|
||||
}
|
||||
bot.available = false;
|
||||
bot.games = getRandomInt(me.config.gamesToPlay.min, me.config.gamesToPlay.max);
|
||||
bot.tid = table.id;
|
||||
logger.debug('bot '+bot.username+' joining table '+table.id+' for '+bot.games+' games');
|
||||
me.tableInstance[table.id] = me.tableInstance[table.id] || 0;
|
||||
me.tableInstance[table.id] += 1;
|
||||
me.listen(table.id);
|
||||
});
|
||||
};
|
||||
|
||||
BotService.prototype.startGame = function(table, tid){
|
||||
var me = this;
|
||||
var interval = setInterval(function(){
|
||||
if(table.state == 'IN_PROGRESS'){
|
||||
clearInterval(interval);
|
||||
}
|
||||
if(table.table.playersToAdd.length >= (me.config.minPlayers ? me.config.minPlayers : 0) && !me.config.banBots){
|
||||
table.tableService.startGame(tid, function(e){
|
||||
if(e){
|
||||
return logger.debug('cant start game yet', e);
|
||||
}
|
||||
clearInterval(interval);
|
||||
});
|
||||
}
|
||||
}, (1000 * getRandomInt(7, 20)));
|
||||
}
|
||||
|
||||
BotService.prototype.leaveGame = function(tid, uid, cb){
|
||||
var me = this;
|
||||
me.tableService.removeMember(tid, uid, function(){
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
BotService.prototype.listen = function(tid){
|
||||
var me = this;
|
||||
if(me.tableInstance[tid] > 1){
|
||||
return false;
|
||||
}
|
||||
logger.debug('initializing listeners for table '+tid);
|
||||
var table = me.tableService.getTable(tid);
|
||||
var playerJoinedListener = function(){
|
||||
logger.debug('playerJoined');
|
||||
me.startGame(table, tid);
|
||||
};
|
||||
var newRoundListener = function(){
|
||||
logger.debug('newRound');
|
||||
me.moveIfTurn(table);
|
||||
};
|
||||
var turnStartListener = function(){
|
||||
logger.debug('turnStart');
|
||||
me.moveIfTurn(table);
|
||||
};
|
||||
var gameInitListener = function(){
|
||||
logger.debug('gameInit');
|
||||
setTimeout(function(){
|
||||
me.removeAllBots(tid);
|
||||
}, 300);
|
||||
};
|
||||
table.table.eventEmitter.on('playerJoined', playerJoinedListener);
|
||||
table.table.eventEmitter.on('newRound', newRoundListener);
|
||||
table.table.eventEmitter.on('turnStart', turnStartListener);
|
||||
table.table.eventEmitter.on('gameInit', gameInitListener);
|
||||
};
|
||||
|
||||
BotService.prototype.moveIfTurn = function(table){
|
||||
var me = this, pid;
|
||||
if(typeof table.table.currentPlayer === 'number' && table.table.players[table.table.currentPlayer])
|
||||
pid = table.table.players[table.table.currentPlayer].id;
|
||||
if(this.bots[pid]){
|
||||
logger.debug('starting move: '+this.bots[pid].username);
|
||||
table.table.stopTimer();
|
||||
setTimeout(function(){
|
||||
if(!table.table || !table.table.game) return false;
|
||||
var board = table.table.game.board || [];
|
||||
if(board.length < 3){
|
||||
table.table.players[table.table.currentPlayer].Call();
|
||||
}else{
|
||||
performMove(table);
|
||||
}
|
||||
logger.debug('completed move.');
|
||||
table.tableService.handleGameState(table.id, function(e){
|
||||
if(e){
|
||||
logger.error(e);
|
||||
}
|
||||
});
|
||||
}, (getRandomInt(me.config.actionInterval.min, me.config.actionInterval.max) * 1000));
|
||||
}
|
||||
};
|
||||
|
||||
function performMove(table){
|
||||
var currentPlayer = table.table.players[table.table.currentPlayer];
|
||||
var myBet = table.table.game.bets[table.table.currentPlayer];
|
||||
var myHand = Hand.make(getHand(table.table.game.board.concat(table.table.players[table.table.currentPlayer].cards)));
|
||||
var maxBet = myBet;
|
||||
var maxRank = myHand.rank;
|
||||
var winningPlayer = currentPlayer.playerName;
|
||||
var hands = [];
|
||||
for(var i=0;i<table.table.players.length;++i){
|
||||
var bet = table.table.game.bets[i];
|
||||
var hand = Hand.make(getHand(table.table.game.board.concat(table.table.players[i].cards)));
|
||||
if(bet > maxBet) maxBet = bet;
|
||||
if(hand.rank > maxRank){
|
||||
maxRank = hand.rank;
|
||||
winningPlayer = table.table.players[i].playerName;
|
||||
}
|
||||
hands.push(hand);
|
||||
}
|
||||
logger.debug('has best hand: '+ winningPlayer);
|
||||
var isWinner = false;
|
||||
var winners = Hand.pickWinners(hands);
|
||||
var diff = maxBet - myBet;
|
||||
for(var i=0;i<winners.length;++i){
|
||||
if(winners[i] === myHand) isWinner = true;
|
||||
}
|
||||
if(myHand.rank < maxRank){
|
||||
if(myBet >= maxBet){
|
||||
if(getRandomInt(1, 51) > 47){
|
||||
currentPlayer.AllIn();
|
||||
}else if(getRandomInt(1, 10) > 7){
|
||||
currentPlayer.Bet(getRandomInt(2, 53));
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}else if(myBet < maxBet){
|
||||
if(diff > getRandomInt(4, 61)){
|
||||
if(getRandomInt(1, 73) > 71){
|
||||
currentPlayer.AllIn();
|
||||
}else if(getRandomInt(1, 10) > 8){
|
||||
currentPlayer.Bet(getRandomInt(2, 36));
|
||||
}else if(getRandomInt(1, 10) > 2){
|
||||
currentPlayer.Fold();
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}else{
|
||||
if(getRandomInt(1, 73) > 70){
|
||||
currentPlayer.AllIn();
|
||||
}else if(getRandomInt(1, 10) > 7){
|
||||
currentPlayer.Bet(getRandomInt(2, 43));
|
||||
}else if(diff > getRandomInt(1, 7) && getRandomInt(1, 10) > 6){
|
||||
currentPlayer.Fold();
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}else{
|
||||
if(myBet >= maxBet){
|
||||
if(getRandomInt(1, 10) == 10){
|
||||
currentPlayer.AllIn();
|
||||
}else if(getRandomInt(1, 10) > 4){
|
||||
currentPlayer.Bet(getRandomInt(1, 271));
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}else if(myBet < maxBet){
|
||||
if(getRandomInt(1, 10) == 10){
|
||||
currentPlayer.AllIn();
|
||||
}else if(getRandomInt(1, 10) > 4){
|
||||
currentPlayer.Bet(getRandomInt(2, 189));
|
||||
}else if(diff > getRandomInt(71, 104) && getRandomInt(1, 10) > 8){
|
||||
currentPlayer.Fold();
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}else{
|
||||
currentPlayer.Call();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getHand(hand){
|
||||
for(var j=0;j<hand.length;++j){
|
||||
hand[j] = hand[j].split('');
|
||||
hand[j] = hand[j][0]+hand[j][1].toLowerCase();
|
||||
}
|
||||
return hand;
|
||||
}
|
||||
|
||||
function getRandomInt(min, max){
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
BotService.prototype.removeAllBots = function(tid, banBots){
|
||||
var me = this, botAry = [];
|
||||
me.config.banBots = banBots;
|
||||
var table = me.tableService.getTable(tid);
|
||||
for(var id in me.bots){
|
||||
if(me.bots[id].tid === tid)
|
||||
botAry.push(id);
|
||||
}
|
||||
if(me.config.validateChips){
|
||||
me.tableInstanceActive[tid] = true;
|
||||
}
|
||||
me.removeBot(botAry, 0, tid, banBots, function(){
|
||||
if(me.tableInstance[tid] === 0){
|
||||
logger.debug('removing listeners for table '+tid);
|
||||
table.table.eventEmitter.removeAllListeners('playerJoined');
|
||||
table.table.eventEmitter.removeAllListeners('newRound');
|
||||
table.table.eventEmitter.removeAllListeners('turnStart');
|
||||
table.table.eventEmitter.removeAllListeners('gameInit');
|
||||
}
|
||||
if(me.config.validateChips){
|
||||
me.validateTotalChips(function(e){
|
||||
if(!e){
|
||||
me.tableInstanceActive[tid] = false;
|
||||
me.startGame(table, tid);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
me.startGame(table, tid);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
BotService.prototype.removeBot = function(botAry, i, tid, banBots, cb){
|
||||
var me = this;
|
||||
if(i === botAry.length){
|
||||
return cb();
|
||||
}
|
||||
var bid = botAry[i];
|
||||
if(me.bots[bid].tid === tid){
|
||||
me.bots[bid].games -= 1;
|
||||
var user = me.tableService.getPlayerJSON(tid, bid, 'players') || me.tableService.getPlayerJSON(tid, bid, 'playersToAdd') || me.tableService.getPlayerJSON(tid, bid, 'previousPlayers');
|
||||
console.log(me.tableService.getTable(tid));
|
||||
console.log(tid, bid, user);
|
||||
if(me.bots[bid].games === 0 || (user && user.chips === 0) || banBots === true){
|
||||
logger.debug('bot '+me.bots[bid].username+' ('+me.bots[bid].id+') left game '+tid+' with '+((user && user.chips) ? user.chips : 0)+' chips', user);
|
||||
me.leaveGame(tid, bid, function(){
|
||||
me.bots[bid].available = true;
|
||||
delete me.bots[bid].tid;
|
||||
me.tableInstance[tid] -= 1;
|
||||
me.removeBot(botAry, (i+1), tid, banBots, cb);
|
||||
});
|
||||
}else{
|
||||
me.removeBot(botAry, (i+1), tid, banBots, cb);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// validate chips per all bots
|
||||
BotService.prototype.validateTotalChips = function(cb){
|
||||
var total = 0;
|
||||
var ids = [];
|
||||
for(var i in this.bots){
|
||||
ids.push(this.bots[i].id);
|
||||
}
|
||||
UserStore.getByIds(ids, function(e, users){
|
||||
for(var user in users){
|
||||
total += users[user].chips;
|
||||
}
|
||||
var correctTotal = (ids.length * 100000);
|
||||
if(total != correctTotal){
|
||||
logger.error('INCORRECT TOTAL CHIPS! '+correctTotal+' - '+total+' = '+(correctTotal - total));
|
||||
return cb('incorrect-total');
|
||||
}
|
||||
logger.debug('correct total chips '+total+'/'+correctTotal);
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
// validate chips per table
|
||||
BotService.prototype.validateChips = function(table, cb){
|
||||
var me = this;
|
||||
var total = 0;
|
||||
var ids = [];
|
||||
for(var i=0;i<table.table.playersToAdd.length;++i){
|
||||
ids.push(table.table.playersToAdd[i].id);
|
||||
}
|
||||
UserStore.getByIds(ids, function(e, users){
|
||||
for(var user in users){
|
||||
total += users[user].chips;
|
||||
}
|
||||
total += (ids.length * me.config.buyIn);
|
||||
var correctTotal = (ids.length * 100000);
|
||||
if(total != correctTotal){
|
||||
logger.error('INCORRECT GAME CHIPS! '+correctTotal+' - '+total+' = '+(correctTotal - total));
|
||||
return cb('incorrect-total');
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
240
game-server/app/services/chatService.js
Normal file
240
game-server/app/services/chatService.js
Normal file
@@ -0,0 +1,240 @@
|
||||
var UserStore = require('../persistence/users');
|
||||
var dispatcher = require('../util/dispatcher');
|
||||
|
||||
var ChatService = function(app) {
|
||||
this.app = app;
|
||||
this.uidMap = {};
|
||||
this.nameMap = {};
|
||||
this.channelMap = {};
|
||||
};
|
||||
|
||||
module.exports = ChatService;
|
||||
|
||||
/**
|
||||
* Add player into a channel
|
||||
*
|
||||
* @param {String} uid user id
|
||||
* @param {String} cid channel id
|
||||
* @return {Number} see code.js
|
||||
*/
|
||||
ChatService.prototype.addToChannel = function(uid, cid, cb){
|
||||
var me = this;
|
||||
UserStore.getByAttr('id', uid, false, function(e, user){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
var sid = getSidByUid(uid, me.app);
|
||||
if(!sid){
|
||||
return cb('invalid-connector-server');
|
||||
}
|
||||
if(checkDuplicate(me, uid, cid)){
|
||||
return cb();
|
||||
}
|
||||
var channel = me.app.get('channelService').getChannel(cid, true);
|
||||
if(!channel){
|
||||
return cb('invalid-channel');
|
||||
}
|
||||
channel.add(uid, sid);
|
||||
addRecord(me, uid, user.username, sid, cid);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add player record
|
||||
*
|
||||
* @param {String} uid user id
|
||||
*/
|
||||
ChatService.prototype.add = function(uid, cb){
|
||||
var me = this;
|
||||
UserStore.getByAttr('id', uid, false, function(e, user){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
var sid = getSidByUid(uid, me.app);
|
||||
if(!sid){
|
||||
return cb('invalid-connector-server');
|
||||
}
|
||||
addRecord(me, uid, user.username, sid);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* User leaves the channel
|
||||
*
|
||||
* @param {String} uid user id
|
||||
* @param {String} cid channel id
|
||||
*/
|
||||
ChatService.prototype.leave = function(uid, cid) {
|
||||
var record = this.uidMap[uid];
|
||||
var channel = this.app.get('channelService').getChannel(cid, true);
|
||||
if(channel && record) {
|
||||
channel.leave(uid, record.sid);
|
||||
}
|
||||
removeRecord(this, uid, cid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disconnect user from all channels in chat service.
|
||||
* This operation would remove the user from all channels and
|
||||
* clear all the records of the user.
|
||||
*
|
||||
* @param {String} uid user id
|
||||
*/
|
||||
ChatService.prototype.disconnect = function(uid){
|
||||
var cids = this.channelMap[uid];
|
||||
var record = this.uidMap[uid];
|
||||
if(cids && record){
|
||||
// remove user from channels
|
||||
var channel;
|
||||
for(var name in cids){
|
||||
channel = this.app.get('channelService').getChannel(name);
|
||||
if(channel){
|
||||
channel.leave(uid, record.sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
clearRecords(this, uid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get friend list
|
||||
* @param {string} uid user id
|
||||
* @param {Function} cb callback function
|
||||
*/
|
||||
ChatService.prototype.getFriendList = function(uid, cb){
|
||||
var me = this;
|
||||
UserStore.getByAttr('id', uid, {
|
||||
getFullEntity : true
|
||||
}, function(e, user){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
user.friends = user.friends || [];
|
||||
for(var i=0;i<user.friends.length;++i){
|
||||
user.friends[i].online = me.uidMap[user.friends[i].id] ? true : false;
|
||||
}
|
||||
cb(null, user.friends);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Push message by the specified channel
|
||||
*
|
||||
* @param {String} cid channel id
|
||||
* @param {Object} msg message json object
|
||||
* @param {Function} cb callback function
|
||||
*/
|
||||
ChatService.prototype.pushByChannel = function(cid, msg, cb){
|
||||
var channel = this.app.get('channelService').getChannel(cid);
|
||||
if(!channel){
|
||||
cb(new Error('channel ' + cid + ' doses not exist'));
|
||||
return;
|
||||
}
|
||||
channel.pushMessage('onChat', msg, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Push message to the specified player
|
||||
*
|
||||
* @param {String} username player's role name
|
||||
* @param {Object} msg message json object
|
||||
* @param {Function} cb callback
|
||||
*/
|
||||
ChatService.prototype.pushByPlayerName = function(username, msg, cb){
|
||||
var record = this.nameMap[username];
|
||||
if(!record){
|
||||
cb('user-not-online');
|
||||
return;
|
||||
}
|
||||
this.app.get('channelService').pushMessageByUids('onUserChat', msg, [{uid: record.uid, sid: record.sid}], cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Push message to the specified player
|
||||
*
|
||||
* @param {String} uid player's user id
|
||||
* @param {Object} msg message json object
|
||||
* @param {Function} cb callback
|
||||
*/
|
||||
ChatService.prototype.pushByPlayerId = function(uid, msg, cb){
|
||||
var record = this.uidMap[uid];
|
||||
if(!record){
|
||||
cb('user-not-online');
|
||||
return;
|
||||
}
|
||||
this.app.get('channelService').pushMessageByUids('onUserChat', msg, [{uid: record.uid, sid: record.sid}], cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the user is already in the channel
|
||||
*/
|
||||
var checkDuplicate = function(service, uid, cid) {
|
||||
return !!service.channelMap[uid] && !!service.channelMap[uid][cid];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add records for the specified user
|
||||
*/
|
||||
var addRecord = function(service, uid, name, sid, cid){
|
||||
var record = {uid: uid, name: name, sid: sid};
|
||||
service.uidMap[uid] = record;
|
||||
service.nameMap[name] = record;
|
||||
var item = service.channelMap[uid];
|
||||
if(!item){
|
||||
item = service.channelMap[uid] = {};
|
||||
}
|
||||
if(cid){
|
||||
item[cid] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove records for the specified user and channel pair
|
||||
*/
|
||||
var removeRecord = function(service, uid, cid) {
|
||||
delete service.channelMap[uid][cid];
|
||||
// if(objLen(service.channelMap[uid])){
|
||||
// return;
|
||||
// }
|
||||
// // if user not in any channel then clear his records
|
||||
// clearRecords(service, uid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear all records of the user
|
||||
*/
|
||||
var clearRecords = function(service, uid) {
|
||||
delete service.channelMap[uid];
|
||||
var record = service.uidMap[uid];
|
||||
if(!record) {
|
||||
return;
|
||||
}
|
||||
delete service.uidMap[uid];
|
||||
delete service.nameMap[record.name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the connector server id associated with the uid
|
||||
*/
|
||||
var getSidByUid = function(uid, app) {
|
||||
var connector = dispatcher.dispatch(uid, app.getServersByType('connector'));
|
||||
if(connector) {
|
||||
return connector.id;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
function objLen(obj){
|
||||
if(!obj) {
|
||||
return 0;
|
||||
}
|
||||
var size = 0;
|
||||
for(var f in obj) {
|
||||
if(obj.hasOwnProperty(f)) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
64
game-server/app/services/stateService.js
Normal file
64
game-server/app/services/stateService.js
Normal file
@@ -0,0 +1,64 @@
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var REDIS_CONFIG = require('../../config/redis.json');
|
||||
var redis = require('redis');
|
||||
|
||||
/**
|
||||
* Maintain a persistent store .
|
||||
*
|
||||
* StateService is created by stateComponent.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
*/
|
||||
module.exports = StateService = function(){
|
||||
this.prefix = 'POKER:';
|
||||
};
|
||||
|
||||
StateService.prototype.start = function(cb){
|
||||
this.redis.createClient(REDIS_CONFIG.port, REDIS_CONFIG.host, REDIS_CONFIG.opts);
|
||||
this.redis.on('error', function(e){
|
||||
logger.error('redis error', e.stack);
|
||||
cb('connection-error');
|
||||
});
|
||||
this.redis.once('ready', function(){
|
||||
logger.info('redis initialized!');
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
StateService.prototype.stop = function(cb){
|
||||
if(this.redis){
|
||||
logger.info('redis stopped');
|
||||
this.redis.end();
|
||||
this.redis = null;
|
||||
}
|
||||
cb();
|
||||
};
|
||||
|
||||
StateService.prototype.push = function(uid, sid ,cb){
|
||||
this.redis.sadd(genKey(this, uid), sid, function(err){
|
||||
invokeCallback(cb, err);
|
||||
});
|
||||
};
|
||||
|
||||
StateService.prototype.remove = function(uid, sid, cb){
|
||||
this.redis.srem(genKey(this, uid), sid, function(err){
|
||||
invokeCallback(cb, err);
|
||||
});
|
||||
};
|
||||
|
||||
StateService.prototype.getSidsByUid = function(uid, cb){
|
||||
this.redis.smembers(genKey(this, uid), function(err, list){
|
||||
invokeCallback(cb, err, list);
|
||||
});
|
||||
};
|
||||
|
||||
var genKey = function(me, uid){
|
||||
return me.prefix + ':' + uid;
|
||||
};
|
||||
|
||||
var invokeCallback = function(cb){
|
||||
if(!!cb && typeof cb === 'function'){
|
||||
cb.apply(null, Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
};
|
677
game-server/app/services/tableService.js
Normal file
677
game-server/app/services/tableService.js
Normal file
@@ -0,0 +1,677 @@
|
||||
var events = require('events');
|
||||
var uuid = require('node-uuid');
|
||||
var logger = require('pomelo-logger').getLogger('game-log', __filename);
|
||||
var TableStore = require('../../app/persistence/tables');
|
||||
var UserStore = require('../../app/persistence/users');
|
||||
var dispatcher = require('../util/dispatcher');
|
||||
var Table = require('../game/table');
|
||||
|
||||
/**
|
||||
* Create and maintain table tables.
|
||||
*
|
||||
* TableService is created by tableComponent.
|
||||
*
|
||||
* @class
|
||||
* @constructor
|
||||
*/
|
||||
var TableService = function(app, opts){
|
||||
opts = opts || {};
|
||||
this.app = app;
|
||||
this.tables = {};
|
||||
this.prefix = opts.prefix;
|
||||
this.store = opts.store;
|
||||
this.stateService = this.app.get('stateService');
|
||||
};
|
||||
|
||||
module.exports = TableService;
|
||||
|
||||
TableService.prototype.start = function(cb){
|
||||
cb();
|
||||
};
|
||||
|
||||
TableService.prototype.stop = function(force, cb){
|
||||
cb();
|
||||
};
|
||||
|
||||
TableService.prototype.getTable = function(tid){
|
||||
return this.tables[tid];
|
||||
};
|
||||
|
||||
TableService.prototype.getTables = function(){
|
||||
var tables = {
|
||||
tables : [],
|
||||
totalMembers : 0,
|
||||
totalPlayers : 0
|
||||
};
|
||||
for(var i in this.tables){
|
||||
var table = this.tables[i];
|
||||
var members = table.table.members.length;
|
||||
var players = (table.table.players.length - table.table.playersToRemove.length);
|
||||
tables.totalMembers += members;
|
||||
tables.totalPlayers += players;
|
||||
tables.tables.push({
|
||||
id : table.id,
|
||||
smallBlind : table.table.smallBlind,
|
||||
bigBlind : table.table.bigBlind,
|
||||
minBuyIn : table.table.minBuyIn,
|
||||
maxBuyIn : table.table.maxBuyIn,
|
||||
minPlayers : table.table.minPlayers,
|
||||
maxPlayers : table.table.maxPlayers,
|
||||
gameMode : table.table.gameMode,
|
||||
players : players,
|
||||
members : members
|
||||
});
|
||||
}
|
||||
return tables;
|
||||
};
|
||||
|
||||
TableService.prototype.createTable = function(uid, obj, cb){
|
||||
if(!obj || (obj && (
|
||||
isNaN(obj.smallBlind) ||
|
||||
isNaN(obj.bigBlind) ||
|
||||
isNaN(obj.minBuyIn) ||
|
||||
isNaN(obj.maxBuyIn) ||
|
||||
isNaN(obj.minPlayers) ||
|
||||
isNaN(obj.maxPlayers) ||
|
||||
obj.minPlayers < 2 ||
|
||||
obj.minPlayers > 10 ||
|
||||
obj.maxPlayers < 2 ||
|
||||
obj.maxPlayers > 10
|
||||
))){
|
||||
return cb('invalid-table-rules');
|
||||
}
|
||||
var tid = uuid.v1();
|
||||
this.tables[tid] = {};
|
||||
this.tables[tid].id = tid;
|
||||
this.tables[tid].creator = uid;
|
||||
this.tables[tid].state = 'JOIN';
|
||||
this.tables[tid].tableService = this;
|
||||
obj.smallBlind = Math.round(parseInt(obj.smallBlind));
|
||||
obj.bigBlind = Math.round(parseInt(obj.bigBlind));
|
||||
obj.minBuyIn = Math.round(parseInt(obj.minBuyIn));
|
||||
obj.maxBuyIn = Math.round(parseInt(obj.maxBuyIn));
|
||||
obj.minPlayers = Math.round(parseInt(obj.minPlayers));
|
||||
obj.maxPlayers = Math.round(parseInt(obj.maxPlayers));
|
||||
obj.gameMode = (obj.gameMode == 'normal' || obj.gameMode == 'fast') ? obj.gameMode : 'normal';
|
||||
this.tables[tid].table = new Table(obj.smallBlind, obj.bigBlind, obj.minPlayers, obj.maxPlayers, obj.minBuyIn, obj.maxBuyIn, obj.gameMode, this.tables[tid]);
|
||||
// automatically join created table
|
||||
// session.set('tid', table.id);
|
||||
// var tid = session.get('tid');
|
||||
// me.app.rpc.chat.chatRemote.add(session, session.uid, tid, function(e, users){
|
||||
// if(e){
|
||||
// next(500, {
|
||||
// code : 200,
|
||||
// error : e
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// var channelService = me.app.get('channelService');
|
||||
// var channel = channelService.getChannel(tid, true);
|
||||
// channel.pushMessage({
|
||||
// route : 'onTableEvent',
|
||||
// msg : tableService.getTableJSON(tid, session.uid)
|
||||
// });
|
||||
// channel.pushMessage({
|
||||
// route : 'onUpdateUsers',
|
||||
// users : users
|
||||
// });
|
||||
// tableService.broadcastGameState(tid);
|
||||
// next(null, {
|
||||
// code : 200,
|
||||
// route : msg.route
|
||||
// });
|
||||
// });
|
||||
cb(null, this.tables[tid]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add member to the table
|
||||
*
|
||||
* @param {Object} tid id of an existing table
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.addMember = function(tid, uid, cb){
|
||||
var me = this;
|
||||
var channelService = me.app.get('channelService');
|
||||
var table = this.tables[tid];
|
||||
if(!table){
|
||||
cb('table-not-found');
|
||||
return;
|
||||
}
|
||||
UserStore.getByAttr('id', uid, false, function(e, user){
|
||||
if(!user){
|
||||
cb(e);
|
||||
}
|
||||
var sid = getSidByUid(uid, me.app);
|
||||
if(!sid){
|
||||
return cb('invalid-connector-server');
|
||||
}
|
||||
// TODO: reduce payload by handling based on game state
|
||||
var channel = channelService.getChannel(tid, true);
|
||||
channel.add(uid, sid);
|
||||
channelService.pushMessageByUids({
|
||||
route : 'onTableEvent',
|
||||
msg : me.getTableJSON(tid, uid)
|
||||
}, [{
|
||||
uid : uid,
|
||||
sid : channel.getMember(uid)['sid']
|
||||
}], function(){
|
||||
logger.debug('initiated player '+uid+' into table '+tid+' with state '+table.state);
|
||||
table.table.members.push(user);
|
||||
channel.pushMessage({
|
||||
route : 'onUpdateUsers',
|
||||
members : table.table.members
|
||||
});
|
||||
cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the connector server id associated with the uid
|
||||
*/
|
||||
var getSidByUid = function(uid, app){
|
||||
var connector = dispatcher.dispatch(uid, app.getServersByType('connector'));
|
||||
if(connector){
|
||||
return connector.id;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove member from the table
|
||||
*
|
||||
* @param {Object} tid id of an existing table
|
||||
* @param {string} uid userId to remove from the table
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.removeMember = function(tid, uid, cb){
|
||||
var me = this;
|
||||
if(!me.tables[tid]){
|
||||
var e = 'table-not-found';
|
||||
logger.error('error removing player '+uid+' from table '+tid, e);
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
var channelService = me.app.get('channelService');
|
||||
var channel = channelService.getChannel(tid, false);
|
||||
if(channel && channel.getMember(uid)){
|
||||
channel.leave(uid, channel.getMember(uid)['sid']);
|
||||
}
|
||||
var user = me.getPlayerJSON(tid, uid, 'players') || me.getPlayerJSON(tid, uid, 'playersToAdd') || me.getPlayerJSON(tid, uid, 'previousPlayers');
|
||||
if(user){
|
||||
console.log('adding '+user.chips+' to player '+user.id);
|
||||
me.updatePlayerInfo(uid, {
|
||||
chips : user.chips
|
||||
}, function(e, updatedUser){
|
||||
if(e){
|
||||
logger.error('error removing player '+uid+' from table ', e);
|
||||
}else{
|
||||
logger.debug('removed player '+uid+' from table '+tid);
|
||||
}
|
||||
me.tables[tid].table.removePlayer(uid);
|
||||
me.pushPlayerInfo(tid, uid, updatedUser);
|
||||
me.handleGameState(tid, cb);
|
||||
});
|
||||
}else{
|
||||
me.tables[tid].table.removePlayer(uid);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update player information
|
||||
*
|
||||
* @param {string} uid id of a user to update
|
||||
* @param {object} obj updated player information
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.updatePlayerInfo = function(uid, obj, cb){
|
||||
UserStore.getByAttr('id', uid, false, function(e, user){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
if(!user){
|
||||
return cb('user-not-found');
|
||||
}
|
||||
var userObj = {
|
||||
id : user.id
|
||||
};
|
||||
if(obj.chips && typeof obj.chips === 'number' && obj.chips != 0){
|
||||
userObj.chips = Math.round(user.chips + Math.round(obj.chips))
|
||||
}
|
||||
if(obj.wins){
|
||||
userObj.wins = Math.round(user.wins + Math.round(obj.wins))
|
||||
}
|
||||
if(obj.wonAmount && obj.wonAmount > user.largestWin){
|
||||
userObj.largestWin = obj.wonAmount;
|
||||
}
|
||||
UserStore.set(userObj, function(e, updatedUser){
|
||||
if(e){
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
cb(null, updatedUser);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
TableService.prototype.getTableJSON = function(tid, uid){
|
||||
if(!this.tables[tid]){
|
||||
return;
|
||||
}
|
||||
var table = this.tables[tid];
|
||||
return {
|
||||
state : table.state,
|
||||
id : (table.table && table.table.game && table.table.game.id ? table.table.game.id : undefined),
|
||||
tid : tid,
|
||||
creator : table.creator,
|
||||
smallBlind : table.table.smallBlind,
|
||||
bigBlind : table.table.bigBlind,
|
||||
minPlayers : table.table.minPlayers,
|
||||
maxPlayers : table.table.maxPlayers,
|
||||
minBuyIn : table.table.minBuyIn,
|
||||
maxBuyIn : table.table.maxBuyIn,
|
||||
gameMode : table.table.gameMode,
|
||||
players : this.getPlayersJSON(tid, 'players', uid),
|
||||
playersToRemove : this.getPlayersJSON(tid, 'playersToRemove', uid),
|
||||
playersToAdd : this.getPlayersJSON(tid, 'playersToAdd', uid),
|
||||
gameWinners : this.getPlayersJSON(tid, 'gameWinners', uid),
|
||||
actions : table.table.actions,
|
||||
game : stripDeck(table.table.game, ['deck', 'id']),
|
||||
board : (table.table.game && table.table.game.board) ? table.table.game.board : [],
|
||||
currentPlayer : table.table.currentPlayer
|
||||
};
|
||||
};
|
||||
|
||||
function stripDeck(obj, props){
|
||||
var out = {};
|
||||
for(var key in obj){
|
||||
if(props.indexOf(key) == -1){
|
||||
out[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
TableService.prototype.getPlayerIndex = function(tid, uid, type){
|
||||
var match;
|
||||
if(!this.tables[tid]){
|
||||
return;
|
||||
}
|
||||
for(var i=0;i<this.tables[tid].table[type ? type : 'players'].length;++i){
|
||||
if(uid == this.tables[tid].table[type ? type : 'players'][i].id){
|
||||
match = i;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
};
|
||||
|
||||
TableService.prototype.getPlayerJSON = function(tid, uid, type, requestUid){
|
||||
if(!this.tables[tid]){
|
||||
return;
|
||||
}
|
||||
var playerIndex = this.getPlayerIndex(tid, uid, type);
|
||||
var player = this.tables[tid].table[type ? type : 'players'][playerIndex];
|
||||
return player ? {
|
||||
playerName : player.playerName,
|
||||
id : player.id,
|
||||
chips : player.chips,
|
||||
folded : player.folded,
|
||||
allIn : player.allIn,
|
||||
talked : player.talked,
|
||||
amount : player.amount,
|
||||
cards : (typeof requestUid === 'undefined' || player.id == requestUid) ? player.cards : undefined,
|
||||
} : undefined;
|
||||
};
|
||||
|
||||
TableService.prototype.getPlayersJSON = function(tid, type, requestUid){
|
||||
var players = [];
|
||||
if(!this.tables[tid]){
|
||||
return;
|
||||
}
|
||||
for(var i=0;i<this.tables[tid].table[type ? type : 'players'].length;++i){
|
||||
players.push(this.getPlayerJSON(tid, this.tables[tid].table[type ? type : 'players'][i].id, type, requestUid));
|
||||
}
|
||||
return players;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a player to the game
|
||||
*
|
||||
* @param {Object} tid id of an existing table
|
||||
* @param {string} uid userId to add to the table
|
||||
* @param {number} buyIn amount to buy in
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.addPlayer = function(tid, uid, buyIn, cb){
|
||||
var me = this;
|
||||
if(!this.tables[tid]){
|
||||
return cb('table-not-found');
|
||||
}
|
||||
var table = this.tables[tid].table;
|
||||
if(me.getPlayerIndex(tid, uid, 'playersToAdd')){
|
||||
return cb('already-joined');
|
||||
}
|
||||
buyIn = parseInt(buyIn);
|
||||
if(isNaN(buyIn) || buyIn < table.minBuyIn || buyIn > table.maxBuyIn){
|
||||
cb('invalid-buyin');
|
||||
return;
|
||||
}
|
||||
buyIn = Math.round(buyIn);
|
||||
UserStore.getByAttr('id', uid, false, function(e, user){
|
||||
if(e){
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
if(Math.round(user.chips) < table.minBuyIn){
|
||||
cb('below-minimum-buyin');
|
||||
return;
|
||||
}
|
||||
if(Math.round(user.chips) < buyIn){
|
||||
cb('not-enough-chips');
|
||||
return;
|
||||
}
|
||||
var chips = Math.round(user.chips - buyIn);
|
||||
UserStore.set({
|
||||
id : user.id,
|
||||
chips : chips
|
||||
}, function(e, updatedUser){
|
||||
if(e){
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
table.eventEmitter.emit('playerJoined');
|
||||
var mIndex = me.getPlayerIndex(tid, updatedUser.id, 'members');
|
||||
if(typeof mIndex === 'number'){
|
||||
table.members[mIndex].chips = chips;
|
||||
}
|
||||
table.AddPlayer(updatedUser.username, buyIn, uid);
|
||||
me.pushPlayerInfo(tid, user.id, updatedUser);
|
||||
me.app.get('channelService').getChannel(tid, true).pushMessage({
|
||||
route : 'onUpdateUsers',
|
||||
members : table.members
|
||||
});
|
||||
me.app.get('channelService').getChannel(tid, true).pushMessage({
|
||||
route : 'onTableJoin',
|
||||
msg : me.getPlayerJSON(tid, uid, 'playersToAdd') || me.getPlayerJSON(tid, uid)
|
||||
});
|
||||
cb();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Push detailed user information to a user
|
||||
*
|
||||
* @param {Object} tid id of an existing table
|
||||
* @param {string} uid userId to add to the table
|
||||
* @param {object} info player information
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.pushPlayerInfo = function(tid, uid, info){
|
||||
var channelService = this.app.get('channelService');
|
||||
var channel = channelService.getChannel(tid, false);
|
||||
if(!channel || !channel.getMember(uid)) return;
|
||||
channelService.pushMessageByUids({
|
||||
route : 'onUpdateMyself',
|
||||
user : info
|
||||
}, [{
|
||||
uid : uid,
|
||||
sid : channel.getMember(uid)['sid']
|
||||
}], function(e){
|
||||
if(e){
|
||||
logger.error('unable to push player info ', e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start the game
|
||||
*
|
||||
* @param {Object} tid id of an existing table
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.startGame = function(tid, cb){
|
||||
var table = this.tables[tid];
|
||||
if(!table){
|
||||
return cb('table-not-found');
|
||||
}
|
||||
if(table.state != 'JOIN'){
|
||||
return cb('table-not-ready');
|
||||
}
|
||||
if(table.table.active){
|
||||
return cb('table-still-active');
|
||||
}
|
||||
if(table.table.playersToAdd.length < table.table.minPlayers){
|
||||
return cb('not-enough-players');
|
||||
}
|
||||
if(table.table.playersToAdd.length > table.table.maxPlayers){
|
||||
return cb('too-many-players');
|
||||
}
|
||||
// remove chips from user for buy in
|
||||
table.table.StartGame();
|
||||
this.app.get('channelService').getChannel(tid, true).pushMessage({
|
||||
route : 'onUpdateUsers',
|
||||
members : table.table.members
|
||||
});
|
||||
this.broadcastGameState(tid);
|
||||
cb();
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform a game action
|
||||
*
|
||||
* @param {string} tid table id
|
||||
* @param {string} uid userId to add to the table
|
||||
* @param {object} action an object containing the action type and optionally the amount of chips
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.performAction = function(tid, uid, action, cb){
|
||||
var me = this;
|
||||
var table = this.tables[tid];
|
||||
if(!table){
|
||||
return cb('table-not-found');
|
||||
}
|
||||
if(table.state != 'IN_PROGRESS'){
|
||||
return cb('game-not-ready');
|
||||
}
|
||||
if(me.getPlayerIndex(tid, uid) != table.table.currentPlayer){
|
||||
return cb('not-your-turn');
|
||||
}
|
||||
if(me.getPlayerJSON(tid, uid).folded == true){
|
||||
return cb('already-folded');
|
||||
}
|
||||
if(action.action == 'bet' && isNaN(action.amt)){
|
||||
return cb('invalid-bet-amt');
|
||||
}
|
||||
// perform action
|
||||
if(action.action == 'call'){
|
||||
table.table.players[table.table.currentPlayer].Call();
|
||||
}else if(action.action == 'bet'){
|
||||
table.table.players[table.table.currentPlayer].Bet(parseInt(action.amt));
|
||||
}else if(action.action == 'check'){
|
||||
table.table.players[table.table.currentPlayer].Check();
|
||||
}else if(action.action == 'allin'){
|
||||
table.table.players[table.table.currentPlayer].AllIn();
|
||||
}else if(action.action == 'fold'){
|
||||
table.table.players[table.table.currentPlayer].Fold();
|
||||
}else{
|
||||
return cb('invalid-action');
|
||||
}
|
||||
table.table.stopTimer();
|
||||
logger.debug('player '+uid+' executed action '+action.action+' on table '+tid+' with state '+table.state);
|
||||
me.handleGameState(tid, function(e){
|
||||
if(e){
|
||||
return cb(e);
|
||||
}
|
||||
cb();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* End game and broadcast result to clients
|
||||
*
|
||||
* @param {string} tid table id
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.endGame = function(tid, cb){
|
||||
var me = this;
|
||||
if(!me.tables[tid]){
|
||||
cb('table-not-found');
|
||||
return;
|
||||
}
|
||||
var table = me.tables[tid];
|
||||
if(table.table.game.roundName != 'GameEnd'){
|
||||
cb('not-game-end');
|
||||
return;
|
||||
}
|
||||
table.table.active = false;
|
||||
table.table.stopTimer();
|
||||
me.saveResults(tid, function(e){
|
||||
if(e){
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
var channelService = me.app.get('channelService');
|
||||
channelService.getChannel(tid, false).pushMessage({
|
||||
route : 'onUpdateUsers',
|
||||
members : table.table.members
|
||||
});
|
||||
table.table.initNewGame();
|
||||
me.broadcastGameState(tid);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Store table results to persistence
|
||||
*
|
||||
* @param {string} tid id of the table
|
||||
* @param {string} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.saveResults = function(tid, cb){
|
||||
var me = this;
|
||||
if(!this.tables[tid]){
|
||||
cb('table-not-found');
|
||||
}
|
||||
var table = this.tables[tid];
|
||||
TableStore.getByAttr('id', table.table.game.id, function(e, foundTable){
|
||||
if(foundTable){
|
||||
cb('game-already-exists');
|
||||
return;
|
||||
}
|
||||
TableStore.create(me.getTableJSON(tid), function(e, newTable){
|
||||
if(e){
|
||||
cb(e);
|
||||
return;
|
||||
}
|
||||
var i = 0;
|
||||
function saveWinner(){
|
||||
me.updatePlayerInfo(table.table.gameWinners[i].id, {
|
||||
wins : 1,
|
||||
wonAmount : table.table.gameWinners[i].amount
|
||||
}, function(){
|
||||
if(++i === table.table.gameWinners.length){
|
||||
cb();
|
||||
}else{
|
||||
saveWinner();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(table.table.gameWinners.length){
|
||||
saveWinner();
|
||||
}else{
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle end of game or broadcast game state to users
|
||||
*
|
||||
* @param {string} tid id of the table
|
||||
* @param {function} cb callback
|
||||
*
|
||||
*/
|
||||
TableService.prototype.handleGameState = function(tid, cb){
|
||||
var me = this;
|
||||
var table = me.tables[tid];
|
||||
if(table.table && table.table.game && table.table.game.roundName == 'GameEnd' && table.state == 'IN_PROGRESS' && table.table.active){
|
||||
me.endGame(tid, cb);
|
||||
}else{
|
||||
me.app.get('channelService').getChannel(tid, true).pushMessage({
|
||||
route : 'onUpdateUsers',
|
||||
members : table.table.members
|
||||
});
|
||||
me.broadcastGameState(tid);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Broadcast game state by iteratively pushing game details to clients
|
||||
*
|
||||
* @param {string} tid id
|
||||
*
|
||||
*/
|
||||
TableService.prototype.broadcastGameState = function(tid){
|
||||
var i = 0;
|
||||
var me = this;
|
||||
var channelService = me.app.get('channelService');
|
||||
var channel = channelService.getChannel(tid, false);
|
||||
function broadcast(){
|
||||
if(i == me.tables[tid].table.members.length){
|
||||
if(me.tables[tid].state == 'IN_PROGRESS' && me.tables[tid].table.active){
|
||||
me.tables[tid].table.startTimer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var uid = me.tables[tid].table.members[i].id;
|
||||
if(channel.getMember(uid)){
|
||||
channelService.pushMessageByUids({
|
||||
route : 'onTableEvent',
|
||||
msg : me.getTableJSON(tid, uid)
|
||||
}, [{
|
||||
uid : uid,
|
||||
sid : channel.getMember(uid)['sid']
|
||||
}], function(){
|
||||
++i;
|
||||
broadcast();
|
||||
});
|
||||
}else{
|
||||
++i;
|
||||
broadcast();
|
||||
}
|
||||
}
|
||||
broadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffles an array
|
||||
*
|
||||
* @param {array} ary an array
|
||||
*
|
||||
*/
|
||||
TableService.prototype.shuffle = function(ary){
|
||||
var currentIndex = ary.length, temporaryValue, randomIndex;
|
||||
while(0 !== currentIndex){
|
||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex -= 1;
|
||||
temporaryValue = ary[currentIndex];
|
||||
ary[currentIndex] = ary[randomIndex];
|
||||
ary[randomIndex] = temporaryValue;
|
||||
}
|
||||
return ary;
|
||||
};
|
||||
|
6
game-server/app/util/dispatcher.js
Normal file
6
game-server/app/util/dispatcher.js
Normal file
@@ -0,0 +1,6 @@
|
||||
var crc = require('crc');
|
||||
|
||||
module.exports.dispatch = function(uid, connectors){
|
||||
var index = Math.abs(crc.crc32(uid)) % connectors.length;
|
||||
return connectors[index];
|
||||
};
|
12
game-server/app/util/routeUtil.js
Normal file
12
game-server/app/util/routeUtil.js
Normal file
@@ -0,0 +1,12 @@
|
||||
var exp = module.exports;
|
||||
var dispatcher = require('./dispatcher');
|
||||
|
||||
exp.game = function(session, msg, app, cb){
|
||||
var gameServers = app.getServersByType('game');
|
||||
if(!gameServers || gameServers.length === 0){
|
||||
cb(new Error('can not find game servers.'));
|
||||
return;
|
||||
}
|
||||
var res = dispatcher.dispatch(1, gameServers);
|
||||
cb(null, res.id);
|
||||
};
|
Reference in New Issue
Block a user