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)
#include "../../bots.h"
#include "game_uno.h"
#include "game_4wins.h"
+#include "game_blackjack.h"
#define BOTID NEONFUN_BOTID
#define BOTALIAS "NeonFun"
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;
}
}
}
+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
struct uno_game;
struct fourwins_game;
+struct bj_game;
struct ChanNode;
struct UserNode;
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
{"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"} */
{"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}
};
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
}
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
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+ }
+}
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;
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#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);
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+#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