]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/csqcmodel_hooks.qc
Merge branch 'master' into Mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / csqcmodel_hooks.qc
index 035ba2a1647c29a2445ca54d73022670536cfed3..87e577c9cea454869acfc3b34ea9ab65110014b6 100644 (file)
 .float death_time;
 .int modelflags;
 
-.bool isplayermodel;
-
 // FEATURE: LOD
 .int lodmodelindex0;
 .int lodmodelindex1;
 .int lodmodelindex2;
-void CSQCPlayer_LOD_Apply(entity this)
+void CSQCPlayer_LOD_Apply(entity this, bool isplayer)
 {
+       int detailreduction = ((isplayer) ? autocvar_cl_playerdetailreduction : autocvar_cl_modeldetailreduction);
+
        // LOD model loading
        if(this.lodmodelindex0 != this.modelindex)
        {
@@ -64,19 +64,19 @@ void CSQCPlayer_LOD_Apply(entity this)
        }
 
        // apply LOD
-       if(autocvar_cl_playerdetailreduction <= 0)
+       if(detailreduction <= 0)
        {
-               if(autocvar_cl_playerdetailreduction <= -2)
+               if(detailreduction <= -2)
                        this.modelindex = this.lodmodelindex2;
-               else if(autocvar_cl_playerdetailreduction <= -1)
+               else if(detailreduction <= -1)
                        this.modelindex = this.lodmodelindex1;
                else
                        this.modelindex = this.lodmodelindex0;
        }
        else
        {
-               float distance = vlen(this.origin - view_origin);
-               float f = (distance * current_viewzoom + 100.0) * autocvar_cl_playerdetailreduction;
+               float distance = vlen(((isplayer) ? this.origin : NearestPointOnBox(this, view_origin)) - view_origin); // TODO: perhaps it should just use NearestPointOnBox all the time, player hitbox can potentially be huge
+               float f = (distance * current_viewzoom + 100.0) * detailreduction;
                f *= 1.0 / bound(0.01, view_quality, 1);
                if(f > autocvar_cl_loddistance2)
                        this.modelindex = this.lodmodelindex2;
@@ -343,10 +343,10 @@ void CSQCPlayer_FallbackFrame_PostUpdate(entity this, bool isnew)
        // player "pops in"
        if(isnew)
        {
-#define FIX_FRAMETIME(f,ft) MACRO_BEGIN {                                                                                                                                                      \
-               if(IS_DEAD_FRAME(this.f) && this.ft != 0 && this.death_time != 0)                                                                                       \
-                       this.ft = this.death_time;                                                                                                                                                              \
-MACRO_END
+#define FIX_FRAMETIME(f,ft) MACRO_BEGIN \
+               if(IS_DEAD_FRAME(this.f) && this.ft != 0 && this.death_time != 0) \
+                       this.ft = this.death_time; \
+MACRO_END
                FIX_FRAMETIME(frame, frame1time);
                FIX_FRAMETIME(frame2, frame2time);
 #ifdef CSQCMODEL_HAVE_TWO_FRAMES
@@ -415,7 +415,7 @@ void CSQCModel_AutoTagIndex_Apply(entity this)
                // recursive predraw call to fix issues with forcemodels and LOD if bone indexes mismatch
                if(this.tag_entity.classname == "csqcmodel")
                {
-                       CSQCModel_Hook_PreDraw(this.tag_entity, (this.tag_entity.entnum >= 1 && this.tag_entity.entnum <= maxclients));
+                       CSQCModel_Hook_PreDraw(this.tag_entity, (this.tag_entity.isplayermodel & ISPLAYER_CLIENT));
                }
 
                if(this.tag_entity.modelindex != this.tag_entity_lastmodelindex)
@@ -443,7 +443,7 @@ void CSQCModel_AutoTagIndex_Apply(entity this)
                                                        LOG_TRACE("h_ model lacks weapon attachment, but v_ model is attached to it");
                                                }
                                        }
-                                       else if(this.tag_entity.isplayermodel)
+                                       else if((this.tag_entity.isplayermodel & ISPLAYER_MODEL))
                                        {
                                                skeleton_loadinfo(this.tag_entity);
                                                this.tag_index = this.tag_entity.bone_weapon;
@@ -542,6 +542,9 @@ void CSQCModel_Effects_Apply(entity this)
                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(this.angles + '0 100 0' * fmod(time, 3.6));
        }
@@ -600,18 +603,23 @@ void CSQCModel_Hook_PreDraw(entity this, bool isplayer)
                return;
        this.csqcmodel_predraw_run = framecount;
 
-       if(!this.modelindex || this.model == "null")
+       if(!this.modelindex || this.model == "null" || this.alpha < 0)
        {
                this.drawmask = 0;
+               if(this.snd_looping > 0)
+               {
+                       sound(this, this.snd_looping, SND_Null, VOL_BASE, autocvar_cl_jetpack_attenuation);
+                       this.snd_looping = 0;
+               }
                return;
        }
        else
                this.drawmask = MASK_NORMAL;
 
-       if(this.isplayermodel) // this checks if it's a player MODEL!
+       if((this.isplayermodel & ISPLAYER_MODEL) && this.drawmask) // this checks if it's a player MODEL!
        {
-               CSQCPlayer_ModelAppearance_Apply(this, this.entnum == player_localnum + 1);
-               CSQCPlayer_LOD_Apply(this);
+               CSQCPlayer_ModelAppearance_Apply(this, (this.isplayermodel & ISPLAYER_LOCAL));
+               CSQCPlayer_LOD_Apply(this, true);
 
                if(!isplayer)
                {
@@ -687,6 +695,8 @@ void CSQCModel_Hook_PreDraw(entity this, bool isplayer)
                        }
                }
        }
+       else
+               CSQCPlayer_LOD_Apply(this, false);
 
        CSQCModel_AutoTagIndex_Apply(this);
 
@@ -699,7 +709,7 @@ void CSQCModel_Hook_PreUpdate(entity this, bool isnew, bool isplayer, bool isloc
        this.iflags |= IFLAG_V_ANGLE_X;
        // revert to values from server
        CSQCModel_Effects_PreUpdate(this);
-       if(this.isplayermodel)
+       if((this.isplayermodel & ISPLAYER_MODEL))
        {
                if(!isplayer)
                        CSQCPlayer_FallbackFrame_PreUpdate(this);
@@ -710,10 +720,12 @@ void CSQCModel_Hook_PreUpdate(entity this, bool isnew, bool isplayer, bool isloc
 void CSQCModel_Hook_PostUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
 {
        // is it a player model? (shared state)
-       this.isplayermodel = (substring(this.model, 0, 14) == "models/player/" || substring(this.model, 0, 17) == "models/ok_player/" || (substring(this.model, 0, 16) == "models/monsters/" && (this.entnum >= 1 && this.entnum <= maxclients)));
+       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);
 
        // save values set by server
-       if(this.isplayermodel)
+       if((this.isplayermodel & ISPLAYER_MODEL))
        {
                CSQCPlayer_ModelAppearance_PostUpdate(this);
                if(isplayer)