game.c
上传用户:tany51
上传日期:2013-06-12
资源大小:1397k
文件大小:56k
源码类别:

MySQL数据库

开发平台:

Visual C++

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