1 /*
2  * (C) 2004		Olaf Freyer	(aaron@cs.tu-berlin.de)
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18 #define TEAM_INTERNAL_ACCESS
19 #include "common/setup_before.h"
20 #ifdef HAVE_STDDEF_H
21 # include <stddef.h>
22 #else
23 # ifndef NULL
24 #  define NULL ((void *)0)
25 # endif
26 #endif
27 #ifdef STDC_HEADERS
28 # include <stdlib.h>
29 #else
30 # ifdef HAVE_MALLOC_H
31 #  include <malloc.h>
32 # endif
33 #endif
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #else
37 # ifdef HAVE_STRINGS_H
38 #  include <strings.h>
39 # endif
40 #endif
41 #include "compat/strdup.h"
42 #include "compat/pdir.h"
43 #include <errno.h>
44 #include "compat/strerror.h"
45 #ifdef TIME_WITH_SYS_TIME
46 # include <sys/time.h>
47 # include <time.h>
48 #else
49 # ifdef HAVE_SYS_TIME_H
50 #  include <sys/time.h>
51 # else
52 #  include <time.h>
53 # endif
54 #endif
55 #ifdef HAVE_SYS_TYPES_H
56 # include <sys/types.h>
57 #endif
58 #include "common/eventlog.h"
59 #include "common/packet.h"
60 #include "common/tag.h"
61 #include "common/util.h"
62 #include "common/xalloc.h"
63 #include "common/list.h"
64 #include "storage.h"
65 #include "team.h"
66 #include "account.h"
67 #include "account_wrap.h"
68 #include "ladder.h"
69 #ifdef HAVE_ASSERT_H
70 # include <assert.h>
71 #endif
72 #include "server.h"
73 #include "common/setup_after.h"
74 
75 static t_list *teamlist_head = NULL;
76 int max_teamid = 0;
77 int teamlist_add_team(t_team * team);
78 
79 /* callback function for storage use */
80 
_cb_load_teams(void * team)81 static int _cb_load_teams(void *team)
82 {
83     if (teamlist_add_team(team) < 0)
84     {
85 	eventlog(eventlog_level_error, __FUNCTION__, "failed to add team to teamlist");
86 	return -1;
87     }
88 
89     if (((t_team *) team)->teamid > max_teamid)
90 	max_teamid = ((t_team *) team)->teamid;
91     return 0;
92 }
93 
94 
teamlist_add_team(t_team * team)95 int teamlist_add_team(t_team * team)
96 {
97     int i;
98 
99     if (!(team))
100     {
101 	eventlog(eventlog_level_error, __FUNCTION__, "got NULL team");
102 	return -1;
103     }
104 
105     for (i=0; i<team->size; i++)
106     {
107 	if (!(team->members[i] = accountlist_find_account_by_uid(team->teammembers[i])))
108 	{
109 	    eventlog(eventlog_level_error,__FUNCTION__,"at least one non-existant member (id %d) in team %u - discarding team",team->teammembers[i],team->teamid);
110 	    //FIXME: delete team file now???
111 	    return team->teamid; //we return teamid even though we have an error, we don't want unintentional overwriting
112 	}
113     }
114 
115     for (i=0; i<team->size; i++)
116       account_add_team(team->members[i],team);
117 
118     if (!(team->teamid))
119 	team->teamid = ++max_teamid;
120 
121     list_append_data(teamlist_head, team);
122 
123     return team->teamid;
124 }
125 
126 
teamlist_load(void)127 int teamlist_load(void)
128 {
129     // make sure to unload previous teamlist before loading again
130     if (teamlist_head)
131 	teamlist_unload();
132 
133     teamlist_head = list_create();
134 
135     storage->load_teams(_cb_load_teams);
136 
137     return 0;
138 }
139 
140 
teamlist_unload(void)141 int teamlist_unload(void)
142 {
143     t_elem *curr;
144     t_team *team;
145 
146     if ((teamlist_head))
147     {
148 	LIST_TRAVERSE(teamlist_head, curr)
149 	{
150 	    if (!(team = elem_get_data(curr)))
151 	    {
152 		eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
153 		continue;
154 	    }
155 	    xfree((void *) team);
156 	    list_remove_elem(teamlist_head, &curr);
157 	}
158 
159 	if (list_destroy(teamlist_head) < 0)
160 	    return -1;
161 
162 	teamlist_head = NULL;
163     }
164 
165     return 0;
166 }
167 
teams_destroy(t_list * teams)168 int teams_destroy(t_list * teams)
169 {
170     t_elem *curr;
171     t_team *team;
172 
173     if ((teams))
174     {
175 	LIST_TRAVERSE(teams,curr)
176 	{
177 	    if (!(team = elem_get_data(curr)))
178 	    {
179 		eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
180 		continue;
181 	    }
182 	    list_remove_elem(teams, &curr);
183 	}
184 
185 	if (list_destroy(teams) < 0)
186 	    return -1;
187     }
188     teams = NULL;
189 
190     return 0;
191 }
192 
create_team(t_account ** accounts,t_clienttag clienttag)193 t_team* create_team(t_account **accounts, t_clienttag clienttag)
194 {
195     t_team * team;
196     int i;
197     unsigned char size;
198 
199     team = xmalloc(sizeof(t_team));
200     memset(team,0,sizeof(t_team));
201     size = 0;
202 
203     for (i=0; i<MAX_TEAMSIZE;i++)
204     {
205 	team->members[i]	= accounts[i];
206 	if ((accounts[i]))
207 	{
208 	  team->teammembers[i]	= account_get_uid(accounts[i]);
209 	  size++;
210 	}
211     }
212     team->size = size;
213     team->clienttag = clienttag;
214 
215     _cb_load_teams(team);
216 
217     storage->write_team(team);
218 
219     return team;
220 }
221 
dispose_team(t_team * team)222 void dispose_team(t_team * team)
223 {
224     if ((team))
225       xfree((void *)team);
226     team = NULL;
227 }
228 
teamlist_find_team_by_accounts(t_account ** accounts,t_clienttag clienttag)229 t_team * teamlist_find_team_by_accounts(t_account **accounts,t_clienttag clienttag)
230 {
231   return _list_find_team_by_accounts(accounts, clienttag, teamlist_head);
232 }
233 
_list_find_team_by_accounts(t_account ** accounts,t_clienttag clienttag,t_list * teamlist)234 t_team * _list_find_team_by_accounts(t_account **accounts, t_clienttag clienttag, t_list * teamlist)
235 {
236     t_elem *curr;
237     t_team *cteam;
238     int i,j,found;
239     unsigned char size;
240 
241     assert(accounts);
242 
243     found = 0;
244 
245     if ((teamlist))
246     {
247 	LIST_TRAVERSE(teamlist,curr)
248 	{
249 	    if (!(cteam = elem_get_data(curr)))
250 	    {
251 		eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
252 		continue;
253 	    }
254     	    size = 0;
255 
256 	    for (i=0; i<MAX_TEAMSIZE;i++)
257 	    {
258 	      if (!(accounts[i]))
259 	        break;
260 
261 	      size++;
262 	      found = 0;
263 	      for (j=0; j<MAX_TEAMSIZE;j++)
264 	      {
265 		if ((accounts[i] == cteam->members[j]))
266 	        {
267 	          found = 1;
268 	          break;
269 	        }
270 	      }
271               if (!(found)) break;
272             }
273 	    if ((found) && (clienttag==cteam->clienttag) && (size==cteam->size))
274 	      return cteam;
275 	}
276 
277     }
278 
279     return NULL;
280 }
281 
teamlist_find_team_by_uids(unsigned int * uids,t_clienttag clienttag)282 t_team * teamlist_find_team_by_uids(unsigned int * uids, t_clienttag clienttag)
283 {
284     return _list_find_team_by_uids(uids, clienttag, teamlist_head);
285 }
286 
_list_find_team_by_uids(unsigned int * uids,t_clienttag clienttag,t_list * teamlist)287 t_team * _list_find_team_by_uids(unsigned int * uids, t_clienttag clienttag, t_list * teamlist)
288 {
289     t_elem *curr;
290     t_team *cteam;
291     int i,j,found;
292     unsigned char size;
293 
294     assert(uids);
295 
296     found = 0;
297 
298     if ((teamlist))
299     {
300 	LIST_TRAVERSE(teamlist,curr)
301 	{
302 	    if (!(cteam = elem_get_data(curr)))
303 	    {
304 		eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
305 		continue;
306 	    }
307 	    size = 0;
308 
309 	    for (i=0; i<MAX_TEAMSIZE;i++)
310 	    {
311 	      if (!(uids[i]))
312 	        break;
313 
314 	      found = 0;
315 	      for (j=0; j<MAX_TEAMSIZE;j++)
316 	      {
317 		if ((uids[i] == cteam->teammembers[j]))
318 	        {
319 	          found = 1;
320 	          break;
321 	        }
322 	      }
323               if (!(found)) break;
324             }
325 	    if ((found) && (clienttag==cteam->clienttag) && (size==cteam->size))
326 	      return cteam;
327 	}
328 
329     }
330 
331     return NULL;
332 }
333 
teamlist_find_team_by_teamid(unsigned int teamid)334 t_team * teamlist_find_team_by_teamid(unsigned int teamid)
335 {
336     return _list_find_team_by_teamid(teamid,teamlist_head);
337 }
338 
_list_find_team_by_teamid(unsigned int teamid,t_list * teamlist)339 t_team* _list_find_team_by_teamid(unsigned int teamid, t_list * teamlist)
340 {
341     t_elem * curr;
342     t_team * cteam;
343 
344     assert(teamid);
345 
346     if ((teamlist))
347     {
348 	LIST_TRAVERSE(teamlist,curr)
349 	{
350 	    if (!(cteam = elem_get_data(curr)))
351 	    {
352 		eventlog(eventlog_level_error, __FUNCTION__, "found NULL entry in list");
353 		continue;
354 	    }
355 
356 	    if ((cteam->teamid == teamid))
357 	      return cteam;
358 
359 	}
360     }
361     return NULL;
362 }
363 
team_get_teamid(t_team * team)364 unsigned int team_get_teamid(t_team * team)
365 {
366     assert(team);
367 
368     return team->teamid;
369 }
370 
team_get_member(t_team * team,int count)371 t_account * team_get_member(t_team * team,int count)
372 {
373     assert(team);
374     assert(count>=0);
375     assert(count<MAX_TEAMSIZE);
376 
377     return team->members[count];
378 }
379 
team_get_memberuid(t_team * team,int count)380 unsigned int team_get_memberuid(t_team * team,int count)
381 {
382     assert(team);
383     assert(count>=0);
384     assert(count<MAX_TEAMSIZE);
385 
386     return team->teammembers[count];
387 }
388 
389 
team_get_clienttag(t_team * team)390 t_clienttag team_get_clienttag(t_team * team)
391 {
392     assert(team);
393 
394     return team->clienttag;
395 }
team_get_size(t_team * team)396 unsigned char team_get_size(t_team * team)
397 {
398     assert(team);
399 
400     return team->size;
401 }
402 
team_get_wins(t_team * team)403 int team_get_wins(t_team * team)
404 {
405     assert(team);
406 
407     return team->wins;
408 }
409 
team_get_losses(t_team * team)410 int team_get_losses(t_team * team)
411 {
412     assert(team);
413 
414     return team->losses;
415 }
416 
team_get_xp(t_team * team)417 int team_get_xp(t_team * team)
418 {
419     assert(team);
420 
421     return team->xp;
422 }
423 
team_get_level(t_team * team)424 int team_get_level(t_team * team)
425 {
426     assert(team);
427 
428     return team->level;
429 }
430 
team_get_rank(t_team * team)431 int team_get_rank(t_team * team)
432 {
433     assert(team);
434 
435     return team->rank;
436 }
437 
team_get_lastgame(t_team * team)438 time_t team_get_lastgame(t_team * team)
439 {
440     assert(team);
441 
442     return team->lastgame;
443 }
444 
team_inc_wins(t_team * team)445 int team_inc_wins(t_team * team)
446 {
447   assert(team);
448 
449   team->wins++;
450   return 0;
451 }
452 
team_inc_losses(t_team * team)453 int team_inc_losses(t_team * team)
454 {
455   assert(team);
456 
457   team->losses++;
458   return 0;
459 }
460 
team_update_lastgame(t_team * team)461 int team_update_lastgame(t_team * team)
462 {
463   assert(team);
464 
465   team->lastgame = now;
466   return 0;
467 }
468 
team_update_xp(t_team * team,int gameresult,unsigned int opponlevel,int * xp_diff)469 extern int team_update_xp(t_team * team, int gameresult, unsigned int opponlevel, int * xp_diff)
470 {
471   int xp;
472   int mylevel;
473   int xpdiff = 0, placeholder;
474 
475   xp = team->xp; //get current xp
476   if (xp < 0) {
477     eventlog(eventlog_level_error, __FUNCTION__, "got negative XP");
478     return -1;
479   }
480 
481   mylevel = team->level; //get teams level
482   if (mylevel > W3_XPCALC_MAXLEVEL) {
483     eventlog(eventlog_level_error, __FUNCTION__, "got invalid level: %d", mylevel);
484     return -1;
485   }
486 
487   if(mylevel<=0) //if level is 0 then set it to 1
488     mylevel=1;
489 
490   if (opponlevel < 1) opponlevel = 1;
491 
492   switch (gameresult)
493     {
494     case W3_GAMERESULT_WIN:
495       ladder_war3_xpdiff(mylevel, opponlevel, &xpdiff, &placeholder); break;
496     case W3_GAMERESULT_LOSS:
497       ladder_war3_xpdiff(opponlevel, mylevel, &placeholder, &xpdiff); break;
498     default:
499       eventlog(eventlog_level_error, __FUNCTION__, "got invalid game result: %d", gameresult);
500       return -1;
501     }
502 
503   *xp_diff = xpdiff;
504   xp += xpdiff;
505   if (xp < 0) xp = 0;
506 
507   team->xp = xp;
508 
509   return 0;
510 }
511 
team_update_level(t_team * team)512 int team_update_level(t_team * team)
513 {
514   int xp, mylevel;
515 
516   xp = team->xp;
517   if (xp < 0) xp = 0;
518 
519   mylevel = team->level;
520   if (mylevel < 1) mylevel = 1;
521 
522   if (mylevel > W3_XPCALC_MAXLEVEL) {
523     eventlog(eventlog_level_error, "account_set_sololevel", "got invalid level: %d", mylevel);
524     return -1;
525   }
526 
527   mylevel = ladder_war3_updatelevel(mylevel, xp);
528 
529   team->level = mylevel;
530 
531   return 0;
532 }
533 
team_set_saveladderstats(t_team * team,unsigned int gametype,int result,unsigned int opponlevel,t_clienttag clienttag)534 int team_set_saveladderstats(t_team * team, unsigned int gametype, int result, unsigned int opponlevel,t_clienttag clienttag)
535 {
536   unsigned int intrace;
537   int xpdiff,level;
538   int i;
539   t_account * account;
540 
541   if(!team)
542     {
543       eventlog(eventlog_level_error,__FUNCTION__, "got NULL team");
544       return -1;
545     }
546 
547     //added for better tracking down of problems with gameresults
548     eventlog(eventlog_level_trace,__FUNCTION__,"parsing game result for team: %u result: %s",team_get_teamid(team),(result==W3_GAMERESULT_WIN)?"WIN":"LOSS");
549 
550 
551   if(result == W3_GAMERESULT_WIN)
552     {
553       team_inc_wins(team);
554     }
555   if(result == W3_GAMERESULT_LOSS)
556     {
557       team_inc_losses(team);
558     }
559   team_update_xp(team, result, opponlevel,&xpdiff);
560   team_update_level(team);
561   team_update_lastgame(team);
562   level = team_get_level(team);
563   /*
564   if (war3_ladder_update(at_ladder(clienttag),uid,xpdiff,level,account,0)!=0)
565     war3_ladder_add(at_ladder(clienttag),uid,account_get_atteamxp(account,current_teamnum,clienttag),level,account,0,clienttag);
566     */
567   storage->write_team(team);
568 
569 
570   // now set currentatteam to 0 so we only get one report for each team
571   for (i=0; i<MAX_TEAMSIZE; i++)
572   {
573     if ((account = team->members[i]))
574     {
575       intrace = account_get_w3pgrace(account,clienttag);
576       if(result == W3_GAMERESULT_WIN)
577       {
578         account_inc_racewins(account,intrace,clienttag);
579       }
580       if(result == W3_GAMERESULT_LOSS)
581       {
582         account_inc_racelosses(account,intrace,clienttag);
583       }
584       account_set_currentatteam(account,0);
585     }
586   }
587 
588   return 0;
589 }
590 
591