1 /*
2 * Copyright (C) 1998 Mark Baysinger (mbaysing@ucsd.edu)
3 * Copyright (C) 1998,1999,2000 Ross Combs (rocombs@cs.nmsu.edu)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 #define GAME_INTERNAL_ACCESS
20 #include "common/setup_before.h"
21 #include <stdio.h>
22 #ifdef HAVE_STDDEF_H
23 # include <stddef.h>
24 #else
25 # ifndef NULL
26 # define NULL ((void *)0)
27 # endif
28 #endif
29 #ifdef STDC_HEADERS
30 # include <stdlib.h>
31 #else
32 # ifdef HAVE_MALLOC_H
33 # include <malloc.h>
34 # endif
35 #endif
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #else
39 # ifdef HAVE_STRINGS_H
40 # include <strings.h>
41 # endif
42 #endif
43 #include "compat/strdup.h"
44 #include "compat/strcasecmp.h"
45 #include <errno.h>
46 #include "compat/strerror.h"
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50 #ifdef TIME_WITH_SYS_TIME
51 # include <sys/time.h>
52 # include <time.h>
53 #else
54 # ifdef HAVE_SYS_TIME_H
55 # include <sys/time.h>
56 # else
57 # include <time.h>
58 # endif
59 #endif
60 #include "compat/difftime.h"
61 #ifdef HAVE_SYS_TYPES_H
62 # include <sys/types.h>
63 #endif
64 #ifdef HAVE_ASSERT_H
65 # include <assert.h>
66 #endif
67 #include "common/eventlog.h"
68 #include "prefs.h"
69 #include "connection.h"
70 #include "account.h"
71 #include "account_wrap.h"
72 #include "ladder.h"
73 #include "ladder_calc.h"
74 #include "common/bnettime.h"
75 #include "common/util.h"
76 #include "common/elist.h"
77 #include "common/tag.h"
78 #include "common/addr.h"
79 #include "common/xalloc.h"
80 #include "realm.h"
81 #include "watch.h"
82 #include "game_conv.h"
83 #include "game.h"
84 #include "server.h"
85 #include "compat/uint.h"
86 #include "compat/rename.h"
87 #include "common/setup_after.h"
88
89 DECLARE_ELIST_INIT(gamelist_head);
90 static int glist_length=0;
91 static int totalcount=0;
92
93
94 static void game_choose_host(t_game * game);
95 static void game_destroy(t_game * game);
96 static int game_report(t_game * game);
97
98
game_choose_host(t_game * game)99 static void game_choose_host(t_game * game)
100 {
101 unsigned int i;
102
103 if (game->count<1)
104 {
105 eventlog(eventlog_level_error,__FUNCTION__,"game has had no connections?!");
106 return;
107 }
108 if (!game->connections)
109 {
110 eventlog(eventlog_level_error,__FUNCTION__,"game has NULL connections array");
111 return;
112 }
113
114 for (i=0; i<game->count; i++)
115 if (game->connections[i])
116 {
117 game->owner = game->connections[i];
118 game->addr = conn_get_game_addr(game->connections[i]);
119 game->port = conn_get_game_port(game->connections[i]);
120 return;
121 }
122 eventlog(eventlog_level_warn,__FUNCTION__,"no valid connections found");
123 }
124
125
game_type_get_str(t_game_type type)126 extern char const * game_type_get_str(t_game_type type)
127 {
128 switch (type)
129 {
130 case game_type_none:
131 return "NONE";
132
133 case game_type_melee:
134 return "melee";
135
136 case game_type_topvbot:
137 return "top vs bottom";
138
139 case game_type_ffa:
140 return "free for all";
141
142 case game_type_oneonone:
143 return "one on one";
144
145 case game_type_ctf:
146 return "capture the flag";
147
148 case game_type_greed:
149 return "greed";
150
151 case game_type_slaughter:
152 return "slaughter";
153
154 case game_type_sdeath:
155 return "sudden death";
156
157 case game_type_ladder:
158 return "ladder";
159
160 case game_type_ironman:
161 return "ironman";
162
163 case game_type_mapset:
164 return "mapset";
165
166 case game_type_teammelee:
167 return "team melee";
168
169 case game_type_teamffa:
170 return "team free for all";
171
172 case game_type_teamctf:
173 return "team capture the flag";
174
175 case game_type_pgl:
176 return "PGL";
177
178 case game_type_diablo:
179 return "Diablo";
180
181 case game_type_diablo2open:
182 return "Diablo II (open)";
183
184 case game_type_diablo2closed:
185 return "Diablo II (closed)";
186
187 case game_type_all:
188 default:
189 return "UNKNOWN";
190 }
191 }
192
193
game_status_get_str(t_game_status status)194 extern char const * game_status_get_str(t_game_status status)
195 {
196 switch (status)
197 {
198 case game_status_started:
199 return "started";
200
201 case game_status_full:
202 return "full";
203
204 case game_status_open:
205 return "open";
206
207 case game_status_done:
208 return "done";
209
210 case game_status_loaded:
211 return "loaded";
212
213 default:
214 return "UNKNOWN";
215 }
216 }
217
218
game_result_get_str(t_game_result result)219 extern char const * game_result_get_str(t_game_result result)
220 {
221 switch (result)
222 {
223 case game_result_none:
224 return "NONE";
225
226 case game_result_win:
227 return "WIN";
228
229 case game_result_loss:
230 return "LOSS";
231
232 case game_result_draw:
233 return "DRAW";
234
235 case game_result_disconnect:
236 return "DISCONNECT";
237
238 case game_result_observer:
239 return "OBSERVER";
240
241 default:
242 return "UNKNOWN";
243 }
244 }
245
246
game_option_get_str(t_game_option option)247 extern char const * game_option_get_str(t_game_option option)
248 {
249 switch (option)
250 {
251 case game_option_melee_normal:
252 return "normal";
253 case game_option_ffa_normal:
254 return "normal";
255 case game_option_oneonone_normal:
256 return "normal";
257 case game_option_ctf_normal:
258 return "normal";
259 case game_option_greed_10000:
260 return "10000 minerals";
261 case game_option_greed_7500:
262 return "7500 minerals";
263 case game_option_greed_5000:
264 return "5000 minerals";
265 case game_option_greed_2500:
266 return "2500 minerals";
267 case game_option_slaughter_60:
268 return "60 minutes";
269 case game_option_slaughter_45:
270 return "45 minutes";
271 case game_option_slaughter_30:
272 return "30 minutes";
273 case game_option_slaughter_15:
274 return "15 minutes";
275 case game_option_sdeath_normal:
276 return "normal";
277 case game_option_ladder_countasloss:
278 return "count as loss";
279 case game_option_ladder_nopenalty:
280 return "no penalty";
281 case game_option_mapset_normal:
282 return "normal";
283 case game_option_teammelee_4:
284 return "4 teams";
285 case game_option_teammelee_3:
286 return "3 teams";
287 case game_option_teammelee_2:
288 return "2 teams";
289 case game_option_teamffa_4:
290 return "4 teams";
291 case game_option_teamffa_3:
292 return "3 teams";
293 case game_option_teamffa_2:
294 return "2 teams";
295 case game_option_teamctf_4:
296 return "4 teams";
297 case game_option_teamctf_3:
298 return "3 teams";
299 case game_option_teamctf_2:
300 return "2 teams";
301 case game_option_topvbot_7:
302 return "7 vs all";
303 case game_option_topvbot_6:
304 return "6 vs all";
305 case game_option_topvbot_5:
306 return "5 vs all";
307 case game_option_topvbot_4:
308 return "4 vs all";
309 case game_option_topvbot_3:
310 return "3 vs all";
311 case game_option_topvbot_2:
312 return "2 vs all";
313 case game_option_topvbot_1:
314 return "1 vs all";
315
316 case game_option_none:
317 return "none";
318 default:
319 return "UNKNOWN";
320 }
321 }
322
323
game_maptype_get_str(t_game_maptype maptype)324 extern char const * game_maptype_get_str(t_game_maptype maptype)
325 {
326 switch (maptype)
327 {
328 case game_maptype_selfmade:
329 return "Self-Made";
330 case game_maptype_blizzard:
331 return "Blizzard";
332 case game_maptype_ladder:
333 return "Ladder";
334 case game_maptype_pgl:
335 return "PGL";
336 case game_maptype_kbk:
337 return "KBK";
338 case game_maptype_compusa:
339 return "CompUSA";
340 default:
341 return "Unknown";
342 }
343 }
344
345
game_tileset_get_str(t_game_tileset tileset)346 extern char const * game_tileset_get_str(t_game_tileset tileset)
347 {
348 switch (tileset)
349 {
350 case game_tileset_badlands:
351 return "Badlands";
352 case game_tileset_space:
353 return "Space";
354 case game_tileset_installation:
355 return "Installation";
356 case game_tileset_ashworld:
357 return "Ash World";
358 case game_tileset_jungle:
359 return "Jungle";
360 case game_tileset_desert:
361 return "Desert";
362 case game_tileset_ice:
363 return "Ice";
364 case game_tileset_twilight:
365 return "Twilight";
366 default:
367 return "Unknown";
368 }
369 }
370
371
game_speed_get_str(t_game_speed speed)372 extern char const * game_speed_get_str(t_game_speed speed)
373 {
374 switch (speed)
375 {
376 case game_speed_slowest:
377 return "slowest";
378 case game_speed_slower:
379 return "slower";
380 case game_speed_slow:
381 return "slow";
382 case game_speed_normal:
383 return "normal";
384 case game_speed_fast:
385 return "fast";
386 case game_speed_faster:
387 return "faster";
388 case game_speed_fastest:
389 return "fastest";
390 default:
391 return "unknown";
392 }
393 }
394
395
game_difficulty_get_str(t_game_difficulty difficulty)396 extern char const * game_difficulty_get_str(t_game_difficulty difficulty)
397 {
398 switch (difficulty)
399 {
400 case game_difficulty_normal:
401 return "normal";
402 case game_difficulty_nightmare:
403 return "nightmare";
404 case game_difficulty_hell:
405 return "hell";
406 case game_difficulty_hardcore_normal:
407 return "hardcore normal";
408 case game_difficulty_hardcore_nightmare:
409 return "hardcore nightmare";
410 case game_difficulty_hardcore_hell:
411 return "hardcore hell";
412 default:
413 return "unknown";
414 }
415 }
416
417
game_create(char const * name,char const * pass,char const * info,t_game_type type,int startver,t_clienttag clienttag,unsigned long gameversion)418 extern t_game * game_create(char const * name, char const * pass, char const * info, t_game_type type, int startver, t_clienttag clienttag, unsigned long gameversion)
419 {
420 t_game * game;
421
422 if (!name)
423 {
424 eventlog(eventlog_level_info,__FUNCTION__,"got NULL game name");
425 return NULL;
426 }
427 if (!pass)
428 {
429 eventlog(eventlog_level_info,__FUNCTION__,"got NULL game pass");
430 return NULL;
431 }
432 if (!info)
433 {
434 eventlog(eventlog_level_info,__FUNCTION__,"got NULL game info");
435 return NULL;
436 }
437
438 if (gamelist_find_game(name, clienttag, game_type_all))
439 {
440 eventlog(eventlog_level_info,__FUNCTION__,"game \"%s\" not created because it already exists",name);
441 return NULL; /* already have a game by that name */
442 }
443
444 game = xmalloc(sizeof(t_game));
445 game->name = xstrdup(name);
446 game->pass = xstrdup(pass);
447 game->info = xstrdup(info);
448 if (!(game->clienttag = clienttag))
449 {
450 eventlog(eventlog_level_error,__FUNCTION__,"got UNKNOWN clienttag");
451 xfree((void *)game->info); /* avoid warning */
452 xfree((void *)game->pass); /* avoid warning */
453 xfree((void *)game->name); /* avoid warning */
454 xfree(game);
455 return NULL;
456 }
457
458 game->type = type;
459 game->addr = 0; /* will be set by first player */
460 game->port = 0; /* will be set by first player */
461 game->version = gameversion;
462 game->startver = startver; /* start packet version */
463 game->status = game_status_open;
464 game->realm = 0;
465 game->realmname = NULL;
466 game->id = ++totalcount;
467 game->mapname = NULL;
468 game->ref = 0;
469 game->count = 0;
470 game->owner = NULL;
471 game->connections = NULL;
472 game->players = NULL;
473 game->results = NULL;
474 game->reported_results = NULL;
475 game->report_heads = NULL;
476 game->report_bodies = NULL;
477 game->create_time = now;
478 game->start_time = (time_t)0;
479 game->lastaccess_time = now;
480 game->option = game_option_none;
481 game->maptype = game_maptype_none;
482 game->tileset = game_tileset_none;
483 game->speed = game_speed_none;
484 game->mapsize_x = 0;
485 game->mapsize_y = 0;
486 game->maxplayers = 0;
487 game->bad = 0;
488 game->description = NULL;
489 game->flag = strcmp(pass,"") ? game_flag_private : game_flag_none;
490 game->difficulty = game_difficulty_none;
491
492 game_parse_info(game,info);
493
494 elist_add(&gamelist_head,&game->glist_link);
495 glist_length++;
496
497 eventlog(eventlog_level_info,__FUNCTION__,"game \"%s\" (pass \"%s\") type %hu(%s) startver %d created",name,pass,(unsigned short)type,game_type_get_str(game->type),startver);
498
499 return game;
500 }
501
502
game_destroy(t_game * game)503 static void game_destroy(t_game * game)
504 {
505 unsigned int i;
506
507 if (!game)
508 {
509 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
510 return;
511 }
512
513 elist_del(&game->glist_link);
514 glist_length--;
515
516 if (game->realmname)
517 {
518 realm_add_game_number(realmlist_find_realm(game->realmname),-1);
519 }
520
521 eventlog(eventlog_level_debug,__FUNCTION__,"game \"%s\" (count=%u ref=%u) removed from list...",game_get_name(game),game->count,game->ref);
522
523 for (i=0; i<game->count; i++)
524 {
525 if (game->report_bodies && game->report_bodies[i])
526 xfree((void *)game->report_bodies[i]); /* avoid warning */
527 if (game->report_heads && game->report_heads[i])
528 xfree((void *)game->report_heads[i]); /* avoid warning */
529 if (game->reported_results && game->reported_results[i])
530 xfree((void *)game->reported_results[i]);
531 }
532 if (game->realmname)
533 xfree((void *)game->realmname); /* avoid warining */
534 if (game->report_bodies)
535 xfree((void *)game->report_bodies); /* avoid warning */
536 if (game->report_heads)
537 xfree((void *)game->report_heads); /* avoid warning */
538 if (game->results)
539 xfree((void *)game->results); /* avoid warning */
540 if (game->reported_results)
541 xfree((void *)game->reported_results);
542 if (game->connections)
543 xfree((void *)game->connections); /* avoid warning */
544 if (game->players)
545 xfree((void *)game->players); /* avoid warning */
546 if (game->mapname)
547 xfree((void *)game->mapname); /* avoid warning */
548 if (game->description)
549 xfree((void *)game->description); /* avoid warning */
550
551 xfree((void *)game->info); /* avoid warning */
552 xfree((void *)game->pass); /* avoid warning */
553 if (game->name) xfree((void *)game->name); /* avoid warning */
554 xfree((void *)game); /* avoid warning */
555
556 eventlog(eventlog_level_info,__FUNCTION__,"game deleted");
557
558 return;
559 }
560
game_evaluate_results(t_game * game)561 static int game_evaluate_results(t_game * game)
562 {
563 unsigned int i,j;
564 unsigned int wins, losses, draws, disconnects, reports;
565
566 if (!game)
567 {
568 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
569 return -1;
570 }
571 if (!game->results)
572 {
573 eventlog(eventlog_level_error,__FUNCTION__,"results array is NULL");
574 return -1;
575 }
576
577 if (!game->reported_results)
578 {
579 eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
580 return -1;
581 }
582
583 for (i=0;i<game->count;i++)
584 {
585 wins = losses = draws = disconnects = reports = 0;
586
587 for (j=0;j<game->count;j++)
588 {
589 if (game->reported_results[j])
590 {
591 switch (game->reported_results[j][i])
592 {
593 case game_result_win:
594 wins++;
595 reports++;
596 break;
597 case game_result_loss:
598 losses++;
599 reports++;
600 break;
601 case game_result_draw:
602 draws++;
603 reports++;
604 break;
605 case game_result_disconnect:
606 disconnects++;
607 reports++;
608 break;
609 default:
610 break;
611 }
612 }
613 }
614 eventlog(eventlog_level_debug,__FUNCTION__,"wins: %u losses: %u draws: %u disconnects: %u",wins,losses,draws,disconnects);
615
616 //now decide what result we give
617 if (!(reports)) // no results at all - game canceled before starting
618 {
619 game->results[i] = game_result_none;
620 eventlog(eventlog_level_debug,__FUNCTION__,"deciding to give \"none\" to player %d",i);
621 }
622 else if ((disconnects>=draws) && (disconnects>=losses) && (disconnects>=wins))
623 {
624 game->results[i] = game_result_disconnect; //consider disconnects the worst case...
625 eventlog(eventlog_level_debug,__FUNCTION__,"deciding to give \"disconnect\" to player %d",i);
626 }
627 else if ((losses>=wins) && (losses>=draws))
628 {
629 game->results[i]=game_result_loss; //losses are also bad...
630 eventlog(eventlog_level_debug,__FUNCTION__,"deciding to give \"loss\" to player %d",i);
631 }
632 else if ((draws>=wins))
633 {
634 game->results[i]=game_result_draw;
635 eventlog(eventlog_level_debug,__FUNCTION__,"deciding to give \"draw\" to player %d",i);
636 }
637 else if (wins)
638 {
639 game->results[i]=game_result_win;
640 eventlog(eventlog_level_debug,__FUNCTION__,"deciding to give \"win\" to player %d",i);
641 }
642 }
643 return 0;
644 }
645
game_match_type(t_game_type type,const char * gametypes)646 static int game_match_type(t_game_type type,const char *gametypes)
647 {
648 char *p, *q;
649 int res;
650
651 if (!gametypes || !gametypes[0]) return 0;
652
653 gametypes = p = xstrdup(gametypes);
654 res = 0;
655 do {
656 q = strchr(p,',');
657 if (q) *q = '\0';
658 if (!strcasecmp(p,"topvbot")) {
659 if (type == game_type_topvbot) { res = 1; break; }
660 } else if (!strcasecmp(p,"melee")) {
661 if (type == game_type_melee) { res = 1; break; }
662 } else if (!strcasecmp(p,"ffa")) {
663 if (type == game_type_ffa) { res = 1; break; }
664 } else if (!strcasecmp(p,"oneonone")) {
665 if (type == game_type_oneonone) { res = 1; break; }
666 }
667 if (q) p = q + 1;
668 } while(q);
669
670 free((void*)gametypes);
671 return res;
672 }
673
game_report(t_game * game)674 static int game_report(t_game * game)
675 {
676 FILE * fp;
677 char * realname;
678 char * tempname;
679 unsigned int i;
680 unsigned int realcount;
681 t_ladder_info * ladder_info=NULL;
682 int discisloss;
683 char clienttag_str[5];
684
685 if (!game)
686 {
687 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
688 return -1;
689 }
690 if (!game->clienttag)
691 {
692 eventlog(eventlog_level_error,__FUNCTION__,"got UNKNOWN clienttag");
693 return -1;
694 }
695 if (!game->players)
696 {
697 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
698 return -1;
699 }
700 if (!game->reported_results)
701 {
702 eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
703 return -1;
704 }
705 if (!game->results)
706 {
707 eventlog(eventlog_level_error,__FUNCTION__,"results array is NULL");
708 return -1;
709 }
710
711 if (prefs_get_discisloss()==1 || game->option==game_option_ladder_countasloss)
712 discisloss = 1;
713 else
714 discisloss = 0;
715
716 if (game->clienttag==CLIENTTAG_WARCRAFT3_UINT || game->clienttag==CLIENTTAG_WAR3XP_UINT)
717 // war3 game reporting is done elsewhere, so we can skip this function
718 return 0;
719
720 if (game->clienttag==CLIENTTAG_DIABLOSHR_UINT ||
721 game->clienttag==CLIENTTAG_DIABLORTL_UINT ||
722 game->clienttag==CLIENTTAG_DIABLO2ST_UINT ||
723 game->clienttag==CLIENTTAG_DIABLO2DV_UINT ||
724 game->clienttag==CLIENTTAG_DIABLO2XP_UINT)
725 {
726 if (prefs_get_report_diablo_games() == 1)
727 /* diablo games have transient players and no reported winners/losers */
728 realcount = 0;
729 else
730 {
731 eventlog(eventlog_level_info,__FUNCTION__,"diablo gamereport disabled: ignoring game");
732 return 0;
733 }
734 }
735 else
736 {
737 game_evaluate_results(game); // evaluate results from the reported results
738 /* "compact" the game; move all the real players to the top... */
739 realcount = 0;
740 for (i=0; i<game->count; i++)
741 {
742 if (!game->players[i])
743 {
744 eventlog(eventlog_level_error,__FUNCTION__,"player slot %u has NULL account",i);
745 continue;
746 }
747
748 if (game->results[i]!=game_result_none)
749 {
750 game->players[realcount] = game->players[i];
751 game->results[realcount] = game->results[i];
752 game->report_heads[realcount] = game->report_heads[i];
753 game->report_bodies[realcount] = game->report_bodies[i];
754 realcount++;
755 }
756 }
757
758 /* then nuke duplicate players after the real players */
759 for (i=realcount; i<game->count; i++)
760 {
761 game->players[i] = NULL;
762 game->results[i] = game_result_none;
763 game->report_heads[i] = NULL;
764 game->report_bodies[i] = NULL;
765 }
766
767 if (realcount<1)
768 {
769 eventlog(eventlog_level_info,__FUNCTION__,"ignoring game");
770 return -1;
771 }
772 }
773
774 eventlog(eventlog_level_debug,__FUNCTION__,"realcount=%d count=%u",realcount,game->count);
775
776 if (realcount>=1 && !game->bad)
777 {
778 if (game_is_ladder(game)
779 )
780 {
781 t_ladder_id id;
782
783 if (game_get_type(game)==game_type_ironman)
784 id = ladder_id_ironman;
785 else
786 id = ladder_id_normal;
787
788 for (i=0; i<realcount; i++)
789 {
790 eventlog(eventlog_level_debug,__FUNCTION__,"realplayer %u result=%u",i+1,(unsigned int)game->results[i]);
791
792 ladder_init_account(game->players[i],game->clienttag,id);
793
794 switch (game->results[i])
795 {
796 case game_result_win:
797 account_inc_ladder_wins(game->players[i],game->clienttag,id);
798 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_win));
799 break;
800 case game_result_loss:
801 account_inc_ladder_losses(game->players[i],game->clienttag,id);
802 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_loss));
803 break;
804 case game_result_draw:
805 account_inc_ladder_draws(game->players[i],game->clienttag,id);
806 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_draw));
807 break;
808 case game_result_disconnect:
809 if (discisloss)
810 {
811 account_inc_ladder_losses(game->players[i],game->clienttag,id);
812 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_loss));
813 }
814 else
815 {
816 /* FIXME: do the first disconnect only stuff like below */
817 account_inc_ladder_disconnects(game->players[i],game->clienttag,id);
818 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_disconnect));
819 }
820 break;
821 default:
822 eventlog(eventlog_level_error,__FUNCTION__,"bad ladder game realplayer results[%u] = %u",i,game->results[i]);
823 account_inc_ladder_disconnects(game->players[i],game->clienttag,id);
824 account_set_ladder_last_result(game->players[i],game->clienttag,id,game_result_get_str(game_result_disconnect));
825 }
826 account_set_ladder_last_time(game->players[i],game->clienttag,id,bnettime());
827 }
828
829 ladder_info = xmalloc(sizeof(t_ladder_info)*realcount);
830 if (ladder_update(game->clienttag,id,
831 realcount,game->players,game->results,ladder_info,
832 discisloss?ladder_option_disconnectisloss:ladder_option_none)<0)
833 {
834 eventlog(eventlog_level_info,__FUNCTION__,"unable to update ladder stats");
835 xfree(ladder_info);
836 ladder_info = NULL;
837 }
838 }
839 else
840 {
841 int disc_set=0;
842
843 for (i=0; i<realcount; i++)
844 {
845 switch (game->results[i])
846 {
847 case game_result_win:
848 account_inc_normal_wins(game->players[i],game->clienttag);
849 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_win));
850 break;
851 case game_result_loss:
852 account_inc_normal_losses(game->players[i],game->clienttag);
853 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_loss));
854 break;
855 case game_result_draw:
856 account_inc_normal_draws(game->players[i],game->clienttag);
857 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_draw));
858 break;
859 case game_result_disconnect:
860 if (discisloss)
861 {
862 account_inc_normal_losses(game->players[i],game->clienttag);
863 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_loss));
864 }
865 else
866 {
867 /* FIXME: Is the missing player always the first one in this array? It seems like it should be
868 the person that created the game */
869 if (!disc_set)
870 {
871 account_inc_normal_disconnects(game->players[i],game->clienttag);
872 disc_set = 1;
873 }
874 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_disconnect));
875 }
876 break;
877 default:
878 eventlog(eventlog_level_error,__FUNCTION__,"bad normal game realplayer results[%u] = %u",i,game->results[i]);
879 /* FIXME: Jung-woo fixed this here but we should find out what value results[i] has...
880 and why "discisloss" isn't set above in game_result_disconnect */
881 #if 0
882 /* commented out for loose disconnect policy */
883 /* account_inc_normal_disconnects(game->players[i],game->clienttag); */
884 #endif
885 account_inc_normal_disconnects(game->players[i],game->clienttag);
886 account_set_normal_last_result(game->players[i],game->clienttag,game_result_get_str(game_result_disconnect));
887 }
888 account_set_normal_last_time(game->players[i],game->clienttag,bnettime());
889 }
890 }
891 }
892
893 if (game_get_type(game)!=game_type_ladder && prefs_get_report_all_games()!=1)
894 {
895 eventlog(eventlog_level_debug,__FUNCTION__,"not reporting normal games");
896 return 0;
897 }
898
899 {
900 struct tm * tmval;
901 char dstr[64];
902
903 if (!(tmval = localtime(&now)))
904 dstr[0] = '\0';
905 else
906 sprintf(dstr,"%04d%02d%02d%02d%02d%02d",
907 1900+tmval->tm_year,
908 tmval->tm_mon+1,
909 tmval->tm_mday,
910 tmval->tm_hour,
911 tmval->tm_min,
912 tmval->tm_sec);
913
914 tempname = xmalloc(strlen(prefs_get_reportdir())+1+1+5+1+2+1+strlen(dstr)+1+6+1);
915 sprintf(tempname,"%s/_bnetd-gr_%s_%06u",prefs_get_reportdir(),dstr,game->id);
916 realname = xmalloc(strlen(prefs_get_reportdir())+1+2+1+strlen(dstr)+1+6+1);
917 sprintf(realname,"%s/gr_%s_%06u",prefs_get_reportdir(),dstr,game->id);
918 }
919
920 if (!(fp = fopen(tempname,"w")))
921 {
922 eventlog(eventlog_level_error,__FUNCTION__,"could not open report file \"%s\" for writing (fopen: %s)",tempname,pstrerror(errno));
923 if (ladder_info)
924 xfree(ladder_info);
925 xfree(realname);
926 xfree(tempname);
927 return -1;
928 }
929
930 if (game->bad)
931 fprintf(fp,"[ game results ignored due to inconsistencies ]\n\n");
932 fprintf(fp,"name=\"%s\" id="GAMEID_FORMAT"\n",
933 game_get_name(game),
934 game->id);
935 fprintf(fp,"clienttag=%4s type=\"%s\" option=\"%s\"\n",
936 tag_uint_to_str(clienttag_str,game->clienttag),
937 game_type_get_str(game->type),
938 game_option_get_str(game->option));
939 {
940 struct tm * gametime;
941 char timetemp[GAME_TIME_MAXLEN];
942
943 if (!(gametime = localtime(&game->create_time)))
944 strcpy(timetemp,"?");
945 else
946 strftime(timetemp,sizeof(timetemp),GAME_TIME_FORMAT,gametime);
947 fprintf(fp,"created=\"%s\" ",timetemp);
948
949 if (!(gametime = localtime(&game->start_time)))
950 strcpy(timetemp,"?");
951 else
952 strftime(timetemp,sizeof(timetemp),GAME_TIME_FORMAT,gametime);
953 fprintf(fp,"started=\"%s\" ",timetemp);
954
955 if (!(gametime = localtime(&now)))
956 strcpy(timetemp,"?");
957 else
958 strftime(timetemp,sizeof(timetemp),GAME_TIME_FORMAT,gametime);
959 fprintf(fp,"ended=\"%s\"\n",timetemp);
960 }
961 {
962 char const * mapname;
963
964 if (!(mapname = game_get_mapname(game)))
965 mapname = "?";
966
967 fprintf(fp,"mapfile=\"%s\" mapauth=\"%s\" mapsize=%ux%u tileset=\"%s\"\n",
968 mapname,
969 game_maptype_get_str(game_get_maptype(game)),
970 game_get_mapsize_x(game),game_get_mapsize_y(game),
971 game_tileset_get_str(game_get_tileset(game)));
972 }
973 fprintf(fp,"joins=%u maxplayers=%u\n",
974 game_get_count(game),
975 game_get_maxplayers(game));
976
977 if (!prefs_get_hide_addr())
978 fprintf(fp,"host=%s\n",addr_num_to_addr_str(game_get_addr(game),game_get_port(game)));
979
980 fprintf(fp,"\n\n");
981
982 if (game->clienttag==CLIENTTAG_DIABLORTL_UINT)
983 for (i=0; i<game->count; i++)
984 fprintf(fp,"%-16s JOINED\n",account_get_name(game->players[i]));
985 else
986 if (ladder_info)
987 for (i=0; i<realcount; i++)
988 fprintf(fp,"%-16s %-8s rating=%u [#%05u] prob=%4.1f%% K=%2u adj=%+d\n",
989 account_get_name(game->players[i]),
990 game_result_get_str(game->results[i]),
991 ladder_info[i].oldrating,
992 ladder_info[i].oldrank,
993 ladder_info[i].prob*100.0,
994 ladder_info[i].k,
995 ladder_info[i].adj);
996 else
997 for (i=0; i<realcount; i++)
998 fprintf(fp,"%-16s %-8s\n",
999 account_get_name(game->players[i]),
1000 game_result_get_str(game->results[i]));
1001 fprintf(fp,"\n\n");
1002
1003 if (ladder_info)
1004 xfree(ladder_info);
1005
1006 for (i=0; i<realcount; i++)
1007 {
1008 if (game->report_heads[i])
1009 fprintf(fp,"%s\n",game->report_heads[i]);
1010 else
1011 fprintf(fp,"[ game report header not available for player %u (\"%s\") ]\n",i+1,account_get_name(game->players[i]));
1012 if (game->report_bodies[i])
1013 fprintf(fp,"%s\n",game->report_bodies[i]);
1014 else
1015 fprintf(fp,"[ game report body not available for player %u (\"%s\") ]\n\n",i+1,account_get_name(game->players[i]));
1016 }
1017 fprintf(fp,"\n\n");
1018
1019 if (game->clienttag==CLIENTTAG_STARCRAFT_UINT ||
1020 game->clienttag==CLIENTTAG_SHAREWARE_UINT ||
1021 game->clienttag==CLIENTTAG_BROODWARS_UINT ||
1022 game->clienttag==CLIENTTAG_WARCIIBNE_UINT)
1023 {
1024 for (i=0; i<realcount; i++)
1025 fprintf(fp,"%s's normal record is now %u/%u/%u (%u draws)\n",
1026 account_get_name(game->players[i]),
1027 account_get_normal_wins(game->players[i],game->clienttag),
1028 account_get_normal_losses(game->players[i],game->clienttag),
1029 account_get_normal_disconnects(game->players[i],game->clienttag),
1030 account_get_normal_draws(game->players[i],game->clienttag));
1031 }
1032 if (game->clienttag==CLIENTTAG_STARCRAFT_UINT ||
1033 game->clienttag==CLIENTTAG_BROODWARS_UINT ||
1034 game->clienttag==CLIENTTAG_WARCIIBNE_UINT)
1035 {
1036 fprintf(fp,"\n");
1037 for (i=0; i<realcount; i++)
1038 fprintf(fp,"%s's standard ladder record is now %u/%u/%u (rating %u [#%05u]) (%u draws)\n",
1039 account_get_name(game->players[i]),
1040 account_get_ladder_wins(game->players[i],game->clienttag,ladder_id_normal),
1041 account_get_ladder_losses(game->players[i],game->clienttag,ladder_id_normal),
1042 account_get_ladder_disconnects(game->players[i],game->clienttag,ladder_id_normal),
1043 account_get_ladder_rating(game->players[i],game->clienttag,ladder_id_normal),
1044 account_get_ladder_rank(game->players[i],game->clienttag,ladder_id_normal),
1045 account_get_ladder_draws(game->players[i],game->clienttag,ladder_id_normal));
1046 }
1047 if (game->clienttag==CLIENTTAG_WARCIIBNE_UINT)
1048 {
1049 fprintf(fp,"\n");
1050 for (i=0; i<realcount; i++)
1051 fprintf(fp,"%s's ironman ladder record is now %u/%u/%u (rating %u [#%05u]) (%u draws)\n",
1052 account_get_name(game->players[i]),
1053 account_get_ladder_wins(game->players[i],game->clienttag,ladder_id_ironman),
1054 account_get_ladder_losses(game->players[i],game->clienttag,ladder_id_ironman),
1055 account_get_ladder_disconnects(game->players[i],game->clienttag,ladder_id_ironman),
1056 account_get_ladder_rating(game->players[i],game->clienttag,ladder_id_ironman),
1057 account_get_ladder_rank(game->players[i],game->clienttag,ladder_id_ironman),
1058 account_get_ladder_draws(game->players[i],game->clienttag,ladder_id_ironman));
1059 }
1060
1061 fprintf(fp,"\nThis game lasted %lu minutes (elapsed).\n",((unsigned long int)difftime(now,game->start_time))/60);
1062
1063 if (fclose(fp)<0)
1064 {
1065 eventlog(eventlog_level_error,__FUNCTION__,"could not close report file \"%s\" after writing (fclose: %s)",tempname,pstrerror(errno));
1066 xfree(realname);
1067 xfree(tempname);
1068 return -1;
1069 }
1070
1071 if (p_rename(tempname,realname)<0)
1072 {
1073 eventlog(eventlog_level_error,__FUNCTION__,"could not rename report file to \"%s\" (rename: %s)",realname,pstrerror(errno));
1074 xfree(realname);
1075 xfree(tempname);
1076 return -1;
1077 }
1078
1079 eventlog(eventlog_level_debug,__FUNCTION__,"game report saved as \"%s\"",realname);
1080 xfree(realname);
1081 xfree(tempname);
1082 return 0;
1083 }
1084
1085
game_get_id(t_game const * game)1086 extern unsigned int game_get_id(t_game const * game)
1087 {
1088 if (!game)
1089 {
1090 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1091 return 0;
1092 }
1093 return game->id;
1094 }
1095
1096
game_get_name(t_game const * game)1097 extern char const * game_get_name(t_game const * game)
1098 {
1099 if (!game)
1100 {
1101 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1102 return NULL;
1103 }
1104 return game->name ? game->name : "BNet";
1105 }
1106
1107
game_get_type(t_game const * game)1108 extern t_game_type game_get_type(t_game const * game)
1109 {
1110 if (!game)
1111 {
1112 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1113 return 0;
1114 }
1115 return game->type;
1116 }
1117
1118
game_get_maptype(t_game const * game)1119 extern t_game_maptype game_get_maptype(t_game const * game)
1120 {
1121 if (!game)
1122 {
1123 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1124 return game_maptype_none;
1125 }
1126 return game->maptype;
1127 }
1128
1129
game_set_maptype(t_game * game,t_game_maptype maptype)1130 extern int game_set_maptype(t_game * game, t_game_maptype maptype)
1131 {
1132 if (!game)
1133 {
1134 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1135 return -1;
1136 }
1137 game->maptype = maptype;
1138 return 0;
1139 }
1140
1141
game_get_tileset(t_game const * game)1142 extern t_game_tileset game_get_tileset(t_game const * game)
1143 {
1144 if (!game)
1145 {
1146 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1147 return game_tileset_none;
1148 }
1149 return game->tileset;
1150 }
1151
1152
game_set_tileset(t_game * game,t_game_tileset tileset)1153 extern int game_set_tileset(t_game * game, t_game_tileset tileset)
1154 {
1155 if (!game)
1156 {
1157 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1158 return -1;
1159 }
1160 game->tileset = tileset;
1161 return 0;
1162 }
1163
1164
game_get_speed(t_game const * game)1165 extern t_game_speed game_get_speed(t_game const * game)
1166 {
1167 if (!game)
1168 {
1169 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1170 return game_speed_none;
1171 }
1172 return game->speed;
1173 }
1174
1175
game_set_speed(t_game * game,t_game_speed speed)1176 extern int game_set_speed(t_game * game, t_game_speed speed)
1177 {
1178 if (!game)
1179 {
1180 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1181 return -1;
1182 }
1183 game->speed = speed;
1184 return 0;
1185 }
1186
1187
game_get_mapsize_x(t_game const * game)1188 extern unsigned int game_get_mapsize_x(t_game const * game)
1189 {
1190 if (!game)
1191 {
1192 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1193 return 0;
1194 }
1195 return game->mapsize_x;
1196 }
1197
1198
game_set_mapsize_x(t_game * game,unsigned int x)1199 extern int game_set_mapsize_x(t_game * game, unsigned int x)
1200 {
1201 if (!game)
1202 {
1203 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1204 return -1;
1205 }
1206 game->mapsize_x = x;
1207 return 0;
1208 }
1209
1210
game_get_mapsize_y(t_game const * game)1211 extern unsigned int game_get_mapsize_y(t_game const * game)
1212 {
1213 if (!game)
1214 {
1215 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1216 return 0;
1217 }
1218 return game->mapsize_y;
1219 }
1220
1221
game_set_mapsize_y(t_game * game,unsigned int y)1222 extern int game_set_mapsize_y(t_game * game, unsigned int y)
1223 {
1224 if (!game)
1225 {
1226 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1227 return -1;
1228 }
1229 game->mapsize_y = y;
1230 return 0;
1231 }
1232
1233
game_get_maxplayers(t_game const * game)1234 extern unsigned int game_get_maxplayers(t_game const * game)
1235 {
1236 if (!game)
1237 {
1238 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1239 return 0;
1240 }
1241 return game->maxplayers;
1242 }
1243
1244
game_set_maxplayers(t_game * game,unsigned int maxplayers)1245 extern int game_set_maxplayers(t_game * game, unsigned int maxplayers)
1246 {
1247 if (!game)
1248 {
1249 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1250 return -1;
1251 }
1252 game->maxplayers = maxplayers;
1253 return 0;
1254 }
1255
1256
game_get_difficulty(t_game const * game)1257 extern unsigned int game_get_difficulty(t_game const * game)
1258 {
1259 if (!game)
1260 {
1261 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1262 return 0;
1263 }
1264 return game->difficulty;
1265 }
1266
1267
game_set_difficulty(t_game * game,unsigned int difficulty)1268 extern int game_set_difficulty(t_game * game, unsigned int difficulty)
1269 {
1270 if (!game)
1271 {
1272 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1273 return -1;
1274 }
1275 game->difficulty = difficulty;
1276 return 0;
1277 }
1278
1279
game_get_description(t_game const * game)1280 extern char const * game_get_description(t_game const * game)
1281 {
1282 if (!game)
1283 {
1284 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1285 return NULL;
1286 }
1287 return game->description;
1288 }
1289
1290
game_set_description(t_game * game,char const * description)1291 extern int game_set_description(t_game * game, char const * description)
1292 {
1293 if (!game)
1294 {
1295 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1296 return -1;
1297 }
1298 if (!description)
1299 {
1300 eventlog(eventlog_level_error,__FUNCTION__,"got NULL description");
1301 return -1;
1302 }
1303
1304 if (game->description != NULL) xfree((void *)game->description);
1305 game->description = xstrdup(description);
1306
1307 return 0;
1308 }
1309
1310
game_get_pass(t_game const * game)1311 extern char const * game_get_pass(t_game const * game)
1312 {
1313 if (!game)
1314 {
1315 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1316 return NULL;
1317 }
1318 return game->pass;
1319 }
1320
1321
game_get_info(t_game const * game)1322 extern char const * game_get_info(t_game const * game)
1323 {
1324 if (!game)
1325 {
1326 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1327 return NULL;
1328 }
1329 return game->info;
1330 }
1331
1332
game_get_startver(t_game const * game)1333 extern int game_get_startver(t_game const * game)
1334 {
1335 if (!game)
1336 {
1337 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1338 return 0;
1339 }
1340 return game->startver;
1341 }
1342
1343
game_get_version(t_game const * game)1344 extern unsigned long game_get_version(t_game const * game)
1345 {
1346 if (!game)
1347 {
1348 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1349 return 0;
1350 }
1351 return game->version;
1352 }
1353
1354
game_get_ref(t_game const * game)1355 extern unsigned int game_get_ref(t_game const * game)
1356 {
1357 if (!game)
1358 {
1359 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1360 return 0;
1361 }
1362 return game->ref;
1363 }
1364
1365
game_get_count(t_game const * game)1366 extern unsigned int game_get_count(t_game const * game)
1367 {
1368 if (!game)
1369 {
1370 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1371 return 0;
1372 }
1373 return game->count;
1374 }
1375
1376
game_set_status(t_game * game,t_game_status status)1377 extern void game_set_status(t_game * game, t_game_status status)
1378 {
1379 if (!game) {
1380 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1381 return;
1382 }
1383 // [quetzal] 20020829 - this should prevent invalid status changes
1384 // its like started game cant become open and so on
1385 if (game->status == game_status_started &&
1386 (status == game_status_open || status == game_status_full || status == game_status_loaded)) {
1387 eventlog(eventlog_level_error, "game_set_status",
1388 "attempting to set status '%s' (%d) to started game", game_status_get_str(status), status);
1389 return;
1390 }
1391
1392 if (game->status == game_status_done && status != game_status_done) {
1393 eventlog(eventlog_level_error, "game_set_status",
1394 "attempting to set status '%s' (%d) to done game", game_status_get_str(status), status);
1395 return;
1396 }
1397
1398 if (status==game_status_started && game->start_time==(time_t)0)
1399 game->start_time = now;
1400 game->status = status;
1401 }
1402
1403
game_get_status(t_game const * game)1404 extern t_game_status game_get_status(t_game const * game)
1405 {
1406 if (!game)
1407 {
1408 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1409 return 0;
1410 }
1411 return game->status;
1412 }
1413
1414
game_get_addr(t_game const * game)1415 extern unsigned int game_get_addr(t_game const * game)
1416 {
1417 if (!game)
1418 {
1419 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1420 return 0;
1421 }
1422
1423 return game->addr; /* host byte order */
1424 }
1425
1426
game_get_port(t_game const * game)1427 extern unsigned short game_get_port(t_game const * game)
1428 {
1429 if (!game)
1430 {
1431 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1432 return 0;
1433 }
1434
1435 return game->port; /* host byte order */
1436 }
1437
1438
game_get_latency(t_game const * game)1439 extern unsigned int game_get_latency(t_game const * game)
1440 {
1441 if (!game)
1442 {
1443 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1444 return 0;
1445 }
1446 if (game->ref<1)
1447 {
1448 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has no players",game_get_name(game));
1449 return 0;
1450 }
1451 if (!game->players)
1452 {
1453 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has NULL players array (ref=%u)",game_get_name(game),game->ref);
1454 return 0;
1455 }
1456 if (!game->players[0])
1457 {
1458 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has NULL players[0] entry (ref=%u)",game_get_name(game),game->ref);
1459 return 0;
1460 }
1461
1462 return 0; /* conn_get_latency(game->players[0]); */
1463 }
1464
game_get_player_conn(t_game const * game,unsigned int i)1465 extern t_connection * game_get_player_conn(t_game const * game, unsigned int i)
1466 {
1467 if (!game)
1468 {
1469 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1470 return NULL;
1471 }
1472 if (game->ref<1)
1473 {
1474 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has no players",game_get_name(game));
1475 return NULL;
1476 }
1477 if (!game->players)
1478 {
1479 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has NULL player array (ref=%u)",game_get_name(game),game->ref);
1480 return NULL;
1481 }
1482 if (!game->players[i])
1483 {
1484 eventlog(eventlog_level_error,__FUNCTION__,"game \"%s\" has NULL players[i] entry (ref=%u)",game_get_name(game),game->ref);
1485 return NULL;
1486 }
1487 return game->connections[i];
1488 }
1489
game_get_clienttag(t_game const * game)1490 extern t_clienttag game_get_clienttag(t_game const * game)
1491 {
1492 if (!game)
1493 {
1494 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1495 return 0;
1496 }
1497 return game->clienttag;
1498 }
1499
1500
game_add_player(t_game * game,char const * pass,int startver,t_connection * c)1501 extern int game_add_player(t_game * game, char const * pass, int startver, t_connection * c)
1502 {
1503 t_connection * * tempc;
1504 t_account * * tempp;
1505 t_game_result * tempr;
1506 t_game_result ** temprr;
1507 char const * * temprh;
1508 char const * * temprb;
1509 unsigned int i = 0;
1510
1511 if (!game)
1512 {
1513 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1514 return -1;
1515 }
1516 if (!pass)
1517 {
1518 eventlog(eventlog_level_error,__FUNCTION__,"got NULL password");
1519 return -1;
1520 }
1521 if (startver!=STARTVER_UNKNOWN && startver!=STARTVER_GW1 && startver!=STARTVER_GW3 && startver!=STARTVER_GW4 && startver!=STARTVER_REALM1)
1522 {
1523 eventlog(eventlog_level_error,__FUNCTION__,"got bad game startver %d",startver);
1524 return -1;
1525 }
1526 if (!c)
1527 {
1528 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
1529 return -1;
1530 }
1531 if (game->type==game_type_ladder && account_get_normal_wins(conn_get_account(c),conn_get_clienttag(c))<10)
1532 /* if () ... */
1533 {
1534 eventlog(eventlog_level_error,__FUNCTION__,"can not join ladder game without 10 normal wins");
1535 return -1;
1536 }
1537
1538 {
1539 t_clienttag gt;
1540
1541 if (!(gt = game_get_clienttag(game)))
1542 {
1543 eventlog(eventlog_level_error,__FUNCTION__,"could not get clienttag for game");
1544 return -1;
1545 }
1546 }
1547
1548 if (game->pass[0]!='\0' && strcasecmp(game->pass,pass)!=0)
1549 {
1550 eventlog(eventlog_level_debug,__FUNCTION__,"game \"%s\" password mismatch \"%s\"!=\"%s\"",game_get_name(game),game->pass,pass);
1551 return -1;
1552 }
1553
1554 if (game->connections && (game->count > 0))
1555 {
1556 for (i=0; i<game->count; i++)
1557 {
1558 if (game->connections[i] == NULL)
1559 {
1560 game->connections[i] = c;
1561 game->players[i] = conn_get_account(c);
1562 game->results[i] = game_result_none;
1563 game->reported_results[i] = NULL;
1564 game->report_heads[i] = NULL;
1565 game->report_bodies[i] = NULL;
1566
1567 game->ref++;
1568 game->lastaccess_time = now;
1569 break;
1570 }
1571 }
1572
1573 }
1574
1575 if ((i == game->count) || (game->count == 0))
1576 {
1577
1578 if (!game->connections) /* some realloc()s are broken */
1579 tempc = xmalloc((game->count+1)*sizeof(t_connection *));
1580 else
1581 tempc = xrealloc(game->connections,(game->count+1)*sizeof(t_connection *));
1582 game->connections = tempc;
1583 if (!game->players) /* some realloc()s are broken */
1584 tempp = xmalloc((game->count+1)*sizeof(t_account *));
1585 else
1586 tempp = xrealloc(game->players,(game->count+1)*sizeof(t_account *));
1587 game->players = tempp;
1588
1589 if (!game->results) /* some realloc()s are broken */
1590 tempr = xmalloc((game->count+1)*sizeof(t_game_result));
1591 else
1592 tempr = xrealloc(game->results,(game->count+1)*sizeof(t_game_result));
1593 game->results = tempr;
1594
1595 if (!game->reported_results)
1596 temprr = xmalloc((game->count+1)*sizeof(t_game_result *));
1597 else
1598 temprr = xrealloc(game->reported_results,(game->count+1)*sizeof(t_game_result *));
1599 game->reported_results = temprr;
1600
1601 if (!game->report_heads) /* some xrealloc()s are broken */
1602 temprh = xmalloc((game->count+1)*sizeof(char const *));
1603 else
1604 temprh = xrealloc((void *)game->report_heads,(game->count+1)*sizeof(char const *)); /* avoid compiler warning */
1605 game->report_heads = temprh;
1606
1607 if (!game->report_bodies) /* some xrealloc()s are broken */
1608 temprb = xmalloc((game->count+1)*sizeof(char const *));
1609 else
1610 temprb = xrealloc((void *)game->report_bodies,(game->count+1)*sizeof(char const *)); /* avoid compiler warning */
1611 game->report_bodies = temprb;
1612
1613 game->connections[game->count] = c;
1614 game->players[game->count] = conn_get_account(c);
1615 game->results[game->count] = game_result_none;
1616 game->reported_results[game->count] = NULL;
1617 game->report_heads[game->count] = NULL;
1618 game->report_bodies[game->count] = NULL;
1619
1620 game->count++;
1621 game->ref++;
1622 game->lastaccess_time = now;
1623
1624 } // end of "if ((i == game->count) || (game->count == 0))"
1625
1626 if (game->startver!=startver && startver!=STARTVER_UNKNOWN) /* with join startver ALWAYS unknown [KWS] */
1627 eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" client \"%s\" startver %u joining game startver %u (count=%u ref=%u)",account_get_name(conn_get_account(c)),clienttag_uint_to_str(conn_get_clienttag(c)),startver,game->startver,game->count,game->ref);
1628
1629 game_choose_host(game);
1630
1631 return 0;
1632 }
1633
game_del_player(t_game * game,t_connection * c)1634 extern int game_del_player(t_game * game, t_connection * c)
1635 {
1636 char const * tname;
1637 unsigned int i;
1638 t_account * account;
1639
1640 if (!game)
1641 {
1642 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1643 return -1;
1644 }
1645 if (!c)
1646 {
1647 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
1648 return -1;
1649 }
1650 if (!game->players)
1651 {
1652 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1653 return -1;
1654 }
1655 if (!game->reported_results)
1656 {
1657 eventlog(eventlog_level_error,__FUNCTION__,"reported results array is NULL");
1658 return -1;
1659 }
1660 account = conn_get_account(c);
1661
1662 if(conn_get_leavegamewhisper_ack(c)==0)
1663 {
1664 watchlist_notify_event(conn_get_account(c),NULL,conn_get_clienttag(c),watch_event_leavegame);
1665 conn_set_leavegamewhisper_ack(c,1); //1 = already whispered. We reset this each time user joins a channel
1666 }
1667
1668 eventlog(eventlog_level_debug,__FUNCTION__,"game \"%s\" has ref=%u, count=%u; trying to remove player \"%s\"",game_get_name(game),game->ref,game->count,account_get_name(account));
1669
1670 for (i=0; i<game->count; i++)
1671 if (game->players[i]==account && game->connections[i])
1672 {
1673 eventlog(eventlog_level_debug,__FUNCTION__,"removing player #%u \"%s\" from \"%s\", %u players left",i,(tname = account_get_name(account)),game_get_name(game),game->ref-1);
1674 game->connections[i] = NULL;
1675 if (!(game->reported_results[i]))
1676 eventlog(eventlog_level_debug,__FUNCTION__,"player \"%s\" left without reporting (valid) results",tname);
1677
1678 eventlog(eventlog_level_debug,__FUNCTION__,"player deleted... (ref=%u)",game->ref);
1679
1680 if (game->ref<2)
1681 {
1682 eventlog(eventlog_level_debug,__FUNCTION__,"no more players, reporting game");
1683 game_report(game);
1684 eventlog(eventlog_level_debug,__FUNCTION__,"no more players, destroying game");
1685 game_destroy(game);
1686 return 0;
1687 }
1688
1689 game->ref--;
1690 game->lastaccess_time = now;
1691
1692 game_choose_host(game);
1693
1694 return 0;
1695 }
1696
1697 eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" was not in the game",account_get_name(account));
1698 return -1;
1699 }
1700
game_get_player(t_game * game,unsigned int i)1701 extern t_account * game_get_player(t_game * game, unsigned int i)
1702 {
1703 if (!game)
1704 {
1705 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1706 return NULL;
1707 }
1708
1709 if (!(i<game->count))
1710 {
1711 eventlog(eventlog_level_error,__FUNCTION__,"requested illegal player id %u",i);
1712 return NULL;
1713 }
1714
1715 return game->players[i];
1716 }
1717
game_set_report(t_game * game,t_account * account,char const * rephead,char const * repbody)1718 extern int game_set_report(t_game * game, t_account * account, char const * rephead, char const * repbody)
1719 {
1720 unsigned int pos;
1721
1722 if (!game)
1723 {
1724 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1725 return -1;
1726 }
1727 if (!account)
1728 {
1729 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1730 return -1;
1731 }
1732 if (!game->players)
1733 {
1734 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1735 return -1;
1736 }
1737 if (!game->report_heads)
1738 {
1739 eventlog(eventlog_level_error,__FUNCTION__,"report_heads array is NULL");
1740 return -1;
1741 }
1742 if (!game->report_bodies)
1743 {
1744 eventlog(eventlog_level_error,__FUNCTION__,"report_bodies array is NULL");
1745 return -1;
1746 }
1747 if (!rephead)
1748 {
1749 eventlog(eventlog_level_error,__FUNCTION__,"report head is NULL");
1750 return -1;
1751 }
1752 if (!repbody)
1753 {
1754 eventlog(eventlog_level_error,__FUNCTION__,"report body is NULL");
1755 return -1;
1756 }
1757
1758 {
1759 unsigned int i;
1760
1761 pos = game->count;
1762 for (i=0; i<game->count; i++)
1763 if (game->players[i]==account)
1764 pos = i;
1765 }
1766 if (pos==game->count)
1767 {
1768 eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set result",account_get_name(account));
1769 return -1;
1770 }
1771
1772 game->report_heads[pos] = xstrdup(rephead);
1773 game->report_bodies[pos] = xstrdup(repbody);
1774
1775 return 0;
1776 }
1777
game_set_reported_results(t_game * game,t_account * account,t_game_result * results)1778 extern int game_set_reported_results(t_game * game, t_account * account, t_game_result * results)
1779 {
1780 unsigned int i,j;
1781 t_game_result result;
1782
1783 if (!game)
1784 {
1785 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1786 return -1;
1787 }
1788
1789 if (!account)
1790 {
1791 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1792 return -1;
1793 }
1794
1795 if (!results)
1796 {
1797 eventlog(eventlog_level_error,__FUNCTION__,"got NULL results");
1798 return -1;
1799 }
1800
1801 if (!game->players)
1802 {
1803 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1804 return -1;
1805 }
1806
1807 if (!game->reported_results)
1808 {
1809 eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1810 return -1;
1811 }
1812
1813 for (i=0;i<game->count;i++)
1814 {
1815 if ((game->players[i]==account)) break;
1816 }
1817
1818 if (i==game->count)
1819 {
1820 eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set reported results",account_get_name(account));
1821 return -1;
1822 }
1823
1824 if (game->reported_results[i])
1825 {
1826 eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" allready reported results - skipping this report",account_get_name(account));
1827 return -1;
1828 }
1829
1830 for (j=0;j<game->count;j++)
1831 {
1832 result = results[j];
1833 switch(result)
1834 {
1835 case game_result_win:
1836 case game_result_loss:
1837 case game_result_draw:
1838 case game_result_observer:
1839 case game_result_disconnect:
1840 break;
1841 case game_result_none:
1842 case game_result_playing:
1843 if (i != j) break; /* accept none/playing only from "others" */
1844 default: /* result is invalid */
1845 if (i!=j)
1846 {
1847 eventlog(eventlog_level_error,__FUNCTION__,"ignoring bad reported result %u for player \"%s\"",(unsigned int)result,account_get_name(game->players[j]));
1848 results[i]=game_result_none;
1849 } else {
1850 eventlog(eventlog_level_error,__FUNCTION__,"got bad reported result %u for self - skipping results",(unsigned int)result);
1851 return -1;
1852 }
1853 }
1854 }
1855
1856 game->reported_results[i] = results;
1857
1858 return 0;
1859 }
1860
1861
game_set_self_report(t_game * game,t_account * account,t_game_result result)1862 extern int game_set_self_report(t_game * game, t_account * account, t_game_result result)
1863 {
1864 unsigned int i;
1865 t_game_result * results;
1866
1867 if (!game)
1868 {
1869 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1870 return -1;
1871 }
1872
1873 if (!account)
1874 {
1875 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1876 return -1;
1877 }
1878
1879 if (!game->players)
1880 {
1881 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1882 return -1;
1883 }
1884
1885 if (!game->reported_results)
1886 {
1887 eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1888 return -1;
1889 }
1890
1891 results = xmalloc(sizeof(t_game_result)*game->count);
1892
1893 for (i=0;i<game->count;i++)
1894 {
1895 if ((game->players[i]==account))
1896 results[i]= result;
1897 else
1898 results[i]= game_result_none;
1899 }
1900
1901 game_set_reported_results(game,account,results);
1902
1903 return 0;
1904 }
1905
game_get_reported_results(t_game * game,t_account * account)1906 extern t_game_result * game_get_reported_results(t_game * game, t_account * account)
1907 {
1908 unsigned int i;
1909
1910 if (!(game))
1911 {
1912 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1913 return NULL;
1914 }
1915
1916 if (!(account))
1917 {
1918 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1919 return NULL;
1920 }
1921
1922 if (!(game->players))
1923 {
1924 eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1925 return NULL;
1926 }
1927
1928 if (!(game->reported_results))
1929 {
1930 eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1931 return NULL;
1932 }
1933
1934 for (i=0;i<game->count;i++)
1935 {
1936 if ((game->players[i]==account)) break;
1937 }
1938
1939 if (i==game->count)
1940 {
1941 eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set reported results",account_get_name(account));
1942 return NULL;
1943 }
1944
1945 if (!(game->reported_results[i]))
1946 {
1947 eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" has not reported any results",account_get_name(account));
1948 return NULL;
1949 }
1950
1951 return game->reported_results[i];
1952 }
1953
1954
game_get_mapname(t_game const * game)1955 extern char const * game_get_mapname(t_game const * game)
1956 {
1957 if (!game)
1958 {
1959 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1960 return NULL;
1961 }
1962
1963 return game->mapname;
1964 }
1965
1966
game_set_mapname(t_game * game,char const * mapname)1967 extern int game_set_mapname(t_game * game, char const * mapname)
1968 {
1969 if (!game)
1970 {
1971 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1972 return -1;
1973 }
1974 if (!mapname)
1975 {
1976 eventlog(eventlog_level_error,__FUNCTION__,"got NULL mapname");
1977 return -1;
1978 }
1979
1980 if (game->mapname != NULL) xfree((void *)game->mapname);
1981
1982 game->mapname = xstrdup(mapname);
1983
1984 return 0;
1985 }
1986
1987
game_get_owner(t_game const * game)1988 extern t_connection * game_get_owner(t_game const * game)
1989 {
1990 if (!game)
1991 {
1992 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1993 return NULL;
1994 }
1995 return game->owner;
1996 }
1997
1998
game_get_create_time(t_game const * game)1999 extern time_t game_get_create_time(t_game const * game)
2000 {
2001 if (!game)
2002 {
2003 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2004 return (time_t)0;
2005 }
2006
2007 return game->create_time;
2008 }
2009
2010
game_get_start_time(t_game const * game)2011 extern time_t game_get_start_time(t_game const * game)
2012 {
2013 if (!game)
2014 {
2015 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2016 return (time_t)0;
2017 }
2018
2019 return game->start_time;
2020 }
2021
2022
game_set_option(t_game * game,t_game_option option)2023 extern int game_set_option(t_game * game, t_game_option option)
2024 {
2025 if (!game)
2026 {
2027 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2028 return -1;
2029 }
2030
2031 game->option = option;
2032 return 0;
2033 }
2034
2035
game_get_option(t_game const * game)2036 extern t_game_option game_get_option(t_game const * game)
2037 {
2038 if (!game)
2039 {
2040 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2041 return game_option_none;
2042 }
2043
2044 return game->option;
2045 }
2046
2047
gamelist_create(void)2048 extern int gamelist_create(void)
2049 {
2050 elist_init(&gamelist_head);
2051 glist_length = 0;
2052 return 0;
2053 }
2054
2055
gamelist_destroy(void)2056 extern int gamelist_destroy(void)
2057 {
2058 /* FIXME: if called with active games, games are not freed */
2059 elist_init(&gamelist_head);
2060 glist_length = 0;
2061
2062 return 0;
2063 }
2064
2065
gamelist_get_length(void)2066 extern int gamelist_get_length(void)
2067 {
2068 return glist_length;
2069 }
2070
2071
gamelist_find_game(char const * name,t_clienttag ctag,t_game_type type)2072 extern t_game * gamelist_find_game(char const * name, t_clienttag ctag, t_game_type type)
2073 {
2074 t_elist *curr;
2075 t_game *game;
2076
2077 elist_for_each(curr,&gamelist_head)
2078 {
2079 game = elist_entry(curr,t_game,glist_link);
2080 if ((type==game_type_all || game->type==type)
2081 && ctag == game->clienttag
2082 && game->name
2083 && !strcasecmp(name,game->name)) return game;
2084 }
2085
2086 return NULL;
2087 }
2088
2089
gamelist_find_game_byid(unsigned int id)2090 extern t_game * gamelist_find_game_byid(unsigned int id)
2091 {
2092 t_elist *curr;
2093 t_game *game;
2094
2095 elist_for_each(curr,&gamelist_head)
2096 {
2097 game = elist_entry(curr,t_game,glist_link);
2098 if (game->id==id)
2099 return game;
2100 }
2101
2102 return NULL;
2103 }
2104
2105
gamelist_traverse(t_glist_func cb,void * data)2106 extern void gamelist_traverse(t_glist_func cb, void *data)
2107 {
2108 t_elist *curr;
2109
2110 elist_for_each(curr,&gamelist_head)
2111 {
2112 if (cb(elist_entry(curr,t_game,glist_link),data)<0) return;
2113 }
2114 }
2115
2116
gamelist_total_games(void)2117 extern int gamelist_total_games(void)
2118 {
2119 return totalcount;
2120 }
2121
game_set_realm(t_game * game,unsigned int realm)2122 extern int game_set_realm(t_game * game, unsigned int realm)
2123 {
2124 if (!game)
2125 {
2126 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2127 return -1;
2128 }
2129 game->realm = realm;
2130 return 0;
2131 }
2132
game_get_realm(t_game const * game)2133 extern unsigned int game_get_realm(t_game const * game)
2134 {
2135 if (!game)
2136 {
2137 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2138 return 0;
2139 }
2140 return game->realm;
2141 }
2142
game_set_realmname(t_game * game,char const * realmname)2143 extern int game_set_realmname(t_game * game, char const * realmname)
2144 {
2145 char const * temp;
2146
2147 if (!game)
2148 {
2149 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2150 return -1;
2151 }
2152
2153 if (realmname)
2154 temp=xstrdup(realmname);
2155 else
2156 temp=NULL;
2157
2158 if (game->realmname)
2159 xfree((void *)game->realmname); /* avoid warning */
2160 game->realmname = temp;
2161 return 0;
2162 }
2163
game_get_realmname(t_game const * game)2164 extern char const * game_get_realmname(t_game const * game)
2165 {
2166 if (!game)
2167 {
2168 eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2169 return NULL;
2170 }
2171 return game->realmname;
2172 }
2173
2174
gamelist_check_voidgame(void)2175 extern void gamelist_check_voidgame(void)
2176 {
2177 t_elist *curr, *save;
2178 t_game *game;
2179
2180 elist_for_each_safe(curr,&gamelist_head,save)
2181 {
2182 game = elist_entry(curr,t_game,glist_link);
2183 if (!game->realm)
2184 continue;
2185 if (game->ref >= 1)
2186 continue;
2187 if ((now - game->lastaccess_time) > MAX_GAME_EMPTY_TIME)
2188 game_destroy(game);
2189 }
2190 }
2191
game_set_flag(t_game * game,t_game_flag flag)2192 extern void game_set_flag(t_game * game, t_game_flag flag)
2193 {
2194 if (!game)
2195 {
2196 eventlog(eventlog_level_error, __FUNCTION__, "got NULL game");
2197 return;
2198 }
2199 game->flag = flag;
2200 }
2201
2202
game_get_flag(t_game const * game)2203 extern t_game_flag game_get_flag(t_game const * game)
2204 {
2205 if (!game)
2206 {
2207 eventlog(eventlog_level_error, __FUNCTION__, "got NULL game");
2208 return 0;
2209 }
2210 return game->flag;
2211 }
2212
game_get_count_by_clienttag(t_clienttag ct)2213 extern int game_get_count_by_clienttag(t_clienttag ct)
2214 {
2215 t_game *game;
2216 t_elist *curr;
2217 int clienttaggames = 0;
2218
2219 if (!ct) {
2220 eventlog(eventlog_level_error, __FUNCTION__, "got UNKNOWN clienttag");
2221 return 0;
2222 }
2223
2224 /* Get number of games for client tag specific */
2225 elist_for_each(curr,&gamelist_head)
2226 {
2227 game = elist_entry(curr,t_game,glist_link);
2228 if(game_get_clienttag(game)==ct)
2229 clienttaggames++;
2230 }
2231
2232 return clienttaggames;
2233 }
2234
game_match_name(const char * name,const char * prefix)2235 static int game_match_name(const char *name, const char *prefix)
2236 {
2237 /* the easy cases */
2238 if (!name || !*name) return 1;
2239 if (!prefix || !*prefix) return 1;
2240
2241 if (!strncmp(name,prefix,strlen(prefix))) return 1;
2242
2243 return 0;
2244 }
2245
game_is_ladder(t_game * game)2246 extern int game_is_ladder(t_game *game)
2247 {
2248 assert(game);
2249
2250 /* all normal ladder games are still counted as ladder games */
2251 if (game->type == game_type_ladder ||
2252 game->type == game_type_ironman) return 1;
2253
2254 /* addition game types are also checked against gamename prefix if set */
2255 if (game_match_type(game_get_type(game),prefs_get_ladder_games()) &&
2256 game_match_name(game_get_name(game),prefs_get_ladder_prefix())) return 1;
2257
2258 return 0;
2259 }
2260