float autocvar_cl_deathglow;
float autocvar_developer_csqcentities;
float autocvar_sv_player_jumpanim_minfall;
+float autocvar_cl_csad;
-void CSQCModel_Hook_PreDraw();
+void CSQCModel_Hook_PreDraw(float isplayer);
.float isplayermodel;
// 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)
{
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"
}
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);
}
{
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
{
entity oldself = self;
self = self.tag_entity;
- CSQCModel_Hook_PreDraw();
+ CSQCModel_Hook_PreDraw((self.entnum >= 1 && self.entnum <= maxclients));
self = oldself;
}
// 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;
CSQCPlayer_ForceModel_Apply(self.entnum == player_localnum + 1);
CSQCPlayer_GlowMod_Apply();
CSQCPlayer_LOD_Apply();
- CSQCPlayer_FallbackFrame_Apply();
+ if(!isplayer || !autocvar_cl_csad)
+ CSQCPlayer_FallbackFrame_Apply();
+ else
+ {
+ // we know that frame3 and frame4 fields, used by InterpolateAnimation, are left alone - but that is all we know!
+ float doblend = FALSE;
+ float flg = 0;
+ if(self == csqcplayer)
+ {
+ if(self.pmove_flags & PMF_ONGROUND)
+ flg |= FL_ONGROUND;
+ if(!(self.pmove_flags & PMF_JUMPRELEASED))
+ if(self.anim_prev_pmove_flags & PMF_JUMPRELEASED)
+ animdecide_setaction(self, ANIMACTION_JUMP, TRUE);
+ self.anim_prev_pmove_flags = self.pmove_flags;
+ }
+ else
+ {
+ traceline(self.origin + '0 0 1' * self.maxs_z, self.origin + '0 0 1' * (self.mins_z - 4), MOVE_NOMONSTERS, self);
+ if(trace_startsolid || trace_fraction < 1)
+ flg |= FL_ONGROUND;
+ }
+ animdecide_setframes(self, flg, 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_saveframe = 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.frame = self.anim_frame2;
+ self.frame2time = self.anim_frame2time;
+ CSQCModel_InterpolateAnimation_2To4_Note(sf | CSQCMODEL_PROPERTY_LERPFRAC, FALSE);
+ }
+ CSQCModel_InterpolateAnimation_2To4_Do();
+ if(doblend)
+ {
+ // build a skeletonobject
+ }
+ else
+ {
+ // remove skeletonobject if any
+ // all is done
+ }
+ }
}
CSQCModel_AutoTagIndex_Apply();
CSQCModel_Effects_PreUpdate();
if(self.isplayermodel)
{
- CSQCPlayer_FallbackFrame_PreUpdate();
+ if(!isplayer || !autocvar_cl_csad)
+ CSQCPlayer_FallbackFrame_PreUpdate();
CSQCPlayer_ForceModel_PreUpdate();
}
}
if(self.isplayermodel)
{
CSQCPlayer_ForceModel_PostUpdate();
- CSQCPlayer_FallbackFrame_PostUpdate(isnew);
+ if(!isplayer || !autocvar_cl_csad)
+ CSQCPlayer_FallbackFrame_PostUpdate(isnew);
}
CSQCModel_Effects_PostUpdate();
}
void animdecide_init(entity e)
{
- e.anim_die1 = animfixfps(e, '0 1 0.5'); // 2 seconds
- e.anim_die2 = animfixfps(e, '1 1 0.5'); // 2 seconds
- e.anim_draw = animfixfps(e, '2 1 3');
- e.anim_duckwalk = animfixfps(e, '4 1 1');
- e.anim_duckjump = animfixfps(e, '5 1 10');
- e.anim_duckidle = animfixfps(e, '6 1 1');
- e.anim_idle = animfixfps(e, '7 1 1');
- e.anim_jump = animfixfps(e, '8 1 10');
- e.anim_pain1 = animfixfps(e, '9 1 2'); // 0.5 seconds
- e.anim_pain2 = animfixfps(e, '10 1 2'); // 0.5 seconds
- e.anim_shoot = animfixfps(e, '11 1 5'); // analyze models and set framerate
- e.anim_taunt = animfixfps(e, '12 1 0.33');
- e.anim_run = animfixfps(e, '13 1 1');
- e.anim_runbackwards = animfixfps(e, '14 1 1');
- e.anim_strafeleft = animfixfps(e, '15 1 1');
- e.anim_straferight = animfixfps(e, '16 1 1');
- e.anim_forwardright = animfixfps(e, '19 1 1');
- e.anim_forwardleft = animfixfps(e, '20 1 1');
- e.anim_backright = animfixfps(e, '21 1 1');
- e.anim_backleft = animfixfps(e, '22 1 1');
- e.anim_melee = animfixfps(e, '23 1 1');
- e.anim_duckwalkbackwards = animfixfps(e, '24 1 1');
- e.anim_duckwalkstrafeleft = animfixfps(e, '25 1 1');
- e.anim_duckwalkstraferight = animfixfps(e, '26 1 1');
- e.anim_duckwalkforwardright = animfixfps(e, '27 1 1');
- e.anim_duckwalkforwardleft = animfixfps(e, '28 1 1');
- e.anim_duckwalkbackright = animfixfps(e, '29 1 1');
- e.anim_duckwalkbackleft = animfixfps(e, '30 1 1');
+ vector none = '0 0 0';
+ e.anim_die1 = animfixfps(e, '0 1 0.5', none); // 2 seconds
+ e.anim_die2 = animfixfps(e, '1 1 0.5', none); // 2 seconds
+ e.anim_draw = animfixfps(e, '2 1 3', none);
+ e.anim_duckwalk = animfixfps(e, '4 1 1', none);
+ e.anim_duckjump = animfixfps(e, '5 1 10', none);
+ e.anim_duckidle = animfixfps(e, '6 1 1', none);
+ e.anim_idle = animfixfps(e, '7 1 1', none);
+ e.anim_jump = animfixfps(e, '8 1 10', none);
+ e.anim_pain1 = animfixfps(e, '9 1 2', none); // 0.5 seconds
+ e.anim_pain2 = animfixfps(e, '10 1 2', none); // 0.5 seconds
+ e.anim_shoot = animfixfps(e, '11 1 5', none); // analyze models and set framerate
+ e.anim_taunt = animfixfps(e, '12 1 0.33', none);
+ e.anim_run = animfixfps(e, '13 1 1', none);
+ e.anim_runbackwards = animfixfps(e, '14 1 1', none);
+ e.anim_strafeleft = animfixfps(e, '15 1 1', none);
+ e.anim_straferight = animfixfps(e, '16 1 1', none);
+ e.anim_forwardright = animfixfps(e, '19 1 1', '16 1 1');
+ e.anim_forwardleft = animfixfps(e, '20 1 1', '15 1 1');
+ e.anim_backright = animfixfps(e, '21 1 1', '16 1 1');
+ e.anim_backleft = animfixfps(e, '22 1 1', '15 1 1');
+ e.anim_melee = animfixfps(e, '23 1 1', '11 1 1');
+ e.anim_duckwalkbackwards = animfixfps(e, '24 1 1', '4 1 1');
+ e.anim_duckwalkstrafeleft = animfixfps(e, '25 1 1', '4 1 1');
+ e.anim_duckwalkstraferight = animfixfps(e, '26 1 1', '4 1 1');
+ e.anim_duckwalkforwardright = animfixfps(e, '27 1 1', '4 1 1');
+ e.anim_duckwalkforwardleft = animfixfps(e, '28 1 1', '4 1 1');
+ e.anim_duckwalkbackright = animfixfps(e, '29 1 1', '4 1 1');
+ e.anim_duckwalkbackleft = animfixfps(e, '30 1 1', '4 1 1');
}
#define ANIMPRIO_IDLE 0
// can't get here
}
-void animdecide_setimplicitstate(entity e)
+void animdecide_setimplicitstate(entity e, float flg)
{
float s;
s = 0;
if(v_y < -fabs(v_x) * 0.5)
s |= ANIMIMPLICITSTATE_LEFT;
}
- if(!(e.flags & FL_ONGROUND))
+ if(!(flg & FL_ONGROUND))
s |= ANIMIMPLICITSTATE_INAIR;
// detect some kinds of otherwise misdetected jumps
if(!(e.anim_implicit_state & ANIMIMPLICITSTATE_INAIR) && (s & ANIMIMPLICITSTATE_INAIR))
{
// ground to air transition - do we want to reset jump anim?
+ if(e.anim_lower_action != ANIMACTION_JUMP || time > e.anim_lower_time + 0.2)
if(e.anim_lower_implicit_action != ANIMACTION_JUMP || time > e.anim_lower_implicit_time + 0.2)
{
traceline(e.origin + '0 0 1' * e.maxs_z, e.origin + '0 0 1' * (e.mins_z - autocvar_sv_player_jumpanim_minfall), MOVE_NOMONSTERS, e);
e.anim_implicit_time = time;
}
}
-void animdecide_setframes(entity e, float support_blending)
+void animdecide_setframes(entity e, float flg, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time)
{
- animdecide_setimplicitstate(e);
+ animdecide_setimplicitstate(e, flg);
// _x: frame
// _y: start time
// _z: priority
{
if(e.frame1time != upper_y || e.frame2time != lower_y)
BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
- e.frame = upper_x;
- e.frame1time = upper_y;
- e.frame2 = lower_x;
- e.frame2time = lower_y;
+ e.fld_frame = upper_x;
+ e.fld_frame1time = upper_y;
+ e.fld_frame2 = lower_x;
+ e.fld_frame2time = lower_y;
}
else
{
if(e.frame1time != upper_y)
BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
- e.frame = upper_x;
- e.frame1time = upper_y;
+ e.fld_frame = upper_x;
+ e.fld_frame1time = upper_y;
}
}
// client side frame inferring
void animdecide_init(entity e);
-void animdecide_setframes(entity e, float support_blending);
+
+// flags to pass here
+float FL_ONGROUND = 512;
+void animdecide_setframes(entity e, float flg, float support_blending, .float fld_frame, .float fld_frame1time, .float fld_frame2, .float fld_frame2time);
// please network this one
.float anim_state;
#define ANIMIMPLICITSTATE_BACKWARDS 4
#define ANIMIMPLICITSTATE_LEFT 8
#define ANIMIMPLICITSTATE_RIGHT 16
+#define ANIMIMPLICITSTATE_JUMPRELEASED 32
// explicit actions (networked); negative values are for lower body
void animdecide_setaction(entity e, float action, float restart);
// define this if svqc code wants to use .frame2 and .lerpfrac
-#define CSQCMODEL_HAVE_TWO_FRAMES
+//#define CSQCMODEL_HAVE_TWO_FRAMES
// don't define this ever
//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
#define CSQCMODEL_HOOK_POSTUPDATE \
CSQCModel_Hook_PostUpdate(isnew, isplayer, islocalplayer);
#define CSQCMODEL_HOOK_PREDRAW \
- CSQCModel_Hook_PreDraw();
+ CSQCModel_Hook_PreDraw(isplayer);
#define CSQCPLAYER_HOOK_POSTCAMERASETUP
// force updates of player entities that often even if unchanged
return v;
}
-vector animfixfps(entity e, vector a)
+vector animfixfps(entity e, vector a, vector b)
{
// multi-frame anim: keep as-is
if(a_y == 1)
{
float dur;
dur = frameduration(e.modelindex, a_x);
+ if(dur <= 0 && b_y)
+ {
+ a = b;
+ dur = frameduration(e.modelindex, a_x);
+ }
if(dur > 0)
a_z = 1.0 / dur;
}
vector vec3(float x, float y, float z);
-vector animfixfps(entity e, vector a);
+vector animfixfps(entity e, vector a, vector b);
void CSQCModel_InterpolateAnimation_Note(float sf)
{
#ifdef CSQCMODEL_HAVE_TWO_FRAMES
- CSQCModel_InterpolateAnimation_2To4_Note(sf, FALSE);
+ CSQCModel_InterpolateAnimation_2To4_Note(sf, TRUE);
#else
- CSQCModel_InterpolateAnimation_1To2_Note(sf, FALSE);
+ CSQCModel_InterpolateAnimation_1To2_Note(sf, TRUE);
#endif
}
animbits |= ANIMSTATE_DUCK;
animdecide_setstate(self, animbits, FALSE);
- animdecide_setframes(self, FALSE);
+ animdecide_setframes(self, self.flags, FALSE, frame, frame1time, frame2, frame2time);
if (self.weaponentity)
{
setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below
// preset some defaults that work great for renamed zym files (which don't need an animinfo)
- self.anim_fire1 = animfixfps(self, '0 1 0.01');
- self.anim_fire2 = animfixfps(self, '1 1 0.01');
- self.anim_idle = animfixfps(self, '2 1 0.01');
- self.anim_reload = animfixfps(self, '3 1 0.01');
+ self.anim_fire1 = animfixfps(self, '0 1 0.01', '0 0 0');
+ self.anim_fire2 = animfixfps(self, '1 1 0.01', '0 0 0');
+ self.anim_idle = animfixfps(self, '2 1 0.01', '0 0 0');
+ self.anim_reload = animfixfps(self, '3 1 0.01', '0 0 0');
// if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
// if we don't, this is a "real" animated model