diff --git a/CMakeLists.txt b/CMakeLists.txt index 45d3f6c50..55d9a4cfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,7 @@ ENDIF(EQEMU_ENABLE_BOTS) #What to build OPTION(EQEMU_BUILD_SERVER "Build the game server." ON) OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF) -OPTION(EQEMU_BUILD_AZONE "Build azone utility." OFF) +OPTION(EQEMU_BUILD_SOCKET_SERVER "Build the socket server." OFF) OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF) OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON) OPTION(EQEMU_BUILD_LUA "Build Lua parser." OFF) @@ -298,6 +298,13 @@ IF(EQEMU_BUILD_LUA) ENDIF(EQEMU_SANITIZE_LUA_LIBS) ENDIF(EQEMU_BUILD_LUA) +IF(EQEMU_BUILD_SOCKET_SERVER) + FIND_PACKAGE(Boost COMPONENTS system filesystem thread REQUIRED) + INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/dependencies/websocketpp") + ADD_DEFINITIONS(-D_WEBSOCKETPP_CPP11_STL_) + +ENDIF(EQEMU_BUILD_SOCKET_SERVER) + INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm") IF(EQEMU_BUILD_LUA) @@ -313,16 +320,13 @@ IF(EQEMU_BUILD_SERVER) ADD_SUBDIRECTORY(zone) ADD_SUBDIRECTORY(ucs) ADD_SUBDIRECTORY(queryserv) + ADD_SUBDIRECTORY(socket_server) ADD_SUBDIRECTORY(eqlaunch) ENDIF(EQEMU_BUILD_SERVER) IF(EQEMU_BUILD_LOGIN) ADD_SUBDIRECTORY(loginserver) ENDIF(EQEMU_BUILD_LOGIN) -IF(EQEMU_BUILD_AZONE) - ADD_SUBDIRECTORY(utils) -ENDIF(EQEMU_BUILD_AZONE) - IF(EQEMU_BUILD_TESTS) ADD_SUBDIRECTORY(tests) ENDIF(EQEMU_BUILD_TESTS) diff --git a/changelog.txt b/changelog.txt index eabbad6fd..0a22ccf8d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,47 @@ 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, +Any effect with B prevents A, C prevents B, D prevents C. +Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) +Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) +Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) +Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) *Not used in any live effects +Kayen: Implemented SE_Berserk (Sets client as 'Berserk' giving chance to crippling blow) *Not used in any live effects +Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used in any live effects +Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. +Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. +Kayen: Fixes and Updates for melee and spell mitigation runes. +Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. +Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] +Kayen: Update to SE_BalanaceMana, SE_BalanceHP to support limit value which caps max mana/hp that can be taken per player. + == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) Setting se_max to 1 for SkillDamageTaken effects (127) will allow for stackable mitigation/weakness same as quest function ModSkillDmgTaken. diff --git a/common/EmuTCPConnection.cpp b/common/EmuTCPConnection.cpp index 465d16c1e..39c297ccf 100644 --- a/common/EmuTCPConnection.cpp +++ b/common/EmuTCPConnection.cpp @@ -366,7 +366,22 @@ bool EmuTCPConnection::LineOutQueuePush(char* line) { safe_delete_array(line); return(true); } - + if (strcmp(line, "**PACKETMODESS**") == 0) { + MSendQueue.lock(); + safe_delete_array(sendbuf); + if (TCPMode == modeConsole) + Send((const uchar*) "\0**PACKETMODESS**\r", 18); + TCPMode = modePacket; + PacketMode = packetModeSocket_Server; + EmuTCPNetPacket_Struct* tnps = 0; + while ((tnps = InModeQueue.pop())) { + SendPacket(tnps); + safe_delete_array(tnps); + } + MSendQueue.unlock(); + safe_delete_array(line); + return(true); + } } return(TCPConnection::LineOutQueuePush(line)); @@ -419,7 +434,15 @@ bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) { sendbuf_used = sendbuf_size; sendbuf = new uchar[sendbuf_size]; memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size); - } else { + } + else if (PacketMode == packetModeSocket_Server) { + safe_delete_array(sendbuf); + sendbuf_size = 18; + sendbuf_used = sendbuf_size; + sendbuf = new uchar[sendbuf_size]; + memcpy(sendbuf, "\0**PACKETMODESS**\r", sendbuf_size); + } + else { //default: packetModeZone safe_delete_array(sendbuf); sendbuf_size = 20; diff --git a/common/EmuTCPConnection.h b/common/EmuTCPConnection.h index ff7dd8995..947ee9480 100644 --- a/common/EmuTCPConnection.h +++ b/common/EmuTCPConnection.h @@ -30,7 +30,7 @@ class EmuTCPServer; class EmuTCPConnection : public TCPConnection { public: enum eTCPMode { modeConsole, modeTransition, modePacket }; - enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ }; + enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ, packetModeSocket_Server }; EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false); EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections diff --git a/common/logtypes.h b/common/logtypes.h index cadfbf71a..1776c9518 100644 --- a/common/logtypes.h +++ b/common/logtypes.h @@ -65,6 +65,13 @@ LOG_TYPE( QUERYSERV, CLIENT, DISABLED ) LOG_TYPE( QUERYSERV, TRACE, DISABLED ) LOG_TYPE( QUERYSERV, PACKETS, DISABLED) +LOG_CATEGORY(SOCKET_SERVER) +LOG_TYPE(SOCKET_SERVER, INIT, ENABLED) +LOG_TYPE(SOCKET_SERVER, ERROR, ENABLED) +LOG_TYPE(SOCKET_SERVER, CLIENT, DISABLED) +LOG_TYPE(SOCKET_SERVER, TRACE, DISABLED) +LOG_TYPE(SOCKET_SERVER, PACKETS, DISABLED) + LOG_CATEGORY( SPAWNS ) LOG_TYPE( SPAWNS, MAIN, DISABLED ) LOG_TYPE( SPAWNS, CONDITIONS, DISABLED ) diff --git a/common/platform.h b/common/platform.h index efb176ec4..7eaae045b 100644 --- a/common/platform.h +++ b/common/platform.h @@ -8,6 +8,7 @@ enum EQEmuExePlatform ExePlatformWorld, ExePlatformLogin, ExePlatformQueryServ, + ExePlatformSocket_Server, ExePlatformUCS, ExePlatformLaunch, ExePlatformSharedMemory, diff --git a/common/ruletypes.h b/common/ruletypes.h index 70e4ba0d2..6f5fe0769 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -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 diff --git a/common/spdat.cpp b/common/spdat.cpp index 013a917f1..3c4989a67 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1009,6 +1009,19 @@ uint32 GetMorphTrigger(uint32 spell_id) return 0; } +bool IsCastonFadeDurationSpell(uint16 spell_id) +{ + for (int i = 0; i < EFFECT_COUNT; ++i) { + if (spells[spell_id].effectid[i] == SE_ImprovedSpellEffect + || spells[spell_id].effectid[i] == SE_BossSpellTrigger + || spells[spell_id].effectid[i] == SE_CastOnWearoff){ + + return true; + } + } + return false; +} + uint32 GetPartialMeleeRuneReduction(uint32 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) diff --git a/common/spdat.h b/common/spdat.h index ada9e3249..75d351fc2 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -190,9 +190,9 @@ typedef enum { #define SE_DivineAura 40 // implemented #define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows #define SE_ShadowStep 42 // implemented -//#define SE_Berserk 43 // not used -#define SE_Lycanthropy 44 // implemented -//#define SE_Vampirism 45 // not used +#define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance. +#define SE_Lycanthropy 44 // implemented +#define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee. #define SE_ResistFire 46 // implemented #define SE_ResistCold 47 // implemented #define SE_ResistPoison 48 // implemented @@ -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 @@ -307,7 +307,7 @@ typedef enum { #define SE_SpellDamageShield 157 // implemented - Petrad's Protection #define SE_Reflect 158 // implemented #define SE_AllStats 159 // implemented -#define SE_MakeDrunk 160 // implemented - poorly though, should check against tolerance +//#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance) #define SE_MitigateSpellDamage 161 // implemented - rune with max value #define SE_MitigateMeleeDamage 162 // implemented - rune with max value #define SE_NegateAttacks 163 // implemented @@ -339,48 +339,48 @@ 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 #define SE_Packrat 221 // implemented as bonus #define SE_BlockBehind 222 // implemented - Chance to block from behind (with our without Shield) -//#define SE_DoubleRiposte 223 // not used +#define SE_DoubleRiposte 223 // implemented - Chance to double riposte [not used on live] #define SE_GiveDoubleRiposte 224 // implemented[AA] #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. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) -//#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism? +#define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. //#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used @@ -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,27 +586,27 @@ 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) #define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y //#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. -//#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch) -//#define SE_BStacker 447 // *not implemented -//#define SE_CStacker 448 // *not implemented -//#define SE_DStacker 449 // *not implemented +#define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) +#define SE_BStacker 447 // implemented +#define SE_CStacker 448 // implemented +#define SE_DStacker 449 // implemented #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage #define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken #define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken -//#define SE_AddHatePct 455 // not used -//#define SE_AddHateOverTimePct 456 // not used +#define SE_AddHatePct 455 // implemented Modify total hate by % +#define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used -//#define SE_DamageModifier2 459 // *not implemented - Modifies melee damage by skill type +#define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type // LAST @@ -833,6 +833,7 @@ bool IsBuffSpell(uint16 spell_id); bool IsPersistDeathSpell(uint16 spell_id); bool IsSuspendableSpell(uint16 spell_id); uint32 GetMorphTrigger(uint32 spell_id); +bool IsCastonFadeDurationSpell(uint16 spell_id); uint32 GetPartialMeleeRuneReduction(uint32 spell_id); uint32 GetPartialMagicRuneReduction(uint32 spell_id); uint32 GetPartialMeleeRuneAmount(uint32 spell_id); diff --git a/luabind/luabind/detail/format_signature.hpp b/luabind/luabind/detail/format_signature.hpp index 56e796363..ec56b6196 100644 --- a/luabind/luabind/detail/format_signature.hpp +++ b/luabind/luabind/detail/format_signature.hpp @@ -13,12 +13,17 @@ # include # include -namespace luabind { +namespace luabind { namespace adl { -class object; -class argument; -template -struct table; + class object; + class argument; + template + struct table; +} // namespace adl + +using adl::object; +using adl::argument; +using adl::table; } // namespace luabind diff --git a/socket_server/CMakeLists.txt b/socket_server/CMakeLists.txt new file mode 100644 index 000000000..abaec0f21 --- /dev/null +++ b/socket_server/CMakeLists.txt @@ -0,0 +1,44 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +SET(socket_server_sources + database.cpp + socket_server.cpp + socket_server_config.cpp + worldserver.cpp +) + +SET(socket_server_headers + database.h + socket_server_config.h + worldserver.h +) + +ADD_EXECUTABLE(socket_server ${socket_server_sources} ${socket_server_headers}) + +INSTALL(TARGETS socket_server RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + +ADD_DEFINITIONS(-DQSERV) + +TARGET_LINK_LIBRARIES(socket_server Common ${Boost_LIBRARIES} debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY}) + +IF(MSVC) + SET_TARGET_PROPERTIES(socket_server PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") + TARGET_LINK_LIBRARIES(socket_server "Ws2_32.lib") +ENDIF(MSVC) + +IF(MINGW) + TARGET_LINK_LIBRARIES(socket_server "WS2_32") +ENDIF(MINGW) + +IF(UNIX) + TARGET_LINK_LIBRARIES(socket_server "${CMAKE_DL_LIBS}") + TARGET_LINK_LIBRARIES(socket_server "z") + TARGET_LINK_LIBRARIES(socket_server "m") + IF(NOT DARWIN) + TARGET_LINK_LIBRARIES(socket_server "rt") + ENDIF(NOT DARWIN) + TARGET_LINK_LIBRARIES(socket_server "pthread") + ADD_DEFINITIONS(-fPIC) +ENDIF(UNIX) + +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/Bin) diff --git a/socket_server/database.cpp b/socket_server/database.cpp new file mode 100644 index 000000000..a2c04bbb4 --- /dev/null +++ b/socket_server/database.cpp @@ -0,0 +1,131 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#include "../common/debug.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Disgrace: for windows compile +#ifdef _WINDOWS +#include +#define snprintf _snprintf +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#else +#include "../common/unix.h" +#include +#endif + +#include "database.h" +#include "../common/eq_packet_structs.h" +#include "../common/StringUtil.h" +#include "../common/servertalk.h" + +Database::Database () +{ + DBInitVars(); +} + +/* +Establish a connection to a mysql database with the supplied parameters +*/ + +Database::Database(const char* host, const char* user, const char* passwd, const char* database, uint32 port) +{ + DBInitVars(); + Connect(host, user, passwd, database, port); +} + +bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port) +{ + uint32 errnum= 0; + char errbuf[MYSQL_ERRMSG_SIZE]; + if (!Open(host, user, passwd, database, port, &errnum, errbuf)) + { + LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf); + HandleMysqlError(errnum); + + return false; + } + else + { + LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port); + return true; + } +} + +void Database::DBInitVars() { + +} + + + +void Database::HandleMysqlError(uint32 errnum) { +} + +/* + +Close the connection to the database +*/ +Database::~Database() +{ +} + +bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { + + char errbuf[MYSQL_ERRMSG_SIZE]; + char* query = 0; + MYSQL_RES *result; + MYSQL_ROW row; + + if (!RunQuery(query,MakeAnyLenString(&query, "select `value` from `variables` where `varname`='%s'", varname), errbuf, &result)) { + + _log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf); + + safe_delete_array(query); + + return false; + } + + safe_delete_array(query); + + if (mysql_num_rows(result) != 1) { + + mysql_free_result(result); + + return false; + } + + row = mysql_fetch_row(result); + + snprintf(varvalue, varvalue_len, "%s", row[0]); + + mysql_free_result(result); + + return true; +} \ No newline at end of file diff --git a/socket_server/database.h b/socket_server/database.h new file mode 100644 index 000000000..6500ffad6 --- /dev/null +++ b/socket_server/database.h @@ -0,0 +1,54 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef CHATSERVER_DATABASE_H +#define CHATSERVER_DATABASE_H + +#define AUTHENTICATION_TIMEOUT 60 +#define INVALID_ID 0xFFFFFFFF + +#include "../common/debug.h" +#include "../common/types.h" +#include "../common/dbcore.h" +#include "../common/linked_list.h" +#include "../common/servertalk.h" +#include +#include +#include + +//atoi is not uint32 or uint32 safe!!!! +#define atoul(str) strtoul(str, nullptr, 10) + +class Database : public DBcore { +public: + Database(); + Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port); + bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port); + ~Database(); + + bool GetVariable(const char* varname, char* varvalue, uint16 varvalue_len); +protected: + void HandleMysqlError(uint32 errnum); +private: + void DBInitVars(); + +}; + +#endif + diff --git a/socket_server/socket_server.cpp b/socket_server/socket_server.cpp new file mode 100644 index 000000000..997d9965f --- /dev/null +++ b/socket_server/socket_server.cpp @@ -0,0 +1,281 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include +#include +#include +/*#include +#include +#include */ +#include + +typedef websocketpp::server server; + +using websocketpp::connection_hdl; +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + +using websocketpp::lib::thread; +using websocketpp::lib::mutex; +using websocketpp::lib::unique_lock; +using websocketpp::lib::condition_variable; + +#include "../common/debug.h" +#include "../common/opcodemgr.h" +#include "../common/EQStreamFactory.h" +#include "../common/rulesys.h" +#include "../common/servertalk.h" +#include "../common/platform.h" +#include "../common/crash.h" +#include "database.h" +#include "socket_server_config.h" +#include "worldserver.h" +#include + +#include +volatile bool RunLoops = true; +TimeoutManager timeout_manager; +Database database; +std::string WorldShortName; + +const socket_server_config *Config; +WorldServer *worldserver = 0; + +void CatchSignal(int sig_num) { + RunLoops = false; + if(worldserver) + worldserver->Disconnect(); +} + +/* Web Sockets Start Shit */ + +enum action_type { + SUBSCRIBE, + UNSUBSCRIBE, + MESSAGE +}; + +struct action { + action(action_type t, connection_hdl h) : type(t), hdl(h) {} + action(action_type t, connection_hdl h, server::message_ptr m) + : type(t), hdl(h), msg(m) {} + + action_type type; + websocketpp::connection_hdl hdl; + server::message_ptr msg; +}; + +class broadcast_server { +public: + broadcast_server() { + // Initialize Asio Transport + m_server.init_asio(); + + // Register handler callbacks + m_server.set_open_handler(bind(&broadcast_server::on_open, this, ::_1)); + m_server.set_close_handler(bind(&broadcast_server::on_close, this, ::_1)); + m_server.set_message_handler(bind(&broadcast_server::on_message, this, ::_1, ::_2)); + } + + void run(uint16_t port) { + // listen on specified port + m_server.listen(port); + + // Start the server accept loop + m_server.start_accept(); + + // Start the ASIO io_service run loop + try { + m_server.run(); + } + catch (const std::exception & e) { + std::cout << e.what() << std::endl; + } + catch (websocketpp::lib::error_code e) { + std::cout << e.message() << std::endl; + } + catch (...) { + std::cout << "other exception" << std::endl; + } + } + + void on_open(connection_hdl hdl) { + unique_lock lock(m_action_lock); + //std::cout << "on_open" << std::endl; + m_actions.push(action(SUBSCRIBE, hdl)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void on_close(connection_hdl hdl) { + unique_lock lock(m_action_lock); + //std::cout << "on_close" << std::endl; + m_actions.push(action(UNSUBSCRIBE, hdl)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void on_message(connection_hdl hdl, server::message_ptr msg) { + // queue message up for sending by processing thread + unique_lock lock(m_action_lock); + msg->set_payload("Niggers"); + // std::cout << "on_message" << std::endl; + m_actions.push(action(MESSAGE, hdl, msg)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void process_messages() { + while (1) { + unique_lock lock(m_action_lock); + + while (m_actions.empty()) { + m_action_cond.wait(lock); + } + + action a = m_actions.front(); + m_actions.pop(); + + lock.unlock(); + + if (a.type == SUBSCRIBE) { + unique_lock con_lock(m_connection_lock); + m_connections.insert(a.hdl); + } + else if (a.type == UNSUBSCRIBE) { + unique_lock con_lock(m_connection_lock); + m_connections.erase(a.hdl); + } + else if (a.type == MESSAGE) { + unique_lock con_lock(m_connection_lock); + + con_list::iterator it; + for (it = m_connections.begin(); it != m_connections.end(); ++it) { + m_server.send(*it, a.msg); + } + } + else { + // undefined. + } + } + } +private: + typedef std::set> con_list; + + server m_server; + con_list m_connections; + std::queue m_actions; + + mutex m_action_lock; + mutex m_connection_lock; + condition_variable m_action_cond; +}; + +/* Web Sockets Shit End*/ + +int main() { + + try { + broadcast_server server_instance; + + // Start a thread to run the processing loop + thread t(bind(&broadcast_server::process_messages, &server_instance)); + + // Run the asio loop with the main thread + server_instance.run(9002); + + t.join(); + + } + catch (std::exception & e) { + std::cout << e.what() << std::endl; + } + + RegisterExecutablePlatform(ExePlatformSocket_Server); + set_exception_handler(); + Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect + _log(SOCKET_SERVER__INIT, "Starting EQEmu Socket Server."); + if (!socket_server_config::LoadConfig()) { + _log(SOCKET_SERVER__INIT, "Loading server configuration failed."); + return 1; + } + + Config = socket_server_config::get(); + + if(!load_log_settings(Config->LogSettingsFile.c_str())) + _log(SOCKET_SERVER__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str()); + else + _log(SOCKET_SERVER__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str()); + + WorldShortName = Config->ShortName; + + /* + _log(SOCKET_SERVER__INIT, "Connecting to MySQL..."); + + if (!database.Connect( + Config->QSDatabaseHost.c_str(), + Config->QSDatabaseUsername.c_str(), + Config->QSDatabasePassword.c_str(), + Config->QSDatabaseDB.c_str(), + Config->QSDatabasePort)) { + _log(WORLD__INIT_ERR, "Cannot continue without a database connection."); + return 1; + } + */ + + if (signal(SIGINT, CatchSignal) == SIG_ERR) { + _log(SOCKET_SERVER__ERROR, "Could not set signal handler"); + return 1; + } + if (signal(SIGTERM, CatchSignal) == SIG_ERR) { + _log(SOCKET_SERVER__ERROR, "Could not set signal handler"); + return 1; + } + + worldserver = new WorldServer; + worldserver->Connect(); + + while(RunLoops) { + Timer::SetCurrentTime(); + if (InterserverTimer.Check()) { + if (worldserver->TryReconnect() && (!worldserver->Connected())) + worldserver->AsyncConnect(); + } + worldserver->Process(); + timeout_manager.CheckTimeouts(); + Sleep(100); + } + + + +} + +void UpdateWindowTitle(char* iNewTitle) { +#ifdef _WINDOWS + char tmp[500]; + if (iNewTitle) { + snprintf(tmp, sizeof(tmp), "SOCKET_SERVER: %s", iNewTitle); + } + else { + snprintf(tmp, sizeof(tmp), "SOCKET_SERVER"); + } + SetConsoleTitle(tmp); +#endif +} diff --git a/socket_server/socket_server_config.cpp b/socket_server/socket_server_config.cpp new file mode 100644 index 000000000..8f08eba9d --- /dev/null +++ b/socket_server/socket_server_config.cpp @@ -0,0 +1,28 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "../common/debug.h" +#include "socket_server_config.h" + +socket_server_config *socket_server_config::_chat_config = nullptr; + +std::string socket_server_config::GetByName(const std::string &var_name) const { + return(EQEmuConfig::GetByName(var_name)); +} + diff --git a/socket_server/socket_server_config.h b/socket_server/socket_server_config.h new file mode 100644 index 000000000..bc86107d3 --- /dev/null +++ b/socket_server/socket_server_config.h @@ -0,0 +1,55 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef __socket_server_config_H +#define __socket_server_config_H + +#include "../common/EQEmuConfig.h" + +class socket_server_config : public EQEmuConfig { +public: + virtual std::string GetByName(const std::string &var_name) const; + +private: + + static socket_server_config *_chat_config; + +public: + + // Produce a const singleton + static const socket_server_config *get() { + if (_chat_config == nullptr) + LoadConfig(); + return(_chat_config); + } + + // Load the config + static bool LoadConfig() { + if (_chat_config != nullptr) + delete _chat_config; + _chat_config=new socket_server_config; + _config=_chat_config; + + return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + } + +}; + +#endif + diff --git a/socket_server/worldserver.cpp b/socket_server/worldserver.cpp new file mode 100644 index 000000000..9c6afa138 --- /dev/null +++ b/socket_server/worldserver.cpp @@ -0,0 +1,68 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "../common/debug.h" +#include +#include +#include +#include +#include +#include +#include + +#include "../common/servertalk.h" +#include "worldserver.h" +#include "socket_server_config.h" +#include "database.h" +#include "../common/packet_functions.h" +#include "../common/md5.h" +#include "../common/packet_dump.h" + +extern WorldServer worldserver; +extern const socket_server_config *Config; +extern Database database; + +WorldServer::WorldServer() +: WorldConnection(EmuTCPConnection::packetModeSocket_Server, Config->SharedKey.c_str()){ + pTryReconnect = true; +} + +WorldServer::~WorldServer(){ +} + +void WorldServer::OnConnected(){ + _log(SOCKET_SERVER__INIT, "Connected to World."); + WorldConnection::OnConnected(); +} + +void WorldServer::Process(){ + WorldConnection::Process(); + if (!Connected()) + return; + + ServerPacket *pack = 0; + while((pack = tcpc.PopPacket())){ + _log(SOCKET_SERVER__TRACE, "Received Opcode: %4X", pack->opcode); + switch(pack->opcode) { + case 0: { break; } + case ServerOP_KeepAlive: { break; } + } + } + + safe_delete(pack); + return; +} \ No newline at end of file diff --git a/socket_server/worldserver.h b/socket_server/worldserver.h new file mode 100644 index 000000000..167342248 --- /dev/null +++ b/socket_server/worldserver.h @@ -0,0 +1,35 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef WORLDSERVER_H +#define WORLDSERVER_H + +#include "../common/worldconn.h" +#include "../common/eq_packet_structs.h" + +class WorldServer : public WorldConnection +{ + public: + WorldServer(); + virtual ~WorldServer(); + virtual void Process(); + + private: + virtual void OnConnected(); +}; +#endif + diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt deleted file mode 100644 index 4aec544ee..000000000 --- a/utils/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -IF(UNIX) - ADD_DEFINITIONS(-fPIC) -ENDIF(UNIX) - -ADD_SUBDIRECTORY(azone2) diff --git a/utils/azone2/CMakeLists.txt b/utils/azone2/CMakeLists.txt deleted file mode 100644 index 3567df948..000000000 --- a/utils/azone2/CMakeLists.txt +++ /dev/null @@ -1,119 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -IF(NOT MSVC) - ADD_DEFINITIONS(-fpermissive) -ENDIF(NOT MSVC) - -#azone common -SET(azone_common_sources - dat.cpp - file.cpp - global.cpp - pfs.cpp - ter.cpp - wld.cpp - zon.cpp - zonv4.cpp -) - -SET(azone_common_headers - 3d.hpp - 3d_base.hpp - archive.hpp - dat.hpp - file.hpp - file_loader.hpp - global.hpp - octree.hpp - pfs.hpp - s3d.h - ter.hpp - types.h - wld.hpp - wld_structs.hpp - zon.hpp - zonv4.hpp -) - -ADD_LIBRARY(azone_common ${azone_common_sources} ${azone_common_headers}) -SET(LIBRARY_OUTPUT_PATH ../../Bin) - -#azone -SET(azone_sources - azone.cpp -) - -SET(azone_headers - azone.h -) - -ADD_EXECUTABLE(azone ${azone_sources} ${azone_headers}) -TARGET_LINK_LIBRARIES(azone azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(azone PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(azone "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(azone "z") -ENDIF(UNIX) - -SET(EXECUTABLE_OUTPUT_PATH ../../Bin) - -#awater -SET(awater_sources - awater.cpp -) - -SET(awater_headers - awater.h -) - -ADD_EXECUTABLE(awater ${awater_sources} ${awater_headers}) -TARGET_LINK_LIBRARIES(awater azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(awater PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(awater "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(awater "z") -ENDIF(UNIX) - -SET(EXECUTABLE_OUTPUT_PATH ../../Bin) - -#listobj -SET(listobj_sources - listobj.cpp -) - -SET(listobj_headers -) - -ADD_EXECUTABLE(listobj ${listobj_sources} ${listobj_headers}) -TARGET_LINK_LIBRARIES(listobj azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(listobj PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(listobj "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(listobj "z") -ENDIF(UNIX) - -#on windows: glmodelviewer -IF(MSVC) - SET(glmodelviewer_sources - GLModelViewer.cpp - ) - - SET(glmodelviewer_headers - GLModelViewer.h - ) - - ADD_EXECUTABLE(glmodelviewer WIN32 ${glmodelviewer_sources} ${glmodelviewer_headers}) - TARGET_LINK_LIBRARIES(glmodelviewer azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} "opengl32.lib" "GLU32.lib" "Ws2_32.lib") - SET_TARGET_PROPERTIES(glmodelviewer PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - - SET(EXECUTABLE_OUTPUT_PATH ../../Bin) -ENDIF(MSVC) diff --git a/utils/sql/git/optional/2014_06_29_HeadShotRules.sql b/utils/sql/git/optional/2014_06_29_HeadShotRules.sql new file mode 100644 index 000000000..ad3de19b6 --- /dev/null +++ b/utils/sql/git/optional/2014_06_29_HeadShotRules.sql @@ -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) .'); \ No newline at end of file diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql new file mode 100644 index 000000000..3d7a048b6 --- /dev/null +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -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'); \ No newline at end of file diff --git a/world/CMakeLists.txt b/world/CMakeLists.txt index 3ac008267..594f77bc1 100644 --- a/world/CMakeLists.txt +++ b/world/CMakeLists.txt @@ -23,6 +23,7 @@ SET(world_sources perl_EQW.cpp perl_HTTPRequest.cpp queryserv.cpp + socket_server.cpp ucs.cpp wguild_mgr.cpp world_logsys.cpp @@ -53,6 +54,7 @@ SET(world_headers LoginServerList.h net.h queryserv.h + socket_server.h SoFCharCreateData.h ucs.h wguild_mgr.h diff --git a/world/console.cpp b/world/console.cpp index 57161487d..5a9ee60f5 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -46,6 +46,7 @@ #include "LauncherList.h" #include "ucs.h" #include "queryserv.h" +#include "socket_server.h" #ifdef _WINDOWS #define snprintf _snprintf @@ -60,6 +61,7 @@ extern ClientList client_list; extern LauncherList launcher_list; extern UCSConnection UCSLink; extern QueryServConnection QSLink; +extern Socket_Server_Connection SSLink; extern volatile bool RunLoops; ConsoleList console_list; @@ -250,18 +252,26 @@ bool Console::Process() { _log(WORLD__CONSOLE,"New launcher from %s:%d", inet_ntoa(in), GetPort()); launcher_list.Add(tcpc); tcpc = 0; - } else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS) + } + else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS) { _log(WORLD__CONSOLE,"New UCS Connection from %s:%d", inet_ntoa(in), GetPort()); UCSLink.SetConnection(tcpc); tcpc = 0; } - else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ) + else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ) { _log(WORLD__CONSOLE,"New QS Connection from %s:%d", inet_ntoa(in), GetPort()); QSLink.SetConnection(tcpc); tcpc = 0; - } else { + } + else if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeSocket_Server) + { + _log(WORLD__CONSOLE, "New Socket Server Connection from %s:%d", inet_ntoa(in), GetPort()); + SSLink.SetConnection(tcpc); + tcpc = 0; + } + else { _log(WORLD__CONSOLE,"Unsupported packet mode from %s:%d", inet_ntoa(in), GetPort()); } return false; diff --git a/world/net.cpp b/world/net.cpp index d7179bffe..f8d3410c0 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -86,6 +86,7 @@ #include "AdventureManager.h" #include "ucs.h" #include "queryserv.h" +#include "socket_server.h" TimeoutManager timeout_manager; EQStreamFactory eqsf(WorldStream,9000); @@ -97,6 +98,7 @@ LoginServerList loginserverlist; EQWHTTPServer http_server; UCSConnection UCSLink; QueryServConnection QSLink; +Socket_Server_Connection SSLink; LauncherList launcher_list; AdventureManager adventure_manager; DBAsync *dbasync = nullptr; @@ -454,6 +456,8 @@ int main(int argc, char** argv) { QSLink.Process(); + SSLink.Process(); + LFPGroupList.Process(); adventure_manager.Process(); diff --git a/world/socket_server.cpp b/world/socket_server.cpp new file mode 100644 index 000000000..826a95620 --- /dev/null +++ b/world/socket_server.cpp @@ -0,0 +1,127 @@ +#include "../common/debug.h" +#include "Socket_Server.h" +#include "WorldConfig.h" +#include "clientlist.h" +#include "zonelist.h" +#include "../common/logsys.h" +#include "../common/logtypes.h" +#include "../common/md5.h" +#include "../common/EmuTCPConnection.h" +#include "../common/packet_dump.h" + +extern ClientList client_list; +extern ZSList zoneserver_list; + +Socket_Server_Connection::Socket_Server_Connection() +{ + Stream = 0; + authenticated = false; +} + +void Socket_Server_Connection::SetConnection(EmuTCPConnection *inStream) +{ + if(Stream) + { + _log(SOCKET_SERVER__ERROR, "Incoming Socket_Server Connection while we were already connected to a Socket_Server."); + Stream->Disconnect(); + } + + Stream = inStream; + + authenticated = false; +} + +bool Socket_Server_Connection::Process() +{ + if (!Stream || !Stream->Connected()) + return false; + + ServerPacket *pack = 0; + + while((pack = Stream->PopPacket())) + { + if (!authenticated) + { + if (WorldConfig::get()->SharedKey.length() > 0) + { + if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) + { + uint8 tmppass[16]; + + MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass); + + if (memcmp(pack->pBuffer, tmppass, 16) == 0) + authenticated = true; + else + { + struct in_addr in; + in.s_addr = GetIP(); + _log(SOCKET_SERVER__ERROR, "Socket_Server authorization failed."); + ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed); + SendPacket(pack); + delete pack; + Disconnect(); + return false; + } + } + else + { + struct in_addr in; + in.s_addr = GetIP(); + _log(SOCKET_SERVER__ERROR, "Socket_Server_ authorization failed."); + ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed); + SendPacket(pack); + delete pack; + Disconnect(); + return false; + } + } + else + { + _log(SOCKET_SERVER__ERROR,"**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthorized zone access."); + authenticated = true; + } + delete pack; + continue; + } + switch(pack->opcode) + { + case 0: + break; + + case ServerOP_KeepAlive: + { + // ignore this + break; + } + case ServerOP_ZAAuth: + { + _log(SOCKET_SERVER__ERROR, "Got authentication from Socket_Server_ when they are already authenticated."); + break; + } + case ServerOP_LFGuildUpdate: + { + zoneserver_list.SendPacket(pack); + break; + } + default: + { + _log(SOCKET_SERVER__ERROR, "Unknown ServerOPcode from Socket_Server_ 0x%04x, size %d", pack->opcode, pack->size); + DumpPacket(pack->pBuffer, pack->size); + break; + } + } + + delete pack; + } + return(true); +} + +bool Socket_Server_Connection::SendPacket(ServerPacket* pack) +{ + if(!Stream) + return false; + + return Stream->SendPacket(pack); +} + diff --git a/world/socket_server.h b/world/socket_server.h new file mode 100644 index 000000000..7cb39c2d6 --- /dev/null +++ b/world/socket_server.h @@ -0,0 +1,23 @@ +#ifndef Socket_Server__H +#define Socket_Server__H + +#include "../common/types.h" +#include "../common/EmuTCPConnection.h" +#include "../common/servertalk.h" + +class Socket_Server_Connection +{ +public: + Socket_Server_Connection(); + void SetConnection(EmuTCPConnection *inStream); + bool Process(); + bool SendPacket(ServerPacket* pack); + void Disconnect() { if(Stream) Stream->Disconnect(); } + void SendMessage(const char *From, const char *Message); +private: + inline uint32 GetIP() const { return Stream ? Stream->GetrIP() : 0; } + EmuTCPConnection *Stream; + bool authenticated; +}; + +#endif /*Socket_Server__H_*/ diff --git a/zone/AA.cpp b/zone/AA.cpp index 8566c09b5..6e5569c3c 100644 --- a/zone/AA.cpp +++ b/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; diff --git a/zone/AA.h b/zone/AA.h index ccdddf317..3adc887e3 100644 --- a/zone/AA.h +++ b/zone/AA.h @@ -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; diff --git a/zone/attack.cpp b/zone/attack.cpp index 34a1de47d..7b641bd96 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -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) { @@ -1350,7 +1360,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -1965,7 +1975,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -3176,7 +3186,11 @@ int32 Mob::ReduceDamage(int32 damage) if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return -6; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return -6; } } @@ -3188,11 +3202,11 @@ int32 Mob::ReduceDamage(int32 damage) { DisableMeleeRune = true; int damage_to_reduce = damage * spellbonuses.MeleeThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + if(damage_to_reduce >= buffs[slot].melee_rune) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MeleeThresholdGuard %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3212,11 +3226,15 @@ int32 Mob::ReduceDamage(int32 damage) if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateMeleeRune[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + + if (spellbonuses.MitigateMeleeRune[2] && (damage_to_reduce > spellbonuses.MitigateMeleeRune[2])) + damage_to_reduce = spellbonuses.MitigateMeleeRune[2]; + + if(spellbonuses.MitigateMeleeRune[3] && (damage_to_reduce >= buffs[slot].melee_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3224,7 +3242,10 @@ int32 Mob::ReduceDamage(int32 damage) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); - buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + + if (spellbonuses.MitigateMeleeRune[3]) + buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3265,7 +3286,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi int32 slot = -1; // See if we block the spell outright first - if (spellbonuses.NegateAttacks[0]){ + if (!iBuffTic && spellbonuses.NegateAttacks[0]){ slot = spellbonuses.NegateAttacks[1]; if(slot >= 0) { if(--buffs[slot].numhits == 0) { @@ -3273,7 +3294,11 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return 0; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return 0; } } @@ -3286,15 +3311,21 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100; - if(damage_to_reduce > buffs[slot].dot_rune) + + if (spellbonuses.MitigateDotRune[2] && (damage_to_reduce > spellbonuses.MitigateDotRune[2])) + damage_to_reduce = spellbonuses.MitigateDotRune[2]; + + if(spellbonuses.MitigateDotRune[3] && (damage_to_reduce >= buffs[slot].dot_rune)) { - damage -= damage_to_reduce; + damage -= buffs[slot].dot_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } else { - buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + if (spellbonuses.MitigateDotRune[3]) + buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3316,9 +3347,9 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { DisableSpellRune = true; int damage_to_reduce = damage * spellbonuses.SpellThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + if(damage_to_reduce >= buffs[slot].magic_rune) { - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3337,11 +3368,15 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateSpellRune[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + + if (spellbonuses.MitigateSpellRune[2] && (damage_to_reduce > spellbonuses.MitigateSpellRune[2])) + damage_to_reduce = spellbonuses.MitigateSpellRune[2]; + + if(spellbonuses.MitigateSpellRune[3] && (damage_to_reduce >= buffs[slot].magic_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateSpellDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].magic_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3349,7 +3384,10 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].magic_rune); - buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + + if (spellbonuses.MitigateSpellRune[3]) + buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3393,7 +3431,7 @@ int32 Mob::ReduceAllDamage(int32 damage) TryTriggerOnValueAmount(false, true); } - CheckNumHitsRemaining(8); + CheckNumHitsRemaining(NUMHIT_IncomingDamage); return(damage); } @@ -3499,10 +3537,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } if (spell_id == SPELL_UNKNOWN && skill_used) { - CheckNumHitsRemaining(1); //Incoming Hit Attempts + CheckNumHitsRemaining(NUMHIT_IncomingHitAttempts); if (attacker) - attacker->CheckNumHitsRemaining(2); //Outgoing Hit Attempts + attacker->CheckNumHitsRemaining(NUMHIT_OutgoingHitAttempts); } if(attacker){ @@ -3576,7 +3614,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } if (skill_used) - CheckNumHitsRemaining(6); //Incomming Hit Success on Defender + CheckNumHitsRemaining(NUMHIT_IncomingHitSuccess); ReduceAllDamage(damage); @@ -3993,7 +4031,7 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam int chance = ProcChance * (DefensiveProcs[i].chance); if ((MakeRandomInt(0, 100) < chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); - CheckNumHitsRemaining(10,0,DefensiveProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_DefensiveSpellProcs,0,DefensiveProcs[i].base_spellID); } } } @@ -4180,7 +4218,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, "Spell proc %d procing spell %d (%.2f percent chance)", i, SpellProcs[i].spellID, chance); ExecWeaponProc(nullptr, SpellProcs[i].spellID, on); - CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs, 0, SpellProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Spell proc %d failed to proc %d (%.2f percent chance)", @@ -4196,7 +4234,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, "Ranged proc %d procing spell %d (%.2f percent chance)", i, RangedProcs[i].spellID, chance); ExecWeaponProc(nullptr, RangedProcs[i].spellID, on); - CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs, 0, RangedProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Ranged proc %d failed to proc %d (%.2f percent chance)", @@ -4283,6 +4321,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack float critChance = 0.0f; + bool IsBerskerSPA = false; //1: Try Slay Undead if(defender && defender->GetBodyType() == BT_Undead || defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire){ @@ -4310,12 +4349,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack //are defined you will have an innate chance to hit at Level 1 regardless of bonuses. //Warning: Do not define these rules if you want live like critical hits. critChance += RuleI(Combat, MeleeBaseCritChance); - + if (IsClient()) { - critChance += RuleI(Combat, ClientBaseCritChance); + critChance += RuleI(Combat, ClientBaseCritChance); - if ((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) { - if (IsBerserk()) + if (spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA) + IsBerskerSPA = true; + + if (((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) || IsBerskerSPA) { + if (IsBerserk() || IsBerskerSPA) critChance += RuleI(Combat, BerserkBaseCritChance); else critChance += RuleI(Combat, WarBerBaseCritChance); @@ -4360,15 +4402,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack uint16 critMod = 200; bool crip_success = false; int16 CripplingBlowChance = GetCrippBlowChance(); - + //Crippling Blow Chance: The percent value of the effect is applied //to the your Chance to Critical. (ie You have 10% chance to critical and you //have a 200% Chance to Critical Blow effect, therefore you have a 20% Chance to Critical Blow. - if (CripplingBlowChance || IsBerserk()) { - if (!IsBerserk()) + if (CripplingBlowChance || (IsBerserk() || IsBerskerSPA)) { + if (!IsBerserk() && !IsBerskerSPA) critChance *= float(CripplingBlowChance)/100.0f; - if (IsBerserk() || MakeRandomFloat(0, 1) < critChance) { + if ((IsBerserk() || IsBerskerSPA) || MakeRandomFloat(0, 1) < critChance) { critMod = 400; crip_success = true; } @@ -4411,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; } @@ -4449,6 +4489,10 @@ void Mob::DoRiposte(Mob* defender) { defender->spellbonuses.GiveDoubleRiposte[0] + defender->itembonuses.GiveDoubleRiposte[0]; + DoubleRipChance = defender->aabonuses.DoubleRiposte + + defender->spellbonuses.DoubleRiposte + + defender->itembonuses.DoubleRiposte; + //Live AA - Double Riposte if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { mlog(COMBAT__ATTACKS, "Preforming a double riposed (%d percent chance)", DoubleRipChance); @@ -4558,7 +4602,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) int ProcChance = chance * (float)SkillProcs[i].chance; if ((MakeRandomInt(0, 100) < ProcChance)) { ExecWeaponProc(nullptr, SkillProcs[i].spellID, on); - CheckNumHitsRemaining(11,0, SkillProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, SkillProcs[i].base_spellID); } } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index d699cdde2..a316c4b3b 100644 --- a/zone/bonuses.cpp +++ b/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))) @@ -1099,6 +1101,15 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += base1; + else + newbon->DamageModifier2[base2] += base1; + break; + } + case SE_SlayUndead: { if(newbon->SlayUndead[1] < base1) @@ -1107,6 +1118,11 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += base1; + } + case SE_GiveDoubleRiposte: { //0=Regular Riposte 1=Skill Attack Riposte 2=Skill @@ -1188,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; @@ -1234,6 +1249,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_Vampirism: + newbon->Vampirism += base1; + break; + case SE_FrenziedDevastation: newbon->FrenziedDevastation += base2; break; @@ -1242,6 +1261,60 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->SpellProcChance += base1; break; + case SE_Berserk: + newbon->BerserkSPA = true; + break; + + case SE_Metabolism: + 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; + } } } @@ -1813,6 +1886,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_Vampirism: + newbon->Vampirism += effect_value; + break; + case SE_AllInstrumentMod: { if(effect_value > newbon->singingMod) @@ -1909,6 +1986,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += effect_value; + else + newbon->DamageModifier2[base2] += effect_value; + break; + } + case SE_MinDamageModifier: { if(base2 == -1) @@ -2093,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) { @@ -2256,9 +2342,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_NegateAttacks: { - if (!newbon->NegateAttacks[0]){ + if (!newbon->NegateAttacks[0] || + ((newbon->NegateAttacks[0] && newbon->NegateAttacks[2]) && (newbon->NegateAttacks[2] < max))){ newbon->NegateAttacks[0] = 1; newbon->NegateAttacks[1] = buffslot; + newbon->NegateAttacks[2] = max; } break; } @@ -2268,6 +2356,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateMeleeRune[0] < effect_value){ newbon->MitigateMeleeRune[0] = effect_value; newbon->MitigateMeleeRune[1] = buffslot; + newbon->MitigateMeleeRune[2] = base2; + newbon->MitigateMeleeRune[3] = max; } break; } @@ -2298,6 +2388,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateSpellRune[0] < effect_value){ newbon->MitigateSpellRune[0] = effect_value; newbon->MitigateSpellRune[1] = buffslot; + newbon->MitigateSpellRune[2] = base2; + newbon->MitigateSpellRune[3] = max; } break; } @@ -2307,6 +2399,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateDotRune[0] < effect_value){ newbon->MitigateDotRune[0] = effect_value; newbon->MitigateDotRune[1] = buffslot; + newbon->MitigateDotRune[2] = base2; + newbon->MitigateDotRune[3] = max; } break; } @@ -2422,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; @@ -2553,6 +2648,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += effect_value; + } + case SE_GiveDoubleRiposte: { //Only allow for regular double riposte chance. @@ -2661,6 +2761,101 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } break; + case SE_AStacker: + newbon->AStacker[0] = 1; + newbon->AStacker[1] = effect_value; + break; + + case SE_BStacker: + newbon->BStacker[0] = 1; + newbon->BStacker[1] = effect_value; + break; + + case SE_CStacker: + newbon->CStacker[0] = 1; + newbon->CStacker[1] = effect_value; + break; + + case SE_DStacker: + newbon->DStacker[0] = 1; + newbon->DStacker[1] = effect_value; + break; + + case SE_Berserk: + newbon->BerserkSPA = true; + break; + + + case SE_Metabolism: + 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) { @@ -3438,6 +3633,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) break; } + case SE_DamageModifier2: + { + for(int e = 0; e < HIGHEST_SKILL+1; e++) + { + spellbonuses.DamageModifier2[e] = effect_value; + aabonuses.DamageModifier2[e] = effect_value; + itembonuses.DamageModifier2[e] = effect_value; + } + break; + } + case SE_MinDamageModifier: { for(int e = 0; e < HIGHEST_SKILL+1; e++) @@ -3583,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) { @@ -3821,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; @@ -3875,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; @@ -3933,6 +4151,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.MasteryofPast = effect_value; break; + case SE_DoubleRiposte: + spellbonuses.DoubleRiposte = effect_value; + itembonuses.DoubleRiposte = effect_value; + aabonuses.DoubleRiposte = effect_value; + break; + case SE_GiveDoubleRiposte: spellbonuses.GiveDoubleRiposte[0] = effect_value; itembonuses.GiveDoubleRiposte[0] = effect_value; @@ -4033,7 +4257,79 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.AbsorbMagicAtt[0] = effect_value; spellbonuses.AbsorbMagicAtt[1] = -1; break; - + + case SE_Berserk: + spellbonuses.BerserkSPA = false; + aabonuses.BerserkSPA = false; + itembonuses.BerserkSPA = false; + break; + + case SE_Vampirism: + spellbonuses.Vampirism = effect_value; + aabonuses.Vampirism = effect_value; + itembonuses.Vampirism = effect_value; + break; + + case SE_Metabolism: + spellbonuses.Metabolism = effect_value; + 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; + } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index 3b996e7a8..e961bd7ec 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -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))) @@ -3389,7 +3389,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes return; if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){ SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); @@ -6632,7 +6632,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -8092,7 +8092,7 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if (HasDied()) return; if (max_damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ diff --git a/zone/client.cpp b/zone/client.cpp index 7aa7bd748..4ec3ce2d7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8134,20 +8134,12 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ uint16 cons_mod = 180; - switch(GetAA(aaInnateMetabolism)){ - case 1: - cons_mod = cons_mod * 110 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 2: - cons_mod = cons_mod * 125 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 3: - cons_mod = cons_mod * 150 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - default: - cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; - break; - } + int16 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; + + if (metabolism_bonus) + cons_mod = cons_mod * metabolism_bonus * RuleI(Character, ConsumptionMultiplier) / 10000; + else + cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; if(type == ItemTypeFood) { diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 955a29d38..3bf2217cb 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -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; diff --git a/zone/common.h b/zone/common.h index d5f516f63..88600492e 100644 --- a/zone/common.h +++ b/zone/common.h @@ -150,6 +150,20 @@ enum TradeState { TradeCompleting }; +enum { //Numhits type + NUMHIT_IncomingHitAttempts = 1, //Attempted incoming melee attacks (hit or miss) on YOU. + NUMHIT_OutgoingHitAttempts = 2, //Attempted outgoing melee attacks (hit or miss) on YOUR TARGET. + NUMHIT_IncomingSpells = 3, //Incoming detrimental spells + NUMHIT_OutgoingSpells = 4, //Outgoing deterimental spells + NUMHIT_OutgoingHitSuccess = 5, //Successful outgoing melee attack HIT on YOUR TARGET. + NUMHIT_IncomingHitSuccess = 6, //Successful incoming melee attack HIT on YOU. + NUMHIT_MatchingSpells = 7, //Any casted spell matching/triggering a focus effect. + NUMHIT_IncomingDamage = 8, //Successful incoming spell or melee dmg attack on YOU + NUMHIT_ReflectSpell = 9, //Incoming Reflected spells. + NUMHIT_DefensiveSpellProcs = 10, //Defensive buff procs + NUMHIT_OffensiveSpellProcs = 11 //Offensive buff procs +}; + //this is our internal representation of the BUFF struct, can put whatever we want in it struct Buffs_Struct { uint16 spellid; @@ -279,6 +293,7 @@ struct StatBonuses { int16 HitChance; //HitChance/15 == % increase i = Accuracy (Item: Accuracy) int16 HitChanceEffect[HIGHEST_SKILL+2]; //Spell effect Chance to Hit, straight percent increase int16 DamageModifier[HIGHEST_SKILL+2]; //i + int16 DamageModifier2[HIGHEST_SKILL+2]; //i int16 MinDamageModifier[HIGHEST_SKILL+2]; //i int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects int16 ProcChanceSPA; // ProcChance from spell effects @@ -289,7 +304,8 @@ struct StatBonuses { int16 FlurryChance; int16 Accuracy[HIGHEST_SKILL+2]; //Accuracy/15 == % increase [Spell Effect: Accuracy) int16 HundredHands; //extra haste, stacks with all other haste i - int8 MeleeLifetap; //i + int16 MeleeLifetap; //i + int16 Vampirism; //i int16 HealRate; // Spell effect that influences effectiveness of heals int32 MaxHPChange; // Spell Effect int16 SkillDmgTaken[HIGHEST_SKILL+2]; // All Skills + -1 @@ -326,12 +342,12 @@ struct StatBonuses { uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) int16 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage - uint16 NegateAttacks[2]; // 0 = bool HasEffect 1 = Buff Slot - uint16 MitigateMeleeRune[2]; // 0 = Mitigation value 1 = Buff Slot + uint16 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit + uint16 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt 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 + uint16 MitigateSpellRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per spell 3 = Rune Amt + uint16 MitigateDotRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per tick 3 = Rune Amt 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 @@ -350,6 +366,12 @@ 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 +/- + 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. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% @@ -378,6 +400,7 @@ struct StatBonuses { int16 PetCriticalHit; // Allow pets to critical hit with % value. int16 PetAvoidance; // Pet avoidance chance. int16 CombatStability; // Melee damage mitigation. + int16 DoubleRiposte; // Chance to double riposte int16 GiveDoubleRiposte[3]; // 0=Regular Chance, 1=Skill Attack Chance, 2=Skill uint16 RaiseSkillCap[2]; // Raise a specific skill cap (1 = value, 2=skill) int16 Ambidexterity; // Increase chance to duel wield by adding bonus 'skill'. @@ -399,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 diff --git a/zone/groups.cpp b/zone/groups.cpp index aa50ba2c9..6aee5f38b 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -447,7 +447,7 @@ bool Group::UpdatePlayer(Mob* update){ //update their player profile PlayerProfile_Struct &pp = update->CastToClient()->GetPP(); for (i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(membername[0] == '\0') + if(membername[i][0] == '\0') memset(pp.groupMembers[i], 0, 64); else strn0cpy(pp.groupMembers[i], membername[i], 64); @@ -1095,7 +1095,7 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range) } -void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) +void Group::BalanceHP(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1103,7 +1103,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; float distance; float range2 = range*range; @@ -1114,7 +1114,12 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if(members[gi]){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - dmgtaken += (members[gi]->GetMaxHP() - members[gi]->GetHP()); + + dmgtaken_tmp = members[gi]->GetMaxHP() - members[gi]->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -1140,7 +1145,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) } } -void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) +void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1151,14 +1156,19 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { - if(members[gi]){ + if(members[gi] && (members[gi]->GetMaxMana() > 0)){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - manataken += (members[gi]->GetMaxMana() - members[gi]->GetMana()); + + manataken_tmp = members[gi]->GetMaxMana() - members[gi]->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); numMem += 1; } } @@ -1166,6 +1176,10 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + + if (limit && (manataken > limit)) + manataken = limit; + for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ diff --git a/zone/groups.h b/zone/groups.h index c5a3f8ab1..fe21ff3a4 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -86,8 +86,8 @@ public: uint16 GetAvgLevel(); bool LearnMembers(); void VerifyGroup(); - void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, int32 range = 0); inline void SetGroupAAs(GroupLeadershipAA_Struct *From) { memcpy(&LeaderAbilities, From, sizeof(GroupLeadershipAA_Struct)); } inline void GetGroupAAs(GroupLeadershipAA_Struct *Into) { memcpy(Into, &LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); } diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index cfe21dc51..645932d1b 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -27,7 +27,7 @@ struct Appearances { }; struct lua_registered_event { std::string encounter_name; - luabind::object lua_reference; + luabind::adl::object lua_reference; QuestEventID event_id; }; @@ -43,7 +43,7 @@ void unload_encounter(std::string name) { parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0); } -void register_event(std::string package_name, std::string name, int evt, luabind::object func) { +void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) { lua_registered_event e; e.encounter_name = name; e.lua_reference = func; @@ -84,7 +84,7 @@ void unregister_event(std::string package_name, std::string name, int evt) { } } -void register_npc_event(std::string name, int evt, int npc_id, luabind::object func) { +void register_npc_event(std::string name, int evt, int npc_id, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { std::stringstream package_name; package_name << "npc_" << npc_id; @@ -100,7 +100,7 @@ void unregister_npc_event(std::string name, int evt, int npc_id) { unregister_event(package_name.str(), name, evt); } -void register_player_event(std::string name, int evt, luabind::object func) { +void register_player_event(std::string name, int evt, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { register_event("player", name, evt, func); } @@ -110,7 +110,7 @@ void unregister_player_event(std::string name, int evt) { unregister_event("player", name, evt); } -void register_item_event(std::string name, int evt, int item_id, luabind::object func) { +void register_item_event(std::string name, int evt, int item_id, luabind::adl::object func) { std::string package_name = "item_"; package_name += std::to_string(static_cast(item_id)); @@ -126,7 +126,7 @@ void unregister_item_event(std::string name, int evt, int item_id) { unregister_event(package_name, name, evt); } -void register_spell_event(std::string name, int evt, int spell_id, luabind::object func) { +void register_spell_event(std::string name, int evt, int spell_id, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { std::stringstream package_name; package_name << "spell_" << spell_id; @@ -392,7 +392,7 @@ bool lua_bury_player_corpse(uint32 char_id) { return quest_manager.buryplayercorpse(char_id); } -void lua_task_selector(luabind::object table) { +void lua_task_selector(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -422,7 +422,7 @@ void lua_task_set_selector(int task_set) { quest_manager.tasksetselector(task_set); } -void lua_enable_task(luabind::object table) { +void lua_enable_task(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -449,7 +449,7 @@ void lua_enable_task(luabind::object table) { quest_manager.enabletask(count, tasks); } -void lua_disable_task(luabind::object table) { +void lua_disable_task(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -743,8 +743,8 @@ void lua_cross_zone_message_player_by_name(uint32 type, const char *player, cons quest_manager.CrossZoneMessagePlayerByName(type, player, message); } -luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = npc; Client *c = client; @@ -759,8 +759,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { return ret; } -luabind::object lua_get_qglobals(lua_State *L, Lua_Client client) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_Client client) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = nullptr; Client *c = client; @@ -775,8 +775,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_Client client) { return ret; } -luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = npc; Client *c = nullptr; @@ -791,8 +791,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { return ret; } -luabind::object lua_get_qglobals(lua_State *L) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = nullptr; Client *c = nullptr; @@ -846,8 +846,8 @@ int lua_get_zone_instance_version() { return zone->GetInstanceVersion(); } -luabind::object lua_get_characters_in_instance(lua_State *L, uint16 instance_id) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_characters_in_instance(lua_State *L, uint16 instance_id) { + luabind::adl::object ret = luabind::newtable(L); std::list charid_list; uint16 i = 1; @@ -868,11 +868,11 @@ int lua_get_zone_weather() { return zone->zone_weather; } -luabind::object lua_get_zone_time(lua_State *L) { +luabind::adl::object lua_get_zone_time(lua_State *L) { TimeOfDay_Struct eqTime; zone->zone_time.getEQTimeOfDay(time(0), &eqTime); - luabind::object ret = luabind::newtable(L); + luabind::adl::object ret = luabind::newtable(L); ret["zone_hour"] = eqTime.hour - 1; ret["zone_minute"] = eqTime.minute; ret["zone_time"] = (eqTime.hour - 1) * 100 + eqTime.minute; @@ -909,7 +909,7 @@ void lua_remove_spawn_point(uint32 spawn2_id) { } } -void lua_add_spawn_point(luabind::object table) { +void lua_add_spawn_point(luabind::adl::object table) { if(!zone) return; @@ -1280,10 +1280,10 @@ luabind::scope lua_register_general() { luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id), luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name), luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_Client))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_NPC))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_Client))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*))&lua_get_qglobals), luabind::def("get_entity_list", &lua_get_entity_list), luabind::def("get_zone_id", &lua_get_zone_id), luabind::def("get_zone_long_name", &lua_get_zone_long_name), diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 17588caef..50a8b50a7 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -103,7 +103,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket return self->Attack(other, hand, from_riposte, is_strikethrough, is_from_spell); } -bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::object opts) { +bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::adl::object opts) { Lua_Safe_Call_Bool(); ExtraAttackOptions options; @@ -1429,7 +1429,7 @@ void Lua_Mob::SetGender(int in) { self->SendIllusionPacket(self->GetRace(), in); } -void Lua_Mob::SendIllusionPacket(luabind::object illusion) { +void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { Lua_Safe_Call_Void(); if(luabind::type(illusion) != LUA_TTABLE) { @@ -1881,7 +1881,7 @@ luabind::scope lua_register_mob() { .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool))&Lua_Mob::Attack) - .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool,luabind::object))&Lua_Mob::Attack) + .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool,luabind::adl::object))&Lua_Mob::Attack) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int))&Lua_Mob::Damage) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool))&Lua_Mob::Damage) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool,int))&Lua_Mob::Damage) @@ -2125,7 +2125,7 @@ luabind::scope lua_register_mob() { .def("SetTexture", (void(Lua_Mob::*)(int))&Lua_Mob::SetTexture) .def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace) .def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender) - .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::object))&Lua_Mob::SendIllusionPacket) + .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::QuestReward) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32))&Lua_Mob::QuestReward) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32))&Lua_Mob::QuestReward) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index b3e44805a..a5c00c5f0 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -47,7 +47,7 @@ public: bool Attack(Lua_Mob other, int hand, bool from_riposte); bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough); bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell); - bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::object opts); + bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::adl::object opts); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable, int buffslot); @@ -294,7 +294,7 @@ public: void SetTexture(int in); void SetRace(int in); void SetGender(int in); - void SendIllusionPacket(luabind::object illusion); + void SendIllusionPacket(luabind::adl::object illusion); void QuestReward(Lua_Client c); void QuestReward(Lua_Client c, uint32 silver); void QuestReward(Lua_Client c, uint32 silver, uint32 gold); diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index c3cb841af..9f082993c 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -121,7 +121,7 @@ extern Zone *zone; struct lua_registered_event { std::string encounter_name; - luabind::object lua_reference; + luabind::adl::object lua_reference; QuestEventID event_id; }; @@ -257,7 +257,7 @@ int LuaParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string } int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -275,7 +275,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M lua_createtable(L, 0, 0); //always push self Lua_NPC l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "self"); @@ -352,7 +352,7 @@ int LuaParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string d } int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -369,7 +369,7 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * lua_createtable(L, 0, 0); //push self Lua_Client l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "self"); @@ -429,7 +429,7 @@ int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob * } int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, - std::string data, uint32 extra_data, std::vector *extra_pointers, luabind::object *l_func) { + std::string data, uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -446,12 +446,12 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl lua_createtable(L, 0, 0); //always push self Lua_ItemInst l_item(item); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "self"); Lua_Client l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "owner"); @@ -508,7 +508,7 @@ int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spe } int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -528,11 +528,11 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, //always push self even if invalid if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } lua_setfield(L, -2, "self"); diff --git a/zone/lua_parser.h b/zone/lua_parser.h index 7c4843ccd..b30e3d3b7 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -17,7 +17,9 @@ class NPC; struct lua_registered_event; namespace luabind { - class object; + namespace adl { + class object; + } } class LuaParser : public QuestInterface { @@ -73,13 +75,13 @@ public: private: int _EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, - uint32 extra_data, std::vector *extra_pointers, luabind::object *l_func = nullptr); + uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector *extra_pointers); diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index c46107844..8064106dc 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -31,7 +31,7 @@ void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in npc->DoQuestPause(init); Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -45,7 +45,7 @@ void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -57,7 +57,7 @@ void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob * for(size_t i = 0; i < extra_pointers->size(); ++i) { std::string prefix = "item" + std::to_string(static_cast(i + 1)); Lua_ItemInst l_inst = reinterpret_cast(extra_pointers->at(i)); - luabind::object l_inst_o = luabind::object(L, l_inst); + luabind::adl::object l_inst_o = luabind::adl::object(L, l_inst); l_inst_o.push(L); lua_setfield(L, -2, prefix.c_str()); @@ -98,7 +98,7 @@ void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); } @@ -106,7 +106,7 @@ void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -114,7 +114,7 @@ void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_NPC l_npc(reinterpret_cast(init)); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "other"); } @@ -122,7 +122,7 @@ void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -133,7 +133,7 @@ void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -144,7 +144,7 @@ void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -155,7 +155,7 @@ void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -179,7 +179,7 @@ void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -190,12 +190,12 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, int spell_id = std::stoi(sep.arg[1]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -209,12 +209,12 @@ void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s int spell_id = std::stoi(data); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -249,7 +249,7 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st Mob *o = entity_list.GetMobID(std::stoi(sep.arg[0])); Lua_Mob l_mob(o); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -259,12 +259,12 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st int spell_id = std::stoi(sep.arg[2]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -284,12 +284,12 @@ void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* cl const Item_Struct *item = database.GetItem(extra_data); if(item) { Lua_Item l_item(item); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } else { Lua_Item l_item(nullptr); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -298,7 +298,7 @@ void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* cl void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -306,7 +306,7 @@ void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Clie void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Object l_object(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_object_o = luabind::object(L, l_object); + luabind::adl::object l_object_o = luabind::adl::object(L, l_object); l_object_o.push(L); lua_setfield(L, -2, "object"); } @@ -314,7 +314,7 @@ void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* cli void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Door l_door(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_door_o = luabind::object(L, l_door); + luabind::adl::object l_door_o = luabind::adl::object(L, l_door); l_door_o.push(L); lua_setfield(L, -2, "door"); } @@ -334,7 +334,7 @@ void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* c void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -344,11 +344,11 @@ void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std int spell_id = std::stoi(data); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } @@ -370,7 +370,7 @@ void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(extra_pointers->at(1))); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -378,7 +378,7 @@ void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -386,12 +386,12 @@ void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); Lua_Corpse l_corpse(reinterpret_cast(extra_pointers->at(1))); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } @@ -426,7 +426,7 @@ void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, lua_pushstring(L, command.c_str()); lua_setfield(L, -2, "command"); - luabind::object args = luabind::newtable(L); + luabind::adl::object args = luabind::newtable(L); int max_args = sep.GetMaxArgNum(); for(int i = 1; i < max_args; ++i) { if(strlen(sep.arg[i]) > 0) { @@ -450,7 +450,7 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_NPC l_npc(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "other"); } @@ -476,7 +476,7 @@ void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Packet l_packet(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_packet_o = luabind::object(L, l_packet); + luabind::adl::object l_packet_o = luabind::adl::object(L, l_packet); l_packet_o.push(L); lua_setfield(L, -2, "packet"); @@ -505,18 +505,18 @@ void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemI std::vector *extra_pointers) { Lua_Mob l_mob(mob); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "target"); if(IsValidSpell(extra_data)) { Lua_Spell l_spell(&spells[extra_data]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -526,12 +526,12 @@ void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemI std::vector *extra_pointers) { if(mob && mob->IsCorpse()) { Lua_Corpse l_corpse(mob->CastToCorpse()); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } else { Lua_Corpse l_corpse(nullptr); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } @@ -546,7 +546,7 @@ void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, Item void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "aug"); @@ -557,7 +557,7 @@ void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, It void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); @@ -568,7 +568,7 @@ void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* cli void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); @@ -588,15 +588,15 @@ void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -613,15 +613,15 @@ void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* cli std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -644,15 +644,15 @@ void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -669,15 +669,15 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } diff --git a/zone/mob.cpp b/zone/mob.cpp index d5ff23a7d..ee468a0e6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -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; @@ -3155,7 +3157,7 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger) if(IsValidSpell(trigger_spell_id) && GetTarget()){ SpellFinished(trigger_spell_id, GetTarget(),10, 0, -1, spells[trigger_spell_id].ResistDiff); - CheckNumHitsRemaining(7,0, focus_spell); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,0, focus_spell); } } } @@ -3408,7 +3410,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining) value += tmp_focus; if (tmp_buffslot >= 0) - CheckNumHitsRemaining(7, tmp_buffslot); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, tmp_buffslot); } return value; } @@ -3509,7 +3511,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id) SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff); } - CheckNumHitsRemaining(7, 0, focus_spell); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, 0, focus_spell); } } @@ -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) { @@ -4277,6 +4279,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]; + dmg_mod += itembonuses.DamageModifier2[HIGHEST_SKILL+1] + spellbonuses.DamageModifier2[HIGHEST_SKILL+1] + aabonuses.DamageModifier2[HIGHEST_SKILL+1] + + itembonuses.DamageModifier2[skill] + spellbonuses.DamageModifier2[skill] + aabonuses.DamageModifier2[skill]; + if (HasShieldEquiped() && !IsOffHandAtk()) dmg_mod += itembonuses.ShieldEquipDmgMod[0] + spellbonuses.ShieldEquipDmgMod[0] + aabonuses.ShieldEquipDmgMod[0]; @@ -4334,22 +4339,19 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) 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; + int16 lifetap_amt = 0; + lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap + + spellbonuses.Vampirism + itembonuses.Vampirism + aabonuses.Vampirism; + if(lifetap_amt && damage > 0){ 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 (lifetap_amt > 0) + HealDamage(lifetap_amt); //Heal self for modified damage amount. + else + Damage(this, -lifetap_amt,0, SkillEvocation,false); //Dmg self for modified damage amount. } } diff --git a/zone/mob.h b/zone/mob.h index c3de2b576..5c1240e83 100644 --- a/zone/mob.h +++ b/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); @@ -800,7 +805,7 @@ public: uint16 GetInstrumentMod(uint16 spell_id) const; int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); - virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr); + virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } // HP Event @@ -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; diff --git a/zone/npc.cpp b/zone/npc.cpp index 3886d7c66..38989bccb 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -599,19 +599,19 @@ bool NPC::Process() //Lieka Edit:Fixing NPC regen.NPCs should regen to full during a set duration, not based on their HPs.Increase NPC's HPs by % of total HPs / tick. if((GetHP() < GetMaxHP()) && !IsPet()) { if(!IsEngaged()) {//NPC out of combat - if(hp_regen > OOCRegen) - SetHP(GetHP() + hp_regen); + if(GetNPCHPRegen() > OOCRegen) + SetHP(GetHP() + GetNPCHPRegen()); else SetHP(GetHP() + OOCRegen); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); } else if(GetHP() < GetMaxHP() && GetOwnerID() !=0) { if(!IsEngaged()) //pet - SetHP(GetHP()+hp_regen+bonus+(GetLevel()/5)); + SetHP(GetHP()+GetNPCHPRegen()+bonus+(GetLevel()/5)); else - SetHP(GetHP()+hp_regen+bonus); + SetHP(GetHP()+GetNPCHPRegen()+bonus); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); if(GetMana() < GetMaxMana()) { SetMana(GetMana()+mana_regen+bonus); diff --git a/zone/npc.h b/zone/npc.h index ae444c099..07c81e79b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -256,6 +256,7 @@ public: virtual void DoClassAttacks(Mob *target); void CheckSignal(); inline bool IsTargetableWithHotkey() const { return no_target_hotkey; } + int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } //waypoint crap int GetMaxWp() const { return max_wp; } diff --git a/zone/raids.cpp b/zone/raids.cpp index bf6f76d5c..c712fc4bd 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -504,7 +504,7 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range) } -void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -512,7 +512,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; int gi = 0; float distance; @@ -525,7 +525,12 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) { distance = caster->DistNoRoot(*members[gi].member); if(distance <= range2){ - dmgtaken += (members[gi].member->GetMaxHP() - members[gi].member->GetHP()); + + dmgtaken_tmp = members[gi].member->GetMaxHP() - members[gi].member->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -555,7 +560,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) } } -void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -566,17 +571,24 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; int gi = 0; for(; gi < MAX_RAID_MEMBERS; gi++) { if(members[gi].member){ if(members[gi].GroupNumber == gid) { - distance = caster->DistNoRoot(*members[gi].member); - if(distance <= range2){ - manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana()); - numMem += 1; + if (members[gi].member->GetMaxMana() > 0) { + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ + + manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); + numMem += 1; + } } } } @@ -584,6 +596,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + for(gi = 0; gi < MAX_RAID_MEMBERS; gi++) { if(members[gi].member){ diff --git a/zone/raids.h b/zone/raids.h index c8c2f61e4..be12788e6 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -147,8 +147,8 @@ public: void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid); void SplitExp(uint32 exp, Mob* other); uint32 GetTotalRaidDamage(Mob* other); - void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range = 0); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4bbd808cc..4ffa21ab4 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -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) { @@ -156,7 +159,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if (HasDied()) return; if (max_damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ @@ -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) { @@ -951,14 +957,17 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item TryCriticalHit(other, SkillArchery, TotalDmg); other->AddToHateList(this, hate, 0, false); - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } } 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 @@ -1056,7 +1065,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); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } else { @@ -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) { @@ -1281,7 +1301,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); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } } @@ -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(weapon_speed) * + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + ProcBonus += static_cast(mydex/35) + static_cast(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(mydex/35) + static_cast(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(ReuseTime*1000) * + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + ProcBonus += (10 + (static_cast(mydex/10) + static_cast(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(mydex/10) + static_cast(itembonuses.HeroicDEX /10)))/100.0f; + + } + + return ProcChance; } void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) @@ -2196,7 +2234,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (HasDied()) return; - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){ int kb_chance = 25; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 4e10160ed..090fb4b75 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -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); } @@ -2393,7 +2405,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceHP(spell.base[i], gid, spell.range, caster); + r->BalanceHP(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2403,7 +2415,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceHP(spell.base[i], spell.range, caster); + g->BalanceHP(spell.base[i], spell.range, caster, spell.base2[i]); break; } @@ -2421,7 +2433,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceMana(spell.base[i], gid, spell.range, caster); + r->BalanceMana(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2431,7 +2443,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceMana(spell.base[i], spell.range, caster); + g->BalanceMana(spell.base[i], spell.range, caster, spell.base2[i]); break; } @@ -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; } @@ -2668,6 +2683,55 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) SlowMitigation(caster); break; + case SE_AddHatePct: + { + 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; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: @@ -2738,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: @@ -2797,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: @@ -2823,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: @@ -2837,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: @@ -2855,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: @@ -2886,6 +2952,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitCastTimeMax: case SE_TriggerOnReqCaster: case SE_FrenziedDevastation: + case SE_AStacker: + case SE_BStacker: + case SE_CStacker: + case SE_DStacker: + case SE_DoubleRiposte: + case SE_Berserk: + case SE_Vampirism: + case SE_Metabolism: { break; } @@ -3324,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){ @@ -3518,6 +3592,18 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste } } + case SE_AddHateOverTimePct: + { + 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; + } + default: { // do we need to do anyting here? @@ -5251,7 +5337,7 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) 1: [Incoming Hit Attempts] (323=SE_DefensiveProc, 172=SE_AvoidMeleeChance, 1=SE_ArmorClass, 40=SE_DivineAura) 2: [Outgoing Hit Attempts] (185=SE_DamageModifer, 184=SE_HitChance) 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_FcSpellVulnerability) //Note: Determinetal spells only unless proven otherwise - 4: NONE + 4: [Outgoing Spells] 5: [Outgoing Hit Successes] (220=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnWearoff) 6: [Incoming Hit Successes] (59=SE_DamageShield, 197=SE_SkillDamageTaken, 162=define SE_MitigateMeleeDamage) 7: [Matching Spells] *When focus is triggered (focus effects) @@ -5567,7 +5653,7 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, } if ((!limit_exists) || (limit_exists && skill_found)){ dmg += temp_dmg; - CheckNumHitsRemaining(7,i); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,i); } } @@ -5575,7 +5661,7 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, int32 focus = caster->CalcFocusEffect(focusFcDamageAmtIncoming, buffs[i].spellid, spell_id); if(focus){ dmg += focus; - CheckNumHitsRemaining(7,i); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,i); } } } @@ -5629,7 +5715,7 @@ int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spel value = tmp_focus; if (tmp_buffslot >= 0) - CheckNumHitsRemaining(7, tmp_buffslot); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, tmp_buffslot); } } @@ -5718,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; diff --git a/zone/spells.cpp b/zone/spells.cpp index 54e98613e..59dbb6625 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -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 @@ -1250,7 +1250,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } if(IsClient()) { - CheckNumHitsRemaining(7); + CheckNumHitsRemaining(NUMHIT_MatchingSpells); TrySympatheticProc(target, spell_id); } @@ -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 { @@ -2542,7 +2542,7 @@ int CalcBuffDuration_formula(int level, int formula, int duration) // -1 if they can't stack and spellid2 should be stopped //currently, a spell will not land if it would overwrite a better spell on any effect //if all effects are better or the same, we overwrite, else we do nothing -int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2) +int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2, int buffslot) { const SPDat_Spell_Struct &sp1 = spells[spellid1]; const SPDat_Spell_Struct &sp2 = spells[spellid2]; @@ -2621,6 +2621,36 @@ 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.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[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[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; + } + if(effect2 == SE_StackingCommand_Overwrite) { overwrite_effect = sp2.base[i]; @@ -2901,7 +2931,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (curbuf.spellid != SPELL_UNKNOWN) { // there's a buff in this slot ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spell_id, - caster_level, entity_list.GetMobID(curbuf.casterid), caster); + caster_level, entity_list.GetMobID(curbuf.casterid), caster, buffslot); if (ret == -1) { // stop the spell mlog(SPELLS__BUFFS, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d", spell_id, curbuf.spellid, buffslot, curbuf.casterlevel); @@ -3047,7 +3077,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) return(-1); //do not recast a buff we already have on, we recast fast enough that we dont need to refresh our buffs // there's a buff in this slot - ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level); + ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level, nullptr, nullptr, i); if(ret == 1) { // should overwrite current slot if(iFailIfOverwrite) { @@ -3383,7 +3413,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r if(IsEffectInSpell(buffs[b].spellid, SE_BlockNextSpellFocus)) { focus = CalcFocusEffect(focusBlockNextSpell, buffs[b].spellid, spell_id); if(focus) { - CheckNumHitsRemaining(7,b); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,b); Message_StringID(MT_SpellFailure, SPELL_WOULDNT_HOLD); safe_delete(action_packet); return false; @@ -3432,7 +3462,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } if(reflect_chance) { Message_StringID(MT_Spells, SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName()); - CheckNumHitsRemaining(9); + CheckNumHitsRemaining(NUMHIT_ReflectSpell); SpellOnTarget(spell_id, this, true, use_resist_adjust, resist_adjust); safe_delete(action_packet); return false; @@ -3483,7 +3513,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } - spelltar->CheckNumHitsRemaining(3); + spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells); + CheckNumHitsRemaining(NUMHIT_OutgoingSpells); safe_delete(action_packet); return false; @@ -3636,8 +3667,13 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } - if (spelltar && IsDetrimentalSpell(spell_id)) - spelltar->CheckNumHitsRemaining(3); //Incoming spells + if (IsDetrimentalSpell(spell_id)) { + + CheckNumHitsRemaining(NUMHIT_OutgoingSpells); + + if (spelltar) + spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells); + } // 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