From 9f992f346db24a642e3fe5362ae377ebe9002aa7 Mon Sep 17 00:00:00 2001 From: pk910 Date: Mon, 12 Nov 2012 03:08:09 +0100 Subject: [PATCH] added blackjack game --- Makefile.am | 4 + src/modules/NeonFun.mod/bot_NeonFun.c | 24 + src/modules/NeonFun.mod/bot_NeonFun.h | 2 + src/modules/NeonFun.mod/cmd_neonfun.c | 25 +- src/modules/NeonFun.mod/cmd_neonfun.h | 4 + .../NeonFun.mod/cmd_neonfun_bjenough.c | 41 ++ src/modules/NeonFun.mod/cmd_neonfun_bjtake.c | 41 ++ .../NeonFun.mod/cmd_neonfun_blackjack.c | 69 +++ src/modules/NeonFun.mod/cmd_neonfun_uno.c | 2 +- src/modules/NeonFun.mod/game_blackjack.c | 419 ++++++++++++++++++ src/modules/NeonFun.mod/game_blackjack.h | 102 +++++ 11 files changed, 731 insertions(+), 2 deletions(-) create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_bjenough.c create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_bjtake.c create mode 100644 src/modules/NeonFun.mod/cmd_neonfun_blackjack.c create mode 100644 src/modules/NeonFun.mod/game_blackjack.c create mode 100644 src/modules/NeonFun.mod/game_blackjack.h diff --git a/Makefile.am b/Makefile.am index 6299256..b03b830 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,6 +168,10 @@ libNeonFun_la_SOURCES = src/modules/NeonFun.mod/bot_NeonFun.c \ src/modules/NeonFun.mod/cmd_neonfun_4stone.c \ src/modules/NeonFun.mod/cmd_neonfun_4view.c \ src/modules/NeonFun.mod/game_4wins.c \ + src/modules/NeonFun.mod/cmd_neonfun_blackjack.c \ + src/modules/NeonFun.mod/cmd_neonfun_bjtake.c \ + src/modules/NeonFun.mod/cmd_neonfun_bjenough.c \ + src/modules/NeonFun.mod/game_blackjack.c \ src/modules/NeonFun.mod/module.c libNeonFun_la_LDFLAGS = -module -rpath /nowhere -avoid-version -no-undefined libNeonFun_la_LIBADD = $(MYSQL_LIBS) diff --git a/src/modules/NeonFun.mod/bot_NeonFun.c b/src/modules/NeonFun.mod/bot_NeonFun.c index ab78474..44df0c3 100644 --- a/src/modules/NeonFun.mod/bot_NeonFun.c +++ b/src/modules/NeonFun.mod/bot_NeonFun.c @@ -39,6 +39,7 @@ #include "../../bots.h" #include "game_uno.h" #include "game_4wins.h" +#include "game_blackjack.h" #define BOTID NEONFUN_BOTID #define BOTALIAS "NeonFun" @@ -132,11 +133,13 @@ static void start_bots(int type) { static void neonfun_parted(struct ChanUser *chanuser, int quit, char *reason) { uno_event_part(chanuser); fourwins_event_part(chanuser); + bj_event_part(chanuser); } static int neonfun_freechan(struct ChanNode *chan) { uno_event_freechan(chan); fourwins_event_freechan(chan); + bj_event_freechan(chan); return 0; } @@ -301,5 +304,26 @@ void fourwins_reply(struct fourwins_game *game, const char *text, ...) { } } +void bj_reply(struct bj_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 :[BJ] %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 index 291c456..a2a9ea4 100644 --- a/src/modules/NeonFun.mod/bot_NeonFun.h +++ b/src/modules/NeonFun.mod/bot_NeonFun.h @@ -24,6 +24,7 @@ void free_NeonFun(int type); struct uno_game; struct fourwins_game; +struct bj_game; struct ChanNode; struct UserNode; @@ -31,5 +32,6 @@ char* getSetting(struct UserNode *user, struct ChanNode *chan, const char *setti 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, ...); void fourwins_reply(struct fourwins_game *game, const char *text, ...); +void bj_reply(struct bj_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 index cb4e784..1fd1199 100644 --- a/src/modules/NeonFun.mod/cmd_neonfun.c +++ b/src/modules/NeonFun.mod/cmd_neonfun.c @@ -61,7 +61,7 @@ static const struct default_language_entry msgtab[] = { {"NF_4WINS_USER_WON", "$b%s$b won the game!"}, /* {ARGS: "TestUser"} */ {"NF_4WINS_ENTER_OPPONENT", "Please enter the nick of the opponent you want to play against as a parameter of 4wins (eg. $b4wins TestUser$b)"}, {"NF_4WINS_OPPONENT_NOT_IN_CHAN", "$b%s$b needs to be in this channel to start a game against him/her."}, /* {ARGS: "TestUser"} */ - {"NF_4WINS_DRAW", "Noone has won this game."}, + {"NF_4WINS_DRAW", "Nobody has won this game."}, {"NF_4WINS_REQUEST", "$b%s$b wants to play a game against you. use $b4wins$b to start the game."}, /* {ARGS: "TestUser"} */ {"NF_4WINS_REQUESTED", "waiting for $b%s$b accepting the game..."}, /* {ARGS: "TestUser"} */ {"NF_4WINS_START", "%s accepted the challenge! game starts:"}, /* {ARGS: "TestUser"} */ @@ -72,6 +72,25 @@ static const struct default_language_entry msgtab[] = { {"NF_4WINS_GAME_CLOSED", "Game aborted."}, {"NF_4WINS_TIMEOUT", "Game aborted (timeout)."}, {"NF_4WINS_SELF", "You may not play against yourself."}, + + {"NF_BJ_ALREADY_RUNNING", "There is already a BlackJack game running in %s."}, /* {ARGS: "#channel"} */ + {"NF_BJ_ALREADY_JOINED", "You have already joined this BlackJack game."}, + {"NF_BJ_USER_JOINED", "$b%s$b has joined the game."}, /* {ARGS: "TestUser"} */ + {"NF_BJ_CREATED", "$b%s$b started a BlackJack game. Type $b+bj$b to join the game."}, /* {ARGS: "TestUser"} */ + {"NF_BJ_ERROR", "BlackJack program error. Please contact a bot administrator. (ErrCode: %d)"}, /* {ARGS: 0} */ + {"NF_BJ_START", "GAME START"}, + {"NF_BJ_USER_HURRY_UP", "$b%s$b, it's your turn! You can take a card with $bbjtake$b or stop playing with $bbjenough$b"}, /* {ARGS: "TestUser"} */ + {"NF_BJ_TAKE", "You took another card: %s (%d points)."}, /* {ARGS: "[♠A]", 11} */ + {"NF_BJ_YOUR_CARDS", "You have %d points! Your cards: %s"}, /* {ARGS: 18, "[♠A] [♣7] ..."} */ + {"NF_BJ_LESS_PLAYERS", "There are not enough players to start the game."}, + {"NF_BJ_USER_TIMEOUT", "It seems that %s doesn't want another card... (Timeout)"}, /* {ARGS: "TestUser"} */ + {"NF_BJ_POINTS_EXCEEDED", "You have more than 21 points... please use $bbjenough$b to finish."}, + {"NF_BJ_GAME_FINISHED", "Game Finished! Showdown:"}, + {"NF_BJ_RANK", "Rank"}, + {"NF_BJ_NAME", "Name"}, + {"NF_BJ_POINTS", "Points"}, + {"NF_BJ_CARDS", "Cards"}, + {NULL, NULL} }; @@ -90,6 +109,10 @@ void register_commands() { USER_COMMAND("4stone", neonfun_cmd_4stone, 1, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); USER_COMMAND("4view", neonfun_cmd_4view, 0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + USER_COMMAND("blackjack", neonfun_cmd_blackjack,0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + USER_COMMAND("bjtake", neonfun_cmd_bjtake, 0, NULL, CMDFLAG_REQUIRE_CHAN | CMDFLAG_REGISTERED_CHAN); + USER_COMMAND("bjenough", neonfun_cmd_bjenough, 0, 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 index 4537bb1..fdccf0f 100644 --- a/src/modules/NeonFun.mod/cmd_neonfun.h +++ b/src/modules/NeonFun.mod/cmd_neonfun.h @@ -50,4 +50,8 @@ CMD_BIND(neonfun_cmd_4wins); CMD_BIND(neonfun_cmd_4stone); CMD_BIND(neonfun_cmd_4view); +CMD_BIND(neonfun_cmd_blackjack); +CMD_BIND(neonfun_cmd_bjtake); +CMD_BIND(neonfun_cmd_bjenough); + #endif diff --git a/src/modules/NeonFun.mod/cmd_neonfun_bjenough.c b/src/modules/NeonFun.mod/cmd_neonfun_bjenough.c new file mode 100644 index 0000000..da1ff9b --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_bjenough.c @@ -0,0 +1,41 @@ +/* cmd_neonfun_bjenough.c - NeonServ v5.6 + * 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_blackjack.h" + +CMD_BIND(neonfun_cmd_bjenough) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct bj_game *game; + for(game = bj_active_games; game; game = game->next) { + if(chan == game->channel) { + if(game->state == BJ_STATE_WAITING) + return; + else + break; + } + } + if(game) { + //check if it's the player's turn + if(game->active_player->chanuser != chanuser) { + reply(textclient, user, "NF_BJ_NOT_YOUR_TURN"); + return; + } + bj_action_next_player(game, game->active_player); + } +} diff --git a/src/modules/NeonFun.mod/cmd_neonfun_bjtake.c b/src/modules/NeonFun.mod/cmd_neonfun_bjtake.c new file mode 100644 index 0000000..91b3f09 --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_bjtake.c @@ -0,0 +1,41 @@ +/* cmd_neonfun_bjtake.c - NeonServ v5.6 + * 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_blackjack.h" + +CMD_BIND(neonfun_cmd_bjtake) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct bj_game *game; + for(game = bj_active_games; game; game = game->next) { + if(chan == game->channel) { + if(game->state == BJ_STATE_WAITING) + return; + else + break; + } + } + if(game) { + //check if it's the player's turn + if(game->active_player->chanuser != chanuser) { + reply(textclient, user, "NF_BJ_NOT_YOUR_TURN"); + return; + } + bj_action_take_card(game, game->active_player); + } +} diff --git a/src/modules/NeonFun.mod/cmd_neonfun_blackjack.c b/src/modules/NeonFun.mod/cmd_neonfun_blackjack.c new file mode 100644 index 0000000..31fe45c --- /dev/null +++ b/src/modules/NeonFun.mod/cmd_neonfun_blackjack.c @@ -0,0 +1,69 @@ +/* cmd_neonfun_blackjack.c - NeonServ v5.6 + * 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_blackjack.h" + +CMD_BIND(neonfun_cmd_blackjack) { + struct ChanUser *chanuser = getChanUser(user, chan); + if(!chanuser) return; + struct bj_game *game; + for(game = bj_active_games; game; game = game->next) { + if(chan == game->channel) + break; + } + if(game) { + //check if player has already joined + struct bj_player *player, *last_player = NULL; + for(player = game->player; player; player = player->next) { + if(player->chanuser == chanuser) { + reply(textclient, user, "NF_BJ_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++; + bj_reply(game, user, "NF_BJ_USER_JOINED", user->nick); + } else { + game = malloc(sizeof(*game)); + game->channel = chan; + game->textbot = textclient; + game->state = BJ_STATE_WAITING; + game->deck = NULL; + struct bj_player *player = malloc(sizeof(*player)); + player->chanuser = chanuser; + player->count = 0; + player->cards = NULL; + player->prev = NULL; + player->next = NULL; + game->player = player; + game->active_player = NULL; + game->players = 1; + game->timer = timeq_add(30, module_id, bj_game_wait_timeout, game); + game->next = bj_active_games; + bj_active_games = game; + bj_reply(game, user, "NF_BJ_CREATED", user->nick); + } +} diff --git a/src/modules/NeonFun.mod/cmd_neonfun_uno.c b/src/modules/NeonFun.mod/cmd_neonfun_uno.c index 09a5267..5742fa0 100644 --- a/src/modules/NeonFun.mod/cmd_neonfun_uno.c +++ b/src/modules/NeonFun.mod/cmd_neonfun_uno.c @@ -66,13 +66,13 @@ CMD_BIND(neonfun_cmd_uno) { player->chanuser = chanuser; player->count = 0; player->cards = NULL; + player->timeout = 0; 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; diff --git a/src/modules/NeonFun.mod/game_blackjack.c b/src/modules/NeonFun.mod/game_blackjack.c new file mode 100644 index 0000000..6c69934 --- /dev/null +++ b/src/modules/NeonFun.mod/game_blackjack.c @@ -0,0 +1,419 @@ +/* game_blackjack.c - NeonServ v5.6 + * 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_blackjack.h" +#include "bot_NeonFun.h" +#include "../../IRCParser.h" +#include "../../bots.h" +#include "../../UserNode.h" +#include "../../ChanUser.h" +#include "../../tools.h" +#include "../botid.h" + +struct bj_game *bj_active_games = NULL; + +static int bj_ctype[] = {BJ_CTYPE_HEARTS, BJ_CTYPE_SPADES, BJ_CTYPE_DIAMONDS, BJ_CTYPE_CLUBS}; +static int bj_irc_colors[] = {4, 1, 4, 1}; +static char *bj_color_chars[] = {"\xE2\x9D\xA4", "\xE2\x99\xA0", "\xE2\x99\xA6", "\xE2\x99\xA3"}; + +static const struct { + const char *name; + unsigned char type; + unsigned int points : 8; +} bj_card_types[] = { + {"2", BJ_CARD_NUMBER_2, 2}, + {"3", BJ_CARD_NUMBER_3, 3}, + {"4", BJ_CARD_NUMBER_4, 4}, + {"5", BJ_CARD_NUMBER_5, 5}, + {"6", BJ_CARD_NUMBER_6, 6}, + {"7", BJ_CARD_NUMBER_7, 7}, + {"8", BJ_CARD_NUMBER_8, 8}, + {"9", BJ_CARD_NUMBER_9, 9}, + {"10", BJ_CARD_NUMBER_10, 10}, + {"J", BJ_CARD_JACK, 10}, + {"Q", BJ_CARD_QUEEN, 10}, + {"K", BJ_CARD_KING, 10}, + {"A", BJ_CARD_ACE, 11}, + {NULL, 0} +}; + +struct bj_card_deck *bj_shuffle_deck() { + struct bj_card *card, *last_card = NULL; + int card_count = 0; + #define ADD_CARD(ctype,ccard) \ + card = malloc(sizeof(*card)); \ + card->type = ctype; \ + card->card = ccard; \ + card->prev = NULL; \ + card->next = last_card; \ + if(last_card) \ + last_card->prev = card; \ + last_card = card; \ + card_count++; + int typecount = BJ_CTYPE_COUNT; + for(typecount--; typecount >= 0; typecount--) { + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_2); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_3); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_4); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_5); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_6); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_7); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_8); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_9); + ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_10); + ADD_CARD(bj_ctype[typecount], BJ_CARD_JACK); + ADD_CARD(bj_ctype[typecount], BJ_CARD_QUEEN); + ADD_CARD(bj_ctype[typecount], BJ_CARD_KING); + ADD_CARD(bj_ctype[typecount], BJ_CARD_ACE); + } + #undef ADD_CARD + struct bj_card_deck *deck = malloc(sizeof(*deck)); + deck->cards = last_card; + deck->count = card_count; + return deck; +} + +struct bj_card *bj_get_card(struct bj_card_deck *deck) { + if(!deck->count) return NULL; + int card_id = (rand() % deck->count); + int i = 0; + struct bj_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 bj_free_deck(struct bj_card_deck *deck) { + struct bj_card *card, *next_card; + if(deck->count) { + for(card = deck->cards; card; card = next_card) { + next_card = card->next; + free(card); + } + } + free(deck); +} + +void bj_free_player(struct bj_player *player, struct bj_card_deck *deck) { + if(player->count) { + struct bj_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 bj_free_game(struct bj_game *game) { + struct bj_player *player, *next_player; + for(player = game->player; player; player = next_player) { + next_player = player->next; + bj_free_player(player, NULL); + } + if(game->deck) + bj_free_deck(game->deck); + if(game->timer) + timeq_del(game->timer); + struct bj_game *cgame, *pgame = NULL; + for(cgame = bj_active_games; cgame; cgame = cgame->next) { + if(cgame == game) { + if(pgame) + pgame->next = game->next; + else + bj_active_games = game->next; + break; + } else + pgame = cgame; + } + free(game); +} + +struct bj_player *bj_get_next_player(struct bj_game *game) { + struct bj_player *player = game->active_player; + player = player->next; + return player; +} + +int bj_get_player_card_points(struct bj_player *player) { + int i, points = 0, ace_count = 0; + struct bj_card *card; + for(card = player->cards; card; card = card->next) { + if(card->card == BJ_CARD_ACE) { + ace_count++; //add these points later ;) + continue; + } + i = 0; + while(bj_card_types[i].name) { + if(bj_card_types[i].type == card->card) { + points += bj_card_types[i].points; + break; + } + i++; + } + } + while((ace_count--) > 0) { + if(points <= 10) + points += 11; + else + points += 1; + } + return points; +} + +static void bj_print_player_cards(struct bj_player *player, char *cards_buf) { + struct bj_card *card; + int cards_bufpos = 0; + for(card = player->cards; card; card = card->next) { + int cardcolor = 1; + char *cardchar = ""; + int i; + for(i = 0; i < BJ_CTYPE_COUNT; i++) { + if(bj_ctype[i] == card->type) { + cardcolor = bj_irc_colors[i]; + cardchar = bj_color_chars[i]; + break; + } + } + i = 0; + while(bj_card_types[i].name) { + if(bj_card_types[i].type == card->card) { + cards_bufpos += sprintf(cards_buf + cards_bufpos, "%s[\003%d%s%s\003]", (cards_bufpos ? " " : ""), cardcolor, cardchar, bj_card_types[i].name); + break; + } + i++; + } + } +} + +void bj_show_player_cards(struct bj_game *game, struct bj_player *player) { + char cards_buf[MAXLEN]; + bj_print_player_cards(player, cards_buf); + int card_points = bj_get_player_card_points(player); + reply(game->textbot, player->chanuser->user, "NF_BJ_YOUR_CARDS", card_points, cards_buf); +} + +TIMEQ_CALLBACK(bj_game_wait_timeout) { + struct bj_game *game = data; + game->timer = NULL; + if(game->players == 1) { + bj_reply(game, NULL, "NF_BJ_LESS_PLAYERS"); + bj_free_game(game); + return; + } + game->deck = bj_shuffle_deck(); + bj_reply(game, NULL, "NF_BJ_START"); + game->state = BJ_STATE_RUNNING; + game->active_player = game->player; //active player + bj_reply(game, NULL, "NF_BJ_USER_HURRY_UP", game->active_player->chanuser->user->nick); + game->timer = timeq_add(30, module_id, bj_player_timeout, game); +} + +TIMEQ_CALLBACK(bj_player_timeout) { + struct bj_game *game = data; + game->timer = NULL; + //player timeout (next player) + struct bj_player *player = game->active_player; + bj_reply(game, NULL, "NF_BJ_USER_TIMEOUT", player->chanuser->user->nick); + bj_action_next_player(game, player); +} + +void bj_action_take_card(struct bj_game *game, struct bj_player *player) { + int points = bj_get_player_card_points(player); + if(points > 21) { + reply(game->textbot, player->chanuser->user, "NF_BJ_POINTS_EXCEEDED"); + return; + } + if(game->timer) { + timeq_del(game->timer); + game->timer = NULL; + } + struct bj_card *card = bj_get_card(game->deck); + if(!card) { + bj_free_deck(game->deck); + game->deck = bj_shuffle_deck(); + card = bj_get_card(game->deck); + } + struct bj_card *last_card; + for(last_card = player->cards; last_card; last_card = last_card->next) { + if(last_card->next == NULL) + break; + } + card->prev = last_card; + if(last_card) + last_card->next = card; + else + player->cards = card; + player->count++; + char cardbuf[16]; + int cardcolor = 1; + char *cardchar = ""; + int i, cardpoints = 0; + cardbuf[0] = '\0'; + for(i = 0; i < BJ_CTYPE_COUNT; i++) { + if(bj_ctype[i] == card->type) { + cardcolor = bj_irc_colors[i]; + cardchar = bj_color_chars[i]; + break; + } + } + i = 0; + while(bj_card_types[i].name) { + if(bj_card_types[i].type == card->card) { + sprintf(cardbuf, "[\003%d%s%s\003]", cardcolor, cardchar, bj_card_types[i].name); + cardpoints = bj_card_types[i].points; + if(bj_card_types[i].type == BJ_CARD_ACE && points > 10) + cardpoints = 1; + break; + } + i++; + } + reply(game->textbot, player->chanuser->user, "NF_BJ_TAKE", cardbuf, cardpoints); + bj_show_player_cards(game, player); + if(points + cardpoints > 21) + reply(game->textbot, player->chanuser->user, "NF_BJ_POINTS_EXCEEDED"); + game->timer = timeq_add(30, module_id, bj_player_timeout, game); +} + +void bj_action_next_player(struct bj_game *game, struct bj_player *player) { + if(game->timer) { + timeq_del(game->timer); + game->timer = NULL; + } + if(player) + bj_show_player_cards(game, player); + game->active_player = bj_get_next_player(game); + if(game->active_player) { + bj_reply(game, NULL, "NF_BJ_USER_HURRY_UP", game->active_player->chanuser->user->nick); + game->timer = timeq_add(30, module_id, bj_player_timeout, game); + } else { + bj_game_end(game); + bj_free_game(game); + } +} + +void bj_event_part(struct ChanUser *chanuser) { + struct bj_game *game; + for(game = bj_active_games; game; game = game->next) { + if(chanuser->chan == game->channel) { + struct bj_player *player; + for(player = game->player; player; player = player->next) { + if(player->chanuser == chanuser) { + if(game->active_player == player) { + if(bj_get_next_player(game) == NULL) { + bj_game_end(game); + bj_free_game(game); + return; + } else + bj_action_next_player(game, NULL); + } + game->players--; + bj_free_player(player, game->deck); + return; + } + } + } + } +} + +void bj_event_freechan(struct ChanNode *chan) { + struct bj_game *game; + for(game = bj_active_games; game; game = game->next) { + if(game->channel == chan) { + bj_free_game(game); + return; + } + } +} + +static int bj_highscore_sort(const void *a, const void *b) { + const struct bj_player *player_a = *((struct bj_player * const *) a); + const struct bj_player *player_b = *((struct bj_player * const *) b); + int points_a, points_b; + if(player_a->count > 21) + points_a = player_a->count * -1; + else + points_a = player_a->count; + if(player_b->count > 21) + points_b = player_b->count * -1; + else + points_b = player_b->count; + return points_b - points_a; +} + +void bj_game_end(struct bj_game *game) { + bj_reply(game, NULL, "NF_BJ_GAME_FINISHED"); + struct Table *table; + table = table_init(4, game->players+1, 0); + char *content[4]; + content[0] = get_language_string(NULL, "NF_BJ_RANK"); + content[1] = get_language_string(NULL, "NF_BJ_NAME"); + content[2] = get_language_string(NULL, "NF_BJ_POINTS"); + content[3] = get_language_string(NULL, "NF_BJ_CARDS"); + table_add(table, content); + //sort users + struct bj_player *players[game->players]; + struct bj_player *player; + int i = 0; + for(player = game->player; player; player = player->next) { + player->count = bj_get_player_card_points(player); + players[i++] = player; + } + qsort(players, game->players, sizeof(struct bj_player *), bj_highscore_sort); + char rankbuf[12]; + char pointbuf[12]; + char cardsbuf[MAXLEN]; + for(i = 0; i < game->players; i++) { + player = players[i]; + sprintf(rankbuf, "#%d", i+1); + content[0] = rankbuf; + content[1] = player->chanuser->user->nick; + sprintf(pointbuf, "%d", player->count); + content[2] = pointbuf; + bj_print_player_cards(player, cardsbuf); + content[3] = cardsbuf; + table_add(table, content); + } + char **table_lines = table_end(table); + for(i = 0; i < table->entrys; i++) { + bj_reply(game, NULL, table_lines[i]); + } + table_free(table); +} diff --git a/src/modules/NeonFun.mod/game_blackjack.h b/src/modules/NeonFun.mod/game_blackjack.h new file mode 100644 index 0000000..0e643ae --- /dev/null +++ b/src/modules/NeonFun.mod/game_blackjack.h @@ -0,0 +1,102 @@ +/* game_blackjack.h - NeonServ v5.6 + * 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_blackjack_h +#define _game_blackjack_h +#include "../../timeq.h" + +#define BJ_STATE_WAITING 1 +#define BJ_STATE_RUNNING 2 + +#define BJ_CTYPE_HEARTS 0 +#define BJ_CTYPE_SPADES 1 +#define BJ_CTYPE_DIAMONDS 2 +#define BJ_CTYPE_CLUBS 3 + +#define BJ_CTYPE_COUNT 4 + +#define BJ_CARD_NUMBER_2 0 +#define BJ_CARD_NUMBER_3 1 +#define BJ_CARD_NUMBER_4 2 +#define BJ_CARD_NUMBER_5 3 +#define BJ_CARD_NUMBER_6 4 +#define BJ_CARD_NUMBER_7 5 +#define BJ_CARD_NUMBER_8 6 +#define BJ_CARD_NUMBER_9 7 +#define BJ_CARD_NUMBER_10 8 +#define BJ_CARD_JACK 9 +#define BJ_CARD_QUEEN 10 +#define BJ_CARD_KING 11 +#define BJ_CARD_ACE 12 + +struct UserNode; +struct ChanNode; +struct ChanUser; +struct ClientSocket; +extern struct bj_game *bj_active_games; + +struct bj_card { + unsigned char type; + unsigned char card; + struct bj_card *prev, *next; +}; + +struct bj_card_deck { + struct bj_card *cards; + int count; +}; + +struct bj_player { + struct ChanUser *chanuser; + struct bj_card *cards; + int count; + struct bj_player *prev, *next; +}; + +struct bj_game { + struct ChanNode *channel; + struct ClientSocket *textbot; + int state : 3; + struct bj_card_deck *deck; + struct bj_player *player; + struct bj_player *active_player; + int players; + + struct timeq_entry *timer; + struct bj_game *next; +}; + +struct bj_card_deck *bj_shuffle_deck(); +struct bj_card *bj_get_card(struct bj_card_deck *deck); +void bj_free_deck(struct bj_card_deck *deck); +void bj_free_player(struct bj_player *player, struct bj_card_deck *deck); +void bj_free_game(struct bj_game *game); +struct bj_player *bj_get_next_player(struct bj_game *game); +int bj_get_player_card_points(struct bj_player *player); +void bj_show_player_cards(struct bj_game *game, struct bj_player *player); + +TIMEQ_CALLBACK(bj_game_wait_timeout); +TIMEQ_CALLBACK(bj_player_timeout); + +void bj_action_take_card(struct bj_game *game, struct bj_player *player); +void bj_action_next_player(struct bj_game *game, struct bj_player *player); + +void bj_event_part(struct ChanUser *chanuser); +void bj_event_freechan(struct ChanNode *chan); + +void bj_game_end(struct bj_game *game); + +#endif -- 2.20.1