1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20 21#include "quakedef.h" 22 23cvar_t baseskin = CVAR2("baseskin", "base"); 24cvar_t noskins = CVAR2("noskins", "0"); 25 26char allskins[128]; 27#define MAX_CACHED_SKINS 128 28skin_t skins[MAX_CACHED_SKINS]; 29int numskins; 30 31/* 32================ 33Skin_Find 34 35 Determines the best skin for the given scoreboard 36 slot, and sets scoreboard->skin 37 38================ 39*/ 40void 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========== 89Skin_Cache 90 91Returns a pointer to the skin bitmap, or NULL to use the default 92========== 93*/ 94byte *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================= 216Skin_NextDownload 217================= 218*/ 219void 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========== 268Skin_Skins_f 269 270Refind all skins, downloading if needed. 271========== 272*/ 273void 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========== 292Skin_AllSkins_f 293 294Sets all skins to one specific one 295========== 296*/ 297void Skin_AllSkins_f (void) 298{ 299 strcpy (allskins, Cmd_Argv(1)); 300 Skin_Skins_f (); 301} 302