From 526e5dc8858b20cb0a0ba57de87656c29a1aa90d Mon Sep 17 00:00:00 2001 From: pk910 Date: Sat, 17 Mar 2012 21:19:07 +0100 Subject: [PATCH] added NeonFun Bot with UNO Game --- Makefile.am | 12 +- src/modules/NeonFun.mod/bot_NeonFun.c | 236 +++++++ src/modules/NeonFun.mod/bot_NeonFun.h | 34 + src/modules/NeonFun.mod/cmd_neonfun.c | 69 ++ src/modules/NeonFun.mod/cmd_neonfun.h | 49 ++ src/modules/NeonFun.mod/cmd_neonfun_uno.c | 80 +++ src/modules/NeonFun.mod/cmd_neonfun_unoplay.c | 68 ++ src/modules/NeonFun.mod/cmd_neonfun_unotake.c | 42 ++ src/modules/NeonFun.mod/game_uno.c | 657 ++++++++++++++++++ src/modules/NeonFun.mod/game_uno.h | 112 +++ src/modules/NeonFun.mod/module.c | 39 ++ src/modules/botid.h | 1 + src/modules/global.mod/cmd_global_setbot.c | 2 +- 13 files changed, 1399 insertions(+), 2 deletions(-) create mode 100644 src/modules/NeonFun.mod/bot_NeonFun.c create mode 100644 src/modules/NeonFun.mod/bot_NeonFun.h create mode 100644 src/modules/NeonFun.mod/cmd_neonfun.c create mode 100644 src/modules/NeonFun.mod/cmd_neonfun.h create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_uno.c create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_unoplay.c create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_unotake.c create mode 100644 src/modules/NeonFun.mod/game_uno.c create mode 100644 src/modules/NeonFun.mod/game_uno.h create mode 100644 src/modules/NeonFun.mod/module.c diff --git a/Makefile.am b/Makefile.am index d3f96fe..aba1bf4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ checkversion: cd src && chmod +x version.sh && ./version.sh && cd .. noinst_PROGRAMS = neonserv -noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonServ.la libNeonSpam.la libstats.la +noinst_LTLIBRARIES = libDummyServ.la libfuncmds.la libglobalcmd.la libNeonHelp.la libNeonServ.la libNeonSpam.la libstats.la libNeonFun.la libDummyServ_la_SOURCES = src/modules/DummyServ.mod/bot_DummyServ.c \ src/modules/DummyServ.mod/module.c @@ -149,6 +149,16 @@ libstats_la_SOURCES = src/modules/stats.mod/module.c libstats_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined libstats_la_LIBADD = $(MYSQL_LIBS) +libNeonFun_la_SOURCES = src/modules/NeonFun.mod/bot_NeonFun.c \ + src/modules/NeonFun.mod/cmd_neonfun.c \ + src/modules/NeonFun.mod/cmd_neonfun_uno.c \ + src/modules/NeonFun.mod/cmd_neonfun_unoplay.c \ + src/modules/NeonFun.mod/cmd_neonfun_unotake.c \ + src/modules/NeonFun.mod/game_uno.c \ + src/modules/NeonFun.mod/module.c +libNeonFun_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined +libNeonFun_la_LIBADD = $(MYSQL_LIBS) + neonserv_SOURCES = src/version.c \ src/EventLogger.c \ src/IRCEvents.c \ diff --git a/src/modules/NeonFun.mod/bot_NeonFun.c b/src/modules/NeonFun.mod/bot_NeonFun.c new file mode 100644 index 0000000..f203f91 --- /dev/null +++ b/src/modules/NeonFun.mod/bot_NeonFun.c @@ -0,0 +1,236 @@ +/* bot_NeonFun.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "../botid.h" + +#include "bot_NeonFun.h" +#include "../../modcmd.h" +#include "../../IRCParser.h" +#include "../../IRCEvents.h" +#include "../../UserNode.h" +#include "../../ChanNode.h" +#include "../../ChanUser.h" +#include "../../ModeNode.h" +#include "../../BanNode.h" +#include "../../ClientSocket.h" +#include "../../mysqlConn.h" +#include "../../lang.h" +#include "../../HandleInfoHandler.h" +#include "../../WHOHandler.h" +#include "../../DBHelper.h" +#include "../../tools.h" +#include "../../timeq.h" +#include "../../version.h" +#include "../../EventLogger.h" +#include "../../bots.h" +#include "game_uno.h" + +#define BOTID NEONFUN_BOTID +#define BOTALIAS "NeonFun" + +static void neonfun_bot_ready(struct ClientSocket *client) { + MYSQL_RES *res; + MYSQL_ROW row; + + printf_mysql_query("SELECT `automodes` FROM `bots` WHERE `id` = '%d'", client->clientid); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + putsock(client, "MODE %s +%s", client->user->nick, row[0]); + } + + printf_mysql_query("SELECT `channel_name`, `channel_key` FROM `bot_channels` LEFT JOIN `channels` ON `chanid` = `channel_id` WHERE `botid` = '%d' AND `suspended` = '0'", client->clientid); + res = mysql_use(); + + while ((row = mysql_fetch_row(res)) != NULL) { + putsock(client, "JOIN %s %s", row[0], row[1]); + } +} + +static void neonfun_trigger_callback(int clientid, struct ChanNode *chan, char *trigger) { + MYSQL_RES *res; + MYSQL_ROW row; + loadChannelSettings(chan); + if(!(chan->flags & CHANFLAG_CHAN_REGISTERED)) { + strcpy(trigger, "+"); + return; + } + printf_mysql_query("SELECT `trigger`, `defaulttrigger` FROM `bot_channels` LEFT JOIN `bots` ON `botid` = `bots`.`id` WHERE `chanid` = '%d' AND `botclass` = '%d'", chan->channel_id, BOTID); + res = mysql_use(); + if(!(row = mysql_fetch_row(res))) { + strcpy(trigger, "+"); + return; + } + if(row[0] && *row[0]) + strcpy(trigger, row[0]); + else + strcpy(trigger, ((row[1] && *row[1]) ? row[1] : "~")); +} + +static void start_bots(int type) { + struct ClientSocket *client; + MYSQL_RES *res, *res2; + MYSQL_ROW row; + + if(type == MODSTATE_STARTSTOP) { + printf_mysql_query("SELECT `nick`, `ident`, `realname`, `server`, `port`, `pass`, `textbot`, `id`, `queue`, `ssl`, `bind` FROM `bots` WHERE `botclass` = '%d' AND `active` = '1'", BOTID); + res = mysql_use(); + + while ((row = mysql_fetch_row(res)) != NULL) { + client = create_socket(row[3], atoi(row[4]), row[10], row[5], row[0], row[1], row[2]); + client->flags |= (strcmp(row[6], "0") ? SOCKET_FLAG_PREFERRED : 0); + client->flags |= (strcmp(row[8], "0") ? SOCKET_FLAG_USE_QUEUE : 0); + client->flags |= (strcmp(row[9], "0") ? SOCKET_FLAG_SSL : 0); + client->flags |= SOCKET_FLAG_SILENT; + client->botid = BOTID; + client->clientid = atoi(row[7]); + connect_socket(client); + } + } + + printf_mysql_query("SELECT `command`, `function`, `parameters`, `global_access`, `chan_access`, `flags` FROM `bot_binds` WHERE `botclass` = '%d'", BOTID); + res2 = mysql_use(); + while ((row = mysql_fetch_row(res2)) != NULL) { + if(bind_cmd_to_command(BOTID, row[0], row[1])) { + if(row[2] && strcmp(row[2], "")) { + bind_set_parameters(BOTID, row[0], row[2]); + } + if(row[3]) { + bind_set_global_access(BOTID, row[0], atoi(row[3])); + } + if(row[4]) { + bind_set_channel_access(BOTID, row[0], row[4]); + } + if(strcmp(row[5], "0")) + bind_set_bind_flags(BOTID, row[0], atoi(row[5])); + } + } + bind_unbound_required_functions(BOTID); +} + +static void neonfun_parted(struct ChanUser *chanuser, char *reason) { + uno_event_part(chanuser); +} + +static void neonfun_quitted(struct UserNode *user, char *reason) { + uno_event_quit(user); +} + +static int neonfun_freechan(struct ChanNode *chan) { + uno_event_freechan(chan); + return 0; +} + +void init_NeonFun(int type) { + set_bot_alias(BOTID, BOTALIAS); + start_bots(type); + + if(type == MODSTATE_REBIND) return; + + //register events + bind_bot_ready(neonfun_bot_ready, module_id); + bind_part(neonfun_parted, module_id); + bind_quit(neonfun_quitted, module_id); + bind_freechan(neonfun_freechan, module_id); + + set_trigger_callback(BOTID, module_id, neonfun_trigger_callback); +} + +void loop_NeonFun() { + +} + +void free_NeonFun(int type) { + unbind_allcmd(BOTID); + if(type == MODSTATE_STARTSTOP) { + //disconnect all our bots + struct ClientSocket *client; + for(client = getBots(0, NULL); client; client = getBots(0, client)) { + if(client->botid == BOTID) { + unbind_botwise_allcmd(0, client->clientid); + close_socket(client); + break; + } + } + } +} + +char* getSetting(struct UserNode *user, struct ChanNode *chan, const char *setting) { + char *uname = ""; + int cid = 0; + MYSQL_RES *res; + MYSQL_ROW row; + if(user) { + uname = ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "*"); + } + if(chan) { + loadChannelSettings(chan); + if(chan->flags & CHANFLAG_CHAN_REGISTERED) + cid = chan->channel_id; + } + printf_mysql_query("SELECT `value` FROM `fundata` WHERE `user` = '%s' AND `cid` = '%d' AND `name` = '%s'", escape_string(uname), cid, escape_string(setting)); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + return row[0]; + } else + return NULL; +} + +void setSetting(struct UserNode *user, struct ChanNode *chan, const char *setting, const char *value) { + char *uname = ""; + int cid = 0; + MYSQL_RES *res; + MYSQL_ROW row; + if(user) { + uname = ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "*"); + } + if(chan) { + loadChannelSettings(chan); + if(chan->flags & CHANFLAG_CHAN_REGISTERED) + cid = chan->channel_id; + } + printf_mysql_query("SELECT `id`, `value` FROM `fundata` WHERE `user` = '%s' AND `cid` = '%d' AND `name` = '%s'", escape_string(uname), cid, escape_string(setting)); + res = mysql_use(); + if ((row = mysql_fetch_row(res)) != NULL) { + if(strcmp(row[1], value)) + printf_mysql_query("UPDATE `fundata` SET `value` = '%s' WHERE `id` = '%s'", escape_string(value), row[0]); + } else + printf_mysql_query("INSERT INTO `fundata` (`user`, `cid`, `name`, `value`) VALUES ('%s', '%d', '%s', '%s')", escape_string(uname), cid, escape_string(setting), escape_string(value)); +} + +void uno_reply(struct uno_game *game, struct UserNode *user, const char *text, ...) { + struct ClientSocket *client = game->textbot; + const char *reply_format = get_language_string(user, text); + if(reply_format == NULL) + reply_format = text; + char formatBuf[MAXLEN]; + sprintf(formatBuf, "PRIVMSG %s :[UNO] %s", game->channel->name, reply_format); + va_list arg_list; + char sendBuf[MAXLEN]; + int pos; + if (!(client->flags & SOCKET_FLAG_CONNECTED)) return; + sendBuf[0] = '\0'; + va_start(arg_list, text); + pos = vsnprintf(sendBuf, MAXLEN - 2, formatBuf, arg_list); + va_end(arg_list); + if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2; + sendBuf[pos] = '\n'; + sendBuf[pos+1] = '\0'; + write_socket(client, sendBuf, pos+1); +} + +#undef BOTID +#undef BOTALIAS diff --git a/src/modules/NeonFun.mod/bot_NeonFun.h b/src/modules/NeonFun.mod/bot_NeonFun.h new file mode 100644 index 0000000..6e0e0f6 --- /dev/null +++ b/src/modules/NeonFun.mod/bot_NeonFun.h @@ -0,0 +1,34 @@ +/* bot_NeonFun.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _bot_NeonFun_h +#define _bot_NeonFun_h + +#include "../../main.h" + +void init_NeonFun(int type); +void loop_NeonFun(); +void free_NeonFun(int type); + +struct uno_game; +struct ChanNode; +struct UserNode; + +char* getSetting(struct UserNode *user, struct ChanNode *chan, const char *setting); +void setSetting(struct UserNode *user, struct ChanNode *chan, const char *setting, const char *value); +void uno_reply(struct uno_game *game, struct UserNode *user, const char *text, ...); + +#endif \ No newline at end of file diff --git a/src/modules/NeonFun.mod/cmd_neonfun.c b/src/modules/NeonFun.mod/cmd_neonfun.c new file mode 100644 index 0000000..4f659c9 --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun.c @@ -0,0 +1,69 @@ +/* cmd_neonfun.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" + +#include "cmd_neonfun.h" +#include "../../modcmd.h" +#include "../../lang.h" +#include "../../ConfigParser.h" + +static const struct default_language_entry msgtab[] = { + {"NF_UNO_ALREADY_RUNNING", "There is already a UNO game running in %s."}, /* {ARGS: "#channel"} */ + {"NF_UNO_ALREADY_JOINED", "You have already joined this UNO game."}, + {"NF_UNO_USER_JOINED", "$b%s$b has joined the game."}, /* {ARGS: "TestUser"} */ + {"NF_UNO_CREATED", "$b%s$b started an UNO game. Type $b+uno$b to join the game."}, /* {ARGS: "TestUser"} */ + {"NF_UNO_ERROR", "UNO program error. Please contact a bot administrator. (ErrCode: %d)"}, /* {ARGS: 0} */ + {"NF_UNO_START", "GAME START"}, + {"NF_UNO_USER_HURRY_UP", "$b%s$b, it's your turn!"}, /* {ARGS: "TestUser"} */ + {"NF_UNO_USER_TOOK_CARD", "$b%s$b took another card."}, /* {ARGS: "TestUser"} */ + {"NF_UNO_USER_TOOK_CARDS", "$b%s$b took $b%d$b cards."}, /* {ARGS: "TestUser", 4} */ + {"NF_UNO_YOUR_CARDS", "Your cards: %s"}, /* {ARGS: "[+2] [+4] [R5] ..."} */ + {"NF_UNO_TOP_CARD", "upper card: %s"}, /* {ARGS: "[+4]"} */ + {"NF_UNO_NOT_YOUR_TURN", "Wait your turn!"}, + {"NF_UNO_UNKNOWN_CARD", "Unknown card [%s]."}, /* {ARGS: "xy"} */ + {"NF_UNO_CARD_NOT_IN_DECK", "You don't have this card."}, + {"NF_UNO_CARD_YELLOW", "yellow"}, + {"NF_UNO_CARD_BLUE", "blue"}, + {"NF_UNO_CARD_RED", "red"}, + {"NF_UNO_CARD_GREEN", "green"}, + {"NF_UNO_DEFINE_COLOR", "Please define the color you want to set as a parameter to the command (eg. $b+unoplay +4 RED$b)"}, + {"NF_UNO_CARD_NOT_POSSIBLE", "You can't play this card."}, + {"NF_UNO_ONE_CARD", "$b%s$b has only one card! $k4U$k$k9N$k$k12O$k"}, /* {ARGS: "TestUser"} */ + {"NF_UNO_USER_WIN", "$b%s$b has 0 cards! $k4U$k$k9N$k$k12O$k $k4U$k$k9N$k$k12O$k!!!"}, /* {ARGS: "TestUser"} */ + {"NF_UNO_TIMEOUT", "game stopped (no more active players)."}, + {"NF_UNO_USER_SKIP", "skipped $b%s$b."}, /* {ARGS: "TestUser"} */ + {"NF_UNO_GAME_FINISHED", "The UNO Game has been finished!"}, + {"NF_UNO_ADD_CARD", "$b%s$b has to take up %d cards. There is still the possibility that he/she has another card of this type...?"}, + {NULL, NULL} +}; + +void register_commands() { + //NeonFun Commands + register_default_language_table(msgtab); + register_command_alias(5, "NeonFun"); + + #define USER_COMMAND(NAME,FUNCTION,PARAMCOUNT,PRIVS,FLAGS) register_command(5, NAME, module_id, FUNCTION, PARAMCOUNT, PRIVS, 0, FLAGS) + // NAME FUNCTION PARAMS PRIVS FLAGS + USER_COMMAND("uno", neonfun_cmd_uno, 0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + USER_COMMAND("unotake", neonfun_cmd_unotake, 0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + USER_COMMAND("unoplay", neonfun_cmd_unoplay, 1, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + + #undef USER_COMMAND + +} + + diff --git a/src/modules/NeonFun.mod/cmd_neonfun.h b/src/modules/NeonFun.mod/cmd_neonfun.h new file mode 100644 index 0000000..a97da59 --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun.h @@ -0,0 +1,49 @@ +/* cmd_neonfun.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _cmd_neonfun_h +#define _cmd_neonfun_h +#include "../module.h" +#include "../../main.h" +#include "../../modcmd.h" +#include "../../IRCParser.h" +#include "../../IRCEvents.h" +#include "../../UserNode.h" +#include "../../ChanNode.h" +#include "../../ChanUser.h" +#include "../../ModeNode.h" +#include "../../BanNode.h" +#include "../../ClientSocket.h" +#include "../../mysqlConn.h" +#include "../../lang.h" +#include "../../HandleInfoHandler.h" +#include "../../WHOHandler.h" +#include "../../DBHelper.h" +#include "../../tools.h" +#include "../../timeq.h" +#include "../../version.h" +#include "../../EventLogger.h" +#include "../../bots.h" +#include "../../ConfigParser.h" +#include "bot_NeonFun.h" + +void register_commands(); + +CMD_BIND(neonfun_cmd_uno); +CMD_BIND(neonfun_cmd_unotake); +CMD_BIND(neonfun_cmd_unoplay); + +#endif diff --git a/src/modules/NeonFun.mod/cmd_neonfun_uno.c b/src/modules/NeonFun.mod/cmd_neonfun_uno.c new file mode 100644 index 0000000..47df483 --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_uno.c @@ -0,0 +1,80 @@ +/* cmd_neonfun_uno.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#include "cmd_neonfun.h" +#include "game_uno.h" + +CMD_BIND(neonfun_cmd_uno) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + if(chan == game->channel) { + if(game->state == UNO_STATE_WAITING) + break; + else { + reply(getTextBot(), user, "NF_UNO_ALREADY_RUNNING", chan->name); + return; + } + } + } + if(game) { + //check if player has already joined + struct uno_player *player, *last_player = NULL; + for(player = game->player; player; player = player->next) { + if(player->chanuser == chanuser) { + reply(getTextBot(), user, "NF_UNO_ALREADY_JOINED"); + return; + } else + last_player = player; + } + if(!last_player) return; //error (game without players?) + player = malloc(sizeof(*player)); + player->chanuser = chanuser; + player->count = 0; + player->cards = NULL; + player->prev = last_player; + player->next = NULL; + last_player->next = player; + game->players++; + uno_reply(game, user, "NF_UNO_USER_JOINED", user->nick); + } else { + game = malloc(sizeof(*game)); + game->channel = chan; + game->textbot = getTextBot(); + game->state = UNO_STATE_WAITING; + game->reverse_direction = 0; + game->take_cards_pending = 0; + game->deck = NULL; + game->top_card = NULL; + struct uno_player *player = malloc(sizeof(*player)); + player->chanuser = chanuser; + player->count = 0; + player->cards = NULL; + player->prev = NULL; + player->next = NULL; + game->player = player; + game->winner = NULL; + game->active_player = NULL; + game->players = 1; + game->active_player = 0; + game->timer = timeq_add(30, module_id, uno_game_wait_timeout, game); + game->next = uno_active_games; + uno_active_games = game; + uno_reply(game, user, "NF_UNO_CREATED", user->nick); + } +} diff --git a/src/modules/NeonFun.mod/cmd_neonfun_unoplay.c b/src/modules/NeonFun.mod/cmd_neonfun_unoplay.c new file mode 100644 index 0000000..a6b3419 --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_unoplay.c @@ -0,0 +1,68 @@ +/* cmd_neonfun_unoplay.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#include "cmd_neonfun.h" +#include "game_uno.h" + +CMD_BIND(neonfun_cmd_unoplay) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + if(chan == game->channel) { + if(game->state == UNO_STATE_WAITING) + return; + else + break; + } + } + if(game) { + //check if it's the player's turn + if(game->active_player->chanuser != chanuser) { + reply(getTextBot(), user, "NF_UNO_NOT_YOUR_TURN"); + return; + } + game->active_player->timeout = 0; + struct uno_card *card = uno_parse_card(game, game->active_player, argv[0]); + if(!card) return; + unsigned char new_color = card->color; + if(card->card == UNO_CARD_ADD_4 || card->card == UNO_CARD_COLOR) { + if(argc < 2) { + reply(game->textbot, user, "NF_UNO_DEFINE_COLOR"); + return; + } + if(!stricmp(argv[1], "RED") || !stricmp(argv[1], "R") || !stricmp(argv[1], get_language_string(user, "NF_UNO_CARD_RED"))) { + new_color = UNO_COLOR_RED; + } else if(!stricmp(argv[1], "BLUE") || !stricmp(argv[1], "B") || !stricmp(argv[1], get_language_string(user, "NF_UNO_CARD_BLUE"))) { + new_color = UNO_COLOR_BLUE; + } else if(!stricmp(argv[1], "GREEN") || !stricmp(argv[1], "G") || !stricmp(argv[1], get_language_string(user, "NF_UNO_CARD_GREEN"))) { + new_color = UNO_COLOR_GREEN; + } else if(!stricmp(argv[1], "YELLOW") || !stricmp(argv[1], "Y") || !stricmp(argv[1], get_language_string(user, "NF_UNO_CARD_YELLOW"))) { + new_color = UNO_COLOR_YELLOW; + } else { + reply(game->textbot, user, "NF_UNO_DEFINE_COLOR"); + return; + } + } + if(uno_check_card_valid(game, card)) { + reply(game->textbot, user, "NF_UNO_CARD_NOT_POSSIBLE"); + return; + } + card->color = new_color; + uno_play_card(game, game->active_player, card); + } +} diff --git a/src/modules/NeonFun.mod/cmd_neonfun_unotake.c b/src/modules/NeonFun.mod/cmd_neonfun_unotake.c new file mode 100644 index 0000000..22fb21c --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_unotake.c @@ -0,0 +1,42 @@ +/* cmd_neonfun_unotake.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ + +#include "cmd_neonfun.h" +#include "game_uno.h" + +CMD_BIND(neonfun_cmd_unotake) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + if(chan == game->channel) { + if(game->state == UNO_STATE_WAITING) + return; + else + break; + } + } + if(game) { + //check if it's the player's turn + if(game->active_player->chanuser != chanuser) { + reply(getTextBot(), user, "NF_UNO_NOT_YOUR_TURN"); + return; + } + game->active_player->timeout = 0; + uno_action_take_card(game, game->active_player); + } +} diff --git a/src/modules/NeonFun.mod/game_uno.c b/src/modules/NeonFun.mod/game_uno.c new file mode 100644 index 0000000..8ddd9c9 --- /dev/null +++ b/src/modules/NeonFun.mod/game_uno.c @@ -0,0 +1,657 @@ +/* game_uno.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "game_uno.h" +#include "bot_NeonFun.h" +#include "../../IRCParser.h" +#include "../../bots.h" +#include "../../UserNode.h" +#include "../../ChanUser.h" +#include "../../tools.h" +#include "../botid.h" + +struct uno_game *uno_active_games = NULL; + +#define UNO_COLOR_COUNT 4 +static int uno_colors[] = {UNO_COLOR_RED, UNO_COLOR_BLUE, UNO_COLOR_GREEN, UNO_COLOR_YELLOW}; +static int uno_irc_colors[] = {4, 12, 3, 7}; +static char *uno_color_chars[] = {"R", "B", "G", "Y"}; + +static const struct { + const char *name; + unsigned char type; +} uno_card_types[] = { + {"0", UNO_CARD_NUMBER_0}, + {"1", UNO_CARD_NUMBER_1}, + {"2", UNO_CARD_NUMBER_2}, + {"3", UNO_CARD_NUMBER_3}, + {"4", UNO_CARD_NUMBER_4}, + {"5", UNO_CARD_NUMBER_5}, + {"6", UNO_CARD_NUMBER_6}, + {"7", UNO_CARD_NUMBER_7}, + {"8", UNO_CARD_NUMBER_8}, + {"9", UNO_CARD_NUMBER_9}, + {"X", UNO_CARD_SKIP}, + {"><", UNO_CARD_DIRECTION}, + {"+2", UNO_CARD_ADD_2}, + {"+4", UNO_CARD_ADD_4}, + {"COLOR", UNO_CARD_COLOR}, + {NULL, 0} +}; + +struct uno_card_deck *uno_shuffle_deck() { + struct uno_card *card, *last_card = NULL; + int card_count = 0; + #define ADD_CARD(ccolor,ctype) \ + card = malloc(sizeof(*card)); \ + card->color = ccolor; \ + card->card = ctype; \ + card->prev = NULL; \ + card->next = last_card; \ + if(last_card) \ + last_card->prev = card; \ + last_card = card; \ + card_count++; + int colorcount = UNO_COLOR_COUNT; + for(colorcount--; colorcount >= 0; colorcount--) { + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_0); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_0); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_1); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_1); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_2); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_2); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_3); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_3); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_4); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_4); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_5); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_5); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_6); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_6); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_7); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_7); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_8); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_8); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_9); + ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_9); + ADD_CARD(uno_colors[colorcount], UNO_CARD_SKIP); + ADD_CARD(uno_colors[colorcount], UNO_CARD_SKIP); + ADD_CARD(uno_colors[colorcount], UNO_CARD_DIRECTION); + ADD_CARD(uno_colors[colorcount], UNO_CARD_DIRECTION); + ADD_CARD(uno_colors[colorcount], UNO_CARD_ADD_2); + ADD_CARD(uno_colors[colorcount], UNO_CARD_ADD_2); + } + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR); + ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR); + #undef ADD_CARD + struct uno_card_deck *deck = malloc(sizeof(*deck)); + deck->cards = last_card; + deck->count = card_count; + return deck; +} + +struct uno_card *uno_get_card(struct uno_card_deck *deck) { + if(!deck->count) return NULL; + int card_id = (rand() % deck->count); + int i = 0; + struct uno_card *card; + for(card = deck->cards; card; card = card->next) { + if(i == card_id) { + if(card->prev) + card->prev->next = card->next; + else + deck->cards = card->next; + if(card->next) + card->next->prev = card->prev; + deck->count--; + card->next = NULL; + card->prev = NULL; + return card; + } + i++; + } + return NULL; +} + +void uno_free_deck(struct uno_card_deck *deck) { + struct uno_card *card, *next_card; + if(deck->count) { + for(card = deck->cards; card; card = next_card) { + next_card = card->next; + free(card); + } + } +} + +void uno_free_player(struct uno_player *player, struct uno_card_deck *deck) { + if(player->count) { + struct uno_card *card, *next_card; + for(card = player->cards; card; card = next_card) { + next_card = card->next; + if(deck) { + card->next = deck->cards; + deck->cards->prev = card; + deck->cards = card; + deck->count++; + } else + free(card); + } + } + if(player->prev) + player->prev->next = player->next; + if(player->next) + player->next->prev = player->prev; + free(player); +} + +void uno_free_topcard(struct uno_card *card) { + struct uno_card *next_card; + for(; card; card = next_card) { + next_card = card->prev; + free(card); + } +} + +void uno_free_game(struct uno_game *game) { + struct uno_player *player, *next_player; + for(player = game->player; player; player = next_player) { + next_player = player->next; + uno_free_player(player, NULL); + } + for(player = game->winner; player; player = next_player) { + next_player = player->next; + uno_free_player(player, NULL); + } + if(game->deck) + uno_free_deck(game->deck); + if(game->top_card) + uno_free_topcard(game->top_card); + if(game->timer) + timeq_del(game->timer); + struct uno_game *cgame, *pgame = NULL; + for(cgame = uno_active_games; cgame; cgame = cgame->next) { + if(cgame == game) { + if(pgame) + pgame->next = game->next; + else + uno_active_games = game->next; + break; + } else + pgame = cgame; + } + free(game); +} + +struct uno_player *uno_get_next_player(struct uno_game *game) { + struct uno_player *player = game->active_player; + if(!game->reverse_direction) { + player = player->next; + if(!player) + player = game->player; + } else { + player = player->prev; + if(!player) { + for(player = game->player; player->next; player = player->next) { + //loop to the last player + } + } + } + return player; +} + +void uno_show_player_cards(struct uno_game *game, struct uno_player *player) { + struct uno_card *card; + char cards_buf[MAXLEN]; + int cards_bufpos = 0; + for(card = player->cards; card; card = card->next) { + int cardcolor = 1; + char *cardchar = ""; + int i; + for(i = 0; i < UNO_COLOR_COUNT; i++) { + if(uno_colors[i] == card->color) { + cardcolor = uno_irc_colors[i]; + cardchar = uno_color_chars[i]; + break; + } + } + i = 0; + while(uno_card_types[i].name) { + if(uno_card_types[i].type == card->card) { + cards_bufpos += sprintf(cards_buf + cards_bufpos, "%s[\003%d%s%s\003]", (cards_bufpos ? " " : ""), cardcolor, cardchar, uno_card_types[i].name); + break; + } + i++; + } + } + reply(game->textbot, player->chanuser->user, "NF_UNO_YOUR_CARDS", cards_buf); +} + +void uno_show_top_card(struct uno_game *game) { + struct uno_card *card = game->top_card; + char card_buf[50]; + int cardcolor = 1; + char *cardchar = ""; + int i; + for(i = 0; i < UNO_COLOR_COUNT; i++) { + if(uno_colors[i] == card->color) { + cardcolor = uno_irc_colors[i]; + cardchar = uno_color_chars[i]; + break; + } + } + i = 0; + while(uno_card_types[i].name) { + if(uno_card_types[i].type == card->card) { + if(card->card == UNO_CARD_ADD_4 || card->card == UNO_CARD_COLOR) + cardchar = ""; + sprintf(card_buf, "[\003%d%s%s\003]", cardcolor, cardchar, uno_card_types[i].name); + break; + } + i++; + } + uno_reply(game, NULL, "NF_UNO_TOP_CARD", card_buf); +} + +TIMEQ_CALLBACK(uno_game_wait_timeout) { + struct uno_game *game = data; + game->timer = NULL; + if(game->players == 1) { + //TEXT: too less users + uno_free_game(game); + return; + } + game->deck = uno_shuffle_deck(); + uno_reply(game, NULL, "NF_UNO_START"); + struct uno_player *player; + for(player = game->player; player; player = player->next) { + //give 7 cards + int i; + for(i = 0; i < 7; i++) { + if(!game->deck->count) + game->deck = uno_shuffle_deck(); + struct uno_card *card = uno_get_card(game->deck); + if(!card) { + uno_reply(game, NULL, "NF_UNO_ERROR", 1); + uno_free_game(game); + return; + } + card->next = player->cards; + if(player->cards) + player->cards->prev = card; + player->cards = card; + player->count++; + } + uno_show_player_cards(game, player); + if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) { + char *tmp; + int game_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_games")) ? atoi(tmp) : 0); + int total_game_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_games")) ? atoi(tmp) : 0); + game_count++; + total_game_count++; + char buf[10]; + sprintf(buf, "%d", game_count); + setSetting(player->chanuser->user, game->channel, "uno_games", buf); + sprintf(buf, "%d", total_game_count); + setSetting(player->chanuser->user, NULL, "uno_games", buf); + } + } + if(!game->deck->count) + game->deck = uno_shuffle_deck(); + struct uno_card *card = uno_get_card(game->deck); + if(!card) { + uno_reply(game, NULL, "NF_UNO_ERROR", 1); + uno_free_game(game); + return; + } + game->top_card = card; + game->state = UNO_STATE_RUNNING; + uno_show_top_card(game); + game->active_player = game->player; //active player + uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick); + game->timer = timeq_add(30, module_id, uno_player_timeout, game); +} + +TIMEQ_CALLBACK(uno_player_timeout) { + struct uno_game *game = data; + game->timer = NULL; + //player timeout (take another card) + struct uno_player *player = game->active_player, *next_player = uno_get_next_player(game); + //add a card to the players deck + if(!game->deck->count) + game->deck = uno_shuffle_deck(); + struct uno_card *card = uno_get_card(game->deck); + if(!card) { + uno_reply(game, NULL, "NF_UNO_ERROR", 2); + uno_free_game(game); + return; + } + card->next = player->cards; + if(player->cards) + player->cards->prev = card; + player->cards = card; + player->count++; + player->timeout = 1; + game->active_player = next_player; + uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick); + struct uno_player *cplayer; + for(cplayer = game->player; cplayer; cplayer = cplayer->next) { + if(!cplayer->timeout) + break; + } + if(!cplayer) { + uno_reply(game, NULL, "NF_UNO_TIMEOUT"); + uno_free_game(game); + return; + } + uno_show_player_cards(game, player); + uno_show_top_card(game); + uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick); + uno_show_player_cards(game, game->active_player); + game->timer = timeq_add(30, module_id, uno_player_timeout, game); +} + +void uno_action_take_card(struct uno_game *game, struct uno_player *player) { + timeq_del(game->timer); + game->timer = NULL; + struct uno_player *next_player = uno_get_next_player(game); + //add a card to the players deck + int ccount; + if(game->take_cards_pending) { + //count cards to take + struct uno_card *card; + ccount = 0; + for(card = game->top_card; card; card = card->prev) { + if(card->card == UNO_CARD_ADD_2) + ccount += 2; + else if(card->card == UNO_CARD_ADD_4) + ccount += 4; + } + } else + ccount = 1; + int i; + for(i = 0; i < ccount; i++) { + if(!game->deck->count) + game->deck = uno_shuffle_deck(game->deck); + struct uno_card *card = uno_get_card(game->deck); + if(!card) { + uno_reply(game, NULL, "NF_UNO_ERROR", 2); + uno_free_game(game); + return; + } + card->next = player->cards; + if(player->cards) + player->cards->prev = card; + player->cards = card; + player->count++; + } + game->active_player = next_player; + if(game->take_cards_pending) { + game->take_cards_pending = 0; + uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARDS", player->chanuser->user->nick, ccount); + } else + uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick); + uno_show_player_cards(game, player); + uno_show_top_card(game); + uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick); + uno_show_player_cards(game, game->active_player); + game->timer = timeq_add(30, module_id, uno_player_timeout, game); +} + + + +struct uno_card *uno_parse_card(struct uno_game *game, struct uno_player *player, char *arg1) { + char *b = arg1; + int a = 0; + while(*b) { + switch (*b) { + case '\003': + if(isdigit(b[1])) + b[1] = '\002'; + if(isdigit(b[2])) + b[2] = '\002'; + case '[': + case '\002': + case ']': + *b = '\0'; + break; + default: + if(!a) { + a = 1; + arg1 = b; + } + } + b++; + } + unsigned char ctype = 255, ccolor = 0; + int i = 0, j; + char tmpbuf[50]; + while(uno_card_types[i].name) { + if(!stricmp(uno_card_types[i].name, arg1)) { + ctype = uno_card_types[i].type; + break; + } + for(j = 0; j < UNO_COLOR_COUNT; j++) { + sprintf(tmpbuf, "%s%s", uno_color_chars[j], uno_card_types[i].name); + if(!stricmp(tmpbuf, arg1)) { + ccolor = uno_colors[j]; + ctype = uno_card_types[i].type; + break; + } + } + i++; + } + if(ctype == 255) { + reply(game->textbot, player->chanuser->user, "NF_UNO_UNKNOWN_CARD", arg1); + return NULL; + } + struct uno_card *card; + for(card = player->cards; card; card = card->next) { + if(card->card == ctype && card->color == ccolor) + break; + } + if(!card) { + reply(game->textbot, player->chanuser->user, "NF_UNO_CARD_NOT_IN_DECK"); + return NULL; + } + return card; +} + +int uno_check_card_valid(struct uno_game *game, struct uno_card *card) { + if(game->take_cards_pending && card->card != game->top_card->card) + return 1; + if(card->color == UNO_COLOR_BLACK) + return 0; + if(card->color != game->top_card->color && card->card != game->top_card->card) + return 1; + return 0; +} + +void uno_play_card(struct uno_game *game, struct uno_player *player, struct uno_card *card) { + timeq_del(game->timer); + game->timer = NULL; + if(card->prev) + card->prev->next = card->next; + else + player->cards = card->next; + if(card->next) + card->next->prev = card->prev; + player->count--; + if(!game->take_cards_pending) { + uno_free_topcard(game->top_card); + card->prev = NULL; + } else + card->prev = game->top_card; + card->next = NULL; + game->top_card = card; + uno_show_top_card(game); + if(player->count == 1) { + uno_reply(game, NULL, "NF_UNO_ONE_CARD", game->active_player->chanuser->user->nick); + } else if(player->count == 0) { + uno_reply(game, NULL, "NF_UNO_USER_WIN", game->active_player->chanuser->user->nick); + if(player->prev) + player->prev->next = player->next; + if(player->next) + player->next->prev = player->prev; + player->next = NULL; + player->prev = NULL; + struct uno_player *cplayer; + int winner_count = 0; + if(game->winner) { + for(cplayer = game->winner; cplayer->next; cplayer = cplayer->next) { + winner_count++; + } + } else + cplayer = NULL; + if(cplayer) { + cplayer->next = player; + } else { + game->winner = player; + if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) { + char *tmp; + int win_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0); + int total_win_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0); + win_count++; + total_win_count++; + char buf[10]; + sprintf(buf, "%d", win_count); + setSetting(player->chanuser->user, game->channel, "uno_win", buf); + sprintf(buf, "%d", total_win_count); + setSetting(player->chanuser->user, NULL, "uno_win", buf); + } + } + player->prev = cplayer; + game->players--; + if(game->players <= 1) { + //game finished + uno_reply(game, NULL, "NF_UNO_GAME_FINISHED"); + struct Table *table; + table = table_init(4, winner_count + 3, 0); + char *content[4]; + content[0] = get_language_string(NULL, "NF_UNO_RANK"); + content[1] = get_language_string(NULL, "NF_UNO_NAME"); + content[2] = get_language_string(NULL, "NF_UNO_WON_GAMES"); + content[3] = get_language_string(NULL, "NF_UNO_TOTAL_WON_GAMES"); + table_add(table, content); + winner_count = 1; + char rank_buf[20], won_buf[50], total_won_buf[50]; + char *tmp, *tmp2; + for(cplayer = game->winner; cplayer->next; cplayer = cplayer->next) { + sprintf(rank_buf, "%d", winner_count++); + content[0] = rank_buf; + content[1] = cplayer->chanuser->user->nick; + if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) { + sprintf(won_buf, "%d/%d", ((tmp = getSetting(cplayer->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0), ((tmp2 = getSetting(cplayer->chanuser->user, game->channel, "uno_games")) ? atoi(tmp2) : 0)); + content[2] = won_buf; + sprintf(total_won_buf, "%d/%d", ((tmp = getSetting(cplayer->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0), ((tmp2 = getSetting(cplayer->chanuser->user, NULL, "uno_games")) ? atoi(tmp2) : 0)); + content[3] = total_won_buf; + } else { + content[2] = "?"; + content[3] = "?"; + } + table_add(table, content); + } + cplayer = game->player; + sprintf(rank_buf, "%d", winner_count++); + content[0] = rank_buf; + content[1] = cplayer->chanuser->user->nick; + if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) { + sprintf(won_buf, "%d/%d", ((tmp = getSetting(cplayer->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0), ((tmp2 = getSetting(cplayer->chanuser->user, game->channel, "uno_games")) ? atoi(tmp2) : 0)); + content[2] = won_buf; + sprintf(total_won_buf, "%d/%d", ((tmp = getSetting(cplayer->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0), ((tmp2 = getSetting(cplayer->chanuser->user, NULL, "uno_games")) ? atoi(tmp2) : 0)); + content[3] = total_won_buf; + } else { + content[2] = "?"; + content[3] = "?"; + } + table_add(table, content); + char **table_lines = table_end(table); + int i; + for(i = 0; i < table->entrys; i++) { + uno_reply(game, NULL, table_lines[i]); + } + table_free(table); + uno_free_game(game); + return; + } + } + if(card->card == UNO_CARD_DIRECTION) + game->reverse_direction = (game->reverse_direction ? 0 : 1); + struct uno_player *next_player = uno_get_next_player(game); + game->active_player = next_player; + if(card->card == UNO_CARD_SKIP) { + uno_reply(game, NULL, "NF_UNO_USER_SKIP", game->active_player->chanuser->user->nick); + next_player = uno_get_next_player(game); + game->active_player = next_player; + } + if(card->card == UNO_CARD_ADD_2 || card->card == UNO_CARD_ADD_4) { + int ccount = 0; + for(card = game->top_card; card; card = card->prev) { + if(card->card == UNO_CARD_ADD_2) + ccount += 2; + else if(card->card == UNO_CARD_ADD_4) + ccount += 4; + } + uno_reply(game, NULL, "NF_UNO_ADD_CARD", game->active_player->chanuser->user->nick, ccount); + game->take_cards_pending = 1; + } + uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick); + uno_show_player_cards(game, game->active_player); + game->timer = timeq_add(30, module_id, uno_player_timeout, game); +} + +void uno_event_part(struct ChanUser *chanuser) { + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + if(chanuser->chan == game->channel) { + struct uno_player *player; + for(player = game->player; player; player = player->next) { + if(player->chanuser == chanuser) { + uno_free_player(player, game->deck); + return; + } + } + } + } +} + +void uno_event_quit(struct UserNode *user) { + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + struct uno_player *player; + for(player = game->player; player; player = player->next) { + if(player->chanuser->user == user) { + uno_free_player(player, game->deck); + break; + } + } + } +} + +void uno_event_freechan(struct ChanNode *chan) { + struct uno_game *game; + for(game = uno_active_games; game; game = game->next) { + if(game->channel == chan) { + uno_free_game(game); + } + } +} diff --git a/src/modules/NeonFun.mod/game_uno.h b/src/modules/NeonFun.mod/game_uno.h new file mode 100644 index 0000000..356fc00 --- /dev/null +++ b/src/modules/NeonFun.mod/game_uno.h @@ -0,0 +1,112 @@ +/* game_uno.h - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#ifndef _game_uno_h +#define _game_uno_h +#include "../../timeq.h" + +#define UNO_STATE_WAITING 1 +#define UNO_STATE_RUNNING 2 + +#define UNO_COLOR_BLACK 0 +#define UNO_COLOR_RED 1 +#define UNO_COLOR_BLUE 2 +#define UNO_COLOR_GREEN 3 +#define UNO_COLOR_YELLOW 4 + +#define UNO_CARD_NUMBER_0 0 +#define UNO_CARD_NUMBER_1 1 +#define UNO_CARD_NUMBER_2 2 +#define UNO_CARD_NUMBER_3 3 +#define UNO_CARD_NUMBER_4 4 +#define UNO_CARD_NUMBER_5 5 +#define UNO_CARD_NUMBER_6 6 +#define UNO_CARD_NUMBER_7 7 +#define UNO_CARD_NUMBER_8 8 +#define UNO_CARD_NUMBER_9 9 +#define UNO_CARD_SKIP 10 +#define UNO_CARD_DIRECTION 11 +#define UNO_CARD_ADD_2 12 +#define UNO_CARD_ADD_4 13 +#define UNO_CARD_COLOR 14 + +#define UNO_IS_NUMBER_CARD(ccard) (ccard->card <= 9) + +struct UserNode; +struct ChanNode; +struct ChanUser; +struct ClientSocket; +extern struct uno_game *uno_active_games; + +struct uno_card { + unsigned char color; + unsigned char card; + struct uno_card *prev, *next; +}; + +struct uno_card_deck { + struct uno_card *cards; + int count; +}; + +struct uno_player { + struct ChanUser *chanuser; + struct uno_card *cards; + int count; + int timeout; + struct uno_player *prev, *next; +}; + +struct uno_game { + struct ChanNode *channel; + struct ClientSocket *textbot; + int state : 3; + int reverse_direction : 1; + int take_cards_pending : 1; + struct uno_card_deck *deck; + struct uno_card *top_card; + struct uno_player *player; + struct uno_player *winner; + struct uno_player *active_player; + int players; + + struct timeq_entry *timer; + struct uno_game *next; +}; + +struct uno_card_deck *uno_shuffle_deck(); +struct uno_card *uno_get_card(struct uno_card_deck *deck); +void uno_free_deck(struct uno_card_deck *deck); +void uno_free_player(struct uno_player *player, struct uno_card_deck *deck); +void uno_free_topcard(struct uno_card *card); +void uno_free_game(struct uno_game *game); +struct uno_player *uno_get_next_player(struct uno_game *game); +void uno_show_player_cards(struct uno_game *game, struct uno_player *player); +void uno_show_top_card(struct uno_game *game); + +TIMEQ_CALLBACK(uno_game_wait_timeout); +TIMEQ_CALLBACK(uno_player_timeout); + +void uno_action_take_card(struct uno_game *game, struct uno_player *player); +struct uno_card *uno_parse_card(struct uno_game *game, struct uno_player *player, char *arg1); +int uno_check_card_valid(struct uno_game *game, struct uno_card *card); +void uno_play_card(struct uno_game *game, struct uno_player *player, struct uno_card *card); + +void uno_event_part(struct ChanUser *chanuser); +void uno_event_quit(struct UserNode *user); +void uno_event_freechan(struct ChanNode *chan); + +#endif diff --git a/src/modules/NeonFun.mod/module.c b/src/modules/NeonFun.mod/module.c new file mode 100644 index 0000000..7a35ecb --- /dev/null +++ b/src/modules/NeonFun.mod/module.c @@ -0,0 +1,39 @@ +/* module.c - NeonServ v5.4 + * Copyright (C) 2011-2012 Philipp Kreil (pk910) + * + * 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 3 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, see . + */ +#include "../module.h" +#include "bot_NeonFun.h" +#include "cmd_neonfun.h" + +static int module_initialize() { + register_commands(); + return 0; +} + +static void module_start(int type) { + init_NeonFun(type); + srand(time(NULL)); +} + +static void module_loop() { + loop_NeonFun(); +} + +static void module_stop(int type) { + free_NeonFun(type); +} + +MODULE_HEADER(module_initialize, module_start, module_loop, module_stop); diff --git a/src/modules/botid.h b/src/modules/botid.h index 0abb44a..b0209fa 100644 --- a/src/modules/botid.h +++ b/src/modules/botid.h @@ -21,5 +21,6 @@ #define NEONSPAM_BOTID 2 #define DUMMYSERV_BOTID 3 #define NEONHELP_BOTID 4 +#define NEONFUN_BOTID 5 #endif \ No newline at end of file diff --git a/src/modules/global.mod/cmd_global_setbot.c b/src/modules/global.mod/cmd_global_setbot.c index 212ffa4..8b58b72 100644 --- a/src/modules/global.mod/cmd_global_setbot.c +++ b/src/modules/global.mod/cmd_global_setbot.c @@ -469,7 +469,7 @@ static int global_cmd_setbot_prefered(struct UserNode *user, MYSQL_ROW bot, char break; } } - printf_mysql_query("UPDATE `bots` SET `prefered` = '%d' WHERE `id` = '%s'", val, bot[15]); + printf_mysql_query("UPDATE `bots` SET `textbot` = '%d' WHERE `id` = '%s'", val, bot[15]); ret = 1; } reply(getTextBot(), user, "\002PREFERED \002 %s", get_language_string(user, (val ? "NS_SET_ON" : "NS_SET_OFF"))); -- 2.20.1