added blackjack game
[NeonServV5.git] / src / modules / NeonFun.mod / game_blackjack.c
1 /* game_blackjack.c - NeonServ v5.6
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_blackjack.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 bj_game *bj_active_games = NULL;
28
29 static int bj_ctype[] =         {BJ_CTYPE_HEARTS, BJ_CTYPE_SPADES, BJ_CTYPE_DIAMONDS, BJ_CTYPE_CLUBS};
30 static int bj_irc_colors[] =    {4,               1,               4,                 1};
31 static char *bj_color_chars[] = {"\xE2\x9D\xA4",  "\xE2\x99\xA0",  "\xE2\x99\xA6",    "\xE2\x99\xA3"};
32
33 static const struct {
34     const char *name;
35     unsigned char type;
36     unsigned int points : 8;
37 } bj_card_types[] = {
38     {"2",  BJ_CARD_NUMBER_2,  2},
39     {"3",  BJ_CARD_NUMBER_3,  3},
40     {"4",  BJ_CARD_NUMBER_4,  4},
41     {"5",  BJ_CARD_NUMBER_5,  5},
42     {"6",  BJ_CARD_NUMBER_6,  6},
43     {"7",  BJ_CARD_NUMBER_7,  7},
44     {"8",  BJ_CARD_NUMBER_8,  8},
45     {"9",  BJ_CARD_NUMBER_9,  9},
46     {"10", BJ_CARD_NUMBER_10, 10},
47     {"J",  BJ_CARD_JACK,      10},
48     {"Q",  BJ_CARD_QUEEN,     10},
49     {"K",  BJ_CARD_KING,      10},
50     {"A",  BJ_CARD_ACE,       11},
51     {NULL, 0}
52 };
53
54 struct bj_card_deck *bj_shuffle_deck() {
55     struct bj_card *card, *last_card = NULL;
56     int card_count = 0;
57     #define ADD_CARD(ctype,ccard) \
58     card = malloc(sizeof(*card)); \
59     card->type = ctype; \
60     card->card = ccard; \
61     card->prev = NULL; \
62     card->next = last_card; \
63     if(last_card) \
64         last_card->prev = card; \
65     last_card = card; \
66     card_count++;
67     int typecount = BJ_CTYPE_COUNT;
68     for(typecount--; typecount >= 0; typecount--) {
69         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_2);
70         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_3);
71         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_4);
72         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_5);
73         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_6);
74         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_7);
75         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_8);
76         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_9);
77         ADD_CARD(bj_ctype[typecount], BJ_CARD_NUMBER_10);
78         ADD_CARD(bj_ctype[typecount], BJ_CARD_JACK);
79         ADD_CARD(bj_ctype[typecount], BJ_CARD_QUEEN);
80         ADD_CARD(bj_ctype[typecount], BJ_CARD_KING);
81         ADD_CARD(bj_ctype[typecount], BJ_CARD_ACE);
82     }
83     #undef ADD_CARD
84     struct bj_card_deck *deck = malloc(sizeof(*deck));
85     deck->cards = last_card;
86     deck->count = card_count;
87     return deck;
88 }
89
90 struct bj_card *bj_get_card(struct bj_card_deck *deck) {
91     if(!deck->count) return NULL;
92     int card_id = (rand() % deck->count);
93     int i = 0;
94     struct bj_card *card;
95     for(card = deck->cards; card; card = card->next) {
96         if(i == card_id) {
97             if(card->prev)
98                 card->prev->next = card->next;
99             else
100                 deck->cards = card->next;
101             if(card->next)
102                 card->next->prev = card->prev;
103             deck->count--;
104             card->next = NULL;
105             card->prev = NULL;
106             return card;
107         }
108         i++;
109     }
110     return NULL;
111 }
112
113 void bj_free_deck(struct bj_card_deck *deck) {
114     struct bj_card *card, *next_card;
115     if(deck->count) {
116         for(card = deck->cards; card; card = next_card) {
117             next_card = card->next;
118             free(card);
119         }
120     }
121     free(deck);
122 }
123
124 void bj_free_player(struct bj_player *player, struct bj_card_deck *deck) {
125     if(player->count) {
126         struct bj_card *card, *next_card;
127         for(card = player->cards; card; card = next_card) {
128             next_card = card->next;
129             if(deck) {
130                 card->next = deck->cards;
131                 deck->cards->prev = card;
132                 deck->cards = card;
133                 deck->count++;
134             } else
135                 free(card);
136         }
137     }
138     if(player->prev)
139         player->prev->next = player->next;
140     if(player->next)
141         player->next->prev = player->prev;
142     free(player);
143 }
144
145 void bj_free_game(struct bj_game *game) {
146     struct bj_player *player, *next_player;
147     for(player = game->player; player; player = next_player) {
148         next_player = player->next;
149         bj_free_player(player, NULL);
150     }
151     if(game->deck)
152         bj_free_deck(game->deck);
153     if(game->timer)
154         timeq_del(game->timer);
155     struct bj_game *cgame, *pgame = NULL;
156     for(cgame = bj_active_games; cgame; cgame = cgame->next) {
157         if(cgame == game) {
158             if(pgame)
159                 pgame->next = game->next;
160             else
161                 bj_active_games = game->next;
162             break;
163         } else
164             pgame = cgame;
165     }
166     free(game);
167 }
168
169 struct bj_player *bj_get_next_player(struct bj_game *game) {
170     struct bj_player *player = game->active_player;
171     player = player->next;
172     return player;
173 }
174
175 int bj_get_player_card_points(struct bj_player *player) {
176     int i, points = 0, ace_count = 0;
177     struct bj_card *card;
178     for(card = player->cards; card; card = card->next) {
179         if(card->card == BJ_CARD_ACE) {
180             ace_count++; //add these points later ;)
181             continue;
182         }
183         i = 0;
184         while(bj_card_types[i].name) {
185             if(bj_card_types[i].type == card->card) {
186                 points += bj_card_types[i].points;
187                 break;
188             }
189             i++;
190         }
191     }
192     while((ace_count--) > 0) {
193         if(points <= 10)
194             points += 11;
195         else
196             points += 1;
197     }
198     return points;
199 }
200
201 static void bj_print_player_cards(struct bj_player *player, char *cards_buf) {
202     struct bj_card *card;
203     int cards_bufpos = 0;
204     for(card = player->cards; card; card = card->next) {
205         int cardcolor = 1;
206         char *cardchar = "";
207         int i;
208         for(i = 0; i < BJ_CTYPE_COUNT; i++) {
209             if(bj_ctype[i] == card->type) {
210                 cardcolor = bj_irc_colors[i];
211                 cardchar = bj_color_chars[i];
212                 break;
213             }
214         }
215         i = 0;
216         while(bj_card_types[i].name) {
217             if(bj_card_types[i].type == card->card) {
218                 cards_bufpos += sprintf(cards_buf + cards_bufpos, "%s[\003%d%s%s\003]", (cards_bufpos ? " " : ""), cardcolor, cardchar, bj_card_types[i].name);
219                 break;
220             }
221             i++;
222         }
223     }
224 }
225
226 void bj_show_player_cards(struct bj_game *game, struct bj_player *player) {
227     char cards_buf[MAXLEN];
228     bj_print_player_cards(player, cards_buf);
229     int card_points = bj_get_player_card_points(player);
230     reply(game->textbot, player->chanuser->user, "NF_BJ_YOUR_CARDS", card_points, cards_buf);
231 }
232
233 TIMEQ_CALLBACK(bj_game_wait_timeout) {
234     struct bj_game *game = data;
235     game->timer = NULL;
236     if(game->players == 1) {
237         bj_reply(game, NULL, "NF_BJ_LESS_PLAYERS");
238         bj_free_game(game);
239         return;
240     }
241     game->deck = bj_shuffle_deck();
242     bj_reply(game, NULL, "NF_BJ_START");
243     game->state = BJ_STATE_RUNNING;
244     game->active_player = game->player; //active player
245     bj_reply(game, NULL, "NF_BJ_USER_HURRY_UP", game->active_player->chanuser->user->nick);
246     game->timer = timeq_add(30, module_id, bj_player_timeout, game);
247 }
248
249 TIMEQ_CALLBACK(bj_player_timeout) {
250     struct bj_game *game = data;
251     game->timer = NULL;
252     //player timeout (next player)
253     struct bj_player *player = game->active_player;
254     bj_reply(game, NULL, "NF_BJ_USER_TIMEOUT", player->chanuser->user->nick);
255     bj_action_next_player(game, player);
256 }
257
258 void bj_action_take_card(struct bj_game *game, struct bj_player *player) {
259     int points = bj_get_player_card_points(player);
260     if(points > 21) {
261         reply(game->textbot, player->chanuser->user, "NF_BJ_POINTS_EXCEEDED");
262         return;
263     }
264     if(game->timer) {
265         timeq_del(game->timer);
266         game->timer = NULL;
267     }
268     struct bj_card *card = bj_get_card(game->deck);
269     if(!card) {
270         bj_free_deck(game->deck);
271         game->deck = bj_shuffle_deck();
272         card = bj_get_card(game->deck);
273     }
274     struct bj_card *last_card;
275     for(last_card = player->cards; last_card; last_card = last_card->next) {
276         if(last_card->next == NULL)
277             break;
278     }
279     card->prev = last_card;
280     if(last_card)
281         last_card->next = card;
282     else
283         player->cards = card;
284     player->count++;
285     char cardbuf[16];
286     int cardcolor = 1;
287     char *cardchar = "";
288     int i, cardpoints = 0;
289     cardbuf[0] = '\0';
290     for(i = 0; i < BJ_CTYPE_COUNT; i++) {
291         if(bj_ctype[i] == card->type) {
292             cardcolor = bj_irc_colors[i];
293             cardchar = bj_color_chars[i];
294             break;
295         }
296     }
297     i = 0;
298     while(bj_card_types[i].name) {
299         if(bj_card_types[i].type == card->card) {
300             sprintf(cardbuf, "[\003%d%s%s\003]", cardcolor, cardchar, bj_card_types[i].name);
301             cardpoints = bj_card_types[i].points;
302             if(bj_card_types[i].type == BJ_CARD_ACE && points > 10)
303                 cardpoints = 1;
304             break;
305         }
306         i++;
307     }
308     reply(game->textbot, player->chanuser->user, "NF_BJ_TAKE", cardbuf, cardpoints);
309     bj_show_player_cards(game, player);
310     if(points + cardpoints > 21)
311         reply(game->textbot, player->chanuser->user, "NF_BJ_POINTS_EXCEEDED");
312     game->timer = timeq_add(30, module_id, bj_player_timeout, game);
313 }
314
315 void bj_action_next_player(struct bj_game *game, struct bj_player *player) {
316     if(game->timer) {
317         timeq_del(game->timer);
318         game->timer = NULL;
319     }
320     if(player)
321         bj_show_player_cards(game, player);
322     game->active_player = bj_get_next_player(game);
323     if(game->active_player) {
324         bj_reply(game, NULL, "NF_BJ_USER_HURRY_UP", game->active_player->chanuser->user->nick);
325         game->timer = timeq_add(30, module_id, bj_player_timeout, game);
326     } else {
327         bj_game_end(game);
328         bj_free_game(game);
329     }
330 }
331
332 void bj_event_part(struct ChanUser *chanuser) {
333     struct bj_game *game;
334     for(game = bj_active_games; game; game = game->next) {
335         if(chanuser->chan == game->channel) {
336             struct bj_player *player;
337             for(player = game->player; player; player = player->next) {
338                 if(player->chanuser == chanuser) {
339                     if(game->active_player == player) {
340                         if(bj_get_next_player(game) == NULL) {
341                             bj_game_end(game);
342                             bj_free_game(game);
343                             return;
344                         } else
345                             bj_action_next_player(game, NULL);
346                     }
347                     game->players--;
348                     bj_free_player(player, game->deck);
349                     return;
350                 }
351             }
352         }
353     }
354 }
355
356 void bj_event_freechan(struct ChanNode *chan) {
357     struct bj_game *game;
358     for(game = bj_active_games; game; game = game->next) {
359         if(game->channel == chan) {
360             bj_free_game(game);
361             return;
362         }
363     }
364 }
365
366 static int bj_highscore_sort(const void *a, const void *b) {
367     const struct bj_player *player_a = *((struct bj_player * const *) a);
368     const struct bj_player *player_b = *((struct bj_player * const *) b); 
369     int points_a, points_b;
370     if(player_a->count > 21)
371         points_a = player_a->count * -1;
372     else
373         points_a = player_a->count;
374     if(player_b->count > 21)
375         points_b = player_b->count * -1;
376     else
377         points_b = player_b->count;
378     return points_b - points_a;
379 }
380
381 void bj_game_end(struct bj_game *game) {
382     bj_reply(game, NULL, "NF_BJ_GAME_FINISHED");
383     struct Table *table;
384     table = table_init(4, game->players+1, 0);
385     char *content[4];
386     content[0] = get_language_string(NULL, "NF_BJ_RANK");
387     content[1] = get_language_string(NULL, "NF_BJ_NAME");
388     content[2] = get_language_string(NULL, "NF_BJ_POINTS");
389     content[3] = get_language_string(NULL, "NF_BJ_CARDS");
390     table_add(table, content);
391     //sort users
392     struct bj_player *players[game->players];
393     struct bj_player *player;
394     int i = 0;
395     for(player = game->player; player; player = player->next) {
396         player->count = bj_get_player_card_points(player);
397         players[i++] = player;
398     }
399     qsort(players, game->players, sizeof(struct bj_player *), bj_highscore_sort);
400     char rankbuf[12];
401     char pointbuf[12];
402     char cardsbuf[MAXLEN];
403     for(i = 0; i < game->players; i++) {
404         player = players[i];
405         sprintf(rankbuf, "#%d", i+1);
406         content[0] = rankbuf;
407         content[1] = player->chanuser->user->nick;
408         sprintf(pointbuf, "%d", player->count);
409         content[2] = pointbuf;
410         bj_print_player_cards(player, cardsbuf);
411         content[3] = cardsbuf;
412         table_add(table, content);
413     }
414     char **table_lines = table_end(table);
415     for(i = 0; i < table->entrys; i++) {
416         bj_reply(game, NULL, table_lines[i]);
417     }
418     table_free(table);
419 }