mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
Merge branch 'master' of github.com:EQEmu/Server
This commit is contained in:
+57
-69
@@ -1054,7 +1054,8 @@ void Mob::AI_Process() {
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
}
|
||||
} else {
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
if (!ImprovedTaunt())
|
||||
SetTarget(hate_list.GetTop(this));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1141,30 +1142,26 @@ void Mob::AI_Process() {
|
||||
Attack(target, 13);
|
||||
}
|
||||
|
||||
if (target)
|
||||
{
|
||||
if (target) {
|
||||
//we use this random value in three comparisons with different
|
||||
//thresholds, and if its truely random, then this should work
|
||||
//out reasonably and will save us compute resources.
|
||||
int32 RandRoll = MakeRandomInt(0, 99);
|
||||
if (CanThisClassDoubleAttack()
|
||||
//check double attack, this is NOT the same rules that clients use...
|
||||
&& RandRoll < (GetLevel() + NPCDualAttackModifier))
|
||||
{
|
||||
if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE)
|
||||
|| GetSpecialAbility(SPECATK_QUAD))
|
||||
//check double attack, this is NOT the same rules that clients use...
|
||||
&& RandRoll < (GetLevel() + NPCDualAttackModifier)) {
|
||||
Attack(target, 13);
|
||||
// lets see if we can do a triple attack with the main hand
|
||||
//pets are excluded from triple and quads...
|
||||
if (GetSpecialAbility(SPECATK_TRIPLE)
|
||||
&& !IsPet() && RandRoll < (GetLevel()+NPCTripleAttackModifier))
|
||||
{
|
||||
if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD))
|
||||
&& !IsPet() && RandRoll < (GetLevel() + NPCTripleAttackModifier)) {
|
||||
Attack(target, 13);
|
||||
// now lets check the quad attack
|
||||
if (GetSpecialAbility(SPECATK_QUAD)
|
||||
&& RandRoll < (GetLevel() + NPCQuadAttackModifier))
|
||||
{
|
||||
&& RandRoll < (GetLevel() + NPCQuadAttackModifier)) {
|
||||
Attack(target, 13);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1173,48 +1170,41 @@ void Mob::AI_Process() {
|
||||
int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0);
|
||||
flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance);
|
||||
|
||||
ExtraAttackOptions opts;
|
||||
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
|
||||
if(cur > 0) {
|
||||
opts.damage_percent = cur / 100.0f;
|
||||
}
|
||||
if (MakeRandomInt(0, 99) < flurry_chance) {
|
||||
ExtraAttackOptions opts;
|
||||
int cur = GetSpecialAbilityParam(SPECATK_FLURRY, 2);
|
||||
if (cur > 0)
|
||||
opts.damage_percent = cur / 100.0f;
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
|
||||
if(cur > 0) {
|
||||
opts.damage_flat = cur;
|
||||
}
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 3);
|
||||
if (cur > 0)
|
||||
opts.damage_flat = cur;
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
|
||||
if(cur > 0) {
|
||||
opts.armor_pen_percent = cur / 100.0f;
|
||||
}
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 4);
|
||||
if (cur > 0)
|
||||
opts.armor_pen_percent = cur / 100.0f;
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
|
||||
if(cur > 0) {
|
||||
opts.armor_pen_flat = cur;
|
||||
}
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 5);
|
||||
if (cur > 0)
|
||||
opts.armor_pen_flat = cur;
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
|
||||
if(cur > 0) {
|
||||
opts.crit_percent = cur / 100.0f;
|
||||
}
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 6);
|
||||
if (cur > 0)
|
||||
opts.crit_percent = cur / 100.0f;
|
||||
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7);
|
||||
if(cur > 0) {
|
||||
opts.crit_flat = cur;
|
||||
}
|
||||
cur = GetSpecialAbilityParam(SPECATK_FLURRY, 7);
|
||||
if (cur > 0)
|
||||
opts.crit_flat = cur;
|
||||
|
||||
if (MakeRandomInt(0, 99) < flurry_chance)
|
||||
Flurry(&opts);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPet()) {
|
||||
|
||||
Mob *owner = GetOwner();
|
||||
|
||||
if (owner){
|
||||
int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
|
||||
|
||||
if (owner) {
|
||||
int16 flurry_chance = owner->aabonuses.PetFlurry +
|
||||
owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry;
|
||||
if (flurry_chance && (MakeRandomInt(0, 99) < flurry_chance))
|
||||
Flurry(nullptr);
|
||||
}
|
||||
@@ -1294,7 +1284,7 @@ void Mob::AI_Process() {
|
||||
if(cur > 0) {
|
||||
opts.crit_flat = cur;
|
||||
}
|
||||
|
||||
|
||||
AreaRampage(&opts);
|
||||
}
|
||||
}
|
||||
@@ -1997,59 +1987,57 @@ bool Mob::Flurry(ExtraAttackOptions *opts)
|
||||
|
||||
bool Mob::AddRampage(Mob *mob)
|
||||
{
|
||||
if(!mob)
|
||||
if (!mob)
|
||||
return false;
|
||||
|
||||
if (!GetSpecialAbility(SPECATK_RAMPAGE))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < RampageArray.size(); i++)
|
||||
{
|
||||
// if name is already on the list dont add it again
|
||||
if (strcasecmp(mob->GetName(), RampageArray[i].c_str()) == 0)
|
||||
for (int i = 0; i < RampageArray.size(); i++) {
|
||||
// if Entity ID is already on the list don't add it again
|
||||
if (mob->GetID() == RampageArray[i])
|
||||
return false;
|
||||
}
|
||||
std::string r_name = mob->GetName();
|
||||
RampageArray.push_back(r_name);
|
||||
RampageArray.push_back(mob->GetID());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mob::ClearRampage(){
|
||||
void Mob::ClearRampage()
|
||||
{
|
||||
RampageArray.clear();
|
||||
}
|
||||
|
||||
bool Mob::Rampage(ExtraAttackOptions *opts)
|
||||
{
|
||||
int index_hit = 0;
|
||||
if (!IsPet()) {
|
||||
if (!IsPet())
|
||||
entity_list.MessageClose_StringID(this, true, 200, MT_NPCRampage, NPC_RAMPAGE, GetCleanName());
|
||||
} else {
|
||||
else
|
||||
entity_list.MessageClose_StringID(this, true, 200, MT_PetFlurry, NPC_RAMPAGE, GetCleanName());
|
||||
}
|
||||
|
||||
int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
|
||||
rampage_targets = rampage_targets > 0 ? rampage_targets : RuleI(Combat, MaxRampageTargets);
|
||||
for (int i = 0; i < RampageArray.size(); i++)
|
||||
{
|
||||
if(index_hit >= rampage_targets)
|
||||
if (rampage_targets == 0) // if set to 0 or not set in the DB
|
||||
rampage_targets = RuleI(Combat, DefaultRampageTargets);
|
||||
if (rampage_targets > RuleI(Combat, MaxRampageTargets))
|
||||
rampage_targets = RuleI(Combat, MaxRampageTargets);
|
||||
for (int i = 0; i < RampageArray.size(); i++) {
|
||||
if (index_hit >= rampage_targets)
|
||||
break;
|
||||
// range is important
|
||||
Mob *m_target = entity_list.GetMob(RampageArray[i].c_str());
|
||||
if(m_target)
|
||||
{
|
||||
if(m_target == GetTarget())
|
||||
Mob *m_target = entity_list.GetMob(RampageArray[i]);
|
||||
if (m_target) {
|
||||
if (m_target == GetTarget())
|
||||
continue;
|
||||
if (CombatRange(m_target))
|
||||
{
|
||||
if (CombatRange(m_target)) {
|
||||
Attack(m_target, 13, false, false, false, opts);
|
||||
index_hit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(index_hit < rampage_targets) {
|
||||
|
||||
if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets)
|
||||
Attack(GetTarget(), 13, false, false, false, opts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ void QuestParserCollection::RegisterQuestInterface(QuestInterface *qi, std::stri
|
||||
_load_precedence.push_back(qi);
|
||||
}
|
||||
|
||||
void QuestParserCollection::ClearInterfaces() {
|
||||
_interfaces.clear();
|
||||
_extensions.clear();
|
||||
_load_precedence.clear();
|
||||
}
|
||||
|
||||
void QuestParserCollection::AddVar(std::string name, std::string val) {
|
||||
std::list<QuestInterface*>::iterator iter = _load_precedence.begin();
|
||||
while(iter != _load_precedence.end()) {
|
||||
|
||||
@@ -39,7 +39,8 @@ public:
|
||||
~QuestParserCollection();
|
||||
|
||||
void RegisterQuestInterface(QuestInterface *qi, std::string ext);
|
||||
|
||||
void UnRegisterQuestInterface(QuestInterface *qi, std::string ext);
|
||||
void ClearInterfaces();
|
||||
void AddVar(std::string name, std::string val);
|
||||
void Init();
|
||||
void ReloadQuests(bool reset_timers = true);
|
||||
|
||||
+3
-6
@@ -1257,7 +1257,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
||||
break;
|
||||
}
|
||||
case SE_ReduceHate:
|
||||
case SE_Calm: {
|
||||
case SE_InstantHate: {
|
||||
nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
|
||||
break;
|
||||
}
|
||||
@@ -1282,9 +1282,6 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
|
||||
if (IsClient())
|
||||
HateMod += CastToClient()->GetFocusEffect(focusSpellHateMod, spell_id);
|
||||
|
||||
//Live AA - Spell casting subtlety
|
||||
HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;
|
||||
|
||||
AggroAmount = (AggroAmount * HateMod) / 100;
|
||||
|
||||
//made up number probably scales a bit differently on live but it seems like it will be close enough
|
||||
@@ -1405,7 +1402,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
|
||||
return true;
|
||||
|
||||
//1: The mob has a default 25% chance of being allowed a resistance check against the charm.
|
||||
if (MakeRandomInt(0, 100) > RuleI(Spells, CharmBreakCheckChance))
|
||||
if (MakeRandomInt(0, 99) > RuleI(Spells, CharmBreakCheckChance))
|
||||
return true;
|
||||
|
||||
//2: The mob makes a resistance check against the charm
|
||||
@@ -1419,7 +1416,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
|
||||
//3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred.
|
||||
uint16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance;
|
||||
|
||||
if (MakeRandomInt(0, 100) < TotalDominationBonus)
|
||||
if (MakeRandomInt(0, 99) < TotalDominationBonus)
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
+217
-153
@@ -199,11 +199,6 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
|
||||
if(IsClient() && other->IsClient())
|
||||
pvpmode = true;
|
||||
|
||||
CheckNumHitsRemaining(1);
|
||||
|
||||
if (attacker)
|
||||
attacker->CheckNumHitsRemaining(2);
|
||||
|
||||
if (chance_mod >= 10000)
|
||||
return true;
|
||||
|
||||
@@ -541,17 +536,16 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
||||
|
||||
void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts)
|
||||
{
|
||||
if(damage <= 0)
|
||||
if (damage <= 0)
|
||||
return;
|
||||
|
||||
Mob* defender = this;
|
||||
float aa_mit = 0;
|
||||
float aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability +
|
||||
spellbonuses.CombatStability) / 100.0f;
|
||||
|
||||
aa_mit = (aabonuses.CombatStability + itembonuses.CombatStability + spellbonuses.CombatStability)/100.0f;
|
||||
|
||||
if(RuleB(Combat, UseIntervalAC))
|
||||
{
|
||||
float softcap = 0.0;
|
||||
if (RuleB(Combat, UseIntervalAC)) {
|
||||
float softcap = (GetSkill(SkillDefense) + GetLevel()) *
|
||||
RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit);
|
||||
float mitigation_rating = 0.0;
|
||||
float attack_rating = 0.0;
|
||||
int shield_ac = 0;
|
||||
@@ -561,150 +555,101 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac
|
||||
float monkweight = RuleI(Combat, MonkACBonusWeight);
|
||||
monkweight = mod_monk_weight(monkweight, attacker);
|
||||
|
||||
if(IsClient())
|
||||
{
|
||||
if (IsClient()) {
|
||||
armor = CastToClient()->GetRawACNoShield(shield_ac);
|
||||
weight = (CastToClient()->CalcCurrentWeight() / 10.0);
|
||||
}
|
||||
else if(IsNPC())
|
||||
{
|
||||
} else if (IsNPC()) {
|
||||
armor = CastToNPC()->GetRawAC();
|
||||
|
||||
if(!IsPet())
|
||||
{
|
||||
if (!IsPet())
|
||||
armor = (armor / RuleR(Combat, NPCACFactor));
|
||||
}
|
||||
|
||||
armor += spellbonuses.AC + itembonuses.AC + 1;
|
||||
}
|
||||
|
||||
if(opts) {
|
||||
if (opts) {
|
||||
armor *= (1.0f - opts->armor_pen_percent);
|
||||
armor -= opts->armor_pen_flat;
|
||||
}
|
||||
|
||||
if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER)
|
||||
{
|
||||
softcap = RuleI(Combat, ClothACSoftcap);
|
||||
}
|
||||
else if(GetClass() == MONK && weight <= monkweight)
|
||||
{
|
||||
softcap = RuleI(Combat, MonkACSoftcap);
|
||||
}
|
||||
else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK)
|
||||
{
|
||||
softcap = RuleI(Combat, LeatherACSoftcap);
|
||||
}
|
||||
else if(GetClass() == SHAMAN || GetClass() == ROGUE || GetClass() == BERSERKER || GetClass() == RANGER)
|
||||
{
|
||||
softcap = RuleI(Combat, ChainACSoftcap);
|
||||
}
|
||||
else
|
||||
{
|
||||
softcap = RuleI(Combat, PlateACSoftcap);
|
||||
if (RuleB(Combat, OldACSoftcapRules)) {
|
||||
if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
|
||||
GetClass() == NECROMANCER || GetClass() == ENCHANTER)
|
||||
softcap = RuleI(Combat, ClothACSoftcap);
|
||||
else if (GetClass() == MONK && weight <= monkweight)
|
||||
softcap = RuleI(Combat, MonkACSoftcap);
|
||||
else if(GetClass() == DRUID || GetClass() == BEASTLORD || GetClass() == MONK)
|
||||
softcap = RuleI(Combat, LeatherACSoftcap);
|
||||
else if(GetClass() == SHAMAN || GetClass() == ROGUE ||
|
||||
GetClass() == BERSERKER || GetClass() == RANGER)
|
||||
softcap = RuleI(Combat, ChainACSoftcap);
|
||||
else
|
||||
softcap = RuleI(Combat, PlateACSoftcap);
|
||||
}
|
||||
|
||||
softcap += shield_ac;
|
||||
armor += shield_ac;
|
||||
softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor)));
|
||||
if(armor > softcap)
|
||||
{
|
||||
if (RuleB(Combat, OldACSoftcapRules))
|
||||
softcap += (softcap * (aa_mit * RuleR(Combat, AAMitigationACFactor)));
|
||||
if (armor > softcap) {
|
||||
int softcap_armor = armor - softcap;
|
||||
if(GetClass() == WARRIOR)
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn);
|
||||
}
|
||||
else if(GetClass() == SHADOWKNIGHT || GetClass() == PALADIN || (GetClass() == MONK && weight <= monkweight))
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn);
|
||||
}
|
||||
else if(GetClass() == CLERIC || GetClass() == BARD || GetClass() == BERSERKER || GetClass() == ROGUE || GetClass() == SHAMAN || GetClass() == MONK)
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn);
|
||||
}
|
||||
else if(GetClass() == RANGER || GetClass() == BEASTLORD)
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn);
|
||||
}
|
||||
else if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER || GetClass() == DRUID)
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn);
|
||||
}
|
||||
else
|
||||
{
|
||||
softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn);
|
||||
if (RuleB(Combat, OldACSoftcapRules)) {
|
||||
if (GetClass() == WARRIOR)
|
||||
softcap_armor = softcap_armor * RuleR(Combat, WarriorACSoftcapReturn);
|
||||
else if (GetClass() == SHADOWKNIGHT || GetClass() == PALADIN ||
|
||||
(GetClass() == MONK && weight <= monkweight))
|
||||
softcap_armor = softcap_armor * RuleR(Combat, KnightACSoftcapReturn);
|
||||
else if (GetClass() == CLERIC || GetClass() == BARD ||
|
||||
GetClass() == BERSERKER || GetClass() == ROGUE ||
|
||||
GetClass() == SHAMAN || GetClass() == MONK)
|
||||
softcap_armor = softcap_armor * RuleR(Combat, LowPlateChainACSoftcapReturn);
|
||||
else if (GetClass() == RANGER || GetClass() == BEASTLORD)
|
||||
softcap_armor = softcap_armor * RuleR(Combat, LowChainLeatherACSoftcapReturn);
|
||||
else if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
|
||||
GetClass() == NECROMANCER || GetClass() == ENCHANTER ||
|
||||
GetClass() == DRUID)
|
||||
softcap_armor = softcap_armor * RuleR(Combat, CasterACSoftcapReturn);
|
||||
else
|
||||
softcap_armor = softcap_armor * RuleR(Combat, MiscACSoftcapReturn);
|
||||
} else {
|
||||
if (GetClass() == WARRIOR)
|
||||
softcap_armor *= RuleR(Combat, WarACSoftcapReturn);
|
||||
else if (GetClass() == PALADIN || GetClass() == SHADOWKNIGHT)
|
||||
softcap_armor *= RuleR(Combat, PalShdACSoftcapReturn);
|
||||
else if (GetClass() == CLERIC || GetClass() == RANGER ||
|
||||
GetClass() == MONK || GetClass() == BARD)
|
||||
softcap_armor *= RuleR(Combat, ClrRngMnkBrdACSoftcapReturn);
|
||||
else if (GetClass() == DRUID || GetClass() == NECROMANCER ||
|
||||
GetClass() == WIZARD || GetClass() == ENCHANTER ||
|
||||
GetClass() == MAGICIAN)
|
||||
softcap_armor *= RuleR(Combat, DruNecWizEncMagACSoftcapReturn);
|
||||
else if (GetClass() == ROGUE || GetClass() == SHAMAN ||
|
||||
GetClass() == BEASTLORD || GetClass() == BERSERKER)
|
||||
softcap_armor *= RuleR(Combat, RogShmBstBerACSoftcapReturn);
|
||||
else
|
||||
softcap_armor *= RuleR(Combat, MiscACSoftcapReturn);
|
||||
}
|
||||
armor = softcap + softcap_armor;
|
||||
}
|
||||
|
||||
mitigation_rating = 0.0;
|
||||
if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER)
|
||||
{
|
||||
if (GetClass() == WIZARD || GetClass() == MAGICIAN ||
|
||||
GetClass() == NECROMANCER || GetClass() == ENCHANTER)
|
||||
mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1;
|
||||
}
|
||||
mitigation_rating *= 0.847;
|
||||
|
||||
mitigation_rating = mod_mitigation_rating(mitigation_rating, attacker);
|
||||
|
||||
if(attacker->IsClient())
|
||||
{
|
||||
if (attacker->IsClient())
|
||||
attack_rating = (attacker->CastToClient()->CalcATK() + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345));
|
||||
}
|
||||
else
|
||||
{
|
||||
attack_rating = (attacker->GetATK() + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9));
|
||||
}
|
||||
|
||||
attack_rating = attacker->mod_attack_rating(attack_rating, this);
|
||||
|
||||
float d = 10.0;
|
||||
float mit_roll = MakeRandomFloat(0, mitigation_rating);
|
||||
float atk_roll = MakeRandomFloat(0, attack_rating);
|
||||
|
||||
if(atk_roll > mit_roll)
|
||||
{
|
||||
float a_diff = (atk_roll - mit_roll);
|
||||
float thac0 = attack_rating * RuleR(Combat, ACthac0Factor);
|
||||
float thac0cap = ((attacker->GetLevel() * 9) + 20);
|
||||
if(thac0 > thac0cap)
|
||||
{
|
||||
thac0 = thac0cap;
|
||||
}
|
||||
d -= 10.0 * (a_diff / thac0);
|
||||
}
|
||||
else if(mit_roll > atk_roll)
|
||||
{
|
||||
float m_diff = (mit_roll - atk_roll);
|
||||
float thac20 = mitigation_rating * RuleR(Combat, ACthac20Factor);
|
||||
float thac20cap = ((defender->GetLevel() * 9) + 20);
|
||||
if(thac20 > thac20cap)
|
||||
{
|
||||
thac20 = thac20cap;
|
||||
|
||||
|
||||
|
||||
}
|
||||
d += 10 * (m_diff / thac20);
|
||||
}
|
||||
|
||||
if(d < 0.0)
|
||||
{
|
||||
d = 0.0;
|
||||
}
|
||||
|
||||
if(d > 20)
|
||||
{
|
||||
d = 20.0;
|
||||
}
|
||||
|
||||
float interval = (damage - minhit) / 20.0;
|
||||
damage = damage - ((int)d * interval);
|
||||
}
|
||||
else{
|
||||
damage = GetMeleeMitDmg(attacker, damage, minhit, mitigation_rating, attack_rating);
|
||||
} else {
|
||||
////////////////////////////////////////////////////////
|
||||
// Scorpious2k: Include AC in the calculation
|
||||
// use serverop variables to set values
|
||||
@@ -755,17 +700,100 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac
|
||||
|
||||
if(damage != 0 && damage < minhit)
|
||||
damage = minhit;
|
||||
//reduce the damage from shielding item and aa based on the min dmg
|
||||
//spells offer pure mitigation
|
||||
damage -= (minhit * defender->itembonuses.MeleeMitigation / 100);
|
||||
damage -= (damage * defender->spellbonuses.MeleeMitigation / 100);
|
||||
}
|
||||
|
||||
//reduce the damage from shielding item and aa based on the min dmg
|
||||
//spells offer pure mitigation
|
||||
damage -= (minhit * defender->itembonuses.MeleeMitigation / 100);
|
||||
damage -= (damage * defender->spellbonuses.MeleeMitigation / 100);
|
||||
|
||||
if(damage < 0)
|
||||
if (damage < 0)
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
// This is called when the Mob is the one being hit
|
||||
int32 Mob::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit,
|
||||
float mit_rating, float atk_rating)
|
||||
{
|
||||
float d = 10.0;
|
||||
float mit_roll = MakeRandomFloat(0, mit_rating);
|
||||
float atk_roll = MakeRandomFloat(0, atk_rating);
|
||||
|
||||
if (atk_roll > mit_roll) {
|
||||
float a_diff = atk_roll - mit_roll;
|
||||
float thac0 = atk_rating * RuleR(Combat, ACthac0Factor);
|
||||
float thac0cap = attacker->GetLevel() * 9 + 20;
|
||||
if (thac0 > thac0cap)
|
||||
thac0 = thac0cap;
|
||||
|
||||
d -= 10.0 * (a_diff / thac0);
|
||||
} else if (mit_roll > atk_roll) {
|
||||
float m_diff = mit_roll - atk_roll;
|
||||
float thac20 = mit_rating * RuleR(Combat, ACthac20Factor);
|
||||
float thac20cap = GetLevel() * 9 + 20;
|
||||
if (thac20 > thac20cap)
|
||||
thac20 = thac20cap;
|
||||
|
||||
d += 10.0 * (m_diff / thac20);
|
||||
}
|
||||
|
||||
if (d < 0.0)
|
||||
d = 0.0;
|
||||
else if (d > 20.0)
|
||||
d = 20.0;
|
||||
|
||||
float interval = (damage - minhit) / 20.0;
|
||||
damage -= ((int)d * interval);
|
||||
|
||||
damage -= (minhit * itembonuses.MeleeMitigation / 100);
|
||||
damage -= (damage * spellbonuses.MeleeMitigation / 100);
|
||||
return damage;
|
||||
}
|
||||
|
||||
// This is called when the Client is the one being hit
|
||||
int32 Client::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit,
|
||||
float mit_rating, float atk_rating)
|
||||
{
|
||||
if (!attacker->IsNPC() || RuleB(Combat, UseOldDamageIntervalRules))
|
||||
return Mob::GetMeleeMitDmg(attacker, damage, minhit, mit_rating, atk_rating);
|
||||
int d = 10;
|
||||
// floats for the rounding issues
|
||||
float dmg_interval = (damage - minhit) / 19.0;
|
||||
float dmg_bonus = minhit - dmg_interval;
|
||||
float spellMeleeMit = spellbonuses.MeleeMitigation / 100.0;
|
||||
if (GetClass() == WARRIOR)
|
||||
spellMeleeMit += 0.05;
|
||||
dmg_bonus -= dmg_bonus * (itembonuses.MeleeMitigation / 100.0);
|
||||
dmg_interval -= dmg_interval * spellMeleeMit;
|
||||
|
||||
float mit_roll = MakeRandomFloat(0, mit_rating);
|
||||
float atk_roll = MakeRandomFloat(0, atk_rating);
|
||||
|
||||
if (atk_roll > mit_roll) {
|
||||
float a_diff = atk_roll - mit_roll;
|
||||
float thac0 = atk_rating * RuleR(Combat, ACthac0Factor);
|
||||
float thac0cap = attacker->GetLevel() * 9 + 20;
|
||||
if (thac0 > thac0cap)
|
||||
thac0 = thac0cap;
|
||||
|
||||
d += 10 * (a_diff / thac0);
|
||||
} else if (mit_roll > atk_roll) {
|
||||
float m_diff = mit_roll - atk_roll;
|
||||
float thac20 = mit_rating * RuleR(Combat, ACthac20Factor);
|
||||
float thac20cap = GetLevel() * 9 + 20;
|
||||
if (thac20 > thac20cap)
|
||||
thac20 = thac20cap;
|
||||
|
||||
d -= 10 * (m_diff / thac20);
|
||||
}
|
||||
|
||||
if (d < 1)
|
||||
d = 1;
|
||||
else if (d > 20)
|
||||
d = 20;
|
||||
|
||||
return static_cast<int32>((dmg_bonus + dmg_interval * d));
|
||||
}
|
||||
|
||||
//Returns the weapon damage against the input mob
|
||||
//if we cannot hit the mob with the current weapon we will get a value less than or equal to zero
|
||||
//Else we know we can hit.
|
||||
@@ -1251,7 +1279,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
hate *= opts->hate_percent;
|
||||
hate += opts->hate_flat;
|
||||
}
|
||||
|
||||
|
||||
//check to see if we hit..
|
||||
if(!other->CheckHitChance(this, skillinuse, Hand)) {
|
||||
mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0.");
|
||||
@@ -1308,6 +1336,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
|
||||
// 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.
|
||||
|
||||
if (!bRiposte) // Ripostes never generate any aggro.
|
||||
other->AddToHateList(this, hate);
|
||||
|
||||
@@ -1318,19 +1347,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
|
||||
if (IsDead()) return false;
|
||||
|
||||
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap))
|
||||
{
|
||||
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap;
|
||||
if(lifetap_amt > 100)
|
||||
lifetap_amt = 100;
|
||||
MeleeLifeTap(damage);
|
||||
|
||||
lifetap_amt = damage * lifetap_amt / 100;
|
||||
|
||||
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
|
||||
//heal self for damage done..
|
||||
HealDamage(lifetap_amt);
|
||||
|
||||
}
|
||||
if (damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
//break invis when you attack
|
||||
if(invisible) {
|
||||
@@ -1882,6 +1902,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
mlog(COMBAT__HITS, "Generating hate %d towards %s", hate, GetName());
|
||||
// now add done damage to the hate list
|
||||
other->AddToHateList(this, hate);
|
||||
|
||||
} else {
|
||||
if(opts) {
|
||||
damage *= opts->damage_percent;
|
||||
@@ -1938,6 +1959,11 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
if (HasDied()) //killed by damage shield ect
|
||||
return false;
|
||||
|
||||
MeleeLifeTap(damage);
|
||||
|
||||
if (damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
//break invis when you attack
|
||||
if(invisible) {
|
||||
mlog(COMBAT__ATTACKS, "Removing invisibility due to melee attack.");
|
||||
@@ -2411,7 +2437,9 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
||||
}
|
||||
|
||||
void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
|
||||
|
||||
assert(other != nullptr);
|
||||
|
||||
if (other == this)
|
||||
return;
|
||||
|
||||
@@ -2492,6 +2520,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
|
||||
if(damage > GetHP())
|
||||
damage = GetHP();
|
||||
|
||||
if (spellbonuses.ImprovedTaunt[1] && (GetLevel() < spellbonuses.ImprovedTaunt[0])
|
||||
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
|
||||
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
|
||||
|
||||
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
|
||||
|
||||
if(other->IsClient())
|
||||
@@ -3241,8 +3273,28 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
|
||||
}
|
||||
|
||||
// If this is a DoT, use DoT Shielding...
|
||||
if(iBuffTic)
|
||||
damage -= (damage * itembonuses.DoTShielding / 100);
|
||||
if(iBuffTic) {
|
||||
damage -= (damage * itembonuses.DoTShielding / 100);
|
||||
|
||||
if (spellbonuses.MitigateDotRune[0]){
|
||||
slot = spellbonuses.MitigateDotRune[1];
|
||||
if(slot >= 0)
|
||||
{
|
||||
int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100;
|
||||
if(damage_to_reduce > buffs[slot].dot_rune)
|
||||
{
|
||||
damage -= damage_to_reduce;
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce);
|
||||
damage -= damage_to_reduce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This must be a DD then so lets apply Spell Shielding and runes.
|
||||
else
|
||||
@@ -3310,7 +3362,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
else{
|
||||
buffs[slot].melee_rune = (buffs[slot].magic_rune - damage);
|
||||
buffs[slot].magic_rune = (buffs[slot].magic_rune - damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3434,7 +3486,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
mlog(COMBAT__DAMAGE, "Avoiding %d damage due to invulnerability.", damage);
|
||||
damage = -5;
|
||||
}
|
||||
|
||||
|
||||
if( spell_id != SPELL_UNKNOWN || attacker == nullptr )
|
||||
avoidable = false;
|
||||
|
||||
@@ -3444,6 +3496,13 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
DamageShield(attacker);
|
||||
}
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN && skill_used) {
|
||||
CheckNumHitsRemaining(1); //Incoming Hit Attempts
|
||||
|
||||
if (attacker)
|
||||
attacker->CheckNumHitsRemaining(2); //Outgoing Hit Attempts
|
||||
}
|
||||
|
||||
if(attacker){
|
||||
if(attacker->IsClient()){
|
||||
if(!RuleB(Combat, EXPFromDmgShield)) {
|
||||
@@ -3514,16 +3573,20 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
|
||||
}
|
||||
|
||||
ReduceAllDamage(damage);
|
||||
if (skill_used)
|
||||
CheckNumHitsRemaining(6); //Incomming Hit Success on Defender
|
||||
|
||||
if(IsClient() && CastToClient()->sneaking){
|
||||
CastToClient()->sneaking = false;
|
||||
SendAppearancePacket(AT_Sneak, 0);
|
||||
}
|
||||
if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){
|
||||
attacker->CastToClient()->sneaking = false;
|
||||
attacker->SendAppearancePacket(AT_Sneak, 0);
|
||||
}
|
||||
ReduceAllDamage(damage);
|
||||
|
||||
if(IsClient() && CastToClient()->sneaking){
|
||||
CastToClient()->sneaking = false;
|
||||
SendAppearancePacket(AT_Sneak, 0);
|
||||
}
|
||||
if(attacker && attacker->IsClient() && attacker->CastToClient()->sneaking){
|
||||
attacker->CastToClient()->sneaking = false;
|
||||
attacker->SendAppearancePacket(AT_Sneak, 0);
|
||||
}
|
||||
|
||||
//final damage has been determined.
|
||||
|
||||
SetHP(GetHP() - damage);
|
||||
@@ -3770,6 +3833,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
|
||||
}
|
||||
}
|
||||
} //end packet sending
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+63
-13
@@ -1216,6 +1216,18 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_HealRate:
|
||||
newbon->HealRate += base1;
|
||||
break;
|
||||
|
||||
case SE_MeleeLifetap:
|
||||
{
|
||||
|
||||
if((base1 < 0) && (newbon->MeleeLifetap > base1))
|
||||
newbon->MeleeLifetap = base1;
|
||||
|
||||
else if(newbon->MeleeLifetap < base1)
|
||||
newbon->MeleeLifetap = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1230,8 +1242,12 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN)
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, buffs[i].ticsremaining,i);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
}
|
||||
}
|
||||
|
||||
//Removes the spell bonuses that are effected by a 'negate' debuff.
|
||||
@@ -1591,12 +1607,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->reflect_chance += effect_value;
|
||||
break;
|
||||
|
||||
case SE_SingingSkill:
|
||||
{
|
||||
if(effect_value > newbon->singingMod)
|
||||
newbon->singingMod = effect_value;
|
||||
case SE_Amplification:
|
||||
newbon->Amplification += effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_ChangeAggro:
|
||||
newbon->hatemod += effect_value;
|
||||
@@ -1750,7 +1763,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
else if((effect_value < 0) && (newbon->MeleeLifetap > effect_value))
|
||||
newbon->MeleeLifetap = spells[spell_id].base[i];
|
||||
|
||||
if(newbon->MeleeLifetap < spells[spell_id].base[i])
|
||||
else if(newbon->MeleeLifetap < spells[spell_id].base[i])
|
||||
newbon->MeleeLifetap = spells[spell_id].base[i];
|
||||
break;
|
||||
}
|
||||
@@ -2223,6 +2236,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_MitigateDotDamage:
|
||||
{
|
||||
if (newbon->MitigateDotRune[0] < effect_value){
|
||||
newbon->MitigateDotRune[0] = effect_value;
|
||||
newbon->MitigateDotRune[1] = buffslot;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_ManaAbsorbPercentDamage:
|
||||
{
|
||||
@@ -2480,7 +2502,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_TriggerOnValueAmount:
|
||||
case SE_TriggerOnReqTarget:
|
||||
case SE_TriggerOnReqCaster:
|
||||
newbon->TriggerOnValueAmount = true;
|
||||
break;
|
||||
|
||||
@@ -2488,6 +2511,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->DivineAura = true;
|
||||
break;
|
||||
|
||||
case SE_ImprovedTaunt:
|
||||
if (newbon->ImprovedTaunt[0] < effect_value) {
|
||||
newbon->ImprovedTaunt[0] = effect_value;
|
||||
newbon->ImprovedTaunt[1] = spells[spell_id].base2[i];
|
||||
newbon->ImprovedTaunt[2] = buffslot;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SE_DistanceRemoval:
|
||||
newbon->DistanceRemoval = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3099,10 +3135,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.reflect_chance = effect_value;
|
||||
break;
|
||||
|
||||
case SE_SingingSkill:
|
||||
spellbonuses.singingMod = effect_value;
|
||||
itembonuses.singingMod = effect_value;
|
||||
aabonuses.singingMod = effect_value;
|
||||
case SE_Amplification:
|
||||
spellbonuses.Amplification = effect_value;
|
||||
itembonuses.Amplification = effect_value;
|
||||
aabonuses.Amplification = effect_value;
|
||||
break;
|
||||
|
||||
case SE_ChangeAggro:
|
||||
@@ -3533,6 +3569,11 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
spellbonuses.MitigateSpellRune[1] = -1;
|
||||
break;
|
||||
|
||||
case SE_MitigateDotDamage:
|
||||
spellbonuses.MitigateDotRune[0] = effect_value;
|
||||
spellbonuses.MitigateDotRune[1] = -1;
|
||||
break;
|
||||
|
||||
case SE_ManaAbsorbPercentDamage:
|
||||
spellbonuses.ManaAbsorbPercentDamage[0] = effect_value;
|
||||
spellbonuses.ManaAbsorbPercentDamage[1] = -1;
|
||||
@@ -3816,7 +3857,16 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.CriticalMend = effect_value;
|
||||
aabonuses.CriticalMend = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_DistanceRemoval:
|
||||
spellbonuses.DistanceRemoval = effect_value;
|
||||
break;
|
||||
|
||||
case SE_ImprovedTaunt:
|
||||
spellbonuses.ImprovedTaunt[0] = effect_value;
|
||||
spellbonuses.ImprovedTaunt[1] = effect_value;
|
||||
spellbonuses.ImprovedTaunt[2] = -1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-34
@@ -2476,7 +2476,7 @@ void Bot::SaveBuffs() {
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO botbuffs (BotId, SpellId, CasterLevel, DurationFormula, "
|
||||
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, "
|
||||
"DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);",
|
||||
"dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
|
||||
GetBotID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula,
|
||||
buffs[BuffCount].ticsremaining,
|
||||
CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
@@ -2484,8 +2484,12 @@ void Bot::SaveBuffs() {
|
||||
CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune,
|
||||
buffs[BuffCount].deathSaveSuccessChance,
|
||||
buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) {
|
||||
buffs[BuffCount].dot_rune,
|
||||
buffs[BuffCount].caston_x,
|
||||
IsPersistent,
|
||||
buffs[BuffCount].caston_y,
|
||||
buffs[BuffCount].caston_z,
|
||||
buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
safe_delete(Query);
|
||||
Query = 0;
|
||||
@@ -2515,7 +2519,7 @@ void Bot::LoadBuffs() {
|
||||
|
||||
bool BuffsLoaded = false;
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM botbuffs WHERE BotId = %u", GetBotID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
}
|
||||
else {
|
||||
@@ -2541,8 +2545,8 @@ void Bot::LoadBuffs() {
|
||||
buffs[BuffCount].numhits = atoi(DataRow[8]);
|
||||
buffs[BuffCount].melee_rune = atoi(DataRow[9]);
|
||||
buffs[BuffCount].magic_rune = atoi(DataRow[10]);
|
||||
buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]);
|
||||
buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]);
|
||||
buffs[BuffCount].dot_rune = atoi(DataRow[11]);
|
||||
buffs[BuffCount].caston_x = atoi(DataRow[12]);
|
||||
buffs[BuffCount].casterid = 0;
|
||||
|
||||
bool IsPersistent = false;
|
||||
@@ -2550,6 +2554,10 @@ void Bot::LoadBuffs() {
|
||||
if(atoi(DataRow[13]))
|
||||
IsPersistent = true;
|
||||
|
||||
buffs[BuffCount].caston_y = atoi(DataRow[14]);
|
||||
buffs[BuffCount].caston_z = atoi(DataRow[15]);
|
||||
buffs[BuffCount].ExtraDIChance = atoi(DataRow[16]);
|
||||
|
||||
buffs[BuffCount].persistant_buff = IsPersistent;
|
||||
|
||||
BuffCount++;
|
||||
@@ -3377,6 +3385,9 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
if (damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){
|
||||
SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff);
|
||||
other->Stun(100);
|
||||
@@ -6593,18 +6604,10 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
|
||||
|
||||
if (GetHP() < 0) return false;
|
||||
|
||||
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap))
|
||||
{
|
||||
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap;
|
||||
if(lifetap_amt > 100)
|
||||
lifetap_amt = 100;
|
||||
MeleeLifeTap(damage);
|
||||
|
||||
lifetap_amt = damage * lifetap_amt / 100;
|
||||
|
||||
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
|
||||
//heal self for damage done..
|
||||
HealDamage(lifetap_amt);
|
||||
}
|
||||
if (damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
//break invis when you attack
|
||||
if(invisible) {
|
||||
@@ -6823,13 +6826,6 @@ int16 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id)
|
||||
SpellSkill_Found = true;
|
||||
break;
|
||||
|
||||
case SE_LimitSpellSubclass:{
|
||||
int16 spell_skill = spell.skill * -1;
|
||||
if(base1 == spell_skill)
|
||||
LimitFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_LimitClass:
|
||||
//Do not use this limit more then once per spell. If multiple class, treat value like items would.
|
||||
if (!PassLimitClass(base1, GetClass()))
|
||||
@@ -7428,13 +7424,6 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
|
||||
SpellSkill_Found = true;
|
||||
break;
|
||||
|
||||
case SE_LimitSpellSubclass:{
|
||||
int16 spell_skill = spell.skill * -1;
|
||||
if(focus_spell.base[i] == spell_skill)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_LimitClass:
|
||||
//Do not use this limit more then once per spell. If multiple class, treat value like items would.
|
||||
if (!PassLimitClass(focus_spell.base[i], GetClass()))
|
||||
@@ -8083,6 +8072,9 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
if(!GetTarget())return;
|
||||
if (HasDied()) return;
|
||||
|
||||
if (max_damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
|
||||
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
|
||||
int kb_chance = 25;
|
||||
@@ -12975,7 +12967,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
pacer->Say("Trying to pacify %s \n", target->GetCleanName());
|
||||
|
||||
if(pacer->Bot_Command_CalmTarget(target)) {
|
||||
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
|
||||
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate))
|
||||
//if(pacer->IsPacified(target))
|
||||
c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
|
||||
return;
|
||||
@@ -12991,7 +12983,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
|
||||
pacer->Say("Trying to pacify %s \n", target->GetCleanName());
|
||||
|
||||
if(pacer->Bot_Command_CalmTarget(target)) {
|
||||
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
|
||||
if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate))
|
||||
//if(pacer->IsPacified(target))
|
||||
c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
|
||||
return;
|
||||
@@ -16315,7 +16307,7 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) {
|
||||
std::string WindowText;
|
||||
int LastCon = -1;
|
||||
int CurrentCon = 0;
|
||||
Mob* curMob = NULL;
|
||||
Mob* curMob = nullptr;
|
||||
|
||||
uint32 array_counter = 0;
|
||||
|
||||
|
||||
+12
-11
@@ -6045,11 +6045,10 @@ void Client::NPCSpawn(NPC *target_npc, const char *identifier, uint32 extra)
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::IsDraggingCorpse(const char *CorpseName)
|
||||
bool Client::IsDraggingCorpse(uint16 CorpseID)
|
||||
{
|
||||
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
|
||||
{
|
||||
if(!strcasecmp((*Iterator).c_str(), CorpseName))
|
||||
for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) {
|
||||
if (It->second == CorpseID)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6058,20 +6057,22 @@ bool Client::IsDraggingCorpse(const char *CorpseName)
|
||||
|
||||
void Client::DragCorpses()
|
||||
{
|
||||
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
|
||||
{
|
||||
Mob* corpse = entity_list.GetMob((*Iterator).c_str());
|
||||
for (auto It = DraggedCorpses.begin(); It != DraggedCorpses.end(); ++It) {
|
||||
Mob *corpse = entity_list.GetMob(It->second);
|
||||
|
||||
if(corpse && corpse->IsPlayerCorpse() && (DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance)))
|
||||
if (corpse && corpse->IsPlayerCorpse() &&
|
||||
(DistNoRootNoZ(*corpse) <= RuleR(Character, DragCorpseDistance)))
|
||||
continue;
|
||||
|
||||
if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted() || !corpse->CastToCorpse()->Summon(this, false, false))
|
||||
{
|
||||
if (!corpse || !corpse->IsPlayerCorpse() ||
|
||||
corpse->CastToCorpse()->IsBeingLooted() ||
|
||||
!corpse->CastToCorpse()->Summon(this, false, false)) {
|
||||
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
|
||||
Iterator = DraggedCorpses.erase(Iterator);
|
||||
It = DraggedCorpses.erase(It);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_override, int pet_count, int pet_duration)
|
||||
{
|
||||
if(!target || !IsValidSpell(spell_id) || this->GetID() == target->GetID())
|
||||
|
||||
+3
-2
@@ -221,6 +221,7 @@ public:
|
||||
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);
|
||||
|
||||
void AI_Init();
|
||||
void AI_Start(uint32 iMoveDelay = 0);
|
||||
@@ -1077,7 +1078,7 @@ public:
|
||||
void ClearHover();
|
||||
inline bool IsBlockedBuff(int16 SpellID) { return PlayerBlockedBuffs.find(SpellID) != PlayerBlockedBuffs.end(); }
|
||||
inline bool IsBlockedPetBuff(int16 SpellID) { return PetBlockedBuffs.find(SpellID) != PetBlockedBuffs.end(); }
|
||||
bool IsDraggingCorpse(const char* CorpseName);
|
||||
bool IsDraggingCorpse(uint16 CorpseID);
|
||||
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
||||
void DragCorpses();
|
||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||
@@ -1480,7 +1481,7 @@ private:
|
||||
|
||||
std::set<uint32> PlayerBlockedBuffs;
|
||||
std::set<uint32> PetBlockedBuffs;
|
||||
std::list<std::string> DraggedCorpses;
|
||||
std::list<std::pair<std::string, uint16> > DraggedCorpses;
|
||||
|
||||
uint8 MaxXTargets;
|
||||
bool XTargetAutoAddHaters;
|
||||
|
||||
@@ -1857,7 +1857,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
effectmod = itembonuses.singingMod;
|
||||
else
|
||||
effectmod = spellbonuses.singingMod;
|
||||
effectmod += aabonuses.singingMod;
|
||||
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
|
||||
break;
|
||||
default:
|
||||
effectmod = 10;
|
||||
|
||||
@@ -9466,7 +9466,7 @@ void Client::CompleteConnect()
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1]);
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
|
||||
break;
|
||||
}
|
||||
case SE_DefensiveProc:
|
||||
@@ -12379,7 +12379,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app)
|
||||
if(!corpse || !corpse->IsPlayerCorpse() || corpse->CastToCorpse()->IsBeingLooted())
|
||||
return;
|
||||
|
||||
Client *c = entity_list.FindCorpseDragger(cds->CorpseName);
|
||||
Client *c = entity_list.FindCorpseDragger(corpse->GetID());
|
||||
|
||||
if(c)
|
||||
{
|
||||
@@ -12394,7 +12394,7 @@ void Client::Handle_OP_CorpseDrag(const EQApplicationPacket *app)
|
||||
if(!corpse->CastToCorpse()->Summon(this, false, true))
|
||||
return;
|
||||
|
||||
DraggedCorpses.push_back(cds->CorpseName);
|
||||
DraggedCorpses.push_back(std::pair<std::string, uint16>(cds->CorpseName, corpse->GetID()));
|
||||
|
||||
Message_StringID(MT_DefaultText, CORPSEDRAG_BEGIN, cds->CorpseName);
|
||||
}
|
||||
@@ -12408,9 +12408,9 @@ void Client::Handle_OP_CorpseDrop(const EQApplicationPacket *app)
|
||||
return;
|
||||
}
|
||||
|
||||
for(std::list<std::string>::iterator Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
|
||||
for (auto Iterator = DraggedCorpses.begin(); Iterator != DraggedCorpses.end(); ++Iterator)
|
||||
{
|
||||
if(!strcasecmp((*Iterator).c_str(), (const char *)app->pBuffer))
|
||||
if(!strcasecmp(Iterator->first.c_str(), (const char *)app->pBuffer))
|
||||
{
|
||||
Message_StringID(MT_DefaultText, CORPSEDRAG_STOP);
|
||||
Iterator = DraggedCorpses.erase(Iterator);
|
||||
|
||||
@@ -11047,9 +11047,6 @@ void command_showbonusstats(Client *c, const Seperator *sep)
|
||||
c->Message(0, " Target Spell Bonuses:");
|
||||
c->Message(0, " Accuracy: %i%% Divine Save: %i%%",c->GetTarget()->GetSpellBonuses().Accuracy, c->GetTarget()->GetSpellBonuses().DivineSaveChance);
|
||||
c->Message(0, " Flurry: %i%% HitChance: %i%% ",c->GetTarget()->GetSpellBonuses().FlurryChance, c->GetTarget()->GetSpellBonuses().HitChance / 15);
|
||||
int deathsaveslot = c->GetTarget()->GetBuffSlotFromType(SE_DeathSave);
|
||||
int dschance = deathsaveslot >= 0 ? c->GetTarget()->GetBuffs()[deathsaveslot].deathSaveSuccessChance : 0;
|
||||
c->Message(0, " Death Save: %i%%",dschance);
|
||||
}
|
||||
c->Message(0, " Effective Casting Level: %i",c->GetTarget()->GetCasterLevel(0));
|
||||
}
|
||||
|
||||
+9
-2
@@ -155,8 +155,11 @@ struct Buffs_Struct {
|
||||
uint32 numhits; //the number of physical hits this buff can take before it fades away, lots of druid armor spells take advantage of this mixed with powerful effects
|
||||
uint32 melee_rune;
|
||||
uint32 magic_rune;
|
||||
uint8 deathSaveSuccessChance;
|
||||
uint8 deathsaveCasterAARank;
|
||||
uint32 dot_rune;
|
||||
int32 caston_x;
|
||||
int32 caston_y;
|
||||
int32 caston_z;
|
||||
int32 ExtraDIChance;
|
||||
bool persistant_buff;
|
||||
bool client; //True if the caster is a client
|
||||
bool UpdateClient;
|
||||
@@ -231,6 +234,7 @@ struct StatBonuses {
|
||||
int effective_casting_level;
|
||||
int reflect_chance; // chance to reflect incoming spell
|
||||
uint16 singingMod;
|
||||
uint16 Amplification; // stacks with singingMod
|
||||
uint16 brassMod;
|
||||
uint16 percussionMod;
|
||||
uint16 windMod;
|
||||
@@ -319,6 +323,7 @@ struct StatBonuses {
|
||||
uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger.
|
||||
uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger.
|
||||
uint16 MitigateSpellRune[2]; // 0 = Mitigation value 1 = Buff Slot
|
||||
uint16 MitigateDotRune[2]; // 0 = Mitigation value 1 = Buff Slot
|
||||
uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger
|
||||
uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger
|
||||
uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot
|
||||
@@ -328,6 +333,8 @@ struct StatBonuses {
|
||||
bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast
|
||||
bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast
|
||||
bool DivineAura; // invulnerability
|
||||
bool DistanceRemoval; // Check if Cancle if Moved effect is present
|
||||
int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid
|
||||
//bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect
|
||||
//bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect
|
||||
|
||||
|
||||
+2
-2
@@ -4512,11 +4512,11 @@ void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height,
|
||||
}
|
||||
}
|
||||
|
||||
Client *EntityList::FindCorpseDragger(const char *CorpseName)
|
||||
Client *EntityList::FindCorpseDragger(uint16 CorpseID)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
if (it->second->IsDraggingCorpse(CorpseName))
|
||||
if (it->second->IsDraggingCorpse(CorpseID))
|
||||
return it->second;
|
||||
++it;
|
||||
}
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ public:
|
||||
|
||||
Spawn2* GetSpawnByID(uint32 id);
|
||||
|
||||
Client* FindCorpseDragger(const char *CorpseName);
|
||||
Client* FindCorpseDragger(uint16 CorpseID);
|
||||
|
||||
inline Object *GetObjectByID(uint16 id)
|
||||
{ return object_list.count(id) ? object_list.at(id) : nullptr; }
|
||||
|
||||
+10
-6
@@ -268,6 +268,9 @@ Mob *HateList::GetTop(Mob *center)
|
||||
Mob* top = nullptr;
|
||||
int32 hate = -1;
|
||||
|
||||
if(center == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (RuleB(Aggro,SmartAggroList)){
|
||||
Mob* topClientTypeInRange = nullptr;
|
||||
int32 hateClientTypeInRange = -1;
|
||||
@@ -380,15 +383,15 @@ Mob *HateList::GetTop(Mob *center)
|
||||
}
|
||||
|
||||
if(!isTopClientType)
|
||||
return topClientTypeInRange;
|
||||
return topClientTypeInRange ? topClientTypeInRange : nullptr;
|
||||
|
||||
return top;
|
||||
return top ? top : nullptr;
|
||||
}
|
||||
else {
|
||||
if(top == nullptr && skipped_count > 0) {
|
||||
return center->GetTarget();
|
||||
return center->GetTarget() ? center->GetTarget() : nullptr;
|
||||
}
|
||||
return top;
|
||||
return top ? top : nullptr;
|
||||
}
|
||||
}
|
||||
else{
|
||||
@@ -413,10 +416,11 @@ Mob *HateList::GetTop(Mob *center)
|
||||
++iterator;
|
||||
}
|
||||
if(top == nullptr && skipped_count > 0) {
|
||||
return center->GetTarget();
|
||||
return center->GetTarget() ? center->GetTarget() : nullptr;
|
||||
}
|
||||
return top;
|
||||
return top ? top : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mob *HateList::GetMostHate(){
|
||||
|
||||
@@ -908,6 +908,16 @@ void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) {
|
||||
self->SetHate(other, hate, damage);
|
||||
}
|
||||
|
||||
void Lua_Mob::HalveAggro(Lua_Mob other) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->HalveAggro(other);
|
||||
}
|
||||
|
||||
void Lua_Mob::DoubleAggro(Lua_Mob other) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->DoubleAggro(other);
|
||||
}
|
||||
|
||||
uint32 Lua_Mob::GetHateAmount(Lua_Mob target) {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetHateAmount(target);
|
||||
@@ -1967,6 +1977,8 @@ luabind::scope lua_register_mob() {
|
||||
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::SetHate)
|
||||
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int))&Lua_Mob::SetHate)
|
||||
.def("SetHate", (void(Lua_Mob::*)(Lua_Mob,int,int))&Lua_Mob::SetHate)
|
||||
.def("HalveAggro", &Lua_Mob::HalveAggro)
|
||||
.def("DoubleAggro", &Lua_Mob::DoubleAggro)
|
||||
.def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetHateAmount)
|
||||
.def("GetHateAmount", (uint32(Lua_Mob::*)(Lua_Mob,bool))&Lua_Mob::GetHateAmount)
|
||||
.def("GetDamageAmount", (uint32(Lua_Mob::*)(Lua_Mob))&Lua_Mob::GetDamageAmount)
|
||||
|
||||
+3
-1
@@ -192,6 +192,8 @@ public:
|
||||
void SetHate(Lua_Mob other);
|
||||
void SetHate(Lua_Mob other, int hate);
|
||||
void SetHate(Lua_Mob other, int hate, int damage);
|
||||
void HalveAggro(Lua_Mob other);
|
||||
void DoubleAggro(Lua_Mob other);
|
||||
uint32 GetHateAmount(Lua_Mob target);
|
||||
uint32 GetHateAmount(Lua_Mob target, bool is_damage);
|
||||
uint32 GetDamageAmount(Lua_Mob target);
|
||||
@@ -346,4 +348,4 @@ public:
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -3670,7 +3670,7 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) {
|
||||
result.time_cancast = 0;
|
||||
|
||||
if(caster) {
|
||||
std::list<MercSpell> mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Calm);
|
||||
std::list<MercSpell> mercSpellList = GetMercSpellsForSpellEffect(caster, SE_InstantHate);
|
||||
|
||||
for(std::list<MercSpell>::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) {
|
||||
// Assuming all the spells have been loaded into this list by level and in descending order
|
||||
|
||||
+44
-16
@@ -3228,11 +3228,20 @@ void Mob::TryApplyEffect(Mob *target, uint32 spell_id)
|
||||
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
|
||||
{
|
||||
/*
|
||||
At present time there is no obvious difference between ReqTarget and ReqCaster
|
||||
ReqTarget is typically used in spells cast on a target where the trigger occurs on that target.
|
||||
ReqCaster is typically self only spells where the triggers on self.
|
||||
Regardless both trigger on the owner of the buff.
|
||||
*/
|
||||
|
||||
/*
|
||||
Base2 Range: 1004 = Below < 80% HP
|
||||
Base2 Range: 500-520 = Below (base2 - 500)*5 HP
|
||||
Base2 Range: 521 = Below (?) Mana UKNOWN - Will assume its 20% unless proven otherwise
|
||||
Base2 Range: 522 = Below (40%) Endurance
|
||||
Base2 Range: 523 = Below (40%) Mana
|
||||
Base2 Range: 220-? = Number of pets on hatelist to trigger (base2 - 220) (Set at 30 pets max for now)
|
||||
38311 = < 10% mana;
|
||||
*/
|
||||
|
||||
if (!spellbonuses.TriggerOnValueAmount)
|
||||
@@ -3250,21 +3259,25 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
|
||||
for(int i = 0; i < EFFECT_COUNT; i++){
|
||||
|
||||
if (spells[spell_id].effectid[i] == SE_TriggerOnValueAmount){
|
||||
if ((spells[spell_id].effectid[i] == SE_TriggerOnReqTarget) || (spells[spell_id].effectid[i] == SE_TriggerOnReqCaster)) {
|
||||
|
||||
int base2 = spells[spell_id].base2[i];
|
||||
bool use_spell = false;
|
||||
|
||||
if (IsHP){
|
||||
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5){
|
||||
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5)
|
||||
use_spell = true;
|
||||
|
||||
else if (base2 = 1004 && GetHPRatio() < 80)
|
||||
use_spell = true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsMana){
|
||||
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40)) {
|
||||
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40))
|
||||
use_spell = true;
|
||||
|
||||
else if (base2 = 38311 && GetManaRatio() < 10)
|
||||
use_spell = true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsEndur){
|
||||
@@ -3283,10 +3296,6 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
|
||||
if (use_spell){
|
||||
SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff);
|
||||
|
||||
/*Note, spell data shows numhits values of 0 or 1, however many descriptions of these spells indicate they should
|
||||
be fading when consumed even with numhits of 0 (It makes sense they should fade...).
|
||||
Unless proven otherwise, they should fade when triggered. */
|
||||
|
||||
if(!TryFadeEffect(e))
|
||||
BuffFadeBySlot(e);
|
||||
}
|
||||
@@ -3412,8 +3421,6 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used)
|
||||
if(skilldmg_mod < -100)
|
||||
skilldmg_mod = -100;
|
||||
|
||||
CheckNumHitsRemaining(6);
|
||||
|
||||
return skilldmg_mod;
|
||||
}
|
||||
|
||||
@@ -4315,17 +4322,38 @@ int16 Mob::GetSkillDmgAmt(uint16 skill)
|
||||
skill_dmg += spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[HIGHEST_SKILL+1]
|
||||
+ itembonuses.SkillDamageAmount2[skill] + spellbonuses.SkillDamageAmount2[skill];
|
||||
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
return skill_dmg;
|
||||
}
|
||||
|
||||
void Mob::MeleeLifeTap(int32 damage) {
|
||||
|
||||
if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap || aabonuses.MeleeLifetap ))
|
||||
{
|
||||
int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap;
|
||||
|
||||
if(lifetap_amt > 100)
|
||||
lifetap_amt = 100;
|
||||
|
||||
else if (lifetap_amt < -99)
|
||||
lifetap_amt = -99;
|
||||
|
||||
|
||||
lifetap_amt = damage * lifetap_amt / 100;
|
||||
|
||||
mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage);
|
||||
//heal self for damage done..
|
||||
HealDamage(lifetap_amt);
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::TryReflectSpell(uint32 spell_id)
|
||||
{
|
||||
if(!GetTarget())
|
||||
return false;
|
||||
if (!spells[spell_id].reflectable)
|
||||
return false;
|
||||
|
||||
if(MakeRandomInt(0, 99) < (GetTarget()->itembonuses.reflect_chance + GetTarget()->spellbonuses.reflect_chance))
|
||||
int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance;
|
||||
|
||||
if(chance && MakeRandomInt(0, 99) < chance)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
+8
-2
@@ -143,6 +143,7 @@ public:
|
||||
virtual void DoRiposte(Mob* defender);
|
||||
void ApplyMeleeDamageBonus(uint16 skill, int32 &damage);
|
||||
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);
|
||||
bool CombatRange(Mob* other);
|
||||
virtual inline bool IsBerserk() { return false; } // only clients
|
||||
|
||||
@@ -427,6 +428,8 @@ public:
|
||||
bool bFrenzy = false, bool iBuffTic = false);
|
||||
bool RemoveFromHateList(Mob* mob);
|
||||
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);}
|
||||
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); }
|
||||
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); }
|
||||
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);}
|
||||
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);}
|
||||
Mob* GetHateTop() { return hate_list.GetTop(this);}
|
||||
@@ -497,7 +500,7 @@ public:
|
||||
bool AddSkillProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool RemoveSkillProc(uint16 spell_id, bool bAll = false);
|
||||
bool HasSkillProcs() const;
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3);
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
|
||||
bool HasProcs() const;
|
||||
|
||||
@@ -587,6 +590,9 @@ public:
|
||||
int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false);
|
||||
int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect);
|
||||
int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg);
|
||||
void MeleeLifeTap(int32 damage);
|
||||
bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true);
|
||||
bool ImprovedTaunt();
|
||||
|
||||
void ModSkillDmgTaken(SkillUseTypes skill_num, int value);
|
||||
int16 GetModSkillDmgTaken(const SkillUseTypes skill_num);
|
||||
@@ -878,7 +884,7 @@ protected:
|
||||
bool IsFullHP;
|
||||
bool moved;
|
||||
|
||||
std::vector<std::string> RampageArray;
|
||||
std::vector<uint16> RampageArray;
|
||||
std::map<std::string, std::string> m_EntityVariables;
|
||||
|
||||
int16 SkillDmgTaken_Mod[HIGHEST_SKILL+2];
|
||||
|
||||
@@ -183,8 +183,7 @@ int Mob::mod_spell_stack(uint16 spellid1, int caster_level1, Mob* caster1, uint1
|
||||
|
||||
//Sum of various resists rolled against a value of 200.
|
||||
int Mob::mod_spell_resist(int resist_chance, int level_mod, int resist_modifier, int target_resist, uint8 resist_type, uint16 spell_id, Mob* caster) {
|
||||
int final = resist_chance + level_mod + resist_modifier + target_resist;
|
||||
return(final);
|
||||
return(resist_chance);
|
||||
}
|
||||
|
||||
//Spell is cast by this on spelltar, called from spellontarget after the event_cast_on NPC event
|
||||
|
||||
+3
-1
@@ -476,6 +476,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
entity_list.Clear();
|
||||
|
||||
parse->ClearInterfaces();
|
||||
|
||||
#ifdef EMBPERL
|
||||
safe_delete(perl_parser);
|
||||
#endif
|
||||
@@ -496,7 +498,7 @@ int main(int argc, char** argv) {
|
||||
dbasync->StopThread();
|
||||
safe_delete(taskmanager);
|
||||
command_deinit();
|
||||
|
||||
safe_delete(parse);
|
||||
CheckEQEMuErrorAndPause();
|
||||
_log(ZONE__INIT, "Proper zone shutdown complete.");
|
||||
return 0;
|
||||
|
||||
@@ -5341,6 +5341,72 @@ XS(XS_Mob_SetHate)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_HalveAggro);
|
||||
XS(XS_Mob_HalveAggro)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::HalveAggro(THIS, other)");
|
||||
{
|
||||
Mob * THIS;
|
||||
Mob * other;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
other = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "other is not of type Mob");
|
||||
if(other == nullptr)
|
||||
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
|
||||
|
||||
THIS->HalveAggro(other);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_DoubleAggro);
|
||||
XS(XS_Mob_DoubleAggro)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: Mob::DoubleAggro(THIS, other)");
|
||||
{
|
||||
Mob * THIS;
|
||||
Mob * other;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (sv_derived_from(ST(1), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(1)));
|
||||
other = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "other is not of type Mob");
|
||||
if(other == nullptr)
|
||||
Perl_croak(aTHX_ "other is nullptr, avoiding crash.");
|
||||
|
||||
THIS->DoubleAggro(other);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetHateAmount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_GetHateAmount)
|
||||
{
|
||||
@@ -8274,6 +8340,8 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "IsRooted"), XS_Mob_IsRooted, file, "$");
|
||||
newXSproto(strcpy(buf, "AddToHateList"), XS_Mob_AddToHateList, file, "$$;$$$$$");
|
||||
newXSproto(strcpy(buf, "SetHate"), XS_Mob_SetHate, file, "$$;$$");
|
||||
newXSproto(strcpy(buf, "HalveAggro"), XS_Mob_HalveAggro, file, "$$");
|
||||
newXSproto(strcpy(buf, "DoubleAggro"), XS_Mob_DoubleAggro, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetHateAmount"), XS_Mob_GetHateAmount, file, "$$;$");
|
||||
newXSproto(strcpy(buf, "GetDamageAmount"), XS_Mob_GetDamageAmount, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetHateTop"), XS_Mob_GetHateTop, file, "$");
|
||||
|
||||
+2
-2
@@ -605,9 +605,9 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
// We need to reapply buff based procs
|
||||
// We need to do this here so suspended pets also regain their procs.
|
||||
if (spells[buffs[j1].spellid].base2[x1] == 0) {
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100);
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100, buffs[j1].spellid);
|
||||
} else {
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1]);
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid);
|
||||
}
|
||||
break;
|
||||
case SE_Charm:
|
||||
|
||||
@@ -155,6 +155,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
if(!GetTarget())return;
|
||||
if (HasDied()) return;
|
||||
|
||||
if (max_damage > 0)
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
//[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill
|
||||
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){
|
||||
int kb_chance = 25;
|
||||
@@ -606,14 +609,16 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
if(IsClient()){
|
||||
const ItemInst *wpn = nullptr;
|
||||
wpn = CastToClient()->GetInv().GetItem(SLOT_PRIMARY);
|
||||
primaryweapondamage = GetWeaponDamage(other, wpn);
|
||||
backstab_dmg = wpn->GetItem()->BackstabDmg;
|
||||
for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i)
|
||||
{
|
||||
ItemInst *aug = wpn->GetAugment(i);
|
||||
if(aug)
|
||||
if(wpn) {
|
||||
primaryweapondamage = GetWeaponDamage(other, wpn);
|
||||
backstab_dmg = wpn->GetItem()->BackstabDmg;
|
||||
for(int i = 0; i < MAX_AUGMENT_SLOTS; ++i)
|
||||
{
|
||||
backstab_dmg += aug->GetItem()->BackstabDmg;
|
||||
ItemInst *aug = wpn->GetAugment(i);
|
||||
if(aug)
|
||||
{
|
||||
backstab_dmg += aug->GetItem()->BackstabDmg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -948,6 +953,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
|
||||
TryCriticalHit(other, SkillArchery, TotalDmg);
|
||||
other->AddToHateList(this, hate, 0, false);
|
||||
CheckNumHitsRemaining(5);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1052,6 +1058,7 @@ void NPC::RangedAttack(Mob* other)
|
||||
TryCriticalHit(GetTarget(), SkillArchery, TotalDmg);
|
||||
GetTarget()->AddToHateList(this, hate, 0, false);
|
||||
GetTarget()->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
|
||||
CheckNumHitsRemaining(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1270,6 +1277,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
TryCriticalHit(other, SkillThrowing, TotalDmg);
|
||||
int32 hate = (2*WDmg);
|
||||
other->AddToHateList(this, hate, 0, false);
|
||||
CheckNumHitsRemaining(5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2181,6 +2189,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
CheckNumHitsRemaining(5);
|
||||
|
||||
if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){
|
||||
int kb_chance = 25;
|
||||
kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100;
|
||||
|
||||
+436
-174
@@ -183,7 +183,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id);
|
||||
}
|
||||
|
||||
Numhits(true);
|
||||
buffs[buffslot].numhits = numhit;
|
||||
}
|
||||
|
||||
@@ -218,83 +217,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
int32 dmg = effect_value;
|
||||
if(dmg < 0)
|
||||
{
|
||||
|
||||
/*Special Cases where Base2 is defined
|
||||
Range 105 : Plant
|
||||
Range 120 : Undead
|
||||
Range 123 : Humanoid
|
||||
Range 190 : No Raid boss flag *not implemented
|
||||
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
|
||||
Range 201 : Damage if HP > 75%
|
||||
Range 221 - 299 : Causing damage dependent on how many pets/swarmpets are attacking your target.
|
||||
Range 300 - 303 : UNKOWN *not implemented
|
||||
Range 399 - 499 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
|
||||
Range 500 - 599 : Heal if HP less than a specified value
|
||||
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
|
||||
Range 818 - 819 : If Undead/If Not Undead
|
||||
Range 835 - : Unknown *not implemented
|
||||
Range 836 - 837 : Progression Server / Live Server *not implemented
|
||||
Range 839 - : Unknown *not implemented
|
||||
Range 10000+ : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement)
|
||||
|
||||
*/
|
||||
|
||||
if (spells[spell_id].base2[i] > 0){
|
||||
|
||||
//It is unlikely these effects would give a fail message (Need to confirm)
|
||||
if (spells[spell_id].base2[i] == 105){
|
||||
if (GetBodyType() != BT_Plant)
|
||||
break;
|
||||
}
|
||||
|
||||
else if (spells[spell_id].base2[i] == 120){
|
||||
if (GetBodyType() != BT_Undead)
|
||||
break;
|
||||
}
|
||||
|
||||
else if (spells[spell_id].base2[i] == 123){
|
||||
if (GetBodyType() != BT_Humanoid)
|
||||
break;
|
||||
}
|
||||
|
||||
//Limit to Body Type.
|
||||
else if (spells[spell_id].base2[i] >= 600 && spells[spell_id].base2[i] <= 699){
|
||||
if (GetBodyType() != (spells[spell_id].base2[i] - 600)){
|
||||
//caster->Message_StringID(13,CANNOT_AFFECT_NPC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (spells[spell_id].base2[i] == 201){
|
||||
if (GetHPRatio() < 75)
|
||||
break;
|
||||
}
|
||||
|
||||
//Limit to Race. *Not implemented on live
|
||||
else if (spells[spell_id].base2[i] >= 10000 && spells[spell_id].base2[i] <= 11000){
|
||||
if (GetRace() != (spells[spell_id].base2[i] - 10000)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Limit to amount of pets
|
||||
else if (spells[spell_id].base2[i] >= 221 && spells[spell_id].base2[i] <= 299){
|
||||
bool allow_spell = false;
|
||||
int count = hate_list.SummonedPetCount(this);
|
||||
|
||||
for (int base2_value = 221; base2_value <= 233; ++base2_value){
|
||||
if (spells[spell_id].base2[i] == base2_value){
|
||||
if (count >= (base2_value - 220)){
|
||||
allow_spell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allow_spell)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!PassCastRestriction(false, spells[spell_id].base2[i], true))
|
||||
break;
|
||||
|
||||
// take partial damage into account
|
||||
dmg = (int32) (dmg * partial / 100);
|
||||
@@ -308,60 +232,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
}
|
||||
else if(dmg > 0) {
|
||||
//healing spell...
|
||||
|
||||
if (spells[spell_id].base2[i] > 0)
|
||||
{
|
||||
bool allow_spell = false;
|
||||
|
||||
//Heal only if HP within specified range. [Doesn't follow a set forumla for all values...]
|
||||
if (spells[spell_id].base2[i] >= 400 && spells[spell_id].base2[i] <= 408){
|
||||
for (int base2_value = 400; base2_value <= 408; ++base2_value){
|
||||
if (spells[spell_id].base2[i] == base2_value){
|
||||
|
||||
if (spells[spell_id].base2[i] == 400){
|
||||
if (GetHPRatio() <= 25){
|
||||
allow_spell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if (spells[spell_id].base2[i] == base2_value){
|
||||
if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10)){
|
||||
allow_spell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if (spells[spell_id].base2[i] >= 500 && spells[spell_id].base2[i] <= 520){
|
||||
for (int base2_value = 500; base2_value <= 520; ++base2_value){
|
||||
if (spells[spell_id].base2[i] == base2_value){
|
||||
|
||||
if (spells[spell_id].base2[i] == base2_value){
|
||||
if (GetHPRatio() < (base2_value - 500)*5) {
|
||||
allow_spell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!PassCastRestriction(false, spells[spell_id].base2[i], false))
|
||||
break;
|
||||
|
||||
else if (spells[spell_id].base2[i] == 399){
|
||||
if (GetHPRatio() > 15 && GetHPRatio() <= 25){
|
||||
allow_spell = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!allow_spell)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(caster)
|
||||
dmg = caster->GetActSpellHealing(spell_id, dmg, this);
|
||||
|
||||
@@ -1410,6 +1284,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_MitigateDotDamage:
|
||||
{
|
||||
buffs[buffslot].dot_rune = spells[spell_id].max[i];
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_TriggerMeleeThreshold:
|
||||
{
|
||||
buffs[buffslot].melee_rune = spells[spell_id].base2[i];
|
||||
@@ -1422,7 +1302,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SE_DistanceRemoval:
|
||||
{
|
||||
buffs[buffslot].caston_x = int(GetX());
|
||||
buffs[buffslot].caston_y = int(GetY());
|
||||
buffs[buffslot].caston_z = int(GetZ());
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Levitate:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@@ -1434,6 +1321,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DeathSave: {
|
||||
|
||||
int16 mod = 0;
|
||||
|
||||
if(caster) {
|
||||
mod = caster->aabonuses.UnfailingDivinity +
|
||||
caster->itembonuses.UnfailingDivinity +
|
||||
caster->spellbonuses.UnfailingDivinity;
|
||||
}
|
||||
|
||||
buffs[buffslot].ExtraDIChance = mod;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Illusion:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@@ -1545,10 +1446,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
snprintf(effect_desc, _EDLEN, "Memory Blur: %d", effect_value);
|
||||
#endif
|
||||
int wipechance = spells[spell_id].base[i];
|
||||
int bonus = spellbonuses.IncreaseChanceMemwipe + itembonuses.IncreaseChanceMemwipe + aabonuses.IncreaseChanceMemwipe;
|
||||
int bonus = 0;
|
||||
|
||||
if (caster){
|
||||
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
|
||||
caster->itembonuses.IncreaseChanceMemwipe +
|
||||
caster->aabonuses.IncreaseChanceMemwipe;
|
||||
}
|
||||
|
||||
wipechance += wipechance*bonus/100;
|
||||
|
||||
if(MakeRandomInt(0, 100) < wipechance)
|
||||
if(MakeRandomInt(0, 99) < wipechance)
|
||||
{
|
||||
if(IsAIControlled())
|
||||
{
|
||||
@@ -1821,9 +1729,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
#endif
|
||||
|
||||
if(spells[spell_id].base2[i] == 0)
|
||||
AddProcToWeapon(procid, false, 100);
|
||||
AddProcToWeapon(procid, false, 100, spell_id);
|
||||
else
|
||||
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100);
|
||||
AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2487,30 +2395,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DeathSave: {
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Death Save: %+i", effect_value);
|
||||
#endif
|
||||
uint8 BonusChance = 0;
|
||||
if(caster) {
|
||||
|
||||
BonusChance = caster->aabonuses.UnfailingDivinity +
|
||||
caster->itembonuses.UnfailingDivinity +
|
||||
caster->spellbonuses.UnfailingDivinity;
|
||||
}
|
||||
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
//snprintf(effect_desc, _EDLEN, "Death Save Chance: %+i", SuccessChance);
|
||||
#endif
|
||||
//buffs[buffslot].deathSaveSuccessChance = SuccessChance;
|
||||
//buffs[buffslot].deathsaveCasterAARank = caster->GetAA(aaUnfailingDivinity);
|
||||
buffs[buffslot].deathsaveCasterAARank = BonusChance;
|
||||
//SetDeathSaveChance(true);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SummonAndResAllCorpses:
|
||||
{
|
||||
if(IsClient())
|
||||
@@ -2757,7 +2641,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_MeleeMitigation:
|
||||
case SE_Reflect:
|
||||
case SE_Screech:
|
||||
case SE_SingingSkill:
|
||||
case SE_Amplification:
|
||||
case SE_MagicWeapon:
|
||||
case SE_Hunger:
|
||||
case SE_MagnifyVision:
|
||||
@@ -2793,7 +2677,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_ChangeAggro:
|
||||
case SE_Hate2:
|
||||
case SE_Identify:
|
||||
case SE_Calm:
|
||||
case SE_InstantHate:
|
||||
case SE_ReduceHate:
|
||||
case SE_SpellDamageShield:
|
||||
case SE_ReverseDS:
|
||||
@@ -2889,7 +2773,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_MitigateDamageShield:
|
||||
case SE_FcBaseEffects:
|
||||
case SE_LimitClass:
|
||||
case SE_LimitSpellSubclass:
|
||||
case SE_BlockBehind:
|
||||
case SE_ShieldBlock:
|
||||
case SE_PetCriticalHit:
|
||||
@@ -2932,7 +2815,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_DoubleRangedAttack:
|
||||
case SE_ShieldEquipHateMod:
|
||||
case SE_ShieldEquipDmgMod:
|
||||
case SE_TriggerOnValueAmount:
|
||||
case SE_TriggerOnReqTarget:
|
||||
case SE_LimitRace:
|
||||
case SE_FcLimitUse:
|
||||
case SE_FcMute:
|
||||
@@ -2942,6 +2825,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_IncreaseChanceMemwipe:
|
||||
case SE_CriticalMend:
|
||||
case SE_LimitCastTimeMax:
|
||||
case SE_TriggerOnReqCaster:
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -3403,6 +3287,31 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_WipeHateList:
|
||||
{
|
||||
|
||||
int wipechance = spells[spell_id].base[i];
|
||||
int bonus = 0;
|
||||
|
||||
if (caster){
|
||||
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
|
||||
caster->itembonuses.IncreaseChanceMemwipe +
|
||||
caster->aabonuses.IncreaseChanceMemwipe;
|
||||
}
|
||||
|
||||
wipechance += wipechance*bonus/100;
|
||||
|
||||
if(MakeRandomInt(0, 99) < wipechance)
|
||||
{
|
||||
if(IsAIControlled())
|
||||
{
|
||||
WipeHateList();
|
||||
}
|
||||
Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago...");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Charm: {
|
||||
if (!caster || !PassCharismaCheck(caster, this, spell_id)) {
|
||||
BuffFadeByEffect(SE_Charm);
|
||||
@@ -3504,6 +3413,26 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DistanceRemoval:
|
||||
{
|
||||
if (spellbonuses.DistanceRemoval){
|
||||
|
||||
int distance = sqrt(
|
||||
((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
|
||||
((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
|
||||
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z))
|
||||
);
|
||||
|
||||
if (distance > spells[spell_id].base[i]){
|
||||
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot , true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// do we need to do anyting here?
|
||||
@@ -4152,13 +4081,12 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case SE_LimitCombatSkills:
|
||||
if (base1 == 0){
|
||||
if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs
|
||||
LimitFailure = true;
|
||||
}
|
||||
break;
|
||||
if (base1 == 0 && IsCombatSkill(spell_id)) //Exclude Discs
|
||||
LimitFailure = true;
|
||||
else if (base1 == 1 && !IsCombatSkill(spell_id)) //Exclude Spells
|
||||
LimitFailure = true;
|
||||
break;
|
||||
|
||||
case SE_LimitSpellGroup:
|
||||
if(base1 < 0) {
|
||||
@@ -4555,10 +4483,10 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
break;
|
||||
|
||||
case SE_LimitCombatSkills:
|
||||
if (focus_spell.base[i] == 0){
|
||||
if((spell.cast_time == 0) && (spell.recast_time == 0) && (spell.recovery_time == 0)) //Exclude procs
|
||||
return 0;
|
||||
}
|
||||
if (focus_spell.base[i] == 0 && IsCombatSkill(spell_id)) //Exclude Disc
|
||||
return 0;
|
||||
else if (focus_spell.base[i] == 1 && !IsCombatSkill(spell_id)) //Include Spells
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SE_LimitSpellGroup:
|
||||
@@ -5376,11 +5304,13 @@ bool Mob::TryDeathSave() {
|
||||
|
||||
int SuccessChance = 0;
|
||||
int buffSlot = spellbonuses.DeathSave[1];
|
||||
uint8 UD_HealMod = buffs[buffSlot].deathsaveCasterAARank; //Contains value of UD heal modifier.
|
||||
int16 UD_HealMod = 0;
|
||||
uint32 HealAmt = 300; //Death Pact max Heal
|
||||
|
||||
if(buffSlot >= 0){
|
||||
|
||||
UD_HealMod = buffs[buffSlot].ExtraDIChance;
|
||||
|
||||
SuccessChance = ( (GetCHA() * (RuleI(Spells, DeathSaveCharismaMod))) + 1) / 10; //(CHA Mod Default = 3)
|
||||
|
||||
if (SuccessChance > 95)
|
||||
@@ -5445,6 +5375,8 @@ bool Mob::TryDeathSave() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuffFadeBySlot(buffSlot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -5704,3 +5636,333 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Mob::ImprovedTaunt(){
|
||||
|
||||
if (spellbonuses.ImprovedTaunt[0]){
|
||||
|
||||
if (GetLevel() > spellbonuses.ImprovedTaunt[0])
|
||||
return false;
|
||||
|
||||
if (spellbonuses.ImprovedTaunt[2] >= 0){
|
||||
|
||||
target = entity_list.GetMob(buffs[spellbonuses.ImprovedTaunt[2]].casterid);
|
||||
|
||||
if (target){
|
||||
SetTarget(target);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if(!TryFadeEffect(spellbonuses.ImprovedTaunt[2]))
|
||||
BuffFadeBySlot(spellbonuses.ImprovedTaunt[2], true); //If caster killed removed effect.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDamage)
|
||||
{
|
||||
/*If return TRUE spell met all restrictions and can continue (this = target).
|
||||
This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit
|
||||
Range 1 : UNKNOWN
|
||||
Range 100 : *Animal OR Humanoid
|
||||
Range 101 : *Dragon
|
||||
Range 102 : *Animal OR Insect
|
||||
Range 103 : NOT USED
|
||||
Range 104 : *Animal
|
||||
Range 105 : Plant
|
||||
Range 106 : *Giant
|
||||
Range 107 : NOT USED
|
||||
Range 108 : NOT Animal or Humaniod
|
||||
Range 109 : *Bixie
|
||||
Range 111 : *Harpy
|
||||
Range 112 : *Sporali
|
||||
Range 113 : *Kobold
|
||||
Range 114 : *Shade Giant
|
||||
Range 115 : *Drakkin
|
||||
Range 116 : NOT USED
|
||||
Range 117 : *Animal OR Plant
|
||||
Range 118 : *Summoned
|
||||
Range 119 : *Firepet
|
||||
Range 120 : Undead
|
||||
Range 121 : *Living (NOT Undead)
|
||||
Range 122 : *Fairy
|
||||
Range 123 : Humanoid
|
||||
Range 124 : *Undead HP < 10%
|
||||
Range 125 : *Clockwork HP < 10%
|
||||
Range 126 : *Wisp HP < 10%
|
||||
Range 127-130 : UNKNOWN
|
||||
Range 150 : UNKNOWN
|
||||
Range 190 : No Raid boss flag *not implemented
|
||||
Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented
|
||||
Range 201 : Damage if HP > 75%
|
||||
Range 203 : Damage if HP < 20%
|
||||
Range 216 : TARGET NOT IN COMBAT
|
||||
Range 221 - 249 : Causing damage dependent on how many pets/swarmpets are attacking your target.
|
||||
Range 250 : Damage if HP < 35%
|
||||
Range 300 - 303 : UNKOWN *not implemented
|
||||
Range 304 : Chain + Plate class (buffs)
|
||||
Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect)
|
||||
Range 410 - 411 : UNKOWN
|
||||
Range 500 - 599 : Heal if HP less than a specified value
|
||||
Range 600 - 699 : Limit to Body Type [base2 - 600 = Body]
|
||||
Range 700 : UNKNOWN
|
||||
Range 701 : NOT PET
|
||||
Range 800 : UKNOWN
|
||||
Range 818 - 819 : If Undead/If Not Undead
|
||||
Range 820 - 822 : UKNOWN
|
||||
Range 835 : Unknown *not implemented
|
||||
Range 836 - 837 : Progression Server / Live Server *not implemented
|
||||
Range 839 : Unknown *not implemented
|
||||
Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2)
|
||||
Range 845 - 847 : UNKNOWN
|
||||
Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement)
|
||||
THIS IS A WORK IN PROGRESS
|
||||
*/
|
||||
|
||||
if (value <= 0)
|
||||
return true;
|
||||
|
||||
if (IsDamage || UseCastRestriction) {
|
||||
|
||||
switch(value)
|
||||
{
|
||||
case 100:
|
||||
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 101:
|
||||
if (GetBodyType() == BT_Dragon || GetBodyType() == BT_VeliousDragon || GetBodyType() == BT_Dragon3)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 102:
|
||||
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Insect))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 104:
|
||||
if (GetBodyType() == BT_Animal)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 105:
|
||||
if (GetBodyType() == BT_Plant)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 106:
|
||||
if (GetBodyType() == BT_Giant)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 108:
|
||||
if ((GetBodyType() != BT_Animal) || (GetBodyType() != BT_Humanoid))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 109:
|
||||
if ((GetRace() == 520) ||(GetRace() == 79))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 111:
|
||||
if ((GetRace() == 527) ||(GetRace() == 11))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 112:
|
||||
if ((GetRace() == 456) ||(GetRace() == 28))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 113:
|
||||
if ((GetRace() == 456) ||(GetRace() == 48))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 114:
|
||||
if (GetRace() == 526)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 115:
|
||||
if (GetRace() == 522)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 117:
|
||||
if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Plant))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 118:
|
||||
if (GetBodyType() == BT_Summoned)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 119:
|
||||
if (IsPet() && ((GetRace() == 212) || ((GetRace() == 75) && GetTexture() == 1)))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 120:
|
||||
if (GetBodyType() == BT_Undead)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 121:
|
||||
if (GetBodyType() != BT_Undead)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 122:
|
||||
if ((GetRace() == 473) || (GetRace() == 425))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 123:
|
||||
if (GetBodyType() == BT_Humanoid)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 124:
|
||||
if ((GetBodyType() == BT_Undead) && (GetHPRatio() < 10))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 125:
|
||||
if ((GetRace() == 457 || GetRace() == 88) && (GetHPRatio() < 10))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 126:
|
||||
if ((GetRace() == 581 || GetRace() == 69) && (GetHPRatio() < 10))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 201:
|
||||
if (GetHPRatio() > 75)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 204:
|
||||
if (GetHPRatio() < 20)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 216:
|
||||
if (!IsEngaged())
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 250:
|
||||
if (GetHPRatio() < 35)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 304:
|
||||
if (IsClient() &&
|
||||
((GetClass() == WARRIOR) || (GetClass() == BARD) || (GetClass() == SHADOWKNIGHT) || (GetClass() == PALADIN) || (GetClass() == CLERIC)
|
||||
|| (GetClass() == RANGER) || (GetClass() == SHAMAN) || (GetClass() == ROGUE) || (GetClass() == BERSERKER)))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 701:
|
||||
if (!IsPet())
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 818:
|
||||
if (GetBodyType() == BT_Undead)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 819:
|
||||
if (GetBodyType() != BT_Undead)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 842:
|
||||
if (GetBodyType() == BT_Humanoid && GetLevel() <= 84)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 843:
|
||||
if (GetBodyType() == BT_Humanoid && GetLevel() <= 86)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case 844:
|
||||
if (GetBodyType() == BT_Humanoid && GetLevel() <= 88)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
//Limit to amount of pets
|
||||
if (value >= 221 && value <= 249){
|
||||
int count = hate_list.SummonedPetCount(this);
|
||||
|
||||
for (int base2_value = 221; base2_value <= 249; ++base2_value){
|
||||
if (value == base2_value){
|
||||
if (count >= (base2_value - 220)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Limit to Body Type
|
||||
if (value >= 600 && value <= 699){
|
||||
if (GetBodyType() == (value - 600))
|
||||
return true;
|
||||
}
|
||||
|
||||
//Limit to Race. *Not implemented on live
|
||||
if (value >= 10000 && value <= 11000){
|
||||
if (GetRace() == (value - 10000))
|
||||
return true;
|
||||
}
|
||||
} //End Damage
|
||||
|
||||
if (!IsDamage || UseCastRestriction) {
|
||||
|
||||
//Heal only if HP within specified range. [Doesn't follow a set forumla for all values...]
|
||||
if (value >= 400 && value <= 408){
|
||||
for (int base2_value = 400; base2_value <= 408; ++base2_value){
|
||||
if (value == base2_value){
|
||||
|
||||
if (value == 400 && GetHPRatio() <= 25)
|
||||
return true;
|
||||
|
||||
else if (value == base2_value){
|
||||
if (GetHPRatio() > 25+((base2_value - 401)*10) && GetHPRatio() <= 35+((base2_value - 401)*10))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (value >= 500 && value <= 549){
|
||||
for (int base2_value = 500; base2_value <= 520; ++base2_value){
|
||||
if (value == base2_value){
|
||||
if (GetHPRatio() < (base2_value - 500)*5)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (value == 399) {
|
||||
if (GetHPRatio() > 15 && GetHPRatio() <= 25)
|
||||
return true;
|
||||
}
|
||||
} // End Heal
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+21
-10
@@ -1361,6 +1361,11 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id);
|
||||
targetType = ST_GroupClientAndPet;
|
||||
}
|
||||
|
||||
if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){
|
||||
Message_StringID(13,SPELL_NEED_TAR);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (targetType)
|
||||
{
|
||||
@@ -2948,8 +2953,11 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
buffs[emptyslot].numhits = spells[spell_id].numhits;
|
||||
buffs[emptyslot].client = caster ? caster->IsClient() : 0;
|
||||
buffs[emptyslot].persistant_buff = 0;
|
||||
buffs[emptyslot].deathsaveCasterAARank = 0;
|
||||
buffs[emptyslot].deathSaveSuccessChance = 0;
|
||||
buffs[emptyslot].caston_x = 0;
|
||||
buffs[emptyslot].caston_y = 0;
|
||||
buffs[emptyslot].caston_z = 0;
|
||||
buffs[emptyslot].dot_rune = 0;
|
||||
buffs[emptyslot].ExtraDIChance = 0;
|
||||
|
||||
if (level_override > 0) {
|
||||
buffs[emptyslot].UpdateClient = true;
|
||||
@@ -3355,7 +3363,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
}
|
||||
}
|
||||
// Reflect
|
||||
if(TryReflectSpell(spell_id) && spelltar && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) {
|
||||
if(spelltar && spelltar->TryReflectSpell(spell_id) && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) {
|
||||
int reflect_chance = 0;
|
||||
switch(RuleI(Spells, ReflectType))
|
||||
{
|
||||
@@ -3402,9 +3410,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
}
|
||||
}
|
||||
|
||||
if (spelltar && IsDetrimentalSpell(spell_id))
|
||||
spelltar->CheckNumHitsRemaining(3);
|
||||
|
||||
// resist check - every spell can be resisted, beneficial or not
|
||||
// add: ok this isn't true, eqlive's spell data is fucked up, buffs are
|
||||
// not all unresistable, so changing this to only check certain spells
|
||||
@@ -3438,6 +3443,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
}
|
||||
}
|
||||
|
||||
spelltar->CheckNumHitsRemaining(3);
|
||||
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
}
|
||||
@@ -3575,7 +3582,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
safe_delete(action_packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// cause the effects to the target
|
||||
if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness))
|
||||
{
|
||||
@@ -3588,6 +3595,10 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (spelltar && IsDetrimentalSpell(spell_id))
|
||||
spelltar->CheckNumHitsRemaining(3); //Incoming spells
|
||||
|
||||
// send the action packet again now that the spell is successful
|
||||
// NOTE: this is what causes the buff icon to appear on the client, if
|
||||
// this is a buff - but it sortof relies on the first packet.
|
||||
@@ -4816,7 +4827,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id) {
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
|
||||
@@ -4826,7 +4837,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
|
||||
if (PermaProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
PermaProcs[i].spellID = spell_id;
|
||||
PermaProcs[i].chance = iChance;
|
||||
PermaProcs[i].base_spellID = SPELL_UNKNOWN;
|
||||
PermaProcs[i].base_spellID = base_spell_id;
|
||||
mlog(SPELLS__PROCS, "Added permanent proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||
|
||||
return true;
|
||||
@@ -4838,7 +4849,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance) {
|
||||
if (SpellProcs[i].spellID == SPELL_UNKNOWN) {
|
||||
SpellProcs[i].spellID = spell_id;
|
||||
SpellProcs[i].chance = iChance;
|
||||
SpellProcs[i].base_spellID = SPELL_UNKNOWN;;
|
||||
SpellProcs[i].base_spellID = base_spell_id;;
|
||||
mlog(SPELLS__PROCS, "Added spell-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
|
||||
+31
-22
@@ -1815,7 +1815,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, "
|
||||
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, "
|
||||
"DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);",
|
||||
"dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);",
|
||||
merc->GetMercID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula,
|
||||
buffs[BuffCount].ticsremaining,
|
||||
CalculatePoisonCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
@@ -1823,8 +1823,12 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
|
||||
CalculateCurseCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
CalculateCorruptionCounters(buffs[BuffCount].spellid) > 0 ? buffs[BuffCount].counters : 0,
|
||||
buffs[BuffCount].numhits, buffs[BuffCount].melee_rune, buffs[BuffCount].magic_rune,
|
||||
buffs[BuffCount].deathSaveSuccessChance,
|
||||
buffs[BuffCount].deathsaveCasterAARank, IsPersistent), TempErrorMessageBuffer)) {
|
||||
buffs[BuffCount].dot_rune,
|
||||
buffs[BuffCount].caston_x,
|
||||
IsPersistent,
|
||||
buffs[BuffCount].caston_y,
|
||||
buffs[BuffCount].caston_z,
|
||||
buffs[BuffCount].ExtraDIChance), TempErrorMessageBuffer)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
safe_delete(Query);
|
||||
Query = 0;
|
||||
@@ -1856,7 +1860,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
|
||||
|
||||
bool BuffsLoaded = false;
|
||||
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, caston_y, caston_z, ExtraDIChance FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
|
||||
errorMessage = std::string(TempErrorMessageBuffer);
|
||||
}
|
||||
else {
|
||||
@@ -1882,8 +1886,8 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
|
||||
buffs[BuffCount].numhits = atoi(DataRow[8]);
|
||||
buffs[BuffCount].melee_rune = atoi(DataRow[9]);
|
||||
buffs[BuffCount].magic_rune = atoi(DataRow[10]);
|
||||
buffs[BuffCount].deathSaveSuccessChance = atoi(DataRow[11]);
|
||||
buffs[BuffCount].deathsaveCasterAARank = atoi(DataRow[12]);
|
||||
buffs[BuffCount].dot_rune = atoi(DataRow[11]);
|
||||
buffs[BuffCount].caston_x = atoi(DataRow[12]);
|
||||
buffs[BuffCount].casterid = 0;
|
||||
|
||||
bool IsPersistent = false;
|
||||
@@ -1891,6 +1895,10 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
|
||||
if(atoi(DataRow[13]))
|
||||
IsPersistent = true;
|
||||
|
||||
buffs[BuffCount].caston_y = atoi(DataRow[13]);
|
||||
buffs[BuffCount].caston_z = atoi(DataRow[14]);
|
||||
buffs[BuffCount].ExtraDIChance = atoi(DataRow[15]);
|
||||
|
||||
buffs[BuffCount].persistant_buff = IsPersistent;
|
||||
|
||||
BuffCount++;
|
||||
@@ -2484,9 +2492,9 @@ void ZoneDatabase::ListAllInstances(Client* c, uint32 charid)
|
||||
MYSQL_ROW row;
|
||||
|
||||
|
||||
if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_lockout.id, zone, version FROM instance_lockout JOIN"
|
||||
" instance_lockout_player ON instance_lockout.id = instance_lockout_player.id"
|
||||
" WHERE instance_lockout_player.charid=%lu", (unsigned long)charid),errbuf,&result))
|
||||
if (RunQuery(query,MakeAnyLenString(&query, "SELECT instance_list.id, zone, version FROM instance_list JOIN"
|
||||
" instance_list_player ON instance_list.id = instance_list_player.id"
|
||||
" WHERE instance_list_player.charid=%lu", (unsigned long)charid),errbuf,&result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
|
||||
@@ -2566,11 +2574,11 @@ void ZoneDatabase::SaveBuffs(Client *c) {
|
||||
for (int i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, "INSERT INTO `character_buffs` (character_id, slot_id, spell_id, "
|
||||
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, death_save_chance, "
|
||||
"death_save_aa_chance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
|
||||
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
|
||||
"caston_x, caston_y, caston_z, ExtraDIChance) VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%i', '%i', '%i', '%i')",
|
||||
c->CharacterID(), i, buffs[i].spellid, buffs[i].casterlevel, buffs[i].caster_name, buffs[i].ticsremaining,
|
||||
buffs[i].counters, buffs[i].numhits, buffs[i].melee_rune, buffs[i].magic_rune, buffs[i].persistant_buff,
|
||||
buffs[i].deathSaveSuccessChance, buffs[i].deathsaveCasterAARank),
|
||||
buffs[i].dot_rune, buffs[i].caston_x, buffs[i].caston_y, buffs[i].caston_z, buffs[i].ExtraDIChance),
|
||||
errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SaveBuffs query '%s': %s", query, errbuf);
|
||||
}
|
||||
@@ -2592,7 +2600,7 @@ void ZoneDatabase::LoadBuffs(Client *c) {
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, counters, "
|
||||
"numhits, melee_rune, magic_rune, persistent, death_save_chance, death_save_aa_chance FROM `character_buffs` WHERE "
|
||||
"numhits, melee_rune, magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance FROM `character_buffs` WHERE "
|
||||
"`character_id`='%u'",
|
||||
c->CharacterID()), errbuf, &result))
|
||||
{
|
||||
@@ -2617,8 +2625,11 @@ void ZoneDatabase::LoadBuffs(Client *c) {
|
||||
uint32 melee_rune = atoul(row[7]);
|
||||
uint32 magic_rune = atoul(row[8]);
|
||||
uint8 persistent = atoul(row[9]);
|
||||
uint32 death_save_chance = atoul(row[10]);
|
||||
uint32 death_save_aa_chance = atoul(row[11]);
|
||||
uint32 dot_rune = atoul(row[10]);
|
||||
int32 caston_x = atoul(row[11]);
|
||||
int32 caston_y = atoul(row[12]);
|
||||
int32 caston_z = atoul(row[13]);
|
||||
int32 ExtraDIChance = atoul(row[14]);
|
||||
|
||||
buffs[slot_id].spellid = spell_id;
|
||||
buffs[slot_id].casterlevel = caster_level;
|
||||
@@ -2638,8 +2649,11 @@ void ZoneDatabase::LoadBuffs(Client *c) {
|
||||
buffs[slot_id].melee_rune = melee_rune;
|
||||
buffs[slot_id].magic_rune = magic_rune;
|
||||
buffs[slot_id].persistant_buff = persistent ? true : false;
|
||||
buffs[slot_id].deathSaveSuccessChance = death_save_chance;
|
||||
buffs[slot_id].deathsaveCasterAARank = death_save_aa_chance;
|
||||
buffs[slot_id].dot_rune = dot_rune;
|
||||
buffs[slot_id].caston_x = caston_x;
|
||||
buffs[slot_id].caston_y = caston_y;
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
if(IsRuneSpell(spell_id)) {
|
||||
c->SetHasRune(true);
|
||||
@@ -2648,11 +2662,6 @@ void ZoneDatabase::LoadBuffs(Client *c) {
|
||||
c->SetHasSpellRune(true);
|
||||
}
|
||||
|
||||
/*
|
||||
if(IsDeathSaveSpell(spell_id)) {
|
||||
c->SetDeathSaveChance(true);
|
||||
}
|
||||
*/
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user