Home | History | Annotate | Download | only in client
      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 */
     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 */
     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 */
    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 */
    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 */
    297 void	Skin_AllSkins_f (void)
    298 {
    299 	strcpy (allskins, Cmd_Argv(1));
    300 	Skin_Skins_f ();
    301 }
    302