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