fixed small memory leak in game_uno.c
[NeonServV5.git] / src / modules / NeonFun.mod / game_uno.c
1 /* game_uno.c - NeonServ v5.5
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     free(deck);
145 }
146
147 void uno_free_player(struct uno_player *player, struct uno_card_deck *deck) {
148     if(player->count) {
149         struct uno_card *card, *next_card;
150         for(card = player->cards; card; card = next_card) {
151             next_card = card->next;
152             if(deck) {
153                 card->next = deck->cards;
154                 deck->cards->prev = card;
155                 deck->cards = card;
156                 deck->count++;
157             } else
158                 free(card);
159         }
160     }
161     if(player->prev)
162         player->prev->next = player->next;
163     if(player->next)
164         player->next->prev = player->prev;
165     free(player);
166 }
167
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;
172         free(card);
173     }
174 }
175
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);
181     }
182     for(player = game->winner; player; player = next_player) {
183         next_player = player->next;
184         uno_free_player(player, NULL);
185     }
186     if(game->deck)
187         uno_free_deck(game->deck);
188     if(game->top_card)
189         uno_free_topcard(game->top_card);
190     if(game->timer)
191         timeq_del(game->timer);
192     struct uno_game *cgame, *pgame = NULL;
193     for(cgame = uno_active_games; cgame; cgame = cgame->next) {
194         if(cgame == game) {
195             if(pgame)
196                 pgame->next = game->next;
197             else
198                 uno_active_games = game->next;
199             break;
200         } else
201             pgame = cgame;
202     }
203     free(game);
204 }
205
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;
210         if(!player)
211             player = game->player;
212     } else {
213         player = player->prev;
214         if(!player) {
215             for(player = game->player; player->next; player = player->next) {
216                 //loop to the last player
217             }
218         }
219     }
220     return player;
221 }
222
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) {
228         int cardcolor = 1;
229         char *cardchar = "";
230         int i;
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];
235                 break;
236             }
237         }
238         i = 0;
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);
242                 break;
243             }
244             i++;
245         }
246     }
247     reply(game->textbot, player->chanuser->user, "NF_UNO_YOUR_CARDS", cards_buf);
248 }
249
250 void uno_show_top_card(struct uno_game *game) {
251     struct uno_card *card = game->top_card;
252     char card_buf[50];
253     int cardcolor = 1;
254     char *cardchar = "";
255     int i;
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];
260             break;
261         }
262     }
263     i = 0;
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)
267                 cardchar = "";
268             sprintf(card_buf, "[\003%d%s%s\003]", cardcolor, cardchar, uno_card_types[i].name);
269             break;
270         }
271         i++;
272     }
273     uno_reply(game, NULL, "NF_UNO_TOP_CARD", card_buf);
274 }
275
276 TIMEQ_CALLBACK(uno_game_wait_timeout) {
277     struct uno_game *game = data;
278     game->timer = NULL;
279     if(game->players == 1) {
280         uno_reply(game, NULL, "NF_UNO_LESS_PLAYERS");
281         uno_free_game(game);
282         return;
283     }
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) {
288         //give 7 cards
289         int i;
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);
294             if(!card) {
295                 uno_reply(game, NULL, "NF_UNO_ERROR", 1);
296                 uno_free_game(game);
297                 return;
298             }
299             card->next = player->cards;
300             if(player->cards)
301                 player->cards->prev = card;
302             player->cards = card;
303             player->count++;
304         }
305         uno_show_player_cards(game, player);
306         if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
307             char *tmp;
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);
310             game_count++;
311             total_game_count++;
312             char buf[10];
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);
317         }
318     }
319     if(!game->deck->count)
320         game->deck = uno_shuffle_deck();
321     struct uno_card *card = uno_get_card(game->deck);
322     if(!card) {
323         uno_reply(game, NULL, "NF_UNO_ERROR", 1);
324         uno_free_game(game);
325         return;
326     }
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(30, module_id, uno_player_timeout, game);
333 }
334
335 TIMEQ_CALLBACK(uno_player_timeout) {
336     struct uno_game *game = data;
337     game->timer = NULL;
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
341     if(!game->deck->count)
342         game->deck = uno_shuffle_deck();
343     struct uno_card *card = uno_get_card(game->deck);
344     if(!card) {
345         uno_reply(game, NULL, "NF_UNO_ERROR", 2);
346         uno_free_game(game);
347         return;
348     }
349     card->next = player->cards;
350     if(player->cards)
351         player->cards->prev = card;
352     player->cards = card;
353     player->count++;
354     player->timeout = 1;
355     game->active_player = next_player;
356     uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
357     struct uno_player *cplayer;
358     for(cplayer = game->player; cplayer; cplayer = cplayer->next) {
359         if(!cplayer->timeout)
360             break;
361     }
362     if(!cplayer) {
363         uno_reply(game, NULL, "NF_UNO_TIMEOUT");
364         uno_free_game(game);
365         return;
366     }
367     uno_show_player_cards(game, player);
368     uno_show_top_card(game);
369     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
370     uno_show_player_cards(game, game->active_player);
371     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
372 }
373
374 void uno_action_take_card(struct uno_game *game, struct uno_player *player) {
375     timeq_del(game->timer);
376     game->timer = NULL;
377     struct uno_player *next_player = uno_get_next_player(game);
378     //add a card to the players deck
379     int ccount;
380     if(game->take_cards_pending) {
381         //count cards to take
382         struct uno_card *card;
383         ccount = 0;
384         for(card = game->top_card; card; card = card->prev) {
385             if(card->card == UNO_CARD_ADD_2)
386                 ccount += 2;
387             else if(card->card == UNO_CARD_ADD_4)
388                 ccount += 4;
389         }
390     } else
391         ccount = 1;
392     int i;
393     for(i = 0; i < ccount; i++) {
394         if(!game->deck->count)
395             game->deck = uno_shuffle_deck(game->deck);
396         struct uno_card *card = uno_get_card(game->deck);
397         if(!card) {
398             uno_reply(game, NULL, "NF_UNO_ERROR", 2);
399             uno_free_game(game);
400             return;
401         }
402         card->next = player->cards;
403         if(player->cards)
404             player->cards->prev = card;
405         player->cards = card;
406         player->count++;
407     }
408     game->active_player = next_player;
409     if(game->take_cards_pending) {
410         game->take_cards_pending = 0;
411         uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARDS", player->chanuser->user->nick, ccount);
412     } else
413         uno_reply(game, NULL, "NF_UNO_USER_TOOK_CARD", player->chanuser->user->nick);
414     uno_show_player_cards(game, player);
415     uno_show_top_card(game);
416     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
417     uno_show_player_cards(game, game->active_player);
418     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
419 }
420
421
422
423 struct uno_card *uno_parse_card(struct uno_game *game, struct uno_player *player, char *arg1) {
424     char *b = arg1;
425     int a = 0;
426     while(*b) {
427         switch (*b) {
428         case '\003':
429             if(isdigit(b[1]))
430                 b[1] = '\002';
431             if(isdigit(b[2]))
432                 b[2] = '\002';
433         case '[':
434         case '\002':
435         case ']':
436             *b = '\0';
437             break;
438         default:
439             if(!a) {
440                 a = 1;
441                 arg1 = b;
442             }
443         }
444         b++;
445     }
446     unsigned char ctype = 255, ccolor = 0;
447     int i = 0, j;
448     char tmpbuf[50];
449     while(uno_card_types[i].name) {
450         if(!stricmp(uno_card_types[i].name, arg1)) {
451             ctype = uno_card_types[i].type;
452             break;
453         }
454         for(j = 0; j < UNO_COLOR_COUNT; j++) {
455             sprintf(tmpbuf, "%s%s", uno_color_chars[j], uno_card_types[i].name);
456             if(!stricmp(tmpbuf, arg1)) {
457                 ccolor = uno_colors[j];
458                 ctype = uno_card_types[i].type;
459                 break;
460             }
461         }
462         i++;
463     }
464     if(ctype == 255) {
465         reply(game->textbot, player->chanuser->user, "NF_UNO_UNKNOWN_CARD", arg1);
466         return NULL;
467     }
468     struct uno_card *card;
469     for(card = player->cards; card; card = card->next) {
470         if(card->card == ctype && card->color == ccolor)
471             break;
472     }
473     if(!card) {
474         reply(game->textbot, player->chanuser->user, "NF_UNO_CARD_NOT_IN_DECK");
475         return NULL;
476     }
477     return card;
478 }
479
480 int uno_check_card_valid(struct uno_game *game, struct uno_card *card) {
481     if(game->take_cards_pending && card->card != game->top_card->card)
482         return 1;
483     if(card->color == UNO_COLOR_BLACK || game->top_card->color == UNO_COLOR_BLACK)
484         return 0;
485     if(card->color != game->top_card->color && card->card != game->top_card->card)
486         return 1;
487     return 0;
488 }
489
490 void uno_play_card(struct uno_game *game, struct uno_player *player, struct uno_card *card) {
491     timeq_del(game->timer);
492     game->timer = NULL;
493     if(card->prev)
494         card->prev->next = card->next;
495     else
496         player->cards = card->next;
497     if(card->next)
498         card->next->prev = card->prev;
499     player->count--;
500     if(!game->take_cards_pending) {
501         uno_free_topcard(game->top_card);
502         card->prev = NULL;
503     } else
504         card->prev = game->top_card;
505     card->next = NULL;
506     game->top_card = card;
507     uno_show_top_card(game);
508     if(player->count == 1) {
509         uno_reply(game, NULL, "NF_UNO_ONE_CARD", game->active_player->chanuser->user->nick);
510     } else if(player->count == 0) {
511         uno_reply(game, NULL, "NF_UNO_USER_WIN", game->active_player->chanuser->user->nick);
512         if(player->prev)
513             player->prev->next = player->next;
514         else
515             game->player = player->next;
516         if(player->next)
517             player->next->prev = player->prev;
518         player->next = NULL;
519         player->prev = NULL;
520         struct uno_player *cplayer;
521         int winner_count = 0;
522         if(game->winner) {
523             for(cplayer = game->winner; cplayer->next; cplayer = cplayer->next) {
524                 winner_count++;
525             }
526         } else
527             cplayer = NULL;
528         if(cplayer) {
529             cplayer->next = player;
530         } else {
531             game->winner = player;
532             if((player->chanuser->user->flags & USERFLAG_ISAUTHED)) {
533                 char *tmp;
534                 int win_count = ((tmp = getSetting(player->chanuser->user, game->channel, "uno_win")) ? atoi(tmp) : 0);
535                 int total_win_count = ((tmp = getSetting(player->chanuser->user, NULL, "uno_win")) ? atoi(tmp) : 0);
536                 win_count++;
537                 total_win_count++;
538                 char buf[10];
539                 sprintf(buf, "%d", win_count);
540                 setSetting(player->chanuser->user, game->channel, "uno_win", buf);
541                 sprintf(buf, "%d", total_win_count);
542                 setSetting(player->chanuser->user, NULL, "uno_win", buf);
543             }
544         }
545         player->prev = cplayer;
546         game->players--;
547         if(game->players <= 1) {
548             //game finished
549             uno_reply(game, NULL, "NF_UNO_GAME_FINISHED");
550             struct Table *table;
551             table = table_init(4, winner_count + 3, 0);
552             char *content[4];
553             content[0] = get_language_string(NULL, "NF_UNO_RANK");
554             content[1] = get_language_string(NULL, "NF_UNO_NAME");
555             content[2] = get_language_string(NULL, "NF_UNO_WON_GAMES");
556             content[3] = get_language_string(NULL, "NF_UNO_TOTAL_WON_GAMES");
557             table_add(table, content);
558             winner_count = 1;
559             char rank_buf[20], won_buf[50], total_won_buf[50];
560             char *tmp, *tmp2;
561             for(cplayer = game->winner; cplayer; cplayer = cplayer->next) {
562                 sprintf(rank_buf, "%d", winner_count++);
563                 content[0] = rank_buf;
564                 content[1] = cplayer->chanuser->user->nick;
565                 if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
566                     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));
567                     content[2] = won_buf;
568                     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));
569                     content[3] = total_won_buf;
570                 } else {
571                     content[2] = "?";
572                     content[3] = "?";
573                 }
574                 table_add(table, content);
575             }
576             cplayer = game->player;
577             sprintf(rank_buf, "%d", winner_count++);
578             content[0] = rank_buf;
579             content[1] = cplayer->chanuser->user->nick;
580             if((cplayer->chanuser->user->flags & USERFLAG_ISAUTHED)) {
581                 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));
582                 content[2] = won_buf;
583                 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));
584                 content[3] = total_won_buf;
585             } else {
586                 content[2] = "?";
587                 content[3] = "?";
588             }
589             table_add(table, content);
590             char **table_lines = table_end(table);
591             int i;
592             for(i = 0; i < table->entrys; i++) {
593                 uno_reply(game, NULL, table_lines[i]);
594             }
595             table_free(table);
596             uno_free_game(game);
597             return;
598         }
599     }
600     if(card->card == UNO_CARD_DIRECTION)
601         game->reverse_direction = (game->reverse_direction ? 0 : 1);
602     struct uno_player *next_player = uno_get_next_player(game);
603     game->active_player = next_player;
604     if(card->card == UNO_CARD_SKIP) {
605         uno_reply(game, NULL, "NF_UNO_USER_SKIP", game->active_player->chanuser->user->nick);
606         next_player = uno_get_next_player(game);
607         game->active_player = next_player;
608     }
609     if(card->card == UNO_CARD_ADD_2 || card->card == UNO_CARD_ADD_4) {
610         int ccount = 0;
611         for(card = game->top_card; card; card = card->prev) {
612             if(card->card == UNO_CARD_ADD_2)
613                 ccount += 2;
614             else if(card->card == UNO_CARD_ADD_4)
615                 ccount += 4;
616         }
617         uno_reply(game, NULL, "NF_UNO_ADD_CARD", game->active_player->chanuser->user->nick, ccount);
618         game->take_cards_pending = 1;
619     }
620     uno_reply(game, NULL, "NF_UNO_USER_HURRY_UP", game->active_player->chanuser->user->nick);
621     uno_show_player_cards(game, game->active_player);
622     game->timer = timeq_add(30, module_id, uno_player_timeout, game);
623 }
624
625 void uno_event_part(struct ChanUser *chanuser) {
626     struct uno_game *game;
627     for(game = uno_active_games; game; game = game->next) {
628         if(chanuser->chan == game->channel) {
629             struct uno_player *player;
630             for(player = game->player; player; player = player->next) {
631                 if(player->chanuser == chanuser) {
632                     uno_free_player(player, game->deck);
633                     return;
634                 }
635             }
636         }
637     }
638 }
639
640 void uno_event_freechan(struct ChanNode *chan) {
641     struct uno_game *game;
642     for(game = uno_active_games; game; game = game->next) {
643         if(game->channel == chan) {
644             uno_free_game(game);
645             return;
646         }
647     }
648 }