From 1f866bf3638e846e459143ac53b74afe88bacbb1 Mon Sep 17 00:00:00 2001 From: Mario Date: Sun, 26 Apr 2015 21:24:15 +1000 Subject: [PATCH] Possibly unstable, but worth it (move monster animation handling to setanim, rather than setting .frame directly) --- qcsrc/client/csqcmodel_hooks.qc | 1 + qcsrc/common/monsters/monster/afrit.qc | 39 +++++++----- qcsrc/common/monsters/monster/creeper.qc | 32 ++++++---- qcsrc/common/monsters/monster/demon.qc | 28 ++++++--- qcsrc/common/monsters/monster/enforcer.qc | 36 ++++++++--- qcsrc/common/monsters/monster/goomba.qc | 2 +- qcsrc/common/monsters/monster/mage.qc | 29 ++++++--- qcsrc/common/monsters/monster/ogre.qc | 52 +++++++++++----- qcsrc/common/monsters/monster/rotfish.qc | 25 +++++--- qcsrc/common/monsters/monster/rottweiler.qc | 28 ++++++--- qcsrc/common/monsters/monster/scrag.qc | 25 +++++--- qcsrc/common/monsters/monster/shambler.qc | 36 +++++++---- qcsrc/common/monsters/monster/spawn.qc | 20 ++++-- qcsrc/common/monsters/monster/spider.qc | 24 +++++--- qcsrc/common/monsters/monster/vore.qc | 27 +++++--- qcsrc/common/monsters/monster/wyvern.qc | 23 +++++-- qcsrc/common/monsters/monster/zombie.qc | 57 +++++++++++------ qcsrc/common/monsters/monsters.qh | 1 + qcsrc/common/monsters/sv_monsters.qc | 68 +++++++++++++++------ qcsrc/common/monsters/sv_monsters.qh | 20 ++++-- qcsrc/server/cl_client.qc | 14 +++-- qcsrc/server/mutators/base.qh | 5 ++ 22 files changed, 406 insertions(+), 186 deletions(-) diff --git a/qcsrc/client/csqcmodel_hooks.qc b/qcsrc/client/csqcmodel_hooks.qc index c574f4f8f..e63c7d68b 100644 --- a/qcsrc/client/csqcmodel_hooks.qc +++ b/qcsrc/client/csqcmodel_hooks.qc @@ -628,6 +628,7 @@ void CSQCModel_Effects_Apply(void) void CSQCModel_Fade_Apply() { + if(!self.fade_end) { return; } vector org; float alph; org = getpropertyvec(VF_ORIGIN); diff --git a/qcsrc/common/monsters/monster/afrit.qc b/qcsrc/common/monsters/monster/afrit.qc index 3a5458d3f..48bce9e2e 100644 --- a/qcsrc/common/monsters/monster/afrit.qc +++ b/qcsrc/common/monsters/monster/afrit.qc @@ -25,6 +25,7 @@ float autocvar_g_monster_afrit_speed_stop; float autocvar_g_monster_afrit_speed_run; float autocvar_g_monster_afrit_speed_walk; +/* const float afrit_anim_sleep = 0; const float afrit_anim_getup = 1; const float afrit_anim_fly = 2; @@ -32,6 +33,7 @@ const float afrit_anim_pain = 3; const float afrit_anim_attack = 4; const float afrit_anim_die1 = 5; const float afrit_anim_die2 = 6; +*/ .float afrit_targetrange_backup; .float afrit_targetcheck_delay; @@ -91,8 +93,8 @@ float M_Afrit_Attack(float attack_type) case MONSTER_ATTACK_RANGED: { self.attack_finished_single = time + 2; - self.anim_finished = time + 1.3; - self.frame = afrit_anim_attack; + setanim(self, self.anim_shoot, false, true, true); + self.anim_finished = self.animstate_endtime; Monster_Delay(2, 0.3, 0.7, M_Afrit_Attack_Fireball); @@ -118,8 +120,8 @@ float M_Afrit(float req) self.target_range = self.afrit_targetrange_backup; if(Monster_FindTarget(self) != world) { - self.frame = afrit_anim_getup; - self.anim_finished = time + 2.3; + setanim(self, self.anim_draw, false, true, true); + self.anim_finished = self.animstate_endtime; } else { @@ -131,11 +133,11 @@ float M_Afrit(float req) self.fire_endtime = 0; // never burns if(self.flags & FL_ONGROUND) - self.m_anim_idle = afrit_anim_sleep; + self.anim_idle = animfixfps(self, '0 1 0.5', '0 0 0'); else - self.m_anim_idle = afrit_anim_fly; + self.anim_idle = animfixfps(self, '2 1 0.5', '0 0 0'); - if(self.frame == afrit_anim_sleep) + if(self.flags & FL_ONGROUND) self.armorvalue = 0.95; // almost invincible else self.armorvalue = autocvar_g_monsters_armor_blockpercent; @@ -147,17 +149,30 @@ float M_Afrit(float req) frag_damage = 0; // afrit doesn't burn else { - self.pain_finished = time + 0.6; - self.frame = afrit_anim_pain; + setanim(self, self.anim_pain1, true, true, true); } return true; } case MR_DEATH: { - self.frame = (random() >= 0.5) ? afrit_anim_die1 : afrit_anim_die2; + setanim(self, ((random() >= 0.5) ? self.anim_die1 : self.anim_die2), false, true, true); self.superweapons_finished = time + 20; return true; } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '5 1 0.5', none); // 2 seconds + self.anim_die2 = animfixfps(self, '6 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '2 1 1', none); + self.anim_idle = animfixfps(self, '0 1 0.5', none); + self.anim_pain1 = animfixfps(self, '3 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + self.anim_draw = animfixfps(self, '1 1 1', none); + + return true; + } case MR_SETUP: { if(!self.health) self.health = (autocvar_g_monster_afrit_health); @@ -166,10 +181,6 @@ float M_Afrit(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_afrit_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_afrit_damageforcescale); } - self.m_anim_walk = afrit_anim_fly; - self.m_anim_run = afrit_anim_fly; - self.m_anim_idle = afrit_anim_fly; - if(!self.target_range) { self.afrit_targetrange_backup = autocvar_g_monsters_target_range; } else { self.afrit_targetrange_backup = self.target_range; } self.target_range = -1; // special handler diff --git a/qcsrc/common/monsters/monster/creeper.qc b/qcsrc/common/monsters/monster/creeper.qc index 21f4f5ad1..a2cb40ac5 100644 --- a/qcsrc/common/monsters/monster/creeper.qc +++ b/qcsrc/common/monsters/monster/creeper.qc @@ -22,13 +22,15 @@ float autocvar_g_monster_creeper_speed_stop; float autocvar_g_monster_creeper_speed_walk; float autocvar_g_monster_creeper_speed_run; -const float creeper_anim_idle = 0; -const float creeper_anim_walk = 1; -const float creeper_anim_die = 2; +/* +const int creeper_anim_idle = 0; +const int creeper_anim_walk = 1; +const int creeper_anim_die = 2; +*/ -.float creeper_primed; +.bool creeper_primed; -float M_Creeper_Attack(float attack_type) +bool M_Creeper_Attack(int attack_type) { switch(attack_type) { @@ -44,7 +46,7 @@ float M_Creeper_Attack(float attack_type) //Monster_Sound(monstersound_attack, 0, false, CH_SHOTS); Damage (self, world, world, self.health + self.max_health + 200, DEATH_KILL, self.origin, '0 0 0'); // killing monster should be reliable enough self.event_damage = func_null; - self.frame = creeper_anim_idle; + setanim(self, self.anim_idle, true, false, false); } else { @@ -52,7 +54,7 @@ float M_Creeper_Attack(float attack_type) self.creeper_primed = true; self.colormod = '1 0 0'; - self.frame = creeper_anim_idle; + setanim(self, self.anim_idle, true, false, false); self.velocity_x = 0; self.velocity_y = 0; self.state = MONSTER_ATTACK_MELEE; @@ -90,7 +92,17 @@ float M_Creeper(float req) } case MR_DEATH: { - self.frame = creeper_anim_die; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '2 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_run = animfixfps(self, '1 1 1', none); + return true; } case MR_SETUP: @@ -103,11 +115,7 @@ float M_Creeper(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_creeper_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_creeper_damageforcescale); } - self.m_anim_walk = creeper_anim_walk; - self.m_anim_run = creeper_anim_walk; - self.m_anim_idle = creeper_anim_idle; self.monster_loot = spawnfunc_ammo_rockets; - self.frame = creeper_anim_idle; self.colormod = '1 1 1'; return true; diff --git a/qcsrc/common/monsters/monster/demon.qc b/qcsrc/common/monsters/monster/demon.qc index 718246f8b..105bfa4fb 100644 --- a/qcsrc/common/monsters/monster/demon.qc +++ b/qcsrc/common/monsters/monster/demon.qc @@ -24,6 +24,7 @@ float autocvar_g_monster_demon_speed_stop; float autocvar_g_monster_demon_speed_run; float autocvar_g_monster_demon_speed_walk; +/* const float demon_anim_stand = 0; const float demon_anim_walk = 1; const float demon_anim_run = 2; @@ -31,6 +32,7 @@ const float demon_anim_leap = 3; const float demon_anim_pain = 4; const float demon_anim_death = 5; const float demon_anim_attack = 6; +*/ void M_Demon_Attack_Leap_Touch() { @@ -61,13 +63,13 @@ float M_Demon_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_demon_attack_melee_damage), demon_anim_attack, self.attack_range, (autocvar_g_monster_demon_attack_melee_delay), DEATH_MONSTER_DEMON_MELEE, true); + return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_demon_attack_melee_damage), self.anim_melee, self.attack_range, (autocvar_g_monster_demon_attack_melee_delay), DEATH_MONSTER_DEMON_MELEE, true); } case MONSTER_ATTACK_RANGED: { if(vlen(self.enemy.origin - self.origin) <= autocvar_g_monster_demon_attack_leap_mindist) { return false; } makevectors(self.angles); - return Monster_Attack_Leap(demon_anim_leap, M_Demon_Attack_Leap_Touch, v_forward * (autocvar_g_monster_demon_attack_leap_speed) + '0 0 200', (autocvar_g_monster_demon_attack_leap_delay)); + return Monster_Attack_Leap(self.anim_shoot, M_Demon_Attack_Leap_Touch, v_forward * (autocvar_g_monster_demon_attack_leap_speed) + '0 0 200', (autocvar_g_monster_demon_attack_leap_delay)); } } @@ -89,12 +91,25 @@ float M_Demon(float req) case MR_PAIN: { self.pain_finished = time + 0.5; - self.frame = demon_anim_pain; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = demon_anim_death; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '5 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '4 1 2', none); // 0.5 seconds + self.anim_melee = animfixfps(self, '6 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + return true; } case MR_SETUP: @@ -105,12 +120,7 @@ float M_Demon(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_demon_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_demon_damageforcescale); } - self.m_anim_walk = demon_anim_walk; - self.m_anim_run = demon_anim_run; - self.m_anim_idle = demon_anim_stand; - self.monster_loot = spawnfunc_item_health_large; - self.frame = demon_anim_stand; return true; } diff --git a/qcsrc/common/monsters/monster/enforcer.qc b/qcsrc/common/monsters/monster/enforcer.qc index a48a0af15..3560f9366 100644 --- a/qcsrc/common/monsters/monster/enforcer.qc +++ b/qcsrc/common/monsters/monster/enforcer.qc @@ -26,6 +26,7 @@ float autocvar_g_monster_enforcer_speed_stop; float autocvar_g_monster_enforcer_speed_run; float autocvar_g_monster_enforcer_speed_walk; +/* const float enforcer_anim_stand = 0; const float enforcer_anim_walk = 1; const float enforcer_anim_run = 2; @@ -36,6 +37,7 @@ const float enforcer_anim_pain1 = 6; const float enforcer_anim_pain2 = 7; const float enforcer_anim_pain3 = 8; const float enforcer_anim_pain4 = 9; +*/ void M_Enforcer_Attack_Plasma_Explode() { @@ -107,7 +109,7 @@ float M_Enforcer_Attack(float attack_type) case MONSTER_ATTACK_MELEE: case MONSTER_ATTACK_RANGED: { - self.frame = enforcer_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + 0.7; self.anim_finished = time + 0.7 * autocvar_g_monster_enforcer_attack_plasma_shots; self.state = MONSTER_ATTACK_RANGED; @@ -131,19 +133,37 @@ float M_Enforcer(float req) } case MR_PAIN: { + vector anim; switch(floor(random() * 5)) { default: - case 1: self.frame = enforcer_anim_pain1; self.pain_finished = time + 0.3; break; - case 2: self.frame = enforcer_anim_pain2; self.pain_finished = time + 0.4; break; - case 3: self.frame = enforcer_anim_pain3; self.pain_finished = time + 0.7; break; - case 4: self.frame = enforcer_anim_pain4; self.pain_finished = time + 1; break; + case 1: anim = self.anim_pain1; self.pain_finished = time + 0.3; break; + case 2: anim = self.anim_pain2; self.pain_finished = time + 0.4; break; + case 3: anim = self.anim_pain3; self.pain_finished = time + 0.7; break; + case 4: anim = self.anim_pain4; self.pain_finished = time + 1; break; } + setanim(self, anim, true, true, false); return true; } case MR_DEATH: { - self.frame = ((random() > 0.5) ? enforcer_anim_death1 : enforcer_anim_death2); + setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '4 1 0.5', none); // 2 seconds + self.anim_die2 = animfixfps(self, '5 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '6 1 2', none); // 0.5 seconds + self.anim_pain2 = animfixfps(self, '7 1 2', none); // 0.5 seconds + self.anim_pain3 = animfixfps(self, '8 1 2', none); // 0.5 seconds + self.anim_pain4 = animfixfps(self, '9 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + return true; } case MR_SETUP: @@ -154,10 +174,6 @@ float M_Enforcer(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_enforcer_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_enforcer_damageforcescale); } - self.m_anim_walk = enforcer_anim_walk; - self.m_anim_run = enforcer_anim_run; - self.m_anim_idle = enforcer_anim_stand; - self.monster_loot = spawnfunc_item_cells; self.weapon = WEP_CRYLINK; diff --git a/qcsrc/common/monsters/monster/goomba.qc b/qcsrc/common/monsters/monster/goomba.qc index 56f635121..884453467 100644 --- a/qcsrc/common/monsters/monster/goomba.qc +++ b/qcsrc/common/monsters/monster/goomba.qc @@ -61,7 +61,7 @@ bool M_Goomba(int req) { case MR_THINK: { - Monster_Move_2D(self.speed, autocvar_g_monster_goomba_allow_jumpoff, 0, 0); + Monster_Move_2D(self.speed, autocvar_g_monster_goomba_allow_jumpoff); return false; // funny handler here, false means don't do regular moving } case MR_PAIN: diff --git a/qcsrc/common/monsters/monster/mage.qc b/qcsrc/common/monsters/monster/mage.qc index 9535701ff..b1ec4e6af 100644 --- a/qcsrc/common/monsters/monster/mage.qc +++ b/qcsrc/common/monsters/monster/mage.qc @@ -42,12 +42,14 @@ float autocvar_g_monster_mage_speed_stop; float autocvar_g_monster_mage_speed_run; float autocvar_g_monster_mage_speed_walk; +/* const float mage_anim_idle = 0; const float mage_anim_walk = 1; const float mage_anim_attack = 2; const float mage_anim_pain = 3; const float mage_anim_death = 4; const float mage_anim_run = 5; +*/ void() M_Mage_Defend_Heal; void() M_Mage_Defend_Shield; @@ -243,7 +245,7 @@ void M_Mage_Defend_Heal() if(washealed) { - self.frame = mage_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + (autocvar_g_monster_mage_heal_delay); self.anim_finished = time + 1.5; } @@ -255,7 +257,7 @@ void M_Mage_Attack_Push() RadiusDamage (self, self, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius), world, world, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE, self.enemy); pointparticles(particleeffectnum("TE_EXPLOSION"), self.origin, '0 0 0', 1); - self.frame = mage_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + (autocvar_g_monster_mage_attack_push_delay); } @@ -288,7 +290,7 @@ void M_Mage_Defend_Shield() self.mage_shield_delay = time + (autocvar_g_monster_mage_shield_delay); self.armorvalue = (autocvar_g_monster_mage_shield_blockpercent); self.mage_shield_time = time + (autocvar_g_monster_mage_shield_time); - self.frame = mage_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + 1; self.anim_finished = time + 1; } @@ -318,7 +320,7 @@ float M_Mage_Attack(float attack_type) } else { - self.frame = mage_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + (autocvar_g_monster_mage_attack_spike_delay); self.anim_finished = time + 1; Monster_Delay(1, 0, 0.2, M_Mage_Attack_Spike); @@ -384,7 +386,19 @@ float M_Mage(float req) } case MR_DEATH: { - self.frame = mage_anim_death; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '4 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '3 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '2 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '5 1 1', none); + return true; } case MR_SETUP: @@ -395,12 +409,7 @@ float M_Mage(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_mage_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_mage_damageforcescale); } - self.m_anim_walk = mage_anim_walk; - self.m_anim_run = mage_anim_run; - self.m_anim_idle = mage_anim_idle; - self.monster_loot = spawnfunc_item_health_large; - self.frame = mage_anim_walk; return true; } diff --git a/qcsrc/common/monsters/monster/ogre.qc b/qcsrc/common/monsters/monster/ogre.qc index ceb4d73fd..cbcd98524 100644 --- a/qcsrc/common/monsters/monster/ogre.qc +++ b/qcsrc/common/monsters/monster/ogre.qc @@ -44,6 +44,7 @@ float autocvar_g_monster_ogre_speed_stop; float autocvar_g_monster_ogre_speed_run; float autocvar_g_monster_ogre_speed_walk; +/* const float ogre_anim_idle = 0; const float ogre_anim_walk = 1; const float ogre_anim_run = 2; @@ -58,6 +59,7 @@ const float ogre_anim_pain5 = 10; const float ogre_anim_death1 = 11; const float ogre_anim_death2 = 12; const float ogre_anim_pull = 13; +*/ void M_Ogre_Attack_MachineGun() { @@ -257,7 +259,7 @@ void M_Ogre_Attack_Chainsaw() if(time >= self.cnt + meleetime) { // melee is finished - self.realowner.frame = ogre_anim_idle; + setanim(self.realowner, self.realowner.anim_idle, true, false, false); remove(self); return; } @@ -280,7 +282,7 @@ float M_Ogre_Attack(float attack_type) if(vdir_z > 0.7) { self.attack_finished_single = time + 1.2; - self.frame = ogre_anim_shoot; + setanim(self, self.anim_pain1, true, true, false); self.state = MONSTER_ATTACK_RANGED; Monster_Delay(2, 0.1, 0.4, M_Ogre_Attack_MachineGun); return 2; @@ -293,7 +295,7 @@ float M_Ogre_Attack(float attack_type) self.attack_finished_single = time + autocvar_g_monster_ogre_attack_melee_time + autocvar_g_monster_ogre_attack_melee_delay + 0.7; self.anim_finished = self.attack_finished_single; self.state = MONSTER_ATTACK_MELEE; - self.frame = ogre_anim_swing; + setanim(self, self.anim_melee1, true, true, false); return true; } @@ -303,7 +305,7 @@ float M_Ogre_Attack(float attack_type) self.state = MONSTER_ATTACK_RANGED; self.attack_finished_single = time + 1; self.anim_finished = time + 0.5; - self.frame = ogre_anim_shoot; + setanim(self, self.anim_pain1, true, true, false); return true; } } @@ -323,20 +325,42 @@ float M_Ogre(float req) } case MR_PAIN: { + vector anim; switch(floor(random() * 6)) { default: - case 1: self.frame = ogre_anim_pain1; self.anim_finished = time + 0.4; break; - case 2: self.frame = ogre_anim_pain2; self.anim_finished = time + 0.2; break; - case 3: self.frame = ogre_anim_pain3; self.anim_finished = time + 0.5; break; - case 4: self.frame = ogre_anim_pain4; self.anim_finished = time + 1.5; break; - case 5: self.frame = ogre_anim_pain5; self.anim_finished = time + 1.4; break; + case 1: anim = self.anim_pain1; self.anim_finished = time + 0.4; break; + case 2: anim = self.anim_pain2; self.anim_finished = time + 0.2; break; + case 3: anim = self.anim_pain3; self.anim_finished = time + 0.5; break; + case 4: anim = self.anim_pain4; self.anim_finished = time + 1.5; break; + case 5: anim = self.anim_pain5; self.anim_finished = time + 1.4; break; } + setanim(self, anim, true, true, true); return true; } case MR_DEATH: { - self.frame = ((random() >= 0.5) ? ogre_anim_death1 : ogre_anim_death2); + setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '11 1 0.5', none); // 2 seconds + self.anim_die2 = animfixfps(self, '12 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '6 1 2', none); // 0.5 seconds + self.anim_pain2 = animfixfps(self, '7 1 2', none); // 0.5 seconds + self.anim_pain3 = animfixfps(self, '8 1 2', none); // 0.5 seconds + self.anim_pain4 = animfixfps(self, '9 1 2', none); // 0.5 seconds + self.anim_pain5 = animfixfps(self, '10 1 2', none); // 0.5 seconds + self.anim_melee1 = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_melee2 = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '5 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + self.anim_draw = animfixfps(self, '13 1 1', none); + return true; } case MR_SETUP: @@ -347,14 +371,10 @@ float M_Ogre(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_ogre_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_ogre_damageforcescale); } - self.m_anim_walk = ogre_anim_walk; - self.m_anim_run = ogre_anim_run; - self.m_anim_idle = ogre_anim_idle; - self.monster_loot = spawnfunc_item_rockets; self.weapon = WEP_MACHINEGUN; - self.frame = ogre_anim_pull; - self.spawn_time = time + 1; + setanim(self, self.anim_draw, false, true, true); + self.spawn_time = self.animstate_endtime; self.spawnshieldtime = self.spawn_time; return true; diff --git a/qcsrc/common/monsters/monster/rotfish.qc b/qcsrc/common/monsters/monster/rotfish.qc index 91351e589..fc8d3022c 100644 --- a/qcsrc/common/monsters/monster/rotfish.qc +++ b/qcsrc/common/monsters/monster/rotfish.qc @@ -20,10 +20,12 @@ float autocvar_g_monster_rotfish_speed_stop; float autocvar_g_monster_rotfish_speed_run; float autocvar_g_monster_rotfish_speed_walk; +/* const float rotfish_anim_attack = 0; const float rotfish_anim_death = 1; const float rotfish_anim_swim = 2; const float rotfish_anim_pain = 3; +*/ float M_Rotfish_Attack(float attack_type) @@ -32,7 +34,7 @@ float M_Rotfish_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_rotfish_attack_melee_damage), rotfish_anim_attack, self.attack_range, (autocvar_g_monster_rotfish_attack_melee_delay), DEATH_MONSTER_ROTFISH_MELEE, true); + return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_rotfish_attack_melee_damage), self.anim_melee, self.attack_range, (autocvar_g_monster_rotfish_attack_melee_delay), DEATH_MONSTER_ROTFISH_MELEE, true); } case MONSTER_ATTACK_RANGED: { @@ -58,12 +60,24 @@ float M_Rotfish(float req) case MR_PAIN: { self.pain_finished = 0.8; - self.frame = rotfish_anim_pain; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = rotfish_anim_death; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '1 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '2 1 1', none); + self.anim_idle = animfixfps(self, '2 1 1', none); + self.anim_pain1 = animfixfps(self, '3 1 2', none); // 0.5 seconds + self.anim_melee = animfixfps(self, '0 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + return true; } case MR_SETUP: @@ -75,12 +89,7 @@ float M_Rotfish(float req) if(!self.attack_range) { self.attack_range = autocvar_g_monster_rotfish_attack_range; } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_rotfish_damageforcescale); } - self.m_anim_walk = rotfish_anim_swim; - self.m_anim_run = rotfish_anim_swim; - self.m_anim_idle = rotfish_anim_swim; - self.monster_loot = spawnfunc_item_armor_small; - self.frame = rotfish_anim_swim; return true; } diff --git a/qcsrc/common/monsters/monster/rottweiler.qc b/qcsrc/common/monsters/monster/rottweiler.qc index c38cb0610..4149357de 100644 --- a/qcsrc/common/monsters/monster/rottweiler.qc +++ b/qcsrc/common/monsters/monster/rottweiler.qc @@ -19,6 +19,7 @@ float autocvar_g_monster_rottweiler_speed_stop; float autocvar_g_monster_rottweiler_speed_run; float autocvar_g_monster_rottweiler_speed_walk; +/* const float rottweiler_anim_attack1 = 0; const float rottweiler_anim_death1 = 1; const float rottweiler_anim_death2 = 2; @@ -28,6 +29,7 @@ const float rottweiler_anim_run = 5; const float rottweiler_anim_leap = 6; const float rottweiler_anim_idle = 7; const float rottweiler_anim_walk = 8; +*/ float M_Rottweiler_Attack(float attack_type) { @@ -35,7 +37,7 @@ float M_Rottweiler_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_rottweiler_attack_melee_damage), ((random() >= 0.5) ? rottweiler_anim_attack1 : rottweiler_anim_attack2), self.attack_range, (autocvar_g_monster_rottweiler_attack_melee_delay), DEATH_MONSTER_ROTTWEILER, true); + return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_rottweiler_attack_melee_damage), ((random() >= 0.5) ? self.anim_melee1 : self.anim_melee2), self.attack_range, (autocvar_g_monster_rottweiler_attack_melee_delay), DEATH_MONSTER_ROTTWEILER, true); } case MONSTER_ATTACK_RANGED: { @@ -62,13 +64,28 @@ float M_Rottweiler(float req) if(random() <= 0.3) { self.pain_finished = time + 1.5; - self.frame = rottweiler_anim_pain; + setanim(self, self.anim_pain1, true, true, false); } return true; } case MR_DEATH: { - self.frame = (random() >= 0.5) ? rottweiler_anim_death1 : rottweiler_anim_death2; + setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '5 1 0.5', none); // 2 seconds + self.anim_die2 = animfixfps(self, '1 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '2 1 1', none); + self.anim_idle = animfixfps(self, '7 1 1', none); + self.anim_pain1 = animfixfps(self, '4 1 2', none); // 0.5 seconds + self.anim_melee1 = animfixfps(self, '0 1 5', none); // analyze models and set framerate + self.anim_melee2 = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '6 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '5 1 1', none); + return true; } case MR_SETUP: @@ -79,12 +96,7 @@ float M_Rottweiler(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_rottweiler_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_rottweiler_damageforcescale); } - self.m_anim_walk = rottweiler_anim_walk; - self.m_anim_run = rottweiler_anim_run; - self.m_anim_idle = rottweiler_anim_idle; - self.monster_loot = spawnfunc_item_health_small; - self.frame = rottweiler_anim_idle; return true; } diff --git a/qcsrc/common/monsters/monster/scrag.qc b/qcsrc/common/monsters/monster/scrag.qc index 7a7220971..cc6c6dde2 100644 --- a/qcsrc/common/monsters/monster/scrag.qc +++ b/qcsrc/common/monsters/monster/scrag.qc @@ -22,11 +22,13 @@ float autocvar_g_monster_scrag_speed_stop; float autocvar_g_monster_scrag_speed_run; float autocvar_g_monster_scrag_speed_walk; +/* const float scrag_anim_hover = 0; const float scrag_anim_fly = 1; const float scrag_anim_magic = 2; const float scrag_anim_pain = 3; const float scrag_anim_death = 4; +*/ void M_Scrag_Attack_Spike_Explode() { @@ -83,7 +85,7 @@ float M_Scrag_Attack(float attack_type) self.attack_finished_single = time + ((random() >= 0.8) ? 1.3 : 0.15); self.anim_finished = self.attack_finished_single; - self.frame = scrag_anim_magic; + setanim(self, self.anim_shoot, true, true, false); M_Scrag_Attack_Spike(); @@ -120,17 +122,29 @@ float M_Scrag(float req) case MR_PAIN: { self.pain_finished = time + 0.3; - self.frame = scrag_anim_pain; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = scrag_anim_death; + setanim(self, self.anim_die1, false, true, true); self.velocity_x = -200 + 400 * random(); self.velocity_y = -200 + 400 * random(); self.velocity_z = 100 + 100 * random(); return true; } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '5 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '0 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '3 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '2 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '1 1 1', none); + + return true; + } case MR_SETUP: { if(!self.health) self.health = (autocvar_g_monster_scrag_health); @@ -139,12 +153,7 @@ float M_Scrag(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_scrag_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_scrag_damageforcescale); } - self.m_anim_walk = scrag_anim_hover; - self.m_anim_run = scrag_anim_fly; - self.m_anim_idle = scrag_anim_hover; - self.monster_loot = spawnfunc_item_shells; - self.frame = scrag_anim_hover; return true; } diff --git a/qcsrc/common/monsters/monster/shambler.qc b/qcsrc/common/monsters/monster/shambler.qc index c614a7801..8557c705d 100644 --- a/qcsrc/common/monsters/monster/shambler.qc +++ b/qcsrc/common/monsters/monster/shambler.qc @@ -28,6 +28,7 @@ float autocvar_g_monster_shambler_speed_stop; float autocvar_g_monster_shambler_speed_run; float autocvar_g_monster_shambler_speed_walk; +/* const float shambler_anim_stand = 0; const float shambler_anim_walk = 1; const float shambler_anim_run = 2; @@ -37,6 +38,7 @@ const float shambler_anim_swingl = 5; const float shambler_anim_magic = 6; const float shambler_anim_pain = 7; const float shambler_anim_death = 8; +*/ .float shambler_lastattack; // delay attacks separately @@ -57,7 +59,7 @@ void M_Shambler_Attack_Smash() void M_Shambler_Attack_Swing() { float r = (random() < 0.5); - Monster_Attack_Melee(self.enemy, (autocvar_g_monster_shambler_attack_claw_damage), ((r) ? shambler_anim_swingr : shambler_anim_swingl), self.attack_range, 0.8, DEATH_MONSTER_SHAMBLER_CLAW, true); + Monster_Attack_Melee(self.enemy, (autocvar_g_monster_shambler_attack_claw_damage), ((r) ? self.anim_melee2 : self.anim_melee3), self.attack_range, 0.8, DEATH_MONSTER_SHAMBLER_CLAW, true); if(r) { Monster_Delay(1, 0, 0.5, M_Shambler_Attack_Swing); @@ -180,7 +182,7 @@ float M_Shambler_Attack(float attack_type) if(self.flags & FL_ONGROUND) if(randomness <= 0.5 && enemy_len <= autocvar_g_monster_shambler_attack_smash_range) { - self.frame = shambler_anim_smash; + setanim(self, self.anim_melee2, true, true, false); Monster_Delay(1, 0, 0.7, M_Shambler_Attack_Smash); self.attack_finished_single = time + 1.1; self.anim_finished = time + 1.1; @@ -190,7 +192,7 @@ float M_Shambler_Attack(float attack_type) } else if(randomness <= 0.1 && enemy_len >= autocvar_g_monster_shambler_attack_smash_range * 1.5) // small chance, don't want this spammed { - self.frame = shambler_anim_magic; + setanim(self, self.anim_shoot, true, true, false); self.state = MONSTER_ATTACK_MELEE; // maybe we should rename this to something more general self.attack_finished_single = time + 1.1; self.anim_finished = 1.1; @@ -219,12 +221,27 @@ float M_Shambler(float req) case MR_PAIN: { self.pain_finished = time + 0.5; - self.frame = shambler_anim_pain; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = shambler_anim_death; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '8 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '7 1 2', none); // 0.5 seconds + self.anim_melee1 = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_melee2 = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_melee3 = animfixfps(self, '5 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '6 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '2 1 1', none); + return true; } case MR_SETUP: @@ -236,16 +253,11 @@ float M_Shambler(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_shambler_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_shambler_damageforcescale); } - self.m_anim_walk = shambler_anim_walk; - self.m_anim_run = shambler_anim_run; - self.m_anim_idle = shambler_anim_stand; - self.monster_loot = spawnfunc_item_health_mega; - self.frame = shambler_anim_stand; self.weapon = WEP_ELECTRO; // matches attacks better than WEP_VORTEX - self.frame = shambler_anim_magic; - self.spawn_time = time + 1.1; + setanim(self, self.anim_shoot, false, true, true); + self.spawn_time = self.animstate_endtime; self.spawnshieldtime = self.spawn_time; return true; diff --git a/qcsrc/common/monsters/monster/spawn.qc b/qcsrc/common/monsters/monster/spawn.qc index 6e6339eb8..2ef2c2e08 100644 --- a/qcsrc/common/monsters/monster/spawn.qc +++ b/qcsrc/common/monsters/monster/spawn.qc @@ -25,11 +25,13 @@ float autocvar_g_monster_spawn_speed_stop; float autocvar_g_monster_spawn_speed_run; float autocvar_g_monster_spawn_speed_walk; +/* const float spawn_anim_walk = 0; const float spawn_anim_run = 1; const float spawn_anim_jump = 2; const float spawn_anim_fly = 3; const float spawn_anim_explode = 4; +*/ void M_Spawn_Attack_Explode() { @@ -68,7 +70,7 @@ float M_Spawn_Attack(float attack_type) case MONSTER_ATTACK_RANGED: { makevectors(self.angles); - float leap_success = Monster_Attack_Leap(spawn_anim_jump, M_Spawn_Attack_Leap_Touch, v_forward * (autocvar_g_monster_spawn_attack_leap_speed) + '0 0 200', (autocvar_g_monster_spawn_attack_leap_delay)); + float leap_success = Monster_Attack_Leap(self.anim_melee, M_Spawn_Attack_Leap_Touch, v_forward * (autocvar_g_monster_spawn_attack_leap_speed) + '0 0 200', (autocvar_g_monster_spawn_attack_leap_delay)); if(leap_success) { self.movetype = MOVETYPE_BOUNCE; @@ -107,6 +109,17 @@ float M_Spawn(float req) defer(0.05, M_Spawn_Attack_Explode); // simply defer to prevent recursion return true; } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '4 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '0 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_melee = animfixfps(self, '2 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '1 1 1', none); + + return true; + } case MR_SETUP: { if(!self.health) self.health = (autocvar_g_monster_spawn_health); @@ -116,12 +129,7 @@ float M_Spawn(float req) if(!self.attack_range) { self.attack_range = autocvar_g_monsters_target_range * 0.8; } // bounce from almost any distance if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_spawn_damageforcescale); } - self.m_anim_walk = spawn_anim_walk; - self.m_anim_run = spawn_anim_run; - self.m_anim_idle = spawn_anim_walk; - self.monster_loot = spawnfunc_item_rockets; - self.frame = spawn_anim_walk; return true; } diff --git a/qcsrc/common/monsters/monster/spider.qc b/qcsrc/common/monsters/monster/spider.qc index 7e75fd541..3f8e5b62b 100644 --- a/qcsrc/common/monsters/monster/spider.qc +++ b/qcsrc/common/monsters/monster/spider.qc @@ -25,10 +25,12 @@ float autocvar_g_monster_spider_speed_stop; float autocvar_g_monster_spider_speed_run; float autocvar_g_monster_spider_speed_walk; +/* const float spider_anim_idle = 0; const float spider_anim_walk = 1; const float spider_anim_attack = 2; const float spider_anim_attack2 = 3; +*/ .float spider_web_delay; @@ -98,13 +100,13 @@ float M_Spider_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_spider_attack_bite_damage), ((random() > 0.5) ? spider_anim_attack : spider_anim_attack2), self.attack_range, (autocvar_g_monster_spider_attack_bite_delay), DEATH_MONSTER_SPIDER, true); + return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_spider_attack_bite_damage), ((random() > 0.5) ? self.anim_melee : self.anim_shoot), self.attack_range, (autocvar_g_monster_spider_attack_bite_delay), DEATH_MONSTER_SPIDER, true); } case MONSTER_ATTACK_RANGED: { if(time >= self.spider_web_delay) { - self.frame = spider_anim_attack2; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + (autocvar_g_monster_spider_attack_web_delay); self.anim_finished = time + 1; M_Spider_Attack_Web(); @@ -135,10 +137,21 @@ float M_Spider(float req) } case MR_DEATH: { - self.frame = spider_anim_attack; + setanim(self, self.anim_melee, false, true, true); self.angles_x = 180; return true; } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_melee = animfixfps(self, '2 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '1 1 1', none); + + return true; + } case MR_SETUP: { if(!self.health) self.health = (autocvar_g_monster_spider_health); @@ -147,12 +160,7 @@ float M_Spider(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_spider_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_spider_damageforcescale); } - self.m_anim_walk = spider_anim_walk; - self.m_anim_run = spider_anim_walk; - self.m_anim_idle = spider_anim_idle; - self.monster_loot = spawnfunc_item_health_medium; - self.frame = spider_anim_idle; return true; } diff --git a/qcsrc/common/monsters/monster/vore.qc b/qcsrc/common/monsters/monster/vore.qc index ebd5c56c3..0c6b478ed 100644 --- a/qcsrc/common/monsters/monster/vore.qc +++ b/qcsrc/common/monsters/monster/vore.qc @@ -32,10 +32,12 @@ float autocvar_g_monster_vore_speed_stop; float autocvar_g_monster_vore_speed_run; float autocvar_g_monster_vore_speed_walk; +/* const float vore_anim_attack = 0; const float vore_anim_pain = 1; const float vore_anim_death = 2; const float vore_anim_walk = 3; +*/ .entity vore_spike; @@ -157,13 +159,13 @@ float M_Vore_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_vore_attack_melee_damage), vore_anim_attack, self.attack_range, (autocvar_g_monster_vore_attack_melee_delay), DEATH_MONSTER_VORE_MELEE, true); + return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_vore_attack_melee_damage), self.anim_shoot, self.attack_range, (autocvar_g_monster_vore_attack_melee_delay), DEATH_MONSTER_VORE_MELEE, true); } case MONSTER_ATTACK_RANGED: { if(!self.vore_spike) { - self.frame = vore_anim_attack; + setanim(self, self.anim_shoot, true, true, true); self.attack_finished_single = time + (autocvar_g_monster_vore_attack_spike_delay); self.anim_finished = time + 1; Monster_Delay(1, 0, 0.2, M_Vore_Attack_Spike); @@ -193,12 +195,24 @@ float M_Vore(float req) case MR_PAIN: { self.pain_finished = time + 0.4; - self.frame = vore_anim_pain; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = vore_anim_death; + setanim(self, self.anim_die1, false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '2 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '3 1 1', none); + self.anim_idle = animfixfps(self, '3 1 1', none); + self.anim_pain1 = animfixfps(self, '1 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '3 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '0 1 1', none); + return true; } case MR_SETUP: @@ -209,13 +223,8 @@ float M_Vore(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_vore_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_vore_damageforcescale); } - self.m_anim_walk = vore_anim_walk; - self.m_anim_run = vore_anim_walk; - self.m_anim_idle = vore_anim_walk; - self.monster_loot = spawnfunc_ammo_cells; self.weapon = WEP_MACHINEGUN; - self.frame = vore_anim_walk; return true; } diff --git a/qcsrc/common/monsters/monster/wyvern.qc b/qcsrc/common/monsters/monster/wyvern.qc index cef6ed66e..d931a5b2e 100644 --- a/qcsrc/common/monsters/monster/wyvern.qc +++ b/qcsrc/common/monsters/monster/wyvern.qc @@ -25,11 +25,13 @@ float autocvar_g_monster_wyvern_speed_stop; float autocvar_g_monster_wyvern_speed_run; float autocvar_g_monster_wyvern_speed_walk; +/* const float wyvern_anim_hover = 0; const float wyvern_anim_fly = 1; const float wyvern_anim_magic = 2; const float wyvern_anim_pain = 3; const float wyvern_anim_death = 4; +*/ void M_Wyvern_Attack_Fireball_Explode() { @@ -113,16 +115,30 @@ float M_Wyvern(float req) } case MR_PAIN: { + self.pain_finished = time + 0.5; + setanim(self, self.anim_pain1, true, true, false); return true; } case MR_DEATH: { - self.frame = wyvern_anim_death; + setanim(self, self.anim_die1, false, true, true); self.velocity_x = -200 + 400 * random(); self.velocity_y = -200 + 400 * random(); self.velocity_z = 100 + 100 * random(); return true; } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '4 1 0.5', none); // 2 seconds + self.anim_walk = animfixfps(self, '1 1 1', none); + self.anim_idle = animfixfps(self, '0 1 1', none); + self.anim_pain1 = animfixfps(self, '3 1 2', none); // 0.5 seconds + self.anim_shoot = animfixfps(self, '2 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '1 1 1', none); + + return true; + } case MR_SETUP: { if(!self.health) self.health = (autocvar_g_monster_wyvern_health); @@ -131,12 +147,7 @@ float M_Wyvern(float req) if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_wyvern_speed_stop); } if(!self.damageforcescale) { self.damageforcescale = (autocvar_g_monster_wyvern_damageforcescale); } - self.m_anim_walk = wyvern_anim_hover; - self.m_anim_run = wyvern_anim_fly; - self.m_anim_idle = wyvern_anim_hover; - self.monster_loot = spawnfunc_item_cells; - self.frame = wyvern_anim_hover; return true; } diff --git a/qcsrc/common/monsters/monster/zombie.qc b/qcsrc/common/monsters/monster/zombie.qc index e754ef408..966dc99a5 100644 --- a/qcsrc/common/monsters/monster/zombie.qc +++ b/qcsrc/common/monsters/monster/zombie.qc @@ -23,6 +23,7 @@ float autocvar_g_monster_zombie_speed_stop; float autocvar_g_monster_zombie_speed_run; float autocvar_g_monster_zombie_speed_walk; +/* const float zombie_anim_attackleap = 0; const float zombie_anim_attackrun1 = 1; const float zombie_anim_attackrun2 = 2; @@ -54,6 +55,7 @@ const float zombie_anim_runforward = 27; const float zombie_anim_runforwardleft = 28; const float zombie_anim_runforwardright = 29; const float zombie_anim_spawn = 30; +*/ void M_Zombie_Attack_Leap_Touch() { @@ -83,17 +85,17 @@ void M_Zombie_Defend_Block_End() if(self.health <= 0) return; - self.frame = zombie_anim_blockend; + setanim(self, self.anim_blockend, false, true, true); self.armorvalue = autocvar_g_monsters_armor_blockpercent; } float M_Zombie_Defend_Block() { - self.frame = zombie_anim_blockstart; self.armorvalue = 0.9; self.state = MONSTER_ATTACK_MELEE; // freeze monster self.attack_finished_single = time + 2.1; self.anim_finished = self.attack_finished_single; + setanim(self, self.anim_blockstart, false, true, true); Monster_Delay(1, 0, 2, M_Zombie_Defend_Block_End); @@ -106,24 +108,25 @@ float M_Zombie_Attack(float attack_type) { case MONSTER_ATTACK_MELEE: { - float rand = random(), chosen_anim; + if(random() < 0.3 && self.health < 75 && self.enemy.health > 10) + return M_Zombie_Defend_Block(); + + float rand = random(); + vector chosen_anim; if(rand < 0.33) - chosen_anim = zombie_anim_attackstanding1; + chosen_anim = self.anim_melee1; else if(rand < 0.66) - chosen_anim = zombie_anim_attackstanding2; + chosen_anim = self.anim_melee2; else - chosen_anim = zombie_anim_attackstanding3; - - if(random() < 0.3 && self.health < 75 && self.enemy.health > 10) - return M_Zombie_Defend_Block(); + chosen_anim = self.anim_melee3; return Monster_Attack_Melee(self.enemy, (autocvar_g_monster_zombie_attack_melee_damage), chosen_anim, self.attack_range, (autocvar_g_monster_zombie_attack_melee_delay), DEATH_MONSTER_ZOMBIE_MELEE, true); } case MONSTER_ATTACK_RANGED: { makevectors(self.angles); - return Monster_Attack_Leap(zombie_anim_attackleap, M_Zombie_Attack_Leap_Touch, v_forward * (autocvar_g_monster_zombie_attack_leap_speed) + '0 0 200', (autocvar_g_monster_zombie_attack_leap_delay)); + return Monster_Attack_Leap(self.anim_shoot, M_Zombie_Attack_Leap_Touch, v_forward * (autocvar_g_monster_zombie_attack_leap_speed) + '0 0 200', (autocvar_g_monster_zombie_attack_leap_delay)); } } @@ -145,13 +148,34 @@ float M_Zombie(float req) case MR_PAIN: { self.pain_finished = time + 0.34; - self.frame = (random() >= 0.5) ? zombie_anim_painfront1 : zombie_anim_painfront2; + setanim(self, ((random() > 0.5) ? self.anim_pain1 : self.anim_pain2), true, true, false); return true; } case MR_DEATH: { self.armorvalue = autocvar_g_monsters_armor_blockpercent; - self.frame = ((random() > 0.5) ? zombie_anim_deathback1 : zombie_anim_deathfront1); + + setanim(self, ((random() > 0.5) ? self.anim_die1 : self.anim_die2), false, true, true); + return true; + } + case MR_ANIM: + { + vector none = '0 0 0'; + self.anim_die1 = animfixfps(self, '9 1 0.5', none); // 2 seconds + self.anim_die2 = animfixfps(self, '12 1 0.5', none); // 2 seconds + self.anim_spawn = animfixfps(self, '30 1 3', none); + self.anim_walk = animfixfps(self, '27 1 1', none); + self.anim_idle = animfixfps(self, '19 1 1', none); + self.anim_pain1 = animfixfps(self, '20 1 2', none); // 0.5 seconds + self.anim_pain2 = animfixfps(self, '22 1 2', none); // 0.5 seconds + self.anim_melee1 = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_melee2 = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_melee3 = animfixfps(self, '4 1 5', none); // analyze models and set framerate + self.anim_shoot = animfixfps(self, '0 1 5', none); // analyze models and set framerate + self.anim_run = animfixfps(self, '27 1 1', none); + self.anim_blockstart = animfixfps(self, '8 1 1', none); + self.anim_blockend = animfixfps(self, '7 1 1', none); + return true; } case MR_SETUP: @@ -161,22 +185,19 @@ float M_Zombie(float req) if(!self.speed2) { self.speed2 = (autocvar_g_monster_zombie_speed_run); } if(!self.stopspeed) { self.stopspeed = (autocvar_g_monster_zombie_speed_stop); } - self.m_anim_walk = zombie_anim_runforward; - self.m_anim_run = zombie_anim_runforward; - self.m_anim_idle = zombie_anim_idle; - if(self.spawnflags & MONSTERFLAG_NORESPAWN) self.spawnflags &= ~MONSTERFLAG_NORESPAWN; // zombies always respawn self.spawnflags |= MONSTER_RESPAWN_DEATHPOINT; self.monster_loot = spawnfunc_item_health_medium; - self.frame = zombie_anim_spawn; - self.spawn_time = time + 2.1; self.spawnshieldtime = self.spawn_time; self.respawntime = 0.2; self.damageforcescale = 0.0001; // no push while spawning + setanim(self, self.anim_spawn, false, true, true); + self.spawn_time = self.animstate_endtime; + return true; } case MR_PRECACHE: diff --git a/qcsrc/common/monsters/monsters.qh b/qcsrc/common/monsters/monsters.qh index 1a2bdeea8..33068648e 100644 --- a/qcsrc/common/monsters/monsters.qh +++ b/qcsrc/common/monsters/monsters.qh @@ -7,6 +7,7 @@ const int MR_THINK = 2; // (SERVER) logic to run every frame const int MR_DEATH = 3; // (SERVER) called when monster dies const int MR_PRECACHE = 4; // (BOTH) precaches models/sounds used by this monster const int MR_PAIN = 5; // (SERVER) called when monster is damaged +const int MR_ANIM = 6; // (BOTH?) sets animations for monster // functions entity get_monsterinfo(float id); diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index 848df83c8..7d21678b4 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -356,13 +356,16 @@ void Monster_Sound(.string samplefield, float sound_delay, float delaytoo, float // Monster attack handlers // ======================= -float Monster_Attack_Melee(entity targ, float damg, float anim, float er, float animtime, int deathtype, float dostop) +float Monster_Attack_Melee(entity targ, float damg, vector anim, float er, float animtime, int deathtype, float dostop) { if(dostop) { self.state = MONSTER_ATTACK_MELEE; } - self.frame = anim; + setanim(self, anim, true, true, true); - if(animtime > 0) { self.attack_finished_single = self.anim_finished = time + animtime; } + if(self.animstate_endtime > time) + self.attack_finished_single = self.anim_finished = self.animstate_endtime; + else + self.attack_finished_single = self.anim_finished = time + animtime; monster_makevectors(targ); @@ -396,21 +399,24 @@ float Monster_Attack_Leap_Check(vector vel) return true; } -bool Monster_Attack_Leap(int anm, void() touchfunc, vector vel, float animtime) +bool Monster_Attack_Leap(vector anm, void() touchfunc, vector vel, float animtime) { if(!Monster_Attack_Leap_Check(vel)) return false; - self.frame = anm; + setanim(self, anm, true, true, true); + + if(self.animstate_endtime > time) + self.attack_finished_single = self.anim_finished = self.animstate_endtime; + else + self.attack_finished_single = self.anim_finished = time + animtime; + self.state = MONSTER_ATTACK_RANGED; self.touch = touchfunc; self.origin_z += 1; self.velocity = vel; self.flags &= ~FL_ONGROUND; - self.attack_finished_single = time + animtime; - self.anim_finished = self.attack_finished_single; // TODO: make these frame based - return true; } @@ -447,6 +453,24 @@ void Monster_Attack_Check(entity e, entity targ) // Main monster functions // ====================== +void Monster_UpdateModel() +{ + // assume some defaults + /*self.anim_idle = animfixfps(self, '0 1 0.01', '0 0 0'); + self.anim_walk = animfixfps(self, '1 1 0.01', '0 0 0'); + self.anim_run = animfixfps(self, '2 1 0.01', '0 0 0'); + self.anim_fire1 = animfixfps(self, '3 1 0.01', '0 0 0'); + self.anim_fire2 = animfixfps(self, '4 1 0.01', '0 0 0'); + self.anim_melee = animfixfps(self, '5 1 0.01', '0 0 0'); + self.anim_pain1 = animfixfps(self, '6 1 0.01', '0 0 0'); + self.anim_pain2 = animfixfps(self, '7 1 0.01', '0 0 0'); + self.anim_die1 = animfixfps(self, '8 1 0.01', '0 0 0'); + self.anim_die2 = animfixfps(self, '9 1 0.01', '0 0 0');*/ + + // then get the real values + MON_ACTION(self.monsterid, MR_ANIM); +} + void Monster_Skin_Check() { vector oldmin = self.mins, oldmax = self.maxs; @@ -458,6 +482,7 @@ void Monster_Skin_Check() precache_model(trymodel); setmodel(self, trymodel); setsize(self, oldmin, oldmax); + Monster_UpdateModel(); CSQCMODEL_AUTOUPDATE(); // do a quick update } @@ -468,6 +493,7 @@ void Monster_Touch() { if(other == world) { return; } + if(other.monster_attack) if(self.enemy != other) if(!IS_MONSTER(other)) if(Monster_ValidTarget(self, other)) @@ -678,7 +704,7 @@ void Monster_CalculateVelocity(entity mon, vector to, vector from, float turnrat //mon.angles = vectoangles(mon.velocity); } -void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_run, float manim_walk, float manim_idle) +void Monster_Move(float runspeed, float walkspeed, float stpspeed) { if(self.target2) { self.goalentity = find(world, targetname, self.target2); } @@ -694,7 +720,7 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_r WaypointSprite_UpdateHealth(self.sprite, self.health); movelib_beak_simple(stpspeed); - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); self.enemy = world; self.nextthink = time + self.ticrate; @@ -713,7 +739,7 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_r WaypointSprite_UpdateHealth(self.sprite, self.health); movelib_beak_simple(stpspeed); - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); self.enemy = world; self.nextthink = time + self.ticrate; @@ -785,7 +811,7 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_r { runspeed = walkspeed = 0; if(time >= self.spawn_time) - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); movelib_beak_simple(stpspeed); return; } @@ -861,9 +887,9 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_r if(!self.state) if(time > self.anim_finished) if(vlen(self.velocity) > 10) - self.frame = ((do_run) ? manim_run : manim_walk); + setanim(self, ((do_run) ? self.anim_run : self.anim_walk), true, false, false); else - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); } else { @@ -878,7 +904,7 @@ void Monster_Move(float runspeed, float walkspeed, float stpspeed, float manim_r if(time > self.pain_finished) if(!self.state) if(vlen(self.velocity) <= 30) - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); } self.steerto = steerlib_attract2(((self.monster_face) ? self.monster_face : self.moveto), 0.5, 500, 0.95); @@ -1114,13 +1140,13 @@ void Monster_Damage(entity inflictor, entity attacker, float damage, int deathty } // don't check for enemies, just keep walking in a straight line -void Monster_Move_2D(float mspeed, float allow_jumpoff, float manim_walk, float manim_idle) +void Monster_Move_2D(float mspeed, float allow_jumpoff) { if(gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || self.draggedby != world || time < game_starttime || (autocvar_g_campaign && !campaign_bots_may_start) || time < self.spawn_time) { mspeed = 0; if(time >= self.spawn_time) - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); movelib_beak_simple(0.6); return; } @@ -1164,9 +1190,9 @@ void Monster_Move_2D(float mspeed, float allow_jumpoff, float manim_walk, float if(time > self.pain_finished) if(time > self.attack_finished_single) if(vlen(self.velocity) > 10) - self.frame = manim_walk; + setanim(self, self.anim_walk, true, false, false); else - self.frame = manim_idle; + setanim(self, self.anim_idle, true, false, false); } void Monster_Think() @@ -1184,7 +1210,7 @@ void Monster_Think() if(self.skin != self.oldskin) { Monster_Skin_Check(); } if(MON_ACTION(self.monsterid, MR_THINK)) - Monster_Move(self.speed2, self.speed, self.stopspeed, self.m_anim_run, self.m_anim_walk, self.m_anim_idle); + Monster_Move(self.speed2, self.speed, self.stopspeed); CSQCMODEL_AUTOUPDATE(); } @@ -1336,6 +1362,8 @@ bool Monster_Spawn(int mon_id) self.ticrate = bound(sys_frametime, ((!self.ticrate) ? autocvar_g_monsters_think_delay : self.ticrate), 60); + Monster_UpdateModel(); + if(!Monster_Spawn_Setup()) { Monster_Remove(self); diff --git a/qcsrc/common/monsters/sv_monsters.qh b/qcsrc/common/monsters/sv_monsters.qh index 5a57fbbbd..d5f04b765 100644 --- a/qcsrc/common/monsters/sv_monsters.qh +++ b/qcsrc/common/monsters/sv_monsters.qh @@ -26,12 +26,20 @@ int monsters_killed; .vector monster_face; // custom looking direction for monster (reset to '0 0 0' when you're done!) .float speed2; // run speed .float stopspeed; -.int m_anim_run; -.int m_anim_walk; -.int m_anim_idle; .int oldskin; .string mdl_dead; // dead model for goombas +.vector anim_blockend; +.vector anim_blockstart; +.vector anim_melee1; +.vector anim_melee2; +.vector anim_melee3; +.vector anim_pain3; +.vector anim_pain4; +.vector anim_pain5; +.vector anim_walk; +.vector anim_spawn; + #define MONSTER_SKILLMOD(mon) (0.5 + mon.monster_skill * ((1.2 - 0.3) / 10)) // other properties @@ -83,13 +91,13 @@ void monster_setupcolors(entity mon); void Monster_Touch(); -void Monster_Move_2D(float mspeed, float allow_jumpoff, float manim_walk, float manim_idle); +void Monster_Move_2D(float mspeed, float allow_jumpoff); void Monster_Delay(float repeat_count, float repeat_defer, float defer_amnt, void() func); -float Monster_Attack_Melee(entity targ, float damg, float anim, float er, float animtime, int deathtype, float dostop); +float Monster_Attack_Melee(entity targ, float damg, vector anim, float er, float animtime, int deathtype, float dostop); -bool Monster_Attack_Leap(int anm, void() touchfunc, vector vel, float animtime); +bool Monster_Attack_Leap(vector anm, void() touchfunc, vector vel, float animtime); entity Monster_FindTarget(entity mon); diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 389f3036e..4b1c8c4ff 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -439,6 +439,10 @@ void FixPlayermodel() if(!cvar("g_overkill") && self.cow && cow_allowed) defaultmodel = "models/player/cow.md3"; + ret_string = defaultmodel; + MUTATOR_CALLHOOK(FixPlayermodel); + defaultmodel = ret_string; + if(defaultmodel != "") { if (defaultmodel != self.model) @@ -2729,8 +2733,8 @@ void PlayerPreThink (void) if (!self.crouch) { self.crouch = true; - self.view_ofs = PL_CROUCH_VIEW_OFS; - setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); + self.view_ofs = self.stat_pl_crouch_view_ofs; + setsize (self, self.stat_pl_crouch_min, self.stat_pl_crouch_max); // setanim(self, self.anim_duck, false, true, true); // this anim is BROKEN anyway } } @@ -2738,12 +2742,12 @@ void PlayerPreThink (void) { if (self.crouch) { - tracebox(self.origin, PL_MIN, PL_MAX, self.origin, false, self); + tracebox(self.origin, self.stat_pl_min, self.stat_pl_max, self.origin, false, self); if (!trace_startsolid || self.pbhost) { self.crouch = false; - self.view_ofs = PL_VIEW_OFS; - setsize (self, PL_MIN, PL_MAX); + self.view_ofs = self.stat_pl_view_ofs; + setsize (self, self.stat_pl_min, self.stat_pl_max); } } } diff --git a/qcsrc/server/mutators/base.qh b/qcsrc/server/mutators/base.qh index c3ea39bad..b1db8a636 100644 --- a/qcsrc/server/mutators/base.qh +++ b/qcsrc/server/mutators/base.qh @@ -104,6 +104,11 @@ MUTATOR_HOOKABLE(SpectateCopy); // INPUT: // entity other; +MUTATOR_HOOKABLE(FixPlayermodel); + // allows modifying player's model + // INPUT, OUTPUT: + // string ret_string; + MUTATOR_HOOKABLE(ForbidThrowCurrentWeapon); // returns 1 if throwing the current weapon shall not be allowed -- 2.39.2