This repository has been archived on 2025-02-12. You can view files and clone it, but cannot push or open issues or pull requests.
NeoStats-yatzeeserv/play.c
2006-01-26 15:39:26 +00:00

664 lines
19 KiB
C

/* YahtzeeServ - Yahtzee Game Service - NeoStats Addon Module
** Copyright (c) 2003-2006 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
**
** YahtzeeServ CVS Identification
** $Id$
*/
#include "neostats.h" /* Required for bot support */
#include "yahtzeeserv.h"
/*
* Start Game
*/
int StartYahtzeeGame (const CmdParams *cmdparams)
{
GameData *gd;
Channel *c;
SET_SEGV_LOCATION();
if (!cmdparams->channel && !cmdparams->ac)
return NS_SUCCESS;
if (cmdparams->ac)
{
if (!YahtzeeServ.multichan)
{
irc_prefmsg (ys_bot, cmdparams->source, "Games outside %s are not currently allowed", YahtzeeServ.yahtzeeroom);
return NS_SUCCESS;
}
if (ValidateChannel(cmdparams->av[0]) == NS_FAILURE)
{
irc_prefmsg (ys_bot, cmdparams->source, "Invalid Channel Name Specified (%s)", cmdparams->av[0]);
return NS_SUCCESS;
}
c = FindChannel(cmdparams->av[0]);
if (!c)
{
irc_prefmsg (ys_bot, cmdparams->source, "%s doesn't currently exist, unable to start.", cmdparams->av[0]);
return NS_SUCCESS;
}
if (IsChannelMember(c, cmdparams->source) == NS_FALSE)
{
irc_prefmsg (ys_bot, cmdparams->source, "You are not currently in %s. Unable to start.", c->name);
return NS_SUCCESS;
}
if ( YahtzeeServ.chanoponly && !IsChanOp(c, cmdparams->source))
{
irc_prefmsg (ys_bot, cmdparams->source, "Currently only Channel Ops may start games outside the main game channel.");
return NS_SUCCESS;
}
if ((YahtzeeServ.exclusions && IsExcluded(c)) || ModIsChannelExcluded(c))
{
irc_prefmsg (ys_bot, cmdparams->source, "%s is currently excluded from Yahtzee games.", c->name);
return NS_SUCCESS;
}
} else {
c = cmdparams->channel;
}
gd = (GameData *)GetChannelModValue(c);
if (!gd)
{
CreateChannelGameData(c);
gd = (GameData *)GetChannelModValue(c);
} else if (gd->gamestatus != YS_GAME_STOPPED) {
irc_prefmsg (ys_bot, cmdparams->source, "A game is already running in %s.", c->name);
return NS_SUCCESS;
}
gd->timer = 25;
gd->gamestatus = YS_GAME_STARTING;
irc_chanprivmsg (ys_bot, c->name, "\0037Yahtzee has been started by %s. The game will start shortly, type '\2\003!Join\2\0037' to play.", cmdparams->source->name);
return NS_SUCCESS;
}
/*
* Timer Procedure
* checks for starting games
* if game if due to start, checks for joined users
* if users joined starts game, if not end game.
*/
int yahtzeetimer(void *userptr)
{
lnode_t *ln, *ln2;
GameData *gd;
Channel *c;
SET_SEGV_LOCATION();
ln = list_first(gamelist);
while (ln)
{
c = lnode_get(ln);
gd = (GameData *)GetChannelModValue(c);
if (!gd)
{
ln2 = list_next(gamelist, ln);
list_delete(gamelist, ln);
lnode_destroy(ln);
ln = ln2;
} else if (gd->gamestatus == YS_GAME_STARTING) {
if (gd->timer > 4)
{
gd->timer -= 5;
ln = list_next(gamelist, ln);
} else {
gd->timer = 0;
if (gd->playercount < 1)
{
irc_chanprivmsg (ys_bot, c->name, "\0034No Players joined to current Game, Exiting");
ln2 = list_next(gamelist, ln);
lnode_destroy(ln);
ln = ln2;
RemoveChannelGameData(c, 0);
} else {
irc_chanprivmsg (ys_bot, c->name, "\00310Yahtzee is now starting, current players are \0037%s %s %s %s %s %s %s %s %s %s", gd->pd[0]->u ? gd->pd[0]->u->name : "", gd->pd[1]->u ? gd->pd[1]->u->name : "", gd->pd[2]->u ? gd->pd[2]->u->name : "", gd->pd[3]->u ? gd->pd[3]->u->name : "", gd->pd[4]->u ? gd->pd[4]->u->name : "", gd->pd[5]->u ? gd->pd[5]->u->name : "", gd->pd[6]->u ? gd->pd[6]->u->name : "", gd->pd[7]->u ? gd->pd[7]->u->name : "", gd->pd[8]->u ? gd->pd[8]->u->name : "", gd->pd[9]->u ? gd->pd[9]->u->name : "");
gd->gamestatus = YS_GAME_PLAYING;
gd->currenthand = 1;
RollDice(c);
ln = list_next(gamelist, ln);
}
}
} else {
ln = list_next(gamelist, ln);
}
}
return NS_SUCCESS;
}
/*
* Join Player To Game
*/
int JoinYahtzeeGame (const CmdParams *cmdparams) {
GameData *gd;
int i;
SET_SEGV_LOCATION();
gd = (GameData *)GetChannelModValue(cmdparams->channel);
if (!gd)
return NS_SUCCESS;
if (gd->gamestatus == YS_GAME_STARTING || (gd->gamestatus == YS_GAME_PLAYING && gd->currenthand < 2))
{
if (gd->playercount < YS_MAX_PLAYERS)
{
for (i = 0; i < gd->playercount; i++)
{
if (gd->pd[i]->u == cmdparams->source)
return NS_SUCCESS;
}
gd->pd[gd->playercount]->u = cmdparams->source;
gd->pd[gd->playercount]->score = 0;
for (i=0;i<15;i++)
gd->pd[gd->playercount]->hand[i] = -1;
gd->playercount++;
if (!GetUserModValue(cmdparams->source))
SetUserModValue(cmdparams->source,(void *)1);
else
SetUserModValue(cmdparams->source,(void *)((int)GetUserModValue(cmdparams->source) + 1));
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0038Welcome to Yahtzee \0037%s", cmdparams->source->name);
} else {
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0034Sorry all places are filled \0037%s\0034, your welcome to try the next game though", cmdparams->source->name);
}
}
return NS_SUCCESS;
}
/*
* Remove Player
*/
int RemoveYahtzeeGame (const CmdParams *cmdparams)
{
Client *u;
SET_SEGV_LOCATION();
if (cmdparams->ac > 0 && (cmdparams->source->user->ulevel >= NS_ULEVEL_LOCOPER || IsChanOp(cmdparams->channel, cmdparams->source)))
{
u = FindUser(cmdparams->av[0]);
if (!u)
return NS_SUCCESS;
} else {
u = cmdparams->source;
}
removenickfromgame(cmdparams->channel, u);
return NS_SUCCESS;
}
/*
* Removes User From Game In Channel
*/
void removenickfromgame(Channel *c, Client *u) {
GameData *gd;
int i, i2, i3, rp;
if (!GetUserModValue(u))
return;
gd = (GameData *)GetChannelModValue(c);
if (!gd)
return;
if (gd->playercount < 1)
return;
if (gd->gamestatus != YS_GAME_STARTING && gd->gamestatus != YS_GAME_PLAYING)
return;
rp = 0;
for (i = 0 ; i < gd->playercount ; i++)
{
if (gd->pd[i]->u == u)
{
if (GetUserModValue(u) > 0)
SetUserModValue(u,(void *)((int)GetUserModValue(u) - 1));
for (i2 = i ; i2 < gd->playercount ; i2++)
{
if (i2 < (gd->playercount - 1))
{
gd->pd[i2]->u = gd->pd[(i2 + 1)]->u;
gd->pd[i2]->score = gd->pd[(i2 + 1)]->score;
for (i3 = 0 ; i3 < 15 ; i3++)
gd->pd[i2]->hand[i3] = gd->pd[(i2 + 1)]->hand[i3];
} else {
gd->pd[i2]->u = NULL;
}
}
gd->playercount--;
if (gd->gamestatus == YS_GAME_PLAYING)
{
if (i < gd->currentplayer)
{
gd->currentplayer--;
} else if (i == gd->currentplayer) {
gd->currentroll = 0;
if (i == gd->playercount)
{
gd->currenthand++;
gd->currentplayer = 0;
}
}
}
if (!rp)
irc_chanprivmsg (ys_bot, c->name, "\0037%s \0038Removed from the current game of Yahtzee", u->name);
rp++;
i--;
}
}
if (gd->playercount < 1)
{
irc_chanprivmsg (ys_bot, c->name, "\0034Last player removed from Game, Stopping Current Game.");
RemoveChannelGameData(c, 0);
return;
}
if (gd->gamestatus == YS_GAME_PLAYING && !gd->currentroll)
{
RollDice(c);
return;
}
return;
}
/*
* Stop Game
*/
int StopYahtzeeGame (const CmdParams *cmdparams)
{
GameData *gd;
SET_SEGV_LOCATION();
if (!GetUserModValue(cmdparams->source) && cmdparams->source->user->ulevel < NS_ULEVEL_LOCOPER && !IsChanOp(cmdparams->channel, cmdparams->source))
return NS_SUCCESS;
gd = (GameData *)GetChannelModValue(cmdparams->channel);
if (!gd)
return NS_SUCCESS;
if (gd->gamestatus != YS_GAME_STARTING && gd->gamestatus != YS_GAME_PLAYING)
return NS_SUCCESS;
if (gd->playercount != 1 && cmdparams->source->user->ulevel < NS_ULEVEL_LOCOPER && !IsChanOp(cmdparams->channel, cmdparams->source))
{
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0034Unable to stop Yahtzee when more than one person playing, please use !remove if you wish to exit the game \0037%s.", cmdparams->source->name);
return NS_SUCCESS;
}
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0034Yahtzee has been stopped by \0037%s.", cmdparams->source->name);
RemoveChannelGameData(cmdparams->channel, 0);
return NS_SUCCESS;
}
/*
* Score to Sheet
*/
int ScoreYahtzeeDice (const CmdParams *cmdparams)
{
GameData *gd;
int i, crs, sa, stt;
SET_SEGV_LOCATION();
if (!GetUserModValue(cmdparams->source))
return NS_SUCCESS;
gd = (GameData *)GetChannelModValue(cmdparams->channel);
if (!gd)
return NS_SUCCESS;
if (gd->playercount < 1 || gd->gamestatus != YS_GAME_PLAYING || gd->pd[gd->currentplayer]->u != cmdparams->source) {
return NS_SUCCESS;
}
for (i = 0; i < 6; i++)
dtsc[i]= 0;
for (i = 0; i < 5; i++)
dtsc[gd->dice[i]]++;
crs = sa = 0;
if (!ircstrcasecmp(cmdparams->av[0], "1") || !ircstrcasecmp(cmdparams->av[0], "one"))
{
stt= 0;
if (gd->pd[gd->currentplayer]->hand[0] >= 0)
sa= 1;
else
crs = dtsc[0];
} else if (!ircstrcasecmp(cmdparams->av[0], "2") || !ircstrcasecmp(cmdparams->av[0], "two")) {
stt= 1;
if (gd->pd[gd->currentplayer]->hand[1] >= 0)
sa= 1;
else
crs = (dtsc[1] * 2);
} else if (!ircstrcasecmp(cmdparams->av[0], "3") || !ircstrcasecmp(cmdparams->av[0], "three")) {
stt= 2;
if (gd->pd[gd->currentplayer]->hand[2] >= 0)
sa= 1;
else
crs = (dtsc[2] * 3);
} else if (!ircstrcasecmp(cmdparams->av[0], "4") || !ircstrcasecmp(cmdparams->av[0], "four")) {
stt= 3;
if (gd->pd[gd->currentplayer]->hand[3] >= 0)
sa= 1;
else
crs = (dtsc[3] * 4);
} else if (!ircstrcasecmp(cmdparams->av[0], "5") || !ircstrcasecmp(cmdparams->av[0], "five")) {
stt= 4;
if (gd->pd[gd->currentplayer]->hand[4] >= 0)
sa= 1;
else
crs = (dtsc[4] * 5);
} else if (!ircstrcasecmp(cmdparams->av[0], "6") || !ircstrcasecmp(cmdparams->av[0], "six")) {
stt= 5;
if (gd->pd[gd->currentplayer]->hand[5] >= 0)
sa= 1;
else
crs = (dtsc[5] * 6);
} else if (!ircstrcasecmp(cmdparams->av[0], "fh") || !ircstrcasecmp(cmdparams->av[0], "full")) {
stt= 6;
if (gd->pd[gd->currentplayer]->hand[6] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
{
if ((dtsc[i] == 2) || (dtsc[i] == 3))
{
crs++;
} else if (dtsc[i] == 1) {
crs--;
}
}
if (crs == 2)
crs = 25;
else
crs = 0;
/* allow for Yahtzee to substitute */
if ((!crs) && (gd->pd[gd->currentplayer]->hand[12] == 50))
{
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 5)
crs = 25;
}
}
}
} else if (!ircstrcasecmp(cmdparams->av[0], "ss") || !ircstrcasecmp(cmdparams->av[0], "short") || !ircstrcasecmp(cmdparams->av[0], "small")) {
stt= 7;
if (gd->pd[gd->currentplayer]->hand[7] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 0)
{
if (crs < 4)
crs= 0;
} else {
crs++;
}
}
if (crs > 3)
crs = 30;
else
crs = 0;
/* allow for Yahtzee to substitute */
if ((!crs) && (gd->pd[gd->currentplayer]->hand[12] == 50))
{
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 5)
crs = 30;
}
}
}
} else if (!ircstrcasecmp(cmdparams->av[0], "ls") || !ircstrcasecmp(cmdparams->av[0], "long") || !ircstrcasecmp(cmdparams->av[0], "large")) {
stt= 8;
if (gd->pd[gd->currentplayer]->hand[8] >= 0)
{
sa= 1;
} else {
if ((dtsc[1] == 1) && (dtsc[2] == 1) && (dtsc[3] == 1) && (dtsc[4] == 1))
crs = 40;
/* allow for Yahtzee to substitute */
if ((!crs) && (gd->pd[gd->currentplayer]->hand[12] == 50))
{
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 5)
crs = 40;
}
}
}
} else if (!ircstrcasecmp(cmdparams->av[0], "3k")) {
stt= 9;
if (gd->pd[gd->currentplayer]->hand[9] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
{
if (dtsc[i] > 2)
crs = 1;
}
if (crs)
{
crs = 0;
for (i = 0; i < 6; i++)
crs += (dtsc[i] * (i + 1));
}
}
} else if (!ircstrcasecmp(cmdparams->av[0], "4k")) {
stt= 10;
if (gd->pd[gd->currentplayer]->hand[10] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
{
if (dtsc[i] > 3)
crs = 1;
}
if (crs)
{
crs = 0;
for (i = 0; i < 6; i++)
crs += (dtsc[i] * (i + 1));
}
}
} else if (!ircstrcasecmp(cmdparams->av[0], "c") || !ircstrcasecmp(cmdparams->av[0], "chance")) {
stt= 11;
if (gd->pd[gd->currentplayer]->hand[11] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
crs += (dtsc[i] * (i + 1));
}
} else if (!ircstrcasecmp(cmdparams->av[0], "y") || !ircstrcasecmp(cmdparams->av[0], "yahtzee")) {
stt= 12;
if (gd->pd[gd->currentplayer]->hand[12] >= 0)
{
sa= 1;
} else {
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 5)
crs = 50;
}
}
} else {
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0034Sorry\0037 %s\0034, thats not a valid score slot, please use one of the following", cmdparams->source->name);
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\00311One's (1) , Two's (2) , Three's (3) , Four's (4) , Five's (5) , Six's (6)");
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\00311Full House (FH) , Short Straight (SS) , Long Straight (LS)");
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\00311Three of a Kind (3K) , Four of a Kind (4K) , Chance (C) , Yahtzee (Y)");
return NS_SUCCESS;
}
if (sa == 1)
{
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0034Sorry\0037 %s\0034 you have already scored on \00311%s", cmdparams->source->name, ysscoretype[stt]);
return NS_SUCCESS;
}
gd->pd[gd->currentplayer]->hand[stt] = crs;
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0037%s\0039 scored\00311 %d\0039 on \00311%s", cmdparams->source->name, crs, ysscoretype[stt]);
gd->pd[gd->currentplayer]->score += crs;
/* check for Yahtzee Bonus on all except fh ss ls and y */
if ((stt < 6 || stt > 8) && stt != 12 && gd->pd[gd->currentplayer]->hand[12] == 50 && crs)
{
for (i = 0; i < 6; i++)
{
if (dtsc[i] == 5)
{
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0037%s\0039 scored\00311 100 \0038Yahtzee Bonus \0039points", cmdparams->source->name);
if (gd->pd[gd->currentplayer]->hand[14] < 0)
gd->pd[gd->currentplayer]->hand[14] = 100;
else
gd->pd[gd->currentplayer]->hand[14] += 100;
gd->pd[gd->currentplayer]->score += 100;
}
}
}
if (gd->pd[gd->currentplayer]->hand[13] < 0)
{
crs = 0;
for (i = 0; i < 6; i++)
crs += gd->pd[gd->currentplayer]->hand[i];
if (crs > 62)
{
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0037%s\0039 scored a \0038Bonus\00311 35 \0039points", cmdparams->source->name);
crs = 35;
gd->pd[gd->currentplayer]->hand[13] = crs;
gd->pd[gd->currentplayer]->score += crs;
}
}
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0037%s\0039 now has a total of\00311 %d\0039 points", cmdparams->source->name, gd->pd[gd->currentplayer]->score);
gd->currentplayer++;
if (gd->currentplayer >= gd->playercount)
{
gd->currentplayer = 0;
gd->currenthand++;
}
gd->currentroll= 0;
RollDice(cmdparams->channel);
return NS_SUCCESS;
}
/*
* Check if Game over, if not First Dice Roll
*/
void RollDice(Channel *c)
{
GameData *gd;
int i, ywn;
ywn = 0;
gd = (GameData *)GetChannelModValue(c);
if (!gd)
return;
if (gd->currentplayer == 0)
{
srand((unsigned int)me.now);
if (gd->currenthand > 13)
{
irc_chanprivmsg (ys_bot, c->name, "\0038Thats the end of the game folks.");
for (i = 0; i < gd->playercount; i++)
{
if ((i != 0) && (gd->pd[i]->score > gd->pd[ywn]->score))
ywn= i;
irc_chanprivmsg (ys_bot, c->name, "\0037%s\00310 ended with\00311 %d\00310 points.", gd->pd[i]->u->name, gd->pd[i]->score);
}
irc_chanprivmsg (ys_bot, c->name, "\0037%s \0038is the winner with\00311 %d \0038points.", gd->pd[ywn]->u->name, gd->pd[ywn]->score);
checkhighscorelists(c);
RemoveChannelGameData(c, 0);
return;
}
}
for (i = 0; i < 5; i++)
{
gd->dice[i]= rand() % 6;
if (gd->dice[i] == 0)
{
strlcpy(dicetext[i], "One", 15);
} else if (gd->dice[i] == 1) {
strlcpy(dicetext[i], "Two", 15);
} else if (gd->dice[i] == 2) {
strlcpy(dicetext[i], "Three", 15);
} else if (gd->dice[i] == 3) {
strlcpy(dicetext[i], "Four", 15);
} else if (gd->dice[i] == 4) {
strlcpy(dicetext[i], "Five", 15);
} else if (gd->dice[i] == 5) {
strlcpy(dicetext[i], "Six", 15);
}
}
gd->currentroll = 1;
irc_chanprivmsg (ys_bot, c->name, "\0037%s\0039 this is roll\00311 %d\0039, you rolled\0034 %s %s %s %s %s", gd->pd[gd->currentplayer]->u->name, gd->currentroll, dicetext[0], dicetext[1], dicetext[2], dicetext[3], dicetext[4]);
return;
}
/*
* Roll Dice
*/
int RollYahtzeeDice (const CmdParams *cmdparams)
{
SET_SEGV_LOCATION();
reroll(cmdparams, 1);
return NS_SUCCESS;
}
/*
* Keep Dice
*/
int KeepYahtzeeDice (const CmdParams *cmdparams)
{
SET_SEGV_LOCATION();
reroll(cmdparams, 0);
return NS_SUCCESS;
}
/*
* ReRolls Selected Dice
*/
void reroll(const CmdParams *cmdparams, int rolltype)
{
GameData *gd;
char *buf;
int i, dc;
if (!GetUserModValue(cmdparams->source))
return;
gd = (GameData *)GetChannelModValue(cmdparams->channel);
if (!gd)
return;
if (gd->pd[gd->currentplayer]->u != cmdparams->source || gd->gamestatus != YS_GAME_PLAYING || gd->currentroll < 1 || gd->currentroll > 2)
return;
buf= joinbuf(cmdparams->av, cmdparams->ac, 0);
strip_mirc_codes(buf);
for (i = 0; i < 5; i++)
{
if ((strchr(buf, (i + 49)) && rolltype) || (!strchr(buf, (i + 49)) && !rolltype))
{
gd->dice[i]= rand() % 6;
dc = 4;
} else {
dc = 11;
}
if (gd->dice[i] == 0)
{
ircsnprintf(dicetext[i], 15, "\003%dOne", dc);
} else if (gd->dice[i] == 1) {
ircsnprintf(dicetext[i], 15, "\003%dTwo", dc);
} else if (gd->dice[i] == 2) {
ircsnprintf(dicetext[i], 15, "\003%dThree", dc);
} else if (gd->dice[i] == 3) {
ircsnprintf(dicetext[i], 15, "\003%dFour", dc);
} else if (gd->dice[i] == 4) {
ircsnprintf(dicetext[i], 15, "\003%dFive", dc);
} else if (gd->dice[i] == 5) {
ircsnprintf(dicetext[i], 15, "\003%dSix", dc);
}
}
gd->currentroll++;
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0037%s\0039 this is roll\00311 %d\0039, you rolled %s %s %s %s %s", cmdparams->source->name, gd->currentroll, dicetext[0], dicetext[1], dicetext[2], dicetext[3], dicetext[4]);
if (gd->currentroll == 3)
irc_chanprivmsg (ys_bot, cmdparams->channel->name, "\0039That was your last roll this turn\0037 %s\0039, select which score to take", cmdparams->source->name);
ns_free(buf);
return;
}