Skip to content
Snippets Groups Projects
dpoker.c 89.5 KiB
Newer Older
/* $Id: dpoker.c,v 1.17 2019/08/13 20:09:01 rswindell Exp $ */
rswindell's avatar
rswindell committed

/******************************************************************************
  DPOKER.EXE: Domain Poker online multi-player poker BBS door game for
  Synchronet (and other) BBS software.
rswindell's avatar
rswindell committed
  Copyright (C) 1992-2007 Allen Christiansen DBA Domain Entertainment.

  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.

  E-Mail      : door.games@domainentertainment.com
  Snail Mail  : Domain Entertainment
                PO BOX 54452
                Irvine, CA 92619-4452
******************************************************************************/

#include "xsdk.h"
rswindell's avatar
rswindell committed
#define VERSION "2K7"
char	revision[16];
char	compiler[32];

#define J 11    /* jack */
#define Q 12    /* queen */
#define K 13    /* king */
#define A 14    /* ace */

#define H 0     /* heart */
#define D 1     /* diamond */
#define C 2     /* club */
#define S 3     /* spade */

#define MAX_PLAYERS 6
#define MAX_TABLES 25

#define COMPUTER    (1<<0)
#define PASSWORD    (1<<1)

typedef struct { char value, suit; } card_t;

card_t newdeck[52]={
	{ 2,H }, { 2,D }, { 2,C }, { 2,S },
	{ 3,H }, { 3,D }, { 3,C }, { 3,S },
	{ 4,H }, { 4,D }, { 4,C }, { 4,S },
	{ 5,H }, { 5,D }, { 5,C }, { 5,S },
	{ 6,H }, { 6,D }, { 6,C }, { 6,S },
	{ 7,H }, { 7,D }, { 7,C }, { 7,S },
	{ 8,H }, { 8,D }, { 8,C }, { 8,S },
	{ 9,H }, { 9,D }, { 9,C }, { 9,S },
	{10,H }, {10,D }, {10,C }, {10,S },
	{ J,H }, { J,D }, { J,C }, { J,S },
	{ Q,H }, { Q,D }, { Q,C }, { Q,S },
	{ K,H }, { K,D }, { K,C }, { K,S },
	{ A,H }, { A,D }, { A,C }, { A,S }
};

card_t deck[52], card[52];
card_t hand[MAX_NODES+1][10];
deuce's avatar
deuce committed
char comp_name[41],password[10]={0};
int cur_card=0,rank=0,last_bet=100,create_log=0,symbols=1,table=1,comp_stat=0,
    player_dis=0,xraised=0;
    /* player_dis tells the computer how many the player threw out */
short cur_table=0,dupcard1=0,dupcard2=0,hicard=0,total_players,cur_node,
      firstbid=0,stage;
deuce's avatar
deuce committed
short num_tables=0,skim=0,bet_limit[MAX_TABLES+1]={0},
    ante[MAX_TABLES+1]={0},options[MAX_TABLES+1]={0};
uchar node[MAX_NODES+1]={0};
ulong player_bet=0,newpts,temppts,current_bet,total_pot,comp_bet=0,
deuce's avatar
deuce committed
    time_played=0,time_allowed=0,max_bet=0,max_total[MAX_TABLES+1]={0};
uint firstbet=1;
unsigned short temp_num,dealer;

long xfer_pts2=0;

/*******************
 Function Prototypes
********************/
int main(int argc, char **argv);
void get_player(int player);
void get_game_status(int tablenum);
void put_game_status(int specnode);
void send_all_message(char *msg,int exception);
void send_player_message(int plr, char *msg);
void quit_out(void);

#ifndef DPCLEAN

void put_player(int player);
int straight_flush(void);
void center_wargs(char *str, ...);
void moduser(void);
void deal(void);
void discard(void);
void computer_discard(void);
void join_game(void);
int select_table(void);
void increase_bet(void);
void computer_bet(void);
void bet_menu(void);
void play_menu(void);
void putdeck(void);
void getdeck(void);
void shuffle(void);
void show_all_hands(int winner);
void player_status(void);
char *handstr(int player);
char *cardstr(card_t card);
char *ranking(int num);
char *activity(int num);
char *activity2(int num);
void single_winner(void);
void dealer_ctrl(void);
int hand_total(int player);
void gethandtype(int player);
void read_player_message(void);
void strip_symbols(char *str);
void readline(char *outstr, int maxlen, FILE *stream);
void show_tables(void);
void show_players(int tablenum);
void next_player(void);
void send_message(void);
void computer_log(long points);
void declare_winner(void);

/* These are the hand types */
enum { NOTHING, ONE_PAIR, TWO_PAIR, THREE_OF_A_KIND, STRAIGHT, FLUSH,
       FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH, ROYAL_FLUSH };

/* These are for the player status */
enum { INACTIVE, WAITING, BETTING, DISCARDING, FOLDED, DEALING };

/* These or for determining what stage the game is in */
enum { OPEN, DEAL, BET, DISCARD, BET2, GET_WINNER };

#ifdef _WIN32	/* necessary for compatibility with SBBS v2 */
#pragma pack(push)
#pragma pack(1)
#endif

#ifdef __GNUC__
	#define _PACK __attribute__ ((packed))
#else
	#define _PACK
#endif

int main(int argc, char **argv)
rswindell's avatar
rswindell committed
    char	ch,str[256],*buf;
	char*	p;
    int		file,i,x;
    long	won,lost;
    ulong	length,l,lastrun;
	FILE	*inifile;
	int		opts;
	char	key_name[8];
rswindell's avatar
rswindell committed
	BOOL	cleanup=FALSE;
        char name[25];
        ulong time;
        long points;
    } player_stuff;

	sscanf("$Revision: 1.17 $", "%*s %s", revision);
rswindell's avatar
rswindell committed
	DESCRIBE_COMPILER(compiler);

    memset(node,'\0',MAX_NODES);

	/* ToDo... this should seed better */
    srand(time(NULL));
	env_node=getenv("SBBSNODE");
	if(env_node==NULL) {
		printf("\nDomain Poker v%s-%s/XSDK v%s  Copyright %s Domain "
				"Entertainment\n",VERSION,revision,xsdk_ver,__DATE__+7);
		printf("\nERROR: SBBSNODE Environment variable not set!\n");
		return(1);
	}
    sprintf(node_dir,"%s",env_node);

    for (x=1; x<argc; x++) {
rswindell's avatar
rswindell committed
		p=argv[x];
		while(*p=='/' || *p=='-')
			p++;
        if(stricmp(p,"L")==0)
            create_log=TRUE;
		else if(stricmp(p,"clean")==0)
			cleanup=TRUE;
		else {
rswindell's avatar
rswindell committed
			printf("\nDomain Poker v%s-%s/XSDK v%s  Copyright %s Domain "
					"Entertainment\n",VERSION,revision,xsdk_ver,__DATE__+7);
			printf("Compiler: %s\n", compiler);
rswindell's avatar
rswindell committed
			printf("\nUsage: dpoker [-L] [-CLEAN]\n");
			printf("\nOptions:\n");
			printf("\tL = Create daily log of computer vs player "
				  "wins/losses\n");
			printf("\tCLEAN = Clean-up player/node data (replaces 'dpclean')\n");
			return(0);
rswindell's avatar
rswindell committed
		}
rswindell's avatar
rswindell committed

	if(cleanup) {
		sprintf(str,"player.%d",node_num);
		if (fexist(str)) {
			get_player(node_num);
			newpts=temppts;
			quit_out();
		}
		return(0);
	}
    if(!(fexist("dpoker.mnt"))) {
        if((file=nopen("dpoker.mnt",O_WRONLY|O_CREAT))!=-1) {
            bprintf("\r\nPLEASE WAIT: Running daily maintenance.\r\n");
            lastrun=time(NULL);
			lastrun-=lastrun%86400;
            write(file,&lastrun,sizeof(lastrun)); close(file);
            delfiles(".","player.*", /* keep: */0);
            delfiles(".","gamestat.*", /* keep: */0);
            delfiles(".","deck.*", /* keep: */0);
            delfiles(".","message.*", /* keep: */0);
            unlink("dpoker.plr");
			close(file);
		}
	}
/* ToDo...
    if((file=nopen("dpoker.mnt",O_RDWR|O_DENYALL))==-1) { */
    if((file=nopen("dpoker.mnt",O_RDWR))==-1) {
        bprintf("\r\nPLEASE WAIT: Daily maintenance is running.\r\n");
        mswait(10000);
    } else {
        read(file,&lastrun,sizeof(lastrun));
        if(time(NULL)-lastrun>=86400) {
            bprintf("\r\nPLEASE WAIT: Running daily maintenance.\r\n");
            lastrun=time(NULL); lseek(file,0L,SEEK_SET);
			lastrun-=lastrun%86400;
            write(file,&lastrun,sizeof(lastrun));
            delfiles(".","player.*", /* keep: */0);
            delfiles(".","gamestat.*", /* keep: */0);
            delfiles(".","deck.*", /* keep: */0);
            delfiles(".","message.*", /* keep: */0);
            unlink("dpoker.plr");
		}
        close(file);
	}
	inifile=fopen("dpoker.ini","r");
	iniReadString(inifile,NULL,"ComputerName","King Drafus",comp_name);
	num_tables=iniReadShortInt(inifile,NULL,"Tables",5);
	if(num_tables>MAX_TABLES)
		num_tables=MAX_TABLES;
	if(num_tables<1)
		num_tables=1;
	time_allowed=iniReadInteger(inifile,NULL,"TimeAllowed",86400);
	if(time_allowed>86400 || time_allowed<0)
		time_allowed=86400;
	skim=iniReadShortInt(inifile,NULL,"Skim",10);
	if(skim<0)
		skim=0;
	if(skim>50)
		skim=50;
	for(i=1;i<=num_tables;i++) {
		sprintf(key_name,"Table%d",i);
		opts=0;
		opts|=(iniReadBool(inifile,key_name,"ComputerPlayer",TRUE)?COMPUTER:0);
		opts|=(iniReadBool(inifile,key_name,"Password",FALSE)?PASSWORD:0);
		options[i]=opts;
		ante[i]=iniReadShortInt(inifile,key_name,"Ante",i*50);
		bet_limit[i]=iniReadShortInt(inifile,key_name,"BetLimit",i*100);
		if(bet_limit[i] < 1)
			bet_limit[i]=1;
		max_total[i]=iniReadInteger(inifile,key_name,"TableLimit",i*1000);
		if(max_total[i] < 1)
			max_total[i]=1;
	}
	if(inifile!=NULL)
		fclose(inifile);

    if (comp_name[0]==0)
        strcpy(comp_name,sys_guru);

    if(fexist("dpoker.plr")) {
        if((file=nopen("dpoker.plr",O_RDONLY))==-1) {
            printf("Error opening time file\r\n");
            pause();
        length=filelength(file);
deuce's avatar
deuce committed
        if ((buf=(char *)malloc(length))!=NULL) {
            read(file,buf,length);
        }
        close(file);
        for (l=0;l<length;l+=sizeof(player_stuff)) {
            sprintf(player_stuff.name,"%.25s",buf+l);
            player_stuff.time=*(ulong *)(buf+l+25);
            player_stuff.points=*(long *)(buf+l+29);
            truncsp(player_stuff.name);
            if (!stricmp(player_stuff.name,user_name))
                time_played+=(player_stuff.time*60);
        }
deuce's avatar
deuce committed
        free(buf);
    }


    for (x=1;x<=num_tables;x++) {
        if (bet_limit[x]<=0 || bet_limit[x]>9999) bet_limit[x]=100;
        if (max_total[x]<bet_limit[x] || max_total[x]>99999)
            max_total[x]=bet_limit[x]*2;
        if (ante[x]<=0 || ante[x]>bet_limit[x]) ante[x]=bet_limit[x];
    }

deuce's avatar
deuce committed
    while(inkey(0));	/* clear input buffer */
    putchar(5); /* ctrl-e */
    mswait(500);
    if(keyhit()) {
deuce's avatar
deuce committed
        while(inkey(0));
        cls(); bputs("\r\n"); center_wargs("\1r\1h\1i*** ATTENTION ***");
        bputs("\r\n\1n\1hDomain Poker \1nuses Ctrl-E (ENQ) for the 'club' card "
              "symbol.");
        bputs("\r\nYour terminal responded to this control character with an "
              "answerback string.");
        bputs("\r\nIf you have any problems with missing characters or "
              "incomplete strings\r\nwhile playing the game, you will probably "
              "need to either disable all Ctrl-E ");
        bputs("\r\n(ENQ) answerback strings (Including Compuserve Quick B "
              "transfers) or toggle\r\ncard symbols OFF.\r\n\r\n");
        pause();
    }
    cls();
rswindell's avatar
rswindell committed
    center_wargs("\1n\1gWelcome to Domain Poker v%s-%s",VERSION,revision);
rswindell's avatar
rswindell committed
    center_wargs("\1n\1gCopyright %s Domain Entertainment", __DATE__+7);

    do {
        mnehigh=GREEN|HIGH; mnelow=GREEN;
        mnemonics("\r\n\r\n~How to play Domain Poker\r\n~Instructions\r\n"
                  "~Join a card game\r\n");
        mnemonics("~List players\r\n~Toggle card symbols ON/OFF\r\n");
        mnemonics("~Player log of the day\r\n~Quit back to ");
        bprintf("\1y\1h%s\1n",sys_name);
        bprintf("\r\n"); nodesync();
        bprintf("\r\n\1m\1hCommand:\1n ");
		ch=getkey(K_UPPER);
        bprintf("%c\r\n",ch);

		switch(ch) {
			case 'Q':
				break;
            case 'P':
                if (!fexist("dpoker.plr")) {
                    bprintf("\r\n\1c\1hNo one has played Domain Poker today.");
                    break;
                }
                won=lost=0L;
                bprintf("\r\n\1y\1hList of today's players\1n\r\n");
                if((file=nopen("dpoker.plr",O_RDONLY))!=-1) {
                    length=filelength(file);
deuce's avatar
deuce committed
                    if ((buf=(char *)malloc(length))!=NULL) {
                        read(file,buf,length);
                    }
                    close(file);
                    for (l=0;l<length;l+=sizeof(player_stuff)) {
                        sprintf(player_stuff.name,"%.25s",buf+l);
                        player_stuff.time=*(ulong *)(buf+l+25);
                        player_stuff.points=*(long *)(buf+l+29);
                        if (player_stuff.points>0) strcpy(str,"\1m\1hWON!");
                        else strcpy(str,"\1y\1hLOST");
                        bprintf("\r\n\1b\1h%-25.25s          %s \1c\1h%8ldK \1b"
                                "\1hof credits.",player_stuff.name,str,
                                labs(player_stuff.points));
                        truncsp(player_stuff.name);
                        if (!stricmp(player_stuff.name,user_name)) {
                            if (player_stuff.points>0)
                                won+=player_stuff.points;
                            else
                                lost+=labs(player_stuff.points);
                        }
                    }
deuce's avatar
deuce committed
                    free(buf);
                    if (won || lost) {
                        bprintf("\r\n\r\n\1m\1hYou've won \1y%ldK \1mand "
                                "lost \1y%ldK \1mfor a total %s of "
                                "\1c%ldK \1mtoday.",won,lost,(lost>won) ? "loss"
                                : "win",(lost>won) ? (lost-won) : (won-lost));
                    }
                }
                break;
            case 'H':
                printfile("dpoker.how");
                printfile("dpoker.ins");
				break;
			case 'L':
                do {
                bprintf("\r\n\1b\1hWhich table [\1c1-%d\1b][\1cT=Table list\1b]"
                        ": ",num_tables);
                x=getkeys("qt",num_tables);
                if(x&0x8000) {
                    x&=~0x8000; show_players(x); }
                if(x=='T') {
                    show_tables(); bputs("\r\n"); }
                if(x=='Q')
                    break;
                } while (x=='T');
				break;
            case 'T':
                symbols=!symbols;
                bprintf("\1_\1b\1h\r\nCard symbols now: \1c%s\r\n",symbols ?
                        "ON":"OFF");
                break;
			case 'J':
                last_bet=100;
                mnehigh=CYAN|HIGH; mnelow=CYAN;
                if (select_table()) {
                    if (newpts<=(max_total[cur_table]*1024L)) {
                        bprintf("\r\n\1r\1hYou don't have enough credits to "
                                "play that table!\1n\r\n\1b\1hThe minimum required "
                                "is \1c\1h%luK\1n",max_total[cur_table]);
                    } else join_game();
                } else break;
                if (node[node_num-1])
                    play_menu();
                break;
		}
    } while (ch!='Q');

    bprintf("\r\n\r\n\1n\1gReturning you to \1g\1h%s\r\n\r\n\1n",sys_name);
rswindell's avatar
rswindell committed
	mswait(500);
}

/*****************************************************************************
 This function allows the player to discard up to three cards, this happens
 after the initial bet round is complete.  This function also draws the number
 of cards from the deck that the player has discarded.
******************************************************************************/
void discard()
{
    char str[256],dishand[256];
    int dc,tdc=1,num,i;
    card_t temp[10];

    getdeck(); player_dis=0;
    get_player(node_num);
    gethandtype(node_num);
    for (num=0;num<5;num++)
        temp[num]=hand[node_num][num];
    get_game_status(cur_table); node[node_num-1]=DISCARDING;
    put_game_status(node_num-1);
    sprintf(str,"\r\n\1n\1gNode %2d: \1h%s \1n\1gis discarding cards.",node_num,
            user_name);
    send_all_message(str,0);
    lncntr=0;
    bprintf("\r\n\r\n\1y\1hDiscard Stage\r\n");
    bprintf("\r\n\r\n\r\n\r\n\r\n\r\n");
    bprintf("\x1b[6A");
    do {
        strcpy(dishand,handstr(node_num)); if(!symbols) strip_symbols(dishand);
        snprintf(str, sizeof(str), "\r\n\t\t\t\1b\1h%s - \1b\1h(\1c%s\1b)\1n",dishand,
            ranking(rank));
        bprintf("%s\r\n\t\t\t\1b\1h(\1c1\1b) (\1c2\1b) (\1c3\1b) (\1c4\1b) "
                "(\1c5\1b)\r\n",str);
        bprintf("\r\n\1b\1hDiscard Which (\1c\1hQ when done\1b\1h): ");
        dc=getnum(5);
        if (hand[node_num][dc-1].value>0 && dc>0) {
            if (tdc>3) {
                bprintf("\r\n\1r\1hYou can only discard up to 3 cards!\1n");
                pause(); for (i=0;i<35;i++) bputs("\b \b"); bprintf("\x1b[A");
            } else { hand[node_num][dc-1].value=0; tdc++; }
        } else if (dc>0) {
            hand[node_num][dc-1]=temp[dc-1]; tdc--; }
        if (user_misc&ANSI) bprintf("\x1b[5A");
    } while (dc!=-1);

    for (num=0;num<5;num++)
        if (!hand[node_num][num].value) {
            hand[node_num][num]=deck[cur_card++];
        }

    putdeck(); put_player(node_num); gethandtype(node_num);
    strcpy(dishand,handstr(node_num)); if(!symbols) strip_symbols(dishand);
    if (user_misc&ANSI) bprintf("\x1b[A");
    bprintf("\r\n\r\n\1m\1h          You now have: %s - \1b\1h(\1c%s\1b)\1n"
            "          ",dishand,ranking(rank));
    if (user_misc&ANSI) bprintf("\r\n\t\t\t                                  ");
    player_dis=tdc-1;
    sprintf(str,"\r\n\1m\1h%s discards %d cards",user_name,tdc-1);
    send_all_message(str,node_num);
    node[node_num-1]=WAITING; put_game_status(node_num-1);
    lncntr=0;
    if (dealer!=node_num)
        next_player();
}

/********************************************************************
 This function checks for possible straight or flush of computer hand
 returns 1 if possible, 0 if not
*********************************************************************/
int straight_flush()
{
    int x,i,j,matchcard=0;

    gethandtype(0);

    /* check for a possible flush */
    x=0;
    for (i=0;i<5;i++) {
        matchcard=hand[0][i].suit; x=0;
        for (j=0;j<5;j++) {
            if (hand[0][j].suit==(matchcard)) x++;
        }
        if (x>2) return 1;      /* yes, possible flush */
    }

    /* check for a possible straight */
    x=0;                                    /* Check for a Straight */
    for (i=0;i<5;i++) {
        matchcard=hand[0][i].value; x=0; if (matchcard==14) matchcard=1;
        for (j=0;j<5;j++) {
            if (hand[0][j].value==(matchcard+1)) {
                x++; matchcard++;
            }
        }
        if (x>2) return 1;      /* yes, possible straight */
    }

    return 0;                   /* nothing */
}

/***************************************************
 This function is where the computer player discards
****************************************************/
void computer_discard()
{
    int x,i,j,match,dc=0,temp_hc=0,matchcard=0;

    getdeck(); gethandtype(0);
    bprintf("\r\n\1g\1h%s \1n\1gis discarding cards.",comp_name);

    /*******************************************************/
    /* This makes the computer discard the oddball card(s) */
    /* when the hand has a certain ranking > NOTHING       */
    /*******************************************************/
    if (rank==ONE_PAIR) {
        for (x=0;x<5;x++)
            if (hand[0][x].value!=dupcard1 && hand[0][x].value<=10) {
                hand[0][x]=deck[cur_card++]; dc++;
            }
        if (!dc)
            for (x=0;x<5;x++)
                if (hand[0][x].value!=dupcard1 && hand[0][x].value<=14) {
                    hand[0][x]=deck[cur_card++]; dc++;
                }
        bprintf("\r\n\1m\1h%s discards %d cards",comp_name,dc);
        putdeck();
        next_player(); return;
    }
    if (rank==TWO_PAIR || rank==THREE_OF_A_KIND || rank==FOUR_OF_A_KIND) {
        for (x=0;x<5;x++)
            if (hand[0][x].value!=dupcard1 && hand[0][x].value!=dupcard2) {
                hand[0][x]=deck[cur_card++]; dc++;
            }
        bprintf("\r\n\1m\1h%s discards %d cards",comp_name,dc);
        putdeck();
        next_player(); return;
    }

    /*************************************************************************/
    /* This routine will run 20% of the time if there's the possibility of a */
    /* straight or a flush (because of the low chances of getting either)    */
    /*************************************************************************/
    if (straight_flush() && !rand()%5) {
        /**********************************************************************/
        /* This checks for a possible flush and discards non-conforming cards */
        /**********************************************************************/
        x=0;
        for (i=0;i<5;i++) {
            matchcard=hand[0][i].suit; x=0;
            for (j=0;j<5;j++) {
                if (hand[0][j].suit==(matchcard)) x++;
            }
            if (x>2 && !xp_random(3)) {
                for (i=0;i<5;i++) {
                    if (hand[0][i].suit!=matchcard)
                        hand[0][i]=deck[cur_card++];
                }
                bprintf("\r\n\1m\1h%s discards %d cards.",comp_name,5-x);
                putdeck(); next_player();
                return;
            }
        }


        /*********************************************************************/
        /* This checks for a possible strt and discards non-conforming cards */
        /*********************************************************************/
        x=0;                                    /* Check for a Straight */
        for (i=0;i<5;i++) {
            matchcard=hand[0][i].value; x=0; if (matchcard==14) matchcard=1;
            for (j=0;j<5;j++) {
                if (hand[0][j].value==(matchcard+1)) {
                    x++; matchcard++;
                }
            }
            if (x>2 && !xp_random(3)) {
                for (i=0;i<5;i++) {
                    match=0;
                    for (j=0;j<x;j++)
                        if (hand[0][i].value==matchcard-j) match=1;
                    if (!match)
                        hand[0][i]=deck[cur_card++];
                }
                bprintf("\r\n\1m\1h%s discards %d cards.",comp_name,5-x);
                putdeck(); next_player();
                return;
            }
        }
        if (x<4) { x=0;                         /* Leave cards at their */
            for (i=0;i<5;i++) {                 /* normal values        */
                matchcard=hand[0][i].value; x=0;
                for (j=0;j<5;j++) {
                    if (hand[0][j].value==(matchcard-1)) {
                        x++; matchcard--;
                    }
                }
                if (x>2) {
                    for (i=0;i<5;i++) {
                        match=0;
                        for (j=0;j<x;j++)
                            if (hand[0][i].value==matchcard+j) match=1;
                        if (!match)
                            hand[0][i]=deck[cur_card++];
                    }
                    bprintf("\r\n\1m\1h%s discards %d cards.",comp_name,5-x);
                    putdeck(); next_player();
                    return;
                }
            }
        }
    }
    /***************************************************************/
    /* This makes the computer discard all but the 2 highest cards */
    /* This is the default when nothing else has been done yet     */
    /***************************************************************/
    for (x=0;x<5;x++) {
        if (hand[0][x].value!=hicard)
            if (hand[0][x].value>temp_hc)
                temp_hc=hand[0][x].value;
    }
    for (x=0;x<5;x++) {
        if (hand[0][x].value!=hicard && hand[0][x].value!=temp_hc)
            hand[0][x]=deck[cur_card++];
    }
    bprintf("\r\n\1m\1h%s discards 3 cards.",comp_name);
    putdeck();
    next_player(); return;
}
/*************************************************************************
 This is where the computer decides how and what to bet or whether to call
 or fold
**************************************************************************/
void computer_bet()
{
rswindell's avatar
rswindell committed
    int add=0,call=0,fold=0,raise=0;

    if (!firstbet && stage==BET && current_bet==0) { next_player(); return; }
    if (!firstbet && stage==BET2 && (comp_bet-current_bet==0) && firstbid) {
        bet_menu();
        if (comp_bet-current_bet!=0 || node[node_num-1]==FOLDED) {
            next_player();
            return;
        }
    }

    gethandtype(0);
    get_game_status(cur_table);
    bprintf("\r\n\1g\1h%s \1n\1gis betting.",comp_name);
    max_bet=bet_limit[cur_table];           /* set to predifined limit */
    if (max_bet>(newpts/1024L)-(current_bet-player_bet))
       max_bet=((newpts/1024L)-(current_bet-player_bet));
    /* set to lowest amount minus the minimum required */
    if (current_bet+max_bet>=max_total[cur_table])
        max_bet=max_total[cur_table]-current_bet;

    while(1) {
        /* No credits available, gotta call! */
        if (max_bet==0) {
            call=1; break;
        }
        if (stage==BET) {
            /* 20% of the time, bet different hand to confuse player */
            /* or raise if the user initial bet was <= 10% of max  & */
            /* random 33% of the time                                */
            if (!rand()%4 || (!firstbet && current_bet<=(.1
                *bet_limit[cur_table]) && !rand()%2)) {
                if (!xraised) {
                    add=(max_bet*.75)+xp_random(max_bet*.25);
                    raise=1; break;
                }
            }

            if (rank==NOTHING) {
                if (!firstbet || current_bet>0) {
                    call=1; break;
                }
                if (hicard<11) {
                    add=(max_bet*.40)+xp_random(max_bet*.20);
                    raise=1; break;
                }
                if (hicard>10) {
                    add=(max_bet*.50)+xp_random(max_bet*.25);
                    raise=1; break;
                }
            }
            if (rank==ONE_PAIR) {
                if (firstbet && xraised>=1) {
                    /* (!firstbet || current_bet>0) */
                    call=1; break;
                }
                if (dupcard1<11) {
                    add=(max_bet*.60)+xp_random(max_bet*.40);
                    raise=1; break;
                }
                if (dupcard1>10) {
                    add=(max_bet*.75)+xp_random(max_bet*.25);
                    raise=1; break;
                }
            }
            if (rank==TWO_PAIR) {
                if ((firstbet && xraised>=2) || xraised>=1) {
                    call=1; break;
                }
                if (dupcard1<11 && dupcard2<11) {
                    add=(max_bet*.80)+xp_random(max_bet*.20);
                    raise=1; break;
                }
                if (dupcard1>10 || dupcard2>10) {
                    add=(max_bet*.90)+xp_random(max_bet*.10);
                    raise=1; break;
                }
            }
            if (rank>=THREE_OF_A_KIND) {
                if ((firstbet && xraised>=3) || xraised>=2) {
                    call=1; break;
                }
                add=max_bet;
                raise=1; break;
            }
            bprintf("\r\nPROBLEM: Stage BET1, please report to SysOp!");
            pause();
        }
        if (stage==BET2) {
            if (rank==NOTHING) {
                if (firstbet) {
                    if (!rand()%5 && hicard>10) {
                        if (xraised) {
                            call=1; break;
                        } else {
                            add=(max_bet*.30)+
                                xp_random(max_bet*.10);
                            raise=1; break;
                        }
                    } else {
                        fold=1; break;
                    }
                }
                if (!firstbet) {
                    if (current_bet-comp_bet==0) {
                        call=1; xraised=1; break;
                    }
                    if (!rand()%3 && hicard>10) {
                        call=1; break;
                    } else {
                        fold=1; break;
                    }
                }
            }
            if (rank==ONE_PAIR) {
                if (!firstbet && current_bet-comp_bet==0) {
                    if (dupcard1<5) {
                        call=1; break;
                    }
                    if (dupcard1<11) {
                        add=(max_bet*.70)+xp_random(max_bet*.30);
                        raise=1; break;
                    }
                    if (dupcard1>10) {
                        add=(max_bet*.80)+xp_random(max_bet*.20);
                        raise=1; break;
                    }
                }
                if (!firstbet || xraised) {
                    call=1; break;
                }
                if (dupcard1<11) {
                    add=(max_bet*.60)+xp_random(max_bet*.40);
                    raise=1; break;
                }
                if (dupcard1>10) {
                    add=(max_bet*.80)+xp_random(max_bet*.20);
                    raise=1; break;
                }
            }
            if (rank==TWO_PAIR) {
                if (xraised>=2) {
                    call=1; break;
                }
                if (dupcard1<11 && dupcard2<11) {
                    add=(max_bet*.80)+xp_random(max_bet*.20);
                    raise=1; break;
                }
                if (dupcard1>10 || dupcard2>10) {
                    add=(max_bet*.90)+xp_random(max_bet*.10);
                    raise=1; break;
                }
            }
            if (rank>=THREE_OF_A_KIND && rank<=FULL_HOUSE) {
                if (xraised>=3) {
                    call=1; break;
                }
                add=max_bet;
                raise=1; break;
            }
            if (rank>=FOUR_OF_A_KIND) {
                if (xraised>=4) {
                    call=1; break;
                }
                add=max_bet;
                raise=1; break;
            }
            bprintf("\r\nPROBLEM: Stage BET2, please report to SysOp!");
            pause();
        }
    }
    if (fold) {
        bprintf("\r\n\1g\1h%s \1n\1gfolds.",comp_name); comp_stat=FOLDED;
        next_player(); return;
    }

    if (call) {
        total_pot+=(add+(current_bet-comp_bet));
        put_game_status(-1);
        comp_bet=current_bet;
        bprintf("\r\n\1g\1h%s \1n\1gcalls - \1b\1h The total pot is now %luK"
                ,comp_name,total_pot);
        next_player(); return;
    }

    if (raise) {
        if (add>10) add-=add%10;
        if (add<1) add=1;
        total_pot+=(add+(current_bet-comp_bet));
        current_bet+=add;
        put_game_status(-1);
        comp_bet+=(current_bet-comp_bet);
        bprintf("\r\n\1g\1h%s \1m\1hhas increased the bet to \1y\1h%luK"
                "\r\n\1b\1hThe total pot is now \1y\1h%luK\1n",comp_name
                ,current_bet,total_pot);
        next_player(); xraised++; return;
    }
}
/************************************************************************
 This function shows the hands of all the players.  If WINNER is a number
 greater than zero, it will show that player as being the winner of the
 game.
*************************************************************************/
void show_all_hands(int winner)
{
    char str[256],str1[256];
    int show;

    str1[0]=0;
    get_game_status(cur_table);
    if (total_players>1) {
        for (show=1;show<=sys_nodes;show++) {
            if (node[show-1]) {
                get_player(show);
                gethandtype(show);
                sprintf(str,"\r\n\1g\1h(%2d) %-25.25s %s \1g\1h(\1y%-15.15s\1g)"
                        ,show,username(temp_num),handstr(show),ranking(rank));
                if (show==winner) strcat(str," \1m\1hWINNER");
                if (node[show-1]==FOLDED) strcat(str," \1r\1hFolded");
                strcpy(str1,str);
                if (!symbols) strip_symbols(str);
                bprintf(str); str[0]=0;
            }
        }
        send_all_message(str1,0); str1[0]=0;
    }
    if (total_players==1) {                 /* Single Player Stuff */
        for (show=1;show<=sys_nodes;show++) {
            if (node[show-1]) {
                get_player(show);
                gethandtype(show);
                sprintf(str,"\r\n\1g\1h(%2d) %-25.25s %s \1g\1h(\1y%-15.15s\1g)"
                        ,show,user_name,handstr(show),ranking(rank));
                if (show==winner) strcat(str," \1m\1hWINNER");
                if (node[show-1]==FOLDED) strcat(str," \1r\1hFolded");
                if (!symbols) strip_symbols(str);
                bprintf(str); str[0]=0;
            }
        }
        gethandtype(0);
        sprintf(str,"\r\n\1g\1h(%2d) %-25.25s %s \1g\1h(\1y%-15.15s\1g)"
                ,sys_nodes+1,comp_name,handstr(0),ranking(rank));
        if (!winner) strcat(str," \1m\1hWINNER!");
        if (comp_stat==FOLDED) strcat(str," \1r\1hFolded");
        if (!symbols) strip_symbols(str);
        bprintf(str); str[0]=0;
    }
}


/*********************************************************
 This function declares the winner on a single player game
**********************************************************/
void single_winner()
{
    int winner=0,comprank,compdup1,compdup2,x;
    long l=0;


    firstbet=!firstbet;     /* Toggle the betting stage */

    gethandtype(0);
    comprank=rank; compdup1=dupcard1; compdup2=dupcard2;
    get_game_status(cur_table); get_player(node_num);

    if (node[node_num-1]==FOLDED || (comprank>rank && comp_stat!=FOLDED))
        winner=0;

    if (comp_stat==FOLDED || (rank>comprank && node[node_num-1]!=FOLDED))
        winner=1;

    if (comp_stat!=FOLDED && node[node_num-1]!=FOLDED) {
        if (rank==comprank) {
            if (rank==ROYAL_FLUSH)
                winner=2;
            if (rank==ONE_PAIR || rank==THREE_OF_A_KIND || rank==FOUR_OF_A_KIND
                || rank==FULL_HOUSE) {
                if (dupcard1>compdup1)
                    winner=1;
                else
                    winner=0;
            }
            if (rank==TWO_PAIR) {
                if ((dupcard1>compdup1 && dupcard1>compdup2) ||
                    (dupcard2>compdup1 && dupcard2>compdup2))
                    winner=1;
                else
                    winner=0;
            }
            if (rank==NOTHING || rank==STRAIGHT || rank==FLUSH ||
                rank==STRAIGHT_FLUSH || (rank==ONE_PAIR &&
                dupcard1==compdup1)) {
                if (hand_total(node_num)>hand_total(0))
                    winner=1;
                if (hand_total(0)>hand_total(node_num))
                    winner=0;
                if (hand_total(0)==hand_total(node_num))
                    winner=2;
            }
        }
    }

    if (create_log) {
        if (!winner)
                l+=(1024L*total_pot);
            else if (winner==1)
                l-=(1024L*total_pot);
            else if (winner==2)
                l+=(1024L*total_pot)/2L;
        computer_log(l);
    }
    if (!winner) {
        show_all_hands(0);
        bprintf("\r\n\r\n\1b\1hThe pot was \1c\1h%luK\1b\1h of credits!\1n"
                ,total_pot);
    }

    if (winner==1) {
        show_all_hands(node_num);
        get_player(node_num);
        temppts=temppts+(1024L*total_pot);