1 /*
2 * Copyright (C) 2000 Ross Combs (rocombs@cs.nmsu.edu)
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 CHARACTER_INTERNAL_ACCESS
19 #include "common/setup_before.h"
20 #include <stdio.h>
21 #ifdef HAVE_STDDEF_H
22 # include <stddef.h>
23 #else
24 # ifndef NULL
25 # define NULL ((void *)0)
26 # endif
27 #endif
28 #ifdef STDC_HEADERS
29 # include <stdlib.h>
30 #else
31 # ifdef HAVE_MALLOC_H
32 # include <malloc.h>
33 # endif
34 #endif
35 #ifdef HAVE_STRING_H
36 # include <string.h>
37 #else
38 # ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 # endif
41 # ifdef HAVE_MEMORY_H
42 # include <memory.h>
43 # endif
44 #endif
45 #include "compat/memcpy.h"
46 #include "compat/strcasecmp.h"
47 #include "compat/strdup.h"
48 #include <errno.h>
49 #include "compat/strerror.h"
50 #include "common/eventlog.h"
51 #include "common/list.h"
52 #include "compat/uint.h"
53 #include "common/bnet_protocol.h"
54 #include "account.h"
55 #include "account_wrap.h"
56 #include "common/bn_type.h"
57 #include "common/util.h"
58 #include "common/xalloc.h"
59 #include "character.h"
60 #include "common/setup_after.h"
61
62
63 static t_list * characterlist_head=NULL;
64
65
bncharacter_class_to_character_class(t_uint8 class)66 static t_character_class bncharacter_class_to_character_class(t_uint8 class)
67 {
68 switch (class)
69 {
70 case D2CHAR_INFO_CLASS_AMAZON:
71 return character_class_amazon;
72 case D2CHAR_INFO_CLASS_SORCERESS:
73 return character_class_sorceress;
74 case D2CHAR_INFO_CLASS_NECROMANCER:
75 return character_class_necromancer;
76 case D2CHAR_INFO_CLASS_PALADIN:
77 return character_class_paladin;
78 case D2CHAR_INFO_CLASS_BARBARIAN:
79 return character_class_barbarian;
80 case D2CHAR_INFO_CLASS_DRUID:
81 return character_class_druid;
82 case D2CHAR_INFO_CLASS_ASSASSIN:
83 return character_class_assassin;
84 default:
85 return character_class_none;
86 }
87 }
88
89
90 /* Function unused
91 static t_uint8 character_class_to_bncharacter_class(t_character_class class)
92 {
93 switch (class)
94 {
95 case character_class_amazon:
96 return D2CHAR_INFO_CLASS_AMAZON;
97 case character_class_sorceress:
98 return D2CHAR_INFO_CLASS_SORCERESS;
99 case character_class_necromancer:
100 return D2CHAR_INFO_CLASS_NECROMANCER;
101 case character_class_paladin:
102 return D2CHAR_INFO_CLASS_PALADIN;
103 case character_class_barbarian:
104 return D2CHAR_INFO_CLASS_BARBARIAN;
105 case character_class_druid:
106 return D2CHAR_INFO_CLASS_DRUID;
107 case character_class_assassin:
108 return D2CHAR_INFO_CLASS_ASSASSIN;
109 default:
110 eventlog(eventlog_level_error,__FUNCTION__,"got unknown class %d",(int)class);
111 case character_class_none:
112 return D2CHAR_INFO_FILLER;
113 }
114 }
115 */
116
character_class_to_classname(t_character_class class)117 static const char * character_class_to_classname (t_character_class class)
118 {
119 switch (class)
120 {
121 case character_class_amazon:
122 return "Amazon";
123 case character_class_sorceress:
124 return "Sorceress";
125 case character_class_necromancer:
126 return "Necromancer";
127 case character_class_paladin:
128 return "Paladin";
129 case character_class_barbarian:
130 return "Barbarian";
131 case character_class_druid:
132 return "Druid";
133 case character_class_assassin:
134 return "Assassin";
135 default:
136 return "Unknown";
137 }
138 }
139
140
character_expansion_to_expansionname(t_character_expansion expansion)141 static const char * character_expansion_to_expansionname (t_character_expansion expansion)
142 {
143 switch (expansion)
144 {
145 case character_expansion_classic:
146 return "Classic";
147 case character_expansion_lod:
148 return "LordOfDestruction";
149 default:
150 return "Unknown";
151 }
152 }
153
154
decode_character_data(t_character * ch)155 static void decode_character_data(t_character * ch)
156 {
157 ch->unknownb1 = D2CHAR_INFO_UNKNOWNB1;
158 ch->unknownb2 = D2CHAR_INFO_UNKNOWNB2;
159 ch->helmgfx = D2CHAR_INFO_FILLER;
160 ch->bodygfx = D2CHAR_INFO_FILLER;
161 ch->leggfx = D2CHAR_INFO_FILLER;
162 ch->lhandweapon = D2CHAR_INFO_FILLER;
163 ch->lhandgfx = D2CHAR_INFO_FILLER;
164 ch->rhandweapon = D2CHAR_INFO_FILLER;
165 ch->rhandgfx = D2CHAR_INFO_FILLER;
166 ch->unknownb3 = D2CHAR_INFO_FILLER;
167 ch->unknownb4 = D2CHAR_INFO_FILLER;
168 ch->unknownb5 = D2CHAR_INFO_FILLER;
169 ch->unknownb6 = D2CHAR_INFO_FILLER;
170 ch->unknownb7 = D2CHAR_INFO_FILLER;
171 ch->unknownb8 = D2CHAR_INFO_FILLER;
172 ch->unknownb9 = D2CHAR_INFO_FILLER;
173 ch->unknownb10 = D2CHAR_INFO_FILLER;
174 ch->unknownb11 = D2CHAR_INFO_FILLER;
175 ch->unknown1 = 0xffffffff;
176 ch->unknown2 = 0xffffffff;
177 ch->unknown3 = 0xffffffff;
178 ch->unknown4 = 0xffffffff;
179 ch->level = 0x01;
180 ch->status = 0x80;
181 ch->title = 0x80;
182 ch->unknownb13 = 0x80;
183 ch->emblembgc = 0x80;
184 ch->emblemfgc = 0xff;
185 ch->emblemnum = 0xff;
186 ch->unknownb14 = D2CHAR_INFO_FILLER;
187
188 /*
189 b1 b2 hg bg lg lw lg rw rg b3 b4 b5 b6 b7 b8 b9 bA bB cl u1 u1 u1 u1 u2 u2 u2 u2 u3 u3 u3 u3 u4 u4 u4 u4 lv st ti bC eb ef en bD \0
190 amazon_qwer.log:
191 83 80 ff ff ff ff ff 43 ff 1b ff ff ff ff ff ff ff ff 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 01 80 80 80 80 ff ff ff 00
192 sor_Bent.log:
193 83 80 ff ff ff ff ff 53 ff ff ff ff ff ff ff ff ff ff 02 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 01 80 80 80 80 ff ff ff 00
194 necro_Thorsen.log:
195 83 80 ff ff ff ff ff 2b ff ff ff ff ff ff ff ff ff ff 03 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 01 80 80 80 80 ff ff ff 00
196 pal_QlexTEST.log:
197 87 80 01 01 01 01 01 ff ff ff 01 01 ff ff ff ff ff ff 04 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 01 80 80 ff ff ff 80 80 00
198 barb_Qlex.log:
199 83 80 ff ff ff ff ff 2f ff 1b ff ff ff ff ff ff ff ff 05 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 01 80 80 80 80 ff ff ff 00
200 */
201 }
202
203
load_initial_data(t_character * character,t_character_class class,t_character_expansion expansion)204 static int load_initial_data (t_character * character, t_character_class class, t_character_expansion expansion)
205 {
206 char const * data_in_hex;
207
208 eventlog(eventlog_level_debug,__FUNCTION__,"Initial Data for %s, %s %s",
209 character->name,
210 character_expansion_to_expansionname(expansion),
211 character_class_to_classname(class));
212
213 /* Ideally, this would be loaded from bnetd_default_user, but I don't want to hack account.c just now */
214
215 /* The "default" character info if everything else messes up; */
216 data_in_hex = NULL; /* FIXME: what should we do if expansion or class isn't known... */
217
218 switch (expansion)
219 {
220 case character_expansion_classic:
221 switch (class)
222 {
223 case character_class_amazon:
224 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 01 FF FF FF FF FF FF FF FF FF FF FF 01 81 80 80 80 FF FF FF";
225 break;
226 case character_class_sorceress:
227 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 02 FF FF FF FF FF FF FF FF FF FF FF 01 81 80 80 80 FF FF FF";
228 break;
229 case character_class_necromancer:
230 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 03 FF FF FF FF FF FF FF FF FF FF FF 01 81 80 80 80 FF FF FF";
231 break;
232 case character_class_paladin:
233 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 04 FF FF FF FF FF FF FF FF FF FF FF 01 81 80 80 80 FF FF FF";
234 break;
235 case character_class_barbarian:
236 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 05 FF FF FF FF FF FF FF FF FF FF FF 01 81 80 80 80 FF FF FF";
237 break;
238 default: break; //should never reach that part ot the code... but to make compiler happy...
239 }
240 break;
241 case character_expansion_lod:
242 switch (class)
243 {
244 case character_class_amazon:
245 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 01 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
246 break;
247 case character_class_sorceress:
248 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 02 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
249 break;
250 case character_class_necromancer:
251 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 03 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
252 break;
253 case character_class_paladin:
254 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 04 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
255 break;
256 case character_class_barbarian:
257 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 05 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
258 break;
259 case character_class_druid:
260 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 06 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
261 break;
262 case character_class_assassin:
263 data_in_hex = "84 80 FF FF FF FF FF FF FF FF FF FF FF 07 FF FF FF FF FF FF FF FF FF FF FF 01 A1 80 80 80 FF FF FF";
264 break;
265 default: break; // again we will never get here... but how can compiler know that?!?
266 }
267 default: break; // well... like I said 2 times before....
268 }
269
270 character->datalen = hex_to_str(data_in_hex, character->data, 33);
271
272 decode_character_data(character);
273
274 return 0;
275 }
276
277
character_create(t_account * account,t_clienttag clienttag,char const * realmname,char const * name,t_character_class class,t_character_expansion expansion)278 extern int character_create(t_account * account, t_clienttag clienttag, char const * realmname, char const * name, t_character_class class, t_character_expansion expansion)
279 {
280 t_character * ch;
281
282 if (!account)
283 {
284 eventlog(eventlog_level_error,__FUNCTION__,"got NULL account");
285 return -1;
286 }
287 if (!clienttag)
288 {
289 eventlog(eventlog_level_error,__FUNCTION__,"got bad clienttag");
290 return -1;
291 }
292 if (!realmname)
293 {
294 eventlog(eventlog_level_error,__FUNCTION__,"got NULL realmname");
295 return -1;
296 }
297 if (!name)
298 {
299 eventlog(eventlog_level_error,__FUNCTION__,"got NULL name");
300 return -1;
301 }
302
303 ch = xmalloc(sizeof(t_character));
304 ch->name = xstrdup(name);
305 ch->realmname = xstrdup(realmname);
306 ch->guildname = xstrdup(""); /* FIXME: how does this work on Battle.net? */
307
308 if (account_check_closed_character(account, clienttag, realmname, name))
309 {
310 eventlog(eventlog_level_error,__FUNCTION__,"a character with the name \"%s\" does already exist in realm \"%s\"",name,realmname);
311 xfree((void *)ch->realmname); /* avoid warning */
312 xfree((void *)ch->name); /* avoid warning */
313 xfree(ch);
314 return -1;
315 }
316
317 load_initial_data (ch, class, expansion);
318
319 account_add_closed_character(account, clienttag, ch);
320
321 return 0;
322 }
323
324
character_get_name(t_character const * ch)325 extern char const * character_get_name(t_character const * ch)
326 {
327 if (!ch)
328 {
329 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
330 return NULL;
331 }
332 return ch->name;
333 }
334
335
character_get_realmname(t_character const * ch)336 extern char const * character_get_realmname(t_character const * ch)
337 {
338 if (!ch)
339 {
340 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
341 return NULL;
342 }
343 return ch->realmname;
344 }
345
346
character_get_class(t_character const * ch)347 extern t_character_class character_get_class(t_character const * ch)
348 {
349 if (!ch)
350 {
351 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
352 return character_class_none;
353 }
354 return bncharacter_class_to_character_class(ch->class);
355 }
356
357
character_get_playerinfo(t_character const * ch)358 extern char const * character_get_playerinfo(t_character const * ch)
359 {
360 t_d2char_info d2char_info;
361 static char playerinfo[sizeof(t_d2char_info)+4];
362
363 if (!ch)
364 {
365 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
366 return NULL;
367 }
368
369 /*
370 ff 0f 68 00 ..h.
371 0x0040: 01 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
372 0x0050: d8 94 f6 08 b1 65 77 02 65 76 69 6c 67 72 75 73 .....ew.evilgrus
373 0x0060: 73 6c 65 72 00 56 44 32 44 42 65 74 61 57 65 73 sler.VD2DBetaWes
374 0x0070: 74 2c 74 61 72 61 6e 2c 83 80 ff ff ff ff ff 2f t,taran,......./
375 0x0080: ff ff ff ff ff ff ff ff ff ff 03 ff ff ff ff ff ................
376 0x0090: ff ff ff ff ff ff ff ff ff ff ff 07 80 80 80 80 ................
377 0x00a0: ff ff ff 00
378
379 */
380 bn_byte_set(&d2char_info.unknownb1,ch->unknownb1);
381 bn_byte_set(&d2char_info.unknownb2,ch->unknownb2);
382 bn_byte_set(&d2char_info.helmgfx,ch->helmgfx);
383 bn_byte_set(&d2char_info.bodygfx,ch->bodygfx);
384 bn_byte_set(&d2char_info.leggfx,ch->leggfx);
385 bn_byte_set(&d2char_info.lhandweapon,ch->lhandweapon);
386 bn_byte_set(&d2char_info.lhandgfx,ch->lhandgfx);
387 bn_byte_set(&d2char_info.rhandweapon,ch->rhandweapon);
388 bn_byte_set(&d2char_info.rhandgfx,ch->rhandgfx);
389 bn_byte_set(&d2char_info.unknownb3,ch->unknownb3);
390 bn_byte_set(&d2char_info.unknownb4,ch->unknownb4);
391 bn_byte_set(&d2char_info.unknownb5,ch->unknownb5);
392 bn_byte_set(&d2char_info.unknownb6,ch->unknownb6);
393 bn_byte_set(&d2char_info.unknownb7,ch->unknownb7);
394 bn_byte_set(&d2char_info.unknownb8,ch->unknownb8);
395 bn_byte_set(&d2char_info.unknownb9,ch->unknownb9);
396 bn_byte_set(&d2char_info.unknownb10,ch->unknownb10);
397 bn_byte_set(&d2char_info.unknownb11,ch->unknownb11);
398 bn_byte_set(&d2char_info.class,ch->class);
399 bn_int_set(&d2char_info.unknown1,ch->unknown1);
400 bn_int_set(&d2char_info.unknown2,ch->unknown2);
401 bn_int_set(&d2char_info.unknown3,ch->unknown3);
402 bn_int_set(&d2char_info.unknown4,ch->unknown4);
403 bn_byte_set(&d2char_info.level,ch->level);
404 bn_byte_set(&d2char_info.status,ch->status);
405 bn_byte_set(&d2char_info.title,ch->title);
406 bn_byte_set(&d2char_info.unknownb13,ch->unknownb13);
407 bn_byte_set(&d2char_info.emblembgc,ch->emblembgc);
408 bn_byte_set(&d2char_info.emblemfgc,ch->emblemfgc);
409 bn_byte_set(&d2char_info.emblemnum,ch->emblemnum);
410 bn_byte_set(&d2char_info.unknownb14,ch->unknownb14);
411
412 memcpy(playerinfo,&d2char_info,sizeof(d2char_info));
413 strcpy(&playerinfo[sizeof(d2char_info)],ch->guildname);
414
415 return playerinfo;
416 }
417
418
character_get_guildname(t_character const * ch)419 extern char const * character_get_guildname(t_character const * ch)
420 {
421 if (!ch)
422 {
423 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
424 return NULL;
425 }
426 return ch->guildname;
427 }
428
429
character_verify_charlist(t_character const * ch,char const * charlist)430 extern int character_verify_charlist(t_character const * ch, char const * charlist)
431 {
432 char * temp;
433 char const * tok1;
434 char const * tok2;
435
436 if (!ch)
437 {
438 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
439 return -1;
440 }
441 if (!charlist)
442 {
443 eventlog(eventlog_level_error,__FUNCTION__,"got NULL character");
444 return -1;
445 }
446
447 temp = xstrdup(charlist);
448
449 tok1 = (char const *)strtok(temp,","); /* strtok modifies the string it is passed */
450 tok2 = strtok(NULL,",");
451 while (tok1)
452 {
453 if (!tok2)
454 {
455 eventlog(eventlog_level_error,__FUNCTION__,"bad character list \"%s\"",temp);
456 break;
457 }
458
459 if (strcasecmp(tok1,ch->realmname)==0 && strcasecmp(tok2,ch->name)==0)
460 {
461 xfree(temp);
462 return 0;
463 }
464
465 tok1 = strtok(NULL,",");
466 tok2 = strtok(NULL,",");
467 }
468 xfree(temp);
469
470 return -1;
471 }
472
473
characterlist_create(char const * dirname)474 extern int characterlist_create(char const * dirname)
475 {
476 characterlist_head = list_create();
477 return 0;
478 }
479
480
characterlist_destroy(void)481 extern int characterlist_destroy(void)
482 {
483 t_elem * curr;
484 t_character * ch;
485
486 if (characterlist_head)
487 {
488 LIST_TRAVERSE(characterlist_head,curr)
489 {
490 ch = elem_get_data(curr);
491 if (!ch) /* should not happen */
492 {
493 eventlog(eventlog_level_error,__FUNCTION__,"characterlist contains NULL item");
494 continue;
495 }
496
497 if (list_remove_elem(characterlist_head,&curr)<0)
498 eventlog(eventlog_level_error,__FUNCTION__,"could not remove item from list");
499 xfree(ch);
500 }
501
502 if (list_destroy(characterlist_head)<0)
503 return -1;
504 characterlist_head = NULL;
505 }
506
507 return 0;
508 }
509
510
characterlist_find_character(char const * realmname,char const * charname)511 extern t_character * characterlist_find_character(char const * realmname, char const * charname)
512 {
513 t_elem * curr;
514 t_character * ch;
515
516 if (!realmname)
517 {
518 eventlog(eventlog_level_error,__FUNCTION__,"got NULL realmname");
519 return NULL;
520 }
521 if (!charname)
522 {
523 eventlog(eventlog_level_error,__FUNCTION__,"got NULL charname");
524 return NULL;
525 }
526
527 LIST_TRAVERSE(characterlist_head,curr)
528 {
529 ch = elem_get_data(curr);
530 if (strcasecmp(ch->name,charname)==0 && strcasecmp(ch->realmname,realmname)==0)
531 return ch;
532 }
533
534 return NULL;
535 }
536