/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/game.c
ViewVC logotype

Annotation of /pvpgn-1.7.4/src/bnetd/game.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide annotations)
Sat Jun 24 09:19:06 2006 UTC (19 years, 8 months ago) by sysadm
Branch: MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, HEAD
Changes since 1.1: +12 -7 lines
Content type: text/x-csrc
Auto check void game, fix bug

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

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1