• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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