1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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.
12
13 See the 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 */
20
21 #include "quakedef.h"
22
23 cvar_t baseskin = CVAR2("baseskin", "base");
24 cvar_t noskins = CVAR2("noskins", "0");
25
26 char allskins[128];
27 #define MAX_CACHED_SKINS 128
28 skin_t skins[MAX_CACHED_SKINS];
29 int numskins;
30
31 /*
32 ================
33 Skin_Find
34
35 Determines the best skin for the given scoreboard
36 slot, and sets scoreboard->skin
37
38 ================
39 */
Skin_Find(player_info_t * sc)40 void Skin_Find (player_info_t *sc)
41 {
42 skin_t *skin;
43 int i;
44 char name[128], *s;
45
46 if (allskins[0])
47 strcpy (name, allskins);
48 else
49 {
50 s = Info_ValueForKey (sc->userinfo, "skin");
51 if (s && s[0])
52 strcpy (name, s);
53 else
54 strcpy (name, baseskin.string);
55 }
56
57 if (strstr (name, "..") || *name == '.')
58 strcpy (name, "base");
59
60 COM_StripExtension (name, name);
61
62 for (i=0 ; i<numskins ; i++)
63 {
64 if (!strcmp (name, skins[i].name))
65 {
66 sc->skin = &skins[i];
67 Skin_Cache (sc->skin);
68 return;
69 }
70 }
71
72 if (numskins == MAX_CACHED_SKINS)
73 { // ran out of spots, so flush everything
74 Skin_Skins_f ();
75 return;
76 }
77
78 skin = &skins[numskins];
79 sc->skin = skin;
80 numskins++;
81
82 memset (skin, 0, sizeof(*skin));
83 strncpy(skin->name, name, sizeof(skin->name) - 1);
84 }
85
86
87 /*
88 ==========
89 Skin_Cache
90
91 Returns a pointer to the skin bitmap, or NULL to use the default
92 ==========
93 */
Skin_Cache(skin_t * skin)94 byte *Skin_Cache (skin_t *skin)
95 {
96 char name[1024];
97 byte *raw;
98 byte *out, *pix;
99 pcx_t *pcx;
100 int x, y;
101 int dataByte;
102 int runLength;
103
104 if (cls.downloadtype == dl_skin)
105 return NULL; // use base until downloaded
106
107 if (noskins.value==1) // JACK: So NOSKINS > 1 will show skins, but
108 return NULL; // not download new ones.
109
110 if (skin->failedload)
111 return NULL;
112
113 out = Cache_Check (&skin->cache);
114 if (out)
115 return out;
116
117 //
118 // load the pic from disk
119 //
120 sprintf (name, "skins/%s.pcx", skin->name);
121 raw = COM_LoadTempFile (name);
122 if (!raw)
123 {
124 Con_Printf ("Couldn't load skin %s\n", name);
125 sprintf (name, "skins/%s.pcx", baseskin.string);
126 raw = COM_LoadTempFile (name);
127 if (!raw)
128 {
129 skin->failedload = true;
130 return NULL;
131 }
132 }
133
134 //
135 // parse the PCX file
136 //
137 pcx = (pcx_t *)raw;
138 raw = &pcx->data;
139
140 if (pcx->manufacturer != 0x0a
141 || pcx->version != 5
142 || pcx->encoding != 1
143 || pcx->bits_per_pixel != 8
144 || pcx->xmax >= 320
145 || pcx->ymax >= 200)
146 {
147 skin->failedload = true;
148 Con_Printf ("Bad skin %s\n", name);
149 return NULL;
150 }
151
152 out = Cache_Alloc (&skin->cache, 320*200, skin->name);
153 if (!out)
154 Sys_Error ("Skin_Cache: couldn't allocate");
155
156 pix = out;
157 memset (out, 0, 320*200);
158
159 for (y=0 ; y<pcx->ymax ; y++, pix += 320)
160 {
161 for (x=0 ; x<=pcx->xmax ; )
162 {
163 if (raw - (byte*)pcx > com_filesize)
164 {
165 Cache_Free (&skin->cache);
166 skin->failedload = true;
167 Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
168 return NULL;
169 }
170 dataByte = *raw++;
171
172 if((dataByte & 0xC0) == 0xC0)
173 {
174 runLength = dataByte & 0x3F;
175 if (raw - (byte*)pcx > com_filesize)
176 {
177 Cache_Free (&skin->cache);
178 skin->failedload = true;
179 Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
180 return NULL;
181 }
182 dataByte = *raw++;
183 }
184 else
185 runLength = 1;
186
187 // skin sanity check
188 if (runLength + x > pcx->xmax + 2) {
189 Cache_Free (&skin->cache);
190 skin->failedload = true;
191 Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
192 return NULL;
193 }
194 while(runLength-- > 0)
195 pix[x++] = dataByte;
196 }
197
198 }
199
200 if ( raw - (byte *)pcx > com_filesize)
201 {
202 Cache_Free (&skin->cache);
203 skin->failedload = true;
204 Con_Printf ("Skin %s was malformed. You should delete it.\n", name);
205 return NULL;
206 }
207
208 skin->failedload = false;
209
210 return out;
211 }
212
213
214 /*
215 =================
216 Skin_NextDownload
217 =================
218 */
Skin_NextDownload(void)219 void Skin_NextDownload (void)
220 {
221 player_info_t *sc;
222 int i;
223
224 if (cls.downloadnumber == 0)
225 Con_Printf ("Checking skins...\n");
226 cls.downloadtype = dl_skin;
227
228 for (
229 ; cls.downloadnumber != MAX_CLIENTS
230 ; cls.downloadnumber++)
231 {
232 sc = &cl.players[cls.downloadnumber];
233 if (!sc->name[0])
234 continue;
235 Skin_Find (sc);
236 if (noskins.value)
237 continue;
238 if (!CL_CheckOrDownloadFile(va("skins/%s.pcx", sc->skin->name)))
239 return; // started a download
240 }
241
242 cls.downloadtype = dl_none;
243
244 // now load them in for real
245 for (i=0 ; i<MAX_CLIENTS ; i++)
246 {
247 sc = &cl.players[i];
248 if (!sc->name[0])
249 continue;
250 Skin_Cache (sc->skin);
251 #ifdef GLQUAKE
252 sc->skin = NULL;
253 #endif
254 }
255
256 if (cls.state != ca_active)
257 { // get next signon phase
258 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
259 MSG_WriteString (&cls.netchan.message,
260 va("begin %i", cl.servercount));
261 Cache_Report (); // print remaining memory
262 }
263 }
264
265
266 /*
267 ==========
268 Skin_Skins_f
269
270 Refind all skins, downloading if needed.
271 ==========
272 */
Skin_Skins_f(void)273 void Skin_Skins_f (void)
274 {
275 int i;
276
277 for (i=0 ; i<numskins ; i++)
278 {
279 if (skins[i].cache.data)
280 Cache_Free (&skins[i].cache);
281 }
282 numskins = 0;
283
284 cls.downloadnumber = 0;
285 cls.downloadtype = dl_skin;
286 Skin_NextDownload ();
287 }
288
289
290 /*
291 ==========
292 Skin_AllSkins_f
293
294 Sets all skins to one specific one
295 ==========
296 */
Skin_AllSkins_f(void)297 void Skin_AllSkins_f (void)
298 {
299 strcpy (allskins, Cmd_Argv(1));
300 Skin_Skins_f ();
301 }
302