software banding: fix player skins.
try to get game controller defaults a little closer to QS. mess with r_dynamic 2 a little, to more closely match vanilla. fix under-lighting bug on models. added extra model lighting pathway for greater vanilla compat, as part of software-banding. fix proquake-client compat issue. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5192 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
c1392378f2
commit
a6ac015c5b
26 changed files with 363 additions and 158 deletions
|
@ -295,7 +295,13 @@ void CL_DecayLights (void)
|
|||
continue;
|
||||
}
|
||||
|
||||
dl->radius -= frametime*dl->decay;
|
||||
if (r_dynamic.ival == 2)
|
||||
{ //don't decay quite so fast, this should aproximate winquake a bit better.
|
||||
dl->die -= frametime * 0.5;
|
||||
dl->radius -= frametime*dl->decay * 0.5;
|
||||
}
|
||||
else
|
||||
dl->radius -= frametime*dl->decay;
|
||||
if (dl->radius < 0)
|
||||
{
|
||||
if (i==rtlights_first)
|
||||
|
|
|
@ -5279,10 +5279,13 @@ static void CL_SetStatMovevar(int pnum, int stat, int ivalue, float value)
|
|||
movevars.stepheight = value;
|
||||
break;
|
||||
case STAT_MOVEVARS_TICRATE: //cl_maxfps limiter hint
|
||||
if (value <= 0)
|
||||
cls.maxfps = 1.0/value;
|
||||
else
|
||||
cls.maxfps = 72;
|
||||
if (cls.protocol == CP_NETQUAKE && CPNQ_IS_DP)
|
||||
{
|
||||
if (value <= 0)
|
||||
cls.maxfps = 1.0/value;
|
||||
else
|
||||
cls.maxfps = 72;
|
||||
}
|
||||
break;
|
||||
case STAT_MOVEFLAGS:
|
||||
// movevars.flags = ivalue;
|
||||
|
|
|
@ -1393,7 +1393,7 @@ qboolean CSQC_UseGamecodeLoadingScreen(void);
|
|||
void CSQC_Shutdown(void);
|
||||
qboolean CSQC_StuffCmd(int lplayernum, char *cmd, char *cmdend);
|
||||
void CSQC_MapEntityEdited(int modelindex, int idx, const char *newe);
|
||||
qboolean CSQC_LoadResource(char *resname, char *restype);
|
||||
//qboolean CSQC_LoadResource(char *resname, char *restype);
|
||||
qboolean CSQC_ParsePrint(char *message, int printlevel);
|
||||
qboolean CSQC_ParseGamePacket(int seat);
|
||||
qboolean CSQC_CenterPrint(int seat, const char *cmd);
|
||||
|
|
|
@ -4779,7 +4779,7 @@ static void Image_ChangeFormat(struct pendingtextureinfo *mips, unsigned int fla
|
|||
mips->mip[mip].needfree = true;
|
||||
|
||||
for (i = 0; i < mips->mip[mip].width*mips->mip[mip].height; i++, in+=4)
|
||||
out[i] = GetPaletteIndex(in[0], in[1], in[2]);
|
||||
out[i] = GetPaletteIndexNoFB(in[0], in[1], in[2]);
|
||||
|
||||
if (needfree)
|
||||
BZ_Free(needfree);
|
||||
|
|
|
@ -78,10 +78,10 @@ static cvar_t joy_advaxis[6] =
|
|||
#define ADVAXISDESC (const char *)"Provides a way to remap each joystick/controller axis.\nShould be set to one of: moveforward, moveback, lookup, lookdown, turnleft, turnright, moveleft, moveright, moveup, movedown, rollleft, rollright"
|
||||
CVARCD("joyadvaxisx", "turnright", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisy", "lookup", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisz", "moveup", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisz", "", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisr", "moveright", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisu", "moveforward", joyaxiscallback, ADVAXISDESC),
|
||||
CVARCD("joyadvaxisv", "rollright", joyaxiscallback, ADVAXISDESC)
|
||||
CVARCD("joyadvaxisv", "", joyaxiscallback, ADVAXISDESC)
|
||||
};
|
||||
static cvar_t joy_advaxisscale[6] =
|
||||
{
|
||||
|
|
|
@ -2704,20 +2704,20 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
|
|||
|
||||
//gamepad buttons should get fallbacks out of the box, even if they're not initially listed on the binds menu.
|
||||
//these may be redefined later...
|
||||
case K_GP_LEFT_SHOULDER: dc = "impulse 12"; goto defaultedbind; //matches QS's default.cfg
|
||||
case K_GP_RIGHT_SHOULDER: dc = "impulse 10"; goto defaultedbind; //matches QS's default.cfg
|
||||
case K_GP_LEFT_TRIGGER: dc = "+jump"; goto defaultedbind; //matches QS's default.cfg
|
||||
case K_GP_RIGHT_TRIGGER: dc = "+attack"; goto defaultedbind; //matches QS's default.cfg
|
||||
case K_GP_START: dc = "togglemenu"; goto defaultedbind;
|
||||
case K_GP_A: dc = "+button4"; goto defaultedbind;
|
||||
case K_GP_B: dc = "+button3"; goto defaultedbind;
|
||||
case K_GP_LEFT_SHOULDER:
|
||||
case K_GP_X: dc = "+attack"; goto defaultedbind;
|
||||
case K_GP_RIGHT_SHOULDER:
|
||||
case K_GP_Y: dc = "+jump"; goto defaultedbind;
|
||||
case K_GP_BACK: dc = "impulse 10"; goto defaultedbind;
|
||||
case K_GP_DPAD_UP: dc = "+forward"; goto defaultedbind;
|
||||
case K_GP_DPAD_DOWN: dc = "+back"; goto defaultedbind;
|
||||
case K_GP_DPAD_LEFT: dc = "+moveleft"; goto defaultedbind;
|
||||
case K_GP_DPAD_RIGHT: dc = "+moveright"; goto defaultedbind;
|
||||
case K_GP_LEFT_TRIGGER: dc = "+left"; goto defaultedbind;
|
||||
case K_GP_RIGHT_TRIGGER: dc = "+right"; goto defaultedbind;
|
||||
case K_GP_LEFT_THUMB: dc = "toggleconsole"; goto defaultedbind;
|
||||
case K_GP_UNKNOWN:
|
||||
case K_GP_RIGHT_THUMB:
|
||||
|
|
|
@ -491,7 +491,7 @@ static void PClassic_DrawParticles(void)
|
|||
// Vector4Set(cl_strisvertc[cl_numstrisvert+1],1,1,1,1);
|
||||
// Vector4Set(cl_strisvertc[cl_numstrisvert+2],1,1,1,1);
|
||||
|
||||
Vector4Set(cl_strisvertc[cl_numstrisvert+0], ((p->rgb&0xff)>>0)/256.0, ((p->rgb&0xff00)>>8)/256.0, ((p->rgb&0xff0000)>>16)/256.0, ((p->type == pt_fire && !r_part_classic_opaque.ival)?((6 - p->ramp) *0.166666):1.0));
|
||||
Vector4Set(cl_strisvertc[cl_numstrisvert+0], ((p->rgb&0xff)>>0)/255.0, ((p->rgb&0xff00)>>8)/255.0, ((p->rgb&0xff0000)>>16)/255.0, ((p->type == pt_fire && !r_part_classic_opaque.ival)?((6 - p->ramp) *0.166666):1.0));
|
||||
Vector4Copy(cl_strisvertc[cl_numstrisvert+0], cl_strisvertc[cl_numstrisvert+1]);
|
||||
Vector4Copy(cl_strisvertc[cl_numstrisvert+0], cl_strisvertc[cl_numstrisvert+2]);
|
||||
|
||||
|
|
|
@ -173,6 +173,7 @@ typedef struct {
|
|||
|
||||
blendmode_t blendmode;
|
||||
shader_t *shader;
|
||||
qboolean nearest;
|
||||
|
||||
float scalefactor;
|
||||
float invscalefactor;
|
||||
|
@ -914,7 +915,7 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn)
|
|||
memset(&tn, 0, sizeof(tn));
|
||||
if (*ptype->texname)
|
||||
{
|
||||
tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_LOADNOW | IF_NOMIPMAP|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff
|
||||
tn.base = R_LoadHiResTexture(ptype->texname, "particles", IF_LOADNOW | IF_NOMIPMAP|(ptype->looks.nearest?IF_NEAREST:IF_LINEAR)|(ptype->looks.premul?IF_PREMULTIPLYALPHA:0)); //mipmapping breaks particlefont stuff
|
||||
if (tn.base && tn.base->status == TEX_LOADING)
|
||||
COM_WorkerPartialSync(tn.base, &tn.base->status, TEX_LOADING);
|
||||
}
|
||||
|
@ -1245,8 +1246,11 @@ void P_ParticleEffect_f(void)
|
|||
else
|
||||
Cbuf_InsertText(buf, Cmd_ExecLevel, true);
|
||||
}
|
||||
else if (!strcmp(var, "texture"))
|
||||
else if (!strcmp(var, "texture") || !strcmp(var, "linear_texture") || !strcmp(var, "nearest_texture") || !strcmp(var, "nearesttexture"))
|
||||
{
|
||||
Q_strncpyz(ptype->texname, value, sizeof(ptype->texname));
|
||||
ptype->looks.nearest = !strncmp(var, "nearest", 7);
|
||||
}
|
||||
else if (!strcmp(var, "tcoords"))
|
||||
{
|
||||
float tscale;
|
||||
|
@ -2383,7 +2387,7 @@ qboolean PScript_Query(int typenum, int body, char *outstr, int outstrlen)
|
|||
if (*ptype->texname || all)
|
||||
{ //note: particles don't really know if the shader was embedded or not. the shader system handles all that.
|
||||
//this means that you'll really need to use external shaders for this to work.
|
||||
Q_strncatz(outstr, va("texture \"%s\"\n", ptype->texname), outstrlen);
|
||||
Q_strncatz(outstr, va("%stexture \"%s\"\n", ptype->looks.nearest?"nearest_":"", ptype->texname), outstrlen);
|
||||
Q_strncatz(outstr, va("tcoords %g %g %g %g %g %i %g\n", ptype->s1, ptype->t1, ptype->s2, ptype->t2, 1.0f, ptype->randsmax, ptype->texsstride), outstrlen);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ extern sfx_t *cl_sfx_r_exp3;
|
|||
\
|
||||
globalfunction(event_sound, "CSQC_Event_Sound"); \
|
||||
globalfunction(serversound, "CSQC_ServerSound");/*obsolete, use event_sound*/ \
|
||||
globalfunction(loadresource, "CSQC_LoadResource");/*EXT_CSQC_1*/ \
|
||||
/*globalfunction(loadresource, "CSQC_LoadResource");*//*EXT_CSQC_1*/ \
|
||||
globalfunction(parse_tempentity, "CSQC_Parse_TempEntity");/*EXT_CSQC_ABSOLUTLY_VILE*/ \
|
||||
\
|
||||
globalfunction(mapentityedited, "CSQC_MapEntityEdited");\
|
||||
|
@ -3172,7 +3172,7 @@ static void QCBUILTIN PF_cs_sendevent (pubprogfuncs_t *prinst, struct globalvars
|
|||
else if (argtypes[i] == 'i')
|
||||
{
|
||||
MSG_WriteByte(&cls.netchan.message, ev_integer);
|
||||
MSG_WriteFloat(&cls.netchan.message, G_FLOAT(OFS_PARM2+i*3));
|
||||
MSG_WriteLong(&cls.netchan.message, G_INT(OFS_PARM2+i*3));
|
||||
}
|
||||
else if (argtypes[i] == 'v')
|
||||
{
|
||||
|
@ -8027,7 +8027,7 @@ void CSQC_MapEntityEdited(int modelindex, int idx, const char *newe)
|
|||
PR_ExecuteProgram (csqcprogs, csqcg.mapentityedited);
|
||||
}
|
||||
|
||||
qboolean CSQC_LoadResource(char *resname, char *restype)
|
||||
/*qboolean CSQC_LoadResource(char *resname, char *restype)
|
||||
{
|
||||
void *pr_globals;
|
||||
if (!csqcprogs || !csqcg.loadresource)
|
||||
|
@ -8040,7 +8040,7 @@ qboolean CSQC_LoadResource(char *resname, char *restype)
|
|||
PR_ExecuteProgram (csqcprogs, csqcg.loadresource);
|
||||
|
||||
return !!G_FLOAT(OFS_RETURN);
|
||||
}
|
||||
}*/
|
||||
|
||||
qboolean CSQC_Parse_Damage(int seat, float save, float take, vec3_t source)
|
||||
{
|
||||
|
|
|
@ -605,7 +605,7 @@ void QCBUILTIN PF_CL_drawsubpic (pubprogfuncs_t *prinst, struct globalvars_s *pr
|
|||
mpic_t *p;
|
||||
|
||||
p = R2D_SafeCachePic(picname);
|
||||
if (!p)
|
||||
if (!p || !R_GetShaderSizes(p, NULL, NULL, false))
|
||||
p = R2D_SafePicFromWad(picname);
|
||||
|
||||
r2d_be_flags = PF_SelectDPDrawFlag(flag);
|
||||
|
|
|
@ -105,6 +105,32 @@ qbyte GetPaletteIndex(int red, int green, int blue)
|
|||
return best;
|
||||
}
|
||||
}
|
||||
qbyte GetPaletteIndexNoFB(int red, int green, int blue)
|
||||
{
|
||||
//slow, horrible method.
|
||||
{
|
||||
int i, best=15;
|
||||
int bestdif=256*256*256, curdif;
|
||||
extern qbyte *host_basepal;
|
||||
qbyte *pa;
|
||||
|
||||
#define _abs(x) ((x)*(x))
|
||||
|
||||
pa = host_basepal;
|
||||
for (i = 0; i < 256 - vid.fullbright; i++, pa+=3)
|
||||
{
|
||||
curdif = _abs(red - pa[0]) + _abs(green - pa[1]) + _abs(blue - pa[2]);
|
||||
if (curdif < bestdif)
|
||||
{
|
||||
if (curdif<1)
|
||||
return i;
|
||||
bestdif = curdif;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
|
||||
void R2D_Shutdown(void)
|
||||
{
|
||||
|
|
|
@ -519,7 +519,7 @@ static void Surf_AddDynamicLightsColours (msurface_t *surf)
|
|||
local[1] -= surf->texturemins[1];
|
||||
|
||||
if (r_dynamic.ival == 2)
|
||||
r = g = b = 128;
|
||||
r = g = b = 256;
|
||||
else
|
||||
{
|
||||
r = cl_dlights[lnum].color[0]*128;
|
||||
|
|
|
@ -224,6 +224,12 @@ void V_StopPitchDrift (playerview_t *pv)
|
|||
pv->pitchvel = 0;
|
||||
}
|
||||
|
||||
void V_CenterView_f(void)
|
||||
{
|
||||
int pnum = CL_TargettedSplit(false);
|
||||
V_StartPitchDrift(&cl.playerview[pnum]);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
V_DriftPitch
|
||||
|
@ -2354,7 +2360,7 @@ void V_Init (void)
|
|||
Cmd_AddCommand ("bf", V_BonusFlash_f);
|
||||
Cmd_AddCommand ("df", V_DarkFlash_f);
|
||||
Cmd_AddCommand ("wf", V_WhiteFlash_f);
|
||||
// Cmd_AddCommand ("centerview", V_StartPitchDrift);
|
||||
Cmd_AddCommand ("centerview", V_CenterView_f);
|
||||
|
||||
Cvar_Register (&v_centermove, VIEWVARS);
|
||||
Cvar_Register (&v_centerspeed, VIEWVARS);
|
||||
|
|
|
@ -257,7 +257,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define MD5MODELS //doom3 models
|
||||
#define ZYMOTICMODELS //zymotic skeletal models.
|
||||
#define DPMMODELS //darkplaces model format (which I've never seen anyone use)
|
||||
#define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses)
|
||||
// #define PSKMODELS //PSK model format (ActorX stuff from UT, though not the format the game itself uses)
|
||||
#define HALFLIFEMODELS //halflife model support (experimental)
|
||||
#define INTERQUAKEMODELS
|
||||
#define RAGDOLL
|
||||
|
@ -299,6 +299,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define DECOMPRESS_ETC2 //decompress etc2(core in gles3/gl4.3) if the graphics driver doesn't support it (eg d3d or crappy gpus with vulkan).
|
||||
// #define DECOMPRESS_S3TC //allows bc1-3 to work even when drivers don't support it. This is probably only an issue on mobile chips. WARNING: not entirely sure if all patents expired yet...
|
||||
#define DECOMPRESS_RGTC //bc4+bc5
|
||||
//would be nice to have BPTC decompression too, for gl<4.2, d3d9, or d3d11_level10, but frankly its overcomplicated. I'm not going to bother with ASTC either.
|
||||
#ifndef RTLIGHTS
|
||||
#define RTLIGHTS //realtime lighting
|
||||
#endif
|
||||
|
|
|
@ -816,16 +816,33 @@ void R_LightArrays(const entity_t *entity, vecV_t *coords, avec4_t *colours, int
|
|||
{
|
||||
l = DotProduct(normals[i], entity->light_dir);
|
||||
#ifdef SSE_INTRINSICS
|
||||
vl = _mm_load1_ps(&l);
|
||||
vr = _mm_mul_ss(va,vl);
|
||||
vr = _mm_add_ss(vr,vs);
|
||||
if (l < 0)
|
||||
{
|
||||
_mm_storeu_ps(colours[i], va);
|
||||
//stomp on colour[i][3] (will be set to 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
vl = _mm_load1_ps(&l);
|
||||
vr = _mm_mul_ss(va,vl);
|
||||
vr = _mm_add_ss(vr,vs);
|
||||
|
||||
_mm_storeu_ps(colours[i], vr);
|
||||
//stomp on colour[i][3] (will be set to 1)
|
||||
_mm_storeu_ps(colours[i], vr);
|
||||
//stomp on colour[i][3] (will be set to 1)
|
||||
}
|
||||
#else
|
||||
colours[i][0] = l*lr[0]+la[0];
|
||||
colours[i][1] = l*lr[1]+la[1];
|
||||
colours[i][2] = l*lr[2]+la[2];
|
||||
if (l < 0)
|
||||
{ //don't over-shade the dark side of the mesh.
|
||||
colours[i][0] = la[0];
|
||||
colours[i][1] = la[1];
|
||||
colours[i][2] = la[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
colours[i][0] = l*lr[0]+la[0];
|
||||
colours[i][1] = l*lr[1]+la[1];
|
||||
colours[i][2] = l*lr[2]+la[2];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -5883,7 +5900,6 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
}
|
||||
|
||||
gmdl = ZG_Malloc(&mod->memgroup, sizeof(*gmdl)*num_matt);
|
||||
Mod_DefaultMesh(gmdl, mod->name, 0);
|
||||
|
||||
/*bones!*/
|
||||
bones = ZG_Malloc(&mod->memgroup, sizeof(galiasbone_t) * num_boneinfo);
|
||||
|
@ -6104,6 +6120,7 @@ qboolean QDECL Mod_LoadPSKModel(model_t *mod, void *buffer, size_t fsize)
|
|||
{
|
||||
#endif
|
||||
//common to all builds
|
||||
Mod_DefaultMesh(&gmdl[i], mod->name, i);
|
||||
|
||||
gmdl[i].ofsanimations = group;
|
||||
gmdl[i].numanimations = num_animinfo;
|
||||
|
|
|
@ -3041,7 +3041,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
|
|||
|
||||
/*quake requires a few settings for compatibility*/
|
||||
#define EZQUAKECOMPETITIVE "set ruleset_allow_fbmodels 1\n"
|
||||
#define QRPCOMPAT "cl_cursor_scale 0.2\ncl_cursor_bias_x 7.5\ncl_cursor_bias_y 0.8"
|
||||
#define QRPCOMPAT "set cl_cursor_scale 0.2\nset cl_cursor_bias_x 7.5\nset cl_cursor_bias_y 0.8"
|
||||
#define QCFG "set com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE QRPCOMPAT
|
||||
//nehahra has to be weird with extra cvars, and buggy fullbrights.
|
||||
#define NEHCFG QCFG "set nospr32 0\nset cutscene 1\nalias startmap_sp \"map nehstart\"\nr_fb_bmodels 0\nr_fb_models 0\n"
|
||||
|
|
|
@ -320,6 +320,14 @@ void Huff_EmitByte(int ch, qbyte *buffer, int *count);
|
|||
#define PROTOCOL_VERSION_BJP2 10001
|
||||
#define PROTOCOL_VERSION_BJP3 10002
|
||||
|
||||
#define MOD_PROQUAKE 1
|
||||
//#define MOD_PROQUAKE_VERSION (10*3.1) //password feature added
|
||||
//#define MOD_PROQUAKE_VERSION (10*3.2) //first 'cheatfree'
|
||||
#define MOD_PROQUAKE_VERSION (10*3.3) //no real changes, but w/e, this is the highest we can claim without having serverside issues.
|
||||
//#define MOD_PROQUAKE_VERSION (10*3.4) //added nat wait weirdness that's redundant and breaks the whole single-port thing by using two ports on the client too. *sigh*.
|
||||
//#define MOD_PROQUAKE_VERSION (10*3.5) //optional cheatfree encryption
|
||||
//#define MOD_PROQUAKE_VERSION (10*4.51) //current version
|
||||
|
||||
/*RMQ protocol flags*/
|
||||
#define RMQFL_SHORTANGLE (1 << 1)
|
||||
#define RMQFL_FLOATANGLE (1 << 2)
|
||||
|
|
|
@ -1010,6 +1010,63 @@ static shader_t *GL_ChooseSkin(galiasinfo_t *inf, model_t *model, int surfnum, e
|
|||
cm->texnum.specular = shader->defaulttextures->specular;
|
||||
cm->texnum.reflectcube = shader->defaulttextures->reflectcube;
|
||||
cm->texnum.reflectmask = shader->defaulttextures->reflectmask;
|
||||
cm->texnum.paletted = shader->defaulttextures->paletted;
|
||||
|
||||
#ifdef HEXEN2 //too lazy to do this
|
||||
if (h2playertranslations && pc)
|
||||
;
|
||||
else
|
||||
#endif
|
||||
if (r_softwarebanding)
|
||||
{
|
||||
qbyte *pixels8 = (void*)pixels;
|
||||
qbyte *out8;
|
||||
for (i=0 ; i<256 ; i++)
|
||||
translate32[i] = i;
|
||||
|
||||
//fancy colours are not supported here. try to aproximate them.
|
||||
if (tc >= 16)
|
||||
tc = GetPaletteIndexNoFB((tc>>16)&0xff, (tc>>8)&0xff, (tc>>0)&0xff)/16;
|
||||
if (bc >= 16)
|
||||
bc = GetPaletteIndexNoFB((bc>>16)&0xff, (bc>>8)&0xff, (bc>>0)&0xff)/16;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (tc < 8)
|
||||
translate32[TOP_RANGE+i] = (tc<<4)+i;
|
||||
else
|
||||
translate32[TOP_RANGE+i] = (tc<<4)+15-i;
|
||||
|
||||
if (bc < 8)
|
||||
translate32[BOTTOM_RANGE+i] = (bc<<4)+i;
|
||||
else
|
||||
translate32[BOTTOM_RANGE+i] = (bc<<4)+15-i;
|
||||
}
|
||||
|
||||
fracstep = tinwidth*0x10000/scaled_width;
|
||||
for (i=0, out8=pixels8 ; i<scaled_height ; i++, out8 += scaled_width)
|
||||
{
|
||||
inrow = original + inwidth*(i*inheight/scaled_height);
|
||||
frac = fracstep >> 1;
|
||||
for (j=0 ; j<scaled_width ; j+=4)
|
||||
{
|
||||
out8[j] = translate32[inrow[frac>>16]];
|
||||
frac += fracstep;
|
||||
out8[j+1] = translate32[inrow[frac>>16]];
|
||||
frac += fracstep;
|
||||
out8[j+2] = translate32[inrow[frac>>16]];
|
||||
frac += fracstep;
|
||||
out8[j+3] = translate32[inrow[frac>>16]];
|
||||
frac += fracstep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cm->texnum.paletted = R_LoadTexture(va("paletted$%x$%x$%i$%i$%i$%s", tc, bc, cm->skinnum, subframe, pc, cm->name),
|
||||
scaled_width, scaled_height, TF_LUM8, pixels8, IF_NEAREST|IF_NOMIPMAP);
|
||||
|
||||
}
|
||||
|
||||
/*if (!h2playertranslations)
|
||||
{
|
||||
qboolean valid = false;
|
||||
|
@ -1313,118 +1370,187 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
lightdir[2] = 1;
|
||||
}
|
||||
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
org = r_refdef.vieworg;
|
||||
|
||||
//don't do world lights, although that might be funny
|
||||
for (i=rtlights_first; i<RTL_FIRST; i++)
|
||||
{
|
||||
if (cl_dlights[i].radius)
|
||||
{
|
||||
VectorSubtract (org,
|
||||
cl_dlights[i].origin,
|
||||
dist);
|
||||
add = cl_dlights[i].radius - Length(dist);
|
||||
|
||||
#ifdef RTLIGHTS
|
||||
//if world lighting is on, there may be no lightmap influence even if r_dynamic is on.
|
||||
if (r_shadow_realtime_world.ival)
|
||||
add *= r_shadow_realtime_world_lightmaps.value;
|
||||
#endif
|
||||
|
||||
if (add > 0)
|
||||
{
|
||||
ambientlight[0] += add * cl_dlights[i].color[0];
|
||||
ambientlight[1] += add * cl_dlights[i].color[1];
|
||||
ambientlight[2] += add * cl_dlights[i].color[2];
|
||||
//ZOID models should be affected by dlights as well
|
||||
shadelight[0] += add * cl_dlights[i].color[0];
|
||||
shadelight[1] += add * cl_dlights[i].color[1];
|
||||
shadelight[2] += add * cl_dlights[i].color[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]);
|
||||
if (m > 255)
|
||||
{
|
||||
ambientlight[0] *= 255.0/m;
|
||||
ambientlight[1] *= 255.0/m;
|
||||
ambientlight[2] *= 255.0/m;
|
||||
}
|
||||
m = max(max(shadelight[0], shadelight[1]), shadelight[2]);
|
||||
if (m > 128)
|
||||
{
|
||||
shadelight[0] *= 128.0/m;
|
||||
shadelight[1] *= 128.0/m;
|
||||
shadelight[2] *= 128.0/m;
|
||||
}
|
||||
|
||||
//MORE HUGE HACKS! WHEN WILL THEY CEASE!
|
||||
// clamp lighting so it doesn't overbright as much
|
||||
// ZOID: never allow players to go totally black
|
||||
if (clmodel->engineflags & MDLF_PLAYER)
|
||||
{
|
||||
float fb = r_fullbrightSkins.value;
|
||||
if (fb > cls.allow_fbskins)
|
||||
fb = cls.allow_fbskins;
|
||||
if (fb < 0)
|
||||
fb = 0;
|
||||
if (fb)
|
||||
{
|
||||
extern cvar_t r_fb_models;
|
||||
|
||||
if (fb >= 1 && r_fb_models.value)
|
||||
{
|
||||
ambientlight[0] = ambientlight[1] = ambientlight[2] = 1;
|
||||
shadelight[0] = shadelight[1] = shadelight[2] = 1;
|
||||
|
||||
e->light_known = 2;
|
||||
return e->light_known-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
ambientlight[i] = max(ambientlight[i], 8 + fb * 120);
|
||||
shadelight[i] = max(shadelight[i], 8 + fb * 120);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ambientlight[i] < 8)
|
||||
ambientlight[i] = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ambientlight[i] > 128)
|
||||
ambientlight[i] = 128;
|
||||
|
||||
shadelight[i] /= 200.0/255;
|
||||
ambientlight[i] /= 200.0/255;
|
||||
}
|
||||
|
||||
if ((e->model->flags & MF_ROTATE) && cl.hexen2pickups)
|
||||
{
|
||||
shadelight[0] = shadelight[1] = shadelight[2] =
|
||||
ambientlight[0] = ambientlight[1] = ambientlight[2] = 128+sin(cl.servertime*4)*64;
|
||||
}
|
||||
#ifdef HEXEN2
|
||||
if ((e->drawflags & MLS_MASK) == MLS_ABSLIGHT)
|
||||
{
|
||||
shadelight[0] = shadelight[1] = shadelight[2] = e->abslight;
|
||||
ambientlight[0] = ambientlight[1] = ambientlight[2] = e->abslight;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
if (r_softwarebanding)
|
||||
{
|
||||
//mimic software rendering as closely as possible
|
||||
lightdir[2] = 0; //horizontal light only.
|
||||
|
||||
VectorMA(vec3_origin, 0.5, shadelight, ambientlight);
|
||||
VectorCopy(ambientlight, shadelight);
|
||||
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
org = r_refdef.vieworg;
|
||||
//don't do world lights, although that might be funny
|
||||
for (i=rtlights_first; i<RTL_FIRST; i++)
|
||||
{
|
||||
if (cl_dlights[i].radius)
|
||||
{
|
||||
VectorSubtract (org,
|
||||
cl_dlights[i].origin,
|
||||
dist);
|
||||
add = cl_dlights[i].radius - Length(dist);
|
||||
#ifdef RTLIGHTS
|
||||
if (r_shadow_realtime_world.ival) //if world lighting is on, there may be no lightmap influence even if r_dynamic is on.
|
||||
add *= r_shadow_realtime_world_lightmaps.value;
|
||||
#endif
|
||||
if (add > 0)
|
||||
{
|
||||
if (r_dynamic.ival == 2)
|
||||
{
|
||||
ambientlight[0] += add * 2;
|
||||
ambientlight[1] += add * 2;
|
||||
ambientlight[2] += add * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ambientlight[0] += add * cl_dlights[i].color[0];
|
||||
ambientlight[1] += add * cl_dlights[i].color[1];
|
||||
ambientlight[2] += add * cl_dlights[i].color[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ambientlight[i] > 128)
|
||||
ambientlight[i] = 128;
|
||||
if (ambientlight[i] + shadelight[i] > 192)
|
||||
shadelight[i] = 192 - ambientlight[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!r_vertexdlights.ival && r_dynamic.ival > 0)
|
||||
{
|
||||
float *org = e->origin;
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
org = r_refdef.vieworg;
|
||||
|
||||
//don't do world lights, although that might be funny
|
||||
for (i=rtlights_first; i<RTL_FIRST; i++)
|
||||
{
|
||||
if (cl_dlights[i].radius)
|
||||
{
|
||||
VectorSubtract (org,
|
||||
cl_dlights[i].origin,
|
||||
dist);
|
||||
add = cl_dlights[i].radius - Length(dist);
|
||||
#ifdef RTLIGHTS
|
||||
if (r_shadow_realtime_world.ival) //if world lighting is on, there may be no lightmap influence even if r_dynamic is on.
|
||||
add *= r_shadow_realtime_world_lightmaps.value;
|
||||
#endif
|
||||
|
||||
if (add > 0)
|
||||
{
|
||||
if (r_dynamic.ival == 2)
|
||||
{
|
||||
ambientlight[0] += add * 2;
|
||||
ambientlight[1] += add * 2;
|
||||
ambientlight[2] += add * 2;
|
||||
//ZOID models should be affected by dlights as well
|
||||
shadelight[0] += add * 2;
|
||||
shadelight[1] += add * 2;
|
||||
shadelight[2] += add * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ambientlight[0] += add * cl_dlights[i].color[0];
|
||||
ambientlight[1] += add * cl_dlights[i].color[1];
|
||||
ambientlight[2] += add * cl_dlights[i].color[2];
|
||||
//ZOID models should be affected by dlights as well
|
||||
shadelight[0] += add * cl_dlights[i].color[0];
|
||||
shadelight[1] += add * cl_dlights[i].color[1];
|
||||
shadelight[2] += add * cl_dlights[i].color[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m = max(max(ambientlight[0], ambientlight[1]), ambientlight[2]);
|
||||
if (m > 255)
|
||||
{
|
||||
ambientlight[0] *= 255.0/m;
|
||||
ambientlight[1] *= 255.0/m;
|
||||
ambientlight[2] *= 255.0/m;
|
||||
}
|
||||
m = max(max(shadelight[0], shadelight[1]), shadelight[2]);
|
||||
if (m > 128)
|
||||
{
|
||||
shadelight[0] *= 128.0/m;
|
||||
shadelight[1] *= 128.0/m;
|
||||
shadelight[2] *= 128.0/m;
|
||||
}
|
||||
|
||||
//MORE HUGE HACKS! WHEN WILL THEY CEASE!
|
||||
// clamp lighting so it doesn't overbright as much
|
||||
// ZOID: never allow players to go totally black
|
||||
if (clmodel->engineflags & MDLF_PLAYER)
|
||||
{
|
||||
float fb = r_fullbrightSkins.value;
|
||||
if (fb > cls.allow_fbskins)
|
||||
fb = cls.allow_fbskins;
|
||||
if (fb < 0)
|
||||
fb = 0;
|
||||
if (fb)
|
||||
{
|
||||
extern cvar_t r_fb_models;
|
||||
|
||||
if (fb >= 1 && r_fb_models.value)
|
||||
{
|
||||
ambientlight[0] = ambientlight[1] = ambientlight[2] = 1;
|
||||
shadelight[0] = shadelight[1] = shadelight[2] = 1;
|
||||
|
||||
e->light_known = 2;
|
||||
return e->light_known-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
ambientlight[i] = max(ambientlight[i], 8 + fb * 120);
|
||||
shadelight[i] = max(shadelight[i], 8 + fb * 120);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ambientlight[i] < 8)
|
||||
ambientlight[i] = 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ambientlight[i] > 128)
|
||||
ambientlight[i] = 128;
|
||||
|
||||
shadelight[i] /= 200.0/255;
|
||||
ambientlight[i] /= 200.0/255;
|
||||
}
|
||||
|
||||
if ((e->model->flags & MF_ROTATE) && cl.hexen2pickups)
|
||||
{
|
||||
shadelight[0] = shadelight[1] = shadelight[2] =
|
||||
ambientlight[0] = ambientlight[1] = ambientlight[2] = 128+sin(cl.servertime*4)*64;
|
||||
}
|
||||
}
|
||||
|
||||
if (e->flags & RF_WEAPONMODEL)
|
||||
{
|
||||
vec3_t temp;
|
||||
|
@ -1458,8 +1584,16 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
|
|||
VectorScale(shadelight, scale, shadelight);
|
||||
}
|
||||
|
||||
VectorMA(ambientlight, 0.5, shadelight, e->light_avg);
|
||||
VectorSubtract(shadelight, ambientlight, e->light_range);
|
||||
if (r_softwarebanding)
|
||||
{ //overbright the models.
|
||||
VectorScale(ambientlight, 2, e->light_avg);
|
||||
VectorScale(shadelight, 2, e->light_range);
|
||||
}
|
||||
else
|
||||
{ //calculate average and range, to allow for negative lighting dotproducts
|
||||
VectorMA(ambientlight, 0.5, shadelight, e->light_avg);
|
||||
VectorSubtract(shadelight, ambientlight, e->light_range);
|
||||
}
|
||||
|
||||
e->light_known = 1;
|
||||
return e->light_known-1;
|
||||
|
|
|
@ -2583,7 +2583,7 @@ static void GenerateColourMods(const shaderpass_t *pass)
|
|||
shaderstate.pendingcolourpointer = NULL;
|
||||
return;
|
||||
}
|
||||
if (r_nolightdir.ival)
|
||||
if (r_nolightdir.ival || (!shaderstate.curentity->light_range[0] && !shaderstate.curentity->light_range[1] && !shaderstate.curentity->light_range[2]))
|
||||
{
|
||||
VectorCopy(shaderstate.curentity->light_avg, shaderstate.pendingcolourflat);
|
||||
shaderstate.pendingcolourflat[3] = shaderstate.curentity->shaderRGBAf[3];
|
||||
|
|
|
@ -1860,7 +1860,7 @@ void GLQ1BSP_LightPointValues(model_t *model, vec3_t point, vec3_t res_diffuse,
|
|||
res_dir[1] = r[4];
|
||||
res_dir[2] = -r[5];
|
||||
if (!res_dir[0] && !res_dir[1] && !res_dir[2])
|
||||
res_dir[1] = res_dir[2] = 1;
|
||||
res_dir[0] = res_dir[2] = 1;
|
||||
VectorNormalize(res_dir);
|
||||
}
|
||||
|
||||
|
|
|
@ -2773,8 +2773,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl)
|
|||
#ifdef USE_EGL
|
||||
case PSL_EGL:
|
||||
visinfo = &vinfodef;
|
||||
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp, TrueColor, visinfo))
|
||||
// if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, DefaultDepth(vid_dpy, scrnum), TrueColor, &visinfo))
|
||||
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp?info->bpp:DefaultDepth(vid_dpy, scrnum), TrueColor, visinfo))
|
||||
{
|
||||
Sys_Error("Couldn't choose visual for EGL\n");
|
||||
}
|
||||
|
@ -2791,8 +2790,7 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl)
|
|||
#ifdef VKQUAKE
|
||||
case PSL_VULKAN:
|
||||
visinfo = &vinfodef;
|
||||
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp, TrueColor, visinfo))
|
||||
// if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, DefaultDepth(vid_dpy, scrnum), TrueColor, &visinfo))
|
||||
if (!x11.pXMatchVisualInfo(vid_dpy, scrnum, info->bpp?info->bpp:DefaultDepth(vid_dpy, scrnum), TrueColor, visinfo))
|
||||
{
|
||||
Sys_Error("Couldn't choose visual for vulkan\n");
|
||||
}
|
||||
|
|
|
@ -970,7 +970,6 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info)
|
|||
int i;
|
||||
HDC hdc;
|
||||
int wwidth, wheight, pleft, ptop, pwidth, pheight;
|
||||
RECT rect;
|
||||
|
||||
modestate = MS_WINDOWED;
|
||||
|
||||
|
@ -1034,7 +1033,7 @@ static qboolean VID_SetWindowedMode (rendererstate_t *info)
|
|||
|
||||
WindowRect = centerrect(pleft, ptop, pwidth, pheight, wwidth, wheight);
|
||||
if (!sys_parentwindow)
|
||||
AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0);
|
||||
AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
|
||||
|
||||
// Create the DIB window
|
||||
if (WinNT)
|
||||
|
|
|
@ -1090,6 +1090,7 @@ qboolean GL_Init(rendererstate_t *info, void *(*getglfunction) (char *name));
|
|||
#endif
|
||||
|
||||
qbyte GetPaletteIndex(int red, int green, int blue);
|
||||
qbyte GetPaletteIndexNoFB(int red, int green, int blue);
|
||||
int Mod_ReadFlagsFromMD1(char *name, int md3version);
|
||||
|
||||
/*
|
||||
|
|
|
@ -2829,7 +2829,9 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
"float d = dot(n,e_light_dir);\n"
|
||||
"if (d < 0.0) //vertex shader. this might get ugly, but I don't really want to make it per vertex.\n"
|
||||
"d = 0.0; //this avoids the dark side going below the ambient level.\n"
|
||||
"light = e_light_ambient + (dot(n,e_light_dir)*e_light_mul);\n"
|
||||
"light = e_light_ambient + (d*e_light_mul);\n"
|
||||
|
||||
//FIXME: Software rendering imitation should possibly push out normals by half a pixel or something to approximate software's over-estimation of distant model sizes (small models are drawn using JUST their verticies using the nearest pixel, which results in larger meshes)
|
||||
|
||||
"#ifdef TESS\n"
|
||||
"normal = n;\n"
|
||||
|
@ -2993,7 +2995,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
//FIXME: with this extra flag, half the permutations are redundant.
|
||||
"lightlev *= 0.5; //counter the fact that the colourmap contains overbright values and logically ranges from 0 to 2 intead of to 1.\n"
|
||||
"float pal = texture2D(s_paletted, tc).r; //the palette index. hopefully not interpolated.\n"
|
||||
"lightlev -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest\n"
|
||||
// lightlev -= 1.0 / 128.0; //software rendering appears to round down, so make sure we favour the lower values instead of rounding to the nearest
|
||||
"col.r = texture2D(s_colourmap, vec2(pal, 1.0-lightlev.r)).r; //do 3 lookups. this is to cope with lit files, would be a waste to not support those.\n"
|
||||
"col.g = texture2D(s_colourmap, vec2(pal, 1.0-lightlev.g)).g; //its not very softwarey, but re-palettizing is ugly.\n"
|
||||
"col.b = texture2D(s_colourmap, vec2(pal, 1.0-lightlev.b)).b; //without lits, it should be identical.\n"
|
||||
|
@ -10684,7 +10686,7 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
|
|||
|
||||
"#include \"sys/fog.h\"\n"
|
||||
|
||||
//FIXME: too lazy to implement this right now.
|
||||
//FIXME: too lazy to implement this right now. rtlights on d3d9 are just bad right now.
|
||||
"#undef RTLIGHT\n"
|
||||
"#undef PCF\n"
|
||||
"#undef CUBE\n"
|
||||
|
|
|
@ -1853,8 +1853,8 @@ void SV_AcceptMessage(client_t *newcl)
|
|||
MSG_WriteLong(&sb, ShortSwap(localaddr.port));
|
||||
if (newcl->proquake_angles_hack)
|
||||
{
|
||||
MSG_WriteByte(&sb, 1/*MOD_PROQUAKE*/);
|
||||
MSG_WriteByte(&sb, 10 * 3.50/*MOD_PROQUAKE_VERSION*/);
|
||||
MSG_WriteByte(&sb, MOD_PROQUAKE);
|
||||
MSG_WriteByte(&sb, MOD_PROQUAKE_VERSION);
|
||||
MSG_WriteByte(&sb, 0/*flags*/);
|
||||
}
|
||||
*(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize);
|
||||
|
@ -3861,7 +3861,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
|
|||
MSG_WriteLong(&sb, BigLong(1)); //sequence 1, because 0 matches the old sequence, and thus might get dropped. hopefully the client will cope with dupes properly and ignore any regular (but unreliable) stuff.
|
||||
|
||||
MSG_WriteByte(&sb, svc_stufftext);
|
||||
MSG_WriteString(&sb, va("cmd challengeconnect %i %i\n", SV_NewChallenge(), 1/*MOD_PROQUAKE*/));
|
||||
MSG_WriteString(&sb, va("cmd challengeconnect %i %i\n", SV_NewChallenge(), MOD_PROQUAKE));
|
||||
|
||||
*(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize);
|
||||
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from);
|
||||
|
@ -3949,8 +3949,8 @@ qboolean SVNQ_ConnectionlessPacket(void)
|
|||
MSG_WriteByte(&sb, CCREP_ACCEPT);
|
||||
NET_LocalAddressForRemote(svs.sockets, &net_from, &localaddr, 0);
|
||||
MSG_WriteLong(&sb, ShortSwap(localaddr.port));
|
||||
MSG_WriteByte(&sb, 1/*MOD_PROQUAKE*/);
|
||||
MSG_WriteByte(&sb, 10 * 3.50/*MOD_PROQUAKE_VERSION*/);
|
||||
MSG_WriteByte(&sb, MOD_PROQUAKE);
|
||||
MSG_WriteByte(&sb, MOD_PROQUAKE_VERSION);
|
||||
*(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize);
|
||||
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from);
|
||||
|
||||
|
|
|
@ -8776,7 +8776,7 @@ void SV_ClientThink (void)
|
|||
//
|
||||
// if dead, behave differently
|
||||
//
|
||||
if (sv_player->v->health <= 0)
|
||||
if (sv_player->v->health <= 0 && !host_client->spectator)
|
||||
return;
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue