#pragma once // must be called at least once to initialize, or when modelindex is changed void animdecide_load_if_needed(entity e); // client side frame inferring void animdecide_setimplicitstate(entity e, float onground); void animdecide_setframes(entity e, bool support_blending, .int fld_frame, .int fld_frame1time, .int fld_frame2, .int fld_frame2time); CLASS(Animation, Object) ATTRIB(Animation, m_framenames, string); STATIC_METHOD(Animation, getframe, int(Animation this, int mdlidx)) { FOREACH_WORD(this.m_framenames, true, { int f = frameforname(mdlidx, it); if (f != -1) return f; }); #ifdef CSQC LOG_DEBUGF("Missing animation for %s: %s", modelnameforindex(mdlidx), this.registered_id); #endif return -1; } ENDCLASS(Animation) REGISTRY(Animations, BITS(8)) REGISTER_REGISTRY(Animations) #define Animations_from(id) _Animations_from(id, NULL) #define WriteAnimation(to, it) WriteRegistered(Animations, to, it) #define ReadAnimation() ReadRegistered(Animations) #define REGISTER_ANIMATION(id, framenames) \ .vector anim_##id; \ REGISTER(Animations, ANIM_##id, m_id, NEW(Animation)) { \ this.m_framenames = framenames; \ } vector anim_vec(Animation anim, int mdlidx, int numframes, float framerate) { vector v; v.x = Animation_getframe(anim, mdlidx); v.y = numframes; v.z = framerate; return v; } // player animation data for this model // each vector is as follows: // _x = startframe // _y = numframes // _z = framerate /** player dies */ REGISTER_ANIMATION(die1, "dieone groupified_0_anim"); /** player dies differently */ REGISTER_ANIMATION(die2, "dietwo groupified_1_anim"); /** player pulls out a weapon */ REGISTER_ANIMATION(draw, "draw groupified_2_anim"); REGISTER_ANIMATION(duck, "duck groupified_3_anim"); /** player walking while crouching */ REGISTER_ANIMATION(duckwalk, "duckwalk groupified_4_anim"); /** player jumping from a crouch */ REGISTER_ANIMATION(duckjump, "duckjump groupified_5_anim"); /** player idling while crouching */ REGISTER_ANIMATION(duckidle, "duckidle groupified_6_anim"); /** player standing */ REGISTER_ANIMATION(idle, "idle groupified_7_anim"); /** player jump */ REGISTER_ANIMATION(jump, "jump groupified_8_anim"); /** player flinches from pain */ REGISTER_ANIMATION(pain1, "painone groupified_9_anim"); /** player flinches from pain, differently */ REGISTER_ANIMATION(pain2, "paintwo groupified_10_anim"); /** player shoots */ REGISTER_ANIMATION(shoot, "shoot groupified_11_anim"); /** player taunts others (FIXME: no code references this) */ REGISTER_ANIMATION(taunt, "taunt groupified_12_anim"); /** player running forward */ REGISTER_ANIMATION(run, "run groupified_13_anim"); /** player running backward */ REGISTER_ANIMATION(runbackwards, "runbackwards groupified_14_anim"); /** player shuffling left quickly */ REGISTER_ANIMATION(strafeleft, "strafeleft groupified_15_anim"); /** player shuffling right quickly */ REGISTER_ANIMATION(straferight, "straferight groupified_16_anim"); /** */ REGISTER_ANIMATION(dead1, "deadone groupified_17_anim"); /** */ REGISTER_ANIMATION(dead2, "deadtwo groupified_18_anim"); /** player running forward and right */ REGISTER_ANIMATION(forwardright, "forwardright groupified_19_anim"); /** player running forward and left */ REGISTER_ANIMATION(forwardleft, "forwardleft groupified_20_anim"); /** player running backward and right */ REGISTER_ANIMATION(backright, "backright groupified_21_anim"); /** player running back and left */ REGISTER_ANIMATION(backleft, "backleft groupified_22_anim"); /** player doing the melee action */ REGISTER_ANIMATION(melee, "melee groupified_23_anim"); REGISTER_ANIMATION(duckwalkbackwards, "duckwalkbackwards groupified_24_anim"); REGISTER_ANIMATION(duckwalkstrafeleft, "duckwalkstrafeleft duckstrafeleft groupified_25_anim"); REGISTER_ANIMATION(duckwalkstraferight, "duckwalkstraferight duckstraferight groupified_26_anim"); REGISTER_ANIMATION(duckwalkforwardright, "duckwalkforwardright duckforwardright groupified_27_anim"); REGISTER_ANIMATION(duckwalkforwardleft, "duckwalkforwardleft groupified_28_anim"); REGISTER_ANIMATION(duckwalkbackright, "duckwalkbackright duckbackwardright groupified_29_anim"); REGISTER_ANIMATION(duckwalkbackleft, "duckwalkbackleft duckbackwardleft groupified_30_anim"); .float animdecide_modelindex; // please network this one .int anim_state; .float anim_time; .float anim_lower_action; .float anim_lower_time; .float anim_upper_action; .float anim_upper_time; // when copying entities, copy these too .int anim_implicit_state; .float anim_implicit_time; .float anim_lower_implicit_action; .float anim_lower_implicit_time; .float anim_upper_implicit_action; .float anim_upper_implicit_time; // explicit anim states (networked) void animdecide_setstate(entity e, int newstate, float restart); const int ANIMSTATE_DEAD1 = BIT(0); // base frames: die1 const int ANIMSTATE_DEAD2 = BIT(1); // base frames: die2 const int ANIMSTATE_DUCK = BIT(2); // turns walk into duckwalk, jump into duckjump, etc. const int ANIMSTATE_FROZEN = BIT(3); // force idle const int ANIMSTATE_FOLLOW = BIT(4); // also force idle // implicit anim states (inferred from velocity, etc.) const int ANIMIMPLICITSTATE_INAIR = BIT(0); const int ANIMIMPLICITSTATE_FORWARD = BIT(1); const int ANIMIMPLICITSTATE_BACKWARDS = BIT(2); const int ANIMIMPLICITSTATE_LEFT = BIT(3); const int ANIMIMPLICITSTATE_RIGHT = BIT(4); const int ANIMIMPLICITSTATE_JUMPRELEASED = BIT(5); // explicit actions (networked); negative values are for lower body void animdecide_setaction(entity e, float action, float restart); const int ANIMACTION_JUMP = -1; // jump const int ANIMACTION_DRAW = 1; // draw const int ANIMACTION_PAIN1 = 2; // pain const int ANIMACTION_PAIN2 = 3; // pain const int ANIMACTION_SHOOT = 4; // shoot const int ANIMACTION_TAUNT = 5; // taunt const int ANIMACTION_MELEE = 6; // melee