]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/csqcmodel_hooks.qc
More cleanup
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / csqcmodel_hooks.qc
index e7988cb5ad1d165920dd654f336bab94b9b430ee..a3e612062f903abd4de191b5e70d38b612c503e3 100644 (file)
@@ -1,4 +1,4 @@
-void CSQCModel_Hook_PreDraw();
+void CSQCModel_Hook_PreDraw(float isplayer);
 
 .float isplayermodel;
 
@@ -69,7 +69,7 @@ void CSQCPlayer_LOD_Apply(void)
        }
 }
 
-// FEATURE: forcemodel (MUST be called BEFORE LOD!)
+// FEATURE: forcemodel and model color selection (MUST be called BEFORE LOD!)
 string forceplayermodels_model;
 float forceplayermodels_modelisgoodmodel;
 float forceplayermodels_modelindex;
@@ -92,14 +92,17 @@ float forceplayermodels_attempted;
 string forceplayermodels_goodmodel;
 float forceplayermodels_goodmodelindex;
 
-void CSQCPlayer_ForceModel_PreUpdate(void)
+.vector glowmod;
+.vector old_glowmod; 
+
+void CSQCPlayer_ModelAppearance_PreUpdate(void)
 {
        self.model = self.forceplayermodels_savemodel;
        self.modelindex = self.forceplayermodels_savemodelindex;
        self.skin = self.forceplayermodels_saveskin;
        self.colormap = self.forceplayermodels_savecolormap;
 }
-void CSQCPlayer_ForceModel_PostUpdate(void)
+void CSQCPlayer_ModelAppearance_PostUpdate(void)
 {
        self.forceplayermodels_savemodel = self.model;
        self.forceplayermodels_savemodelindex = self.modelindex;
@@ -114,7 +117,7 @@ void CSQCPlayer_ForceModel_PostUpdate(void)
                        print(sprintf("Warning: missing model %s has been used\n", self.forceplayermodels_savemodel));
        }
 }
-void CSQCPlayer_ForceModel_Apply(float islocalplayer)
+void CSQCPlayer_ModelAppearance_Apply(float islocalplayer)
 {
        // which one is ALWAYS good?
        if not(forceplayermodels_goodmodel)
@@ -208,6 +211,7 @@ void CSQCPlayer_ForceModel_Apply(float islocalplayer)
                self.skin = self.forceplayermodels_saveskin;
        }
 
+       //float selected_colormap = cm;
        // forceplayercolors too
        if(teamplay)
        {
@@ -218,7 +222,7 @@ void CSQCPlayer_ForceModel_Apply(float islocalplayer)
                entity tm;
 
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
-                       if(tm.team != FL_SPECTATOR)
+                       if(tm.team != NUM_SPECTATOR)
                                ++teams_count;
 
                if(autocvar_cl_forcemyplayercolors)
@@ -265,13 +269,71 @@ void CSQCPlayer_ForceModel_Apply(float islocalplayer)
                else if(autocvar_cl_forceplayercolors)
                        self.colormap = player_localnum + 1;
        }
+
+       if(self.colormap > 0)
+               self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
+       else
+               self.glowmod = '1 1 1';
+
+       if(autocvar_cl_deathglow > 0)
+       {
+               if(self.csqcmodel_isdead)
+               {
+                       // Fade out to black now...
+                       if(self.old_glowmod == '0 0 0') { self.old_glowmod = self.glowmod; }
+                       self.colormap = 0;
+                       
+                       self.glowmod = self.old_glowmod * bound(0, 1 - (time - self.death_time) / autocvar_cl_deathglow, 1);
+                       self.glowmod_x = max(self.glowmod_x, 0.0001);
+                       self.glowmod_y = max(self.glowmod_y, 0.0001);
+                       self.glowmod_z = max(self.glowmod_z, 0.0001);
+               }
+               else if(self.old_glowmod != '0 0 0') { self.old_glowmod = '0 0 0'; }
+       }
+
+       //print(sprintf("CSQCPlayer_ModelAppearance_Apply(): state = %s, colormap = %f, glowmod = %s\n", (self.csqcmodel_isdead ? "DEAD" : "ALIVE"), self.colormap, vtos(self.glowmod)));
 }
 
+/*// FEATURE: auto glowmod
+.vector glowmod;
+void CSQCPlayer_GlowMod_Apply(void)
+{
+       float cm = self.colormap;
+
+       if(self.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST)
+               cm = 1024;
+
+       if(self.colormap > 0)
+               self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
+       else
+               self.glowmod = '1 1 1';
+
+       if(self.colormod != '0 0 0') { self.colormod = '0 0 0'; }
+
+       if(autocvar_cl_deathglow > 0)
+       {
+               if(self.csqcmodel_isdead)
+               {
+                       self.colormap = 0;
+                       self.glowmod = self.glowmod * bound(0, 1 - (time - self.death_time) / autocvar_cl_deathglow, 1);
+                       // prevent the zero vector
+                       self.glowmod_x = max(self.glowmod_x, 0.0001);
+                       self.glowmod_y = max(self.glowmod_y, 0.0001);
+                       self.glowmod_z = max(self.glowmod_z, 0.0001);
+               }
+               
+       }
+       
+       print(sprintf("CSQCPlayer_GlowMod_Apply(): state = %s, colormap = %f, colormod = %s, glowmod = %s\n", (self.csqcmodel_isdead ? "DEAD" : "ALIVE"), cm, vtos(self.colormod), vtos(self.glowmod)));
+}*/
+
 // FEATURE: fallback frames
 .float csqcmodel_saveframe;
 .float csqcmodel_saveframe2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
 .float csqcmodel_saveframe3;
 .float csqcmodel_saveframe4;
+#endif
 .float csqcmodel_framecount;
 
 #define IS_DEAD_FRAME(f) ((f) == 0 || (f) == 1)
@@ -279,15 +341,19 @@ void CSQCPlayer_FallbackFrame_PreUpdate(void)
 {
        self.frame = self.csqcmodel_saveframe;
        self.frame2 = self.csqcmodel_saveframe2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.frame3 = self.csqcmodel_saveframe3;
        self.frame4 = self.csqcmodel_saveframe4;
+#endif
 }
 void CSQCPlayer_FallbackFrame_PostUpdate(float isnew)
 {
        self.csqcmodel_saveframe = self.frame;
        self.csqcmodel_saveframe2 = self.frame2;
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.csqcmodel_saveframe3 = self.frame3;
        self.csqcmodel_saveframe4 = self.frame4;
+#endif
 
        // hack for death animations: set their frametime to zero in case a
        // player "pops in"
@@ -300,11 +366,17 @@ void CSQCPlayer_FallbackFrame_PostUpdate(float isnew)
                }
                FIX_FRAMETIME(frame, frame1time)
                FIX_FRAMETIME(frame2, frame2time)
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
                FIX_FRAMETIME(frame3, frame3time)
                FIX_FRAMETIME(frame4, frame4time)
+#endif
        }
        self.csqcmodel_isdead = IS_DEAD_FRAME(self.frame);
 }
+void CSQCPlayer_AnimDecide_PostUpdate(float isnew)
+{
+       self.csqcmodel_isdead = !!(self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+}
 float CSQCPlayer_FallbackFrame(float f)
 {
        if(frameduration(self.modelindex, f) > 0)
@@ -329,8 +401,10 @@ void CSQCPlayer_FallbackFrame_Apply(void)
 {
        self.frame = CSQCPlayer_FallbackFrame(self.frame);
        self.frame2 = CSQCPlayer_FallbackFrame(self.frame2);
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
        self.frame3 = CSQCPlayer_FallbackFrame(self.frame3);
        self.frame4 = CSQCPlayer_FallbackFrame(self.frame4);
+#endif
 }
 
 // FEATURE: auto tag_index
@@ -357,7 +431,7 @@ void CSQCModel_AutoTagIndex_Apply(void)
                {
                        entity oldself = self;
                        self = self.tag_entity;
-                       CSQCModel_Hook_PreDraw();
+                       CSQCModel_Hook_PreDraw((self.entnum >= 1 && self.entnum <= maxclients));
                        self = oldself;
                }
 
@@ -388,11 +462,8 @@ void CSQCModel_AutoTagIndex_Apply(void)
                                        }
                                        else if(self.tag_entity.isplayermodel)
                                        {
-                                               self.tag_index = gettagindex(self.tag_entity, "weapon");
-                                               if(!self.tag_index)
-                                                       self.tag_index = gettagindex(self.tag_entity, "tag_weapon");
-                                               if(!self.tag_index)
-                                                       self.tag_index = gettagindex(self.tag_entity, "bip01 r hand");
+                                               skeleton_loadinfo(self.tag_entity);
+                                               self.tag_index = self.tag_entity.bone_weapon;
                                        }
                                }
 
@@ -419,6 +490,8 @@ float EF_DIMLIGHT   = 8;
 float EF_DOUBLESIDED = 32768;
 float EF_NOSELFSHADOW = 65536;
 float EF_DYNAMICMODELLIGHT = 131072;
+float EF_RESTARTANIM_BIT = 1048576;
+float EF_TELEPORT_BIT = 2097152;
 float MF_ROCKET  =   1; // leave a trail
 float MF_GRENADE =   2; // leave a trail
 float MF_GIB     =   4; // leave a trail
@@ -443,6 +516,7 @@ void CSQCModel_Effects_PostUpdate(void)
        if(self.csqcmodel_teleported)
                Projectile_ResetTrail(self.origin);
 }
+.float snd_looping;
 void CSQCModel_Effects_Apply(void)
 {
        float eff = self.csqcmodel_effects;
@@ -514,36 +588,42 @@ void CSQCModel_Effects_Apply(void)
        if(self.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST)
                self.renderflags |= RF_ADDITIVE;
                // also special in CSQCPlayer_GlowMod_Apply
-}
-
-// FEATURE: auto glowmod
-.vector glowmod;
-void CSQCPlayer_GlowMod_Apply(void)
-{
-       float cm = self.colormap;
-
-       if(self.csqcmodel_effects & CSQCMODEL_EF_RESPAWNGHOST)
-               cm = 1024;
 
-       if(self.colormap > 0)
-               self.glowmod = colormapPaletteColor(((self.colormap >= 1024) ? self.colormap : stof(getplayerkeyvalue(self.colormap - 1, "colors"))) & 0x0F, TRUE) * 2;
+       if(self.csqcmodel_modelflags & MF_ROCKET)
+       {
+               if(!self.snd_looping)
+               {
+                       sound(self, CH_TRIGGER_SINGLE, "misc/jetpack_fly.wav", VOL_BASE, autocvar_g_jetpack_attenuation);
+                       self.snd_looping = CH_TRIGGER_SINGLE;
+               }
+       }
        else
-               self.glowmod = '1 1 1';
-
-       if(autocvar_cl_deathglow > 0)
-               if(self.csqcmodel_isdead)
+       {
+               if(self.snd_looping)
                {
-                       self.glowmod = self.glowmod * bound(0, 1 - (time - self.death_time) / autocvar_cl_deathglow, 1);
-                       // prevent the zero vector
-                       self.glowmod_x = max(self.glowmod_x, 0.0001);
-                       self.glowmod_y = max(self.glowmod_y, 0.0001);
-                       self.glowmod_z = max(self.glowmod_z, 0.0001);
+                       sound(self, self.snd_looping, "misc/null.wav", VOL_BASE, autocvar_g_jetpack_attenuation);
+                       self.snd_looping = 0;
                }
+       }
+}
+
+void CSQCPlayer_Precache()
+{
+       precache_sound("misc/jetpack_fly.wav");
 }
 
 // general functions
 .float csqcmodel_predraw_run;
-void CSQCModel_Hook_PreDraw()
+.float anim_frame;
+.float anim_frame1time;
+.float anim_frame2;
+.float anim_frame2time;
+.float anim_saveframe;
+.float anim_saveframe1time;
+.float anim_saveframe2;
+.float anim_saveframe2time;
+.float anim_prev_pmove_flags;
+void CSQCModel_Hook_PreDraw(float isplayer)
 {
        if(self.csqcmodel_predraw_run == framecount)
                return;
@@ -559,10 +639,68 @@ void CSQCModel_Hook_PreDraw()
 
        if(self.isplayermodel) // this checks if it's a player MODEL!
        {
-               CSQCPlayer_ForceModel_Apply(self.entnum == player_localnum + 1);
-               CSQCPlayer_GlowMod_Apply();
+               float islocalplayer = (self.entnum == player_localnum + 1);
+               CSQCPlayer_ModelAppearance_Apply(islocalplayer);
                CSQCPlayer_LOD_Apply();
-               CSQCPlayer_FallbackFrame_Apply();
+               if(!isplayer)
+                       CSQCPlayer_FallbackFrame_Apply();
+               else
+               {
+                       // we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
+                       skeleton_loadinfo(self);
+                       float doblend = (self.bone_upperbody >= 0);
+                       float onground = 0;
+                       if(self == csqcplayer)
+                       {
+                               if(self.pmove_flags & PMF_ONGROUND)
+                                       onground = 1;
+                               self.anim_prev_pmove_flags = self.pmove_flags;
+                               if(self.pmove_flags & PMF_DUCKED)
+                                       animdecide_setstate(self, self.anim_state | ANIMSTATE_DUCK, FALSE);
+                               else if(self.anim_state & ANIMSTATE_DUCK)
+                                       animdecide_setstate(self, self.anim_state - ANIMSTATE_DUCK, FALSE);
+                       }
+                       else
+                       {
+                               tracebox(self.origin + '0 0 1', self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self);
+                               if(trace_startsolid || trace_fraction < 1)
+                                       onground = 1;
+                       }
+                       animdecide_init(self);
+                       animdecide_setimplicitstate(self, onground);
+                       animdecide_setframes(self, doblend, anim_frame, anim_frame1time, anim_frame2, anim_frame2time);
+                       float sf = 0;
+                       if(self.anim_saveframe != self.anim_frame || self.anim_saveframe1time != self.anim_frame1time)
+                               sf |= CSQCMODEL_PROPERTY_FRAME;
+                       if(self.anim_saveframe2 != self.anim_frame2 || self.anim_saveframe2time != self.anim_frame2time)
+                               sf |= CSQCMODEL_PROPERTY_FRAME2;
+                       self.anim_saveframe = self.anim_frame;
+                       self.anim_saveframe1time = self.anim_frame1time;
+                       self.anim_saveframe2 = self.anim_frame2;
+                       self.anim_saveframe2time = self.anim_frame2time;
+                       if(sf)
+                       {
+                               CSQCModel_InterpolateAnimation_2To4_PreNote(sf | CSQCMODEL_PROPERTY_LERPFRAC);
+                               self.lerpfrac = (doblend ? 0.5 : 0);
+                               self.frame = self.anim_frame;
+                               self.frame1time = self.anim_frame1time;
+                               self.frame2 = self.anim_frame2;
+                               self.frame2time = self.anim_frame2time;
+                               CSQCModel_InterpolateAnimation_2To4_Note(sf | CSQCMODEL_PROPERTY_LERPFRAC, FALSE);
+                       }
+                       CSQCModel_InterpolateAnimation_2To4_Do();
+                       if(doblend)
+                       {
+                               skeleton_from_frames(self, self.csqcmodel_isdead);
+                       }
+                       else
+                       {
+                               free_skeleton_from_frames(self);
+                               // just in case, clear these (we're animating in frame and frame3)
+                               self.lerpfrac = 0;
+                               self.lerpfrac4 = 0;
+                       }
+               }
        }
 
        CSQCModel_AutoTagIndex_Apply();
@@ -572,12 +710,15 @@ void CSQCModel_Hook_PreDraw()
 
 void CSQCModel_Hook_PreUpdate(float isnew, float isplayer, float islocalplayer)
 {
+       // interpolate v_angle
+       self.iflags |= IFLAG_V_ANGLE_X;
        // revert to values from server
        CSQCModel_Effects_PreUpdate();
        if(self.isplayermodel)
        {
-               CSQCPlayer_FallbackFrame_PreUpdate();
-               CSQCPlayer_ForceModel_PreUpdate();
+               if(!isplayer)
+                       CSQCPlayer_FallbackFrame_PreUpdate();
+               CSQCPlayer_ModelAppearance_PreUpdate();
        }
 }
 
@@ -589,8 +730,11 @@ void CSQCModel_Hook_PostUpdate(float isnew, float isplayer, float islocalplayer)
        // save values set by server
        if(self.isplayermodel)
        {
-               CSQCPlayer_ForceModel_PostUpdate();
-               CSQCPlayer_FallbackFrame_PostUpdate(isnew);
+               CSQCPlayer_ModelAppearance_PostUpdate();
+               if(isplayer)
+                       CSQCPlayer_AnimDecide_PostUpdate(isnew);
+               else
+                       CSQCPlayer_FallbackFrame_PostUpdate(isnew);
        }
        CSQCModel_Effects_PostUpdate();
 }