1 /*
2  * Copyright (C) 2000,2001	Onlyer	(onlyer@263.net)
3  * Copyright (C) 2001		sousou	(liupeng.cs@263.net)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 #include "common/setup_before.h"
20 #include "setup.h"
21 
22 #ifdef HAVE_STDDEF_H
23 # include <stddef.h>
24 #else
25 # ifndef NULL
26 #  define NULL ((void *)0)
27 # endif
28 #endif
29 #include <stdio.h>
30 #ifdef HAVE_STRING_H
31 # include <string.h>
32 #else
33 # ifdef HAVE_STRINGS_H
34 #  include <strings.h>
35 # endif
36 # ifdef HAVE_MEMORY_H
37 #  include <memory.h>
38 # endif
39 #endif
40 #include "compat/strcasecmp.h"
41 #include "compat/memset.h"
42 #include <errno.h>
43 #include "compat/strerror.h"
44 #ifdef STDC_HEADERS
45 # include <stdlib.h>
46 #else
47 # ifdef HAVE_MALLOC_H
48 #  include <malloc.h>
49 # endif
50 #endif
51 
52 #include "prefs.h"
53 #include "d2charfile.h"
54 #include "d2ladder.h"
55 #include "d2cs_protocol.h"
56 #include "common/tag.h"
57 #include "common/eventlog.h"
58 #include "common/xalloc.h"
59 #include "common/setup_after.h"
60 
61 static t_d2ladder	* ladder_data=NULL;
62 static unsigned int	max_ladder_type=0;
63 
64 static int d2ladderlist_create(unsigned int maxtype);
65 static int d2ladder_create(unsigned int type, unsigned int len);
66 static int d2ladder_append_ladder(unsigned int type, t_d2ladderfile_ladderinfo * info);
67 static int d2ladder_readladder(void);
68 
d2ladder_init(void)69 extern int d2ladder_init(void)
70 {
71 	if (d2ladder_readladder()<0) {
72 		eventlog(eventlog_level_error,__FUNCTION__,"failed to initialize ladder data");
73 		return -1;
74 	}
75 	eventlog(eventlog_level_info,__FUNCTION__,"ladder data initialized");
76 	return 0;
77 }
78 
d2ladder_readladder(void)79 static int d2ladder_readladder(void)
80 {
81 	FILE				* fp;
82 	t_d2ladderfile_ladderindex	* ladderheader;
83 	t_d2ladderfile_ladderinfo	* ladderinfo;
84 	char				* ladderfile;
85 	t_d2ladderfile_header		header;
86 	unsigned int			i, n, temp, count, type, number;
87 
88 	ladderfile=xmalloc(strlen(prefs_get_ladder_dir())+1+strlen(LADDER_FILE_PREFIX)+1+
89 			strlen(CLIENTTAG_DIABLO2DV)+1);
90 	sprintf(ladderfile,"%s/%s.%s",prefs_get_ladder_dir(),LADDER_FILE_PREFIX,CLIENTTAG_DIABLO2DV);
91 	if (!(fp=fopen(ladderfile,"rb"))) {
92 		eventlog(eventlog_level_error,__FUNCTION__,"error opening ladder file \"%s\" for reading (fopen: %s)",ladderfile,pstrerror(errno));
93 		xfree(ladderfile);
94 		return -1;
95 	}
96 	xfree(ladderfile);
97 	if (fread(&header,1,sizeof(header),fp)!=sizeof(header)) {
98 		eventlog(eventlog_level_error,__FUNCTION__,"error reading ladder file");
99 		fclose(fp);
100 		return -1;
101 	}
102 	max_ladder_type= bn_int_get(header.maxtype);
103 	if (d2ladderlist_create(max_ladder_type)<0) {
104 		eventlog(eventlog_level_error,__FUNCTION__,"error create ladder list");
105 		fclose(fp);
106 		return -1;
107 	}
108 	temp= max_ladder_type * sizeof(*ladderheader);
109 	ladderheader=xmalloc(temp);
110 	if (fread(ladderheader,1,temp,fp)!=temp) {
111 		eventlog(eventlog_level_error,__FUNCTION__,"error read ladder file");
112 		xfree(ladderheader);
113 		fclose(fp);
114 		return -1;
115 	}
116 	for (i=0, count=0; i< max_ladder_type ; i++) {
117 		type=bn_int_get(ladderheader[i].type);
118 		number=bn_int_get(ladderheader[i].number);
119 		if (d2ladder_create(type,number)<0) {
120 			eventlog(eventlog_level_error,__FUNCTION__,"error create ladder %d",type);
121 			continue;
122 		}
123 		fseek(fp,bn_int_get(ladderheader[i].offset),SEEK_SET);
124 		temp=number * sizeof(*ladderinfo);
125 		ladderinfo=xmalloc(temp);
126 		if (fread(ladderinfo,1,temp,fp)!=temp) {
127 			eventlog(eventlog_level_error,__FUNCTION__,"error read ladder file");
128 			xfree(ladderinfo);
129 			continue;
130 		}
131 		for (n=0; n< number; n++) {
132 			d2ladder_append_ladder(type,ladderinfo+n);
133 		}
134 		xfree(ladderinfo);
135 		if (number) count++;
136 	}
137 	xfree(ladderheader);
138 	fclose(fp);
139 	eventlog(eventlog_level_info,__FUNCTION__,"ladder file loaded successfully (%d types %d maxtype)",count,max_ladder_type);
140 	return 0;
141 }
142 
d2ladderlist_create(unsigned int maxtype)143 static int d2ladderlist_create(unsigned int maxtype)
144 {
145 	ladder_data=xmalloc(maxtype * sizeof(*ladder_data));
146 	memset(ladder_data,0, maxtype * sizeof(*ladder_data));
147 	return 0;
148 }
149 
d2ladder_refresh(void)150 extern int d2ladder_refresh(void)
151 {
152 	d2ladder_destroy();
153 	return d2ladder_readladder();
154 }
155 
d2ladder_create(unsigned int type,unsigned int len)156 static int d2ladder_create(unsigned int type, unsigned int len)
157 {
158 	if (type>max_ladder_type) {
159 		eventlog(eventlog_level_error,__FUNCTION__,"ladder type %d exceed max ladder type %d",type,max_ladder_type);
160 		return -1;
161 	}
162 	ladder_data[type].info=xmalloc(sizeof(t_d2cs_client_ladderinfo) * len);
163 	ladder_data[type].len=len;
164 	ladder_data[type].type=type;
165 	ladder_data[type].curr_len=0;
166 	return 0;
167 }
168 
d2ladder_append_ladder(unsigned int type,t_d2ladderfile_ladderinfo * info)169 static int d2ladder_append_ladder(unsigned int type, t_d2ladderfile_ladderinfo * info)
170 {
171 	t_d2cs_client_ladderinfo	* ladderinfo;
172 	unsigned short			ladderstatus;
173 	unsigned short			status;
174 	unsigned char			class;
175 
176 	if (!info) {
177 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL info");
178 		return -1;
179 	}
180 	if (type > max_ladder_type) {
181 		eventlog(eventlog_level_error,__FUNCTION__,"ladder type %d exceed max ladder type %d",type,max_ladder_type);
182 		return -1;
183 	}
184 	if (!ladder_data[type].info) {
185 		eventlog(eventlog_level_error,__FUNCTION__,"ladder data info not initialized");
186 		return -1;
187 	}
188 	if (ladder_data[type].curr_len >= ladder_data[type].len) {
189 		eventlog(eventlog_level_error,__FUNCTION__,"ladder data overflow %d > %d", ladder_data[type].curr_len, ladder_data[type].len);
190 		return -1;
191 	}
192 	status = bn_short_get(info->status);
193 	class = bn_byte_get(info->class);
194 	ladderstatus = (status & LADDERSTATUS_FLAG_DIFFICULTY);
195 	if (charstatus_get_hardcore(status)) {
196 		ladderstatus |= LADDERSTATUS_FLAG_HARDCORE;
197 		if (charstatus_get_dead(status)) {
198 			ladderstatus |= LADDERSTATUS_FLAG_DEAD;
199 		}
200 	}
201 	if (charstatus_get_expansion(status)) {
202 		ladderstatus |= LADDERSTATUS_FLAG_EXPANSION;
203 		ladderstatus |= min(class,D2CHAR_EXP_CLASS_MAX);
204 	} else {
205 		ladderstatus |= min(class,D2CHAR_CLASS_MAX);
206 	}
207 	ladderinfo=ladder_data[type].info+ladder_data[type].curr_len;
208 	bn_int_set(&ladderinfo->explow, bn_int_get(info->experience));
209 	bn_int_set(&ladderinfo->exphigh,0);
210 	bn_short_set(&ladderinfo->status,ladderstatus);
211 	bn_byte_set(&ladderinfo->level, bn_int_get(info->level));
212 	bn_byte_set(&ladderinfo->u1, 0);
213 	strncpy(ladderinfo->charname, info->charname, MAX_CHARNAME_LEN);
214 	ladder_data[type].curr_len++;
215 	return 0;
216 }
217 
d2ladder_destroy(void)218 extern int d2ladder_destroy(void)
219 {
220 	unsigned int i;
221 
222 	if (ladder_data) {
223 		for (i=0; i< max_ladder_type; i++) {
224 			if (ladder_data[i].info) {
225 				xfree(ladder_data[i].info);
226 				ladder_data[i].info=NULL;
227 			}
228 		}
229 		xfree(ladder_data);
230 		ladder_data=NULL;
231 	}
232 	max_ladder_type=0;
233 	return 0;
234 }
235 
d2ladder_get_ladder(unsigned int * from,unsigned int * count,unsigned int type,t_d2cs_client_ladderinfo const ** info)236 extern int d2ladder_get_ladder(unsigned int * from, unsigned int * count, unsigned int type,
237 					t_d2cs_client_ladderinfo const * * info)
238 {
239 	t_d2ladder	* ladder;
240 
241 	if (!ladder_data) return -1;
242 	ladder=ladder_data+type;
243 	if (!ladder->curr_len || !ladder->info) {
244 		eventlog(eventlog_level_warn,__FUNCTION__,"ladder type %d not found",type);
245 		return -1;
246 	}
247 	if (ladder->type != type) {
248 		eventlog(eventlog_level_error,__FUNCTION__,"got bad ladder data");
249 		return -1;
250 	}
251 	if (ladder->curr_len < *count) {
252 		*from = 0;
253 		*count=ladder->curr_len;
254 	} else if (*from + *count> ladder->curr_len) {
255 		*from= ladder->curr_len - *count;
256 	}
257 	*info = ladder->info+ *from;
258 	return 0;
259 }
260 
d2ladder_find_character_pos(unsigned int type,char const * charname)261 extern int d2ladder_find_character_pos(unsigned int type, char const * charname)
262 {
263 	unsigned int	i;
264 	t_d2ladder	* ladder;
265 
266 	if (!ladder_data) return -1;
267 	ladder=ladder_data+type;
268 	if (!ladder->curr_len || !ladder->info) {
269 		eventlog(eventlog_level_warn,__FUNCTION__,"ladder type %d not found",type);
270 		return -1;
271 	}
272 	if (ladder->type != type) {
273 		eventlog(eventlog_level_error,__FUNCTION__,"got bad ladder data");
274 		return -1;
275 	}
276 	for (i=0; i< ladder->curr_len; i++) {
277 		if (!strcasecmp(ladder->info[i].charname,charname)) return i;
278 	}
279 	return -1;
280 }
281