newtree/source/skin.c
Bill Currie 5d15e27a3e pcx.c:
forgot to close the skin file.
skin.c:
	seeking within a file inside a pak does NOT work for SEEK_SET and SEEK_END
	so load the whole file at once into memory and change processing
	accordingly. The Hunk_*Alloc calls work nicely because the file is loaded
	into the lower hunk space while the tex is allocated from the temp space
	which is in the high hunk space.
2001-01-18 19:09:37 +00:00

342 lines
6.9 KiB
C

/*
skin.c
(description)
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include "cl_parse.h"
#include "console.h"
#include "cmd.h"
#include "host.h"
#include "msg.h"
#include "pcx.h"
#include "qendian.h"
#include "screen.h"
#include "skin.h"
#include "sys.h"
#include "texture.h"
#include "va.h"
cvar_t *baseskin;
cvar_t *noskins;
cvar_t *skin;
cvar_t *topcolor;
cvar_t *bottomcolor;
char allskins[128];
#define MAX_CACHED_SKINS 128
skin_t skins[MAX_CACHED_SKINS];
int numskins;
/*
Skin_Find
Determines the best skin for the given scoreboard
slot, and sets scoreboard->skin
*/
void
Skin_Find (player_info_t *sc)
{
skin_t *skin;
int i;
char name[128], *s;
if (allskins[0])
strcpy (name, allskins);
else {
s = Info_ValueForKey (sc->userinfo, "skin");
if (s && s[0])
strcpy (name, s);
else
strcpy (name, baseskin->string);
}
if (strstr (name, "..") || *name == '.')
strcpy (name, "base");
COM_StripExtension (name, name);
for (i = 0; i < numskins; i++) {
if (!strcmp (name, skins[i].name)) {
sc->skin = &skins[i];
Skin_Cache (sc->skin);
return;
}
}
if (numskins == MAX_CACHED_SKINS) { // ran out of spots, so flush
// everything
Skin_Skins_f ();
return;
}
skin = &skins[numskins];
sc->skin = skin;
numskins++;
memset (skin, 0, sizeof (*skin));
strncpy (skin->name, name, sizeof (skin->name) - 1);
}
/*
Skin_Cache
Returns a pointer to the skin bitmap, or NULL to use the default
*/
byte *
Skin_Cache (skin_t *skin)
{
char name[1024];
byte *out;
QFile *file;
tex_t *tex;
if (cls.downloadtype == dl_skin)
return NULL; // use base until downloaded
if (noskins->int_val) // JACK: So NOSKINS > 1 will show
// skins, but
return NULL; // not download new ones.
if (skin->failedload)
return NULL;
out = Cache_Check (&skin->cache);
if (out)
return out;
// load the pic from disk
snprintf (name, sizeof (name), "skins/%s.pcx", skin->name);
COM_FOpenFile (name, &file);
if (!file) {
Con_Printf ("Couldn't load skin %s\n", name);
snprintf (name, sizeof (name), "skins/%s.pcx", baseskin->string);
COM_FOpenFile (name, &file);
if (!file) {
skin->failedload = true;
return NULL;
}
}
tex = LoadPCX (file, 0);
Qclose (file);
if (!tex || tex->width > 320 || tex->height > 200) {
skin->failedload = true;
Con_Printf ("Bad skin %s\n", name);
return NULL;
}
out = Cache_Alloc (&skin->cache, 320 * 200, skin->name);
if (!out)
Sys_Error ("Skin_Cache: couldn't allocate");
memcpy (out, tex->data, tex->width * tex->height);
skin->failedload = false;
return out;
}
/*
Skin_NextDownload
*/
void
Skin_NextDownload (void)
{
player_info_t *sc;
int i;
if (cls.downloadnumber == 0) {
Con_Printf ("Checking skins...\n");
SCR_UpdateScreen ();
}
cls.downloadtype = dl_skin;
for (; cls.downloadnumber != MAX_CLIENTS; cls.downloadnumber++) {
sc = &cl.players[cls.downloadnumber];
if (!sc->name[0])
continue;
Skin_Find (sc);
if (noskins->int_val)
continue;
if (!CL_CheckOrDownloadFile (va ("skins/%s.pcx", sc->skin->name)))
return; // started a download
}
cls.downloadtype = dl_none;
// now load them in for real
for (i = 0; i < MAX_CLIENTS; i++) {
sc = &cl.players[i];
if (!sc->name[0])
continue;
Skin_Cache (sc->skin);
sc->skin = NULL;
}
if (cls.state != ca_active) { // get next signon phase
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, va ("begin %i", cl.servercount));
Cache_Report (); // print remaining memory
}
}
/*
Skin_Skins_f
Refind all skins, downloading if needed.
*/
void
Skin_Skins_f (void)
{
int i;
for (i = 0; i < numskins; i++) {
if (skins[i].cache.data)
Cache_Free (&skins[i].cache);
}
numskins = 0;
cls.downloadnumber = 0;
cls.downloadtype = dl_skin;
Skin_NextDownload ();
}
/*
Skin_AllSkins_f
Sets all skins to one specific one
*/
void
Skin_AllSkins_f (void)
{
strcpy (allskins, Cmd_Argv (1));
Skin_Skins_f ();
}
void
CL_Color_f (void)
{
// just for quake compatability...
int top, bottom;
char num[16];
if (Cmd_Argc () == 1) {
Con_Printf ("\"color\" is \"%s %s\"\n",
Info_ValueForKey (cls.userinfo, "topcolor"),
Info_ValueForKey (cls.userinfo, "bottomcolor"));
Con_Printf ("color <0-13> [0-13]\n");
return;
}
if (Cmd_Argc () == 2)
top = bottom = atoi (Cmd_Argv (1));
else {
top = atoi (Cmd_Argv (1));
bottom = atoi (Cmd_Argv (2));
}
top &= 15;
if (top > 13)
top = 13;
bottom &= 15;
if (bottom > 13)
bottom = 13;
snprintf (num, sizeof (num), "%i", top);
Cvar_Set (topcolor, num);
snprintf (num, sizeof (num), "%i", bottom);
Cvar_Set (bottomcolor, num);
}
void
Skin_Init (void)
{
Cmd_AddCommand ("skins", Skin_Skins_f, "No Description");
Cmd_AddCommand ("allskins", Skin_AllSkins_f, "No Description");
Cmd_AddCommand ("color", CL_Color_f, "No Description");
Skin_Init_Translation ();
}
void
Skin_Init_Cvars (void)
{
baseskin = Cvar_Get ("baseskin", "base", CVAR_NONE,
"default base skin name");
noskins = Cvar_Get ("noskins", "0", CVAR_NONE,
"set to 1 to not download new skins");
skin = Cvar_Get ("skin", "", CVAR_ARCHIVE | CVAR_USERINFO, "Players skin");
topcolor = Cvar_Get ("topcolor", "0", CVAR_ARCHIVE | CVAR_USERINFO,
"Players color on top");
bottomcolor = Cvar_Get ("bottomcolor", "0", CVAR_ARCHIVE | CVAR_USERINFO,
"Players color on bottom");
}
/*
CL_NewTranslation
*/
void
CL_NewTranslation (int slot)
{
player_info_t *player;
char s[512];
if (slot > MAX_CLIENTS)
Host_EndGame ("CL_NewTranslation: slot > MAX_CLIENTS");
player = &cl.players[slot];
if (!player->name[0])
return;
strcpy (s, Info_ValueForKey (player->userinfo, "skin"));
COM_StripExtension (s, s);
if (player->skin && !strequal (s, player->skin->name))
player->skin = NULL;
if (player->_topcolor != player->topcolor ||
player->_bottomcolor != player->bottomcolor || !player->skin) {
player->_topcolor = player->topcolor;
player->_bottomcolor = player->bottomcolor;
Skin_Set_Translate (player);
Skin_Do_Translation (player);
}
}