1 /*
2  * Copyright (C) 1999  Rob Crittenden (rcrit@greyoak.com)
3  * Copyright (C) 1999,2000  Ross Combs (rocombs@cs.nmsu.edu)
4  * Copyright (C) 1999,2000  D.Moreaux (vapula@linuxbe.org)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  */
20 #define LADDER_INTERNAL_ACCESS
21 #include "common/setup_before.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 <errno.h>
44 #include <compat/strerror.h>
45 #include "common/field_sizes.h"
46 #include "account.h"
47 #include "account_wrap.h"
48 #include "common/eventlog.h"
49 #include "common/util.h"
50 #include "game.h"
51 #include "common/tag.h"
52 #include "common/list.h"
53 #include "common/bnettime.h"
54 #include "prefs.h"
55 #include "common/hashtable.h"
56 #include "ladder_calc.h"
57 #include "ladder.h"
58 #include "compat/strcasecmp.h"
59 #include "compat/strncasecmp.h"
60 #include "ladder_binary.h"
61 #include "storage.h"
62 #include "account.h"
63 #include "common/bnet_protocol.h"
64 #include "common/xalloc.h"
65 #include "common/setup_after.h"
66 
67 #define MaxRankKeptInLadder 1000
68 
69 /* for War3 XP computations */
70 static t_xpcalc_entry  * xpcalc;
71 static t_xplevel_entry * xplevels;
72 int w3_xpcalc_maxleveldiff;
73 
74 const char * WAR3_solo_file = "WAR3_solo";
75 const char * W3XP_solo_file = "W3XP_solo";
76 const char * WAR3_team_file = "WAR3_team";
77 const char * W3XP_team_file = "W3XP_team";
78 const char * WAR3_ffa_file  = "WAR3_ffa";
79 const char * W3XP_ffa_file  = "W3XP_ffa";
80 const char * WAR3_at_file   = "WAR3_atteam";
81 const char * W3XP_at_file   = "W3XP_atteam";
82 const char * STAR_ar_file   = "STAR_active_rating";
83 const char * STAR_cr_file   = "STAR_current_rating";
84 const char * SEXP_ar_file   = "SEXP_active_rating";
85 const char * SEXP_cr_file   = "SEXP_current_rating";
86 const char * W2BN_ar_file   = "W2BN_active_rating";
87 const char * W2BN_cr_file   = "W2BN_current_rating";
88 const char * W2BN_ari_file   = "W2BN_active_rating_iron";
89 const char * W2BN_cri_file   = "W2BN_current_rating_iron";
90 const char * std_end   = ".dat";
91 const char * xml_end   = ".xml";
92 
93 char * ladder_id_str[] = {"0","1","","3","","solo","team","ffa"};
94 
95 char * WAR3_solo_filename, * WAR3_team_filename, * WAR3_ffa_filename, * WAR3_at_filename;
96 char * W3XP_solo_filename, * W3XP_team_filename, * W3XP_ffa_filename, * W3XP_at_filename;
97 char * STAR_ar_filename, * STAR_cr_filename, * SEXP_ar_filename, * SEXP_cr_filename;
98 char * W2BN_ar_filename, * W2BN_cr_filename, * W2BN_ari_filename, * W2BN_cri_filename;
99 
100 t_ladder WAR3_solo_ladder, WAR3_team_ladder, WAR3_ffa_ladder, WAR3_at_ladder;
101 t_ladder W3XP_solo_ladder, W3XP_team_ladder, W3XP_ffa_ladder, W3XP_at_ladder;
102 t_ladder STAR_active_rating,          STAR_active_wins,          STAR_active_games,
103          STAR_current_rating,         STAR_current_wins,         STAR_current_games;
104 t_ladder SEXP_active_rating,          SEXP_active_wins,          SEXP_active_games,
105          SEXP_current_rating,         SEXP_current_wins,         SEXP_current_games;
106 t_ladder W2BN_active_rating,          W2BN_active_wins,          W2BN_active_games,
107          W2BN_active_rating_ironman,  W2BN_active_wins_ironman,  W2BN_active_games_ironman;
108 t_ladder W2BN_current_rating,         W2BN_current_wins,         W2BN_current_games,
109          W2BN_current_rating_ironman, W2BN_current_wins_ironman, W2BN_current_games_ironman;
110 
111 t_ladder_internal * last_internal = NULL;
112 t_ladder	     * last_ladder   = NULL;
113 int 		       last_rank     = 0;
114 
115 /*
116  * Make the current ladder statistics the active ones.
117  */
118 
119 extern int ladder_make_active(t_ladder *current, t_ladder *active,int set_attributes);
120 
ladderlist_make_all_active(void)121 extern int ladderlist_make_all_active(void)
122 {
123 	ladder_make_active(ladder_cr(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),1);
124 	ladder_make_active(ladder_cw(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),0);
125 	ladder_make_active(ladder_cg(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_STARCRAFT_UINT,ladder_id_normal),0);
126 	ladder_make_active(ladder_cr(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),1);
127 	ladder_make_active(ladder_cw(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),0);
128 	ladder_make_active(ladder_cg(CLIENTTAG_BROODWARS_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_BROODWARS_UINT,ladder_id_normal),0);
129 	ladder_make_active(ladder_cr(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_ar(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),1);
130 	ladder_make_active(ladder_cw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_aw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),0);
131 	ladder_make_active(ladder_cg(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal), ladder_ag(CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal),0);
132 	ladder_make_active(ladder_cr(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_ar(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),1);
133 	ladder_make_active(ladder_cw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_aw(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),0);
134 	ladder_make_active(ladder_cg(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),ladder_ag(CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman),0);
135 	ladder_update_all_accounts();
136     return 0;
137 }
138 
139 
140 /*
141  * Prepare an account for first ladder play if necessary.
142  */
ladder_init_account(t_account * account,t_clienttag clienttag,t_ladder_id id)143 extern int ladder_init_account(t_account * account, t_clienttag clienttag, t_ladder_id id)
144 {
145     int uid;
146 
147     if (!account)
148     {
149 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
150 	return -1;
151     }
152     if (!clienttag)
153     {
154 	eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
155 	return -1;
156     }
157 
158     if (account_get_ladder_rating(account,clienttag,id)==0)
159     {
160 	if (account_get_ladder_wins(account,clienttag,id)+
161 	    account_get_ladder_losses(account,clienttag,id)>0) /* no ladder games so far... */
162 	{
163 	    eventlog(eventlog_level_warn,__FUNCTION__,"account for \"%s\" (%s) has %u wins and %u losses but has zero rating",account_get_name(account),clienttag_uint_to_str(clienttag),account_get_ladder_wins(account,clienttag,id),account_get_ladder_losses(account,clienttag,id));
164 	    return -1;
165 	}
166 	account_adjust_ladder_rating(account,clienttag,id,prefs_get_ladder_init_rating());
167 
168 	uid = account_get_uid(account);
169 
170 	war3_ladder_add(ladder_cr(clienttag,id),uid,0,account_get_ladder_rating(account,clienttag,id),account,0,clienttag);
171 	war3_ladder_add(ladder_cw(clienttag,id),uid,0,0,account,0,clienttag);
172 	war3_ladder_add(ladder_cg(clienttag,id),uid,0,0,account,0,clienttag);
173 
174 	eventlog(eventlog_level_info,__FUNCTION__,"initialized account for \"%s\" for \"%s\" ladder",account_get_name(account),clienttag_uint_to_str(clienttag));
175     }
176 
177     return 0;
178 }
179 
180 
181 /*
182  * Update player ratings, rankings, etc due to game results.
183  */
ladder_update(t_clienttag clienttag,t_ladder_id id,unsigned int count,t_account ** players,t_game_result * results,t_ladder_info * info,t_ladder_option opns)184 extern int ladder_update(t_clienttag clienttag, t_ladder_id id, unsigned int count, t_account * * players, t_game_result * results, t_ladder_info * info, t_ladder_option opns)
185 {
186     unsigned int curr;
187     unsigned int winners=0;
188     unsigned int losers=0;
189     unsigned int draws=0;
190 	int uid;
191 
192     if (count<1 || count>8)
193     {
194 	eventlog(eventlog_level_error,__FUNCTION__,"got invalid player count %u",count);
195 	return -1;
196     }
197     if (!players)
198     {
199 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL players");
200 	return -1;
201     }
202     if (!results)
203     {
204 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL results");
205 	return -1;
206     }
207     if (!clienttag)
208     {
209 	eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
210 	return -1;
211     }
212     if (!info)
213     {
214 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL info");
215 	return -1;
216     }
217 
218     for (curr=0; curr<count; curr++)
219     {
220 	if (!players[curr])
221 	{
222 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL player[%u] (of %u)",curr,count);
223 	    return -1;
224 	}
225 
226 	switch (results[curr])
227 	{
228 	case game_result_win:
229 	    winners++;
230 	    break;
231 	case game_result_loss:
232 	    losers++;
233 	    break;
234 	case game_result_draw:
235 	    draws++;
236 	    break;
237 	case game_result_disconnect:
238 	    if (opns&ladder_option_disconnectisloss)
239 		losers++;
240 	    break;
241 	default:
242 	    eventlog(eventlog_level_error,__FUNCTION__,"bad results[%u]=%u",curr,(unsigned int)results[curr]);
243 	    return -1;
244 	}
245     }
246 
247     if (draws>0)
248     {
249 	if (draws!=count)
250 	{
251 	    eventlog(eventlog_level_error,__FUNCTION__,"some, but not all players had a draw count=%u (winners=%u losers=%u draws=%u)",count,winners,losers,draws);
252 	    return -1;
253 	}
254 
255 	return -1; /* no change in case of draw */
256     }
257     if ((losers<1) || (winners<1) || (winners>1 && (winners!=losers)))
258     {
259 	eventlog(eventlog_level_info,__FUNCTION__,"missing winner or loser for count=%u (winners=%u losers=%u draws=%u) - discarding result",count,winners,losers,draws);
260 	return -1;
261     }
262 
263     if (ladder_calc_info(clienttag,id,count,players,results,info)<0)
264     {
265 	eventlog(eventlog_level_error,__FUNCTION__,"unable to calculate info from game results");
266 	return -1;
267     }
268 
269     for (curr=0; curr<count; curr++)
270 	{
271 	  int won,wins,games;
272 	  t_account * account;
273 
274 	  if (results[curr]==game_result_win) won=1; else won=0;
275 
276 	  account = players[curr];
277 	  uid = account_get_uid(account);
278 	  wins = account_get_ladder_wins(account,clienttag,id);
279 	  games = wins + account_get_ladder_losses(account,clienttag,id) + account_get_ladder_disconnects(account,clienttag,id);
280 
281 	  account_adjust_ladder_rating(account,clienttag,id,info[curr].adj);
282 
283 	  war3_ladder_update(ladder_cr(clienttag,id),uid,won,account_get_ladder_rating(account,clienttag,id),players[curr],0);
284 
285 	  if (results[curr]!=game_result_draw)
286 	        war3_ladder_update(ladder_cg(clienttag,id),uid,info[curr].adj,games,players[curr],0);
287 
288 	  if (results[curr]==game_result_win)
289 		war3_ladder_update(ladder_cw(clienttag,id),uid,info[curr].adj,wins,players[curr],0);
290 	}
291 
292 	ladder_update_all_accounts();
293 
294     return 0;
295 }
296 
297 
ladder_check_map(char const * mapname,t_game_maptype maptype,t_clienttag clienttag)298 extern int ladder_check_map(char const * mapname, t_game_maptype maptype, t_clienttag clienttag)
299 {
300     if (!mapname)
301     {
302 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL mapname");
303 	return -1;
304     }
305     if (!clienttag)
306     {
307 	eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
308 	return -1;
309     }
310 
311     eventlog(eventlog_level_debug,__FUNCTION__,"checking mapname \"%s\" maptype=%d",mapname,(int)maptype);
312     if (maptype==game_maptype_ladder) /* FIXME: what about Ironman? */
313 	return 1;
314 
315     return 0;
316 }
317 
318 
ladder_get_account_by_rank(unsigned int rank,t_ladder_sort lsort,t_ladder_time ltime,t_clienttag clienttag,t_ladder_id id)319 extern t_account * ladder_get_account_by_rank(unsigned int rank, t_ladder_sort lsort, t_ladder_time ltime, t_clienttag clienttag, t_ladder_id id)
320 {
321     unsigned int dummy;
322 
323     if (rank<1)
324     {
325 	eventlog(eventlog_level_error,__FUNCTION__,"got zero rank");
326 	return NULL;
327     }
328     if (!clienttag)
329     {
330 	eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
331 	return NULL;
332     }
333 
334     switch (lsort)
335     {
336     case ladder_sort_highestrated:
337 		if (ltime == ladder_time_current)
338 			return ladder_get_account(ladder_cr(clienttag,id),rank,&dummy,clienttag);
339 		else
340 			return ladder_get_account(ladder_ar(clienttag,id),rank,&dummy,clienttag);
341     case ladder_sort_mostwins:
342 		if (ltime == ladder_time_current)
343 			return ladder_get_account(ladder_cw(clienttag,id),rank,&dummy,clienttag);
344 		else
345 			return ladder_get_account(ladder_aw(clienttag,id),rank,&dummy,clienttag);
346     case ladder_sort_mostgames:
347 		if (ltime == ladder_time_current)
348 			return ladder_get_account(ladder_cg(clienttag,id),rank,&dummy,clienttag);
349 		else
350 			return ladder_get_account(ladder_ag(clienttag,id),rank,&dummy,clienttag);
351     default:
352 	eventlog(eventlog_level_error,__FUNCTION__,"got bad ladder sort %u",(unsigned int)lsort);
353     }
354     return NULL;
355 }
356 
357 
ladder_get_rank_by_account(t_account * account,t_ladder_sort lsort,t_ladder_time ltime,t_clienttag clienttag,t_ladder_id id)358 extern unsigned int ladder_get_rank_by_account(t_account * account, t_ladder_sort lsort, t_ladder_time ltime, t_clienttag clienttag, t_ladder_id id)
359 {
360     int uid;
361 
362     if (!account)
363     {
364 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
365 	return 0;
366     }
367     if (!clienttag)
368     {
369 	eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
370 	return 0;
371     }
372 
373 	uid = account_get_uid(account);
374 
375     switch (lsort)
376     {
377     case ladder_sort_highestrated:
378 		if (ltime == ladder_time_current)
379 			return ladder_get_rank(ladder_cr(clienttag,id),uid,0,clienttag);
380 		else
381 			return ladder_get_rank(ladder_ar(clienttag,id),uid,0,clienttag);
382     case ladder_sort_mostwins:
383 		if (ltime == ladder_time_current)
384 			return ladder_get_rank(ladder_cw(clienttag,id),uid,0,clienttag);
385 		else
386 			return ladder_get_rank(ladder_aw(clienttag,id),uid,0,clienttag);
387     case ladder_sort_mostgames:
388 		if (ltime == ladder_time_current)
389 			return ladder_get_rank(ladder_cg(clienttag,id),uid,0,clienttag);
390 		else
391 			return ladder_get_rank(ladder_ag(clienttag,id),uid,0,clienttag);
392     default:
393 	eventlog(eventlog_level_error,__FUNCTION__,"got bad ladder sort %u",(unsigned int)lsort);
394     }
395 
396     return 0;
397 }
398 
in_same_team(t_account * acc1,t_account * acc2,unsigned int tc1,unsigned int tc2,t_clienttag clienttag)399 int in_same_team(t_account * acc1, t_account * acc2, unsigned int tc1, unsigned int tc2, t_clienttag clienttag)
400 {
401    return 0;
402 }
403 
solo_ladder(t_clienttag clienttag)404 extern t_ladder * solo_ladder(t_clienttag clienttag)
405 {
406   if (clienttag==CLIENTTAG_WARCRAFT3_UINT)
407     return &WAR3_solo_ladder;
408   if (clienttag==CLIENTTAG_WAR3XP_UINT)
409     return &W3XP_solo_ladder;
410   else
411     return NULL;
412 }
413 
team_ladder(t_clienttag clienttag)414 extern t_ladder * team_ladder(t_clienttag clienttag)
415 {
416   if (clienttag==CLIENTTAG_WARCRAFT3_UINT)
417     return &WAR3_team_ladder;
418   if (clienttag==CLIENTTAG_WAR3XP_UINT)
419     return &W3XP_team_ladder;
420   else
421     return NULL;
422 }
423 
ffa_ladder(t_clienttag clienttag)424 extern t_ladder * ffa_ladder(t_clienttag clienttag)
425 {
426   if (clienttag==CLIENTTAG_WARCRAFT3_UINT)
427     return &WAR3_ffa_ladder;
428   else
429     return &W3XP_ffa_ladder;
430 }
431 
at_ladder(t_clienttag clienttag)432 extern t_ladder * at_ladder(t_clienttag clienttag)
433 {
434   if (clienttag==CLIENTTAG_WARCRAFT3_UINT)
435     return &WAR3_at_ladder;
436   else
437     return &W3XP_at_ladder;
438 }
439 
ladder_ar(t_clienttag clienttag,t_ladder_id ladder_id)440  extern t_ladder * ladder_ar(t_clienttag clienttag, t_ladder_id ladder_id)
441  {
442    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
443 	   return &STAR_active_rating;
444    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
445 	   return &SEXP_active_rating;
446    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
447    {
448            if (ladder_id == ladder_id_normal)
449 	           return &W2BN_active_rating;
450 	   else
451 	           return &W2BN_active_rating_ironman;
452    }
453    else return NULL;
454  }
455 
ladder_aw(t_clienttag clienttag,t_ladder_id ladder_id)456  extern t_ladder * ladder_aw(t_clienttag clienttag, t_ladder_id ladder_id)
457  {
458    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
459 	   return &STAR_active_wins;
460    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
461 	   return &SEXP_active_wins;
462    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
463    {
464            if (ladder_id == ladder_id_normal)
465 	           return &W2BN_active_wins;
466 	   else
467 	           return &W2BN_active_wins_ironman;
468    }
469    else return NULL;
470  }
471 
ladder_ag(t_clienttag clienttag,t_ladder_id ladder_id)472  extern t_ladder * ladder_ag(t_clienttag clienttag, t_ladder_id ladder_id)
473  {
474    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
475 	   return &STAR_active_games;
476    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
477 	   return &SEXP_active_games;
478    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
479    {
480            if (ladder_id == ladder_id_normal)
481 	           return &W2BN_active_games;
482 	   else
483 	           return &W2BN_active_games_ironman;
484    }
485    else return NULL;
486  }
487 
ladder_cr(t_clienttag clienttag,t_ladder_id ladder_id)488  extern t_ladder * ladder_cr(t_clienttag clienttag, t_ladder_id ladder_id)
489 {
490    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
491 	   return &STAR_current_rating;
492    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
493 	   return &SEXP_current_rating;
494    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
495    {
496 	   if (ladder_id == ladder_id_normal)
497 		   return &W2BN_current_rating;
498 	   else
499 		   return &W2BN_current_rating_ironman;
500    }
501    else return NULL;
502  }
503 
ladder_cw(t_clienttag clienttag,t_ladder_id ladder_id)504  extern t_ladder * ladder_cw(t_clienttag clienttag, t_ladder_id ladder_id)
505 {
506    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
507 	   return &STAR_current_wins;
508    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
509 	   return &SEXP_current_wins;
510    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
511    {
512 	   if (ladder_id == ladder_id_normal)
513 		   return &W2BN_current_wins;
514 	   else
515 		   return &W2BN_current_wins_ironman;
516    }
517    else return NULL;
518  }
519 
ladder_cg(t_clienttag clienttag,t_ladder_id ladder_id)520  extern t_ladder * ladder_cg(t_clienttag clienttag, t_ladder_id ladder_id)
521 {
522    if (clienttag==CLIENTTAG_STARCRAFT_UINT)
523 	   return &STAR_current_games;
524    else if (clienttag==CLIENTTAG_BROODWARS_UINT)
525 	   return &SEXP_current_games;
526    else if (clienttag==CLIENTTAG_WARCIIBNE_UINT)
527    {
528 	   if (ladder_id == ladder_id_normal)
529 		   return &W2BN_current_games;
530 	   else
531 		   return &W2BN_current_games_ironman;
532    }
533    else return NULL;
534  }
535 
ladder_get_clienttag(t_ladder * ladder)536 t_clienttag ladder_get_clienttag(t_ladder * ladder)
537 {
538   return ladder->clienttag;
539 }
540 
w3_ladder_to_binary_ladder_types(t_ladder * ladder)541 t_binary_ladder_types w3_ladder_to_binary_ladder_types(t_ladder * ladder)
542 {
543   return ladder->type;
544 }
545 
binary_ladder_types_to_w3_ladder(t_binary_ladder_types type)546 t_ladder * binary_ladder_types_to_w3_ladder(t_binary_ladder_types type)
547 {
548   t_ladder * ladder;
549 
550   switch (type)
551   {
552     case WAR3_SOLO:
553 	ladder = &WAR3_solo_ladder;
554 	break;
555     case WAR3_TEAM:
556 	ladder = &WAR3_team_ladder;
557 	break;
558     case WAR3_FFA:
559 	ladder = &WAR3_ffa_ladder;
560 	break;
561     case WAR3_AT:
562 	ladder = &WAR3_at_ladder;
563 	break;
564     case W3XP_SOLO:
565 	ladder = &W3XP_solo_ladder;
566 	break;
567     case W3XP_TEAM:
568 	ladder = &W3XP_team_ladder;
569 	break;
570     case W3XP_FFA:
571 	ladder = &W3XP_ffa_ladder;
572 	break;
573     case W3XP_AT:
574 	ladder = &W3XP_at_ladder;
575 	break;
576 	case STAR_AR  :
577 	ladder = &STAR_active_rating;
578 	break;
579 	case STAR_AW  :
580 	ladder = &STAR_active_wins;
581 	break;
582 	case STAR_AG  :
583 	ladder = &STAR_active_games;
584 	break;
585 	case STAR_CR  :
586 	ladder = &STAR_current_rating;
587 	break;
588 	case STAR_CW  :
589 	ladder = &STAR_current_wins;
590 	break;
591 	case STAR_CG  :
592 	ladder = &STAR_current_games;
593 	break;
594 	case SEXP_AR  :
595 	ladder = &SEXP_active_rating;
596 	break;
597 	case SEXP_AW  :
598 	ladder = &SEXP_active_wins;
599 	break;
600 	case SEXP_AG  :
601 	ladder = &SEXP_active_games;
602 	break;
603 	case SEXP_CR  :
604 	ladder = &SEXP_current_rating;
605 	break;
606 	case SEXP_CW  :
607 	ladder = &SEXP_current_wins;
608 	break;
609 	case SEXP_CG  :
610 	ladder = &SEXP_current_games;
611 	break;
612 	case W2BN_AR  :
613 	ladder = &W2BN_active_rating;
614 	break;
615 	case W2BN_AW  :
616 	ladder = &W2BN_active_wins;
617 	break;
618 	case W2BN_AG  :
619 	ladder = &W2BN_active_games;
620 	break;
621 	case W2BN_CR  :
622 	ladder = &W2BN_current_rating;
623 	break;
624 	case W2BN_CW  :
625 	ladder = &W2BN_current_wins;
626 	break;
627 	case W2BN_CG  :
628 	ladder = &W2BN_current_games;
629 	break;
630 	case W2BN_ARI :
631 	ladder = &W2BN_active_rating_ironman;
632 	break;
633 	case W2BN_AWI :
634 	ladder = &W2BN_active_wins_ironman;
635 	break;
636 	case W2BN_AGI :
637 	ladder = &W2BN_active_games_ironman;
638 	break;
639 	case W2BN_CRI :
640 	ladder = &W2BN_current_rating_ironman;
641 	break;
642 	case W2BN_CWI :
643 	ladder = &W2BN_current_wins_ironman;
644 	break;
645 	case W2BN_CGI :
646 	ladder = &W2BN_current_games_ironman;
647 	break;
648 
649     default:
650 	eventlog(eventlog_level_error,__FUNCTION__,"got invalid ladder type %d",type);
651 	return NULL;
652   }
653   return ladder;
654 }
655 
ladder_init(t_ladder * ladder,t_binary_ladder_types type,t_clienttag clienttag,t_ladder_id ladder_id)656 void ladder_init(t_ladder *ladder,t_binary_ladder_types type, t_clienttag clienttag, t_ladder_id ladder_id)
657 {
658     ladder->first = NULL;
659     ladder->last  = NULL;
660     ladder->dirty = 1;
661     ladder->type = type;
662     ladder->clienttag = clienttag;
663     ladder->ladder_id = ladder_id;
664 }
665 
ladder_destroy(t_ladder * ladder)666 void ladder_destroy(t_ladder *ladder)
667 {
668   t_ladder_internal *pointer;
669 
670   while (ladder->first!=NULL)
671   {
672     pointer = ladder->first;
673     ladder->first = pointer->prev;
674     xfree((void *)pointer);
675   }
676 }
677 
war3_ladder_add(t_ladder * ladder,int uid,int xp,int level,t_account * account,unsigned int teamcount,t_clienttag clienttag)678 extern int war3_ladder_add(t_ladder *ladder, int uid, int xp, int level, t_account *account, unsigned int teamcount,t_clienttag clienttag)
679 {
680    t_ladder_internal *ladder_entry;
681    ladder_entry = xmalloc(sizeof(t_ladder_internal));
682 
683    ladder_entry->uid       = uid;
684    ladder_entry->xp        = xp;
685    ladder_entry->level     = level;
686    ladder_entry->account   = account;
687    ladder_entry->teamcount = teamcount;
688    ladder_entry->prev      = NULL;
689    ladder_entry->next      = NULL;
690 
691    if (ladder->first == NULL)
692    { // ladder empty, so just insert element
693       ladder->first = ladder_entry;
694       ladder->last  = ladder_entry;
695    }
696    else
697    { // already elements in list
698      // determine if first or last user in ladder has XP
699      // closest to current, cause should be the shorter way to insert
700      // new user
701         if ((ladder->first->xp - xp) >= (xp - ladder->last->xp))
702         // we should enter from last to first
703         {
704           t_ladder_internal *search;
705           search = ladder->last;
706           while ((search != NULL) && (search->level < level))
707           {
708             search = search->next;
709           }
710           while ((search != NULL) && (search->level == level) && (search->xp < xp))
711 	  {
712             search = search->next;
713 	  }
714 
715           if (teamcount!=0) // this only happens for atteams
716 	  {
717 	     t_ladder_internal *teamsearch;
718 	     t_ladder_internal *teamfound;
719 
720 	     teamsearch = search;
721 	     teamfound = NULL;
722 
723 	     while ((teamsearch != NULL) && (teamsearch->xp == xp) && (teamsearch->level == level))
724 	     {
725 	         if (in_same_team(account,teamsearch->account,teamcount,teamsearch->teamcount,clienttag))
726 	    	 {
727 		    teamfound = teamsearch;
728 		    break;
729 		 }
730 		 teamsearch = teamsearch->next;
731 	     }
732 	     if (teamfound!=NULL) search = teamfound;
733           }
734 
735           if (search == NULL)
736           {
737             ladder->first->next = ladder_entry;
738             ladder_entry->prev  = ladder->first;
739             ladder->first       = ladder_entry;
740           }
741           else
742           {
743              ladder_entry->next = search;
744              ladder_entry->prev = search->prev;
745              if (search == ladder->last)
746              // enter at end of list
747              {
748                 search->prev = ladder_entry;
749                 ladder->last = ladder_entry;
750              }
751              else
752              {
753                 search->prev->next = ladder_entry;
754                 search->prev       = ladder_entry;
755              }
756           }
757         }
758         else
759         // start from first and the search towards last
760         {
761           t_ladder_internal *search;
762           search = ladder->first;
763 	  while ((search != NULL) && (search->level > level))
764 	  {
765 	     search = search->prev;
766 	  }
767           while ((search != NULL) && (search->level == level) && (search->xp > xp))
768           {
769              search = search->prev;
770           }
771 
772 	  if (teamcount!=0) // this only happens for atteams
773 	  {
774 	     t_ladder_internal *teamsearch;
775 	     t_ladder_internal *teamfound;
776 
777 	     teamsearch = search;
778 	     teamfound = NULL;
779 
780 	     while ((teamsearch != NULL) && (teamsearch->xp == xp))
781 	     {
782 	         if (in_same_team(account,teamsearch->account,teamcount,teamsearch->teamcount,clienttag))
783 		 {
784 		    teamfound = teamsearch;
785 		    break;
786 		 }
787 		 teamsearch = teamsearch->prev;
788 	     }
789 	     if (teamfound!=NULL) search = teamfound;
790 
791 	  }
792 
793 
794           if (search == NULL)
795           {
796              ladder->last->prev = ladder_entry;
797              ladder_entry->next = ladder->last;
798              ladder->last       = ladder_entry;
799           }
800           else
801           {
802              ladder_entry->prev = search;
803              ladder_entry->next = search->next;
804              if (search == ladder->first)
805              // enter at beginning of list
806              {
807                 search->next  = ladder_entry;
808                 ladder->first = ladder_entry;
809              }
810              else
811              {
812                 search->next->prev = ladder_entry;
813                 search->next       = ladder_entry;
814              }
815            }
816         }
817       }
818        ladder->dirty = 1;
819        return 0;
820 }
821 
war3_ladder_update(t_ladder * ladder,int uid,int xp,int level,t_account * account,unsigned int teamcount)822 extern int war3_ladder_update(t_ladder *ladder, int uid, int xp, int level, t_account *account, unsigned int teamcount)
823 {
824    t_ladder_internal *search, *newpos;
825    search = ladder->first;
826    while (search && ((search->uid != uid) || (search->teamcount!=teamcount))) { search = search->prev; }
827    if (search != NULL)
828    {
829      search->xp += xp;
830      search->level = level;
831      ladder->dirty = 1;
832 
833      // make sure, we don't get negative XP
834      if (search->xp < 0) search->xp = 0;
835 
836      if (xp>0)
837      // XP gained.... maybe getting better ranking
838      {
839         newpos = search->next;
840 	while ((newpos != NULL) && (newpos->level < level))
841 	{
842 	  newpos = newpos->next;
843 	}
844         while ((newpos != NULL) && (newpos->level == level) && (newpos->xp < search->xp))
845         {
846           newpos = newpos->next;
847         }
848         if (newpos != search->next)
849         // so we really have to change ranking now
850         {
851           // first close gap, where we've been...
852           search->next->prev = search->prev;
853           if (search->prev != NULL)
854             search->prev->next = search->next;
855           else
856             ladder->last = search->next;
857           // and then move to new position
858           search->next = newpos;
859           if (newpos == NULL)
860           {
861              search->prev = ladder->first;
862              ladder->first->next = search;
863              ladder->first       = search;
864           }
865           else
866           {
867             search->prev = newpos->prev;
868             newpos->prev->next = search;
869             newpos->prev = search;
870           }
871         }
872      }
873      if (xp<0)
874      // XP lost.... maybe ranking gets worse
875      {
876         newpos = search->prev;
877 	while ((newpos != NULL) && (newpos->level > level))
878 	{
879 	  newpos = newpos->prev;
880 	}
881         while ((newpos != NULL) && (newpos->level == level) && (newpos->xp > search->xp))
882         {
883           newpos = newpos->prev;
884         }
885         if (newpos != search->prev)
886         // so we really have to change ranking now
887         {
888           // first close gap, where we've been...
889           search->prev->next = search->next;
890           if (search->next != NULL)
891             search->next->prev = search->prev;
892           else
893             ladder->first = search->prev;
894           // and then move to new position
895           search->prev = newpos;
896           if (newpos == NULL)
897           {
898              search->next = ladder->last;
899              ladder->last->prev = search;
900              ladder->last       = search;
901           }
902           else
903           {
904             search->next = newpos->next;
905             newpos->next->prev = search;
906             newpos->next = search;
907           }
908         }
909      }
910      return 0;
911    }
912    else
913    return -1;
914  }
915 
ladder_get_rank(t_ladder * ladder,int uid,unsigned int teamcount,t_clienttag clienttag)916  extern int ladder_get_rank(t_ladder *ladder, int uid, unsigned int teamcount, t_clienttag clienttag)
917  {
918    int ranking = 1;
919    t_ladder_internal *search;
920    search = ladder->first;
921    while ((search!=NULL) && ((search->uid != uid) || (search->teamcount!=teamcount)))
922    {
923      search = search->prev;
924      ranking++;
925      if (ladder==at_ladder(clienttag))
926      {
927        // if in the same team as previous account
928        if ((search) && (search->next)
929            && in_same_team(search->account,search->next->account,teamcount,search->next->teamcount,clienttag))
930 	       ranking--;
931      }
932    }
933    if (search != NULL)
934    {
935      return ranking;
936    }
937    else
938    {
939      return 0;
940    }
941  }
942 
ladder_get_rank_internal(t_ladder * ladder,int rank,t_clienttag clienttag)943 t_ladder_internal * ladder_get_rank_internal(t_ladder * ladder,int rank, t_clienttag clienttag)
944 {
945   int ranking;
946   t_ladder_internal *search;
947 
948   // this should be a huge speedup when getting many subsequent entries from ladder
949   // like used in saving of binary ladders
950   if ((last_ladder == ladder) && (last_rank < rank) && (last_internal != NULL))
951     {
952       ranking = last_rank;
953       search = last_internal;
954     }
955   else
956     {
957       ranking = 1;
958       search = ladder->first;
959     }
960 
961   while ((search!=NULL) && (ranking<rank))
962   {
963      search = search->prev;
964      ranking++;
965      if (ladder == at_ladder(clienttag))
966      {
967        if ((search) && (search->next)
968 	  && in_same_team(search->account,search->next->account,search->teamcount,search->next->teamcount,clienttag))
969 	      ranking--;
970      }
971   }
972   last_ladder   = ladder;
973   last_internal = search;
974   last_rank     = rank;
975   return search;
976 }
977 
ladder_get_account(t_ladder * ladder,int rank,unsigned int * teamcount,t_clienttag clienttag)978 extern t_account * ladder_get_account(t_ladder *ladder, int rank, unsigned int * teamcount,t_clienttag clienttag)
979 {
980   t_ladder_internal *search;
981 
982   if (!(ladder))
983   {
984     // eventlog(eventlog_level_error,__FUNCTION__,"got request for non-existant ladder");
985     return NULL;
986   }
987 
988   search = ladder_get_rank_internal(ladder,rank,clienttag);
989 
990   if (search)
991   {
992     *teamcount = search->teamcount;
993     return search->account;
994   }
995   else
996   {
997     *teamcount = 0;
998     return NULL;
999   }
1000 }
1001 
1002 typedef int (* t_set_fct)(t_account *account,t_clienttag cltag, t_ladder_id ldr_id,unsigned int rank);
1003 typedef int (* t_get_fct)(t_account *account,t_clienttag cltag, t_ladder_id ldr_id);
1004 
ladder_update_accounts(t_ladder * ladder,t_set_fct set_fct,t_get_fct get_fct1)1005 extern int ladder_update_accounts(t_ladder *ladder, t_set_fct set_fct, t_get_fct get_fct1)
1006 {
1007     t_ladder_internal *pointer, *tmp_pointer;
1008     t_account *account;
1009     t_clienttag clienttag;
1010     int rank = 1;
1011     int update = 0;
1012     char clienttag_str[5];
1013 
1014     if (ladder->dirty == 1)
1015     {
1016       if ((set_fct!=NULL) && (get_fct1!=NULL))
1017       {
1018       clienttag = ladder_get_clienttag(ladder);
1019       pointer = ladder->first;
1020       while (pointer!=NULL)
1021       {
1022          account = pointer->account;
1023          if (rank <= MaxRankKeptInLadder)
1024          {
1025            if (ladder->ladder_id == ladder_id_none) //war3/w3xp AT ladder
1026 	   {
1027 		   // do nothing now
1028 	   }
1029 	   else //other ladders...
1030 	   {
1031 	     if ((*get_fct1)(account,clienttag,ladder->ladder_id)!=rank)
1032              {
1033 	       (*set_fct)(account,clienttag,ladder->ladder_id,rank);
1034 	       update++;
1035 	     }
1036 	   }
1037 
1038 	   pointer=pointer->prev;
1039 	   rank++;
1040 
1041          }
1042          else
1043 	 {
1044 	   // leave while loop
1045            break;
1046 	 }
1047       }
1048       while (pointer!=NULL)
1049       {
1050         // all accounts following now are out of the ladder range we keep track of....
1051 	    // so set rank to 0 and remove account from ladder
1052         if (ladder->ladder_id == ladder_id_none) //war3/w3xp AT ladder
1053 		{
1054 	          if ((*get_fct1)(account,pointer->teamcount,clienttag)!=0)
1055 		    (*set_fct)(account,pointer->teamcount,clienttag,0);
1056 		}
1057 		else
1058 		{
1059 		  if ((*get_fct1)(account,clienttag,ladder->ladder_id)!=0)
1060 		    (*set_fct)(account,clienttag,ladder->ladder_id,0);
1061 		}
1062 
1063 	// remove account from ladder
1064 	if (pointer->next!=NULL) pointer->next->prev = pointer->prev;
1065 	if (pointer->prev!=NULL) pointer->prev->next = pointer->next;
1066 	if (ladder->last == pointer)  ladder->last  = pointer->next;
1067 	if (ladder->first == pointer) ladder->first = pointer->prev;
1068 	tmp_pointer = pointer->prev;
1069 	xfree((void *)pointer);
1070 	pointer = tmp_pointer;
1071       }
1072       }
1073       binary_ladder_save(w3_ladder_to_binary_ladder_types(ladder),4,&ladder_get_from_ladder);
1074       if (update != 0)
1075         eventlog(eventlog_level_info,__FUNCTION__,"updated %u accounts for clienttag %s",update,tag_uint_to_str(clienttag_str,ladder->clienttag));
1076     }
1077     ladder->dirty = 0;
1078     return 0;
1079 }
1080 
ladder_update_all_accounts(void)1081 extern int ladder_update_all_accounts(void)
1082 {
1083   eventlog(eventlog_level_info,__FUNCTION__,"updating ranking for all accounts");
1084   ladder_update_accounts(&WAR3_solo_ladder, &account_set_ladder_rank,   &account_get_ladder_rank);
1085   ladder_update_accounts(&WAR3_team_ladder, &account_set_ladder_rank,   &account_get_ladder_rank);
1086   ladder_update_accounts(&WAR3_ffa_ladder,  &account_set_ladder_rank,   &account_get_ladder_rank);
1087   //ladder_update_accounts(&WAR3_at_ladder,  &account_set_atteamrank, &account_get_atteamrank);
1088   ladder_update_accounts(&W3XP_solo_ladder, &account_set_ladder_rank,   &account_get_ladder_rank);
1089   ladder_update_accounts(&W3XP_team_ladder, &account_set_ladder_rank,   &account_get_ladder_rank);
1090   ladder_update_accounts(&W3XP_ffa_ladder,  &account_set_ladder_rank,   &account_get_ladder_rank);
1091   //ladder_update_accounts(&W3XP_at_ladder,  &account_set_atteamrank, &account_get_atteamrank);
1092   ladder_update_accounts(&STAR_current_rating,&account_set_ladder_rank, &account_get_ladder_rank);
1093   ladder_update_accounts(&STAR_current_wins,  NULL,                      NULL);
1094   ladder_update_accounts(&STAR_current_games, NULL,                      NULL);
1095   ladder_update_accounts(&SEXP_current_rating,&account_set_ladder_rank, &account_get_ladder_rank);
1096   ladder_update_accounts(&SEXP_current_wins,  NULL,                      NULL);
1097   ladder_update_accounts(&SEXP_current_games, NULL,                      NULL);
1098   ladder_update_accounts(&STAR_active_rating, &account_set_ladder_active_rank, &account_get_ladder_active_rank);
1099   ladder_update_accounts(&STAR_active_wins,   NULL,                      NULL);
1100   ladder_update_accounts(&STAR_active_games,  NULL,                      NULL);
1101   ladder_update_accounts(&SEXP_active_rating, &account_set_ladder_active_rank, &account_get_ladder_active_rank);
1102   ladder_update_accounts(&SEXP_active_wins,   NULL,                      NULL);
1103   ladder_update_accounts(&SEXP_active_games,  NULL,                      NULL);
1104   ladder_update_accounts(&W2BN_current_rating,&account_set_ladder_rank, &account_get_ladder_rank);
1105   ladder_update_accounts(&W2BN_current_wins,  NULL,                      NULL);
1106   ladder_update_accounts(&W2BN_current_games, NULL,                      NULL);
1107   ladder_update_accounts(&W2BN_active_rating, &account_set_ladder_rank, &account_get_ladder_rank);
1108   ladder_update_accounts(&W2BN_active_wins,   NULL,                      NULL);
1109   ladder_update_accounts(&W2BN_active_games,  NULL,                      NULL);
1110   ladder_update_accounts(&W2BN_current_rating_ironman, &account_set_ladder_rank, &account_get_ladder_rank);
1111   ladder_update_accounts(&W2BN_current_wins_ironman,  NULL,                      NULL);
1112   ladder_update_accounts(&W2BN_current_games_ironman, NULL,                      NULL);
1113   ladder_update_accounts(&W2BN_active_rating_ironman, &account_set_ladder_rank, &account_get_ladder_rank);
1114   ladder_update_accounts(&W2BN_active_wins_ironman,  NULL,                      NULL);
1115   ladder_update_accounts(&W2BN_active_games_ironman, NULL,                      NULL);
1116 
1117   eventlog(eventlog_level_info,__FUNCTION__,"finished updating ranking for all accounts");
1118   return 0;
1119 }
1120 
binary_load(t_binary_ladder_types type)1121 t_binary_ladder_load_result binary_load(t_binary_ladder_types type)
1122 {
1123   t_binary_ladder_load_result result;
1124   t_ladder * ladder;
1125 
1126   result = binary_ladder_load(type,4,&ladder_put_into_ladder);
1127   if (result == illegal_checksum)
1128   {
1129     t_clienttag clienttag;
1130 	t_ladder_id ladder_id;
1131 
1132     ladder = binary_ladder_types_to_w3_ladder(type);
1133 	clienttag = ladder_get_clienttag(ladder);
1134 	ladder_id = ladder->ladder_id;
1135     ladder_destroy(ladder);
1136     ladder_init(ladder,type,clienttag,ladder_id);
1137   }
1138   return result;
1139 }
1140 
ladders_load_accounts_to_ladderlists(void)1141 extern void ladders_load_accounts_to_ladderlists(void)
1142 {
1143   t_entry   * curr;
1144   t_account * account;
1145   int xp;
1146 
1147   t_binary_ladder_load_result war3_solo_res, war3_team_res, war3_ffa_res, war3_at_res;
1148   t_binary_ladder_load_result w3xp_solo_res, w3xp_team_res, w3xp_ffa_res, w3xp_at_res;
1149   t_binary_ladder_load_result star_ar_res, star_aw_res, star_ag_res, star_cr_res, star_cw_res, star_cg_res;
1150   t_binary_ladder_load_result sexp_ar_res, sexp_aw_res, sexp_ag_res, sexp_cr_res, sexp_cw_res, sexp_cg_res;
1151   t_binary_ladder_load_result w2bn_cr_res, w2bn_cw_res, w2bn_cg_res, w2bn_cri_res, w2bn_cwi_res, w2bn_cgi_res;
1152   t_binary_ladder_load_result w2bn_ar_res, w2bn_aw_res, w2bn_ag_res, w2bn_ari_res, w2bn_awi_res, w2bn_agi_res;
1153 
1154   war3_solo_res = binary_load(WAR3_SOLO);
1155   war3_team_res = binary_load(WAR3_TEAM);
1156   war3_ffa_res  = binary_load(WAR3_FFA);
1157   war3_at_res   = load_success; // binary_load(WAR3_AT);
1158   w3xp_solo_res = binary_load(W3XP_SOLO);
1159   w3xp_team_res = binary_load(W3XP_TEAM);
1160   w3xp_ffa_res  = binary_load(W3XP_FFA);
1161   w3xp_at_res   = load_success; // binary_load(W3XP_AT);
1162   star_ar_res   = binary_load(STAR_AR);
1163   star_aw_res   = binary_load(STAR_AW);
1164   star_ag_res   = binary_load(STAR_AG);
1165   star_cr_res   = binary_load(STAR_CR);
1166   star_cw_res   = binary_load(STAR_CW);
1167   star_cg_res   = binary_load(STAR_CG);
1168   sexp_ar_res   = binary_load(SEXP_AR);
1169   sexp_aw_res   = binary_load(SEXP_AW);
1170   sexp_ag_res   = binary_load(SEXP_AG);
1171   sexp_cr_res   = binary_load(SEXP_CR);
1172   sexp_cw_res   = binary_load(SEXP_CW);
1173   sexp_cg_res   = binary_load(SEXP_CG);
1174   w2bn_cr_res   = binary_load(W2BN_CR);
1175   w2bn_cw_res   = binary_load(W2BN_CW);
1176   w2bn_cg_res   = binary_load(W2BN_CG);
1177   w2bn_cri_res  = binary_load(W2BN_CRI);
1178   w2bn_cwi_res  = binary_load(W2BN_CWI);
1179   w2bn_cgi_res  = binary_load(W2BN_CGI);
1180   w2bn_ar_res   = binary_load(W2BN_AR);
1181   w2bn_aw_res   = binary_load(W2BN_AW);
1182   w2bn_ag_res   = binary_load(W2BN_AG);
1183   w2bn_ari_res  = binary_load(W2BN_ARI);
1184   w2bn_awi_res  = binary_load(W2BN_AWI);
1185   w2bn_agi_res  = binary_load(W2BN_AGI);
1186 
1187   if ((war3_solo_res + war3_team_res + war3_ffa_res + war3_at_res +
1188        w3xp_solo_res + w3xp_team_res + w3xp_ffa_res + w3xp_at_res +
1189        star_ar_res   + star_aw_res   + star_ag_res  + star_cr_res + star_cw_res + star_cg_res +
1190        sexp_ar_res   + sexp_aw_res   + sexp_ag_res  + sexp_cr_res + sexp_cw_res + sexp_cg_res +
1191        w2bn_cr_res   + w2bn_cw_res   + w2bn_cg_res  +
1192        w2bn_cri_res  + w2bn_cwi_res  + w2bn_cgi_res +
1193        w2bn_ar_res   + w2bn_aw_res   + w2bn_ag_res  +
1194        w2bn_ari_res  + w2bn_awi_res  + w2bn_agi_res ) == load_success)
1195   {
1196     eventlog(eventlog_level_trace,__FUNCTION__,"everything went smooth... taking shortcut");
1197     return;
1198   }
1199 
1200   eventlog(eventlog_level_warn, __FUNCTION__, "binary ladders missing or incomplete, going to load all accounts to rebuild them");
1201   if (accountlist_load_all(ST_FORCE)) {
1202     eventlog(eventlog_level_error, __FUNCTION__, "error loading all accounts");
1203     return;
1204   }
1205   HASHTABLE_TRAVERSE(accountlist(),curr)
1206     {
1207       if ((account=((t_account *)entry_get_data(curr))))
1208 	  {
1209 	      int rating, wins;
1210 	      int uid = account_get_uid(account);
1211 
1212 	      if ((war3_solo_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_solo))))
1213 		  {
1214 		  war3_ladder_add(&WAR3_solo_ladder,
1215 				  uid, xp,
1216 				  account_get_ladder_level(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_solo),
1217 				  account,0,CLIENTTAG_WARCRAFT3_UINT);
1218 		  }
1219 	      if ((war3_team_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_team))))
1220 		  {
1221 		  war3_ladder_add(&WAR3_team_ladder,
1222 				  uid, xp,
1223 				  account_get_ladder_level(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_team),
1224 				  account,0,CLIENTTAG_WARCRAFT3_UINT);
1225 
1226 		  }
1227 	      if ((war3_ffa_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_ffa))))
1228 		  {
1229 		  war3_ladder_add(&WAR3_ffa_ladder,
1230 				  uid, xp,
1231 				  account_get_ladder_level(account,CLIENTTAG_WARCRAFT3_UINT,ladder_id_ffa),
1232 				  account,0,CLIENTTAG_WARCRAFT3_UINT);
1233 		  }
1234 	      // user is part of a team
1235 	      /*
1236 	      if ((war3_at_res!=load_success) && ((teamcount = account_get_atteamcount(account,CLIENTTAG_WARCRAFT3_UINT))))
1237 		  {
1238 		  int counter;
1239 		  for (counter=1; counter<=teamcount; counter++)
1240 		    {
1241 		      if ((xp = account_get_atteamxp(account,counter,CLIENTTAG_WARCRAFT3_UINT)) &&
1242 				   account_get_atteammembers(account,counter,CLIENTTAG_WARCRAFT3_UINT))
1243 			  {
1244 			  war3_ladder_add(&WAR3_at_ladder,
1245 					  uid, xp,
1246 					  account_get_atteamlevel(account,counter,CLIENTTAG_WARCRAFT3_UINT),
1247 					  account,
1248 					  counter,CLIENTTAG_WARCRAFT3_UINT);
1249 			  }
1250 		    }
1251 		  }
1252 		  */
1253 	      if ((w3xp_solo_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WAR3XP_UINT,ladder_id_solo))))
1254 		  {
1255 		  war3_ladder_add(&W3XP_solo_ladder,
1256 				  uid, xp,
1257 				  account_get_ladder_level(account,CLIENTTAG_WAR3XP_UINT,ladder_id_solo),
1258 				  account,0,CLIENTTAG_WAR3XP_UINT);
1259 		  }
1260 	      if ((w3xp_team_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WAR3XP_UINT,ladder_id_team))))
1261 		  {
1262 		  war3_ladder_add(&W3XP_team_ladder,
1263 				  uid, xp,
1264 				  account_get_ladder_level(account,CLIENTTAG_WAR3XP_UINT,ladder_id_team),
1265 				  account,0,CLIENTTAG_WAR3XP_UINT);
1266 
1267 		  }
1268 	      if ((w3xp_ffa_res!=load_success) && ((xp = account_get_ladder_xp(account,CLIENTTAG_WAR3XP_UINT,ladder_id_ffa))))
1269 		  {
1270 		  war3_ladder_add(&W3XP_ffa_ladder,
1271 				  uid, xp,
1272 				  account_get_ladder_level(account,CLIENTTAG_WAR3XP_UINT,ladder_id_ffa),
1273 				  account,0,
1274 				  CLIENTTAG_WAR3XP_UINT);
1275 		  }
1276 	      // user is part of a team
1277 	      /*
1278 	      if ((w3xp_at_res!=load_success) && ((teamcount = account_get_atteamcount(account,CLIENTTAG_WAR3XP_UINT))))
1279 	 	  {
1280 		  int counter;
1281 		  for (counter=1; counter<=teamcount; counter++)
1282 		    {
1283 
1284 		      if ((xp = account_get_atteamxp(account,counter,CLIENTTAG_WAR3XP_UINT)) &&
1285 				   account_get_atteammembers(account,counter,CLIENTTAG_WAR3XP_UINT))
1286 			  {
1287 			  war3_ladder_add(&W3XP_at_ladder,
1288 					  uid, xp,
1289 					  account_get_atteamlevel(account,counter,CLIENTTAG_WAR3XP_UINT),
1290 					  account,
1291 					  counter,CLIENTTAG_WAR3XP_UINT);
1292 			  }
1293 		    }
1294 		  }
1295 		  */
1296 
1297 		  if ((rating = account_get_ladder_rating(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal))>0)
1298 		  {
1299 		    wins   = account_get_ladder_wins(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1300 
1301 		    if (star_cr_res!=load_success)
1302 	     	    {
1303 		       war3_ladder_add(&STAR_current_rating, uid,wins,rating,account,0,CLIENTTAG_STARCRAFT_UINT);
1304 	 	    }
1305 
1306 		    if (star_cw_res!=load_success)
1307 	     	    {
1308 	 	       war3_ladder_add(&STAR_current_wins, uid,rating,wins,account,0,CLIENTTAG_STARCRAFT_UINT);
1309 	 	    }
1310 
1311 		    if (star_cg_res!=load_success)
1312 	     	    {
1313 	 	      int games = wins +
1314 		                  account_get_ladder_losses(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal)+
1315 	                          account_get_ladder_disconnects(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1316 
1317 	 	      war3_ladder_add(&STAR_current_games, uid,rating,games,account,0,CLIENTTAG_STARCRAFT_UINT);
1318 	     	    }
1319 		  }
1320 
1321 		  if ((rating = account_get_ladder_active_rating(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal))>0)
1322 		  {
1323 		    wins   = account_get_ladder_active_wins(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1324 
1325 	 	    if (star_ar_res!=load_success)
1326 	 	    {
1327 		      war3_ladder_add(&STAR_active_rating, uid,wins,rating,account,0,CLIENTTAG_STARCRAFT_UINT);
1328 	 	    }
1329 
1330 		    if (star_aw_res!=load_success)
1331 	     	    {
1332 		      war3_ladder_add(&STAR_active_wins, uid,rating,wins,account,0,CLIENTTAG_STARCRAFT_UINT);
1333 	 	    }
1334 
1335 		    if (star_ag_res!=load_success)
1336 	     	    {
1337 		      int games = wins +
1338 			     	  account_get_ladder_active_losses(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal)+
1339 	                     	  account_get_ladder_active_disconnects(account,CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1340 
1341 	 	      war3_ladder_add(&STAR_active_games, uid,rating,games,account,0,CLIENTTAG_STARCRAFT_UINT);
1342 	     	    }
1343 		  }
1344 
1345 		  if ((rating = account_get_ladder_rating(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal))>0)
1346 		  {
1347 		    wins = account_get_ladder_wins(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1348 
1349 		    if (sexp_cr_res!=load_success)
1350 	     	    {
1351 		      war3_ladder_add(&SEXP_current_rating, uid,wins,rating,account,0,CLIENTTAG_BROODWARS_UINT);
1352 	 	    }
1353 
1354 		    if (sexp_cw_res!=load_success)
1355 	     	    {
1356 	 	      war3_ladder_add(&SEXP_current_wins, uid,rating,wins,account,0,CLIENTTAG_BROODWARS_UINT);
1357 	 	    }
1358 
1359 		    if (sexp_cg_res!=load_success)
1360 	     	    {
1361 	 	      int games = wins +
1362 		 		  account_get_ladder_losses(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal)+
1363 	         	          account_get_ladder_disconnects(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1364 
1365 	 	      war3_ladder_add(&SEXP_current_games, uid,rating,games,account,0,CLIENTTAG_BROODWARS_UINT);
1366 	     	    }
1367 		  }
1368 
1369 		  if ((rating = account_get_ladder_active_rating(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal))>0)
1370 		  {
1371 		    wins = account_get_ladder_active_wins(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1372 
1373 	 	    if (sexp_ar_res!=load_success)
1374 	 	    {
1375 		      war3_ladder_add(&SEXP_active_rating, uid,wins,rating,account,0,CLIENTTAG_BROODWARS_UINT);
1376 	 	    }
1377 
1378 		    if (sexp_aw_res!=load_success)
1379 	     	    {
1380 		      war3_ladder_add(&SEXP_active_wins, uid,rating,wins,account,0,CLIENTTAG_BROODWARS_UINT);
1381 	 	    }
1382 
1383 		    if (sexp_ag_res!=load_success)
1384 	     	    {
1385 		      int games = wins +
1386 			     	  account_get_ladder_active_losses(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal)+
1387 	                     	  account_get_ladder_active_disconnects(account,CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1388 
1389 	 	       war3_ladder_add(&SEXP_active_games, uid,rating,games,account,0,CLIENTTAG_BROODWARS_UINT);
1390 	     	    }
1391 		  }
1392 
1393 		  if ((rating = account_get_ladder_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal))>0)
1394 		  {
1395 		    wins = account_get_ladder_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1396 
1397 		    if (w2bn_cr_res!=load_success)
1398 	     	    {
1399 		      war3_ladder_add(&W2BN_current_rating, uid,wins,rating,account,0,CLIENTTAG_WARCIIBNE_UINT);
1400 	 	    }
1401 
1402 		    if (w2bn_cw_res!=load_success)
1403 	     	    {
1404 	 	      war3_ladder_add(&W2BN_current_wins, uid,rating,wins,account,0,CLIENTTAG_WARCIIBNE_UINT);
1405 	 	    }
1406 
1407 		    if (w2bn_cg_res!=load_success)
1408 	     	    {
1409 	 	      int games = wins +
1410 		 		  account_get_ladder_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal)+
1411 	         	          account_get_ladder_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1412 
1413 	 	      war3_ladder_add(&W2BN_current_games, uid,rating,games,account,0,CLIENTTAG_WARCIIBNE_UINT);
1414 	     	    }
1415 		  }
1416 
1417 		  if ((rating = account_get_ladder_active_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal))>0)
1418 		  {
1419 		    wins = account_get_ladder_active_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1420 
1421 		    if (w2bn_ar_res!=load_success)
1422 	     	    {
1423 		      war3_ladder_add(&W2BN_active_rating, uid,wins,rating,account,0,CLIENTTAG_WARCIIBNE_UINT);
1424 	 	    }
1425 
1426 		    if (w2bn_aw_res!=load_success)
1427 	     	    {
1428 	 	      war3_ladder_add(&W2BN_active_wins, uid,rating,wins,account,0,CLIENTTAG_WARCIIBNE_UINT);
1429 	 	    }
1430 
1431 		    if (w2bn_ag_res!=load_success)
1432 	     	    {
1433 	 	      int games = wins +
1434 		 		  account_get_ladder_active_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal)+
1435 	         	          account_get_ladder_active_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1436 
1437 	 	      war3_ladder_add(&W2BN_active_games, uid,rating,games,account,0,CLIENTTAG_WARCIIBNE_UINT);
1438 	     	    }
1439 		  }
1440 
1441 		  if ((rating = account_get_ladder_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman))>0)
1442 		  {
1443 	            wins = account_get_ladder_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1444 
1445 		    if (w2bn_cri_res!=load_success)
1446 	     	    {
1447 		      war3_ladder_add(&W2BN_current_rating_ironman, uid,wins,rating,account,0,CLIENTTAG_WARCIIBNE_UINT);
1448 	 	    }
1449 
1450 		    if (w2bn_cwi_res!=load_success)
1451 	     	    {
1452 	 	      war3_ladder_add(&W2BN_current_wins_ironman, uid,rating,wins,account,0,CLIENTTAG_WARCIIBNE_UINT);
1453 	 	    }
1454 
1455 		    if (w2bn_cgi_res!=load_success)
1456 	     	    {
1457 	 	      int games = wins +
1458 		 		  account_get_ladder_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman)+
1459 	         	          account_get_ladder_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1460 
1461 	 	      war3_ladder_add(&W2BN_current_games_ironman, uid,rating,games,account,0,CLIENTTAG_WARCIIBNE_UINT);
1462 	     	    }
1463 		  }
1464 
1465 		  if ((rating = account_get_ladder_active_rating(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman))>0)
1466 		  {
1467 		    wins = account_get_ladder_active_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1468 
1469 		    if (w2bn_ari_res!=load_success)
1470 	     	    {
1471 		      war3_ladder_add(&W2BN_active_rating_ironman, uid,wins,rating,account,0,CLIENTTAG_WARCIIBNE_UINT);
1472 	 	    }
1473 
1474 		    if (w2bn_awi_res!=load_success)
1475 	     	    {
1476 	 	      war3_ladder_add(&W2BN_active_wins_ironman, uid,rating,wins,account,0,CLIENTTAG_WARCIIBNE_UINT);
1477 	 	    }
1478 
1479 		    if (w2bn_agi_res!=load_success)
1480 	     	    {
1481 	 	      int games = account_get_ladder_active_wins(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman)+
1482 		 		  account_get_ladder_active_losses(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman)+
1483 	         	          account_get_ladder_active_disconnects(account,CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1484 
1485 	 	      war3_ladder_add(&W2BN_active_games_ironman, uid,rating, games,account,0,CLIENTTAG_WARCIIBNE_UINT);
1486 	     	    }
1487 		  }
1488 
1489 	   }
1490     }
1491 }
1492 
1493 
standard_writer(FILE * fp,t_ladder * ladder,t_clienttag clienttag)1494 int standard_writer(FILE * fp, t_ladder * ladder, t_clienttag clienttag)
1495 {
1496     t_ladder_internal * pointer;
1497     unsigned int rank=0;
1498 
1499     pointer = ladder->first;
1500     while (pointer != NULL)
1501     {
1502 	rank++;
1503 	if (clienttag==CLIENTTAG_WARCRAFT3_UINT || clienttag==CLIENTTAG_WAR3XP_UINT)
1504 	{
1505 	    if (ladder==at_ladder(clienttag))
1506 	    {
1507 		// if in the same team as previous account
1508 		if ((pointer) && (pointer->next)
1509 		    && in_same_team(pointer->account,pointer->next->account,pointer->teamcount,pointer->next->teamcount,clienttag))
1510 		{
1511 		    rank--;
1512 		}
1513 		// other team... so write all team members names, xp and rank to file
1514 		else
1515 		{
1516 		    //fprintf(fp,"%s,%u,%u\n",account_get_atteammembers(pointer->account,pointer->teamcount,clienttag),pointer->xp,rank);
1517 		}
1518 	    }
1519 	    else
1520 	    // write username, xp and rank to file
1521 		fprintf(fp,"%s,%u,%u\n",account_get_name(pointer->account),pointer->xp,rank);
1522 	}
1523 	else if (clienttag==CLIENTTAG_STARCRAFT_UINT || clienttag==CLIENTTAG_BROODWARS_UINT || clienttag==CLIENTTAG_WARCIIBNE_UINT)
1524 	{
1525 	    fprintf(fp,"%u %s %u (%u / %u / %u)\n",rank, account_get_name(pointer->account),pointer->level,
1526 		account_get_ladder_wins(pointer->account,ladder->clienttag,ladder->ladder_id),
1527 		account_get_ladder_losses(pointer->account,ladder->clienttag,ladder->ladder_id),
1528 		account_get_ladder_disconnects(pointer->account,ladder->clienttag,ladder->ladder_id));
1529 	}
1530 	pointer=pointer->prev;
1531   }
1532   return 0;
1533 }
1534 
XML_writer(FILE * fp,t_ladder * ladder,t_clienttag clienttag)1535 int XML_writer(FILE * fp, t_ladder * ladder, t_clienttag clienttag)
1536   /* XML Ladder files
1537    * added by jfro
1538    * 1/2/2003
1539    */
1540 {
1541   t_ladder_internal * pointer;
1542   unsigned int rank=0;
1543   unsigned int level;
1544   unsigned int wins;
1545   unsigned int losses;
1546   unsigned int discs;
1547   unsigned int orc_wins,human_wins,undead_wins,nightelf_wins,random_wins;
1548   unsigned int orc_losses,human_losses,undead_losses,nightelf_losses,random_losses;
1549 
1550   fprintf(fp,"<?xml version=\"1.0\"?>\n<ladder>\n");
1551   pointer = ladder->first;
1552   while (pointer != NULL)
1553   {
1554      rank++;
1555 
1556      if (clienttag==CLIENTTAG_WARCRAFT3_UINT || clienttag==CLIENTTAG_WAR3XP_UINT)
1557      {
1558 
1559      if (ladder==at_ladder(clienttag))
1560      {
1561        // if in the same team as previous account
1562        if ((pointer) && (pointer->next)
1563            && in_same_team(pointer->account,pointer->next->account,pointer->teamcount,pointer->next->teamcount,clienttag))
1564 	       rank--;
1565        else
1566 	 {
1567 	   /* other team... so write all team members names, xp and rank to file
1568 	   fprintf(fp,"\t<team>\n");
1569 	   if (account_get_atteammembers(pointer->account,pointer->teamcount,clienttag)==NULL)
1570 	     {
1571 	       eventlog(eventlog_level_error,__FUNCTION__,"got invalid team, skipping");
1572 	       pointer=pointer->prev;
1573 	       continue;
1574 	     }
1575 
1576 	   members = xstrdup(account_get_atteammembers(pointer->account,pointer->teamcount,clienttag));
1577 	   for ( member = strtok(members," ");
1578 		 member;
1579 		 member = strtok(NULL," "))
1580 	       fprintf(fp,"\t\t<member>%s</member>\n",member);
1581 	   xfree(members);
1582 	   fprintf(fp,"\t\t<xp>%u</xp>\n\t\t<rank>%u</rank>\n\t</team>\n",pointer->xp,rank);
1583 	   */
1584 	 }
1585      }
1586      else {
1587          if (ladder==solo_ladder(clienttag)) {
1588            level = account_get_ladder_level(pointer->account,clienttag,ladder_id_solo);
1589            wins = account_get_ladder_wins(pointer->account,clienttag,ladder_id_solo);
1590            losses = account_get_ladder_losses(pointer->account,clienttag,ladder_id_solo);
1591          }
1592          else if (ladder==team_ladder(clienttag)) {
1593            level = account_get_ladder_level(pointer->account,clienttag,ladder_id_team);
1594            wins = account_get_ladder_wins(pointer->account,clienttag,ladder_id_team);
1595            losses = account_get_ladder_losses(pointer->account,clienttag,ladder_id_team);
1596          }
1597          else if (ladder==ffa_ladder(clienttag)) {
1598            level = account_get_ladder_level(pointer->account,clienttag,ladder_id_ffa);
1599            wins = account_get_ladder_wins(pointer->account,clienttag,ladder_id_ffa);
1600            losses = account_get_ladder_losses(pointer->account,clienttag,ladder_id_ffa);
1601          }
1602          else {
1603            level = 0;
1604            wins = 0;
1605            losses = 0;
1606          }
1607          orc_wins = account_get_racewins(pointer->account,W3_RACE_ORCS,clienttag);
1608          orc_losses = account_get_racelosses(pointer->account,W3_RACE_ORCS,clienttag);
1609          undead_wins = account_get_racewins(pointer->account,W3_RACE_UNDEAD,clienttag);
1610          undead_losses = account_get_racelosses(pointer->account,W3_RACE_UNDEAD,clienttag);
1611          human_wins = account_get_racewins(pointer->account,W3_RACE_HUMANS,clienttag);
1612          human_losses = account_get_racelosses(pointer->account,W3_RACE_HUMANS,clienttag);
1613          nightelf_wins = account_get_racewins(pointer->account,W3_RACE_NIGHTELVES,clienttag);
1614          nightelf_losses = account_get_racelosses(pointer->account,W3_RACE_NIGHTELVES,clienttag);
1615          random_wins = account_get_racewins(pointer->account,W3_RACE_RANDOM,clienttag);
1616          random_losses = account_get_racelosses(pointer->account,W3_RACE_RANDOM,clienttag);
1617      // write username, xp and rank to file and everyhing else needed for nice ladder pages
1618 	 fprintf(fp,"\t<player>\n\t\t<name>%s</name>\n\t\t<level>%u</level>\n\t\t<xp>%u</xp>\n",
1619                     account_get_name(pointer->account),level,pointer->xp);
1620 	 fprintf(fp,"\t\t<wins>%u</wins>\n\t\t<losses>%u</losses>\n\t\t<rank>%u</rank>\n",
1621                     wins,losses,rank);
1622 	 fprintf(fp,"\t\t<races>\n\t\t\t<orc>\n\t\t\t\t<wins>%u</wins>\n\t\t\t\t<losses>%u</losses>\n\t\t\t</orc>\n",
1623                     orc_wins,orc_losses);
1624 	 fprintf(fp,"\t\t\t<human>\n\t\t\t\t<wins>%u</wins>\n\t\t\t\t<losses>%u</losses>\n\t\t\t</human>\n",
1625                     human_wins,human_losses);
1626 	 fprintf(fp,"\t\t\t<nightelf>\n\t\t\t\t<wins>%u</wins>\n\t\t\t\t<losses>%u</losses>\n\t\t\t</nightelf>\n",
1627 		    nightelf_wins,nightelf_losses);
1628 	 fprintf(fp,"\t\t\t<undead>\n\t\t\t\t<wins>%u</wins>\n\t\t\t\t<losses>%u</losses>\n\t\t\t</undead>\n",
1629 		    undead_wins,undead_losses);
1630 	 fprintf(fp,"\t\t\t<random>\n\t\t\t\t<wins>%u</wins>\n\t\t\t\t<losses>%u</losses>\n\t\t\t</random>\n\t\t</races>\n\t</player>\n",
1631                     random_wins,random_losses);
1632      }
1633 
1634      } // end: if clienttag WAR3 or WAR3XP
1635     else if (clienttag==CLIENTTAG_STARCRAFT_UINT || clienttag==CLIENTTAG_BROODWARS_UINT || clienttag==CLIENTTAG_WARCIIBNE_UINT)
1636     {
1637 	wins = account_get_ladder_wins(pointer->account,ladder->clienttag,ladder->ladder_id);
1638 	losses = account_get_ladder_losses(pointer->account,ladder->clienttag,ladder->ladder_id);
1639 	discs = account_get_ladder_disconnects(pointer->account,ladder->clienttag,ladder->ladder_id);
1640 
1641 	fprintf(fp,"\t<player>\n\t\t<rank>%u</rank>\n\t\t<name>%s</name>\n\t\t<rating>%u</rating>\n",
1642 	    rank, account_get_name(pointer->account),pointer->level);
1643 	fprintf(fp,"\t\t<wins>%u</wins>\n\t\t<losses>%u</losses>\n\t\t<discs>%u</discs>\n\t</player>\n",
1644                     wins,losses,discs);
1645     }
1646 
1647      pointer=pointer->prev;
1648   }
1649   fprintf(fp,"</ladder>\n");
1650   return 0;
1651 }
1652 
1653 
ladder_write_to_file(char const * filename,t_ladder * ladder,t_clienttag clienttag)1654 extern int ladder_write_to_file(char const * filename, t_ladder * ladder, t_clienttag clienttag)
1655 {
1656   FILE * fp;
1657 
1658   if (!filename)
1659   {
1660     eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename");
1661     return -1;
1662   }
1663 
1664   if (!(fp = fopen(filename,"w")))
1665   {
1666      eventlog(eventlog_level_error,__FUNCTION__,"could not open file \"%s\" for writing (fopen: %s)",filename,pstrerror(errno));
1667      return -1;
1668   }
1669 
1670   if (prefs_get_XML_output_ladder())
1671     XML_writer(fp,ladder,clienttag);
1672   else
1673     standard_writer(fp,ladder,clienttag);
1674 
1675   fclose(fp);
1676   return 0;
1677 }
1678 
ladders_write_to_file()1679 extern int ladders_write_to_file()
1680 {
1681 
1682   ladder_write_to_file(WAR3_solo_filename, &WAR3_solo_ladder,CLIENTTAG_WARCRAFT3_UINT);
1683   ladder_write_to_file(WAR3_team_filename, &WAR3_team_ladder,CLIENTTAG_WARCRAFT3_UINT);
1684   ladder_write_to_file(WAR3_ffa_filename,  &WAR3_ffa_ladder, CLIENTTAG_WARCRAFT3_UINT);
1685   ladder_write_to_file(WAR3_at_filename,   &WAR3_at_ladder,  CLIENTTAG_WARCRAFT3_UINT);
1686   ladder_write_to_file(W3XP_solo_filename, &W3XP_solo_ladder,   CLIENTTAG_WAR3XP_UINT);
1687   ladder_write_to_file(W3XP_team_filename, &W3XP_team_ladder,   CLIENTTAG_WAR3XP_UINT);
1688   ladder_write_to_file(W3XP_ffa_filename,  &W3XP_ffa_ladder,    CLIENTTAG_WAR3XP_UINT);
1689   ladder_write_to_file(W3XP_at_filename,   &W3XP_at_ladder,     CLIENTTAG_WAR3XP_UINT);
1690   ladder_write_to_file(STAR_ar_filename,   &STAR_active_rating, CLIENTTAG_STARCRAFT_UINT);
1691   ladder_write_to_file(STAR_cr_filename,   &STAR_current_rating,CLIENTTAG_STARCRAFT_UINT);
1692   ladder_write_to_file(SEXP_ar_filename,   &SEXP_active_rating, CLIENTTAG_BROODWARS_UINT);
1693   ladder_write_to_file(SEXP_cr_filename,   &SEXP_current_rating,CLIENTTAG_BROODWARS_UINT);
1694   ladder_write_to_file(W2BN_ar_filename,   &W2BN_active_rating, CLIENTTAG_WARCIIBNE_UINT);
1695   ladder_write_to_file(W2BN_cr_filename,   &W2BN_current_rating,CLIENTTAG_WARCIIBNE_UINT);
1696   ladder_write_to_file(W2BN_ari_filename,  &W2BN_active_rating_ironman, CLIENTTAG_WARCIIBNE_UINT);
1697   ladder_write_to_file(W2BN_cri_filename,  &W2BN_current_rating_ironman,CLIENTTAG_WARCIIBNE_UINT);
1698 
1699   return 0;
1700 }
1701 
create_filename(const char * path,const char * filename,const char * ending)1702 extern char * create_filename(const char * path, const char * filename, const char * ending)
1703 {
1704   char * result;
1705 
1706   result = xmalloc(strlen(path)+1+strlen(filename)+strlen(ending)+1);
1707   sprintf(result,"%s/%s%s",path,filename,ending);
1708 
1709   return result;
1710 }
1711 
dispose_filename(char * filename)1712 static void dispose_filename(char * filename)
1713 {
1714   if (filename) xfree(filename);
1715 }
1716 
create_filenames(void)1717 void create_filenames(void)
1718 {
1719     // In the ladderdir are binary ladder files, the human readable ladderlist output
1720     // is better in other place, in the outputdir [KWS]
1721 
1722   if (prefs_get_XML_output_ladder())
1723   {
1724     WAR3_solo_filename = create_filename(prefs_get_outputdir(),WAR3_solo_file,xml_end);
1725     WAR3_team_filename = create_filename(prefs_get_outputdir(),WAR3_team_file,xml_end);
1726     WAR3_ffa_filename  = create_filename(prefs_get_outputdir(),WAR3_ffa_file,xml_end);
1727     WAR3_at_filename   = create_filename(prefs_get_outputdir(),WAR3_at_file,xml_end);
1728     W3XP_solo_filename = create_filename(prefs_get_outputdir(),W3XP_solo_file,xml_end);
1729     W3XP_team_filename = create_filename(prefs_get_outputdir(),W3XP_team_file,xml_end);
1730     W3XP_ffa_filename  = create_filename(prefs_get_outputdir(),W3XP_ffa_file,xml_end);
1731     W3XP_at_filename   = create_filename(prefs_get_outputdir(),W3XP_at_file,xml_end);
1732     STAR_ar_filename   = create_filename(prefs_get_outputdir(),STAR_ar_file,xml_end);
1733     STAR_cr_filename   = create_filename(prefs_get_outputdir(),STAR_cr_file,xml_end);
1734     SEXP_ar_filename   = create_filename(prefs_get_outputdir(),SEXP_ar_file,xml_end);
1735     SEXP_cr_filename   = create_filename(prefs_get_outputdir(),SEXP_cr_file,xml_end);
1736     W2BN_ar_filename   = create_filename(prefs_get_outputdir(),W2BN_ar_file,xml_end);
1737     W2BN_cr_filename   = create_filename(prefs_get_outputdir(),W2BN_cr_file,xml_end);
1738     W2BN_ari_filename  = create_filename(prefs_get_outputdir(),W2BN_ari_file,xml_end);
1739     W2BN_cri_filename  = create_filename(prefs_get_outputdir(),W2BN_cri_file,xml_end);
1740   }
1741   else
1742   {
1743     WAR3_solo_filename = create_filename(prefs_get_outputdir(),WAR3_solo_file,std_end);
1744     WAR3_team_filename = create_filename(prefs_get_outputdir(),WAR3_team_file,std_end);
1745     WAR3_ffa_filename  = create_filename(prefs_get_outputdir(),WAR3_ffa_file,std_end);
1746     WAR3_at_filename   = create_filename(prefs_get_outputdir(),WAR3_at_file,std_end);
1747     W3XP_solo_filename = create_filename(prefs_get_outputdir(),W3XP_solo_file,std_end);
1748     W3XP_team_filename = create_filename(prefs_get_outputdir(),W3XP_team_file,std_end);
1749     W3XP_ffa_filename  = create_filename(prefs_get_outputdir(),W3XP_ffa_file,std_end);
1750     W3XP_at_filename   = create_filename(prefs_get_outputdir(),W3XP_at_file,std_end);
1751     STAR_ar_filename   = create_filename(prefs_get_outputdir(),STAR_ar_file,std_end);
1752     STAR_cr_filename   = create_filename(prefs_get_outputdir(),STAR_cr_file,std_end);
1753     SEXP_ar_filename   = create_filename(prefs_get_outputdir(),SEXP_ar_file,std_end);
1754     SEXP_cr_filename   = create_filename(prefs_get_outputdir(),SEXP_cr_file,std_end);
1755     W2BN_ar_filename   = create_filename(prefs_get_outputdir(),W2BN_ar_file,std_end);
1756     W2BN_cr_filename   = create_filename(prefs_get_outputdir(),W2BN_cr_file,std_end);
1757     W2BN_ari_filename  = create_filename(prefs_get_outputdir(),W2BN_ari_file,std_end);
1758     W2BN_cri_filename  = create_filename(prefs_get_outputdir(),W2BN_cri_file,std_end);
1759   }
1760 }
1761 
ladders_init(void)1762 extern void ladders_init(void)
1763 {
1764   eventlog(eventlog_level_info,__FUNCTION__,"initializing war3 ladders");
1765   ladder_init(&WAR3_solo_ladder,    WAR3_SOLO, CLIENTTAG_WARCRAFT3_UINT,ladder_id_solo);
1766   ladder_init(&WAR3_team_ladder,    WAR3_TEAM, CLIENTTAG_WARCRAFT3_UINT,ladder_id_team);
1767   ladder_init(&WAR3_ffa_ladder,     WAR3_FFA,  CLIENTTAG_WARCRAFT3_UINT,ladder_id_ffa);
1768   ladder_init(&WAR3_at_ladder,      WAR3_AT,   CLIENTTAG_WARCRAFT3_UINT,ladder_id_none);
1769   ladder_init(&W3XP_solo_ladder,    W3XP_SOLO, CLIENTTAG_WAR3XP_UINT,ladder_id_solo);
1770   ladder_init(&W3XP_team_ladder,    W3XP_TEAM, CLIENTTAG_WAR3XP_UINT,ladder_id_team);
1771   ladder_init(&W3XP_ffa_ladder,     W3XP_FFA,  CLIENTTAG_WAR3XP_UINT,ladder_id_ffa);
1772   ladder_init(&W3XP_at_ladder,      W3XP_AT,   CLIENTTAG_WAR3XP_UINT,ladder_id_none);
1773   ladder_init(&STAR_active_rating,  STAR_AR,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1774   ladder_init(&STAR_active_wins,    STAR_AW,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1775   ladder_init(&STAR_active_games,   STAR_AG,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1776   ladder_init(&STAR_current_rating, STAR_CR,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1777   ladder_init(&STAR_current_wins,   STAR_CW,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1778   ladder_init(&STAR_current_games,  STAR_CG,   CLIENTTAG_STARCRAFT_UINT,ladder_id_normal);
1779   ladder_init(&SEXP_active_rating,  SEXP_AR,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1780   ladder_init(&SEXP_active_wins,    SEXP_AW,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1781   ladder_init(&SEXP_active_games,   SEXP_AG,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1782   ladder_init(&SEXP_current_rating, SEXP_CR,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1783   ladder_init(&SEXP_current_wins,   SEXP_CW,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1784   ladder_init(&SEXP_current_games,  SEXP_CG,   CLIENTTAG_BROODWARS_UINT,ladder_id_normal);
1785   ladder_init(&W2BN_current_rating,         W2BN_CR,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1786   ladder_init(&W2BN_current_wins,           W2BN_CW,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1787   ladder_init(&W2BN_current_games,          W2BN_CG,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1788   ladder_init(&W2BN_current_rating_ironman, W2BN_CRI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1789   ladder_init(&W2BN_current_wins_ironman,   W2BN_CWI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1790   ladder_init(&W2BN_current_games_ironman,  W2BN_CGI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1791   ladder_init(&W2BN_active_rating,          W2BN_AR,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1792   ladder_init(&W2BN_active_wins,            W2BN_AW,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1793   ladder_init(&W2BN_active_games,           W2BN_AG,   CLIENTTAG_WARCIIBNE_UINT,ladder_id_normal);
1794   ladder_init(&W2BN_active_rating_ironman,  W2BN_ARI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1795   ladder_init(&W2BN_active_wins_ironman,    W2BN_AWI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1796   ladder_init(&W2BN_active_games_ironman,   W2BN_AGI,  CLIENTTAG_WARCIIBNE_UINT,ladder_id_ironman);
1797 
1798   create_filenames();
1799 }
1800 
dispose_filenames(void)1801 void dispose_filenames(void)
1802 {
1803   dispose_filename(WAR3_solo_filename);
1804   dispose_filename(WAR3_team_filename);
1805   dispose_filename(WAR3_ffa_filename);
1806   dispose_filename(WAR3_at_filename);
1807   dispose_filename(W3XP_solo_filename);
1808   dispose_filename(W3XP_team_filename);
1809   dispose_filename(W3XP_ffa_filename);
1810   dispose_filename(W3XP_at_filename);
1811   dispose_filename(STAR_ar_filename);
1812   dispose_filename(STAR_cr_filename);
1813   dispose_filename(SEXP_ar_filename);
1814   dispose_filename(SEXP_cr_filename);
1815   dispose_filename(W2BN_ar_filename);
1816   dispose_filename(W2BN_cr_filename);
1817   dispose_filename(W2BN_ari_filename);
1818   dispose_filename(W2BN_cri_filename);
1819 }
1820 
ladders_destroy(void)1821 extern void ladders_destroy(void)
1822 {
1823   eventlog(eventlog_level_info,__FUNCTION__,"destroying war3 ladders");
1824   ladder_destroy(&WAR3_solo_ladder);
1825   ladder_destroy(&WAR3_team_ladder);
1826   ladder_destroy(&WAR3_ffa_ladder);
1827   ladder_destroy(&WAR3_at_ladder);
1828   ladder_destroy(&W3XP_solo_ladder);
1829   ladder_destroy(&W3XP_team_ladder);
1830   ladder_destroy(&W3XP_ffa_ladder);
1831   ladder_destroy(&W3XP_at_ladder);
1832   ladder_destroy(&STAR_active_rating);
1833   ladder_destroy(&STAR_active_wins);
1834   ladder_destroy(&STAR_active_games);
1835   ladder_destroy(&STAR_current_rating);
1836   ladder_destroy(&STAR_current_wins);
1837   ladder_destroy(&STAR_current_games);
1838   ladder_destroy(&SEXP_active_rating);
1839   ladder_destroy(&SEXP_active_wins);
1840   ladder_destroy(&SEXP_active_games);
1841   ladder_destroy(&SEXP_current_rating);
1842   ladder_destroy(&SEXP_current_wins);
1843   ladder_destroy(&SEXP_current_games);
1844   ladder_destroy(&W2BN_current_rating);
1845   ladder_destroy(&W2BN_current_wins);
1846   ladder_destroy(&W2BN_current_games);
1847   ladder_destroy(&W2BN_current_rating_ironman);
1848   ladder_destroy(&W2BN_current_wins_ironman);
1849   ladder_destroy(&W2BN_current_games_ironman);
1850   ladder_destroy(&W2BN_active_rating);
1851   ladder_destroy(&W2BN_active_wins);
1852   ladder_destroy(&W2BN_active_games);
1853   ladder_destroy(&W2BN_active_rating_ironman);
1854   ladder_destroy(&W2BN_active_wins_ironman);
1855   ladder_destroy(&W2BN_active_games_ironman);
1856   dispose_filenames();
1857 }
1858 
ladder_reload_conf(void)1859 extern void ladder_reload_conf(void)
1860 {
1861   dispose_filenames();
1862   create_filenames();
1863 }
1864 
ladder_get_from_ladder(t_binary_ladder_types type,int rank,int * results)1865 int ladder_get_from_ladder(t_binary_ladder_types type, int rank,int * results)
1866 {
1867   t_ladder * ladder;
1868   t_ladder_internal * internal;
1869 
1870   if (!(results))
1871   {
1872     eventlog(eventlog_level_error,__FUNCTION__,"got NULL results");
1873     return -1;
1874   }
1875 
1876   if (!(ladder = binary_ladder_types_to_w3_ladder(type)))
1877     return -1;
1878 
1879   if (!(internal = ladder_get_rank_internal(ladder,rank,ladder_get_clienttag(ladder))))
1880   {
1881     return -1;
1882   }
1883 
1884   results[0] = internal->uid;
1885   results[1] = internal->xp;
1886   results[2] = internal->level;
1887   results[3] = internal->teamcount;
1888 
1889   return 0;
1890 }
1891 
ladder_put_into_ladder(t_binary_ladder_types type,int * values)1892 int ladder_put_into_ladder(t_binary_ladder_types type, int * values)
1893 {
1894   t_ladder * ladder;
1895   t_account * acct;
1896 
1897   if (!(values))
1898   {
1899     eventlog(eventlog_level_error,__FUNCTION__,"got NULL values");
1900     return -1;
1901   }
1902 
1903   if (!(ladder = binary_ladder_types_to_w3_ladder(type)))
1904     return -1;
1905 
1906   if ((acct = accountlist_find_account_by_uid(values[0])))
1907     war3_ladder_add(ladder,values[0],values[1],values[2],acct,values[3],ladder_get_clienttag(ladder));
1908   else
1909     eventlog(eventlog_level_error,__FUNCTION__,"no account with this UID - skip");
1910 
1911   return 0;
1912 }
1913 
ladder_make_active(t_ladder * current,t_ladder * active,int set_attributes)1914 extern int ladder_make_active(t_ladder *current, t_ladder *active,int set_attributes)
1915 {
1916   t_ladder_id id;
1917   t_clienttag clienttag;
1918   t_binary_ladder_types type;
1919   t_ladder_internal * internal;
1920   t_account * account;
1921   char const * timestr;
1922   t_bnettime bt;
1923   int rank = 1;
1924 
1925   id = active->ladder_id;
1926   clienttag = active->clienttag;
1927   type = active->type;
1928 
1929   //FIXME: take care of ppl that might have drop'ed from ladder !!!
1930   ladder_destroy(active);
1931   ladder_init(active,type,clienttag,id);
1932 
1933   while ((internal = ladder_get_rank_internal(current,rank,clienttag)))
1934   {
1935     account = internal->account;
1936     war3_ladder_add(active,internal->uid,internal->xp,internal->level,account,0,clienttag);
1937     if (set_attributes)
1938     {
1939       account_set_ladder_active_wins(account,clienttag,id,account_get_ladder_wins(account,clienttag,id));
1940       account_set_ladder_active_losses(account,clienttag,id,account_get_ladder_losses(account,clienttag,id));
1941       account_set_ladder_active_draws(account,clienttag,id,account_get_ladder_draws(account,clienttag,id));
1942       account_set_ladder_active_disconnects(account,clienttag,id,account_get_ladder_disconnects(account,clienttag,id));
1943       account_set_ladder_active_rating(account,clienttag,id,account_get_ladder_rating(account,clienttag,id));
1944       account_set_ladder_active_rank(account,clienttag,id,account_get_ladder_rank(account,clienttag,id));
1945       if (!(timestr = account_get_ladder_last_time(account,clienttag,id)))
1946         timestr = BNETD_LADDER_DEFAULT_TIME;
1947       bnettime_set_str(&bt,timestr);
1948       account_set_ladder_active_last_time(account,clienttag,id,bt);
1949     }
1950     rank++;
1951   }
1952 
1953   //now traverse the current ladder and put everything into the active one....
1954 
1955 
1956   return 0;
1957 }
1958 
ladder_createxptable(const char * xplevelfile,const char * xpcalcfile)1959 extern int ladder_createxptable(const char *xplevelfile, const char *xpcalcfile)
1960 {
1961    FILE *fd1, *fd2;
1962    char buffer[256];
1963    char *p;
1964    t_xpcalc_entry * newxpcalc;
1965    int len,i ,j;
1966    int level, startxp, neededxp, mingames;
1967    float lossfactor;
1968    int minlevel, leveldiff, higher_xpgained, higher_xplost, lower_xpgained, lower_xplost  = 10;
1969 
1970    if (xplevelfile == NULL || xpcalcfile == NULL) {
1971       eventlog(eventlog_level_error, "ladder_createxptable", "got NULL filename(s)");
1972       return -1;
1973    }
1974 
1975    /* first lets open files */
1976    if ((fd1 = fopen(xplevelfile, "rt")) == NULL) {
1977       eventlog(eventlog_level_error, "ladder_createxptable", "could not open XP level file : \"%s\"", xplevelfile);
1978       return -1;
1979    }
1980 
1981    if ((fd2 = fopen(xpcalcfile, "rt")) == NULL) {
1982       eventlog(eventlog_level_error, "ladder_createxptable", "could not open XP calc file : \"%s\"", xpcalcfile);
1983       fclose(fd1);
1984       return -1;
1985    }
1986 
1987    /* then lets allocate mem for all the arrays */
1988    xpcalc = xmalloc(sizeof(t_xpcalc_entry) * W3_XPCALC_MAXLEVEL); //presume the maximal leveldiff is level number
1989 
1990    w3_xpcalc_maxleveldiff = -1;
1991    memset(xpcalc, 0, sizeof(t_xpcalc_entry) * W3_XPCALC_MAXLEVEL);
1992    xplevels = xmalloc(sizeof(t_xplevel_entry) * W3_XPCALC_MAXLEVEL);
1993    memset(xplevels, 0, sizeof(t_xplevel_entry) * W3_XPCALC_MAXLEVEL);
1994 
1995    /* finally, lets read from the files */
1996 
1997    while(fgets(buffer, 256, fd1)) {
1998       len = strlen(buffer);
1999       if (len < 2) continue;
2000       if (buffer[len - 1] == '\n') buffer[len - 1] = '\0';
2001 
2002       /* support comments */
2003       for(p=buffer; *p && *p != '#'; p++);
2004       if (*p == '#') *p = '\0';
2005 
2006       if (sscanf(buffer, "%d %d %d %f %d", &level, &startxp, &neededxp, &lossfactor, &mingames) != 5)
2007 	continue;
2008 
2009       if (level < 1 || level > W3_XPCALC_MAXLEVEL) { /* invalid level */
2010 	 eventlog(eventlog_level_error, "ladder_createxptable", "read INVALID player level : %d", level);
2011 	 continue;
2012       }
2013 
2014       level--; /* the index in a C array starts from 0 */
2015       xplevels[level].startxp = startxp;
2016       xplevels[level].neededxp = neededxp;
2017       xplevels[level].lossfactor = lossfactor * 100; /* we store the loss factor as % */
2018       xplevels[level].mingames = mingames;
2019       eventlog(eventlog_level_trace, "ladder_createxptable", "inserting level XP info (level: %d, startxp: %d neededxp: %d lossfactor: %d mingames: %d)", level+1, xplevels[level].startxp, xplevels[level].neededxp, xplevels[level].lossfactor, xplevels[level].mingames);
2020    }
2021    fclose(fd1);
2022 
2023    while(fgets(buffer, 256, fd2)) {
2024       len = strlen(buffer);
2025       if (len < 2) continue;
2026       if (buffer[len - 1] == '\n') buffer[len - 1] = '\0';
2027 
2028       /* support comments */
2029       for(p=buffer; *p && *p != '#'; p++);
2030       if (*p == '#') *p = '\0';
2031 
2032       if (sscanf(buffer, " %d %d %d %d %d %d ", &minlevel, &leveldiff, &higher_xpgained, &higher_xplost, &lower_xpgained, &lower_xplost) != 6)
2033 	continue;
2034 
2035       eventlog(eventlog_level_trace, "ladder_createxptable", "parsed xpcalc leveldiff : %d", leveldiff);
2036 
2037       if (leveldiff <0) {
2038 	 eventlog(eventlog_level_error, "ladder_createxptable", "got invalid level diff : %d", leveldiff);
2039 	 continue;
2040       }
2041 
2042       if (leveldiff> (w3_xpcalc_maxleveldiff+1)) {
2043          eventlog(eventlog_level_error, __FUNCTION__,"expected entry for leveldiff=%u but found %u",w3_xpcalc_maxleveldiff+1,leveldiff);
2044 	 continue;
2045       }
2046 
2047       w3_xpcalc_maxleveldiff = leveldiff;
2048 
2049       xpcalc[leveldiff].higher_winxp = higher_xpgained;
2050       xpcalc[leveldiff].higher_lossxp = higher_xplost;
2051       xpcalc[leveldiff].lower_winxp = lower_xpgained;
2052       xpcalc[leveldiff].lower_lossxp = lower_xplost;
2053    }
2054    fclose(fd2);
2055 
2056    newxpcalc = xrealloc(xpcalc, sizeof(t_xpcalc_entry) * (w3_xpcalc_maxleveldiff+1));
2057    xpcalc=newxpcalc;
2058 
2059    /* OK, now we need to test couse if the user forgot to put some values
2060     * lots of profiles could get screwed up
2061     */
2062 
2063     if (w3_xpcalc_maxleveldiff<0)
2064     {
2065       eventlog(eventlog_level_error,__FUNCTION__,"found no valid entries for WAR3 xp calculation");
2066       ladder_destroyxptable();
2067       return -1;
2068     }
2069 
2070     eventlog(eventlog_level_info,__FUNCTION__,"set war3 xpcalc maxleveldiff to %u",w3_xpcalc_maxleveldiff);
2071 
2072      for(j=0;j<=w3_xpcalc_maxleveldiff;j++)
2073        if (xpcalc[j].higher_winxp == 0 || xpcalc[j].higher_lossxp == 0 ||
2074            xpcalc[j].lower_winxp  == 0 || xpcalc[j].lower_lossxp  == 0) {
2075 	  eventlog(eventlog_level_error, "ladder_createxptable", "i found 0 for a win/loss XP, please check your config file");
2076 	  ladder_destroyxptable();
2077 	  return -1;
2078        }
2079 
2080    for (i=0; i<W3_XPCALC_MAXLEVEL; i++)
2081      if ((i > 0 && xplevels[i].neededxp == 0) || xplevels[i].lossfactor == 0
2082 	 || xplevels[i].neededxp > xplevels[i].startxp
2083 	 || (i > 0 && (xplevels[i].startxp <= xplevels[i-1].startxp || xplevels[i].neededxp < xplevels[i-1].neededxp))) {
2084 	eventlog(eventlog_level_error, "ladder_createxptable", "i found 0 for a level XP, please check your config file (level: %d neededxp: %d lossfactor: %d)", i+1, xplevels[i].neededxp , xplevels[i].lossfactor);
2085 	ladder_destroyxptable();
2086 	return -1;
2087      }
2088 
2089    return 0;
2090 }
2091 
ladder_destroyxptable()2092 extern void ladder_destroyxptable()
2093 {
2094    if (xpcalc != NULL) xfree(xpcalc);
2095    if (xplevels != NULL) xfree(xplevels);
2096 }
2097 
war3_get_maxleveldiff()2098 extern int war3_get_maxleveldiff()
2099 {
2100   return w3_xpcalc_maxleveldiff;
2101 }
2102 
2103 
ladder_war3_xpdiff(unsigned int winnerlevel,unsigned int looserlevel,int * winxpdiff,int * loosxpdiff)2104 extern int ladder_war3_xpdiff(unsigned int winnerlevel, unsigned int looserlevel, int *winxpdiff, int *loosxpdiff)
2105 {
2106    int diff, absdiff;
2107 
2108    diff = winnerlevel - looserlevel;
2109    absdiff = (diff < 0)?(-diff):diff;
2110 
2111    if (absdiff > w3_xpcalc_maxleveldiff) {
2112       eventlog(eventlog_level_error, "ladder_war3_xpdiff", "got invalid level difference : %d", absdiff);
2113       return -1;
2114    }
2115 
2116    if (winnerlevel > W3_XPCALC_MAXLEVEL || looserlevel > W3_XPCALC_MAXLEVEL || winnerlevel <1 || looserlevel<1) {
2117       eventlog(eventlog_level_error, "ladder_war3_xpdiff", "got invalid account levels (win: %d loss: %d)",winnerlevel, looserlevel);
2118       return -1;
2119    }
2120 
2121    if (winxpdiff == NULL || loosxpdiff == NULL) {
2122       eventlog(eventlog_level_error, "ladder_war3_xpdiff", "got NULL winxpdiff, loosxpdiff");
2123       return -1;
2124    }
2125    /* we return the xp difference for the winner and the looser
2126     * we compute that from the xp charts also applying the loss factor for
2127     * lower level profiles
2128     * FIXME: ?! loss factor doesnt keep the sum of xp won/lost constant
2129     * DON'T CARE, cause current win/loss values aren't symetrical any more
2130     */
2131    if (diff >= 0) {
2132       *winxpdiff = xpcalc[absdiff].higher_winxp;
2133       *loosxpdiff = - (xpcalc[absdiff].lower_lossxp * xplevels[looserlevel - 1].lossfactor) / 100;
2134    } else {
2135       *winxpdiff = xpcalc[absdiff].lower_winxp;
2136       *loosxpdiff = - (xpcalc[absdiff].higher_lossxp * xplevels[looserlevel - 1].lossfactor) / 100;
2137    }
2138 
2139    return 0;
2140 }
2141 
ladder_war3_updatelevel(unsigned int oldlevel,int xp)2142 extern int ladder_war3_updatelevel(unsigned int oldlevel, int xp)
2143 {
2144    int i, mylevel;
2145 
2146    if (oldlevel < 1 || oldlevel > W3_XPCALC_MAXLEVEL) {
2147       eventlog(eventlog_level_error, "ladder_war3_updatelevel", "got invalid level: %d", oldlevel);
2148       return oldlevel;
2149    }
2150 
2151    if (xp <= 0) return 1;
2152 
2153    mylevel = oldlevel;
2154 
2155    for(i=mylevel ; i < W3_XPCALC_MAXLEVEL; i++)
2156      if (xplevels[i].startxp > xp) { mylevel = i; break;}
2157 
2158    for(i=mylevel - 1; i >0 ; i--)
2159      if (xplevels[i-1].startxp < xp) { mylevel = i+1; break; }
2160 
2161    return mylevel;
2162 }
2163 
ladder_war3_get_min_xp(unsigned int Level)2164 extern int ladder_war3_get_min_xp(unsigned int Level)
2165 {
2166   if (Level < 1 || Level > W3_XPCALC_MAXLEVEL)
2167   {
2168 	eventlog(eventlog_level_error,__FUNCTION__,"got invalid Level %d",Level);
2169 	return -1;
2170   }
2171   return xplevels[Level-1].startxp;
2172 }
2173