Kayen: Implemented SE_ArcheryDoubleAttack (Chance to do an extra archery attack)

Kayen: Implemented SE_ShieldEquipDmgMod (Increase damage in primary hand if shield equiped)
Kayen: Implemented SE_ShieldEquipHateMod (Increase hate generated if shield equiped)
Kayen: Implemented SE_TriggerOnAmountValue (Trigger spell if HP/Mana/End bellow X value or num pet on target)
This commit is contained in:
KayenEQ
2013-12-17 21:51:13 -05:00
parent 8007097aae
commit bfb17a2fb5
13 changed files with 216 additions and 21 deletions
+33 -9
View File
@@ -444,19 +444,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
RollTable[1] = RollTable[0];
}
if(damage > 0 && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
&& (!other->BehindMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
/*
bool equiped = CastToClient()->m_inv.GetItem(14);
if(equiped) {
uint8 shield = CastToClient()->m_inv.GetItem(14)->GetItem()->ItemType;
float bonusShieldBlock = 0.0f;
if(shield == ItemTypeShield) {
//Live AA - Shield Block
bonusShieldBlock = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock;
RollTable[1] += bonusShieldBlock;
}
}
*/
float bonusShieldBlock = 0.0f;
bonusShieldBlock = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock;
RollTable[1] += bonusShieldBlock;
}
if(damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock)
@@ -1141,7 +1142,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
}
else{
weapon = GetInv().GetItem(SLOT_PRIMARY);
OffHandAtk(false);
OffHandAtk(false);
}
if(weapon != nullptr) {
@@ -2432,6 +2433,12 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
if(other){
AddRampage(other);
int hatemod = 100 + other->spellbonuses.hatemod + other->itembonuses.hatemod + other->aabonuses.hatemod;
int16 shieldhatemod = other->spellbonuses.ShieldEquipHateMod + other->itembonuses.ShieldEquipHateMod + other->aabonuses.ShieldEquipHateMod;
if (shieldhatemod && other->HasShieldEquiped())
hatemod += shieldhatemod;
if(hatemod < 1)
hatemod = 1;
hate = ((hate * (hatemod))/100);
@@ -2446,6 +2453,9 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
return;
}
if (other->IsNPC() && (other->IsPet() || other->CastToNPC()->GetSwarmOwner() > 0))
TryTriggerOnValueAmount(false, false, false, true);
if(IsClient() && !IsAIControlled())
return;
@@ -3223,6 +3233,7 @@ int32 Mob::ReduceDamage(int32 damage)
if(GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100) {
damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100);
SetMana(GetMana() - damage);
TryTriggerOnValueAmount(false, true);
CheckHitsRemaining(slot);
}
}
@@ -3298,6 +3309,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
if(GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100) {
damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100);
SetMana(GetMana() - damage);
TryTriggerOnValueAmount(false, true);
CheckHitsRemaining(slot);
}
}
@@ -3374,6 +3386,16 @@ bool Client::CheckDoubleAttack(bool tripleAttack) {
return false;
}
bool Client::CheckArcheryDoubleAttack() {
int16 chance = spellbonuses.ArcheryDoubleAttack + itembonuses.ArcheryDoubleAttack + aabonuses.ArcheryDoubleAttack;
if(chance && (MakeRandomInt(0, 100) < chance))
return true;
return false;
}
void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, const SkillUseTypes skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic) {
// This method is called with skill_used=ABJURE for Damage Shield damage.
bool FromDamageShield = (skill_used == SkillAbjuration);
@@ -3481,7 +3503,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
ReduceAllDamage(damage);
SetHP(GetHP() - damage);
if(HasDied()) {
bool IsSaved = false;
@@ -3501,6 +3523,8 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
TryDeathSave();
}
TryTriggerOnValueAmount(true);
//fade mez if we are mezzed
if (IsMezzed()) {
mlog(COMBAT__HITS, "Breaking mez due to attack.");
+51
View File
@@ -135,6 +135,7 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
// Clear item faction mods
ClearItemFactionBonuses();
ShieldEquiped(false);
unsigned int i;
//should not include 21 (SLOT_AMMO)
@@ -143,6 +144,10 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
if(inst == 0)
continue;
AddItemBonuses(inst, newbon);
//Check if item is secondary slot is a 'shield'. Required for multiple spelll effects.
if (i == 14 && (m_inv.GetItem(14)->GetItem()->ItemType == ItemTypeShield))
ShieldEquiped(true);
}
//Power Source Slot
@@ -846,6 +851,9 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_ArcheryDamageModifier:
newbon->ArcheryDamageModifier += base1;
break;
case SE_ArcheryDoubleAttack:
newbon->ArcheryDoubleAttack += base1;
break;
case SE_DamageShield:
newbon->DamageShield += base1;
break;
@@ -905,6 +913,13 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
case SE_ShieldBlock:
newbon->ShieldBlock += base1;
break;
case SE_ShieldEquipHateMod:
newbon->ShieldEquipHateMod += base1;
break;
case SE_ShieldEquipDmgMod:
newbon->ShieldEquipDmgMod[0] += base1;
newbon->ShieldEquipDmgMod[1] += base2;
break;
case SE_SecondaryDmgInc:
newbon->SecondaryDmgInc = true;
break;
@@ -2196,6 +2211,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
case SE_ShieldBlock:
newbon->ShieldBlock += effect_value;
break;
case SE_ShieldEquipHateMod:
newbon->ShieldEquipHateMod += effect_value;
break;
case SE_ShieldEquipDmgMod:
newbon->ShieldEquipDmgMod[0] += effect_value;
newbon->ShieldEquipDmgMod[1] += spells[spell_id].base2[i];
break;
case SE_BlockBehind:
newbon->BlockBehind += effect_value;
@@ -2258,6 +2282,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
newbon->ArcheryDamageModifier += effect_value;
break;
case SE_ArcheryDoubleAttack:
newbon->ArcheryDoubleAttack += effect_value;
break;
case SE_SecondaryDmgInc:
newbon->SecondaryDmgInc = true;
break;
@@ -2391,6 +2419,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
break;
}
case SE_TriggerOnValueAmount:
newbon->TriggerOnValueAmount = true;
break;
}
}
@@ -3659,7 +3690,27 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.SlayUndead[0] = effect_value;
aabonuses.SlayUndead[1] = effect_value;
break;
case SE_ArcheryDoubleAttack:
spellbonuses.ArcheryDoubleAttack = effect_value;
aabonuses.ArcheryDoubleAttack = effect_value;
itembonuses.ArcheryDoubleAttack = effect_value;
break;
case SE_ShieldEquipHateMod:
spellbonuses.ShieldEquipHateMod = effect_value;
aabonuses.ShieldEquipHateMod = effect_value;
itembonuses.ShieldEquipHateMod = effect_value;
break;
case SE_ShieldEquipDmgMod:
spellbonuses.ShieldEquipDmgMod[0] = effect_value;
spellbonuses.ShieldEquipDmgMod[1] = effect_value;
aabonuses.ShieldEquipDmgMod[0] = effect_value;
aabonuses.ShieldEquipDmgMod[1] = effect_value;
itembonuses.ShieldEquipDmgMod[0] = effect_value;
itembonuses.ShieldEquipDmgMod[1] = effect_value;
break;
}
}
}
+2 -1
View File
@@ -819,6 +819,7 @@ public:
void LinkDead();
void Insight(uint32 t_id);
bool CheckDoubleAttack(bool tripleAttack = false);
bool CheckArcheryDoubleAttack();
//remove charges/multiple objects from inventory:
//bool DecreaseByType(uint32 type, uint8 amt);
@@ -828,7 +829,7 @@ public:
void RemoveNoRent(bool client_update = true);
void RemoveDuplicateLore(bool client_update = true);
void MoveSlotNotAllowed(bool client_update = true);
virtual void RangedAttack(Mob* other);
virtual void RangedAttack(Mob* other, bool CanDoubleAttack = false);
virtual void ThrowingAttack(Mob* other);
void DoClassAttacks(Mob *ca_target, uint16 skill = -1, bool IsRiposte=false);
+5 -1
View File
@@ -303,6 +303,8 @@ bool Client::Process() {
if(CheckLosFN(GetTarget())){
//client has built in los check, but auto fire does not.. done last.
RangedAttack(GetTarget());
if (CheckArcheryDoubleAttack())
RangedAttack(GetTarget(), true);
}
else
ranged_timer.Start();
@@ -1931,8 +1933,10 @@ void Client::DoEnduranceUpkeep() {
}
}
if(upkeep_sum != 0)
if(upkeep_sum != 0){
SetEndurance(GetEndurance() - upkeep_sum);
TryTriggerOnValueAmount(false, false, true);
}
}
void Client::CalcRestState() {
+4
View File
@@ -250,6 +250,7 @@ struct StatBonuses {
int16 DualWieldChance; //i
int16 DoubleAttackChance; //i
int16 TripleAttackChance; //i
int16 ArcheryDoubleAttack; //i
int16 ResistSpellChance; //i
int16 ResistFearChance; //i
bool Fearless; //i
@@ -359,6 +360,9 @@ struct StatBonuses {
int16 ItemATKCap; // Raise item attack cap
int32 FinishingBlow[2]; // Chance to do a finishing blow for specified damage amount.
uint16 FinishingBlowLvl[2]; // Sets max level an NPC can be affected by FB. (base1 = lv, base2= ???)
int16 ShieldEquipHateMod; // Hate mod when shield equiped.
int16 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown
bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect.
};
typedef struct
+1
View File
@@ -612,6 +612,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
if(GetEndurance() > spell.EndurCost) {
SetEndurance(GetEndurance() - spell.EndurCost);
TryTriggerOnValueAmount(false, false, true);
} else {
Message(11, "You are too fatigued to use this skill right now.");
return(false);
+78
View File
@@ -177,6 +177,7 @@ Mob::Mob(const char* in_name,
slow_mitigation= 0;
findable = false;
trackable = true;
has_shieldequiped = false;
if(in_aa_title>0)
aa_title = in_aa_title;
@@ -3223,6 +3224,80 @@ void Mob::TryApplyEffect(Mob *target, uint32 spell_id)
}
}
}
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
{
/*
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)
*/
if (!spellbonuses.TriggerOnValueAmount)
return;
if (spellbonuses.TriggerOnValueAmount){
int buff_count = GetMaxTotalSlots();
for(int e = 0; e < buff_count; e++){
uint32 spell_id = buffs[e].spellid;
if (IsValidSpell(spell_id)){
for(int i = 0; i < EFFECT_COUNT; i++){
if (spells[spell_id].effectid[i] == SE_TriggerOnValueAmount){
int base2 = spells[spell_id].base2[i];
bool use_spell = false;
if (IsHP){
if ((base2 >= 500 && base2 <= 520) && GetHPRatio() < (base2 - 500)*5){
use_spell = true;
}
}
else if (IsMana){
if ( (base2 = 521 && GetManaRatio() < 20) || (base2 = 523 && GetManaRatio() < 40)) {
use_spell = true;
}
}
else if (IsEndur){
if (base2 = 522 && GetEndurancePercent() < 40){
use_spell = true;
}
}
else if (IsPet){
int count = hate_list.SummonedPetCount(this);
if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){
use_spell = true;
}
}
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);
}
}
}
}
}
}
}
//Twincast Focus effects should stack across different types (Spell, AA - when implemented ect)
void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
{
@@ -4200,6 +4275,9 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill)
dmg_mod += itembonuses.DamageModifier[HIGHEST_SKILL+1] + spellbonuses.DamageModifier[HIGHEST_SKILL+1] + aabonuses.DamageModifier[HIGHEST_SKILL+1] +
itembonuses.DamageModifier[skill] + spellbonuses.DamageModifier[skill] + aabonuses.DamageModifier[skill];
if (HasShieldEquiped() && !IsOffHandAtk())
dmg_mod += itembonuses.ShieldEquipDmgMod[0] + spellbonuses.ShieldEquipDmgMod[0] + aabonuses.ShieldEquipDmgMod[0];
if(dmg_mod < -100)
dmg_mod = -100;
+4
View File
@@ -259,6 +259,8 @@ public:
void TempName(const char *newname = nullptr);
void SetTargetable(bool on);
bool IsTargetable() const { return m_targetable; }
bool HasShieldEquiped() const { return has_shieldequiped; }
inline void ShieldEquiped(bool val) { has_shieldequiped = val; }
virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; }
virtual uint32 GetEquipment(uint8 material_slot) const { return(0); }
virtual int32 GetEquipmentMaterial(uint8 material_slot) const;
@@ -531,6 +533,7 @@ public:
void TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger);
void TrySpellTrigger(Mob *target, uint32 spell_id);
void TryApplyEffect(Mob *target, uint32 spell_id);
void TryTriggerOnValueAmount(bool IsHP = false, bool IsMana = false, bool IsEndur = false, bool IsPet = false);
void TryTwincast(Mob *caster, Mob *target, uint32 spell_id);
void TrySympatheticProc(Mob *target, uint32 spell_id);
bool TryFadeEffect(int slot);
@@ -1044,6 +1047,7 @@ protected:
uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids
int16 rooted_mod; //Modifier to root break chance, defined when root is cast on a target.
bool offhand;
bool has_shieldequiped;
// Bind wound
Timer bindwound_timer;
+5 -2
View File
@@ -203,6 +203,9 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
if (ca_atk->m_skill == SkillArchery) {
SetAttackTimer();
RangedAttack(GetTarget());
bool test = CheckArcheryDoubleAttack();
if (CheckArcheryDoubleAttack())
RangedAttack(GetTarget(), true);
return;
}
//could we return here? Im not sure is m_atk 11 is used for real specials
@@ -682,12 +685,12 @@ void Mob::RogueAssassinate(Mob* other)
DoAnim(animPiercing); //piercing animation
}
void Client::RangedAttack(Mob* other) {
void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
//conditions to use an attack checked before we are called
//make sure the attack and ranged timers are up
//if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow
if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())) {
if(!CanDoubleAttack && ((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) {
mlog(COMBAT__RANGED, "Throwing attack canceled. Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
// The server and client timers are not exact matches currently, so this would spam too often if enabled
//Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
+20 -3
View File
@@ -180,6 +180,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (caster && caster->IsClient())
numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id);
buffs[buffslot].numhits = numhit;
}
@@ -467,6 +468,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
#endif
SetMana(GetMana() + effect_value);
caster->SetMana(caster->GetMana() + abs(effect_value));
if (effect_value < 0)
TryTriggerOnValueAmount(false, true);
#ifdef SPELL_EFFECT_SPAM
caster->Message(0, "You have gained %+i mana!", effect_value);
#endif
@@ -480,6 +484,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break;
SetMana(GetMana() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, true);
}
break;
@@ -2366,6 +2372,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
#endif
if(IsClient()) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, false, true);
}
break;
}
@@ -2378,6 +2386,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if(IsClient()) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + effect_value);
if (effect_value < 0)
TryTriggerOnValueAmount(false, false, true);
}
break;
}
@@ -2549,7 +2559,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
int mana_damage = 0;
int32 mana_to_use = GetMana() - spell.base[i];
if(mana_to_use > -1) {
SetMana(GetMana() - spell.base[i]);
SetMana(GetMana() - spell.base[i]);
TryTriggerOnValueAmount(false, true);
// we take full dmg(-10 to make the damage the right sign)
mana_damage = spell.base[i] / -10 * spell.base2[i];
Damage(caster, mana_damage, spell_id, spell.skill, false, i, true);
@@ -2569,6 +2580,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
int32 end_to_use = CastToClient()->GetEndurance() - spell.base[i];
if(end_to_use > -1) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - spell.base[i]);
TryTriggerOnValueAmount(false, false, true);
// we take full dmg(-10 to make the damage the right sign)
end_damage = spell.base[i] / -10 * spell.base2[i];
Damage(caster, end_damage, spell_id, spell.skill, false, i, true);
@@ -2650,6 +2662,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
else {
dmg = ratio*max_mana/10;
caster->SetMana(caster->GetMana() - max_mana);
TryTriggerOnValueAmount(false, true);
}
if(IsDetrimentalSpell(spell_id)) {
@@ -2896,6 +2909,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_CastonFocusEffect:
case SE_ReduceHeal:
case SE_IncreaseHitDmgTaken:
case SE_ArcheryDoubleAttack:
case SE_ShieldEquipHateMod:
case SE_ShieldEquipDmgMod:
case SE_TriggerOnValueAmount:
{
break;
}
@@ -3772,7 +3789,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
SetBodyType(GetOrigBodyType(), false);
break;
}
case SE_MovementSpeed:
{
if(IsClient())
@@ -5206,7 +5223,7 @@ bool Mob::CheckHitsRemaining(uint32 buff_slot, bool when_spell_done, bool negate
}
return false;
}
// For spell buffs that are limited by the number of times it can successfully trigger a spell.
// Effects: SE_TriggerOnCast, SE_SympatheticProc,SE_DefensiveProc, SE_SkillProc, SE_RangedProc
if(spell_id){
+2
View File
@@ -235,6 +235,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
// fizzle 1/4 the mana away
SetMana(GetMana() - use_mana);
TryTriggerOnValueAmount(false, true);
return(false);
}
@@ -2069,6 +2070,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
mlog(SPELLS__CASTING, "Spell %d: consuming %d mana", spell_id, mana_used);
if (!DoHPToManaCovert(mana_used))
SetMana(GetMana() - mana_used);
TryTriggerOnValueAmount(false, true);
}
//set our reuse timer on long ass reuse_time spells...