rewrote IRC cache parser to be (hopefully) more stable
[NeonServV5.git] / src / modules / NeonFun.mod / game_uno.c
1 /* game_uno.c - NeonServ v5.4
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
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.
8  * 
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.
13  * 
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/>. 
16  */
17 #include "../module.h"
18 #include "game_uno.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"
25 #include "../botid.h"
26
27 struct uno_game *uno_active_games = NULL;
28
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"};
33
34 static const struct {
35     const char *name;
36     unsigned char type;
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},
48     {"X", UNO_CARD_SKIP},
49     {"><", UNO_CARD_DIRECTION},
50     {"+2", UNO_CARD_ADD_2},
51     {"+4", UNO_CARD_ADD_4},
52     {"COLOR", UNO_CARD_COLOR},
53     {NULL, 0}
54 };
55
56 struct uno_card_deck *uno_shuffle_deck() {
57     struct uno_card *card, *last_card = NULL;
58     int card_count = 0;
59     #define ADD_CARD(ccolor,ctype) \
60     card = malloc(sizeof(*card)); \
61     card->color = ccolor; \
62     card->card = ctype; \
63     card->prev = NULL; \
64     card->next = last_card; \
65     if(last_card) \
66         last_card->prev = card; \
67     last_card = card; \
68     card_count++;
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);
97     }
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);
106     #undef ADD_CARD
107     struct uno_card_deck *deck = malloc(sizeof(*deck));
108     deck->cards = last_card;
109     deck->count = card_count;
110     return deck;
111 }
112
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);
116     int i = 0;
117     struct uno_card *card;
118     for(card = deck->cards; card; card = card->next) {
119         if(i == card_id) {
120             if(card->prev)
121                 card->prev->next = card->next;
122             else
123                 deck->cards = card->next;
124             if(card->next)
125                 card->next->prev = card->prev;
126             deck->count--;
127             card->next = NULL;
128             card->prev = NULL;
129             return card;
130         }
131         i++;
132     }
133     return NULL;
134 }
135
136 void uno_free_deck(struct uno_card_deck *deck) {
137     struct uno_card *card, *next_card;
138     if(deck->count) {
139         for(card = deck->cards; card; card = next_card) {
140             next_card = card->next;
141             free(card);
142         }
143     }
144 }
145
146 void uno_free_player(struct uno_player *player, struct uno_card_deck *deck) {
147     if(player->count) {
148         struct uno_card *card, *next_card;
149         for(card = player->cards; card; card = next_card) {
150             next_card = card->next;
151             if(deck) {
152                 card->next = deck->cards;
153                 deck->cards->prev = card;
154                 deck->cards = card;
155                 deck->count++;
156             } else
157                 free(card);
158         }
159     }
160     if(player->prev)
161         player->prev->next = player->next;
162     if(player->next)
163         player->next->prev = player->prev;
164     free(player);
165 }
166
167 void uno_free_topcard(struct uno_card *card) {
168     struct uno_card *next_card;
169     for(; card; card = next_card) {
170         next_card = card->prev;
171         free(card);
172     }
173 }
174
175 void uno_free_game(struct uno_game *game) {
176     struct uno_player *player, *next_player;
177     for(player = game->player; player; player = next_player) {
178         next_player = player->next;
179         uno_free_player(player, NULL);
180     }
181     for(player = game->winner; player; player = next_player) {
182         next_player = player->next;
183         uno_free_player(player, NULL);
184     }
185     if(game->deck)
186         uno_free_deck(game->deck);
187     if(game->top_card)
188         uno_free_topcard(game->top_card);
189     if(game->timer)
190         timeq_del(game->timer);
191     struct uno_game *cgame, *pgame = NULL;
192     for(cgame = uno_active_games; cgame; cgame = cgame->next) {
193         if(cgame == game) {
194             if(pgame)
195                 pgame->next = game->next;
196             else
197                 uno_active_games = game->next;
198             break;
199         } else
200             pgame = cgame;
201     }
202     free(game);
203 }
204
205 struct uno_player *uno_get_next_player(struct uno_game *game) {
206     struct uno_player *player = game->active_player;
207     if(!game->reverse_direction) {
208         player = player->next;
209         if(!player)
210             player = game->player;
211     } else {
212         player = player->prev;
213         if(!player) {
214             for(player = game->player; player->next; player = player->next) {
215                 //loop to the last player
216             }
217         }
218     }
219     return player;
220 }
221
222 void uno_show_player_cards(struct uno_game *game, struct uno_player *player) {
223     struct uno_card *card;
224     char cards_buf[MAXLEN];
225     int cards_bufpos = 0;
226     for(card = player->cards; card; card = card->next) {
227         int cardcolor = 1;
228         char *cardchar = "";
229         int i;
230         for(i = 0; i < UNO_COLOR_COUNT; i++) {
231             if(uno_colors[i] == card->color) {
232                 cardcolor = uno_irc_colors[i];
233                 cardchar = uno_color_chars[i];
234                 break;
235             }
236         }
237         i = 0;
238         while(uno_card_types[i].name) {
239             if(uno_card_types[i].type == card->card) {
240                 cards_bufpos += sprintf(cards_buf + cards_bufpos, "%s[\003%d%s%s\003]", (cards_bufpos ? " " : ""), cardcolor, cardchar, uno_card_types[i].name);
241                 break;
242             }
243             i++;
244         }
245     }
246     reply(game->textbot, player->chanuser->user, "NF_UNO_YOUR_CARDS", cards_buf);
247 }
248
249 void uno_show_top_card(struct uno_game *game) {
250     struct uno_card *card = game->top_card;
251     char card_buf[50];
252     int cardcolor = 1;
253     char *cardchar = "";
254     int i;
255     for(i = 0; i < UNO_COLOR_COUNT; i++) {
256         if(uno_colors[i] == card->color) {
257             cardcolor = uno_irc_colors[i];
258             cardchar = uno_color_chars[i];
259             break;
260         }
261     }
262     i = 0;
263     while(uno_card_types[i].name) {
264         if(uno_card_types[i].type == card->card) {
265             if(card->card == UNO_CARD_ADD_4 || card->card == UNO_CARD_COLOR)
266                 cardchar = "";
267             sprintf(card_buf, "[\003%d%s%s\003]", cardcolor, cardchar, uno_card_types[i].name);
268             break;
269         }
270         i++;
271     }
272     uno_reply(game, NULL, "NF_UNO_TOP_CARD", card_buf);
273 }
274
275 TIMEQ_CALLBACK(uno_game_wait_timeout) {
276     struct uno_game *game = data;
277     game->timer = NULL;
278     if(game->players == 1) {
279         uno_reply(game, NULL, "NF_UNO_LESS_PLAYERS");
280         uno_free_game(game);
281         return;
282     }
283     game->deck = uno_shuffle_deck();
284     uno_reply(game, NULL, "NF_UNO_START");
285     struct uno_player *player;
286     for(player = game->player; player; player = player->next) {
287         //give 7 cards
288         int i;
289         for(i = 0; i < 7; i++) {
290             if(!game->deck->count)
291                 game->deck = uno_shuffle_deck();
292             struct uno_card *card = uno_get_card(game->deck);
293             if(!card) {
294                 uno_reply(game, NULL, "NF_UNO_ERROR", 1);
295                 uno_free_game(game);
296                 return;
297             }
298             card->next = player->cards;
299             if(player->cards)
300                 player->cards->prev = card;
301             player->cards = card;
302             player->count++;
303         }
304         uno_show_player_cards(game, player);
305         if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
306             char *tmp;
307             int game_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_games")) ? atoi(tmp) : 0);
308             int total_game_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_games")) ? atoi(tmp) : 0);
309             game_count++;
310             total_game_count++;
311             char buf[10];
312             sprintf(buf, "%d", game_count);
313             setSetting(player->chanuser->user, game->channel, "uno_games", buf);
314             sprintf(buf, "%d", total_game_count);
315             setSetting(player->chanuser->user, NULL, "uno_games", buf);
316         }
317     }
318     if(!game->deck->count)
319         game->deck = uno_shuffle_deck();
320     struct uno_card *card = uno_get_card(game->deck);
321     if(!card) {
322         uno_reply(game, NULL, "NF_UNO_ERROR", 1);
323         uno_free_game(game);
324         return;
325     }
326     game->top_card = card;
327     game->state = UNO_STATE_RUNNING;
328     uno_show_top_card(game);
329     game->active_player = game->player; //active player
330     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
331     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
332 }
333
334 TIMEQ_CALLBACK(uno_player_timeout) {
335     struct uno_game *game = data;
336     game->timer = NULL;
337     //player timeout (take another card)
338     struct uno_player *player = game->active_player, *next_player = uno_get_next_player(game);
339     //add a card to the players deck
340     if(!game->deck->count)
341         game->deck = uno_shuffle_deck();
342     struct uno_card *card = uno_get_card(game->deck);
343     if(!card) {
344         uno_reply(game, NULL, "NF_UNO_ERROR", 2);
345         uno_free_game(game);
346         return;
347     }
348     card->next = player->cards;
349     if(player->cards)
350         player->cards->prev = card;
351     player->cards = card;
352     player->count++;
353     player->timeout = 1;
354     game->active_player = next_player;
355     uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
356     struct uno_player *cplayer;
357     for(cplayer = game->player; cplayer; cplayer = cplayer->next) {
358         if(!cplayer->timeout)
359             break;
360     }
361     if(!cplayer) {
362         uno_reply(game, NULL, "NF_UNO_TIMEOUT");
363         uno_free_game(game);
364         return;
365     }
366     uno_show_player_cards(game, player);
367     uno_show_top_card(game);
368     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
369     uno_show_player_cards(game, game->active_player);
370     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
371 }
372
373 void uno_action_take_card(struct uno_game *game, struct uno_player *player) {
374     timeq_del(game->timer);
375     game->timer = NULL;
376     struct uno_player *next_player = uno_get_next_player(game);
377     //add a card to the players deck
378     int ccount;
379     if(game->take_cards_pending) {
380         //count cards to take
381         struct uno_card *card;
382         ccount = 0;
383         for(card = game->top_card; card; card = card->prev) {
384             if(card->card == UNO_CARD_ADD_2)
385                 ccount += 2;
386             else if(card->card == UNO_CARD_ADD_4)
387                 ccount += 4;
388         }
389     } else
390         ccount = 1;
391     int i;
392     for(i = 0; i < ccount; i++) {
393         if(!game->deck->count)
394             game->deck = uno_shuffle_deck(game->deck);
395         struct uno_card *card = uno_get_card(game->deck);
396         if(!card) {
397             uno_reply(game, NULL, "NF_UNO_ERROR", 2);
398             uno_free_game(game);
399             return;
400         }
401         card->next = player->cards;
402         if(player->cards)
403             player->cards->prev = card;
404         player->cards = card;
405         player->count++;
406     }
407     game->active_player = next_player;
408     if(game->take_cards_pending) {
409         game->take_cards_pending = 0;
410         uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARDS", player->chanuser->user->nick, ccount);
411     } else
412         uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
413     uno_show_player_cards(game, player);
414     uno_show_top_card(game);
415     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
416     uno_show_player_cards(game, game->active_player);
417     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
418 }
419
420
421
422 struct uno_card *uno_parse_card(struct uno_game *game, struct uno_player *player, char *arg1) {
423     char *b = arg1;
424     int a = 0;
425     while(*b) {
426         switch (*b) {
427         case '\003':
428             if(isdigit(b[1]))
429                 b[1] = '\002';
430             if(isdigit(b[2]))
431                 b[2] = '\002';
432         case '[':
433         case '\002':
434         case ']':
435             *b = '\0';
436             break;
437         default:
438             if(!a) {
439                 a = 1;
440                 arg1 = b;
441             }
442         }
443         b++;
444     }
445     unsigned char ctype = 255, ccolor = 0;
446     int i = 0, j;
447     char tmpbuf[50];
448     while(uno_card_types[i].name) {
449         if(!stricmp(uno_card_types[i].name, arg1)) {
450             ctype = uno_card_types[i].type;
451             break;
452         }
453         for(j = 0; j < UNO_COLOR_COUNT; j++) {
454             sprintf(tmpbuf, "%s%s", uno_color_chars[j], uno_card_types[i].name);
455             if(!stricmp(tmpbuf, arg1)) {
456                 ccolor = uno_colors[j];
457                 ctype = uno_card_types[i].type;
458                 break;
459             }
460         }
461         i++;
462     }
463     if(ctype == 255) {
464         reply(game->textbot, player->chanuser->user, "NF_UNO_UNKNOWN_CARD", arg1);
465         return NULL;
466     }
467     struct uno_card *card;
468     for(card = player->cards; card; card = card->next) {
469         if(card->card == ctype && card->color == ccolor)
470             break;
471     }
472     if(!card) {
473         reply(game->textbot, player->chanuser->user, "NF_UNO_CARD_NOT_IN_DECK");
474         return NULL;
475     }
476     return card;
477 }
478
479 int uno_check_card_valid(struct uno_game *game, struct uno_card *card) {
480     if(game->take_cards_pending && card->card != game->top_card->card)
481         return 1;
482     if(card->color == UNO_COLOR_BLACK || game->top_card->color == UNO_COLOR_BLACK)
483         return 0;
484     if(card->color != game->top_card->color && card->card != game->top_card->card)
485         return 1;
486     return 0;
487 }
488
489 void uno_play_card(struct uno_game *game, struct uno_player *player, struct uno_card *card) {
490     timeq_del(game->timer);
491     game->timer = NULL;
492     if(card->prev)
493         card->prev->next = card->next;
494     else
495         player->cards = card->next;
496     if(card->next)
497         card->next->prev = card->prev;
498     player->count--;
499     if(!game->take_cards_pending) {
500         uno_free_topcard(game->top_card);
501         card->prev = NULL;
502     } else
503         card->prev = game->top_card;
504     card->next = NULL;
505     game->top_card = card;
506     uno_show_top_card(game);
507     if(player->count == 1) {
508         uno_reply(game, NULL, "NF_UNO_ONE_CARD", game->active_player->chanuser->user->nick);
509     } else if(player->count == 0) {
510         uno_reply(game, NULL, "NF_UNO_USER_WIN", game->active_player->chanuser->user->nick);
511         if(player->prev)
512             player->prev->next = player->next;
513         else
514             game->player = player->next;
515         if(player->next)
516             player->next->prev = player->prev;
517         player->next = NULL;
518         player->prev = NULL;
519         struct uno_player *cplayer;
520         int winner_count = 0;
521         if(game->winner) {
522             for(cplayer = game->winner; cplayer->next; cplayer = cplayer->next) {
523                 winner_count++;
524             }
525         } else
526             cplayer = NULL;
527         if(cplayer) {
528             cplayer->next = player;
529         } else {
530             game->winner = player;
531             if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
532                 char *tmp;
533                 int win_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0);
534                 int total_win_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0);
535                 win_count++;
536                 total_win_count++;
537                 char buf[10];
538                 sprintf(buf, "%d", win_count);
539                 setSetting(player->chanuser->user, game->channel, "uno_win", buf);
540                 sprintf(buf, "%d", total_win_count);
541                 setSetting(player->chanuser->user, NULL, "uno_win", buf);
542             }
543         }
544         player->prev = cplayer;
545         game->players--;
546         if(game->players <= 1) {
547             //game finished
548             uno_reply(game, NULL, "NF_UNO_GAME_FINISHED");
549             struct Table *table;
550             table = table_init(4, winner_count + 3, 0);
551             char *content[4];
552             content[0] = get_language_string(NULL, "NF_UNO_RANK");
553             content[1] = get_language_string(NULL, "NF_UNO_NAME");
554             content[2] = get_language_string(NULL, "NF_UNO_WON_GAMES");
555             content[3] = get_language_string(NULL, "NF_UNO_TOTAL_WON_GAMES");
556             table_add(table, content);
557             winner_count = 1;
558             char rank_buf[20], won_buf[50], total_won_buf[50];
559             char *tmp, *tmp2;
560             for(cplayer = game->winner; cplayer; cplayer = cplayer->next) {
561                 sprintf(rank_buf, "%d", winner_count++);
562                 content[0] = rank_buf;
563                 content[1] = cplayer->chanuser->user->nick;
564                 if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
565                     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));
566                     content[2] = won_buf;
567                     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));
568                     content[3] = total_won_buf;
569                 } else {
570                     content[2] = "?";
571                     content[3] = "?";
572                 }
573                 table_add(table, content);
574             }
575             cplayer = game->player;
576             sprintf(rank_buf, "%d", winner_count++);
577             content[0] = rank_buf;
578             content[1] = cplayer->chanuser->user->nick;
579             if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
580                 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));
581                 content[2] = won_buf;
582                 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));
583                 content[3] = total_won_buf;
584             } else {
585                 content[2] = "?";
586                 content[3] = "?";
587             }
588             table_add(table, content);
589             char **table_lines = table_end(table);
590             int i;
591             for(i = 0; i < table->entrys; i++) {
592                 uno_reply(game, NULL, table_lines[i]);
593             }
594             table_free(table);
595             uno_free_game(game);
596             return;
597         }
598     }
599     if(card->card == UNO_CARD_DIRECTION)
600         game->reverse_direction = (game->reverse_direction ? 0 : 1);
601     struct uno_player *next_player = uno_get_next_player(game);
602     game->active_player = next_player;
603     if(card->card == UNO_CARD_SKIP) {
604         uno_reply(game, NULL, "NF_UNO_USER_SKIP", game->active_player->chanuser->user->nick);
605         next_player = uno_get_next_player(game);
606         game->active_player = next_player;
607     }
608     if(card->card == UNO_CARD_ADD_2 || card->card == UNO_CARD_ADD_4) {
609         int ccount = 0;
610         for(card = game->top_card; card; card = card->prev) {
611             if(card->card == UNO_CARD_ADD_2)
612                 ccount += 2;
613             else if(card->card == UNO_CARD_ADD_4)
614                 ccount += 4;
615         }
616         uno_reply(game, NULL, "NF_UNO_ADD_CARD", game->active_player->chanuser->user->nick, ccount);
617         game->take_cards_pending = 1;
618     }
619     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
620     uno_show_player_cards(game, game->active_player);
621     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
622 }
623
624 void uno_event_part(struct ChanUser *chanuser) {
625     struct uno_game *game;
626     for(game = uno_active_games; game; game = game->next) {
627         if(chanuser->chan == game->channel) {
628             struct uno_player *player;
629             for(player = game->player; player; player = player->next) {
630                 if(player->chanuser == chanuser) {
631                     uno_free_player(player, game->deck);
632                     return;
633                 }
634             }
635         }
636     }
637 }
638
639 void uno_event_freechan(struct ChanNode *chan) {
640     struct uno_game *game;
641     for(game = uno_active_games; game; game = game->next) {
642         if(game->channel == chan) {
643             uno_free_game(game);
644             return;
645         }
646     }
647 }