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