1 /* game_uno.c - NeonServ v5.6
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "../module.h"
19 #include "bot_NeonFun.h"
20 #include "../../IRCParser.h"
21 #include "../../bots.h"
22 #include "../../UserNode.h"
23 #include "../../ChanUser.h"
24 #include "../../tools.h"
27 struct uno_game *uno_active_games = NULL;
29 #define UNO_COLOR_COUNT 4
30 static int uno_colors[] = {UNO_COLOR_RED, UNO_COLOR_BLUE, UNO_COLOR_GREEN, UNO_COLOR_YELLOW};
31 static int uno_irc_colors[] = {4, 12, 3, 7};
32 static char *uno_color_chars[] = {"R", "B", "G", "Y"};
37 } uno_card_types[] = {
38 {"0", UNO_CARD_NUMBER_0},
39 {"1", UNO_CARD_NUMBER_1},
40 {"2", UNO_CARD_NUMBER_2},
41 {"3", UNO_CARD_NUMBER_3},
42 {"4", UNO_CARD_NUMBER_4},
43 {"5", UNO_CARD_NUMBER_5},
44 {"6", UNO_CARD_NUMBER_6},
45 {"7", UNO_CARD_NUMBER_7},
46 {"8", UNO_CARD_NUMBER_8},
47 {"9", UNO_CARD_NUMBER_9},
49 {"><", UNO_CARD_DIRECTION},
50 {"+2", UNO_CARD_ADD_2},
51 {"+4", UNO_CARD_ADD_4},
52 {"COLOR", UNO_CARD_COLOR},
56 struct uno_card_deck *uno_shuffle_deck() {
57 struct uno_card *card, *last_card = NULL;
59 #define ADD_CARD(ccolor,ctype) \
60 card = malloc(sizeof(*card)); \
61 card->color = ccolor; \
64 card->next = last_card; \
66 last_card->prev = card; \
69 int colorcount = UNO_COLOR_COUNT;
70 for(colorcount--; colorcount >= 0; colorcount--) {
71 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_0);
72 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_0);
73 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_1);
74 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_1);
75 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_2);
76 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_2);
77 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_3);
78 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_3);
79 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_4);
80 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_4);
81 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_5);
82 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_5);
83 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_6);
84 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_6);
85 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_7);
86 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_7);
87 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_8);
88 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_8);
89 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_9);
90 ADD_CARD(uno_colors[colorcount], UNO_CARD_NUMBER_9);
91 ADD_CARD(uno_colors[colorcount], UNO_CARD_SKIP);
92 ADD_CARD(uno_colors[colorcount], UNO_CARD_SKIP);
93 ADD_CARD(uno_colors[colorcount], UNO_CARD_DIRECTION);
94 ADD_CARD(uno_colors[colorcount], UNO_CARD_DIRECTION);
95 ADD_CARD(uno_colors[colorcount], UNO_CARD_ADD_2);
96 ADD_CARD(uno_colors[colorcount], UNO_CARD_ADD_2);
98 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4);
99 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4);
100 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4);
101 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_ADD_4);
102 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR);
103 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR);
104 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR);
105 ADD_CARD(UNO_COLOR_BLACK, UNO_CARD_COLOR);
107 struct uno_card_deck *deck = malloc(sizeof(*deck));
108 deck->cards = last_card;
109 deck->count = card_count;
113 struct uno_card *uno_get_card(struct uno_card_deck *deck) {
114 if(!deck->count) return NULL;
115 int card_id = (rand() % deck->count);
117 struct uno_card *card;
118 for(card = deck->cards; card; card = card->next) {
121 card->prev->next = card->next;
123 deck->cards = card->next;
125 card->next->prev = card->prev;
136 void uno_free_deck(struct uno_card_deck *deck) {
137 struct uno_card *card, *next_card;
139 for(card = deck->cards; card; card = next_card) {
140 next_card = card->next;
147 void uno_free_player(struct uno_player *player, struct uno_card_deck *deck) {
149 struct uno_card *card, *next_card;
150 for(card = player->cards; card; card = next_card) {
151 next_card = card->next;
153 card->next = deck->cards;
154 deck->cards->prev = card;
162 player->prev->next = player->next;
164 player->next->prev = player->prev;
168 void uno_free_topcard(struct uno_card *card) {
169 struct uno_card *next_card;
170 for(; card; card = next_card) {
171 next_card = card->prev;
176 void uno_free_game(struct uno_game *game) {
177 struct uno_player *player, *next_player;
178 for(player = game->player; player; player = next_player) {
179 next_player = player->next;
180 uno_free_player(player, NULL);
182 for(player = game->winner; player; player = next_player) {
183 next_player = player->next;
184 uno_free_player(player, NULL);
187 uno_free_deck(game->deck);
189 uno_free_topcard(game->top_card);
191 timeq_del(game->timer);
192 struct uno_game *cgame, *pgame = NULL;
193 for(cgame = uno_active_games; cgame; cgame = cgame->next) {
196 pgame->next = game->next;
198 uno_active_games = game->next;
206 struct uno_player *uno_get_next_player(struct uno_game *game) {
207 struct uno_player *player = game->active_player;
208 if(!game->reverse_direction) {
209 player = player->next;
211 player = game->player;
213 player = player->prev;
215 for(player = game->player; player->next; player = player->next) {
216 //loop to the last player
223 void uno_show_player_cards(struct uno_game *game, struct uno_player *player) {
224 struct uno_card *card;
225 char cards_buf[MAXLEN];
226 int cards_bufpos = 0;
227 for(card = player->cards; card; card = card->next) {
231 for(i = 0; i < UNO_COLOR_COUNT; i++) {
232 if(uno_colors[i] == card->color) {
233 cardcolor = uno_irc_colors[i];
234 cardchar = uno_color_chars[i];
239 while(uno_card_types[i].name) {
240 if(uno_card_types[i].type == card->card) {
241 cards_bufpos += sprintf(cards_buf + cards_bufpos, "%s[\003%d%s%s\003]", (cards_bufpos ? " " : ""), cardcolor, cardchar, uno_card_types[i].name);
247 reply(game->textbot, player->chanuser->user, "NF_UNO_YOUR_CARDS", cards_buf);
250 void uno_show_top_card(struct uno_game *game) {
251 struct uno_card *card = game->top_card;
256 for(i = 0; i < UNO_COLOR_COUNT; i++) {
257 if(uno_colors[i] == card->color) {
258 cardcolor = uno_irc_colors[i];
259 cardchar = uno_color_chars[i];
264 while(uno_card_types[i].name) {
265 if(uno_card_types[i].type == card->card) {
266 if(card->card == UNO_CARD_ADD_4 || card->card == UNO_CARD_COLOR)
268 sprintf(card_buf, "[\003%d%s%s\003]", cardcolor, cardchar, uno_card_types[i].name);
273 uno_reply(game, NULL, "NF_UNO_TOP_CARD", card_buf);
276 TIMEQ_CALLBACK(uno_game_wait_timeout) {
277 struct uno_game *game = data;
279 if(game->players == 1) {
280 uno_reply(game, NULL, "NF_UNO_LESS_PLAYERS");
284 game->deck = uno_shuffle_deck();
285 uno_reply(game, NULL, "NF_UNO_START");
286 struct uno_player *player;
287 for(player = game->player; player; player = player->next) {
290 for(i = 0; i < 7; i++) {
291 if(!game->deck->count)
292 game->deck = uno_shuffle_deck();
293 struct uno_card *card = uno_get_card(game->deck);
295 uno_reply(game, NULL, "NF_UNO_ERROR", 1);
299 card->next = player->cards;
301 player->cards->prev = card;
302 player->cards = card;
305 uno_show_player_cards(game, player);
306 if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
308 int game_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_games")) ? atoi(tmp) : 0);
309 int total_game_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_games")) ? atoi(tmp) : 0);
313 sprintf(buf, "%d", game_count);
314 setSetting(player->chanuser->user, game->channel, "uno_games", buf);
315 sprintf(buf, "%d", total_game_count);
316 setSetting(player->chanuser->user, NULL, "uno_games", buf);
319 if(!game->deck->count)
320 game->deck = uno_shuffle_deck();
321 struct uno_card *card = uno_get_card(game->deck);
323 uno_reply(game, NULL, "NF_UNO_ERROR", 1);
327 game->top_card = card;
328 game->state = UNO_STATE_RUNNING;
329 uno_show_top_card(game);
330 game->active_player = game->player; //active player
331 uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
332 game->timer = timeq_add(40, module_id, uno_player_timeout, game);
335 TIMEQ_CALLBACK(uno_player_timeout) {
336 struct uno_game *game = data;
338 //player timeout (take another card)
339 struct uno_player *player = game->active_player, *next_player = uno_get_next_player(game);
340 //add a card to the players deck
342 if(game->take_cards_pending) {
343 //count cards to take
344 struct uno_card *card;
346 for(card = game->top_card; card; card = card->prev) {
347 if(card->card == UNO_CARD_ADD_2)
349 else if(card->card == UNO_CARD_ADD_4)
355 for(i = 0; i < ccount; i++) {
356 if(!game->deck->count)
357 game->deck = uno_shuffle_deck();
358 struct uno_card *card = uno_get_card(game->deck);
360 uno_reply(game, NULL, "NF_UNO_ERROR", 2);
364 card->next = player->cards;
366 player->cards->prev = card;
367 player->cards = card;
371 game->active_player = next_player;
372 if(game->take_cards_pending) {
373 game->take_cards_pending = 0;
374 uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARDS", player->chanuser->user->nick, ccount);
376 uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
377 struct uno_player *cplayer;
378 for(cplayer = game->player; cplayer; cplayer = cplayer->next) {
379 if(!cplayer->timeout)
383 uno_reply(game, NULL, "NF_UNO_TIMEOUT");
387 uno_show_player_cards(game, player);
388 uno_show_top_card(game);
389 uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
390 uno_show_player_cards(game, game->active_player);
391 game->timer = timeq_add(40, module_id, uno_player_timeout, game);
394 void uno_action_take_card(struct uno_game *game, struct uno_player *player) {
395 timeq_del(game->timer);
397 struct uno_player *next_player = uno_get_next_player(game);
398 //add a card to the players deck
400 if(game->take_cards_pending) {
401 //count cards to take
402 struct uno_card *card;
404 for(card = game->top_card; card; card = card->prev) {
405 if(card->card == UNO_CARD_ADD_2)
407 else if(card->card == UNO_CARD_ADD_4)
413 for(i = 0; i < ccount; i++) {
414 if(!game->deck->count)
415 game->deck = uno_shuffle_deck(game->deck);
416 struct uno_card *card = uno_get_card(game->deck);
418 uno_reply(game, NULL, "NF_UNO_ERROR", 2);
422 card->next = player->cards;
424 player->cards->prev = card;
425 player->cards = card;
428 game->active_player = next_player;
429 if(game->take_cards_pending) {
430 game->take_cards_pending = 0;
431 uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARDS", player->chanuser->user->nick, ccount);
433 uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
434 uno_show_player_cards(game, player);
435 uno_show_top_card(game);
436 uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
437 uno_show_player_cards(game, game->active_player);
438 game->timer = timeq_add(40, module_id, uno_player_timeout, game);
443 struct uno_card *uno_parse_card(struct uno_game *game, struct uno_player *player, char *arg1) {
466 unsigned char ctype = 255, ccolor = 0;
469 while(uno_card_types[i].name) {
470 if(!stricmp(uno_card_types[i].name, arg1)) {
471 ctype = uno_card_types[i].type;
474 for(j = 0; j < UNO_COLOR_COUNT; j++) {
475 sprintf(tmpbuf, "%s%s", uno_color_chars[j], uno_card_types[i].name);
476 if(!stricmp(tmpbuf, arg1)) {
477 ccolor = uno_colors[j];
478 ctype = uno_card_types[i].type;
485 reply(game->textbot, player->chanuser->user, "NF_UNO_UNKNOWN_CARD", arg1);
488 struct uno_card *card;
489 for(card = player->cards; card; card = card->next) {
490 if(card->card == ctype && card->color == ccolor)
494 reply(game->textbot, player->chanuser->user, "NF_UNO_CARD_NOT_IN_DECK");
500 int uno_check_card_valid(struct uno_game *game, struct uno_card *card) {
501 if(game->take_cards_pending && card->card != game->top_card->card)
503 if(card->color == UNO_COLOR_BLACK || game->top_card->color == UNO_COLOR_BLACK)
505 if(card->color != game->top_card->color && card->card != game->top_card->card)
510 void uno_play_card(struct uno_game *game, struct uno_player *player, struct uno_card *card) {
511 timeq_del(game->timer);
514 card->prev->next = card->next;
516 player->cards = card->next;
518 card->next->prev = card->prev;
520 if(!game->take_cards_pending) {
521 uno_free_topcard(game->top_card);
524 card->prev = game->top_card;
526 game->top_card = card;
527 uno_show_top_card(game);
528 if(player->count == 1) {
529 uno_reply(game, NULL, "NF_UNO_ONE_CARD", game->active_player->chanuser->user->nick);
530 } else if(player->count == 0) {
531 uno_reply(game, NULL, "NF_UNO_USER_WIN", game->active_player->chanuser->user->nick);
533 player->prev->next = player->next;
535 game->player = player->next;
537 player->next->prev = player->prev;
540 struct uno_player *cplayer;
541 int winner_count = 0;
543 for(cplayer = game->winner; cplayer->next; cplayer = cplayer->next) {
549 cplayer->next = player;
551 game->winner = player;
552 if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
554 int win_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0);
555 int total_win_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0);
559 sprintf(buf, "%d", win_count);
560 setSetting(player->chanuser->user, game->channel, "uno_win", buf);
561 sprintf(buf, "%d", total_win_count);
562 setSetting(player->chanuser->user, NULL, "uno_win", buf);
565 player->prev = cplayer;
567 if(game->players <= 1) {
569 uno_reply(game, NULL, "NF_UNO_GAME_FINISHED");
571 table = table_init(4, winner_count + 3, 0);
573 content[0] = get_language_string(NULL, "NF_UNO_RANK");
574 content[1] = get_language_string(NULL, "NF_UNO_NAME");
575 content[2] = get_language_string(NULL, "NF_UNO_WON_GAMES");
576 content[3] = get_language_string(NULL, "NF_UNO_TOTAL_WON_GAMES");
577 table_add(table, content);
579 char rank_buf[20], won_buf[50], total_won_buf[50];
581 for(cplayer = game->winner; cplayer; cplayer = cplayer->next) {
582 sprintf(rank_buf, "%d", winner_count++);
583 content[0] = rank_buf;
584 content[1] = cplayer->chanuser->user->nick;
585 if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
586 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));
587 content[2] = won_buf;
588 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));
589 content[3] = total_won_buf;
594 table_add(table, content);
596 cplayer = game->player;
597 sprintf(rank_buf, "%d", winner_count++);
598 content[0] = rank_buf;
599 content[1] = cplayer->chanuser->user->nick;
600 if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
601 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));
602 content[2] = won_buf;
603 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));
604 content[3] = total_won_buf;
609 table_add(table, content);
610 char **table_lines = table_end(table);
612 for(i = 0; i < table->entrys; i++) {
613 uno_reply(game, NULL, table_lines[i]);
620 if(card->card == UNO_CARD_DIRECTION)
621 game->reverse_direction = (game->reverse_direction ? 0 : 1);
622 struct uno_player *next_player = uno_get_next_player(game);
623 game->active_player = next_player;
624 if(card->card == UNO_CARD_SKIP) {
625 uno_reply(game, NULL, "NF_UNO_USER_SKIP", game->active_player->chanuser->user->nick);
626 next_player = uno_get_next_player(game);
627 game->active_player = next_player;
629 if(card->card == UNO_CARD_ADD_2 || card->card == UNO_CARD_ADD_4) {
631 for(card = game->top_card; card; card = card->prev) {
632 if(card->card == UNO_CARD_ADD_2)
634 else if(card->card == UNO_CARD_ADD_4)
637 uno_reply(game, NULL, "NF_UNO_ADD_CARD", game->active_player->chanuser->user->nick, ccount);
638 game->take_cards_pending = 1;
640 uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
641 uno_show_player_cards(game, game->active_player);
642 game->timer = timeq_add(40, module_id, uno_player_timeout, game);
645 void uno_event_part(struct ChanUser *chanuser) {
646 struct uno_game *game;
647 for(game = uno_active_games; game; game = game->next) {
648 if(chanuser->chan == game->channel) {
649 struct uno_player *player;
650 for(player = game->player; player; player = player->next) {
651 if(player->chanuser == chanuser) {
652 uno_free_player(player, game->deck);
660 void uno_event_freechan(struct ChanNode *chan) {
661 struct uno_game *game;
662 for(game = uno_active_games; game; game = game->next) {
663 if(game->channel == chan) {