/[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.1.1.1 - (hide annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU
CVS Tags: arelease
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

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    
1617     } // 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     if (game->ref<2)
1674     {
1675     eventlog(eventlog_level_debug,__FUNCTION__,"no more players, reporting game");
1676     game_report(game);
1677     eventlog(eventlog_level_debug,__FUNCTION__,"no more players, destroying game");
1678     game_destroy(game);
1679     return 0;
1680     }
1681    
1682     game->ref--;
1683     game->lastaccess_time = now;
1684    
1685     game_choose_host(game);
1686    
1687     return 0;
1688     }
1689    
1690     eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" was not in the game",account_get_name(account));
1691     return -1;
1692     }
1693    
1694    
1695     extern int game_set_report(t_game * game, t_account * account, char const * rephead, char const * repbody)
1696     {
1697     unsigned int pos;
1698    
1699     if (!game)
1700     {
1701     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1702     return -1;
1703     }
1704     if (!account)
1705     {
1706     eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1707     return -1;
1708     }
1709     if (!game->players)
1710     {
1711     eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1712     return -1;
1713     }
1714     if (!game->report_heads)
1715     {
1716     eventlog(eventlog_level_error,__FUNCTION__,"report_heads array is NULL");
1717     return -1;
1718     }
1719     if (!game->report_bodies)
1720     {
1721     eventlog(eventlog_level_error,__FUNCTION__,"report_bodies array is NULL");
1722     return -1;
1723     }
1724     if (!rephead)
1725     {
1726     eventlog(eventlog_level_error,__FUNCTION__,"report head is NULL");
1727     return -1;
1728     }
1729     if (!repbody)
1730     {
1731     eventlog(eventlog_level_error,__FUNCTION__,"report body is NULL");
1732     return -1;
1733     }
1734    
1735     {
1736     unsigned int i;
1737    
1738     pos = game->count;
1739     for (i=0; i<game->count; i++)
1740     if (game->players[i]==account)
1741     pos = i;
1742     }
1743     if (pos==game->count)
1744     {
1745     eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set result",account_get_name(account));
1746     return -1;
1747     }
1748    
1749     game->report_heads[pos] = xstrdup(rephead);
1750     game->report_bodies[pos] = xstrdup(repbody);
1751    
1752     return 0;
1753     }
1754    
1755     extern int game_set_reported_results(t_game * game, t_account * account, t_game_result * results)
1756     {
1757     unsigned int i,j;
1758     t_game_result result;
1759    
1760     if (!game)
1761     {
1762     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1763     return -1;
1764     }
1765    
1766     if (!account)
1767     {
1768     eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1769     return -1;
1770     }
1771    
1772     if (!results)
1773     {
1774     eventlog(eventlog_level_error,__FUNCTION__,"got NULL results");
1775     return -1;
1776     }
1777    
1778     if (!game->players)
1779     {
1780     eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1781     return -1;
1782     }
1783    
1784     if (!game->reported_results)
1785     {
1786     eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1787     return -1;
1788     }
1789    
1790     for (i=0;i<game->count;i++)
1791     {
1792     if ((game->players[i]==account)) break;
1793     }
1794    
1795     if (i==game->count)
1796     {
1797     eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set reported results",account_get_name(account));
1798     return -1;
1799     }
1800    
1801     if (game->reported_results[i])
1802     {
1803     eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" allready reported results - skipping this report",account_get_name(account));
1804     return -1;
1805     }
1806    
1807     for (j=0;j<game->count;j++)
1808     {
1809     result = results[j];
1810     switch(result)
1811     {
1812     case game_result_win:
1813     case game_result_loss:
1814     case game_result_draw:
1815     case game_result_observer:
1816     case game_result_disconnect:
1817     break;
1818     case game_result_none:
1819     case game_result_playing:
1820     if (i != j) break; /* accept none/playing only from "others" */
1821     default: /* result is invalid */
1822     if (i!=j)
1823     {
1824     eventlog(eventlog_level_error,__FUNCTION__,"ignoring bad reported result %u for player \"%s\"",(unsigned int)result,account_get_name(game->players[j]));
1825     results[i]=game_result_none;
1826     } else {
1827     eventlog(eventlog_level_error,__FUNCTION__,"got bad reported result %u for self - skipping results",(unsigned int)result);
1828     return -1;
1829     }
1830     }
1831     }
1832    
1833     game->reported_results[i] = results;
1834    
1835     return 0;
1836     }
1837    
1838    
1839     extern int game_set_self_report(t_game * game, t_account * account, t_game_result result)
1840     {
1841     unsigned int i;
1842     t_game_result * results;
1843    
1844     if (!game)
1845     {
1846     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1847     return -1;
1848     }
1849    
1850     if (!account)
1851     {
1852     eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1853     return -1;
1854     }
1855    
1856     if (!game->players)
1857     {
1858     eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1859     return -1;
1860     }
1861    
1862     if (!game->reported_results)
1863     {
1864     eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1865     return -1;
1866     }
1867    
1868     results = xmalloc(sizeof(t_game_result)*game->count);
1869    
1870     for (i=0;i<game->count;i++)
1871     {
1872     if ((game->players[i]==account))
1873     results[i]= result;
1874     else
1875     results[i]= game_result_none;
1876     }
1877    
1878     game_set_reported_results(game,account,results);
1879    
1880     return 0;
1881     }
1882    
1883     extern t_game_result * game_get_reported_results(t_game * game, t_account * account)
1884     {
1885     unsigned int i;
1886    
1887     if (!(game))
1888     {
1889     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1890     return NULL;
1891     }
1892    
1893     if (!(account))
1894     {
1895     eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
1896     return NULL;
1897     }
1898    
1899     if (!(game->players))
1900     {
1901     eventlog(eventlog_level_error,__FUNCTION__,"player array is NULL");
1902     return NULL;
1903     }
1904    
1905     if (!(game->reported_results))
1906     {
1907     eventlog(eventlog_level_error,__FUNCTION__,"reported_results array is NULL");
1908     return NULL;
1909     }
1910    
1911     for (i=0;i<game->count;i++)
1912     {
1913     if ((game->players[i]==account)) break;
1914     }
1915    
1916     if (i==game->count)
1917     {
1918     eventlog(eventlog_level_error,__FUNCTION__,"could not find player \"%s\" to set reported results",account_get_name(account));
1919     return NULL;
1920     }
1921    
1922     if (!(game->reported_results[i]))
1923     {
1924     eventlog(eventlog_level_error,__FUNCTION__,"player \"%s\" has not reported any results",account_get_name(account));
1925     return NULL;
1926     }
1927    
1928     return game->reported_results[i];
1929     }
1930    
1931    
1932     extern char const * game_get_mapname(t_game const * game)
1933     {
1934     if (!game)
1935     {
1936     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1937     return NULL;
1938     }
1939    
1940     return game->mapname;
1941     }
1942    
1943    
1944     extern int game_set_mapname(t_game * game, char const * mapname)
1945     {
1946     if (!game)
1947     {
1948     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1949     return -1;
1950     }
1951     if (!mapname)
1952     {
1953     eventlog(eventlog_level_error,__FUNCTION__,"got NULL mapname");
1954     return -1;
1955     }
1956    
1957     if (game->mapname != NULL) xfree((void *)game->mapname);
1958    
1959     game->mapname = xstrdup(mapname);
1960    
1961     return 0;
1962     }
1963    
1964    
1965     extern t_connection * game_get_owner(t_game const * game)
1966     {
1967     if (!game)
1968     {
1969     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1970     return NULL;
1971     }
1972     return game->owner;
1973     }
1974    
1975    
1976     extern time_t game_get_create_time(t_game const * game)
1977     {
1978     if (!game)
1979     {
1980     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1981     return (time_t)0;
1982     }
1983    
1984     return game->create_time;
1985     }
1986    
1987    
1988     extern time_t game_get_start_time(t_game const * game)
1989     {
1990     if (!game)
1991     {
1992     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
1993     return (time_t)0;
1994     }
1995    
1996     return game->start_time;
1997     }
1998    
1999    
2000     extern int game_set_option(t_game * game, t_game_option option)
2001     {
2002     if (!game)
2003     {
2004     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2005     return -1;
2006     }
2007    
2008     game->option = option;
2009     return 0;
2010     }
2011    
2012    
2013     extern t_game_option game_get_option(t_game const * game)
2014     {
2015     if (!game)
2016     {
2017     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2018     return game_option_none;
2019     }
2020    
2021     return game->option;
2022     }
2023    
2024    
2025     extern int gamelist_create(void)
2026     {
2027     elist_init(&gamelist_head);
2028     glist_length = 0;
2029     return 0;
2030     }
2031    
2032    
2033     extern int gamelist_destroy(void)
2034     {
2035     /* FIXME: if called with active games, games are not freed */
2036     elist_init(&gamelist_head);
2037     glist_length = 0;
2038    
2039     return 0;
2040     }
2041    
2042    
2043     extern int gamelist_get_length(void)
2044     {
2045     return glist_length;
2046     }
2047    
2048    
2049     extern t_game * gamelist_find_game(char const * name, t_game_type type)
2050     {
2051     t_elist *curr;
2052     t_game *game;
2053    
2054     elist_for_each(curr,&gamelist_head)
2055     {
2056     game = elist_entry(curr,t_game,glist_link);
2057     if ((type==game_type_all || game->type==type) && game->name && strcasecmp(name,game->name)==0)
2058     return game;
2059     }
2060    
2061     return NULL;
2062     }
2063    
2064    
2065     extern t_game * gamelist_find_game_byid(unsigned int id)
2066     {
2067     t_elist *curr;
2068     t_game *game;
2069    
2070     elist_for_each(curr,&gamelist_head)
2071     {
2072     game = elist_entry(curr,t_game,glist_link);
2073     if (game->id==id)
2074     return game;
2075     }
2076    
2077     return NULL;
2078     }
2079    
2080    
2081     extern void gamelist_traverse(t_glist_func cb, void *data)
2082     {
2083     t_elist *curr;
2084    
2085     elist_for_each(curr,&gamelist_head)
2086     {
2087     if (cb(elist_entry(curr,t_game,glist_link),data)<0) return;
2088     }
2089     }
2090    
2091    
2092     extern int gamelist_total_games(void)
2093     {
2094     return totalcount;
2095     }
2096    
2097     extern int game_set_realm(t_game * game, unsigned int realm)
2098     {
2099     if (!game)
2100     {
2101     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2102     return -1;
2103     }
2104     game->realm = realm;
2105     return 0;
2106     }
2107    
2108     extern unsigned int game_get_realm(t_game const * game)
2109     {
2110     if (!game)
2111     {
2112     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2113     return 0;
2114     }
2115     return game->realm;
2116     }
2117    
2118     extern int game_set_realmname(t_game * game, char const * realmname)
2119     {
2120     char const * temp;
2121    
2122     if (!game)
2123     {
2124     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2125     return -1;
2126     }
2127    
2128     if (realmname)
2129     temp=xstrdup(realmname);
2130     else
2131     temp=NULL;
2132    
2133     if (game->realmname)
2134     xfree((void *)game->realmname); /* avoid warning */
2135     game->realmname = temp;
2136     return 0;
2137     }
2138    
2139     extern char const * game_get_realmname(t_game const * game)
2140     {
2141     if (!game)
2142     {
2143     eventlog(eventlog_level_error,__FUNCTION__,"got NULL game");
2144     return NULL;
2145     }
2146     return game->realmname;
2147     }
2148    
2149    
2150     extern void gamelist_check_voidgame(void)
2151     {
2152     t_elist *curr, *save;
2153     t_game *game;
2154    
2155     elist_for_each_safe(curr,&gamelist_head,save)
2156     {
2157     game = elist_entry(curr,t_game,glist_link);
2158     if (!game->realm)
2159     continue;
2160     if (game->ref >= 1)
2161     continue;
2162     if ((now - game->lastaccess_time) > MAX_GAME_EMPTY_TIME)
2163     game_destroy(game);
2164     }
2165     }
2166    
2167     extern void game_set_flag(t_game * game, t_game_flag flag)
2168     {
2169     if (!game)
2170     {
2171     eventlog(eventlog_level_error, __FUNCTION__, "got NULL game");
2172     return;
2173     }
2174     game->flag = flag;
2175     }
2176    
2177    
2178     extern t_game_flag game_get_flag(t_game const * game)
2179     {
2180     if (!game)
2181     {
2182     eventlog(eventlog_level_error, __FUNCTION__, "got NULL game");
2183     return 0;
2184     }
2185     return game->flag;
2186     }
2187    
2188     extern int game_get_count_by_clienttag(t_clienttag ct)
2189     {
2190     t_game *game;
2191     t_elist *curr;
2192     int clienttaggames = 0;
2193    
2194     if (!ct) {
2195     eventlog(eventlog_level_error, __FUNCTION__, "got UNKNOWN clienttag");
2196     return 0;
2197     }
2198    
2199     /* Get number of games for client tag specific */
2200     elist_for_each(curr,&gamelist_head)
2201     {
2202     game = elist_entry(curr,t_game,glist_link);
2203     if(game_get_clienttag(game)==ct)
2204     clienttaggames++;
2205     }
2206    
2207     return clienttaggames;
2208     }
2209    
2210     static int game_match_name(const char *name, const char *prefix)
2211     {
2212     /* the easy cases */
2213     if (!name || !*name) return 1;
2214     if (!prefix || !*prefix) return 1;
2215    
2216     if (!strncmp(name,prefix,strlen(prefix))) return 1;
2217    
2218     return 0;
2219     }
2220    
2221     extern int game_is_ladder(t_game *game)
2222     {
2223     assert(game);
2224    
2225     /* all normal ladder games are still counted as ladder games */
2226     if (game->type == game_type_ladder ||
2227     game->type == game_type_ironman) return 1;
2228    
2229     /* addition game types are also checked against gamename prefix if set */
2230     if (game_match_type(game_get_type(game),prefs_get_ladder_games()) &&
2231     game_match_name(game_get_name(game),prefs_get_ladder_prefix())) return 1;
2232    
2233     return 0;
2234     }

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