552 lines
15 KiB
C
552 lines
15 KiB
C
/* WarServ - War Card Game Service - NeoStats Addon Module
|
|
** Copyright (c) 2004-2008 Justin Hammond, Mark Hetherington, Jeff Lang
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
** USA
|
|
**
|
|
** WarServ CVS Identification
|
|
** $Id$
|
|
*/
|
|
|
|
#include "neostats.h" /* Required for bot support */
|
|
#include "warserv.h"
|
|
|
|
char warroom[MAXCHANLEN];
|
|
int currentwargamestatus;
|
|
int currentwarplayercount;
|
|
char wplayernick[10][MAXNICK];
|
|
int wplayercardstotal[10];
|
|
int warinprogress;
|
|
int currentplayer;
|
|
int wpln;
|
|
|
|
static int wplayercardsinhand[10][52];
|
|
static int wplayercardplayed[10];
|
|
static int wplayeratwar[10];
|
|
static int wplayerwarcardsplayed[10][3];
|
|
static int wstackcards[52];
|
|
static int wstackcardscurrent;
|
|
static char csuit[10];
|
|
static char csuitcolour[10];
|
|
static char csuitcard[10];
|
|
|
|
static void checkhandwinner(void);
|
|
static void checkwarwinner(void);
|
|
static void clearstack(void);
|
|
static void playershufflecards(void);
|
|
static void wardealcards(void);
|
|
static void askplaycard(void);
|
|
int startwar(void *userptr);
|
|
|
|
/*
|
|
* Stop Game
|
|
* resets everything to default as if no game running
|
|
*/
|
|
|
|
void stopwar(void)
|
|
{
|
|
int i;
|
|
if (currentwargamestatus == WS_GAME_STARTING) {
|
|
DelTimer ("startwar");
|
|
}
|
|
for (wpln = 0; wpln < 10; wpln++) {
|
|
strlcpy (wplayernick[wpln], " ", MAXNICK);
|
|
wplayercardstotal[wpln]= 0;
|
|
wplayercardplayed[wpln]= 0;
|
|
wplayeratwar[wpln]= 0;
|
|
for (i = 0; i < 52; i++) {
|
|
wplayercardsinhand[wpln][i]= 0;
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
wplayerwarcardsplayed[wpln][i]= 0;
|
|
}
|
|
}
|
|
for (wpln = 0; wpln < 52; wpln++) {
|
|
wstackcards[wpln]= 0;
|
|
}
|
|
warinprogress= 0;
|
|
wstackcardscurrent= 0;
|
|
currentwarplayercount = 0;
|
|
currentwargamestatus = WS_GAME_STOPPED;
|
|
currentplayer= 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Start Game Countdown
|
|
* Starts a timer to allow 30 seconds for people to join the game
|
|
*/
|
|
|
|
void startcountdowntimer(char *nic) {
|
|
currentwargamestatus = WS_GAME_STARTING;
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037A new game of \0034WAR\0037 has been started by %s. Game will start in 30 seconds, type '\2\003!Join\2\0037' to play.", nic);
|
|
AddTimer (TIMER_TYPE_COUNTDOWN, startwar, "startwar", 30, NULL);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Start Game
|
|
* Initializes variables and starts game
|
|
*/
|
|
|
|
int startwar(void *userptr)
|
|
{
|
|
/* DelTimer ("startwar"); */
|
|
if (currentwargamestatus == WS_GAME_STARTING) {
|
|
if (currentwarplayercount < 1) {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0034No Players joined to current Game, Exiting");
|
|
currentwargamestatus = WS_GAME_STOPPING;
|
|
stopwar();
|
|
return NS_SUCCESS;
|
|
}
|
|
if (currentwarplayercount < 10) {
|
|
joinwar(ws_bot->name);
|
|
}
|
|
irc_chanprivmsg (ws_bot, warroom, "\0034WAR\00310 is now starting, current players are \0037%s %s %s %s %s %s %s %s %s %s", wplayernick[0], wplayernick[1], wplayernick[2], wplayernick[3], wplayernick[4], wplayernick[5], wplayernick[6], wplayernick[7], wplayernick[8], wplayernick[9]);
|
|
irc_chanprivmsg (ws_bot, warroom, "\0039Shuffling Deck and Dealing Cards");
|
|
currentplayer= 0;
|
|
currentwargamestatus = WS_GAME_PLAYING;
|
|
wardealcards();
|
|
wstackcardscurrent= 0;
|
|
askplaycard();
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Join Game
|
|
* adds new player to game during countdown
|
|
*/
|
|
|
|
void joinwar(char *nic) {
|
|
if (currentwarplayercount < 10) {
|
|
for (wpln = 0; wpln < 10; wpln++) {
|
|
if (!ircstrcasecmp (wplayernick[wpln], nic)) {
|
|
return;
|
|
}
|
|
}
|
|
strlcpy (wplayernick[currentwarplayercount], nic, MAXNICK);
|
|
currentwarplayercount++;
|
|
irc_chanprivmsg (ws_bot, warroom, "\0038Welcome to \0034WAR \0037%s", nic);
|
|
} else {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0034Sorry all places are filled \0037%s\0034, your welcome to try the next game though", nic);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Remove Player
|
|
* removes player from game and adds any cards they have to the stack
|
|
*/
|
|
|
|
void removewar(char *nic)
|
|
{
|
|
int i;
|
|
int tfrpacp;
|
|
int tfrpacpn;
|
|
int wplnht;
|
|
int cpfp;
|
|
tfrpacp= 0;
|
|
tfrpacpn= 0;
|
|
if (currentwarplayercount < 1) {
|
|
return;
|
|
}
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
if (!ircstrcasecmp (wplayernick[wpln], nic)) {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s \0038Removed from the current game of \0034War", nic);
|
|
if (wpln == currentplayer) {
|
|
tfrpacp= 1;
|
|
} else if (wpln < currentplayer) {
|
|
tfrpacp= 2;
|
|
tfrpacpn= wpln;
|
|
}
|
|
for (wplnht = 0; wplnht < wplayercardstotal[wpln]; wplnht++) {
|
|
wstackcards[wstackcardscurrent]= wplayercardsinhand[wpln][wplnht];
|
|
wstackcardscurrent++;
|
|
}
|
|
for (i = wpln; i < currentwarplayercount; i++) {
|
|
cpfp= (i + 1);
|
|
if (cpfp == currentwarplayercount) {
|
|
strlcpy (wplayernick[i], " ", MAXNICK);
|
|
for (wplnht = 0; wplnht < wplayercardstotal[i]; wplnht++) {
|
|
wplayercardsinhand[i][wplnht]= 0;
|
|
}
|
|
wplayercardstotal[i]= 0;
|
|
} else {
|
|
strlcpy (wplayernick[i], wplayernick[cpfp], MAXNICK);
|
|
for (wplnht = 0; wplnht < 52; wplnht++) {
|
|
wplayercardsinhand[i][wplnht]= wplayercardsinhand[cpfp][wplnht];
|
|
}
|
|
wplayercardstotal[i]= wplayercardstotal[cpfp];
|
|
}
|
|
}
|
|
currentwarplayercount--;
|
|
}
|
|
}
|
|
if (currentwarplayercount < 2) {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0039Stopping Current Game , \0037%s\0039 wins.", wplayernick[0]);
|
|
stopwar();
|
|
} else if (tfrpacp == 1) {
|
|
if (currentplayer > (currentwarplayercount - 1)) {
|
|
currentplayer= 0;
|
|
}
|
|
if (currentwargamestatus == WS_GAME_STARTING) {
|
|
askplaycard();
|
|
}
|
|
} else if (tfrpacp == 2) {
|
|
if (currentplayer > tfrpacpn) {
|
|
currentplayer--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deal Cards
|
|
*/
|
|
static void wardealcards(void) {
|
|
int cd;
|
|
int cnd;
|
|
int cndn;
|
|
int ptdt = 0;
|
|
for (wpln = 0; wpln < 52; wpln++) {
|
|
wstackcards[wpln]= wpln;
|
|
}
|
|
for (cd = 52; cd > 0; cd--) {
|
|
cnd= rand() % cd;
|
|
cndn= wstackcards[cnd];
|
|
for (wpln = cnd; wpln < (cd - 1); wpln++) {
|
|
wstackcards[wpln]= wstackcards[(wpln + 1)];
|
|
}
|
|
wstackcards[(cd - 1)]= 0;
|
|
wplayercardsinhand[ptdt][wplayercardstotal[ptdt]]= cndn;
|
|
wplayercardstotal[ptdt]++;
|
|
ptdt++;
|
|
if (ptdt == currentwarplayercount) {
|
|
ptdt= 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Shuffle Players Cards
|
|
*/
|
|
|
|
void playershufflecards(void)
|
|
{
|
|
int tcs;
|
|
int tcsp;
|
|
int tcsps;
|
|
int i;
|
|
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
for (i = 0; i < wplayercardstotal[wpln]; i++) {
|
|
tcsps= 0;
|
|
tcsp= rand() % wplayercardstotal[wpln];
|
|
if (tcsp == i) {
|
|
tcsps= 1;
|
|
}
|
|
if (tcsps == 0) {
|
|
tcs= wplayercardsinhand[wpln][tcsp];
|
|
wplayercardsinhand[wpln][tcsp] = wplayercardsinhand[wpln][i];
|
|
wplayercardsinhand[wpln][i] = tcs;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* asks each player for card to play
|
|
* or check war results if in war
|
|
* or removes player if no cards left
|
|
*/
|
|
static void askplaycard(void)
|
|
{
|
|
int trn;
|
|
int wspa[5];
|
|
int nwp = (currentwarplayercount + 1);
|
|
if (wplayercardstotal[currentplayer] == 0) {
|
|
removewar(wplayernick[currentplayer]);
|
|
}
|
|
if (wplayercardstotal[currentplayer] == 52) {
|
|
currentplayer++;
|
|
removewar(wplayernick[currentplayer]);
|
|
}
|
|
if (currentwarplayercount < 2) {
|
|
return;
|
|
}
|
|
if (warinprogress == 1) {
|
|
if (currentplayer < currentwarplayercount) {
|
|
for (wpln = currentplayer; wpln < currentwarplayercount; wpln++) {
|
|
if (wplayeratwar[wpln] == 1) {
|
|
nwp= wpln;
|
|
wpln= currentwarplayercount;
|
|
}
|
|
}
|
|
currentplayer = nwp;
|
|
}
|
|
if (nwp > currentwarplayercount) {
|
|
checkwarwinner();
|
|
} else {
|
|
if (!ircstrcasecmp (wplayernick[currentplayer], ws_bot->name)) {
|
|
trn= wplayercardstotal[currentplayer];
|
|
wspa[2]= ((rand() % trn) + 1);
|
|
trn--;
|
|
wspa[3]= ((rand() % trn) + 1);
|
|
if (wspa[3] == wspa[2]) {
|
|
wspa[3]++;
|
|
}
|
|
trn--;
|
|
wspa[4]= ((rand() % trn) + 1);
|
|
if ((wspa[4] == wspa[2]) || (wspa[4] == wspa[3])) {
|
|
wspa[4]++;
|
|
}
|
|
if ((wspa[4] == wspa[2]) || (wspa[4] == wspa[3])) {
|
|
wspa[4]++;
|
|
}
|
|
playwarcards(wspa[2], wspa[3], wspa[4]);
|
|
} else {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 you hold\00311 %d\0039 cards, and are currently at \0034WAR\0039 which three would you like to play ?", wplayernick[currentplayer], wplayercardstotal[currentplayer]);
|
|
}
|
|
}
|
|
} else {
|
|
if (!ircstrcasecmp (wplayernick[currentplayer], ws_bot->name)) {
|
|
playcard(((rand() % wplayercardstotal[currentplayer]) + 1));
|
|
} else {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 you currently hold\00311 %d\0039 cards, which would you like to play ?", wplayernick[currentplayer], wplayercardstotal[currentplayer]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Player War Play Card
|
|
*/
|
|
void playwarcards(int cnp1, int cnp2, int cnp3)
|
|
{
|
|
int i;
|
|
int cnp[3];
|
|
cnp[0] = cnp1;
|
|
cnp[1] = cnp2;
|
|
cnp[2] = cnp3;
|
|
for (wpln = 0; wpln < 3; wpln++) {
|
|
if ((cnp[wpln] < 1) || (cnp[wpln] > wplayercardstotal[currentplayer])) {
|
|
return;
|
|
}
|
|
}
|
|
if (wplayercardsinhand[currentplayer][(cnp[2] - 1)] < 13) {
|
|
strlcpy (csuitcolour, "\0034", 10);
|
|
strlcpy (csuit, "Hearts", 10);
|
|
} else if (wplayercardsinhand[currentplayer][(cnp[2] - 1)] < 26) {
|
|
strlcpy (csuitcolour, "\0037", 10);
|
|
strlcpy (csuit, "Diamonds", 10);
|
|
} else if (wplayercardsinhand[currentplayer][(cnp[2] - 1)] < 39) {
|
|
strlcpy (csuitcolour, "\00314", 10);
|
|
strlcpy (csuit, "Clubs", 10);
|
|
} else {
|
|
strlcpy (csuitcolour, "\00315", 10);
|
|
strlcpy (csuit, "Spades", 10);
|
|
}
|
|
switch ((wplayercardsinhand[currentplayer][(cnp[2] - 1)] % 13)) {
|
|
case 12:
|
|
strlcpy (csuitcard, "Ace", 10);
|
|
break;
|
|
case 11:
|
|
strlcpy (csuitcard, "King", 10);
|
|
break;
|
|
case 10:
|
|
strlcpy (csuitcard, "Queen", 10);
|
|
break;
|
|
case 9:
|
|
strlcpy (csuitcard, "Jack", 10);
|
|
break;
|
|
default:
|
|
ircsnprintf(csuitcard, 10, "%d", ((wplayercardsinhand[currentplayer][(cnp[2] - 1)] % 13) + 2));
|
|
break;
|
|
}
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 played Cards\00311 %d , %d , %d \0039(%s %s of %s \0039)", wplayernick[currentplayer], cnp[0], cnp[1], cnp[2], csuitcolour, csuitcard, csuit);
|
|
for (wpln = 0; wpln < 3; wpln++) {
|
|
cnp[wpln]--;
|
|
wstackcards[wstackcardscurrent]= wplayercardsinhand[currentplayer][cnp[wpln]];
|
|
wstackcardscurrent++;
|
|
wplayerwarcardsplayed[currentplayer][wpln]= wplayercardsinhand[currentplayer][cnp[wpln]];
|
|
}
|
|
if (cnp[2] > cnp[0])
|
|
cnp[2]--;
|
|
if (cnp[2] > cnp[1])
|
|
cnp[2]--;
|
|
if (cnp[1] > cnp[0])
|
|
cnp[1]--;
|
|
for (wpln = 0; wpln < 3; wpln++) {
|
|
wplayercardstotal[currentplayer]--;
|
|
for (i = cnp[wpln]; i < wplayercardstotal[currentplayer]; i++) {
|
|
wplayercardsinhand[currentplayer][i]= wplayercardsinhand[currentplayer][(i +1)];
|
|
}
|
|
wplayercardsinhand[currentplayer][wplayercardstotal[currentplayer]]= 0;
|
|
}
|
|
currentplayer++;
|
|
if (currentplayer < currentwarplayercount) {
|
|
askplaycard();
|
|
} else {
|
|
checkwarwinner();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Player Plays Card
|
|
*/
|
|
void playcard(int cnp)
|
|
{
|
|
if ((cnp > 0) && (cnp < (wplayercardstotal[currentplayer] + 1))){
|
|
if (wplayercardsinhand[currentplayer][(cnp - 1)] < 13) {
|
|
strlcpy (csuitcolour, "\0034", 10);
|
|
strlcpy (csuit, "Hearts", 10);
|
|
} else if (wplayercardsinhand[currentplayer][(cnp - 1)] < 26) {
|
|
strlcpy (csuitcolour, "\0037", 10);
|
|
strlcpy (csuit, "Diamonds", 10);
|
|
} else if (wplayercardsinhand[currentplayer][(cnp - 1)] < 39) {
|
|
strlcpy (csuitcolour, "\00314", 10);
|
|
strlcpy (csuit, "Clubs", 10);
|
|
} else {
|
|
strlcpy (csuitcolour, "\00315", 10);
|
|
strlcpy (csuit, "Spades", 10);
|
|
}
|
|
switch ((wplayercardsinhand[currentplayer][(cnp - 1)] % 13)) {
|
|
case 12:
|
|
strlcpy (csuitcard, "Ace", 10);
|
|
break;
|
|
case 11:
|
|
strlcpy (csuitcard, "King", 10);
|
|
break;
|
|
case 10:
|
|
strlcpy (csuitcard, "Queen", 10);
|
|
break;
|
|
case 9:
|
|
strlcpy (csuitcard, "Jack", 10);
|
|
break;
|
|
default:
|
|
ircsnprintf(csuitcard, 10, "%d", ((wplayercardsinhand[currentplayer][(cnp - 1)] % 13) + 2));
|
|
break;
|
|
}
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 played Card\00311 %d \0039(%s %s of %s \0039)", wplayernick[currentplayer], cnp, csuitcolour, csuitcard, csuit);
|
|
cnp--;
|
|
wstackcards[wstackcardscurrent]= wplayercardsinhand[currentplayer][cnp];
|
|
wstackcardscurrent++;
|
|
wplayercardplayed[currentplayer]= wplayercardsinhand[currentplayer][cnp];
|
|
wplayercardstotal[currentplayer]--;
|
|
for (wpln = cnp; wpln < wplayercardstotal[currentplayer]; wpln++) {
|
|
wplayercardsinhand[currentplayer][wpln]= wplayercardsinhand[currentplayer][(wpln +1)];
|
|
}
|
|
wplayercardsinhand[currentplayer][wplayercardstotal[currentplayer]]= 0;
|
|
currentplayer++;
|
|
if (currentplayer < currentwarplayercount) {
|
|
askplaycard();
|
|
} else {
|
|
checkhandwinner();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Checks standard hand for a winner (not a war hand)
|
|
*/
|
|
static void checkhandwinner(void)
|
|
{
|
|
int i;
|
|
int hcnp = 0;
|
|
int hcnpt = 0;
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
if (warinprogress == wplayeratwar[wpln]) {
|
|
if ((wplayercardplayed[wpln] % 13) > hcnp) {
|
|
hcnp = (wplayercardplayed[wpln] % 13);
|
|
hcnpt = 1;
|
|
} else if ((wplayercardplayed[wpln] % 13) == hcnp) {
|
|
hcnpt++;
|
|
}
|
|
}
|
|
}
|
|
if (hcnpt == 1) {
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
if (warinprogress == wplayeratwar[wpln]) {
|
|
if ((wplayercardplayed[wpln] % 13) == hcnp) {
|
|
if (warinprogress == 1) {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 wins the \0034WAR\0039.", wplayernick[wpln]);
|
|
} else {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0039 takes the hand.", wplayernick[wpln]);
|
|
}
|
|
for (i = 0; i < wstackcardscurrent; i++) {
|
|
wplayercardsinhand[wpln][wplayercardstotal[wpln]]= wstackcards[i];
|
|
wplayercardstotal[wpln]++;
|
|
}
|
|
clearstack();
|
|
wpln= currentwarplayercount;
|
|
}
|
|
}
|
|
}
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
wplayeratwar[wpln]= 0;
|
|
}
|
|
warinprogress= 0;
|
|
} else {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0034WAR DECLARED");
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
if (warinprogress == wplayeratwar[wpln]) {
|
|
wplayeratwar[wpln] = 0;
|
|
if ((wplayercardplayed[wpln] % 13) == hcnp) {
|
|
wplayeratwar[wpln]= 1;
|
|
if (wplayercardstotal[wpln] < 3) {
|
|
irc_chanprivmsg (ws_bot, warroom, "\0037%s\0038 Surrenders\0039 (Insufficient Cards)", wplayernick[wpln]);
|
|
hcnpt--;
|
|
removewar(wplayernick[wpln]);
|
|
if (currentwarplayercount < 2) {
|
|
wpln= currentwarplayercount;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
warinprogress= 1;
|
|
}
|
|
currentplayer= 0;
|
|
playershufflecards();
|
|
askplaycard();
|
|
}
|
|
|
|
/*
|
|
* copy war hand to normal for checking
|
|
*/
|
|
static void checkwarwinner(void)
|
|
{
|
|
int i;
|
|
for (wpln = 0; wpln < currentwarplayercount; wpln++) {
|
|
if (wplayeratwar[wpln] == 1) {
|
|
wplayercardplayed[wpln]= wplayerwarcardsplayed[wpln][2];
|
|
} else {
|
|
wplayercardplayed[wpln]= 0;
|
|
}
|
|
for (i = 0; i < 3; i++) {
|
|
wplayerwarcardsplayed[wpln][i]= 0;
|
|
}
|
|
}
|
|
checkhandwinner();
|
|
}
|
|
|
|
/*
|
|
* clears the stack
|
|
*/
|
|
static void clearstack(void) {
|
|
for (wpln = 0; wpln < 52; wpln++) {
|
|
wstackcards[wpln]= 0;
|
|
}
|
|
wstackcardscurrent= 0;
|
|
}
|