Implement mob and client melee push

New rules:
Combat:MeleePush turns melee push on/off
Combat:MeleePushChance is the chance that an NPC will be pushed
Clients are pushed every successful hit, need to verify or disprove this
This commit is contained in:
Michael Cook (mackal) 2015-04-30 19:36:21 -04:00
parent 8b4d601027
commit 06f4fd49ef
21 changed files with 257 additions and 178 deletions

View File

@ -1,5 +1,10 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 04/30/2015 ==
demonstar55: Implement mob and client melee push
You can set Combat:MeleePush to false to turn off or change Combat:MeleePushChance to increase the chance an NPC can be pushed
PCs are always pushed, need to do more testing to verify.
== 04/22/2015 == == 04/22/2015 ==
Uleat: Probable fix for 'Debug Assertion Failure' in Client::GarbleMessage() when calling the 'isalpha' macro. Uleat: Probable fix for 'Debug Assertion Failure' in Client::GarbleMessage() when calling the 'isalpha' macro.
ref: https://connect.microsoft.com/VisualStudio/feedback/details/932876/calling-isdigit-with-a-signed-char-1-results-in-a-assert-failure-in-debug-compiles ref: https://connect.microsoft.com/VisualStudio/feedback/details/932876/calling-isdigit-with-a-signed-char-1-results-in-a-assert-failure-in-debug-compiles

View File

@ -1318,9 +1318,9 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ uint32 damage; /* 07 */ uint32 damage;
/* 11 */ uint32 unknown11; /* 11 */ float force;
/* 15 */ uint32 sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint32 unknown19; /* 19 */ float meleepush_z;
/* 23 */ /* 23 */
}; };

View File

@ -658,7 +658,9 @@ namespace RoF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -4389,7 +4391,7 @@ namespace RoF
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -729,7 +729,9 @@ namespace RoF2
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -4538,7 +4540,7 @@ namespace RoF2
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -1484,9 +1484,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid; /* 05 */ uint32 spellid;
/* 09 */ int32 damage; /* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d /* 13 */ float force; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct /* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9] /* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */ /* 30 */
}; };

View File

@ -1514,9 +1514,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint32 spellid; /* 05 */ uint32 spellid;
/* 09 */ int32 damage; /* 09 */ int32 damage;
/* 13 */ float unknown11; // cd cc cc 3d /* 13 */ float force; // cd cc cc 3d
/* 17 */ float sequence; // see above notes in Action_Struct /* 17 */ float meleepush_xy; // see above notes in Action_Struct
/* 21 */ uint8 unknown19[9]; // was [9] /* 21 */ float meleepush_z;
/* 25 */ uint8 unknown25[5]; // was [9]
/* 30 */ /* 30 */
}; };

View File

@ -446,7 +446,9 @@ namespace SoD
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }

View File

@ -1272,9 +1272,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };

View File

@ -426,7 +426,9 @@ namespace SoF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }

View File

@ -1249,9 +1249,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };

View File

@ -1101,9 +1101,9 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ uint32 damage; /* 07 */ uint32 damage;
/* 11 */ uint32 unknown11; /* 11 */ float force;
/* 15 */ uint32 sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint32 unknown19; /* 19 */ float meleepush_z;
/* 23 */ /* 23 */
}; };

View File

@ -581,7 +581,9 @@ namespace UF
OUT(type); OUT(type);
OUT(spellid); OUT(spellid);
OUT(damage); OUT(damage);
eq->sequence = emu->sequence; OUT(force)
OUT(meleepush_xy);
OUT(meleepush_z)
FINISH_ENCODE(); FINISH_ENCODE();
} }
@ -3356,7 +3358,7 @@ namespace UF
IN(type); IN(type);
IN(spellid); IN(spellid);
IN(damage); IN(damage);
emu->sequence = eq->sequence; IN(meleepush_xy);
FINISH_DIRECT_DECODE(); FINISH_DIRECT_DECODE();
} }

View File

@ -1330,9 +1330,10 @@ struct CombatDamage_Struct
/* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells
/* 05 */ uint16 spellid; /* 05 */ uint16 spellid;
/* 07 */ int32 damage; /* 07 */ int32 damage;
/* 11 */ float unknown11; // cd cc cc 3d /* 11 */ float force; // cd cc cc 3d
/* 15 */ float sequence; // see above notes in Action_Struct /* 15 */ float meleepush_xy; // see above notes in Action_Struct
/* 19 */ uint8 unknown19[9]; // was [9] /* 19 */ float meleepush_z;
/* 23 */ uint8 unknown23[5]; // was [9]
/* 28 */ /* 28 */
}; };

View File

@ -438,6 +438,8 @@ RULE_INT ( Combat, BerserkerFrenzyStart, 35)
RULE_INT ( Combat, BerserkerFrenzyEnd, 45) RULE_INT ( Combat, BerserkerFrenzyEnd, 45)
RULE_BOOL ( Combat, OneProcPerWeapon, true) //If enabled, One proc per weapon per round RULE_BOOL ( Combat, OneProcPerWeapon, true) //If enabled, One proc per weapon per round
RULE_BOOL ( Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arrows) will hit on impact, instead of instantly. RULE_BOOL ( Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arrows) will hit on impact, instead of instantly.
RULE_BOOL ( Combat, MeleePush, true) // enable melee push
RULE_INT ( Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY( NPC ) RULE_CATEGORY( NPC )

View File

@ -55,3 +55,40 @@ bool EQEmu::IsSpecializedSkill(SkillUseTypes skill)
return false; return false;
} }
} }
float EQEmu::GetSkillMeleePushForce(SkillUseTypes skill)
{
// This is the force/magnitude of the push from an attack of this skill type
// You can find these numbers in the clients skill struct
switch (skill) {
case Skill1HBlunt:
case Skill1HSlashing:
case SkillHandtoHand:
case SkillThrowing:
return 0.1f;
case Skill2HBlunt:
case Skill2HSlashing:
case SkillEagleStrike:
case SkillKick:
case SkillTigerClaw:
//case Skill2HPiercing:
return 0.2f;
case SkillArchery:
return 0.15f;
case SkillBackstab:
case SkillBash:
return 0.3f;
case SkillDragonPunch:
case SkillRoundKick:
return 0.25f;
case SkillFlyingKick:
return 0.4f;
case Skill1HPiercing:
case SkillFrenzy:
return 0.05f;
case SkillIntimidation:
return 2.5f;
default:
return 0.0f;
}
}

View File

@ -270,6 +270,7 @@ typedef enum {
namespace EQEmu { namespace EQEmu {
bool IsTradeskill(SkillUseTypes skill); bool IsTradeskill(SkillUseTypes skill);
bool IsSpecializedSkill(SkillUseTypes skill); bool IsSpecializedSkill(SkillUseTypes skill);
float GetSkillMeleePushForce(SkillUseTypes skill);
} }
#endif #endif

View File

@ -0,0 +1,2 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePush', 'true', 'Turns on Melee Push.');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePushChance', '50', 'Chance that an NPC can be pushed from melee.');

View File

@ -3708,6 +3708,23 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
a->type = SkillDamageTypes[skill_used]; // was 0x1c a->type = SkillDamageTypes[skill_used]; // was 0x1c
a->damage = damage; a->damage = damage;
a->spellid = spell_id; a->spellid = spell_id;
a->meleepush_xy = attacker->GetHeading() * 2.0f;
if (RuleB(Combat, MeleePush) && damage > 0 && !IsRooted() &&
(IsClient() || zone->random.Roll(RuleI(Combat, MeleePushChance)))) {
a->force = EQEmu::GetSkillMeleePushForce(skill_used);
// update NPC stuff
auto new_pos = glm::vec3(m_Position.x + (a->force * std::sin(a->meleepush_xy) + m_Delta.x),
m_Position.y + (a->force * std::cos(a->meleepush_xy) + m_Delta.y), m_Position.z);
if (zone->zonemap->CheckLoS(glm::vec3(m_Position), new_pos)) { // If we have LoS on the new loc it should be reachable.
if (IsNPC()) {
// Is this adequate?
Teleport(new_pos);
SendPosUpdate();
}
} else {
a->force = 0.0f; // we couldn't move there, so lets not
}
}
//Note: if players can become pets, they will not receive damage messages of their own //Note: if players can become pets, they will not receive damage messages of their own
//this was done to simplify the code here (since we can only effectively skip one mob on queue) //this was done to simplify the code here (since we can only effectively skip one mob on queue)

View File

@ -921,7 +921,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
cd->source = action->source; cd->source = action->source;
cd->type = action->type; cd->type = action->type;
cd->spellid = action->spell; cd->spellid = action->spell;
cd->sequence = action->sequence; cd->meleepush_xy = action->sequence;
CastToClient()->QueuePacket(action_packet); CastToClient()->QueuePacket(action_packet);
if(caster->IsClient() && caster != this) if(caster->IsClient() && caster != this)
@ -970,7 +970,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
cd->source = action->source; cd->source = action->source;
cd->type = action->type; cd->type = action->type;
cd->spellid = action->spell; cd->spellid = action->spell;
cd->sequence = action->sequence; cd->meleepush_xy = action->sequence;
CastToClient()->QueuePacket(action_packet); CastToClient()->QueuePacket(action_packet);
if(caster->IsClient() && caster != this) if(caster->IsClient() && caster != this)
@ -1006,7 +1006,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
cd->source = action->source; cd->source = action->source;
cd->type = action->type; cd->type = action->type;
cd->spellid = action->spell; cd->spellid = action->spell;
cd->sequence = action->sequence; cd->meleepush_xy = action->sequence;
CastToClient()->QueuePacket(action_packet); CastToClient()->QueuePacket(action_packet);
if(caster->IsClient() && caster != this) if(caster->IsClient() && caster != this)

View File

@ -2563,7 +2563,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
cd->source = action->source; cd->source = action->source;
cd->type = DamageTypeSpell; cd->type = DamageTypeSpell;
cd->spellid = action->spell; cd->spellid = action->spell;
cd->sequence = action->sequence; cd->meleepush_xy = action->sequence;
cd->damage = 0; cd->damage = 0;
if(!IsEffectInSpell(spell_id, SE_BindAffinity)) if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{ {
@ -3827,7 +3827,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
cd->source = action->source; cd->source = action->source;
cd->type = action->type; cd->type = action->type;
cd->spellid = action->spell; cd->spellid = action->spell;
cd->sequence = action->sequence; cd->meleepush_xy = action->sequence;
cd->damage = 0; cd->damage = 0;
if(!IsEffectInSpell(spell_id, SE_BindAffinity)) if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{ {

View File

@ -192,7 +192,7 @@ void Trap::Trigger(Mob* trigger)
int dmg = zone->random.Int(effectvalue, effectvalue2); int dmg = zone->random.Int(effectvalue, effectvalue2);
trigger->SetHP(trigger->GetHP() - dmg); trigger->SetHP(trigger->GetHP() - dmg);
a->damage = dmg; a->damage = dmg;
a->sequence = zone->random.Int(0, 1234567); a->meleepush_xy = zone->random.Int(0, 1234567);
a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID(); a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID();
a->spellid = 0; a->spellid = 0;
a->target = trigger->GetID(); a->target = trigger->GetID();