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