mirror of
https://github.com/EQEmu/Server.git
synced 2026-09-01 11:36:36 +00:00
Merge branch 'master' into eqstream
This commit is contained in:
+1134
-755
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -35,9 +35,9 @@ public:
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr, int special = 0) { return false; }
|
||||
ExtraAttackOptions *opts = nullptr) { return false; }
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
|
||||
+35
-20
@@ -46,6 +46,7 @@ void Mob::CalcBonuses()
|
||||
CalcMaxHP();
|
||||
CalcMaxMana();
|
||||
SetAttackTimer();
|
||||
CalcAC();
|
||||
|
||||
rooted = FindType(SE_Root);
|
||||
}
|
||||
@@ -669,6 +670,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
}
|
||||
|
||||
switch (effect) {
|
||||
case SE_ACv2:
|
||||
case SE_ArmorClass:
|
||||
newbon->AC += base1;
|
||||
break;
|
||||
// Note: AA effects that use accuracy are skill limited, while spell effect is not.
|
||||
case SE_Accuracy:
|
||||
// Bad data or unsupported new skill
|
||||
@@ -1308,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;
|
||||
}
|
||||
|
||||
@@ -1322,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;
|
||||
}
|
||||
|
||||
@@ -1381,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:
|
||||
@@ -1527,9 +1535,6 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
}
|
||||
}
|
||||
|
||||
// THIS IS WRONG, leaving for now
|
||||
//this prolly suffer from roundoff error slightly...
|
||||
newbon->AC = newbon->AC * 10 / 34; //ratio determined impirically from client.
|
||||
if (GetClass() == BARD)
|
||||
newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
@@ -1927,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:
|
||||
@@ -3024,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;
|
||||
}
|
||||
|
||||
@@ -3040,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;
|
||||
}
|
||||
|
||||
@@ -4647,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:
|
||||
@@ -4662,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:
|
||||
|
||||
+320
-463
File diff suppressed because it is too large
Load Diff
+7
-6
@@ -206,9 +206,9 @@ public:
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); }
|
||||
@@ -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);
|
||||
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; }
|
||||
@@ -248,13 +248,12 @@ public:
|
||||
uint16 GetPrimarySkillValue();
|
||||
uint16 MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const;
|
||||
inline uint16 MaxSkill(EQEmu::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
virtual int GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target = nullptr);
|
||||
virtual void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance = false);
|
||||
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
||||
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
|
||||
virtual void RogueAssassinate(Mob* other);
|
||||
virtual void DoClassAttacks(Mob *target, bool IsRiposte=false);
|
||||
virtual bool TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse);
|
||||
virtual 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 ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg);
|
||||
bool CanDoSpecialAttack(Mob *other);
|
||||
virtual int32 CheckAggroAmount(uint16 spellid);
|
||||
@@ -294,6 +293,7 @@ public:
|
||||
bool UseDiscipline(uint32 spell_id, uint32 target);
|
||||
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
|
||||
bool GetNeedsCured(Mob *tar);
|
||||
bool GetNeedsHateRedux(Mob *tar);
|
||||
bool HasOrMayGetAggro();
|
||||
void SetDefaultBotStance();
|
||||
void CalcChanceToCast();
|
||||
@@ -503,7 +503,6 @@ public:
|
||||
|
||||
bool GetAltOutOfCombatBehavior() { return _altoutofcombatbehavior;}
|
||||
bool GetShowHelm() { return _showhelm; }
|
||||
inline virtual int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetSTR() const { return STR; }
|
||||
inline virtual int32 GetSTA() const { return STA; }
|
||||
inline virtual int32 GetDEX() const { return DEX; }
|
||||
@@ -672,6 +671,8 @@ private:
|
||||
glm::vec3 m_PreSummonLocation;
|
||||
uint8 _spellCastingChances[MaxStances][MaxSpellTypes];
|
||||
|
||||
Timer evade_timer;
|
||||
|
||||
std::shared_ptr<HealRotation> m_member_of_heal_rotation;
|
||||
|
||||
std::map<uint32, BotAA> botAAs;
|
||||
|
||||
@@ -436,6 +436,8 @@ public:
|
||||
case 10:
|
||||
if (spells[spell_id].effectdescnum != 65)
|
||||
break;
|
||||
if (IsEffectInSpell(spell_id, SE_NegateIfCombat))
|
||||
break;
|
||||
entry_prototype = new STMovementSpeedEntry();
|
||||
entry_prototype->SafeCastToMovementSpeed()->group = BCSpells::IsGroupType(target_type);
|
||||
break;
|
||||
|
||||
@@ -617,7 +617,8 @@ bool BotDatabase::LoadBuffs(Bot* bot_inst)
|
||||
" `caston_x`,"
|
||||
" `caston_y`,"
|
||||
" `caston_z`,"
|
||||
" `extra_di_chance`"
|
||||
" `extra_di_chance`,"
|
||||
" `instrument_mod`"
|
||||
" FROM `bot_buffs`"
|
||||
" WHERE `bot_id` = '%u'",
|
||||
bot_inst->GetBotID()
|
||||
@@ -657,6 +658,7 @@ bool BotDatabase::LoadBuffs(Bot* bot_inst)
|
||||
bot_buffs[buff_count].caston_y = atoi(row[14]);
|
||||
bot_buffs[buff_count].caston_z = atoi(row[15]);
|
||||
bot_buffs[buff_count].ExtraDIChance = atoi(row[16]);
|
||||
bot_buffs[buff_count].instrument_mod = atoi(row[17]);
|
||||
bot_buffs[buff_count].casterid = 0;
|
||||
++buff_count;
|
||||
}
|
||||
|
||||
+71
-11
@@ -33,6 +33,7 @@ extern volatile bool RunLoops;
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/features.h"
|
||||
#include "../common/emu_legacy.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/guilds.h"
|
||||
#include "../common/rulesys.h"
|
||||
@@ -1997,6 +1998,7 @@ void Client::SetGM(bool toggle) {
|
||||
}
|
||||
|
||||
void Client::ReadBook(BookRequest_Struct *book) {
|
||||
int16 book_language=0;
|
||||
char *txtfile = book->txtfile;
|
||||
|
||||
if(txtfile[0] == '0' && txtfile[1] == '\0') {
|
||||
@@ -2004,7 +2006,7 @@ void Client::ReadBook(BookRequest_Struct *book) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string booktxt2 = database.GetBook(txtfile);
|
||||
std::string booktxt2 = database.GetBook(txtfile, &book_language);
|
||||
int length = booktxt2.length();
|
||||
|
||||
if (booktxt2[0] != '\0') {
|
||||
@@ -2015,21 +2017,47 @@ void Client::ReadBook(BookRequest_Struct *book) {
|
||||
|
||||
BookText_Struct *out = (BookText_Struct *) outapp->pBuffer;
|
||||
out->window = book->window;
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
const EQEmu::ItemInstance *inst = m_inv[book->invslot];
|
||||
|
||||
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
|
||||
// Find out what slot the book was read from.
|
||||
// SoF+ need to look up book type for the output message.
|
||||
int16 read_from_slot;
|
||||
|
||||
if (book->subslot >= 0) {
|
||||
uint16 offset;
|
||||
offset = (book->invslot-23) * 10; // How many packs to skip.
|
||||
read_from_slot = 251 + offset + book->subslot;
|
||||
}
|
||||
else {
|
||||
read_from_slot = book->invslot -1;
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance *inst = 0;
|
||||
|
||||
if (read_from_slot <= EQEmu::legacy::SLOT_PERSONAL_BAGS_END)
|
||||
{
|
||||
inst = m_inv[read_from_slot];
|
||||
}
|
||||
|
||||
if(inst)
|
||||
out->type = inst->GetItem()->Book;
|
||||
else
|
||||
out->type = book->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
out->type = book->type;
|
||||
}
|
||||
out->invslot = book->invslot;
|
||||
|
||||
memcpy(out->booktext, booktxt2.c_str(), length);
|
||||
|
||||
if (book_language > 0 && book_language < MAX_PP_LANGUAGE) {
|
||||
if (m_pp.languages[book_language] < 100) {
|
||||
GarbleMessage(out->booktext, (100 - m_pp.languages[book_language]));
|
||||
}
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -6861,16 +6889,46 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
indP + "Wind: " + itoa(GetWindMod()) + "<br>";
|
||||
}
|
||||
|
||||
EQEmu::skills::SkillType skill = EQEmu::skills::SkillHandtoHand;
|
||||
auto *inst = GetInv().GetItem(EQEmu::inventory::slotPrimary);
|
||||
if (inst && inst->IsClassCommon()) {
|
||||
switch (inst->GetItem()->ItemType) {
|
||||
case EQEmu::item::ItemType1HSlash:
|
||||
skill = EQEmu::skills::Skill1HSlashing;
|
||||
break;
|
||||
case EQEmu::item::ItemType2HSlash:
|
||||
skill = EQEmu::skills::Skill2HSlashing;
|
||||
break;
|
||||
case EQEmu::item::ItemType1HPiercing:
|
||||
skill = EQEmu::skills::Skill1HPiercing;
|
||||
break;
|
||||
case EQEmu::item::ItemType1HBlunt:
|
||||
skill = EQEmu::skills::Skill1HBlunt;
|
||||
break;
|
||||
case EQEmu::item::ItemType2HBlunt:
|
||||
skill = EQEmu::skills::Skill2HBlunt;
|
||||
break;
|
||||
case EQEmu::item::ItemType2HPiercing:
|
||||
if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2)
|
||||
skill = EQEmu::skills::Skill1HPiercing;
|
||||
else
|
||||
skill = EQEmu::skills::Skill2HPiercing;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream final_string;
|
||||
final_string <<
|
||||
/* C/L/R */ indP << "Class: " << class_Name << indS << "Level: " << static_cast<int>(GetLevel()) << indS << "Race: " << race_Name << "<br>" <<
|
||||
/* Runes */ indP << "Rune: " << rune_number << indL << indS << "Spell Rune: " << magic_rune_number << "<br>" <<
|
||||
/* HP/M/E */ HME_row <<
|
||||
/* DS */ indP << "DS: " << (itembonuses.DamageShield + spellbonuses.DamageShield*-1) << " (Spell: " << (spellbonuses.DamageShield*-1) << " + Item: " << itembonuses.DamageShield << " / " << RuleI(Character, ItemDamageShieldCap) << ")<br>" <<
|
||||
/* Atk */ indP << "<c \"#CCFF00\">ATK: " << GetTotalATK() << "</c><br>" <<
|
||||
/* Atk2 */ indP << "- Base: " << GetATKRating() << " | Item: " << itembonuses.ATK << " (" << RuleI(Character, ItemATKCap) << ")~Used: " << (itembonuses.ATK * 1.342) << " | Spell: " << spellbonuses.ATK << "<br>" <<
|
||||
/* AC */ indP << "<c \"#CCFF00\">AC: " << CalcAC() << "</c><br>" <<
|
||||
/* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
|
||||
/* Atk */ indP << "<c \"#CCFF00\">tohit: " << compute_tohit(skill) << " / " << GetTotalToHit(skill, 0) << "</c><br>" <<
|
||||
/* Atk2 */ indP << "- Offense: " << offense(skill) << " | Item: " << itembonuses.ATK << " (" << RuleI(Character, ItemATKCap) << ")~Used: " << (itembonuses.ATK * 1.342) << " | Spell: " << spellbonuses.ATK << "<br>" <<
|
||||
/* AC */ indP << "<c \"#CCFF00\">mitigation AC: " << GetMitigationAC() << "</c><br>" <<
|
||||
/* AC2 */ indP << "- defense: " << compute_defense() << " / " << GetTotalDefense() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
|
||||
/* Haste */ indP << "<c \"#CCFF00\">Haste: " << GetHaste() << "</c><br>" <<
|
||||
/* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br>" <<
|
||||
/* RunSpeed*/ indP << "<c \"#CCFF00\">Runspeed: " << GetRunspeed() << "</c><br>" <<
|
||||
@@ -6908,7 +6966,9 @@ void Client::SendStatsWindow(Client* client, bool use_window)
|
||||
client->Message(15, "~~~~~ %s %s ~~~~~", GetCleanName(), GetLastName());
|
||||
client->Message(0, " Level: %i Class: %i Race: %i DS: %i/%i Size: %1.1f Weight: %.1f/%d ", GetLevel(), GetClass(), GetRace(), GetDS(), RuleI(Character, ItemDamageShieldCap), GetSize(), (float)CalcCurrentWeight() / 10.0f, GetSTR());
|
||||
client->Message(0, " HP: %i/%i HP Regen: %i/%i",GetHP(), GetMaxHP(), CalcHPRegen(), CalcHPRegenCap());
|
||||
client->Message(0, " AC: %i ( Mit.: %i + Avoid.: %i + Spell: %i ) | Shield AC: %i", CalcAC(), GetACMit(), GetACAvoid(), spellbonuses.AC, shield_ac);
|
||||
client->Message(0, " compute_tohit: %i TotalToHit: %i", compute_tohit(skill), GetTotalToHit(skill, 0));
|
||||
client->Message(0, " compute_defense: %i TotalDefense: %i", compute_defense(), GetTotalDefense());
|
||||
client->Message(0, " offense: %i mitigation ac: %i", offense(skill), GetMitigationAC());
|
||||
if(CalcMaxMana() > 0)
|
||||
client->Message(0, " Mana: %i/%i Mana Regen: %i/%i", GetMana(), GetMaxMana(), CalcManaRegen(), CalcManaRegenCap());
|
||||
client->Message(0, " End.: %i/%i End. Regen: %i/%i",GetEndurance(), GetMaxEndurance(), CalcEnduranceRegen(), CalcEnduranceRegenCap());
|
||||
|
||||
+4
-9
@@ -221,18 +221,18 @@ public:
|
||||
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); }
|
||||
virtual Group* GetGroup() { return entity_list.GetGroupByClient(this); }
|
||||
virtual inline bool IsBerserk() { return berserk; }
|
||||
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
|
||||
virtual void SetAttackTimer();
|
||||
int GetQuiverHaste(int delay);
|
||||
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
|
||||
int DoDamageCaps(int base_damage);
|
||||
|
||||
void AI_Init();
|
||||
void AI_Start(uint32 iMoveDelay = 0);
|
||||
@@ -418,8 +418,6 @@ public:
|
||||
|
||||
virtual void CalcBonuses();
|
||||
//these are all precalculated now
|
||||
inline virtual int32 GetAC() const { return AC; }
|
||||
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; }
|
||||
inline virtual int GetHaste() const { return Haste; }
|
||||
int GetRawACNoShield(int &shield_ac) const;
|
||||
@@ -1292,7 +1290,7 @@ private:
|
||||
void OPGMEndTraining(const EQApplicationPacket *app);
|
||||
void OPGMTrainSkill(const EQApplicationPacket *app);
|
||||
void OPGMSummon(const EQApplicationPacket *app);
|
||||
void OPCombatAbility(const EQApplicationPacket *app);
|
||||
void OPCombatAbility(const CombatAbility_Struct *ca_atk);
|
||||
|
||||
// Bandolier Methods
|
||||
void CreateBandolier(const EQApplicationPacket *app);
|
||||
@@ -1301,9 +1299,6 @@ private:
|
||||
|
||||
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
|
||||
|
||||
int32 CalcAC();
|
||||
int32 GetACMit();
|
||||
int32 GetACAvoid();
|
||||
int32 CalcATK();
|
||||
int32 CalcItemATKCap();
|
||||
int32 CalcHaste();
|
||||
|
||||
@@ -1025,111 +1025,6 @@ int32 Client::acmod()
|
||||
return 0;
|
||||
};
|
||||
|
||||
// This is a testing formula for AC, the value this returns should be the same value as the one the client shows...
|
||||
// ac1 and ac2 are probably the damage migitation and damage avoidance numbers, not sure which is which.
|
||||
// I forgot to include the iksar defense bonus and i cant find my notes now...
|
||||
// AC from spells are not included (cant even cast spells yet..)
|
||||
int32 Client::CalcAC()
|
||||
{
|
||||
// new formula
|
||||
int avoidance = (acmod() + ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9);
|
||||
if (avoidance < 0) {
|
||||
avoidance = 0;
|
||||
}
|
||||
|
||||
if (RuleB(Character, EnableAvoidanceCap)) {
|
||||
if (avoidance > RuleI(Character, AvoidanceCap)) {
|
||||
avoidance = RuleI(Character, AvoidanceCap);
|
||||
}
|
||||
}
|
||||
|
||||
int mitigation = 0;
|
||||
if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
|
||||
//something is wrong with this, naked casters have the wrong natural AC
|
||||
// mitigation = (spellbonuses.AC/3) + (GetSkill(DEFENSE)/2) + (itembonuses.AC+1);
|
||||
mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1);
|
||||
//this might be off by 4..
|
||||
mitigation -= 4;
|
||||
}
|
||||
else {
|
||||
// mitigation = (spellbonuses.AC/4) + (GetSkill(DEFENSE)/3) + ((itembonuses.AC*4)/3);
|
||||
mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3);
|
||||
if (m_pp.class_ == MONK) {
|
||||
mitigation += GetLevel() * 13 / 10; //the 13/10 might be wrong, but it is close...
|
||||
}
|
||||
}
|
||||
int displayed = 0;
|
||||
displayed += ((avoidance + mitigation) * 1000) / 847; //natural AC
|
||||
//Iksar AC, untested
|
||||
if (GetRace() == IKSAR) {
|
||||
displayed += 12;
|
||||
int iksarlevel = GetLevel();
|
||||
iksarlevel -= 10;
|
||||
if (iksarlevel > 25) {
|
||||
iksarlevel = 25;
|
||||
}
|
||||
if (iksarlevel > 0) {
|
||||
displayed += iksarlevel * 12 / 10;
|
||||
}
|
||||
}
|
||||
// Shield AC bonus for HeroicSTR
|
||||
if (itembonuses.HeroicSTR) {
|
||||
bool equiped = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary);
|
||||
if (equiped) {
|
||||
uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary)->GetItem()->ItemType;
|
||||
if (shield == EQEmu::item::ItemTypeShield) {
|
||||
displayed += itembonuses.HeroicSTR / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
//spell AC bonuses are added directly to natural total
|
||||
displayed += spellbonuses.AC;
|
||||
AC = displayed;
|
||||
return (AC);
|
||||
}
|
||||
|
||||
int32 Client::GetACMit()
|
||||
{
|
||||
int mitigation = 0;
|
||||
if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
|
||||
mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1);
|
||||
mitigation -= 4;
|
||||
}
|
||||
else {
|
||||
mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3);
|
||||
if (m_pp.class_ == MONK) {
|
||||
mitigation += GetLevel() * 13 / 10; //the 13/10 might be wrong, but it is close...
|
||||
}
|
||||
}
|
||||
// Shield AC bonus for HeroicSTR
|
||||
if (itembonuses.HeroicSTR) {
|
||||
bool equiped = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary);
|
||||
if (equiped) {
|
||||
uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary)->GetItem()->ItemType;
|
||||
if (shield == EQEmu::item::ItemTypeShield) {
|
||||
mitigation += itembonuses.HeroicSTR / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (mitigation * 1000 / 847);
|
||||
}
|
||||
|
||||
int32 Client::GetACAvoid()
|
||||
{
|
||||
int32 avoidance = (acmod() + ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9);
|
||||
if (avoidance < 0) {
|
||||
avoidance = 0;
|
||||
}
|
||||
|
||||
if (RuleB(Character, EnableAvoidanceCap)) {
|
||||
if ((avoidance * 1000 / 847) > RuleI(Character, AvoidanceCap)) {
|
||||
return RuleI(Character, AvoidanceCap);
|
||||
}
|
||||
}
|
||||
|
||||
return (avoidance * 1000 / 847);
|
||||
}
|
||||
|
||||
int32 Client::CalcMaxMana()
|
||||
{
|
||||
switch (GetCasterClass()) {
|
||||
|
||||
@@ -4621,7 +4621,8 @@ void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app)
|
||||
std::cout << "Wrong size on OP_CombatAbility. Got: " << app->size << ", Expected: " << sizeof(CombatAbility_Struct) << std::endl;
|
||||
return;
|
||||
}
|
||||
OPCombatAbility(app);
|
||||
auto ca_atk = (CombatAbility_Struct *)app->pBuffer;
|
||||
OPCombatAbility(ca_atk);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+27
-2
@@ -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
|
||||
@@ -638,5 +645,23 @@ struct ExtraAttackOptions {
|
||||
|
||||
};
|
||||
|
||||
struct DamageTable {
|
||||
int32 max_extra; // max extra damage
|
||||
int32 chance; // chance not to apply?
|
||||
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
|
||||
|
||||
|
||||
+2
-2
@@ -52,8 +52,8 @@ class Corpse : public Mob {
|
||||
|
||||
/* Corpse: General */
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0) { return false; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; }
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
|
||||
+2
-2
@@ -35,9 +35,9 @@ public:
|
||||
|
||||
//abstract virtual function implementations required by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; }
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||
ExtraAttackOptions *opts = nullptr, int special = 0) {
|
||||
ExtraAttackOptions *opts = nullptr) {
|
||||
return false;
|
||||
}
|
||||
virtual bool HasRaid() { return false; }
|
||||
|
||||
+1
-1
@@ -553,7 +553,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
|
||||
auto mob = entity_list.GetMobID(id);
|
||||
if (mob) {
|
||||
++hit_count;
|
||||
caster->ProcessAttackRounds(mob, opts, 1);
|
||||
caster->ProcessAttackRounds(mob, opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -332,8 +332,10 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
CastToMob()->AddProcToWeapon(item2->Proc.Effect, true);
|
||||
|
||||
eslot = EQEmu::textures::weaponPrimary;
|
||||
if (item2->Damage > 0)
|
||||
if (item2->Damage > 0) {
|
||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||
SetFacestab(true);
|
||||
}
|
||||
if (item2->IsType2HWeapon())
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
+8
-27
@@ -4426,20 +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)) {
|
||||
if(RuleB(Combat, UseIntervalAC))
|
||||
dmg = GetKickDamage();
|
||||
else
|
||||
dmg = zone->random.Int(1, GetKickDamage());
|
||||
|
||||
}
|
||||
}
|
||||
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0)
|
||||
dmg = DMG_INVULNERABLE;
|
||||
|
||||
reuse = KickReuseTime * 1000;
|
||||
DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse);
|
||||
@@ -4448,19 +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)) {
|
||||
if(RuleB(Combat, UseIntervalAC))
|
||||
dmg = GetBashDamage();
|
||||
else
|
||||
dmg = zone->random.Int(1, GetBashDamage());
|
||||
}
|
||||
}
|
||||
if (GetWeaponDamage(target, (const EQEmu::ItemData*)nullptr) <= 0)
|
||||
dmg = DMG_INVULNERABLE;
|
||||
|
||||
reuse = BashReuseTime * 1000;
|
||||
DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse);
|
||||
@@ -4474,7 +4455,7 @@ void Merc::DoClassAttacks(Mob *target) {
|
||||
classattack_timer.Start(reuse / HasteModifier);
|
||||
}
|
||||
|
||||
bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, int special)
|
||||
bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
|
||||
{
|
||||
if (!other) {
|
||||
SetTarget(nullptr);
|
||||
@@ -4485,7 +4466,7 @@ bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, boo
|
||||
return NPC::Attack(other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts);
|
||||
}
|
||||
|
||||
void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, int special)
|
||||
void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, eSpecialAttacks special)
|
||||
{
|
||||
if(IsDead() || IsCorpse())
|
||||
return;
|
||||
|
||||
+2
-3
@@ -65,9 +65,9 @@ public:
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
@@ -197,7 +197,6 @@ public:
|
||||
virtual void CalcBonuses();
|
||||
int32 GetEndurance() const {return cur_end;} //This gets our current endurance
|
||||
inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); }
|
||||
inline virtual int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetATK() const { return ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
int32 GetRawACNoShield(int &shield_ac) const;
|
||||
|
||||
+26
-2
@@ -110,7 +110,9 @@ Mob::Mob(const char* in_name,
|
||||
m_TargetV(glm::vec3()),
|
||||
flee_timer(FLEE_CHECK_TIMER),
|
||||
m_Position(position),
|
||||
tmHidden(-1)
|
||||
tmHidden(-1),
|
||||
mitigation_ac(0),
|
||||
m_specialattacks(eSpecialAttacks::None)
|
||||
{
|
||||
targeted = 0;
|
||||
tar_ndx=0;
|
||||
@@ -212,6 +214,7 @@ Mob::Mob(const char* in_name,
|
||||
has_shieldequiped = false;
|
||||
has_twohandbluntequiped = false;
|
||||
has_twohanderequipped = false;
|
||||
can_facestab = false;
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
@@ -285,6 +288,8 @@ Mob::Mob(const char* in_name,
|
||||
armor_tint.Slot[i].Color = in_armor_tint.Slot[i].Color;
|
||||
}
|
||||
|
||||
std::fill(std::begin(m_spellHitsLeft), std::end(m_spellHitsLeft), 0);
|
||||
|
||||
m_Delta = glm::vec4();
|
||||
animation = 0;
|
||||
|
||||
@@ -1497,6 +1502,10 @@ void Mob::ShowStats(Client* client)
|
||||
if (IsAIControlled()) {
|
||||
client->Message(0, " AggroRange: %1.0f AssistRange: %1.0f", GetAggroRange(), GetAssistRange());
|
||||
}
|
||||
|
||||
client->Message(0, " compute_tohit: %i TotalToHit: %i", compute_tohit(EQEmu::skills::SkillHandtoHand), GetTotalToHit(EQEmu::skills::SkillHandtoHand, 0));
|
||||
client->Message(0, " compute_defense: %i TotalDefense: %i", compute_defense(), GetTotalDefense());
|
||||
client->Message(0, " offense: %i mitigation ac: %i", offense(EQEmu::skills::SkillHandtoHand), GetMitigationAC());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2773,7 +2782,22 @@ void Mob::SendWearChange(uint8 material_slot, Client *one_client)
|
||||
wc->material = GetEquipmentMaterial(material_slot);
|
||||
wc->elite_material = IsEliteMaterialItem(material_slot);
|
||||
wc->hero_forge_model = GetHerosForgeModel(material_slot);
|
||||
|
||||
#ifdef BOTS
|
||||
if (IsBot()) {
|
||||
auto item_inst = CastToBot()->GetBotItem(EQEmu::InventoryProfile::CalcSlotFromMaterial(material_slot));
|
||||
if (item_inst)
|
||||
wc->color.Color = item_inst->GetColor();
|
||||
else
|
||||
wc->color.Color = 0;
|
||||
}
|
||||
else {
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
}
|
||||
#else
|
||||
wc->color.Color = GetEquipmentColor(material_slot);
|
||||
#endif
|
||||
|
||||
wc->wear_slot_id = material_slot;
|
||||
|
||||
if (!one_client)
|
||||
@@ -4644,7 +4668,7 @@ void Mob::SetRaidGrouped(bool v)
|
||||
}
|
||||
}
|
||||
|
||||
int16 Mob::GetCriticalChanceBonus(uint16 skill)
|
||||
int Mob::GetCriticalChanceBonus(uint16 skill)
|
||||
{
|
||||
int critical_chance = 0;
|
||||
|
||||
|
||||
+56
-32
@@ -54,6 +54,13 @@ namespace EQEmu
|
||||
class ItemInstance;
|
||||
}
|
||||
|
||||
enum class eSpecialAttacks : int {
|
||||
None,
|
||||
Rampage,
|
||||
AERampage,
|
||||
ChaoticStab
|
||||
};
|
||||
|
||||
class Mob : public Entity {
|
||||
public:
|
||||
enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD,
|
||||
@@ -152,45 +159,54 @@ public:
|
||||
float HeadingAngleToMob(Mob *other); // to keep consistent with client generated messages
|
||||
virtual void RangedAttack(Mob* other) { }
|
||||
virtual void ThrowingAttack(Mob* other) { }
|
||||
uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg);
|
||||
// 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, int special = 0) = 0;
|
||||
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, int32 &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();
|
||||
virtual bool CheckHitChance(Mob* attacker, EQEmu::skills::SkillType skillinuse, int chance_mod = 0);
|
||||
virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr);
|
||||
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
|
||||
virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse);
|
||||
uint32 TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse);
|
||||
uint32 TryAssassinate(Mob* defender, EQEmu::skills::SkillType skillInUse, uint16 ReuseTime);
|
||||
int GetTotalDefense(); // compute_defense + spell bonuses
|
||||
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);
|
||||
virtual void DoRiposte(Mob* defender);
|
||||
void ApplyMeleeDamageBonus(uint16 skill, int32 &damage,ExtraAttackOptions *opts = nullptr);
|
||||
virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr);
|
||||
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
|
||||
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(); }
|
||||
int GetACSoftcap();
|
||||
double GetSoftcapReturns();
|
||||
int GetClassRaceACBonus();
|
||||
inline int GetMitigationAC() { return mitigation_ac; }
|
||||
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, int32 &damage, EQEmu::skills::SkillType skillInUse, ExtraAttackOptions *opts = nullptr);
|
||||
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||
void BreakInvisibleSpells();
|
||||
virtual void CancelSneakHide();
|
||||
void CommonBreakInvisible();
|
||||
void CommonBreakInvisibleFromCombat();
|
||||
bool HasDied();
|
||||
virtual bool CheckDualWield();
|
||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool CheckDoubleAttack();
|
||||
// inline process for places where we need to do them outside of the AI_Process
|
||||
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0)
|
||||
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr)
|
||||
{
|
||||
if (target) {
|
||||
DoMainHandAttackRounds(target, opts, special);
|
||||
DoMainHandAttackRounds(target, opts);
|
||||
if (CanThisClassDualWield())
|
||||
DoOffHandAttackRounds(target, opts, special);
|
||||
DoOffHandAttackRounds(target, opts);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -357,6 +373,8 @@ public:
|
||||
inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; }
|
||||
bool HasTwoHanderEquipped() { return has_twohanderequipped; }
|
||||
void SetTwoHanderEquipped(bool val) { has_twohanderequipped = val; }
|
||||
bool CanFacestab() { return can_facestab; }
|
||||
void SetFacestab(bool val) { can_facestab = val; }
|
||||
virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; }
|
||||
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
|
||||
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
@@ -367,7 +385,7 @@ public:
|
||||
bool AffectedBySpellExcludingSlot(int slot, int effect);
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0;
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill,
|
||||
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) = 0;
|
||||
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
|
||||
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
|
||||
inline void SetOOCRegen(int32 newoocregen) {oocregen = newoocregen;}
|
||||
@@ -404,9 +422,10 @@ public:
|
||||
strn0cpy(name, GetName(), 64); return; };
|
||||
inline Mob* GetTarget() const { return target; }
|
||||
virtual void SetTarget(Mob* mob);
|
||||
inline bool HasTargetReflection() const { return (target && target != this && target->target == this); }
|
||||
virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); }
|
||||
virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp); }
|
||||
inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; }
|
||||
inline int32 GetAC() const { return AC; }
|
||||
inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; }
|
||||
inline virtual int32 GetSTR() const { return STR + itembonuses.STR + spellbonuses.STR; }
|
||||
@@ -673,7 +692,7 @@ public:
|
||||
int16 GetMeleeMinDamageMod_SE(uint16 skill);
|
||||
int16 GetCrippBlowChance();
|
||||
int16 GetSkillReuseTime(uint16 skill);
|
||||
int16 GetCriticalChanceBonus(uint16 skill);
|
||||
int GetCriticalChanceBonus(uint16 skill);
|
||||
int16 GetSkillDmgAmt(uint16 skill);
|
||||
bool TryReflectSpell(uint32 spell_id);
|
||||
bool CanBlockSpell() const { return(spellbonuses.BlockNextSpell); }
|
||||
@@ -778,7 +797,8 @@ public:
|
||||
int32 GetMeleeMitigation();
|
||||
|
||||
uint8 GetWeaponDamageBonus(const EQEmu::ItemData* weapon, bool offhand = false);
|
||||
uint16 GetDamageTable(EQEmu::skills::SkillType skillinuse);
|
||||
const DamageTable &GetDamageTable() const;
|
||||
void ApplyDamageTable(DamageHitInfo &hit);
|
||||
virtual int GetHandToHandDamage(void);
|
||||
|
||||
bool CanThisClassDoubleAttack(void) const;
|
||||
@@ -801,9 +821,9 @@ public:
|
||||
int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker);
|
||||
int32 ReduceAllDamage(int32 damage);
|
||||
|
||||
virtual void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, 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);
|
||||
virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0);
|
||||
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);
|
||||
bool TryProjectileAttack(Mob* other, const EQEmu::ItemData *item, EQEmu::skills::SkillType skillInUse, uint16 weapon_dmg, const EQEmu::ItemInstance* RangeWeapon, const EQEmu::ItemInstance* Ammo, int AmmoSlot, float speed);
|
||||
void ProjectileAttack();
|
||||
@@ -816,6 +836,7 @@ public:
|
||||
bool AddRampage(Mob*);
|
||||
void ClearRampage();
|
||||
void AreaRampage(ExtraAttackOptions *opts);
|
||||
inline bool IsSpecialAttack(eSpecialAttacks in) { return m_specialattacks == in; }
|
||||
|
||||
void StartEnrage();
|
||||
void ProcessEnrage();
|
||||
@@ -1042,7 +1063,7 @@ public:
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const EQEmu::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0);
|
||||
void CommonDamage(Mob* other, int &damage, const uint16 spell_id, const EQEmu::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||
float _GetMovementSpeed(int mod) const;
|
||||
int _GetWalkSpeed() const;
|
||||
@@ -1079,6 +1100,7 @@ protected:
|
||||
bool multitexture;
|
||||
|
||||
int AC;
|
||||
int mitigation_ac; // cached Mob::ACSum
|
||||
int32 ATK;
|
||||
int32 STR;
|
||||
int32 STA;
|
||||
@@ -1150,6 +1172,7 @@ protected:
|
||||
int base_walkspeed;
|
||||
int base_fearspeed;
|
||||
int current_speed;
|
||||
eSpecialAttacks m_specialattacks;
|
||||
|
||||
uint32 pLastChange;
|
||||
bool held;
|
||||
@@ -1168,15 +1191,14 @@ 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);
|
||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||
int GetKickDamage();
|
||||
int GetBashDamage();
|
||||
virtual void ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg);
|
||||
#ifdef BOTS
|
||||
virtual
|
||||
#endif
|
||||
int GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target = nullptr);
|
||||
virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; }
|
||||
void CalculateNewFearpoint();
|
||||
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||
@@ -1211,7 +1233,7 @@ protected:
|
||||
Timer attack_dw_timer;
|
||||
Timer ranged_timer;
|
||||
float attack_speed; //% increase/decrease in attack speed (not haste)
|
||||
int8 attack_delay; //delay between attacks in 10ths of seconds
|
||||
int attack_delay; //delay between attacks in 10ths of seconds
|
||||
int16 slow_mitigation; // Allows for a slow mitigation (100 = 100%, 50% = 50%)
|
||||
Timer tic_timer;
|
||||
Timer mana_timer;
|
||||
@@ -1278,6 +1300,7 @@ protected:
|
||||
bool has_shieldequiped;
|
||||
bool has_twohandbluntequiped;
|
||||
bool has_twohanderequipped;
|
||||
bool can_facestab;
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
@@ -1394,7 +1417,8 @@ protected:
|
||||
|
||||
glm::vec3 m_TargetRing;
|
||||
|
||||
uint32 m_spellHitsLeft[38]; // Used to track which spells will have their numhits incremented when spell finishes casting, 38 Buffslots
|
||||
// we might want to do this differently, we gotta do max NPC buffs ... which is 97
|
||||
uint32 m_spellHitsLeft[EQEmu::constants::TotalBuffs]; // Used to track which spells will have their numhits incremented when spell finishes casting
|
||||
int flymode;
|
||||
bool m_targetable;
|
||||
int QGVarDuration(const char *fmt);
|
||||
|
||||
+12
-19
@@ -1160,11 +1160,8 @@ void Mob::AI_Process() {
|
||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){
|
||||
if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] || aabonuses.PC_Pet_Rampage[0]){
|
||||
int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] + aabonuses.PC_Pet_Rampage[0];
|
||||
int dmg_mod = spellbonuses.PC_Pet_Rampage[1] + itembonuses.PC_Pet_Rampage[1] + aabonuses.PC_Pet_Rampage[1];
|
||||
if(zone->random.Roll(chance)) {
|
||||
ExtraAttackOptions opts;
|
||||
opts.damage_percent = dmg_mod / 100.0f;
|
||||
Rampage(&opts);
|
||||
Rampage(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1175,12 +1172,7 @@ void Mob::AI_Process() {
|
||||
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
|
||||
if(zone->random.Roll(rampage_chance)) {
|
||||
ExtraAttackOptions opts;
|
||||
int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 2);
|
||||
if(cur > 0) {
|
||||
opts.damage_percent = cur / 100.0f;
|
||||
}
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3);
|
||||
int cur = GetSpecialAbilityParam(SPECATK_RAMPAGE, 3);
|
||||
if(cur > 0) {
|
||||
opts.damage_flat = cur;
|
||||
}
|
||||
@@ -1215,12 +1207,7 @@ void Mob::AI_Process() {
|
||||
rampage_chance = rampage_chance > 0 ? rampage_chance : 20;
|
||||
if(zone->random.Roll(rampage_chance)) {
|
||||
ExtraAttackOptions opts;
|
||||
int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 2);
|
||||
if(cur > 0) {
|
||||
opts.damage_percent = cur / 100.0f;
|
||||
}
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3);
|
||||
int cur = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 3);
|
||||
if(cur > 0) {
|
||||
opts.damage_flat = cur;
|
||||
}
|
||||
@@ -1992,6 +1979,8 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
||||
rampage_targets = RuleI(Combat, DefaultRampageTargets);
|
||||
if (rampage_targets > RuleI(Combat, MaxRampageTargets))
|
||||
rampage_targets = RuleI(Combat, MaxRampageTargets);
|
||||
|
||||
m_specialattacks = eSpecialAttacks::Rampage;
|
||||
for (int i = 0; i < RampageArray.size(); i++) {
|
||||
if (index_hit >= rampage_targets)
|
||||
break;
|
||||
@@ -2001,14 +1990,16 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
||||
if (m_target == GetTarget())
|
||||
continue;
|
||||
if (CombatRange(m_target)) {
|
||||
ProcessAttackRounds(m_target, opts, 2);
|
||||
ProcessAttackRounds(m_target, opts);
|
||||
index_hit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets)
|
||||
ProcessAttackRounds(GetTarget(), opts, 2);
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
|
||||
m_specialattacks = eSpecialAttacks::None;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2024,10 +2015,12 @@ void Mob::AreaRampage(ExtraAttackOptions *opts)
|
||||
|
||||
int rampage_targets = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 1);
|
||||
rampage_targets = rampage_targets > 0 ? rampage_targets : -1;
|
||||
m_specialattacks = eSpecialAttacks::AERampage;
|
||||
index_hit = hate_list.AreaRampage(this, GetTarget(), rampage_targets, opts);
|
||||
|
||||
if(index_hit == 0)
|
||||
ProcessAttackRounds(GetTarget(), opts, 1);
|
||||
ProcessAttackRounds(GetTarget(), opts);
|
||||
m_specialattacks = eSpecialAttacks::None;
|
||||
}
|
||||
|
||||
uint32 Mob::GetLevelCon(uint8 mylevel, uint8 iOtherLevel) {
|
||||
|
||||
+21
-6
@@ -201,6 +201,9 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if
|
||||
CalcNPCDamage();
|
||||
}
|
||||
|
||||
base_damage = round((max_dmg - min_dmg) / 1.9);
|
||||
min_damage = min_dmg - round(base_damage / 10.0);
|
||||
|
||||
accuracy_rating = d->accuracy_rating;
|
||||
avoidance_rating = d->avoidance_rating;
|
||||
ATK = d->ATK;
|
||||
@@ -1054,7 +1057,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client*
|
||||
npc_type->WIS = 150;
|
||||
npc_type->CHA = 150;
|
||||
|
||||
npc_type->attack_delay = 30;
|
||||
npc_type->attack_delay = 3000;
|
||||
|
||||
npc_type->prim_melee_type = 28;
|
||||
npc_type->sec_melee_type = 28;
|
||||
@@ -1956,10 +1959,10 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
id[i] = std::tolower(id[i]);
|
||||
}
|
||||
|
||||
if(id == "ac") { AC = atoi(val.c_str()); return; }
|
||||
if(id == "ac") { AC = atoi(val.c_str()); CalcAC(); return; }
|
||||
else if(id == "str") { STR = atoi(val.c_str()); return; }
|
||||
else if(id == "sta") { STA = atoi(val.c_str()); return; }
|
||||
else if(id == "agi") { AGI = atoi(val.c_str()); return; }
|
||||
else if(id == "agi") { AGI = atoi(val.c_str()); CalcAC(); return; }
|
||||
else if(id == "dex") { DEX = atoi(val.c_str()); return; }
|
||||
else if(id == "wis") { WIS = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
else if(id == "int" || id == "_int") { INT = atoi(val.c_str()); CalcMaxMana(); return; }
|
||||
@@ -1984,13 +1987,25 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue)
|
||||
else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; }
|
||||
else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; }
|
||||
else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; }
|
||||
else if(id == "attack_delay") { /* TODO: fix DB */attack_delay = atoi(val.c_str()) * 100; CalcBonuses(); return; }
|
||||
else if(id == "atk") { ATK = atoi(val.c_str()); return; }
|
||||
else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; }
|
||||
else if(id == "trackable") { trackable = atoi(val.c_str()); return; }
|
||||
else if(id == "min_hit") { min_dmg = atoi(val.c_str()); return; }
|
||||
else if(id == "max_hit") { max_dmg = atoi(val.c_str()); return; }
|
||||
else if(id == "min_hit") {
|
||||
min_dmg = atoi(val.c_str());
|
||||
// TODO: fix DB
|
||||
base_damage = round((max_dmg - min_dmg) / 1.9);
|
||||
min_damage = min_dmg - round(base_damage / 10.0);
|
||||
return;
|
||||
}
|
||||
else if(id == "max_hit") {
|
||||
max_dmg = atoi(val.c_str());
|
||||
// TODO: fix DB
|
||||
base_damage = round((max_dmg - min_dmg) / 1.9);
|
||||
min_damage = min_dmg - round(base_damage / 10.0);
|
||||
return;
|
||||
}
|
||||
else if(id == "attack_count") { attack_count = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis") { see_invis = atoi(val.c_str()); return; }
|
||||
else if(id == "see_invis_undead") { see_invis_undead = atoi(val.c_str()); return; }
|
||||
|
||||
+7
-3
@@ -109,9 +109,9 @@ public:
|
||||
|
||||
//abstract virtual function implementations requird by base abstract class
|
||||
virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0);
|
||||
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0);
|
||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
||||
virtual bool HasRaid() { return false; }
|
||||
virtual bool HasGroup() { return false; }
|
||||
virtual Raid* GetRaid() { return 0; }
|
||||
@@ -259,9 +259,11 @@ public:
|
||||
|
||||
uint32 GetMaxDMG() const {return max_dmg;}
|
||||
uint32 GetMinDMG() const {return min_dmg;}
|
||||
int GetBaseDamage() const { return base_damage; }
|
||||
int GetMinDamage() const { return min_damage; }
|
||||
float GetSlowMitigation() const { return slow_mitigation; }
|
||||
float GetAttackSpeed() const {return attack_speed;}
|
||||
uint8 GetAttackDelay() const {return attack_delay;}
|
||||
int GetAttackDelay() const {return attack_delay;}
|
||||
bool IsAnimal() const { return(bodytype == BT_Animal); }
|
||||
uint16 GetPetSpellID() const {return pet_spell_id;}
|
||||
void SetPetSpellID(uint16 amt) {pet_spell_id = amt;}
|
||||
@@ -463,6 +465,8 @@ protected:
|
||||
|
||||
uint32 max_dmg;
|
||||
uint32 min_dmg;
|
||||
int base_damage;
|
||||
int min_damage;
|
||||
int32 accuracy_rating;
|
||||
int32 avoidance_rating;
|
||||
int16 attack_count;
|
||||
|
||||
+3
-2
@@ -225,8 +225,7 @@ Object::Object(const char *model, float x, float y, float z, float heading, uint
|
||||
{
|
||||
user = nullptr;
|
||||
last_user = nullptr;
|
||||
EQEmu::ItemInstance* inst = nullptr;
|
||||
inst = new EQEmu::ItemInstance(ItemInstWorldContainer);
|
||||
EQEmu::ItemInstance* inst = new EQEmu::ItemInstance(ItemInstWorldContainer);
|
||||
|
||||
// Initialize members
|
||||
m_id = 0;
|
||||
@@ -257,6 +256,8 @@ Object::Object(const char *model, float x, float y, float z, float heading, uint
|
||||
strcpy(m_data.object_name, model);
|
||||
else
|
||||
strcpy(m_data.object_name, "IT64_ACTORDEF"); //default object name if model isn't specified for some unknown reason
|
||||
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
|
||||
+712
-1004
File diff suppressed because it is too large
Load Diff
@@ -5566,6 +5566,7 @@ void Client::InitializeBuffSlots()
|
||||
for(int x = 0; x < max_slots; ++x)
|
||||
{
|
||||
buffs[x].spellid = SPELL_UNKNOWN;
|
||||
buffs[x].UpdateClient = false;
|
||||
}
|
||||
current_buff_count = 0;
|
||||
}
|
||||
@@ -5582,6 +5583,7 @@ void NPC::InitializeBuffSlots()
|
||||
for(int x = 0; x < max_slots; ++x)
|
||||
{
|
||||
buffs[x].spellid = SPELL_UNKNOWN;
|
||||
buffs[x].UpdateClient = false;
|
||||
}
|
||||
current_buff_count = 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -486,7 +486,7 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh
|
||||
}
|
||||
|
||||
|
||||
damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating);
|
||||
//damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating);
|
||||
}
|
||||
|
||||
if (damage < 0)
|
||||
@@ -539,7 +539,7 @@ int32 Client::Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 mi
|
||||
float mit_rating, float atk_rating)
|
||||
{
|
||||
if (!attacker->IsNPC() || RuleB(Combat, UseOldDamageIntervalRules))
|
||||
return Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating);
|
||||
return 0; //Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating);
|
||||
int d = 10;
|
||||
// floats for the rounding issues
|
||||
float dmg_interval = (damage - minhit) / 19.0;
|
||||
@@ -613,7 +613,7 @@ int32 Client::GetMeleeDamage(Mob* other, bool GetMinDamage)
|
||||
}
|
||||
|
||||
int min_hit = 1;
|
||||
int max_hit = (2*weapon_damage*GetDamageTable(skillinuse)) / 100;
|
||||
int max_hit = 2;//(2*weapon_damage*GetDamageTable(skillinuse)) / 100;
|
||||
|
||||
if(GetLevel() < 10 && max_hit > RuleI(Combat, HitCapPre10))
|
||||
max_hit = (RuleI(Combat, HitCapPre10));
|
||||
@@ -1086,4 +1086,4 @@ float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, EQEmu::skills::Skil
|
||||
}
|
||||
|
||||
return(chancetohit);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2133,7 +2133,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
temp_npctype_data->healscale = atoi(row[87]);
|
||||
temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
|
||||
temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false: true;
|
||||
temp_npctype_data->attack_delay = atoi(row[90]);
|
||||
temp_npctype_data->attack_delay = atoi(row[90]) * 100; // TODO: fix DB
|
||||
temp_npctype_data->light = (atoi(row[91]) & 0x0F);
|
||||
|
||||
temp_npctype_data->armtexture = atoi(row[92]);
|
||||
|
||||
+1
-1
@@ -110,7 +110,7 @@ struct NPCType
|
||||
uint8 spawn_limit; //only this many may be in zone at a time (0=no limit)
|
||||
uint8 mount_color; //only used by horse class
|
||||
float attack_speed; //%+- on attack delay of the mob.
|
||||
uint8 attack_delay; //delay between attacks in 10ths of a second
|
||||
int attack_delay; //delay between attacks in ms
|
||||
int accuracy_rating; // flat bonus before mods
|
||||
int avoidance_rating; // flat bonus before mods
|
||||
bool findable; //can be found with find command
|
||||
|
||||
Reference in New Issue
Block a user