From a50fb8a2385ca2270696751107001a45937a2512 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 21 Nov 2012 11:57:11 +0100 Subject: [PATCH] Factor out animation decisions and gameplay This will later allow performing the animation decision on the client, using flags networked by the server. Requirement for animation blending. --- qcsrc/common/animdecide.qc | 258 +++++++++++++++++++++++ qcsrc/common/animdecide.qh | 33 +++ qcsrc/common/util.qc | 9 + qcsrc/common/util.qh | 2 + qcsrc/server/cl_client.qc | 2 +- qcsrc/server/cl_physics.qc | 5 +- qcsrc/server/cl_player.qc | 164 +++++--------- qcsrc/server/cl_weaponsystem.qc | 16 +- qcsrc/server/defs.qh | 38 ---- qcsrc/server/mutators/mutator_dodging.qc | 2 +- qcsrc/server/progs.src | 2 + qcsrc/server/t_jumppads.qc | 8 +- qcsrc/server/w_electro.qc | 9 +- 13 files changed, 361 insertions(+), 187 deletions(-) create mode 100644 qcsrc/common/animdecide.qc create mode 100644 qcsrc/common/animdecide.qh diff --git a/qcsrc/common/animdecide.qc b/qcsrc/common/animdecide.qc new file mode 100644 index 0000000000..79004cfe0d --- /dev/null +++ b/qcsrc/common/animdecide.qc @@ -0,0 +1,258 @@ +// implicit anim state +.float anim_implicit_state; +.float anim_implicit_time; + +// actions +.float anim_lower_action; +.float anim_lower_time; +.float anim_upper_action; +.float anim_upper_time; + +// player animation data for this model +// each vector is as follows: +// _x = startframe +// _y = numframes +// _z = framerate +.vector anim_die1; // player dies +.vector anim_die2; // player dies differently +.vector anim_draw; // player pulls out a weapon +.vector anim_duckwalk; // player walking while crouching +.vector anim_duckjump; // player jumping from a crouch +.vector anim_duckidle; // player idling while crouching +.vector anim_idle; // player standing +.vector anim_jump; // player jump +.vector anim_pain1; // player flinches from pain +.vector anim_pain2; // player flinches from pain, differently +.vector anim_shoot; // player shoots +.vector anim_taunt; // player taunts others (FIXME: no code references this) +.vector anim_run; // player running forward +.vector anim_runbackwards; // player running backward +.vector anim_strafeleft; // player shuffling left quickly +.vector anim_straferight; // player shuffling right quickly +.vector anim_forwardright; // player running forward and right +.vector anim_forwardleft; // player running forward and left +.vector anim_backright; // player running backward and right +.vector anim_backleft; // player running back and left +.vector anim_melee; // player doing the melee action +.vector anim_duck; // player doing the melee action +.vector anim_duckwalkbackwards; +.vector anim_duckwalkstrafeleft; +.vector anim_duckwalkstraferight; +.vector anim_duckwalkforwardright; +.vector anim_duckwalkforwardleft; +.vector anim_duckwalkbackright; +.vector anim_duckwalkbackleft; + +void animdecide_init(entity e) +{ + self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds + self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds + self.anim_draw = animfixfps(self, '2 1 3'); + self.anim_duckwalk = animfixfps(self, '4 1 1'); + self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_duckidle = animfixfps(self, '6 1 1'); + self.anim_idle = animfixfps(self, '7 1 1'); + self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds + self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds + self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate + self.anim_taunt = animfixfps(self, '12 1 0.33'); + self.anim_run = animfixfps(self, '13 1 1'); + self.anim_runbackwards = animfixfps(self, '14 1 1'); + self.anim_strafeleft = animfixfps(self, '15 1 1'); + self.anim_straferight = animfixfps(self, '16 1 1'); + self.anim_forwardright = animfixfps(self, '19 1 1'); + self.anim_forwardleft = animfixfps(self, '20 1 1'); + self.anim_backright = animfixfps(self, '21 1 1'); + self.anim_backleft = animfixfps(self, '22 1 1'); + self.anim_melee = animfixfps(self, '23 1 1'); + self.anim_duckwalkbackwards = animfixfps(self, '24 1 1'); + self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1'); + self.anim_duckwalkstraferight = animfixfps(self, '26 1 1'); + self.anim_duckwalkforwardright = animfixfps(self, '27 1 1'); + self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1'); + self.anim_duckwalkbackright = animfixfps(self, '29 1 1'); + self.anim_duckwalkbackleft = animfixfps(self, '30 1 1'); +} + +#define ANIMPRIO_IDLE 0 +#define ANIMPRIO_STATIC 1 +#define ANIMPRIO_ACTIVE 2 +#define ANIMPRIO_DEAD 3 + +vector animdecide_getupperanim(entity e) +{ + // is there an action? + vector outframe = '-1 0 0'; + switch(e.anim_upper_action) + { + case ANIMACTION_DRAW: outframe = e.anim_draw; break; + case ANIMACTION_PAIN1: outframe = e.anim_pain1; break; + case ANIMACTION_PAIN2: outframe = e.anim_pain2; break; + case ANIMACTION_SHOOT: outframe = e.anim_shoot; break; + case ANIMACTION_TAUNT: outframe = e.anim_taunt; break; + case ANIMACTION_MELEE: outframe = e.anim_melee; break; + } + if(outframe_x >= 0) + { + if(time <= e.anim_upper_time + outframe_y / outframe_z) + { + // animation is running! + return vec3(outframe_x, e.anim_upper_time, ANIMPRIO_ACTIVE); + } + } + float t = max(e.anim_time, e.anim_implicit_time); + // or, decide the anim by state + // but all states are for lower body! + return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE); +} + +vector animdecide_getloweranim(entity e) +{ + // death etc. + if(e.anim_state & ANIMSTATE_FROZEN) + return vec3(e.anim_idle_x, e.anim_time, ANIMPRIO_DEAD); + if(e.anim_state & ANIMSTATE_DEAD1) + return vec3(e.anim_die1_x, e.anim_time, ANIMPRIO_DEAD); + if(e.anim_state & ANIMSTATE_DEAD2) + return vec3(e.anim_die2_x, e.anim_time, ANIMPRIO_DEAD); + + // is there an action? + vector outframe = '-1 0 0'; + switch(e.anim_lower_action) + { + case ANIMACTION_JUMP: if(e.anim_state & ANIMSTATE_DUCK) outframe = e.anim_duckjump; else outframe = e.anim_jump; break; + } + if(outframe_x >= 0) + { + if(time <= e.anim_lower_time + outframe_y / outframe_z) + { + // animation is running! + return vec3(outframe_x, e.anim_lower_time, ANIMPRIO_ACTIVE); + } + } + float t = max(e.anim_time, e.anim_implicit_time); + // or, decide the anim by state + if(e.anim_state & ANIMSTATE_DUCK) + { + switch(self.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT)) + { + case ANIMIMPLICITSTATE_FORWARD: + return vec3(e.anim_duckwalk_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS: + return vec3(e.anim_duckwalkbackwards_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_duckwalkstraferight_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_duckwalkstrafeleft_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_duckwalkforwardright_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_duckwalkforwardleft_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_duckwalkbackright_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_duckwalkbackleft_x, t, ANIMPRIO_ACTIVE); + default: + return vec3(e.anim_duckidle_x, t, ANIMPRIO_STATIC); + } + } + else if(e.anim_implicit_state & ANIMIMPLICITSTATE_RUN) + { + switch(self.anim_implicit_state & (ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT | ANIMIMPLICITSTATE_RIGHT)) + { + case ANIMIMPLICITSTATE_FORWARD: + return vec3(e.anim_run_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS: + return vec3(e.anim_runbackwards_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_straferight_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_strafeleft_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_forwardright_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_FORWARD | ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_forwardleft_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_RIGHT: + return vec3(e.anim_backright_x, t, ANIMPRIO_ACTIVE); + case ANIMIMPLICITSTATE_BACKWARDS | ANIMIMPLICITSTATE_LEFT: + return vec3(e.anim_backleft_x, t, ANIMPRIO_ACTIVE); + default: + return vec3(e.anim_run_x, t, ANIMPRIO_STATIC); + } + } + return vec3(e.anim_idle_x, t, ANIMPRIO_IDLE); +} + +void animdecide_setimplicitstate(entity e) +{ + float s; + s = 0; + + makevectors(self.angles); + if(self.velocity * v_forward > 0) + s |= ANIMIMPLICITSTATE_FORWARD; + if(self.velocity * v_forward < 0) + s |= ANIMIMPLICITSTATE_BACKWARDS; + if(self.velocity * v_right > 0) + s |= ANIMIMPLICITSTATE_RIGHT; + if(self.velocity * v_right < 0) + s |= ANIMIMPLICITSTATE_LEFT; + if(vlen(self.velocity) > 100) + s |= ANIMIMPLICITSTATE_RUN; + + // TODO infer jumping too! +} +void animdecide_setframes(entity e, float support_blending) +{ + animdecide_setimplicitstate(e); + // _x: frame + // _y: priority + // _z: start time + vector upper = animdecide_getupperanim(e); + vector lower = animdecide_getloweranim(e); + if(upper_y > lower_y) + lower = upper; + else if(lower_y > upper_y) + upper = lower; + if(support_blending) + { + self.frame = upper_x; + self.frame1time = upper_z; + self.frame2 = lower_x; + self.frame2time = lower_z; + } + else + { + self.frame = upper_x; + self.frame1time = upper_z; + } +} + +void animdecide_setstate(entity e, float newstate, float restart) +{ + if(!restart) + if(newstate == e.anim_state) + return; + e.anim_state = newstate; + e.anim_time = time; +} +void animdecide_setaction(entity e, float action, float restart) +{ + if(action < 0) + { + if(!restart) + if(action == e.anim_lower_action) + return; + e.anim_lower_action = action; + e.anim_lower_time = time; + } + else + { + if(!restart) + if(action == e.anim_upper_action) + return; + e.anim_upper_action = action; + e.anim_upper_time = time; + } +} diff --git a/qcsrc/common/animdecide.qh b/qcsrc/common/animdecide.qh new file mode 100644 index 0000000000..e26abe3125 --- /dev/null +++ b/qcsrc/common/animdecide.qh @@ -0,0 +1,33 @@ +// client side frame inferring +void animdecide_init(entity e); +void animdecide_setframes(entity e, float support_blending); + +// please network this one +.float anim_state; +.float anim_time; +#define ReadAnimState() do { self.anim_state = ReadByte(); self.anim_time = ReadApproxPastTime(); } while(0) +#define WriteAnimState(dest) do { WriteByte(dest, self.anim_state); WriteApproxPastTime(dest, self.anim_time); } while(0) + +// explicit anim states (networked) +void animdecide_setstate(entity e, float newstate, float restart); +#define ANIMSTATE_DEAD1 1 // base frames: die1 +#define ANIMSTATE_DEAD2 2 // base frames: die2 +#define ANIMSTATE_DUCK 4 // turns walk into duckwalk, jump into duckjump, etc. +#define ANIMSTATE_FROZEN 8 // force idle + +// implicit anim states (inferred from velocity, etc.) +#define ANIMIMPLICITSTATE_RUN 1 +#define ANIMIMPLICITSTATE_FORWARD 2 +#define ANIMIMPLICITSTATE_BACKWARDS 4 +#define ANIMIMPLICITSTATE_LEFT 8 +#define ANIMIMPLICITSTATE_RIGHT 16 + +// explicit actions (networked); negative values are for lower body +void animdecide_setaction(entity e, float action, float restart); +#define ANIMACTION_JUMP -1 // jump +#define ANIMACTION_DRAW 1 // draw +#define ANIMACTION_PAIN1 2 // pain +#define ANIMACTION_PAIN2 3 // pain +#define ANIMACTION_SHOOT 4 // shoot +#define ANIMACTION_TAUNT 5 // taunt +#define ANIMACTION_MELEE 6 // melee diff --git a/qcsrc/common/util.qc b/qcsrc/common/util.qc index 53c14cfb0c..331e464b87 100644 --- a/qcsrc/common/util.qc +++ b/qcsrc/common/util.qc @@ -2463,3 +2463,12 @@ void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t for(queue_start = e; queue_start; queue_start = queue_start.fld) queue_start.FindConnectedComponent_processing = 0; } + +vector vec3(float x, float y, float z) +{ + vector v; + v_x = x; + v_y = y; + v_z = z; + return v; +} diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh index faa605f887..9b5608025c 100644 --- a/qcsrc/common/util.qh +++ b/qcsrc/common/util.qh @@ -361,3 +361,5 @@ float cubic_speedfunc_is_sane(float startspeedfactor, float endspeedfactor); typedef entity(entity cur, entity near, entity pass) findNextEntityNearFunction_t; typedef float(entity a, entity b, entity pass) isConnectedFunction_t; void FindConnectedComponent(entity e, .entity fld, findNextEntityNearFunction_t nxt, isConnectedFunction_t iscon, entity pass); + +vector vec3(float x, float y, float z); diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 9d6bcf798d..71431693ae 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -2785,7 +2785,7 @@ void PlayerPreThink (void) self.prevorigin = self.origin; if (!self.vehicle) - if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && self.animstate_startframe != self.anim_melee_x && !self.freezetag_frozen) // prevent crouching if using melee attack + if (((self.BUTTON_CROUCH && !self.hook.state) || self.health <= g_bloodloss) && !self.freezetag_frozen) // FIXME-CSAD: prevent crouching if using melee attack { if (!self.crouch) { diff --git a/qcsrc/server/cl_physics.qc b/qcsrc/server/cl_physics.qc index 3e2268d897..95dba951df 100644 --- a/qcsrc/server/cl_physics.qc +++ b/qcsrc/server/cl_physics.qc @@ -169,10 +169,7 @@ void PlayerJump (void) self.flags &~= FL_ONGROUND; self.flags &~= FL_JUMPRELEASED; - if (self.crouch) - setanim(self, self.anim_duckjump, FALSE, TRUE, TRUE); - else if (self.animstate_startframe != self.anim_melee_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // jump animation shouldn't override melee until we have animation blending (or until the anim finished, 21/20 = numframes/fps) - setanim(self, self.anim_jump, FALSE, TRUE, TRUE); + animdecide_setaction(self, ANIMACTION_JUMP, TRUE); if(g_jump_grunt) PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND); diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 3e560bd245..5b4b1c001c 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -225,132 +225,64 @@ float player_getspecies() void player_setupanimsformodel() { - // defaults for legacy .zym models without animinfo files - self.anim_die1 = animfixfps(self, '0 1 0.5'); // 2 seconds - self.anim_die2 = animfixfps(self, '1 1 0.5'); // 2 seconds - self.anim_draw = animfixfps(self, '2 1 3'); - // self.anim_duck = '3 1 100'; // This anim is broken, use slot 3 as a new free slot in the future ;) - self.anim_duckwalk = animfixfps(self, '4 1 1'); - self.anim_duckjump = '5 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it - self.anim_duckidle = animfixfps(self, '6 1 1'); - self.anim_idle = animfixfps(self, '7 1 1'); - self.anim_jump = '8 1 100'; // NOTE: zym anims keep playing until changed, so this only has to start the anim, landing will end it - self.anim_pain1 = animfixfps(self, '9 1 2'); // 0.5 seconds - self.anim_pain2 = animfixfps(self, '10 1 2'); // 0.5 seconds - self.anim_shoot = animfixfps(self, '11 1 5'); // analyze models and set framerate - self.anim_taunt = animfixfps(self, '12 1 0.33'); - self.anim_run = animfixfps(self, '13 1 1'); - self.anim_runbackwards = animfixfps(self, '14 1 1'); - self.anim_strafeleft = animfixfps(self, '15 1 1'); - self.anim_straferight = animfixfps(self, '16 1 1'); - //self.anim_dead1 = animfixfps(self, '17 1 1'); - //self.anim_dead2 = animfixfps(self, '18 1 1'); - self.anim_forwardright = animfixfps(self, '19 1 1'); - self.anim_forwardleft = animfixfps(self, '20 1 1'); - self.anim_backright = animfixfps(self, '21 1 1'); - self.anim_backleft = animfixfps(self, '22 1 1'); - self.anim_melee = animfixfps(self, '23 1 1'); - self.anim_duckwalkbackwards = animfixfps(self, '24 1 1'); - self.anim_duckwalkstrafeleft = animfixfps(self, '25 1 1'); - self.anim_duckwalkstraferight = animfixfps(self, '26 1 1'); - self.anim_duckwalkforwardright = animfixfps(self, '27 1 1'); - self.anim_duckwalkforwardleft = animfixfps(self, '28 1 1'); - self.anim_duckwalkbackright = animfixfps(self, '29 1 1'); - self.anim_duckwalkbackleft = animfixfps(self, '30 1 1'); - // TODO introspect models for finding right "fps" value (1/duration) - // reset animstate now - setanim(self, self.anim_idle, TRUE, FALSE, TRUE); + // load animation info + animdecide_init(self); + animdecide_setstate(self, 0, FALSE); } void player_anim (void) { - updateanim(self); - if (self.weaponentity) - updateanim(self.weaponentity); - - if (self.deadflag != DEAD_NO) - return; - - if (!self.animstate_override) + float deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2)); + if(self.deadflag && !deadbits) + if(random() < 0.5) + deadbits = ANIMSTATE_DEAD1; + else + deadbits = ANIMSTATE_DEAD2; + float animbits = deadbits; + if(self.freezetag_frozen) + animbits |= ANIMSTATE_FROZEN; + if(self.crouch) + animbits |= ANIMSTATE_DUCK; + animdecide_setstate(self, animbits, FALSE); + + /* FIXME-CSAD port this to animdecide.qc + if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP) { - if (self.freezetag_frozen) - setanim(self, self.anim_idle, TRUE, FALSE, FALSE); - else if (!(self.flags & FL_ONGROUND) || self.BUTTON_JUMP) + if (self.crouch) { - if (self.crouch) + if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim { - if (self.animstate_startframe != self.anim_duckjump_x) // don't perform another trace if already playing the crouch jump anim + traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self); + if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims { - traceline(self.origin + '0 0 1' * PL_CROUCH_MIN_z, self.origin + '0 0 1' * (PL_CROUCH_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self); - if(!trace_startsolid && trace_fraction == 1 || !(self.animstate_startframe == self.anim_duckwalk_x || self.animstate_startframe == self.anim_duckidle_x)) // don't get stuck on non-crouch anims - { - setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump); - self.restart_jump = FALSE; - } + setanim(self, self.anim_duckjump, FALSE, TRUE, self.restart_jump); + self.restart_jump = FALSE; } } - else - { - if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim - { - traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self); - if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished - { - setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump); - self.restart_jump = FALSE; - } - } - } - } - else if (self.crouch) - { - if (self.movement_x > 0 && self.movement_y == 0) - setanim(self, self.anim_duckwalk, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y == 0) - setanim(self, self.anim_duckwalkbackwards, TRUE, FALSE, FALSE); - else if (self.movement_x == 0 && self.movement_y > 0) - setanim(self, self.anim_duckwalkstraferight, TRUE, FALSE, FALSE); - else if (self.movement_x == 0 && self.movement_y < 0) - setanim(self, self.anim_duckwalkstrafeleft, TRUE, FALSE, FALSE); - else if (self.movement_x > 0 && self.movement_y > 0) - setanim(self, self.anim_duckwalkforwardright, TRUE, FALSE, FALSE); - else if (self.movement_x > 0 && self.movement_y < 0) - setanim(self, self.anim_duckwalkforwardleft, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y > 0) - setanim(self, self.anim_duckwalkbackright, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y < 0) - setanim(self, self.anim_duckwalkbackleft, TRUE, FALSE, FALSE); - else - setanim(self, self.anim_duckidle, TRUE, FALSE, FALSE); } - else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20) + else { - if (self.movement_x > 0 && self.movement_y == 0) - setanim(self, self.anim_run, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y == 0) - setanim(self, self.anim_runbackwards, TRUE, FALSE, FALSE); - else if (self.movement_x == 0 && self.movement_y > 0) - setanim(self, self.anim_straferight, TRUE, FALSE, FALSE); - else if (self.movement_x == 0 && self.movement_y < 0) - setanim(self, self.anim_strafeleft, TRUE, FALSE, FALSE); - else if (self.movement_x > 0 && self.movement_y > 0) - setanim(self, self.anim_forwardright, TRUE, FALSE, FALSE); - else if (self.movement_x > 0 && self.movement_y < 0) - setanim(self, self.anim_forwardleft, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y > 0) - setanim(self, self.anim_backright, TRUE, FALSE, FALSE); - else if (self.movement_x < 0 && self.movement_y < 0) - setanim(self, self.anim_backleft, TRUE, FALSE, FALSE); - else - setanim(self, self.anim_run, TRUE, FALSE, FALSE); + if (self.animstate_startframe != self.anim_jump_x) // don't perform another trace if already playing the jump anim + { + traceline(self.origin + '0 0 1' * PL_MIN_z, self.origin + '0 0 1' * (PL_MIN_z - autocvar_sv_player_jumpanim_minfall), TRUE, self); + if(!trace_startsolid && trace_fraction == 1 || self.animstate_startframe == self.anim_idle_x || (self.animstate_startframe == self.anim_melee_x && time - self.animstate_starttime >= 21/20)) // don't get stuck on idle animation in midair, nor melee after it finished + { + setanim(self, self.anim_jump, FALSE, TRUE, self.restart_jump); + self.restart_jump = FALSE; + } + } } - else - setanim(self, self.anim_idle, TRUE, FALSE, FALSE); } + */ + + animdecide_setframes(self, FALSE); if (self.weaponentity) - if (!self.weaponentity.animstate_override) - setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE); + { + updateanim(self.weaponentity); + if (!self.weaponentity.animstate_override) + setanim(self.weaponentity, self.weaponentity.anim_idle, TRUE, FALSE, FALSE); + } } void SpawnThrownWeapon (vector org, float w) @@ -542,9 +474,9 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht if (!self.animstate_override) { if (random() > 0.5) - setanim(self, self.anim_pain1, FALSE, TRUE, TRUE); + animdecide_setaction(self, ANIMACTION_PAIN1, TRUE); else - setanim(self, self.anim_pain2, FALSE, TRUE, TRUE); + animdecide_setaction(self, ANIMACTION_PAIN2, TRUE); } } @@ -771,9 +703,9 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.respawn_countdown = -1; // do not count down self.death_time = time; if (random() < 0.5) - setanim(self, self.anim_die1, FALSE, TRUE, TRUE); + animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD1, TRUE); else - setanim(self, self.anim_die2, FALSE, TRUE, TRUE); + animdecide_setstate(self, self.anim_state | ANIMSTATE_DEAD2, TRUE); if (self.maxs_z > 5) { self.maxs_z = 5; @@ -1252,7 +1184,7 @@ void FakeGlobalSound(string sample, float chan, float voicetype) case VOICETYPE_TAUNT: if(self.classname == "player") if(self.deadflag == DEAD_NO) - setanim(self, self.anim_taunt, FALSE, TRUE, TRUE); + animdecide_setaction(self, ANIMACTION_TAUNT, TRUE); if(!sv_taunt) break; if(sv_gentle) @@ -1349,7 +1281,7 @@ void GlobalSound(string sample, float chan, float voicetype) case VOICETYPE_TAUNT: if(self.classname == "player") if(self.deadflag == DEAD_NO) - setanim(self, self.anim_taunt, FALSE, TRUE, TRUE); + animdecide_setaction(self, ANIMACTION_TAUNT, TRUE); if(!sv_taunt) break; if(sv_gentle) diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index 402b692af1..4ab5ade72b 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -1048,23 +1048,13 @@ void weapon_thinkf(float fr, float t, void() func) // The shoot animation looks TERRIBLE without animation blending! Yay for moonwalking while shooting! //anim = self.anim_shoot; - if (restartanim) if (t) if (!self.crouch) // shoot anim stands up, this looks bad { - vector anim; if(self.weapon == WEP_SHOTGUN && self.BUTTON_ATCK2) - { - anim = self.anim_melee; - anim_z = anim_y / (t + sys_frametime); - setanim(self, anim, FALSE, TRUE, TRUE); - } - else if (self.animstate_startframe == self.anim_idle_x) // only allow shoot anim to override idle animation until we have animation blending - { - anim = self.anim_shoot; - anim_z = anim_y / (t + sys_frametime); - setanim(self, anim, FALSE, TRUE, TRUE); - } + animdecide_setaction(self, ANIMACTION_MELEE, restartanim); + else + animdecide_setaction(self, ANIMACTION_SHOOT, restartanim); } } diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index 9068fa75bf..d81f229245 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -116,44 +116,6 @@ float maxclients; .float animstate_override; .float animstate_looping; -// player animation data for this model -// each vector is as follows: -// _x = startframe -// _y = numframes -// _z = framerate -.vector anim_die1; // player dies -.vector anim_die2; // player dies differently -.vector anim_draw; // player pulls out a weapon -// .vector anim_duck; // player crouches (from idle to duckidle) -.vector anim_duckwalk; // player walking while crouching -.vector anim_duckjump; // player jumping from a crouch -.vector anim_duckidle; // player idling while crouching -.vector anim_idle; // player standing -.vector anim_jump; // player jump -.vector anim_pain1; // player flinches from pain -.vector anim_pain2; // player flinches from pain, differently -.vector anim_shoot; // player shoots -.vector anim_taunt; // player taunts others (FIXME: no code references this) -.vector anim_run; // player running forward -.vector anim_runbackwards; // player running backward -.vector anim_strafeleft; // player shuffling left quickly -.vector anim_straferight; // player shuffling right quickly -//.vector anim_dead1; // player dead (must be identical to last frame of die1) -//.vector anim_dead2; // player dead (must be identical to last frame of die2) -.vector anim_forwardright; // player running forward and right -.vector anim_forwardleft; // player running forward and left -.vector anim_backright; // player running backward and right -.vector anim_backleft; // player running back and left -.vector anim_melee; // player doing the melee action -.vector anim_duck; // player doing the melee action -.vector anim_duckwalkbackwards; -.vector anim_duckwalkstrafeleft; -.vector anim_duckwalkstraferight; -.vector anim_duckwalkforwardright; -.vector anim_duckwalkforwardleft; -.vector anim_duckwalkbackright; -.vector anim_duckwalkbackleft; - // weapon animation vectors: .vector anim_fire1; .vector anim_fire2; diff --git a/qcsrc/server/mutators/mutator_dodging.qc b/qcsrc/server/mutators/mutator_dodging.qc index bdd39b1283..969c980a29 100644 --- a/qcsrc/server/mutators/mutator_dodging.qc +++ b/qcsrc/server/mutators/mutator_dodging.qc @@ -117,7 +117,7 @@ MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) { if (autocvar_sv_dodging_sound == 1) PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND); - setanim(self, self.anim_jump, TRUE, FALSE, TRUE); + animdecide_setaction(self, ANIMACTION_JUMP, TRUE); self.dodging_single_action = 0; } diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 028519372f..0ef33f8540 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -22,6 +22,7 @@ sys-post.qh ../common/command/generic.qh ../common/command/shared_defs.qh ../common/net_notice.qh +../common/animdecide.qh autocvars.qh constants.qh @@ -229,6 +230,7 @@ mutators/mutator_superspec.qc ../warpzonelib/util_server.qc ../warpzonelib/server.qc +../common/animdecide.qc ../common/util.qc ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail diff --git a/qcsrc/server/t_jumppads.qc b/qcsrc/server/t_jumppads.qc index 8923c19f18..2458e262f2 100644 --- a/qcsrc/server/t_jumppads.qc +++ b/qcsrc/server/t_jumppads.qc @@ -200,14 +200,8 @@ void trigger_push_touch() else other.lastteleporttime = time; - if (!other.animstate_override) if (other.deadflag == DEAD_NO) - { - if (other.crouch) - setanim(other, other.anim_duckjump, FALSE, TRUE, TRUE); - else - setanim(other, other.anim_jump, FALSE, TRUE, TRUE); - } + animdecide_setaction(other, ANIMACTION_JUMP, TRUE); } else other.jumppadcount = TRUE; diff --git a/qcsrc/server/w_electro.qc b/qcsrc/server/w_electro.qc index 7a91cbd89c..575ff677e2 100644 --- a/qcsrc/server/w_electro.qc +++ b/qcsrc/server/w_electro.qc @@ -436,13 +436,8 @@ float w_electro(float req) { if(autocvar_g_balance_electro_lightning) if(self.BUTTON_ATCK_prev) - { - // prolong the animtime while the gun is being fired - if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y) - weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_electro_primary_animtime, w_ready); - else - weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready); - } + weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_electro_primary_animtime, w_ready); + if (weapon_prepareattack(0, (autocvar_g_balance_electro_lightning ? 0 : autocvar_g_balance_electro_primary_refire))) { if(autocvar_g_balance_electro_lightning) -- 2.39.2