From 274b6dd34a99fdbe806401ae2e7a9146ca032fe2 Mon Sep 17 00:00:00 2001 From: lordhavoc Date: Fri, 7 Dec 2007 18:08:17 +0000 Subject: [PATCH] implemented models/player/whatever.md3.animinfo file support so md3 player models can be used (also .dpm and all other model formats) added models/player/template.md3.animinfo example note: animinfo can not be used for zym player models because it does not include dead1/dead2 anims - this can be added if needed git-svn-id: svn://svn.icculus.org/nexuiz/trunk@3007 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/models/player/template.md3.animinfo | 21 ++ data/qcsrc/server/cl_client.qc | 11 +- data/qcsrc/server/cl_physics.qc | 5 + data/qcsrc/server/cl_player.qc | 237 +++++++++++++++++------ data/qcsrc/server/cl_weapons.qc | 1 + data/qcsrc/server/cl_weaponsystem.qc | 9 + data/qcsrc/server/defs.qh | 43 +++- data/weapons.cfg | 8 +- pro/weaponsPro.cfg | 6 +- 9 files changed, 268 insertions(+), 73 deletions(-) create mode 100644 data/models/player/template.md3.animinfo diff --git a/data/models/player/template.md3.animinfo b/data/models/player/template.md3.animinfo new file mode 100644 index 000000000..7eda00798 --- /dev/null +++ b/data/models/player/template.md3.animinfo @@ -0,0 +1,21 @@ + 0 40 20 // die1 : die + 40 40 20 // die2 : die differently + 80 6 20 // draw : raise weapon + 86 6 20 // duck : crouch quickly + 92 12 20 // duckwalk : crouch walking +104 10 20 // duckjump : jump from crouching position, stays on last frame until you land +114 20 20 // duckidle : crouched +134 30 20 // idle : standing +164 10 20 // jump : jump, stays on last frame until you land +174 10 20 // pain1 : flinch from pain +184 10 20 // pain2 : flinch differently +194 6 20 // shoot : 300ms shooting anim, may be played faster/slower by code, used for all weapons +200 1 20 // taunt : not used +201 10 20 // run : run forward +211 10 20 // runbackwards : run backwards +221 10 20 // strafeleft : fast shuffling to the left +231 10 20 // straferight : fast shuffling to the right +241 10 20 // forwardright : running forward and right +251 10 20 // forwardleft : running forward and left +261 10 20 // backright : running backward and right +271 10 20 // backleft : running backward and left \ No newline at end of file diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 713f02836..51950a488 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -248,7 +248,8 @@ void setmodel_lod(entity e, string modelname) #ifdef ALLOW_VARIABLE_LOD string s; - s = strcat(substring(modelname, 0, strlen(modelname) - 4), "_1.zym"); + // FIXME: this only supports 3-letter extensions + s = strcat(substring(modelname, 0, strlen(modelname) - 4), "_1", substring(modelname, 0, strlen(modelname) - 4)); if(fexists(s)) { precache_model(s); @@ -258,7 +259,7 @@ void setmodel_lod(entity e, string modelname) else self.modelindex_lod1 = -1; - s = strcat(substring(modelname, 0, strlen(modelname) - 4), "_2.zym"); + s = strcat(substring(modelname, 0, strlen(modelname) - 4), "_2", substring(modelname, 0, strlen(modelname) - 4)); if(fexists(s)) { precache_model(s); @@ -281,6 +282,7 @@ void setmodel_lod(entity e, string modelname) precache_model(modelname); setmodel(e, modelname); // players have high precision #endif + player_setupanimsformodel(); } /* @@ -332,9 +334,7 @@ void PutObserverInServer (void) self.pauseregen_finished = 0; self.damageforcescale = 0; self.death_time = 0; - self.dead_time = 0; self.dead_frame = 0; - self.die_frame = 0; self.deaths = 0; self.alpha = 0; self.scale = 0; @@ -451,9 +451,7 @@ void PutClientInServer (void) self.pauseregen_finished = time + cvar("g_balance_pause_health_regen_spawn"); self.damageforcescale = 2; self.death_time = 0; - self.dead_time = 0; self.dead_frame = 0; - self.die_frame = 0; self.alpha = 0; self.scale = 0; self.fade_time = 0; @@ -1386,6 +1384,7 @@ void PlayerPreThink (void) self.crouch = TRUE; self.view_ofs = PL_CROUCH_VIEW_OFS; setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); + player_setanim(self.anim_duck, FALSE, TRUE, TRUE); } } else diff --git a/data/qcsrc/server/cl_physics.qc b/data/qcsrc/server/cl_physics.qc index d86c5c0a7..a3f950a4e 100644 --- a/data/qcsrc/server/cl_physics.qc +++ b/data/qcsrc/server/cl_physics.qc @@ -74,6 +74,11 @@ void PlayerJump (void) self.flags = self.flags - FL_ONGROUND; self.flags = self.flags - FL_JUMPRELEASED; + + if (self.crouch) + player_setanim(self.anim_duckjump, FALSE, TRUE, TRUE); + else + player_setanim(self.anim_jump, FALSE, TRUE, TRUE); } void() CheckWaterJump = diff --git a/data/qcsrc/server/cl_player.qc b/data/qcsrc/server/cl_player.qc index ccb245aa9..f8f252e64 100644 --- a/data/qcsrc/server/cl_player.qc +++ b/data/qcsrc/server/cl_player.qc @@ -1,7 +1,3 @@ -$frame die1 die2 draw duck duckwalk duckjump duckidle idle -$frame jump pain1 pain2 shoot taunt run runbackwards -$frame strafeleft straferight dead1 dead2 forwardright -$frame forwardleft backright backleft // changes by LordHavoc on 03/29/04 and 03/30/04 at Vermeulen's request // merged player_run and player_stand to player_anim @@ -32,7 +28,16 @@ void CopyBody(float keepvelocity) self.damageforcescale = oldself.damageforcescale; self.effects = oldself.effects; self.event_damage = oldself.event_damage; + self.animstate_startframe = oldself.animstate_startframe; + self.animstate_numframes = oldself.animstate_numframes; + self.animstate_framerate = oldself.animstate_framerate; + self.animstate_starttime = oldself.animstate_starttime; + self.animstate_endtime = oldself.animstate_endtime; + self.animstate_override = oldself.animstate_override; + self.animstate_looping = oldself.animstate_looping; self.frame = oldself.frame; + self.dead_frame = oldself.dead_frame; + self.pain_finished = oldself.pain_finished; self.health = oldself.health; self.armorvalue = oldself.armorvalue; self.armortype = oldself.armortype; @@ -58,11 +63,137 @@ void CopyBody(float keepvelocity) self = oldself; } +float animparseerror; +vector(float animfile) animparseline = +{ + local string line; + local float c; + local vector anim; + if (animfile < 0) + return '0 1 2'; + line = fgets(animfile); + c = tokenize(line); + if (c != 3) + { + animparseerror = TRUE; + return '0 1 2'; + } + anim_x = stof(argv(0)); + anim_y = stof(argv(1)); + anim_z = stof(argv(2)); + // don't allow completely bogus values + if (anim_x < 0 || anim_y < 1 || anim_z < 0.001) + anim = '0 1 2'; + return anim; +}; + +void() player_setupanimsformodel = +{ + local string animfilename; + local float animfile; + // defaults for legacy .zym models without animinfo files + self.anim_die1 = '0 1 0.5'; // 2 seconds + self.anim_die2 = '1 1 0.5'; // 2 seconds + self.anim_draw = '2 1 3'; // TODO: analyze models and set framerate + self.anim_duck = '3 1 100'; // this anim seems bogus in most models, so make it play VERY briefly! + self.anim_duckwalk = '4 1 1'; + self.anim_duckjump = '5 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_duckidle = '6 1 1'; + self.anim_idle = '7 1 1'; + self.anim_jump = '8 1 100'; // zym anims keep playing until changed, so this only has to start the anim, landing will end it + self.anim_pain1 = '9 1 2'; // 0.5 seconds + self.anim_pain2 = '10 1 2'; // 0.5 seconds + self.anim_shoot = '11 1 5'; // TODO: analyze models and set framerate + self.anim_taunt = '12 1 1'; // FIXME? there is no code using this anim + self.anim_run = '13 1 1'; + self.anim_runbackwards = '14 1 1'; + self.anim_strafeleft = '15 1 1'; + self.anim_straferight = '16 1 1'; + self.anim_dead1 = '17 1 1'; + self.anim_dead2 = '18 1 1'; + self.anim_forwardright = '19 1 1'; + self.anim_forwardleft = '20 1 1'; + self.anim_backright = '21 1 1'; + self.anim_backleft = '22 1 1'; + animparseerror = FALSE; + animfilename = strcat(self.model, ".animinfo"); + animfile = fopen(animfilename, FILE_READ); + if (animfile >= 0) + { + self.anim_die1 = animparseline(animfile); + self.anim_die2 = animparseline(animfile); + self.anim_draw = animparseline(animfile); + self.anim_duck = animparseline(animfile); + self.anim_duckwalk = animparseline(animfile); + self.anim_duckjump = animparseline(animfile); + self.anim_duckidle = animparseline(animfile); + self.anim_idle = animparseline(animfile); + self.anim_jump = animparseline(animfile); + self.anim_pain1 = animparseline(animfile); + self.anim_pain2 = animparseline(animfile); + self.anim_shoot = animparseline(animfile); + self.anim_taunt = animparseline(animfile); + self.anim_run = animparseline(animfile); + self.anim_runbackwards = animparseline(animfile); + self.anim_strafeleft = animparseline(animfile); + self.anim_straferight = animparseline(animfile); + self.anim_forwardright = animparseline(animfile); + self.anim_forwardleft = animparseline(animfile); + self.anim_backright = animparseline(animfile); + self.anim_backleft = animparseline(animfile); + fclose(animfile); + + // derived anims + self.anim_dead1 = '0 1 1' + '1 0 0' * (self.anim_die1_x + self.anim_die1_y - 1); + self.anim_dead2 = '0 1 1' + '1 0 0' * (self.anim_die2_x + self.anim_die2_y - 1); + + if (animparseerror) + print("Parse error in ", animfilename, ", some player animations are broken\n"); + } + else + dprint("File ", animfilename, " not found, assuming legacy .zym model animation timings\n"); + // reset animstate now + player_setanim(self.anim_idle, TRUE, FALSE, TRUE); +}; + +void(vector anim, float looping, float override, float restart) player_setanim = +{ + if (!restart) + if (anim_x != self.animstate_startframe) + if (anim_y != self.animstate_numframes) + if (anim_z != self.animstate_framerate) + return; + self.animstate_startframe = anim_x; + self.animstate_numframes = anim_y; + self.animstate_framerate = anim_z; + self.animstate_starttime = time; + self.animstate_endtime = time + self.animstate_numframes / self.animstate_framerate; + self.animstate_looping = looping; + self.animstate_override = override; + self.frame = self.animstate_startframe; +}; + +void() player_updateframe = +{ + if (time >= self.animstate_endtime) + { + if (self.animstate_looping) + { + self.animstate_starttime = self.animstate_endtime; + self.animstate_endtime = self.animstate_endtime + self.animstate_numframes / self.animstate_framerate; + } + self.animstate_override = FALSE; + } + self.frame = self.animstate_startframe + bound(0, (time - self.animstate_starttime) * self.animstate_framerate, self.animstate_numframes - 1); +}; + void player_anim (void) { + player_updateframe(); + if (self.deadflag != DEAD_NO) { - if (time > self.dead_time) + if (time > self.animstate_endtime) { if (self.maxs_z > 5) { @@ -71,53 +202,48 @@ void player_anim (void) } self.frame = self.dead_frame; } - else - self.frame = self.die_frame; return; } - - if (self.crouch) - { - if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20) - self.frame = $duckwalk; - else - self.frame = $duckidle; - } - else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20) - { - if (self.movement_x > 0 && self.movement_y == 0) - self.frame = $run; - else if (self.movement_x < 0 && self.movement_y == 0) - self.frame = $runbackwards; - else if (self.movement_x == 0 && self.movement_y > 0) - self.frame = $straferight; - else if (self.movement_x == 0 && self.movement_y < 0) - self.frame = $strafeleft; - else if (self.movement_x > 0 && self.movement_y > 0) - self.frame = $forwardright; - else if (self.movement_x > 0 && self.movement_y < 0) - self.frame = $forwardleft; - else if (self.movement_x < 0 && self.movement_y > 0) - self.frame = $backright; - else if (self.movement_x < 0 && self.movement_y < 0) - self.frame = $backleft; - else - self.frame = $run; - } - else if (self.pain_finished > time) - self.frame = self.pain_frame; - else if (ATTACK_FINISHED(self) > time) - self.frame = $shoot; - else - self.frame = $idle; - - if (!(self.flags & FL_ONGROUND)) + if (!self.animstate_override) { - if (self.crouch) - self.frame = $duckidle; // if player is crouching while in air, show crouch frame + if (!(self.flags & FL_ONGROUND)) + { + if (self.crouch) + player_setanim(self.anim_duckjump, FALSE, TRUE, FALSE); + else + player_setanim(self.anim_jump, FALSE, TRUE, FALSE); + } + else if (self.crouch) + { + if (self.movement_x * self.movement_x + self.movement_y * self.movement_y > 20) + player_setanim(self.anim_duckwalk, TRUE, FALSE, FALSE); + else + player_setanim(self.anim_duckidle, TRUE, FALSE, FALSE); + } + else if ((self.movement_x * self.movement_x + self.movement_y * self.movement_y) > 20) + { + if (self.movement_x > 0 && self.movement_y == 0) + player_setanim(self.anim_run, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y == 0) + player_setanim(self.anim_runbackwards, TRUE, FALSE, FALSE); + else if (self.movement_x == 0 && self.movement_y > 0) + player_setanim(self.anim_straferight, TRUE, FALSE, FALSE); + else if (self.movement_x == 0 && self.movement_y < 0) + player_setanim(self.anim_strafeleft, TRUE, FALSE, FALSE); + else if (self.movement_x > 0 && self.movement_y > 0) + player_setanim(self.anim_forwardright, TRUE, FALSE, FALSE); + else if (self.movement_x > 0 && self.movement_y < 0) + player_setanim(self.anim_forwardleft, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y > 0) + player_setanim(self.anim_backright, TRUE, FALSE, FALSE); + else if (self.movement_x < 0 && self.movement_y < 0) + player_setanim(self.anim_backleft, TRUE, FALSE, FALSE); + else + player_setanim(self.anim_run, TRUE, FALSE, FALSE); + } else - self.frame = $jump; + player_setanim(self.anim_idle, TRUE, FALSE, FALSE); } } //End change by Supajoe on 11:44 PM EST 11/16/03 (Subject: Player animations) @@ -173,7 +299,6 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float // don't use any animations as a gib self.frame = 0; self.dead_frame = 0; - self.die_frame = 0; // view just above the floor self.view_ofs = '0 0 4'; @@ -224,9 +349,9 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht if (self.pain_finished < time) //Don't switch pain sequences like crazy { if (random() > 0.5) - self.pain_frame = $pain1; + player_setanim(self.anim_pain1, FALSE, TRUE, TRUE); else - self.pain_frame = $pain2; + player_setanim(self.anim_pain2, FALSE, TRUE, TRUE); self.pain_finished = time + 0.5; //Supajoe // throw off bot aim temporarily @@ -360,20 +485,16 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht self.respawn_countdown = 10; // first number to count down from is 10 else self.respawn_countdown = -1; // do not count down - // when to switch to the dead_frame - self.dead_time = time + 2; if (random() < 0.5) { - self.die_frame = $die1; - self.dead_frame = $dead1; + player_setanim(self.anim_die1, FALSE, TRUE, TRUE); + self.dead_frame = self.anim_dead1_x; } else { - self.die_frame = $die2; - self.dead_frame = $dead2; + player_setanim(self.anim_die2, FALSE, TRUE, TRUE); + self.dead_frame = self.anim_dead2_x; } - // start the animation - player_anim(); // set damage function to corpse damage self.event_damage = PlayerCorpseDamage; // call the corpse damage function just in case it wants to gib diff --git a/data/qcsrc/server/cl_weapons.qc b/data/qcsrc/server/cl_weapons.qc index 679bd2301..c4e889068 100644 --- a/data/qcsrc/server/cl_weapons.qc +++ b/data/qcsrc/server/cl_weapons.qc @@ -231,6 +231,7 @@ void() W_WeaponFrame = { if (self.weaponentity.state == WS_CLEAR) { + player_setanim(self.anim_draw, FALSE, TRUE, TRUE); self.weaponentity.state = WS_RAISE; weapon_action(self.switchweapon, WR_SETUP); // VorteX: add player model weapon select frame here diff --git a/data/qcsrc/server/cl_weaponsystem.qc b/data/qcsrc/server/cl_weaponsystem.qc index 5598149f5..3fbfc35ac 100644 --- a/data/qcsrc/server/cl_weaponsystem.qc +++ b/data/qcsrc/server/cl_weaponsystem.qc @@ -410,6 +410,15 @@ void(float fr, float t, void() func) weapon_thinkf = // VorteX: haste can be added here self.weapon_nextthink = max(time, self.weapon_nextthink_lastframe + t); self.weapon_think = func; + + if (fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) + if (t) + { + local vector anim; + anim = self.anim_shoot; + anim_z = anim_y / t; + player_setanim(anim, FALSE, TRUE, TRUE); + } }; void(float spd, vector org) weapon_boblayer1 = diff --git a/data/qcsrc/server/defs.qh b/data/qcsrc/server/defs.qh index cb2e55e18..d85de7c00 100644 --- a/data/qcsrc/server/defs.qh +++ b/data/qcsrc/server/defs.qh @@ -68,12 +68,51 @@ float maxclients; .float play_time; .float death_time; -.float dead_time; .float dead_frame; -.float die_frame; .float fade_time; .float fade_rate; +// player animation state +.float animstate_startframe; +.float animstate_numframes; +.float animstate_framerate; +.float animstate_starttime; +.float animstate_endtime; +.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 + +void() player_setupanimsformodel; +void(vector anim, float looping, float override, float restart) player_setanim; + .string mdl; .string playermodel; diff --git a/data/weapons.cfg b/data/weapons.cfg index 64f9422dc..2c8e28b93 100644 --- a/data/weapons.cfg +++ b/data/weapons.cfg @@ -102,7 +102,7 @@ set g_balance_electro_primary_radius 150 set g_balance_electro_primary_speed 2000 set g_balance_electro_primary_lifetime 30 set g_balance_electro_primary_refire 0.6 -set g_balance_electro_primary_animtime 0.05 +set g_balance_electro_primary_animtime 0.3 set g_balance_electro_primary_ammo 2 set g_balance_electro_secondary_damage 60 set g_balance_electro_secondary_edgedamage 0 @@ -112,7 +112,7 @@ set g_balance_electro_secondary_speed 900 set g_balance_electro_secondary_speed_up 200 set g_balance_electro_secondary_lifetime 5 set g_balance_electro_secondary_refire 0.3 -set g_balance_electro_secondary_animtime 0.05 +set g_balance_electro_secondary_animtime 0.3 set g_balance_electro_secondary_ammo 2 set g_balance_electro_combo_damage 70 set g_balance_electro_combo_edgedamage 0 @@ -128,7 +128,7 @@ set g_balance_crylink_primary_spread 0.06 set g_balance_crylink_primary_shots 4 set g_balance_crylink_primary_lifetime 30 set g_balance_crylink_primary_refire 0.25 -set g_balance_crylink_primary_animtime 0.15 +set g_balance_crylink_primary_animtime 0.3 set g_balance_crylink_primary_ammo 1 set g_balance_crylink_secondary_damage 20 set g_balance_crylink_secondary_edgedamage 0 @@ -139,7 +139,7 @@ set g_balance_crylink_secondary_spread 0.08 set g_balance_crylink_secondary_shots 7 set g_balance_crylink_secondary_lifetime 30 set g_balance_crylink_secondary_refire 0.5 -set g_balance_crylink_secondary_animtime 0.15 +set g_balance_crylink_secondary_animtime 0.3 set g_balance_crylink_secondary_ammo 3 set g_balance_nex_damage 140 diff --git a/pro/weaponsPro.cfg b/pro/weaponsPro.cfg index f77dfe62a..e8a9e15c3 100644 --- a/pro/weaponsPro.cfg +++ b/pro/weaponsPro.cfg @@ -102,7 +102,7 @@ set g_balance_electro_primary_radius 200 set g_balance_electro_primary_speed 2000 set g_balance_electro_primary_lifetime 30 set g_balance_electro_primary_refire 0.5 -set g_balance_electro_primary_animtime 0.05 +set g_balance_electro_primary_animtime 0.3 set g_balance_electro_primary_ammo 2 set g_balance_electro_secondary_damage 50 set g_balance_electro_secondary_edgedamage 10 @@ -112,7 +112,7 @@ set g_balance_electro_secondary_speed 700 set g_balance_electro_secondary_speed_up 200 set g_balance_electro_secondary_lifetime 5 set g_balance_electro_secondary_refire 0.3 -set g_balance_electro_secondary_animtime 0.05 +set g_balance_electro_secondary_animtime 0.3 set g_balance_electro_secondary_ammo 2 set g_balance_electro_combo_damage 70 set g_balance_electro_combo_edgedamage 0 @@ -139,7 +139,7 @@ set g_balance_crylink_secondary_spread 0.08 set g_balance_crylink_secondary_shots 5 set g_balance_crylink_secondary_lifetime 30 set g_balance_crylink_secondary_refire 0.6 -set g_balance_crylink_secondary_animtime 0.15 +set g_balance_crylink_secondary_animtime 0.3 set g_balance_crylink_secondary_ammo 5 set g_balance_nex_damage 70 -- 2.39.2