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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show 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 /*
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 game->ref--;
1674 game->lastaccess_time = now;
1675
1676 if (game->ref<1)
1677 {
1678 eventlog(eventlog_level_debug,__FUNCTION__,"no more players, reporting game");
1679 game_report(game);
1680 /* 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 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 /* seems to be incorrect -- By Leaflet, 2006-06-24
2162 if (!game->realm)
2163 continue;
2164 */
2165 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