Rework combat to make use of a struct to fix some bugs

This commit is contained in:
Michael Cook (mackal) 2017-01-28 19:38:44 -05:00
parent e300f82c28
commit 37e87e8cef
12 changed files with 893 additions and 1085 deletions

View File

@ -392,15 +392,12 @@ RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the
RULE_CATEGORY_END()
RULE_CATEGORY(Combat)
RULE_INT(Combat, MeleeBaseCritChance, 0) //The base crit chance for non warriors, NOTE: This will apply to NPCs as well
RULE_INT(Combat, WarBerBaseCritChance, 3) //The base crit chance for warriors and berserkers, only applies to clients
RULE_INT(Combat, BerserkBaseCritChance, 6) //The bonus base crit chance you get when you're berserk
RULE_INT(Combat, PetBaseCritChance, 0) // Pet Base crit chance
RULE_INT(Combat, NPCBashKickLevel, 6) //The level that npcs can KICK/BASH
RULE_INT(Combat, NPCBashKickStunChance, 15) //Percent chance that a bash/kick will stun
RULE_INT(Combat, RogueCritThrowingChance, 25) //Rogue throwing crit bonus
RULE_INT(Combat, RogueDeadlyStrikeChance, 80) //Rogue chance throwing from behind crit becomes a deadly strike
RULE_INT(Combat, RogueDeadlyStrikeMod, 2) //Deadly strike modifier to crit damage
RULE_INT(Combat, ClientBaseCritChance, 0) //The base crit chance for all clients, this will stack with warrior's/zerker's crit chance.
RULE_INT(Combat, MeleeCritDifficulty, 8900) // lower is easier
RULE_INT(Combat, ArcheryCritDifficulty, 3400) // lower is easier
RULE_INT(Combat, ThrowingCritDifficulty, 1100) // lower is easier
RULE_BOOL(Combat, UseIntervalAC, true)
RULE_INT(Combat, PetAttackMagicLevel, 30)
RULE_BOOL(Combat, EnableFearPathing, true)

View File

@ -77,6 +77,8 @@ app.controller('MainCtrl', function($scope, $interval) {
$scope.stop();
});
var damage_mods = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
@ -94,45 +96,20 @@ app.controller('MainCtrl', function($scope, $interval) {
}
function doCombatRound() {
var offense = $scope.offense;
var mitigation = $scope.mitigation;
mitigation = mitigation - ((mitigation - offense) / 2.0);
var diff = offense - mitigation;
var mean = 0.0;
var mult1 = 0.0;
var mult2 = 0.0;
if (offense > 30.0) {
mult1 = offense / 200.0 + 25.75;
if ((mitigation / offense) < 0.35) {
mult1 = mult1 + 1.0;
} else if ((mitigation / offense) > 0.65) {
mult1 = mult1 - 1.0;
}
mult2 = offense / 140 + 18.5;
} else {
mult1 = 11.5 + offense / 2.0;
mult2 = 14.0 + offense / 6.0;
var offense = getRandomInt(0, $scope.offense + 5);
var mitigation = getRandomInt(0, $scope.mitigation + 5);
var avg = parseInt(($scope.offense + $scope.mitigation + 10) / 2);
var index = parseInt((offense - mitigation) + (avg / 2));
if (index < 0) {
index = 0;
}
if (offense > mitigation) {
mean = diff / offense * mult1;
} else if (mitigation > offense) {
mean = diff / mitigation * mult2;
}
var stddev = 8.8;
var theta = 2 * Math.PI * getRandom(0.0, 1.0);
var rho = Math.sqrt(-2 * Math.log(1 - getRandom(0.0, 1.0)));
var d = mean + stddev * rho * Math.cos(theta);
if (d < -9.5) {
d = -9.5;
} else if (d > 9.5) {
d = 9.5;
}
d = d + 11;
addRoll(parseInt(d));
index = parseInt((index * 20) / avg);
if (index >= 20)
index = 19;
if (index < 0)
index = 0;
var roll = damage_mods[index];
addRoll(roll);
};
});

File diff suppressed because it is too large Load Diff

View File

@ -1313,8 +1313,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_HeadShotLevel: {
if (newbon->HSLevel < base1)
newbon->HSLevel = base1;
if (newbon->HSLevel[0] < base1)
newbon->HSLevel[0] = base1;
newbon->HSLevel[1] = base2;
break;
}
@ -1327,8 +1328,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_AssassinateLevel: {
if (newbon->AssassinateLevel < base1)
newbon->AssassinateLevel = base1;
if (newbon->AssassinateLevel[0] < base1) {
newbon->AssassinateLevel[0] = base1;
newbon->AssassinateLevel[1] = base2;
}
break;
}
@ -1386,7 +1389,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_MeleeMitigation:
newbon->MeleeMitigationEffect -= base1;
newbon->MeleeMitigationEffect += base1;
break;
case SE_ATK:
@ -1929,8 +1932,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
case SE_MeleeMitigation:
//for some reason... this value is negative for increased mitigation
new_bonus->MeleeMitigationEffect -= effect_value;
// This value is negative because it counteracts another SPA :P
new_bonus->MeleeMitigationEffect += effect_value;
break;
case SE_CriticalHitChance:
@ -3026,8 +3029,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_HeadShotLevel:
{
if(new_bonus->HSLevel < effect_value)
new_bonus->HSLevel = effect_value;
if(new_bonus->HSLevel[0] < effect_value) {
new_bonus->HSLevel[0] = effect_value;
new_bonus->HSLevel[1] = base2;
}
break;
}
@ -3042,8 +3047,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_AssassinateLevel:
{
if(new_bonus->AssassinateLevel < effect_value)
new_bonus->AssassinateLevel = effect_value;
if(new_bonus->AssassinateLevel[0] < effect_value) {
new_bonus->AssassinateLevel[0] = effect_value;
new_bonus->AssassinateLevel[1] = base2;
}
break;
}
@ -4649,9 +4656,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
case SE_HeadShotLevel:
spellbonuses.HSLevel = effect_value;
aabonuses.HSLevel = effect_value;
itembonuses.HSLevel = effect_value;
spellbonuses.HSLevel[0] = effect_value;
aabonuses.HSLevel[0] = effect_value;
itembonuses.HSLevel[0] = effect_value;
spellbonuses.HSLevel[1] = effect_value;
aabonuses.HSLevel[1] = effect_value;
itembonuses.HSLevel[1] = effect_value;
break;
case SE_Assassinate:
@ -4664,9 +4674,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
case SE_AssassinateLevel:
spellbonuses.AssassinateLevel = effect_value;
aabonuses.AssassinateLevel = effect_value;
itembonuses.AssassinateLevel = effect_value;
spellbonuses.AssassinateLevel[0] = effect_value;
aabonuses.AssassinateLevel[0] = effect_value;
itembonuses.AssassinateLevel[0] = effect_value;
spellbonuses.AssassinateLevel[1] = effect_value;
aabonuses.AssassinateLevel[1] = effect_value;
itembonuses.AssassinateLevel[1] = effect_value;
break;
case SE_FinishingBlow:

View File

@ -3701,24 +3701,24 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
// calculate attack_skill and skillinuse depending on hand and weapon
// also send Packet to near clients
EQEmu::skills::SkillType skillinuse;
AttackAnimation(skillinuse, Hand, weapon);
Log.Out(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, skillinuse);
DamageHitInfo my_hit;
AttackAnimation(my_hit.skill, Hand, weapon);
Log.Out(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, my_hit.skill);
/// Now figure out damage
int damage = 0;
my_hit.damage_done =0;
uint8 mylevel = GetLevel() ? GetLevel() : 1;
uint32 hate = 0;
if (weapon)
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
int weapon_damage = GetWeaponDamage(other, weapon, &hate);
if (hate == 0 && weapon_damage > 1)
hate = weapon_damage;
my_hit.base_damage = GetWeaponDamage(other, weapon, &hate);
if (hate == 0 && my_hit.base_damage > 1)
hate = my_hit.base_damage;
//if weapon damage > 0 then we know we can hit the target with this weapon
//otherwise we cannot and we set the damage to -5 later on
if(weapon_damage > 0) {
int min_damage = 0;
if (my_hit.base_damage > 0) {
my_hit.min_damage = 0;
// ***************************************************************
// *** Calculate the damage bonus, if applicable, for this hit ***
@ -3736,7 +3736,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
// Damage bonuses apply only to hits from the main hand (Hand == MainPrimary) by characters level 28 and above
// who belong to a melee class. If we're here, then all of these conditions apply.
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemData*) nullptr);
min_damage = ucDamageBonus;
my_hit.min_damage = ucDamageBonus;
hate += ucDamageBonus;
}
#endif
@ -3744,55 +3744,29 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
if (Hand == EQEmu::inventory::slotSecondary) {
if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc){
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemData*) nullptr);
min_damage = ucDamageBonus;
my_hit.min_damage = ucDamageBonus;
hate += ucDamageBonus;
}
}
int min_cap = (weapon_damage * GetMeleeMinDamageMod_SE(skillinuse) / 100);
Log.Out(Logs::Detail, Logs::Combat, "Damage calculated: base %d min damage %d skill %d", my_hit.base_damage, my_hit.min_damage, my_hit.skill);
Log.Out(Logs::Detail, Logs::Combat, "Damage calculated to %d (bonus %d, base %d, str %d, skill %d, DMG %d, lv %d)",
damage, min_damage, weapon_damage, GetSTR(), GetSkill(skillinuse), weapon_damage, mylevel);
my_hit.offense = offense(my_hit.skill);
my_hit.hand = Hand;
auto offense = this->offense(skillinuse);
if(opts) {
weapon_damage *= opts->damage_percent;
weapon_damage += opts->damage_flat;
if (opts) {
my_hit.base_damage *= opts->damage_percent;
my_hit.base_damage += opts->damage_flat;
hate *= opts->hate_percent;
hate += opts->hate_flat;
}
//check to see if we hit..
if (other->AvoidDamage(this, damage, Hand)) {
if (!FromRiposte && !IsStrikethrough) {
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
if(strike_through && zone->random.Roll(strike_through)) {
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
return false;
}
if (damage == -3 && !FromRiposte) {
DoRiposte(other);
if (HasDied())
return false;
}
}
} else {
if (other->CheckHitChance(this, skillinuse)) {
other->MeleeMitigation(this, damage, weapon_damage, offense, skillinuse, opts);
if (damage > 0) {
ApplyDamageTable(damage, offense);
CommonOutgoingHitSuccess(other, damage, min_damage, min_cap, skillinuse, opts);
}
} else {
damage = 0;
}
}
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
DoAttack(other, my_hit, opts);
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", my_hit.damage_done);
} else {
my_hit.damage_done = DMG_INVULNERABLE;
}
else
damage = -5;
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
// If we are this far, this means we are atleast making a swing.
@ -3801,14 +3775,14 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
///////////////////////////////////////////////////////////
////// Send Attack Damage
///////////////////////////////////////////////////////////
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill);
if (GetHP() < 0)
return false;
MeleeLifeTap(damage);
MeleeLifeTap(my_hit.damage_done);
if (damage > 0)
if (my_hit.damage_done > 0)
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
CommonBreakInvisibleFromCombat();
@ -3816,9 +3790,9 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
BuffFadeByEffect(SE_NegateIfCombat);
if(GetTarget())
TriggerDefensiveProcs(other, Hand, true, damage);
TriggerDefensiveProcs(other, Hand, true, my_hit.damage_done);
if (damage > 0)
if (my_hit.damage_done > 0)
return true;
else
return false;
@ -4699,16 +4673,16 @@ int Bot::GetHandToHandDamage(void) {
return 2;
}
bool Bot::TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse, int &damage)
bool Bot::TryFinishingBlow(Mob *defender, int &damage)
{
if (!defender)
return false;
if (aabonuses.FinishingBlow[1] && !defender->IsClient() && defender->GetHPRatio() < 10) {
int chance = (aabonuses.FinishingBlow[0] / 10);
int chance = aabonuses.FinishingBlow[0];
int fb_damage = aabonuses.FinishingBlow[1];
int levelreq = aabonuses.FinishingBlowLvl[0];
if (defender->GetLevel() <= levelreq && (chance >= zone->random.Int(0, 1000))) {
if (defender->GetLevel() <= levelreq && (chance >= zone->random.Int(1, 1000))) {
Log.Out(Logs::Detail, Logs::Combat, "Landed a finishing blow: levelreq at %d, other level %d",
levelreq, defender->GetLevel());
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName());
@ -4849,36 +4823,29 @@ void Bot::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32
}
}
int min_cap = max_damage * GetMeleeMinDamageMod_SE(skill) / 100;
int hand = EQEmu::inventory::slotPrimary;
int damage = 0;
auto offense = this->offense(skill);
DamageHitInfo my_hit;
my_hit.base_damage = max_damage;
my_hit.min_damage = min_damage;
my_hit.damage_done = 0;
my_hit.skill = skill;
my_hit.offense = offense(my_hit.skill);
my_hit.tohit = GetTotalToHit(my_hit.skill, 0);
my_hit.hand = EQEmu::inventory::slotPrimary;
if (skill == EQEmu::skills::SkillThrowing || skill == EQEmu::skills::SkillArchery)
hand = EQEmu::inventory::slotRange;
if (who->AvoidDamage(this, damage, hand)) {
if (damage == -3)
DoRiposte(who);
} else {
if (HitChance || who->CheckHitChance(this, skill)) {
if (max_damage > 0)
who->MeleeMitigation(this, damage, max_damage, offense, skill);
if (damage > 0) {
ApplyDamageTable(damage, offense);
CommonOutgoingHitSuccess(who, damage, min_damage, min_cap, skill);
}
} else {
damage = 0;
}
}
my_hit.hand = EQEmu::inventory::slotRange;
DoAttack(who, my_hit);
who->AddToHateList(this, hate);
who->Damage(this, damage, SPELL_UNKNOWN, skill, false);
who->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, skill, false);
if(!GetTarget() || HasDied())
return;
if (damage > 0)
if (my_hit.damage_done > 0)
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
@ -4894,7 +4861,7 @@ void Bot::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32
if (HasSkillProcs())
TrySkillProc(who, skill, (ReuseTime * 1000));
if (damage > 0 && HasSkillProcSuccess())
if (my_hit.damage_done > 0 && HasSkillProcSuccess())
TrySkillProc(who, skill, (ReuseTime * 1000), true);
}
@ -5030,7 +4997,6 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
return;
float HasteModifier = (GetHaste() * 0.01f);
int32 dmg = 0;
uint16 skill_to_use = -1;
int level = GetLevel();
int reuse = (TauntReuseTime * 1000);
@ -5084,18 +5050,14 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
if(skill_to_use == -1)
return;
int dmg = GetBaseSkillDamage(static_cast<EQEmu::skills::SkillType>(skill_to_use), GetTarget());
if (skill_to_use == EQEmu::skills::SkillBash) {
if (target != this) {
DoAnim(animTailRake);
if (GetWeaponDamage(target, GetBotItem(EQEmu::inventory::slotSecondary)) <= 0 && GetWeaponDamage(target, GetBotItem(EQEmu::inventory::slotShoulders)) <= 0)
dmg = -5;
else {
if (!target->CheckHitChance(this, EQEmu::skills::SkillBash, 0))
dmg = 0;
else {
dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash);
}
}
dmg = DMG_INVULNERABLE;
reuse = (BashReuseTime * 1000);
DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 0, -1, reuse);
did_attack = true;
@ -5104,14 +5066,13 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
if (skill_to_use == EQEmu::skills::SkillFrenzy) {
int AtkRounds = 3;
int32 max_dmg = GetBaseSkillDamage(EQEmu::skills::SkillFrenzy);
DoAnim(anim2HSlashing);
reuse = (FrenzyReuseTime * 1000);
did_attack = true;
while(AtkRounds > 0) {
if (GetTarget() && (AtkRounds == 1 || zone->random.Int(0, 100) < 75)) {
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, 0, max_dmg, reuse, true);
DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, dmg, 0, dmg, reuse, true);
}
AtkRounds--;
@ -5122,14 +5083,8 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) {
if(target != this) {
DoAnim(animKick);
if (GetWeaponDamage(target, GetBotItem(EQEmu::inventory::slotFeet)) <= 0)
dmg = -5;
else {
if (!target->CheckHitChance(this, EQEmu::skills::SkillKick, 0))
dmg = 0;
else {
dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick);
}
}
dmg = DMG_INVULNERABLE;
reuse = (KickReuseTime * 1000);
DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 0, -1, reuse);
did_attack = true;

View File

@ -239,7 +239,7 @@ public:
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
virtual float GetProcChances(float ProcBonus, uint16 hand);
virtual int GetHandToHandDamage(void);
virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse, int &damage);
virtual bool TryFinishingBlow(Mob *defender, int &damage);
virtual void DoRiposte(Mob* defender);
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQEmu::skills::SkillOffense)) * 9 / 10); }
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }

View File

@ -35,6 +35,13 @@
#define CON_YELLOW 15
#define CON_RED 13
#define DMG_BLOCKED -1
#define DMG_PARRIED -2
#define DMG_RIPOSTED -3
#define DMG_DODGED -4
#define DMG_INVULNERABLE -5
#define DMG_RUNE -6
//Spell specialization parameters, not sure of a better place for them
#define SPECIALIZE_FIZZLE 11 //% fizzle chance reduce at 200 specialized
#define SPECIALIZE_MANA_REDUCE 12 //% mana cost reduction at 200 specialized
@ -464,9 +471,9 @@ struct StatBonuses {
int8 CriticalMend; // chance critical monk mend
int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
uint32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg
uint8 HSLevel; // Max Level Headshot will be effective at.
uint8 HSLevel[2]; // Max Level Headshot will be effective at. and chance mod
uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg
uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
uint8 AssassinateLevel[2]; // Max Level Assassinate will be effective at.
int32 PetMeleeMitigation; // Add AC to owner's pet.
bool IllusionPersistence; // Causes illusions not to fade.
uint16 extra_xtargets; // extra xtarget entries
@ -644,5 +651,17 @@ struct DamageTable {
int32 minusfactor; // difficulty of rolling
};
struct DamageHitInfo {
//uint16 attacker; // id
//uint16 defender; // id
int base_damage;
int min_damage;
int damage_done;
int offense;
int tohit;
int hand;
EQEmu::skills::SkillType skill;
};
#endif

View File

@ -1270,12 +1270,6 @@ void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, in
self->DoSpecialAttackDamage(other, static_cast<EQEmu::skills::SkillType>(skill), max_damage, min_damage, hate_override, reuse_time);
}
void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override, int reuse_time,
bool hit_chance) {
Lua_Safe_Call_Void();
self->DoSpecialAttackDamage(other, static_cast<EQEmu::skills::SkillType>(skill), max_damage, min_damage, hate_override, reuse_time, hit_chance);
}
void Lua_Mob::DoThrowingAttackDmg(Lua_Mob other) {
Lua_Safe_Call_Void();
self->DoThrowingAttackDmg(other);
@ -2218,7 +2212,6 @@ luabind::scope lua_register_mob() {
.def("DoSpecialAttackDamage", (void(Lua_Mob::*)(Lua_Mob,int,int,int))&Lua_Mob::DoSpecialAttackDamage)
.def("DoSpecialAttackDamage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,int))&Lua_Mob::DoSpecialAttackDamage)
.def("DoSpecialAttackDamage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,int,int))&Lua_Mob::DoSpecialAttackDamage)
.def("DoSpecialAttackDamage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,int,int,bool))&Lua_Mob::DoSpecialAttackDamage)
.def("DoThrowingAttackDmg", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::DoThrowingAttackDmg)
.def("DoThrowingAttackDmg", (void(Lua_Mob::*)(Lua_Mob,Lua_ItemInst))&Lua_Mob::DoThrowingAttackDmg)
.def("DoThrowingAttackDmg", (void(Lua_Mob::*)(Lua_Mob,Lua_ItemInst,Lua_Item))&Lua_Mob::DoThrowingAttackDmg)

View File

@ -267,7 +267,6 @@ public:
void DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage);
void DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override);
void DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override, int reuse_time);
void DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override, int reuse_time, bool hit_chance);
void DoThrowingAttackDmg(Lua_Mob other);
void DoThrowingAttackDmg(Lua_Mob other, Lua_ItemInst range_weapon);
void DoThrowingAttackDmg(Lua_Mob other, Lua_ItemInst range_weapon, Lua_Item item);

View File

@ -4426,15 +4426,10 @@ void Merc::DoClassAttacks(Mob *target) {
if(zone->random.Int(0, 100) > 25) //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference.
{
DoAnim(animKick);
int32 dmg = 0;
int32 dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick);
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0){
dmg = -5;
}
else{
if (target->CheckHitChance(this, EQEmu::skills::SkillKick, 0))
dmg = GetBaseSkillDamage(EQEmu::skills::SkillKick, GetTarget());
}
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0)
dmg = DMG_INVULNERABLE;
reuse = KickReuseTime * 1000;
DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse);
@ -4443,15 +4438,10 @@ void Merc::DoClassAttacks(Mob *target) {
else
{
DoAnim(animTailRake);
int32 dmg = 0;
int32 dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash);
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0){
dmg = -5;
}
else{
if (target->CheckHitChance(this, EQEmu::skills::SkillBash, 0))
dmg = GetBaseSkillDamage(EQEmu::skills::SkillBash, GetTarget());
}
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0)
dmg = DMG_INVULNERABLE;
reuse = BashReuseTime * 1000;
DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse);

View File

@ -162,21 +162,22 @@ public:
// 13 = Primary (default), 14 = secondary
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) = 0;
void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
int MonkSpecialAttack(Mob* other, uint8 skill_used);
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
bool AvoidDamage(Mob* attacker, int &damage, int hand);
bool AvoidDamage(Mob *attacker, DamageHitInfo &hit);
int compute_tohit(EQEmu::skills::SkillType skillinuse);
int GetTotalToHit(EQEmu::skills::SkillType skill, int chance_mod); // compute_tohit + spell bonuses
int compute_defense();
int GetTotalDefense(); // compute_defense + spell bonuses
bool CheckHitChance(Mob* attacker, EQEmu::skills::SkillType skillinuse, int chance_mod = 0);
virtual void TryCriticalHit(Mob *defender, uint16 skill, int &damage, int min_damage, ExtraAttackOptions *opts = nullptr);
void TryPetCriticalHit(Mob *defender, uint16 skill, int &damage);
virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse, int &damage);
bool CheckHitChance(Mob* attacker, DamageHitInfo &hit);
void TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
void TryPetCriticalHit(Mob *defender, DamageHitInfo &hit);
virtual bool TryFinishingBlow(Mob *defender, int &damage);
int TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse);
int TryAssassinate(Mob* defender, EQEmu::skills::SkillType skillInUse, uint16 ReuseTime);
int TryAssassinate(Mob* defender, EQEmu::skills::SkillType skillInUse);
virtual void DoRiposte(Mob* defender);
void ApplyMeleeDamageBonus(uint16 skill, int &damage,ExtraAttackOptions *opts = nullptr);
void ApplyMeleeDamageMods(uint16 skill, int &damage, Mob * defender = nullptr, ExtraAttackOptions *opts = nullptr);
int ACSum();
int offense(EQEmu::skills::SkillType skill);
void CalcAC() { mitigation_ac = ACSum(); }
@ -184,12 +185,12 @@ public:
double GetSoftcapReturns();
int GetClassRaceACBonus();
inline int GetMitigationAC() { return mitigation_ac; }
void MeleeMitigation(Mob *attacker, int &damage, int base_damage, int offense, EQEmu::skills::SkillType, ExtraAttackOptions *opts = nullptr);
double RollD20(double offense, double mitigation); // CALL THIS FROM THE DEFENDER
void MeleeMitigation(Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
double RollD20(int offense, int mitigation); // CALL THIS FROM THE DEFENDER
bool CombatRange(Mob* other);
virtual inline bool IsBerserk() { return false; } // only clients
void RogueEvade(Mob *other);
void CommonOutgoingHitSuccess(Mob* defender, int &damage, int min_damage, int min_mod, EQEmu::skills::SkillType skillInUse, ExtraAttackOptions *opts = nullptr);
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
void BreakInvisibleSpells();
virtual void CancelSneakHide();
void CommonBreakInvisible();
@ -794,7 +795,7 @@ public:
uint8 GetWeaponDamageBonus(const EQEmu::ItemData* weapon, bool offhand = false);
const DamageTable &GetDamageTable() const;
void ApplyDamageTable(int &damage, int offense);
void ApplyDamageTable(DamageHitInfo &hit);
virtual int GetHandToHandDamage(void);
bool CanThisClassDoubleAttack(void) const;
@ -817,7 +818,7 @@ public:
int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker);
int32 ReduceAllDamage(int32 damage);
void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int base_damage, int min_damage = 0, int32 hate_override = -1, int ReuseTime = 10, bool CheckHitChance = false, bool CanAvoid = true);
void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int base_damage, int min_damage = 0, int32 hate_override = -1, int ReuseTime = 10);
virtual void DoThrowingAttackDmg(Mob* other, const EQEmu::ItemInstance* RangeWeapon = nullptr, const EQEmu::ItemData* AmmoItem = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, int AmmoSlot = 0, float speed = 4.0f);
void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0);
virtual void DoArcheryAttackDmg(Mob* other, const EQEmu::ItemInstance* RangeWeapon = nullptr, const EQEmu::ItemInstance* Ammo = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, uint32 ammo_id = 0, const EQEmu::ItemData *AmmoItem = nullptr, int AmmoSlot = 0, float speed = 4.0f);
@ -1187,8 +1188,6 @@ protected:
void ExecWeaponProc(const EQEmu::ItemInstance* weapon, uint16 spell_id, Mob *on, int level_override = -1);
virtual float GetProcChances(float ProcBonus, uint16 hand = EQEmu::inventory::slotPrimary);
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQEmu::inventory::slotPrimary, Mob *on = nullptr);
virtual float GetSpecialProcChances(uint16 hand);
virtual float GetAssassinateProcChances(uint16 ReuseTime);
virtual float GetSkillProcChances(uint16 ReuseTime, uint16 hand = 0); // hand = MainCharm?
uint16 GetWeaponSpeedbyHand(uint16 hand);
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);

File diff suppressed because it is too large Load Diff