#include "csqcmodel_hooks.qh"
-#include "autocvars.qh"
-#include "csqcmodel_hooks.qh"
-#include "miscfunctions.qh"
+
#include <client/mutators/_mod.qh>
-#include "player_skeleton.qh"
-#include "weapons/projectile.qh"
+#include <client/player_skeleton.qh>
+#include <client/weapons/projectile.qh>
#include <common/animdecide.qh>
+#include <common/effects/all.inc>
+#include <common/effects/all.qh>
#include <common/ent_cs.qh>
+#include <common/gamemodes/_mod.qh>
+#include <common/mapinfo.qh>
#include <common/physics/movetypes/movetypes.qh>
+#include <common/physics/player.qh>
#include <common/viewloc.qh>
-#include <common/effects/all.qh>
-#include <common/effects/all.inc>
#include <lib/csqcmodel/cl_model.qh>
#include <lib/csqcmodel/cl_player.qh>
#include <lib/csqcmodel/interpolate.qh>
int forceplayermodels_goodmodelindex;
.vector glowmod;
-.vector old_glowmod;
void CSQCPlayer_ModelAppearance_PreUpdate(entity this)
{
}
void CSQCPlayer_ModelAppearance_Apply(entity this, bool islocalplayer)
{
+ int cm = this.forceplayermodels_savecolormap;
+ cm = (cm >= 1024) ? cm : (entcs_GetClientColors(cm - 1) + 1024);
+
if(MUTATOR_CALLHOOK(ForcePlayermodels_Skip, this, islocalplayer))
goto skipforcemodels;
// apply it
bool isfriend;
- int cm;
- cm = this.forceplayermodels_savecolormap;
- cm = (cm >= 1024) ? cm : (entcs_GetClientColors(cm - 1) + 1024);
if(teamplay)
isfriend = (cm == 1024 + 17 * myteam);
this.skin = this.forceplayermodels_saveskin;
}
+ LABEL(skipforcemodels)
+
+ if(MUTATOR_CALLHOOK(ForcePlayercolors_Skip, this, islocalplayer))
+ goto skipforcecolors;
+
+ bool forceplayercolors_enabled = false;
+ #define fpc autocvar_cl_forceplayercolors
+ if (gametype.m_1v1)
+ {
+ if ((myteam != NUM_SPECTATOR) && (fpc == 1 || fpc == 2 || fpc == 3 || fpc == 5))
+ forceplayercolors_enabled = true;
+ }
+ else if (teamplay)
+ {
+ if ((team_count == 2) && (myteam != NUM_SPECTATOR) && (fpc == 2 || fpc == 4 || fpc == 5))
+ forceplayercolors_enabled = true;
+ }
+ else
+ {
+ if (fpc == 1 || fpc == 2)
+ forceplayercolors_enabled = true;
+ }
+
// forceplayercolors too
if(teamplay)
{
// own team's color is never forced
- int forcecolor_friend = 0;
- int forcecolor_enemy = 0;
+ int forcecolor_friend = 0, forcecolor_enemy = 0;
entity tm;
if(autocvar_cl_forcemyplayercolors)
forcecolor_friend = 1024 + autocvar_cl_forcemyplayercolors;
- if(autocvar_cl_forceplayercolors == 2 && team_count == 2)
+
+ if(forceplayercolors_enabled)
forcecolor_enemy = 1024 + autocvar__cl_color;
if(forcecolor_enemy && !forcecolor_friend)
this.colormap = forcecolor_enemy;
}
}
- else
+ else // if(!teamplay)
{
if(autocvar_cl_forcemyplayercolors && islocalplayer)
this.colormap = 1024 + autocvar_cl_forcemyplayercolors;
- else if(autocvar_cl_forceplayercolors)
+ else if (autocvar_cl_forceuniqueplayercolors && !islocalplayer && !gametype.m_1v1)
+ {
+ // Assign each enemy unique colors
+ // pick colors from 0 to 14 since 15 is the rainbow color
+ // pl01 0 1, pl02 1 2, ..., pl14 13 14, pl15 14 0
+ // pl16 0 2, pl17 1 3, ..., pl29 13 0, pl30 14 1
+ int num = this.entnum - 1;
+ int c1 = num % 15;
+ int q = floor(num / 15);
+ int c2 = (c1 + 1 + q) % 15;
+ this.colormap = 1024 + (c1 << 4) + c2;
+ }
+ else if(forceplayercolors_enabled)
this.colormap = player_localnum + 1;
}
- LABEL(skipforcemodels)
+ LABEL(skipforcecolors)
+
+ if((this.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST) && !autocvar_cl_respawn_ghosts_keepcolors)
+ {
+ this.glowmod = '0 0 0';
+ this.colormap = 0;
+ return;
+ }
// GLOWMOD AND DEATH FADING
if(this.colormap > 0)
{
if(this.csqcmodel_isdead)
{
- // Fade out to black now...
- if(this.old_glowmod == '0 0 0') { this.old_glowmod = this.glowmod; }
- this.colormap = 0;
-
- this.glowmod = this.old_glowmod * bound(0, 1 - (time - this.death_time) / autocvar_cl_deathglow, 1);
- this.glowmod_x = max(this.glowmod.x, 0.0001);
- this.glowmod_y = max(this.glowmod.y, 0.0001);
- this.glowmod_z = max(this.glowmod.z, 0.0001);
+ float min_factor = bound(0, autocvar_cl_deathglow_min, 1);
+ if(this.colormap > 0)
+ min_factor /= 2;
+ float glow_fade = bound(0, 1 - (time - this.death_time) / autocvar_cl_deathglow, 1);
+ this.glowmod *= (min_factor + glow_fade * (1 - min_factor));
+ if (this.glowmod == '0 0 0')
+ this.glowmod.x = 0.000001;
}
- else if(this.old_glowmod != '0 0 0') { this.old_glowmod = '0 0 0'; }
}
//printf("CSQCPlayer_ModelAppearance_Apply(): state = %s, colormap = %f, glowmod = %s\n", (this.csqcmodel_isdead ? "DEAD" : "ALIVE"), this.colormap, vtos(this.glowmod));
}
// recursive predraw call to fix issues with forcemodels and LOD if bone indexes mismatch
- if(this.tag_entity.classname == "csqcmodel")
+ if(this.tag_entity.classname == "ENT_CLIENT_MODEL")
{
CSQCModel_Hook_PreDraw(this.tag_entity, (this.tag_entity.isplayermodel & ISPLAYER_CLIENT));
}
if(eff & EF_FULLBRIGHT)
this.renderflags |= RF_FULLBRIGHT;
if(eff & EF_FLAME)
- pointparticles(EFFECT_EF_FLAME, this.origin, '0 0 0', bound(0, frametime, 0.1));
+ {
+ boxparticles(particleeffectnum(EFFECT_EF_FLAME), this, this.absmin, this.absmax, this.velocity, this.velocity, bound(0, frametime, 0.1), 0);
+ //pointparticles(EFFECT_EF_FLAME, this.origin, '0 0 0', bound(0, frametime, 0.1));
+ }
if(eff & EF_STARDUST)
- pointparticles(EFFECT_EF_STARDUST, this.origin, '0 0 0', bound(0, frametime, 0.1));
+ {
+ boxparticles(particleeffectnum(EFFECT_EF_STARDUST), this, this.absmin, this.absmax, this.velocity, this.velocity, bound(0, frametime, 0.1), 0);
+ //pointparticles(EFFECT_EF_STARDUST, this.origin, '0 0 0', bound(0, frametime, 0.1));
+ }
if(eff & EF_NOSHADOW)
this.renderflags |= RF_NOSHADOW;
if(eff & EF_NODEPTHTEST)
tref = EFFECT_TR_BLOOD.m_id;
if(this.csqcmodel_modelflags & MF_ROTATE)
{
+ // This will be hard to replace with MAKE_VECTORS because it's called as part of the predraw function
+ // as documented in csprogs.h in the engine. The globals can then be read in many places in the engine.
+ // However MF_ROTATE is currently only used in one place - might be possible to get rid of it entirely.
this.renderflags |= RF_USEAXIS;
- MAKEVECTORS(makevectors, this.angles + '0 100 0' * fmod(time, 3.6), v_forward, v_right, v_up);
+ makevectors(this.angles + '0 100 0' * fmod(time, 3.6));
}
if(this.csqcmodel_modelflags & MF_TRACER)
tref = EFFECT_TR_WIZSPIKE.m_id;
return;
this.csqcmodel_predraw_run = framecount;
- if(!this.modelindex || this.model == "null" || this.alpha < 0)
+ if(!this.modelindex || this.model == "null")
{
this.drawmask = 0;
if(this.snd_looping > 0)
tracebox(this.origin + '0 0 1', this.mins, this.maxs, this.origin - '0 0 4', MOVE_NORMAL, this);
if(trace_startsolid || trace_fraction < 1)
onground = 1;
+ // predicted clients handle smoothing in the prediction code
+ this.origin = CSQCModel_ApplyStairSmoothing(this, onground, this.origin);
}
animdecide_load_if_needed(this);
animdecide_setimplicitstate(this, onground);
bool is_playermodel = (substring(this.model, 0, 14) == "models/player/" || substring(this.model, 0, 17) == "models/ok_player/" ||
(substring(this.model, 0, 16) == "models/monsters/" && (this.isplayermodel & BIT(1))));
this.isplayermodel = BITSET(this.isplayermodel, ISPLAYER_MODEL, is_playermodel);
+ this.csqcmodel_isdead = false; // workaround for dead players who become a spectator
// save values set by server
if((this.isplayermodel & ISPLAYER_MODEL))