mirror of
https://github.com/EQEmu/Server.git
synced 2026-01-04 07:23:57 +00:00
Merge pull request #164 from KayenEQ/Development
Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant...
This commit is contained in:
commit
bd86e70766
@ -1,5 +1,30 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
|
||||
== 06/25/2014 ==
|
||||
Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells.
|
||||
Kayen: Updated SE_FadingMemories - Base value will be properly utilized to set % chance for fade effect to work.
|
||||
Kayen: Implemented SE_StrikeThough (Was incorrectly defined as implemented previously) - Works same as item bonus.
|
||||
Kayen: Update SE_Taunt - Limit value if present will now add instant hate.
|
||||
Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this)
|
||||
Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA now uses this)
|
||||
Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This will not result in any change to currently used spells).
|
||||
Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost.
|
||||
Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet.
|
||||
Kayen: Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements.
|
||||
Revised HeadShot mechanic so damage now receives all archery bonuses, proc chance can be set to either (lives new Proc Per minute
|
||||
system, or flat chance based on dex (formula updated).
|
||||
Kayen: Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements.
|
||||
Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute
|
||||
system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments.
|
||||
Kayen: Fix to AA Finishing Blow missing aa_effects data, update required SQL.
|
||||
Revised Finishing blow so that damage now receives all melee bonus. Support also for this effect if placed on items or spells.
|
||||
Kayen: Implemented SE_PetMeleeMitigation - Bonus applied to pet owner. Gives AC to owner's pet.
|
||||
|
||||
Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql
|
||||
Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql
|
||||
|
||||
|
||||
== 06/17/2014 ==
|
||||
Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker.
|
||||
These effects when present in buffs prevent each other from stacking,
|
||||
|
||||
@ -333,6 +333,8 @@ RULE_REAL ( Combat, AvgProcsPerMinute, 2.0)
|
||||
RULE_REAL ( Combat, ProcPerMinDexContrib, 0.075)
|
||||
RULE_REAL ( Combat, BaseProcChance, 0.035)
|
||||
RULE_REAL ( Combat, ProcDexDivideBy, 11000)
|
||||
RULE_BOOL ( Combat, AdjustSpecialProcPerMinute, true) //Set PPM for special abilities like HeadShot (Live does this as of 4-14)
|
||||
RULE_REAL ( Combat, AvgSpecialProcsPerMinute, 2.0) //Unclear what best value is atm.
|
||||
RULE_REAL ( Combat, BaseHitChance, 69.0)
|
||||
RULE_REAL ( Combat, NPCBonusHitChance, 26.0)
|
||||
RULE_REAL ( Combat, HitFalloffMinor, 5.0) //hit will fall off up to 5% over the initial level range
|
||||
|
||||
@ -237,7 +237,7 @@ typedef enum {
|
||||
#define SE_MagnifyVision 87 // implemented - Telescope
|
||||
#define SE_Succor 88 // implemented - Evacuate/Succor lines
|
||||
#define SE_ModelSize 89 // implemented - Shrink, Growth
|
||||
#define SE_Cloak 90 // *not implemented - Used in only 2 spells
|
||||
//#define SE_Cloak 90 // *not implemented - Used in only 2 spells
|
||||
#define SE_SummonCorpse 91 // implemented
|
||||
#define SE_InstantHate 92 // implemented - add hate
|
||||
#define SE_StopRain 93 // implemented - Wake of Karana
|
||||
@ -339,32 +339,32 @@ typedef enum {
|
||||
#define SE_CurrentEndurance 189 // implemented
|
||||
#define SE_EndurancePool 190 // implemented
|
||||
#define SE_Amnesia 191 // implemented - Silence vs Melee Effect
|
||||
#define SE_Hate2 192 // implemented
|
||||
#define SE_Hate 192 // implemented - Instant and hate over time.
|
||||
#define SE_SkillAttack 193 // implemented
|
||||
#define SE_FadingMemories 194 // implemented
|
||||
#define SE_StunResist 195 // implemented
|
||||
#define SE_Strikethrough 196 // implemented
|
||||
#define SE_StrikeThrough 196 // implemented
|
||||
#define SE_SkillDamageTaken 197 // implemented
|
||||
#define SE_CurrentEnduranceOnce 198 // implemented
|
||||
#define SE_Taunt 199 // implemented - % chance to taunt the target
|
||||
#define SE_ProcChance 200 // implemented
|
||||
#define SE_RangedProc 201 // implemented
|
||||
//#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion)
|
||||
//#define SE_MassGroupBuff 203 // *not implemented as bonus
|
||||
#define SE_GroupFearImmunity 204 // *not implemented as bonus
|
||||
#define SE_IllusionOther 202 // implemented - Project Illusion
|
||||
#define SE_MassGroupBuff 203 // implemented
|
||||
#define SE_GroupFearImmunity 204 // implemented - (Does not use bonus)
|
||||
#define SE_Rampage 205 // implemented
|
||||
#define SE_AETaunt 206 // implemented
|
||||
#define SE_FleshToBone 207 // implemented
|
||||
//#define SE_PurgePoison 208 // not used
|
||||
#define SE_DispelBeneficial 209 // implemented
|
||||
//#define SE_PetShield 210 // *not implemented
|
||||
#define SE_AEMelee 211 // implemented
|
||||
#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm).
|
||||
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
|
||||
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
|
||||
#define SE_MaxHPChange 214 // implemented
|
||||
#define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage
|
||||
#define SE_Accuracy 216 // implemented
|
||||
//#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage)
|
||||
#define SE_HeadShot 217 // implemented - ability to head shot (base2 = damage)
|
||||
#define SE_PetCriticalHit 218 // implemented[AA] - gives pets a baseline critical hit chance
|
||||
#define SE_SlayUndead 219 // implemented - Allow extra damage against undead (base1 = rate, base2 = damage mod).
|
||||
#define SE_SkillDamageAmount 220 // implemented
|
||||
@ -375,7 +375,7 @@ typedef enum {
|
||||
#define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance.
|
||||
#define SE_TwoHandBash 226 // *not implemented as bonus
|
||||
#define SE_ReduceSkillTimer 227 // implemented
|
||||
#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling
|
||||
//#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling
|
||||
#define SE_PersistantCasting 229 // implemented
|
||||
//#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability
|
||||
#define SE_StunBashChance 231 // implemented - increase chance to stun from bash.
|
||||
@ -388,7 +388,7 @@ typedef enum {
|
||||
//#define SE_IllusionPersistence 238 // *not implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed.
|
||||
//#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you.
|
||||
//#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.]
|
||||
#define SE_ImprovedReclaimEnergy 241 // not implemented as bonus - increase the amount of mana returned to you when reclaiming your pet.
|
||||
#define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet.
|
||||
#define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr
|
||||
#define SE_CharmBreakChance 243 // implemented - Total Domination
|
||||
#define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break.
|
||||
@ -410,7 +410,7 @@ typedef enum {
|
||||
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
|
||||
#define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live)
|
||||
#define SE_RaiseStatCap 262 // implemented
|
||||
#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master.
|
||||
//#define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master.
|
||||
//#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect
|
||||
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
|
||||
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
|
||||
@ -492,8 +492,8 @@ typedef enum {
|
||||
#define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing
|
||||
#define SE_InterruptCasting 343 // implemented - % chance to interrupt spells being cast every tic. Cacophony (8272)
|
||||
#define SE_ChannelChanceItems 344 // implemented[AA] - chance to not have ITEM effects interrupted when you take damage.
|
||||
//#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill
|
||||
//#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill
|
||||
#define SE_AssassinateLevel 345 // implemented as bonus - AA Assisination max level to kill
|
||||
#define SE_HeadShotLevel 346 // implemented[AA] - HeadShot max level to kill
|
||||
#define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow)
|
||||
#define SE_LimitManaMin 348 // implemented
|
||||
#define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield.
|
||||
@ -506,13 +506,13 @@ typedef enum {
|
||||
//#define SE_ChangeTriggerType 356 // not used
|
||||
#define SE_FcMute 357 // implemented - silences casting of spells that contain specific spell effects (focus limited)
|
||||
#define SE_CurrentManaOnce 358 // implemented
|
||||
#define SE_Invulnerabilty 359 // *not implemented - Invulnerability (Brell's Blessing)
|
||||
#define SE_SpellOnKill 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level
|
||||
//#define SE_PassiveSenseTrap 359 // *not implemented - Invulnerability (Brell's Blessing)
|
||||
#define SE_ProcOnKillShot 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level
|
||||
#define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed
|
||||
//#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank.
|
||||
//#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank.
|
||||
#define SE_TripleAttackChance 364 // implemented
|
||||
#define SE_SpellOnKill2 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin)
|
||||
#define SE_ProcOnSpellKillShot 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin)
|
||||
#define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA
|
||||
#define SE_SetBodyType 367 // implemented - set body type of base1 so it can be affected by spells that are limited to that type (Plant, Animal, Undead, etc)
|
||||
//#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2
|
||||
@ -544,7 +544,7 @@ typedef enum {
|
||||
#define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions.
|
||||
#define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited]
|
||||
#define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells
|
||||
//#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets.
|
||||
#define SE_PetMeleeMitigation 397 // implemented[AA] - additional mitigation to your pets. Adds AC.
|
||||
#define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets
|
||||
#define SE_FcTwincast 399 // implemented - cast 2 spells for every 1
|
||||
#define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained
|
||||
@ -586,7 +586,7 @@ typedef enum {
|
||||
//#define SE_BeneficialCountDownHold 436 // not used ( 23491 | ABTest Buff Hold)
|
||||
//#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099)
|
||||
//#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750)
|
||||
//#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination
|
||||
#define SE_Assassinate 439 // implemented[AA] - Assassinate damage
|
||||
#define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC
|
||||
#define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit.
|
||||
#define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist)
|
||||
|
||||
2
utils/sql/git/optional/2014_06_29_HeadShotRules.sql
Normal file
2
utils/sql/git/optional/2014_06_29_HeadShotRules.sql
Normal file
@ -0,0 +1,2 @@
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AdjustSpecialProcPerMinute', 'false', 'Allow PPM for special abilities HeadShot, Assassinate, Decap ect.');
|
||||
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AvgSpecialProcsPerMinute', '2.0', 'Set PPM for special abilities HeadShot, Assassinate, Decap ect. (Unknown what value live uses) .');
|
||||
34
utils/sql/git/required/2014_06_25_AA_Updates..sql
Normal file
34
utils/sql/git/required/2014_06_25_AA_Updates..sql
Normal file
@ -0,0 +1,34 @@
|
||||
-- AA MGB update
|
||||
UPDATE altadv_vars SET spellid = 5228 WHERE skill_id = 128;
|
||||
UPDATE aa_actions SET spell_id = 5228, nonspell_action = 0 WHERE aaid = 128;
|
||||
|
||||
-- AA Project Illusion update
|
||||
UPDATE altadv_vars SET spellid = 5227 WHERE skill_id = 643;
|
||||
UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643;
|
||||
|
||||
-- AA Improved Reclaim Energy
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('180', '1', '241', '95', '0');
|
||||
|
||||
-- AA Headshot
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0');
|
||||
|
||||
-- AA Anatomy (Rogue Assassinate)
|
||||
INSERT INTO `altadv_vars` (`skill_id`, `name`, `cost`, `max_level`, `hotkey_sid`, `hotkey_sid2`, `title_sid`, `desc_sid`, `type`, `spellid`, `prereq_skill`, `prereq_minpoints`, `spell_type`, `spell_refresh`, `classes`, `berserker`, `class_type`, `cost_inc`, `aa_expansion`, `special_category`, `sof_type`, `sof_cost_inc`, `sof_max_level`, `sof_next_skill`, `clientver`, `account_time_required`, `sof_current_level`,`sof_next_id`,`level_inc`) VALUES ('1604', 'Anatomy', '5', '3', '4294967295', '4294967295', '1604', '1604', '1', '4294967295', '0', '0', '0', '0', '512', '0', '60', '1', '10', '4294967295', '3', '0', '3', '1604', '1', '0', '0', '0', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '1', '439', '0', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '2', '345', '48', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0');
|
||||
|
||||
-- AA Finishing Blow Fix
|
||||
DELETE FROM aa_effects WHERE aaid = 199 AND slot = 2;
|
||||
DELETE FROM aa_effects WHERE aaid = 200 AND slot = 2;
|
||||
DELETE FROM aa_effects WHERE aaid = 201 AND slot = 2;
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '1', '278', '500', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '2', '440', '50', '200');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '1', '278', '500', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '2', '440', '52', '200');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '1', '278', '500', '32000');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '2', '440', '54', '200');
|
||||
11
zone/AA.cpp
11
zone/AA.cpp
@ -352,11 +352,6 @@ void Client::HandleAAAction(aaID activate) {
|
||||
entity_list.AETaunt(this);
|
||||
break;
|
||||
|
||||
case aaActionMassBuff:
|
||||
EnableAAEffect(aaEffectMassGroupBuff, 3600);
|
||||
Message_StringID(MT_Disciplines, MGB_STRING); //The next group buff you cast will hit all targets in range.
|
||||
break;
|
||||
|
||||
case aaActionFlamingArrows:
|
||||
//toggle it
|
||||
if(CheckAAEffect(aaEffectFlamingArrows))
|
||||
@ -459,12 +454,6 @@ void Client::HandleAAAction(aaID activate) {
|
||||
}
|
||||
break;
|
||||
|
||||
case aaActionProjectIllusion:
|
||||
EnableAAEffect(aaEffectProjectIllusion, 3600);
|
||||
Message(10, "The power of your next illusion spell will flow to your grouped target in your place.");
|
||||
break;
|
||||
|
||||
|
||||
case aaActionEscape:
|
||||
Escape();
|
||||
break;
|
||||
|
||||
@ -43,14 +43,14 @@ typedef enum {
|
||||
//use these for AAs which dont cast spells, yet need effects
|
||||
//if this list grows beyond 32, more work is needed in *AAEffect
|
||||
typedef enum { //AA Effect IDs
|
||||
aaEffectMassGroupBuff = 1,
|
||||
aaEffectMassGroupBuff = 1, //unused - Handled via spell effect.
|
||||
aaEffectRampage,
|
||||
aaEffectSharedHealth,
|
||||
aaEffectFlamingArrows,
|
||||
aaEffectFrostArrows,
|
||||
aaEffectWarcry,
|
||||
aaEffectLeechTouch,
|
||||
aaEffectProjectIllusion // seveian 2008-09-23
|
||||
aaEffectProjectIllusion // unused - Handled via spell effect
|
||||
} aaEffectType;
|
||||
|
||||
|
||||
|
||||
@ -560,11 +560,21 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac
|
||||
weight = (CastToClient()->CalcCurrentWeight() / 10.0);
|
||||
} else if (IsNPC()) {
|
||||
armor = CastToNPC()->GetRawAC();
|
||||
int PetACBonus = 0;
|
||||
|
||||
if (!IsPet())
|
||||
armor = (armor / RuleR(Combat, NPCACFactor));
|
||||
else{
|
||||
Mob *owner = nullptr;
|
||||
owner = GetOwner();
|
||||
if (owner){
|
||||
PetACBonus = owner->aabonuses.PetMeleeMitigation
|
||||
+ owner->itembonuses.PetMeleeMitigation +
|
||||
owner->spellbonuses.PetMeleeMitigation;
|
||||
}
|
||||
}
|
||||
|
||||
armor += spellbonuses.AC + itembonuses.AC + 1;
|
||||
armor += spellbonuses.AC + itembonuses.AC + PetACBonus + 1;
|
||||
}
|
||||
|
||||
if (opts) {
|
||||
@ -4443,27 +4453,25 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
|
||||
|
||||
bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse)
|
||||
{
|
||||
if (defender && !defender->IsClient() && defender->GetHPRatio() < 10){
|
||||
|
||||
if (!defender)
|
||||
return false;
|
||||
uint32 FB_Dmg = aabonuses.FinishingBlow[1] + spellbonuses.FinishingBlow[1] + itembonuses.FinishingBlow[1];
|
||||
|
||||
uint16 FB_Level = 0;
|
||||
FB_Level = aabonuses.FinishingBlowLvl[0];
|
||||
if (FB_Level < spellbonuses.FinishingBlowLvl[0])
|
||||
FB_Level = spellbonuses.FinishingBlowLvl[0];
|
||||
else if (FB_Level < itembonuses.FinishingBlowLvl[0])
|
||||
FB_Level = itembonuses.FinishingBlowLvl[0];
|
||||
|
||||
if (aabonuses.FinishingBlow[1] && !defender->IsClient() && defender->GetHPRatio() < 10){
|
||||
//Proc Chance value of 500 = 5%
|
||||
uint32 ProcChance = (aabonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0])/10;
|
||||
|
||||
uint32 chance = aabonuses.FinishingBlow[0]/10; //500 = 5% chance.
|
||||
uint32 damage = aabonuses.FinishingBlow[1];
|
||||
uint16 levelreq = aabonuses.FinishingBlowLvl[0];
|
||||
|
||||
if(defender->GetLevel() <= levelreq && (chance >= MakeRandomInt(0, 1000))){
|
||||
mlog(COMBAT__ATTACKS, "Landed a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel());
|
||||
if(FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) && (ProcChance >= MakeRandomInt(0, 1000))){
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName());
|
||||
defender->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
||||
DoSpecialAttackDamage(defender, skillinuse, FB_Dmg, 1, -1, 10, false, false);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mlog(COMBAT__ATTACKS, "FAILED a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
204
zone/bonuses.cpp
204
zone/bonuses.cpp
@ -637,7 +637,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
continue;
|
||||
|
||||
_log(AA__BONUSES, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
|
||||
|
||||
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
@ -953,6 +953,8 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_BlockBehind:
|
||||
newbon->BlockBehind += base1;
|
||||
break;
|
||||
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
newbon->StrikeThrough += base1;
|
||||
break;
|
||||
@ -987,7 +989,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->CrippBlowChance += base1;
|
||||
break;
|
||||
|
||||
case SE_SpellOnKill:
|
||||
case SE_ProcOnKillShot:
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3)
|
||||
{
|
||||
if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1)))
|
||||
@ -1202,7 +1204,6 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_FinishingBlow:
|
||||
{
|
||||
|
||||
//base1 = chance, base2 = damage
|
||||
if (newbon->FinishingBlow[1] < base2){
|
||||
newbon->FinishingBlow[0] = base1;
|
||||
@ -1268,6 +1269,52 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->Metabolism += base1;
|
||||
break;
|
||||
|
||||
case SE_ImprovedReclaimEnergy:
|
||||
{
|
||||
if((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1))
|
||||
newbon->ImprovedReclaimEnergy = base1;
|
||||
|
||||
else if(newbon->ImprovedReclaimEnergy < base1)
|
||||
newbon->ImprovedReclaimEnergy = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShot:
|
||||
{
|
||||
if(newbon->HeadShot[1] < base2){
|
||||
newbon->HeadShot[0] = base1;
|
||||
newbon->HeadShot[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShotLevel:
|
||||
{
|
||||
if(newbon->HSLevel < base1)
|
||||
newbon->HSLevel = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Assassinate:
|
||||
{
|
||||
if(newbon->Assassinate[1] < base2){
|
||||
newbon->Assassinate[0] = base1;
|
||||
newbon->Assassinate[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_AssassinateLevel:
|
||||
{
|
||||
if(newbon->AssassinateLevel < base1)
|
||||
newbon->AssassinateLevel = base1;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_PetMeleeMitigation:
|
||||
newbon->PetMeleeMitigation += base1;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2132,7 +2179,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->CriticalDoTChance += effect_value;
|
||||
break;
|
||||
|
||||
case SE_SpellOnKill:
|
||||
case SE_ProcOnKillShot:
|
||||
{
|
||||
for(int e = 0; e < MAX_SPELL_TRIGGER*3; e+=3)
|
||||
{
|
||||
@ -2469,6 +2516,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->SecondaryDmgInc = true;
|
||||
break;
|
||||
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
newbon->StrikeThrough += effect_value;
|
||||
break;
|
||||
@ -2714,19 +2762,23 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
break;
|
||||
|
||||
case SE_AStacker:
|
||||
newbon->AStacker = true;
|
||||
newbon->AStacker[0] = 1;
|
||||
newbon->AStacker[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_BStacker:
|
||||
newbon->BStacker = true;
|
||||
newbon->BStacker[0] = 1;
|
||||
newbon->BStacker[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_CStacker:
|
||||
newbon->CStacker = true;
|
||||
newbon->CStacker[0] = 1;
|
||||
newbon->CStacker[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_DStacker:
|
||||
newbon->DStacker = true;
|
||||
newbon->DStacker[0] = 1;
|
||||
newbon->DStacker[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_Berserk:
|
||||
@ -2738,6 +2790,72 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->Metabolism += effect_value;
|
||||
break;
|
||||
|
||||
case SE_ImprovedReclaimEnergy:
|
||||
{
|
||||
if((effect_value < 0) && (newbon->ImprovedReclaimEnergy > effect_value))
|
||||
newbon->ImprovedReclaimEnergy = effect_value;
|
||||
|
||||
else if(newbon->ImprovedReclaimEnergy < effect_value)
|
||||
newbon->ImprovedReclaimEnergy = effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShot:
|
||||
{
|
||||
if(newbon->HeadShot[1] < base2){
|
||||
newbon->HeadShot[0] = effect_value;
|
||||
newbon->HeadShot[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_HeadShotLevel:
|
||||
{
|
||||
if(newbon->HSLevel < effect_value)
|
||||
newbon->HSLevel = effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Assassinate:
|
||||
{
|
||||
if(newbon->Assassinate[1] < base2){
|
||||
newbon->Assassinate[0] = effect_value;
|
||||
newbon->Assassinate[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_AssassinateLevel:
|
||||
{
|
||||
if(newbon->AssassinateLevel < effect_value)
|
||||
newbon->AssassinateLevel = effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FinishingBlow:
|
||||
{
|
||||
//base1 = chance, base2 = damage
|
||||
if (newbon->FinishingBlow[1] < base2){
|
||||
newbon->FinishingBlow[0] = effect_value;
|
||||
newbon->FinishingBlow[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FinishingBlowLvl:
|
||||
{
|
||||
//base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?)
|
||||
if (newbon->FinishingBlowLvl[0] < effect_value){
|
||||
newbon->FinishingBlowLvl[0] = effect_value;
|
||||
newbon->FinishingBlowLvl[1] = base2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_PetMeleeMitigation:
|
||||
newbon->PetMeleeMitigation += effect_value;
|
||||
break;
|
||||
|
||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
@ -3671,7 +3789,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.CriticalDoTChance = effect_value;
|
||||
break;
|
||||
|
||||
case SE_SpellOnKill:
|
||||
case SE_ProcOnKillShot:
|
||||
{
|
||||
for(int e = 0; e < MAX_SPELL_TRIGGER*3; e=3)
|
||||
{
|
||||
@ -3909,6 +4027,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.SecondaryDmgInc = false;
|
||||
break;
|
||||
|
||||
case SE_StrikeThrough:
|
||||
spellbonuses.StrikeThrough = effect_value;
|
||||
aabonuses.StrikeThrough = effect_value;
|
||||
itembonuses.StrikeThrough = effect_value;
|
||||
break;
|
||||
|
||||
case SE_StrikeThrough2:
|
||||
spellbonuses.StrikeThrough = effect_value;
|
||||
aabonuses.StrikeThrough = effect_value;
|
||||
@ -3963,6 +4087,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.GivePetGroupTarget = false;
|
||||
break;
|
||||
|
||||
case SE_PetMeleeMitigation:
|
||||
spellbonuses.PetMeleeMitigation = effect_value;
|
||||
itembonuses.PetMeleeMitigation = effect_value;
|
||||
aabonuses.PetMeleeMitigation = effect_value;
|
||||
break;
|
||||
|
||||
case SE_RootBreakChance:
|
||||
spellbonuses.RootBreakChance = effect_value;
|
||||
aabonuses.RootBreakChance = effect_value;
|
||||
@ -4145,7 +4275,61 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.Metabolism = effect_value;
|
||||
itembonuses.Metabolism = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_ImprovedReclaimEnergy:
|
||||
spellbonuses.ImprovedReclaimEnergy = effect_value;
|
||||
aabonuses.ImprovedReclaimEnergy = effect_value;
|
||||
itembonuses.ImprovedReclaimEnergy = effect_value;
|
||||
break;
|
||||
|
||||
case SE_HeadShot:
|
||||
spellbonuses.HeadShot[0] = effect_value;
|
||||
aabonuses.HeadShot[0] = effect_value;
|
||||
itembonuses.HeadShot[0] = effect_value;
|
||||
spellbonuses.HeadShot[1] = effect_value;
|
||||
aabonuses.HeadShot[1] = effect_value;
|
||||
itembonuses.HeadShot[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_HeadShotLevel:
|
||||
spellbonuses.HSLevel = effect_value;
|
||||
aabonuses.HSLevel = effect_value;
|
||||
itembonuses.HSLevel = effect_value;
|
||||
break;
|
||||
|
||||
case SE_Assassinate:
|
||||
spellbonuses.Assassinate[0] = effect_value;
|
||||
aabonuses.Assassinate[0] = effect_value;
|
||||
itembonuses.Assassinate[0] = effect_value;
|
||||
spellbonuses.Assassinate[1] = effect_value;
|
||||
aabonuses.Assassinate[1] = effect_value;
|
||||
itembonuses.Assassinate[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_AssassinateLevel:
|
||||
spellbonuses.AssassinateLevel = effect_value;
|
||||
aabonuses.AssassinateLevel = effect_value;
|
||||
itembonuses.AssassinateLevel = effect_value;
|
||||
break;
|
||||
|
||||
case SE_FinishingBlow:
|
||||
spellbonuses.FinishingBlow[0] = effect_value;
|
||||
aabonuses.FinishingBlow[0] = effect_value;
|
||||
itembonuses.FinishingBlow[0] = effect_value;
|
||||
spellbonuses.FinishingBlow[1] = effect_value;
|
||||
aabonuses.FinishingBlow[1] = effect_value;
|
||||
itembonuses.FinishingBlow[1] = effect_value;
|
||||
break;
|
||||
|
||||
case SE_FinishingBlowLvl:
|
||||
spellbonuses.FinishingBlowLvl[0] = effect_value;
|
||||
aabonuses.FinishingBlowLvl[0] = effect_value;
|
||||
itembonuses.FinishingBlowLvl[0] = effect_value;
|
||||
spellbonuses.FinishingBlowLvl[1] = effect_value;
|
||||
aabonuses.FinishingBlowLvl[1] = effect_value;
|
||||
itembonuses.FinishingBlowLvl[1] = effect_value;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1900,7 +1900,7 @@ void Bot::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->UnfailingDivinity += base1;
|
||||
break;
|
||||
|
||||
case SE_SpellOnKill:
|
||||
case SE_ProcOnKillShot:
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3)
|
||||
{
|
||||
if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1)))
|
||||
|
||||
@ -1177,7 +1177,7 @@ uint32 Client::CalcCurrentWeight() {
|
||||
Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4;
|
||||
}
|
||||
|
||||
float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat;
|
||||
float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat;
|
||||
if (Packrat > 0)
|
||||
Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same %
|
||||
//without casting to float & back to uint32, this didn't work right
|
||||
@ -1864,7 +1864,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
break;
|
||||
}
|
||||
|
||||
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap;
|
||||
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
|
||||
|
||||
if (effectmod < 10)
|
||||
effectmod = 10;
|
||||
|
||||
@ -366,10 +366,10 @@ struct StatBonuses {
|
||||
bool NegateIfCombat; // Bool Drop buff if cast or melee
|
||||
int8 Screech; // -1 = Will be blocked if another Screech is +(1)
|
||||
int16 AlterNPCLevel; // amount of lvls +/-
|
||||
bool AStacker; // For buff stack blocking
|
||||
bool BStacker; // For buff stack blocking
|
||||
bool CStacker; // For buff stack blocking
|
||||
bool DStacker; // For buff stack blocking
|
||||
int16 AStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 BStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 CStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
int16 DStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value
|
||||
bool BerserkSPA; // berserk effect
|
||||
int16 Metabolism; // Food/drink consumption rates.
|
||||
|
||||
@ -422,6 +422,13 @@ struct StatBonuses {
|
||||
int8 StunBashChance; // chance to stun with bash.
|
||||
int8 IncreaseChanceMemwipe; // increases chance to memory wipe
|
||||
int8 CriticalMend; // chance critical monk mend
|
||||
int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
|
||||
uint32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg
|
||||
uint8 HSLevel; // Max Level Headshot will be effective at.
|
||||
uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg
|
||||
uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
|
||||
int32 PetMeleeMitigation; // Add AC to owner's pet.
|
||||
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
||||
@ -180,6 +180,8 @@ Mob::Mob(const char* in_name,
|
||||
trackable = true;
|
||||
has_shieldequiped = false;
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
|
||||
if(in_aa_title>0)
|
||||
aa_title = in_aa_title;
|
||||
@ -4137,9 +4139,9 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
||||
{
|
||||
if (spell_id != SPELL_UNKNOWN)
|
||||
{
|
||||
if(IsEffectInSpell(spell_id, SE_SpellOnKill2)) {
|
||||
if(IsEffectInSpell(spell_id, SE_ProcOnSpellKillShot)) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (spells[spell_id].effectid[i] == SE_SpellOnKill2)
|
||||
if (spells[spell_id].effectid[i] == SE_ProcOnSpellKillShot)
|
||||
{
|
||||
if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level)
|
||||
{
|
||||
|
||||
13
zone/mob.h
13
zone/mob.h
@ -141,7 +141,8 @@ public:
|
||||
virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr);
|
||||
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
|
||||
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
||||
virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse);
|
||||
uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse);
|
||||
uint32 TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime);
|
||||
virtual void DoRiposte(Mob* defender);
|
||||
void ApplyMeleeDamageBonus(uint16 skill, int32 &damage);
|
||||
virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr);
|
||||
@ -268,6 +269,10 @@ public:
|
||||
void CheckNumHitsRemaining(uint8 type, uint32 buff_slot=0, uint16 spell_id=SPELL_UNKNOWN);
|
||||
bool HasNumhits() const { return has_numhits; }
|
||||
inline void Numhits(bool val) { has_numhits = val; }
|
||||
bool HasMGB() const { return has_MGB; }
|
||||
inline void SetMGB(bool val) { has_MGB = val; }
|
||||
bool HasProjectIllusion() const { return has_ProjectIllusion ; }
|
||||
inline void SetProjectIllusion(bool val) { has_ProjectIllusion = val; }
|
||||
void SpreadVirus(uint16 spell_id, uint16 casterID);
|
||||
bool IsNimbusEffectActive(uint32 nimbus_effect);
|
||||
void SetNimbusEffect(uint32 nimbus_effect);
|
||||
@ -690,7 +695,7 @@ public:
|
||||
int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker);
|
||||
int32 ReduceAllDamage(int32 damage);
|
||||
|
||||
virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false);
|
||||
virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true);
|
||||
virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0);
|
||||
virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false);
|
||||
virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0);
|
||||
@ -987,6 +992,8 @@ protected:
|
||||
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13);
|
||||
virtual float GetSpecialProcChances(uint16 hand);
|
||||
virtual float GetAssassinateProcChances(uint16 ReuseTime);
|
||||
int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item);
|
||||
int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr);
|
||||
int GetKickDamage();
|
||||
@ -1097,6 +1104,8 @@ protected:
|
||||
bool offhand;
|
||||
bool has_shieldequiped;
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
|
||||
// Bind wound
|
||||
Timer bindwound_timer;
|
||||
|
||||
@ -100,7 +100,8 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg)
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, bool HitChance) {
|
||||
void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime,
|
||||
bool HitChance, bool CanAvoid) {
|
||||
//this really should go through the same code as normal melee damage to
|
||||
//pick up all the special behavior there
|
||||
|
||||
@ -135,7 +136,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
||||
if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&'
|
||||
CanRiposte = false;
|
||||
|
||||
who->AvoidDamage(this, max_damage, CanRiposte);
|
||||
if (CanAvoid)
|
||||
who->AvoidDamage(this, max_damage, CanRiposte);
|
||||
|
||||
who->MeleeMitigation(this, max_damage, min_damage);
|
||||
|
||||
if(max_damage > 0) {
|
||||
@ -373,8 +376,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillBackstab) {
|
||||
break;
|
||||
}
|
||||
TryBackstab(GetTarget(), ReuseTime);
|
||||
ReuseTime = BackstabReuseTime-1 - skill_reduction;
|
||||
TryBackstab(GetTarget(), ReuseTime);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -527,64 +530,47 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100)))
|
||||
bCanFrontalBS = true;
|
||||
}
|
||||
|
||||
|
||||
if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab
|
||||
|
||||
if (bCanFrontalBS) {
|
||||
if (bCanFrontalBS)
|
||||
CastToClient()->Message(0,"Your fierce attack is executed with such grace, your target did not see it coming!");
|
||||
}
|
||||
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
if (level > 54) {
|
||||
|
||||
// solar - chance to assassinate
|
||||
int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex
|
||||
if(
|
||||
level >= 60 && // player is 60 or higher
|
||||
other->GetLevel() <= 45 && // mob 45 or under
|
||||
!other->CastToNPC()->IsEngaged() && // not aggro
|
||||
other->GetHP()<=32000
|
||||
&& other->IsNPC()
|
||||
&& MakeRandomFloat(0, 99) < chance // chance
|
||||
) {
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
|
||||
if(IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
|
||||
RogueAssassinate(other);
|
||||
}
|
||||
else {
|
||||
RogueBackstab(other);
|
||||
if (level > 54) {
|
||||
float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max
|
||||
// Check for double attack with main hand assuming maxed DA Skill (MS)
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
{
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
|
||||
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA
|
||||
{
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
|
||||
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
}
|
||||
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
}
|
||||
if(IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
|
||||
}
|
||||
|
||||
if(IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
|
||||
|
||||
}
|
||||
//Live AA - Chaotic Backstab
|
||||
else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) {
|
||||
|
||||
//we can stab from any angle, we do min damage though.
|
||||
RogueBackstab(other, true);
|
||||
RogueBackstab(other, true, ReuseTime);
|
||||
if (level > 54) {
|
||||
float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max
|
||||
if(IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
|
||||
|
||||
// Check for double attack with main hand assuming maxed DA Skill (MS)
|
||||
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA
|
||||
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
|
||||
if(other->GetHP() > 0)
|
||||
RogueBackstab(other,true, ReuseTime);
|
||||
|
||||
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
|
||||
RogueBackstab(other,false,ReuseTime);
|
||||
}
|
||||
|
||||
if(IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
|
||||
}
|
||||
else { //We do a single regular attack if we attack from the front without chaotic stab
|
||||
Attack(other, 13);
|
||||
@ -594,6 +580,9 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
|
||||
//heko: backstab
|
||||
void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
{
|
||||
if (!other)
|
||||
return;
|
||||
|
||||
int32 ndamage = 0;
|
||||
int32 max_hit = 0;
|
||||
int32 min_hit = 0;
|
||||
@ -668,12 +657,20 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
|
||||
}
|
||||
|
||||
ndamage = mod_backstab_damage(ndamage);
|
||||
|
||||
uint32 Assassinate_Dmg = 0;
|
||||
Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime);
|
||||
|
||||
if (Assassinate_Dmg) {
|
||||
ndamage = Assassinate_Dmg;
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
|
||||
}
|
||||
|
||||
DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime);
|
||||
DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime, false, false);
|
||||
DoAnim(animPiercing);
|
||||
}
|
||||
|
||||
// solar - assassinate
|
||||
// solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14]
|
||||
void Mob::RogueAssassinate(Mob* other)
|
||||
{
|
||||
//can you dodge, parry, etc.. an assassinate??
|
||||
@ -861,8 +858,12 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
} else {
|
||||
mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName());
|
||||
|
||||
if(!TryHeadShot(other, SkillArchery))
|
||||
{
|
||||
|
||||
bool HeadShot = false;
|
||||
uint32 HeadShot_Dmg = TryHeadShot(other, SkillArchery);
|
||||
if (HeadShot_Dmg)
|
||||
HeadShot = true;
|
||||
|
||||
int32 TotalDmg = 0;
|
||||
int16 WDmg = 0;
|
||||
int16 ADmg = 0;
|
||||
@ -882,6 +883,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
uint32 MaxDmg = (RuleR(Combat, ArcheryBaseDamageBonus)*(WDmg+ADmg)*GetDamageTable(SkillArchery)) / 100;
|
||||
int32 hate = ((WDmg+ADmg));
|
||||
|
||||
if (HeadShot)
|
||||
MaxDmg = HeadShot_Dmg;
|
||||
|
||||
uint16 bonusArcheryDamageModifier = aabonuses.ArcheryDamageModifier + itembonuses.ArcheryDamageModifier + spellbonuses.ArcheryDamageModifier;
|
||||
|
||||
MaxDmg += MaxDmg*bonusArcheryDamageModifier / 100;
|
||||
@ -938,7 +942,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
hate += (2*((GetLevel()-25)/3));
|
||||
}
|
||||
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
if (!HeadShot)
|
||||
other->AvoidDamage(this, TotalDmg, false);
|
||||
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
{
|
||||
@ -957,8 +963,11 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
else
|
||||
TotalDmg = -5;
|
||||
|
||||
if (HeadShot)
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName());
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//try proc on hits and misses
|
||||
@ -1264,13 +1273,24 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
|
||||
int32 TotalDmg = 0;
|
||||
|
||||
uint32 Assassinate_Dmg = 0;
|
||||
if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY())))
|
||||
Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration());
|
||||
|
||||
if(WDmg > 0)
|
||||
{
|
||||
int minDmg = 1;
|
||||
uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg);
|
||||
|
||||
if (Assassinate_Dmg) {
|
||||
TotalDmg = Assassinate_Dmg;
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
|
||||
}
|
||||
|
||||
mlog(COMBAT__RANGED, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
|
||||
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
|
||||
if (!Assassinate_Dmg)
|
||||
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
|
||||
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
{
|
||||
@ -1854,92 +1874,6 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
|
||||
if (who == nullptr)
|
||||
return;
|
||||
|
||||
if(DivineAura())
|
||||
return;
|
||||
|
||||
if(!CombatRange(who))
|
||||
return;
|
||||
|
||||
if(!always_succeed && IsClient())
|
||||
CastToClient()->CheckIncreaseSkill(TAUNT, who, 10);
|
||||
|
||||
int level = GetLevel();
|
||||
Mob *hate_top = who->GetHateMost();
|
||||
|
||||
// Check to see if we're already at the top of the target's hate list
|
||||
// a mob will not be taunted if its target's health is below 20%
|
||||
if ((hate_top != this)
|
||||
&& (who->GetLevel() < level)
|
||||
&& (hate_top == nullptr || hate_top->GetHPRatio() >= 20) ) {
|
||||
int32 newhate, tauntvalue;
|
||||
|
||||
float tauntchance;
|
||||
if(always_succeed) {
|
||||
tauntchance = 101;
|
||||
} else {
|
||||
|
||||
// no idea how taunt success is actually calculated
|
||||
// TODO: chance for level 50+ mobs should be lower
|
||||
int level_difference = level - who->GetLevel();
|
||||
if (level_difference <= 5) {
|
||||
tauntchance = 25.0; // minimum
|
||||
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
|
||||
if (tauntchance > 65.0)
|
||||
tauntchance = 65.0;
|
||||
}
|
||||
else if (level_difference <= 10) {
|
||||
tauntchance = 30.0; // minimum
|
||||
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
|
||||
if (tauntchance > 85.0)
|
||||
tauntchance = 85.0;
|
||||
}
|
||||
else if (level_difference <= 15) {
|
||||
tauntchance = 40.0; // minimum
|
||||
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
|
||||
if (tauntchance > 90.0)
|
||||
tauntchance = 90.0;
|
||||
}
|
||||
else {
|
||||
tauntchance = 50.0; // minimum
|
||||
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
|
||||
if (tauntchance > 95.0)
|
||||
tauntchance = 95.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (chance_bonus)
|
||||
tauntchance = tauntchance + (tauntchance*chance_bonus/100.0f);
|
||||
|
||||
if (tauntchance > MakeRandomFloat(0, 100)) {
|
||||
// this is the max additional hate added per succesfull taunt
|
||||
tauntvalue = (MakeRandomInt(2, 4) * level);
|
||||
//tauntvalue = (int32) ((float)level * 10.0 * (float)rand()/(float)RAND_MAX + 1);
|
||||
// new hate: find diff of player's hate and whoever's at top of list, add that plus tauntvalue to players hate
|
||||
newhate = who->GetNPCHate(hate_top) - who->GetNPCHate(this) + tauntvalue;
|
||||
// add the hate
|
||||
who->CastToNPC()->AddToHateList(this, newhate);
|
||||
}
|
||||
else{
|
||||
//generate at least some hate reguardless of the outcome.
|
||||
who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level));
|
||||
}
|
||||
}
|
||||
|
||||
//generate at least some hate reguardless of the outcome.
|
||||
who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level));
|
||||
if (HasSkillProcs()){
|
||||
float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(who, TAUNT, chance);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
|
||||
if (who == nullptr)
|
||||
@ -2074,30 +2008,134 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
||||
bool Result = false;
|
||||
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
|
||||
|
||||
if(defender && skillInUse == SkillArchery) {
|
||||
if(GetAA(aaHeadshot) && defender->GetBodyType() == BT_Humanoid) {
|
||||
if((GetLevelCon(GetLevel(), defender->GetLevel()) == CON_LIGHTBLUE || GetLevelCon(GetLevel(), defender->GetLevel()) == CON_GREEN) && defender->GetLevel() <= 60 && !defender->IsClient()) {
|
||||
// WildcardX: These chance formula's below are arbitrary. If someone has a better formula that is more
|
||||
// consistent with live, feel free to update these.
|
||||
int AttackerChance = 20 + ((GetLevel() - 51) / 2) + (itembonuses.HeroicDEX / 10);
|
||||
int DefenderChance = MakeRandomInt(0, 100);
|
||||
if(AttackerChance > DefenderChance) {
|
||||
mlog(COMBAT__ATTACKS, "Landed a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance);
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName());
|
||||
defender->Damage(this, 32000, SPELL_UNKNOWN, skillInUse);
|
||||
Result = true;
|
||||
}
|
||||
else {
|
||||
mlog(COMBAT__ATTACKS, "FAILED a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance);
|
||||
}
|
||||
}
|
||||
//Only works on YOUR target.
|
||||
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient()
|
||||
&& (skillInUse == SkillArchery) && (GetTarget() == defender)) {
|
||||
|
||||
uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1];
|
||||
|
||||
uint8 HeadShot_Level = 0; //Get Highest Headshot Level
|
||||
HeadShot_Level = aabonuses.HSLevel;
|
||||
if (HeadShot_Level < spellbonuses.HSLevel)
|
||||
HeadShot_Level = spellbonuses.HSLevel;
|
||||
else if (HeadShot_Level < itembonuses.HSLevel)
|
||||
HeadShot_Level = itembonuses.HSLevel;
|
||||
|
||||
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
|
||||
|
||||
float ProcChance = GetSpecialProcChances(11);
|
||||
if(ProcChance > MakeRandomFloat(0,1))
|
||||
return HeadShot_Dmg;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Mob::GetSpecialProcChances(uint16 hand)
|
||||
{
|
||||
int mydex = GetDEX();
|
||||
|
||||
if (mydex > 255)
|
||||
mydex = 255;
|
||||
|
||||
uint16 weapon_speed;
|
||||
float ProcChance = 0.0f;
|
||||
float ProcBonus = 0.0f;
|
||||
|
||||
switch (hand) {
|
||||
case 13:
|
||||
weapon_speed = attack_timer.GetDuration();
|
||||
break;
|
||||
case 14:
|
||||
weapon_speed = attack_dw_timer.GetDuration();
|
||||
break;
|
||||
case 11:
|
||||
weapon_speed = ranged_timer.GetDuration();
|
||||
break;
|
||||
}
|
||||
|
||||
if (weapon_speed < RuleI(Combat, MinHastedDelay))
|
||||
weapon_speed = RuleI(Combat, MinHastedDelay);
|
||||
|
||||
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
|
||||
ProcBonus += static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25);
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
} else {
|
||||
/*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.”
|
||||
Kayen: Most reports suggest a ~ 6% chance to Headshot which consistent with above.*/
|
||||
|
||||
ProcChance = (static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25))/100.0f;
|
||||
}
|
||||
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime) {
|
||||
|
||||
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() &&
|
||||
(skillInUse == SkillBackstab || skillInUse == SkillThrowing)) {
|
||||
|
||||
uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1];
|
||||
|
||||
uint8 Assassinate_Level = 0; //Get Highest Headshot Level
|
||||
Assassinate_Level = aabonuses.AssassinateLevel;
|
||||
if (Assassinate_Level < spellbonuses.AssassinateLevel)
|
||||
Assassinate_Level = spellbonuses.AssassinateLevel;
|
||||
else if (Assassinate_Level < itembonuses.AssassinateLevel)
|
||||
Assassinate_Level = itembonuses.AssassinateLevel;
|
||||
|
||||
if (GetLevel() >= 60){ //Innate Assassinate Ability if client as no bonuses.
|
||||
if (!Assassinate_Level)
|
||||
Assassinate_Level = 45;
|
||||
|
||||
if (!Assassinate_Dmg)
|
||||
Assassinate_Dmg = 32000;
|
||||
}
|
||||
|
||||
if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){
|
||||
float ProcChance = 0.0f;
|
||||
|
||||
if (skillInUse == SkillThrowing)
|
||||
ProcChance = GetSpecialProcChances(11);
|
||||
else
|
||||
ProcChance = GetAssassinateProcChances(ReuseTime);
|
||||
|
||||
if(ProcChance > MakeRandomFloat(0,1))
|
||||
return Assassinate_Dmg;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Mob::GetAssassinateProcChances(uint16 ReuseTime)
|
||||
{
|
||||
int mydex = GetDEX();
|
||||
|
||||
if (mydex > 255)
|
||||
mydex = 255;
|
||||
|
||||
float ProcChance = 0.0f;
|
||||
float ProcBonus = 0.0f;
|
||||
|
||||
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(ReuseTime*1000) *
|
||||
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
|
||||
ProcBonus += (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
|
||||
} else {
|
||||
/*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/
|
||||
ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
|
||||
|
||||
}
|
||||
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte)
|
||||
|
||||
@ -1551,15 +1551,22 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
GetPetType() != petCharmed
|
||||
)
|
||||
{
|
||||
int lvlmod = 4;
|
||||
if(caster->IsClient() && caster->CastToClient()->GetAA(aaImprovedReclaimEnergy))
|
||||
lvlmod = 8; //this is an unconfirmed number, I made it up
|
||||
if(caster->IsClient() && caster->CastToClient()->GetAA(aaImprovedReclaimEnergy2))
|
||||
lvlmod = 8; //this is an unconfirmed number, I made it up
|
||||
caster->SetMana(caster->GetMana()+(GetLevel()*lvlmod));
|
||||
uint16 pet_spellid = CastToNPC()->GetPetSpellID();
|
||||
uint16 pet_ActSpellCost = caster->GetActSpellCost(pet_spellid, spells[pet_spellid].mana);
|
||||
int16 ImprovedReclaimMod = caster->spellbonuses.ImprovedReclaimEnergy +
|
||||
caster->itembonuses.ImprovedReclaimEnergy +
|
||||
caster->aabonuses.ImprovedReclaimEnergy;
|
||||
|
||||
if (!ImprovedReclaimMod)
|
||||
ImprovedReclaimMod = 75; //Reclaim Energy default is 75% of actual mana cost
|
||||
|
||||
pet_ActSpellCost = pet_ActSpellCost*ImprovedReclaimMod/100;
|
||||
|
||||
caster->SetMana(caster->GetMana() + pet_ActSpellCost);
|
||||
|
||||
if(caster->IsClient())
|
||||
caster->CastToClient()->SetPet(0);
|
||||
|
||||
SetOwnerID(0); // this will kill the pet
|
||||
}
|
||||
break;
|
||||
@ -2183,12 +2190,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Fading Memories");
|
||||
#endif
|
||||
if(caster && caster->IsClient())
|
||||
caster->CastToClient()->Escape();
|
||||
else
|
||||
{
|
||||
entity_list.RemoveFromTargets(caster);
|
||||
SetInvisible(1);
|
||||
if(MakeRandomInt(0, 99) < spells[spell_id].base[i] ) {
|
||||
|
||||
if(caster && caster->IsClient())
|
||||
caster->CastToClient()->Escape();
|
||||
else
|
||||
{
|
||||
entity_list.RemoveFromTargets(caster);
|
||||
SetInvisible(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2234,8 +2244,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "AE Taunt");
|
||||
#endif
|
||||
if(caster && caster->IsClient())
|
||||
entity_list.AETaunt(caster->CastToClient());
|
||||
if(caster && caster->IsClient()){
|
||||
float range = 0.0f;
|
||||
if (spells[spell_id].base2[i])
|
||||
range = (float)spells[spell_id].base[i];
|
||||
|
||||
entity_list.AETaunt(caster->CastToClient(), range);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2279,12 +2294,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
#endif
|
||||
//meh dupe issue with npc casting this
|
||||
if(caster->IsClient()){
|
||||
//this spell doesn't appear to actually contain the information on duration inside of it oddly
|
||||
int dur = 60;
|
||||
if(spell_id == 3269)
|
||||
dur += 15;
|
||||
else if(spell_id == 3270)
|
||||
dur += 30;
|
||||
int dur = spells[spell_id].max[i];
|
||||
if (!dur)
|
||||
dur = 60;
|
||||
|
||||
caster->WakeTheDead(spell_id, caster->GetTarget(), dur);
|
||||
}
|
||||
@ -2643,9 +2655,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
case SE_Taunt:
|
||||
{
|
||||
if (IsNPC())
|
||||
if (IsNPC()){
|
||||
caster->Taunt(this->CastToNPC(), false, spell.base[i]);
|
||||
|
||||
|
||||
if (spell.base2[i] > 0)
|
||||
CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2670,9 +2685,50 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
case SE_AddHatePct:
|
||||
{
|
||||
if (IsNPC())
|
||||
CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100));
|
||||
if (IsNPC()){
|
||||
int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
|
||||
CastToNPC()->SetHate(caster, new_hate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Hate:{
|
||||
|
||||
if (buffslot >= 0)
|
||||
break;
|
||||
|
||||
if(caster){
|
||||
if(effect_value > 0){
|
||||
if(caster){
|
||||
if(caster->IsClient() && !caster->CastToClient()->GetFeigned())
|
||||
AddToHateList(caster, effect_value);
|
||||
else if(!caster->IsClient())
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
}else{
|
||||
int32 newhate = GetHateAmount(caster) + effect_value;
|
||||
if (newhate < 1)
|
||||
SetHate(caster,1);
|
||||
else
|
||||
SetHate(caster,newhate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_MassGroupBuff:{
|
||||
|
||||
SetMGB(true);
|
||||
Message_StringID(MT_Disciplines, MGB_STRING);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_IllusionOther: {
|
||||
SetProjectIllusion(true);
|
||||
Message(10, "The power of your next illusion spell will flow to your grouped target in your place.");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2746,7 +2802,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_ChangeFrenzyRad:
|
||||
case SE_Harmony:
|
||||
case SE_ChangeAggro:
|
||||
case SE_Hate2:
|
||||
case SE_Identify:
|
||||
case SE_InstantHate:
|
||||
case SE_ReduceHate:
|
||||
@ -2805,8 +2860,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_CriticalHealChance:
|
||||
case SE_CriticalHealOverTime:
|
||||
case SE_CriticalDoTChance:
|
||||
case SE_SpellOnKill:
|
||||
case SE_SpellOnKill2:
|
||||
case SE_ProcOnKillShot:
|
||||
case SE_ProcOnSpellKillShot:
|
||||
case SE_CriticalDamageMob:
|
||||
case SE_LimitSpellGroup:
|
||||
case SE_ResistCorruption:
|
||||
@ -2831,7 +2886,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_ACv2:
|
||||
case SE_ManaRegen_v2:
|
||||
case SE_FcDamagePctCrit:
|
||||
case SE_FcHealAmt:
|
||||
case SE_FcHealAmt:
|
||||
case SE_FcHealPctIncoming:
|
||||
case SE_CriticalHealDecay:
|
||||
case SE_CriticalRegenDecay:
|
||||
@ -2845,6 +2900,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_PetCriticalHit:
|
||||
case SE_SlayUndead:
|
||||
case SE_GiveDoubleAttack:
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
case SE_SecondaryDmgInc:
|
||||
case SE_ArcheryDamageModifier:
|
||||
@ -2863,6 +2919,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_CombatStability:
|
||||
case SE_AddSingingMod:
|
||||
case SE_SongModCap:
|
||||
case SE_HeadShot:
|
||||
case SE_HeadShotLevel:
|
||||
case SE_PetAvoidance:
|
||||
case SE_GiveDoubleRiposte:
|
||||
case SE_Ambidexterity:
|
||||
@ -3340,7 +3398,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Hate2:{
|
||||
case SE_Hate:{
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level);
|
||||
if(caster){
|
||||
if(effect_value > 0){
|
||||
@ -3536,9 +3594,13 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
|
||||
case SE_AddHateOverTimePct:
|
||||
{
|
||||
if (IsNPC())
|
||||
CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100));
|
||||
|
||||
if (IsNPC()){
|
||||
int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
|
||||
CastToNPC()->SetHate(caster, new_hate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5742,16 +5804,25 @@ uint16 Mob::GetSpellEffectResistChance(uint16 spell_id)
|
||||
|
||||
bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){
|
||||
|
||||
/*Live 5-20-14 Patch Note: Updated all spells which use Remove Detrimental and
|
||||
Cancel Beneficial spell effects to use a new method. The chances for those spells to
|
||||
affect their targets have not changed unless otherwise noted.*/
|
||||
|
||||
/*This should provide a somewhat accurate conversion between pre 5/14 base values and post.
|
||||
until more information is avialble - Kayen*/
|
||||
if (level_modifier >= 100)
|
||||
level_modifier = level_modifier/100;
|
||||
|
||||
//Dispels - Check level of caster agianst buffs level (level of the caster who cast the buff)
|
||||
//Effect value of dispels are treated as a level modifier.
|
||||
//Values for scaling were obtain from live parses, best estimates.
|
||||
|
||||
caster_level += level_modifier - 1;
|
||||
int dispel_chance = 36; //Baseline chance if no level difference and no modifier
|
||||
int dispel_chance = 32; //Baseline chance if no level difference and no modifier
|
||||
int level_diff = caster_level - buff_level;
|
||||
|
||||
if (level_diff > 0)
|
||||
dispel_chance += level_diff * 8;
|
||||
dispel_chance += level_diff * 7;
|
||||
|
||||
else if (level_diff < 0)
|
||||
dispel_chance += level_diff * 2;
|
||||
|
||||
@ -399,7 +399,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
mana_cost = GetActSpellCost(spell_id, mana_cost);
|
||||
}
|
||||
|
||||
if(IsClient() && CastToClient()->CheckAAEffect(aaEffectMassGroupBuff) && spells[spell_id].can_mgb)
|
||||
if(HasMGB() && spells[spell_id].can_mgb)
|
||||
mana_cost *= 2;
|
||||
|
||||
// mana is checked for clients on the frontend. we need to recheck it for NPCs though
|
||||
@ -1371,7 +1371,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
&& IsClient()
|
||||
&& (IsGrouped() // still self only if not grouped
|
||||
|| IsRaidGrouped())
|
||||
&& CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){
|
||||
&& (HasProjectIllusion())){
|
||||
mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id);
|
||||
targetType = ST_GroupClientAndPet;
|
||||
}
|
||||
@ -1853,7 +1853,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
range = GetActSpellRange(spell_id, range);
|
||||
if(IsPlayerIllusionSpell(spell_id)
|
||||
&& IsClient()
|
||||
&& CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){
|
||||
&& (HasProjectIllusion())){
|
||||
range = 100;
|
||||
}
|
||||
if(spell_target != nullptr && spell_target != this) {
|
||||
@ -1912,9 +1912,9 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
|
||||
if(IsPlayerIllusionSpell(spell_id)
|
||||
&& IsClient()
|
||||
&& CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){
|
||||
&& (HasProjectIllusion())){
|
||||
mlog(AA__MESSAGE, "Effect Project Illusion for %s on spell id: %d was ON", GetName(), spell_id);
|
||||
CastToClient()->DisableAAEffect(aaEffectProjectIllusion);
|
||||
SetProjectIllusion(false);
|
||||
}
|
||||
else{
|
||||
mlog(AA__MESSAGE, "Effect Project Illusion for %s on spell id: %d was OFF", GetName(), spell_id);
|
||||
@ -1969,11 +1969,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
}
|
||||
#endif //BOTS
|
||||
|
||||
if(spells[spell_id].can_mgb && IsClient() && CastToClient()->CheckAAEffect(aaEffectMassGroupBuff))
|
||||
if(spells[spell_id].can_mgb && HasMGB())
|
||||
{
|
||||
SpellOnTarget(spell_id, this);
|
||||
entity_list.MassGroupBuff(this, this, spell_id, true);
|
||||
CastToClient()->DisableAAEffect(aaEffectMassGroupBuff);
|
||||
SetMGB(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2622,19 +2622,31 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
}
|
||||
|
||||
/*Buff stacking prevention spell effects (446 - 449) works as follows... If B prevent A, if C prevent B, if D prevent C.
|
||||
If checking same type ie A vs A, which ever effect base value is higher will take hold.
|
||||
Special check is added to make sure the buffs stack properly when applied from fade on duration effect, since the buff
|
||||
is not fully removed at the time of the trgger*/
|
||||
if (spellbonuses.BStacker) {
|
||||
if (spellbonuses.AStacker[0]) {
|
||||
if ((effect2 == SE_AStacker) && (sp2.effectid[i] <= spellbonuses.AStacker[1]))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spellbonuses.BStacker[0]) {
|
||||
if ((effect2 == SE_BStacker) && (sp2.effectid[i] <= spellbonuses.BStacker[1]))
|
||||
return -1;
|
||||
if ((effect2 == SE_AStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_BStacker)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spellbonuses.CStacker) {
|
||||
if (spellbonuses.CStacker[0]) {
|
||||
if ((effect2 == SE_CStacker) && (sp2.effectid[i] <= spellbonuses.CStacker[1]))
|
||||
return -1;
|
||||
if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spellbonuses.DStacker) {
|
||||
if (spellbonuses.DStacker[0]) {
|
||||
if ((effect2 == SE_DStacker) && (sp2.effectid[i] <= spellbonuses.DStacker[1]))
|
||||
return -1;
|
||||
if ((effect2 == SE_CStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_DStacker)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user