Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Arthur Ice 2014-07-03 15:05:22 -07:00
commit 53fd5e0a5c
52 changed files with 2059 additions and 628 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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 )

View File

@ -8,6 +8,7 @@ enum EQEmuExePlatform
ExePlatformWorld,
ExePlatformLogin,
ExePlatformQueryServ,
ExePlatformSocket_Server,
ExePlatformUCS,
ExePlatformLaunch,
ExePlatformSharedMemory,

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -13,12 +13,17 @@
# include <boost/mpl/next.hpp>
# include <boost/mpl/size.hpp>
namespace luabind {
namespace luabind { namespace adl {
class object;
class argument;
template <class Base>
struct table;
class object;
class argument;
template <class Base>
struct table;
} // namespace adl
using adl::object;
using adl::argument;
using adl::table;
} // namespace luabind

View File

@ -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)

131
socket_server/database.cpp Normal file
View File

@ -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 <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errmsg.h>
#include <mysqld_error.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
#include <map>
// Disgrace: for windows compile
#ifdef _WINDOWS
#include <windows.h>
#define snprintf _snprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include "../common/unix.h"
#include <netinet/in.h>
#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;
}

54
socket_server/database.h Normal file
View File

@ -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 <string>
#include <vector>
#include <map>
//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

View File

@ -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 <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
/*#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>*/
#include <websocketpp/common/thread.hpp>
typedef websocketpp::server<websocketpp::config::asio> 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 <list>
#include <signal.h>
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<mutex> 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<mutex> 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<mutex> 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<mutex> 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<mutex> con_lock(m_connection_lock);
m_connections.insert(a.hdl);
}
else if (a.type == UNSUBSCRIBE) {
unique_lock<mutex> con_lock(m_connection_lock);
m_connections.erase(a.hdl);
}
else if (a.type == MESSAGE) {
unique_lock<mutex> 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<connection_hdl, std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
std::queue<action> 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
}

View File

@ -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));
}

View File

@ -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

View File

@ -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 <iostream>
#include <string.h>
#include <stdio.h>
#include <iomanip>
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#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;
}

View File

@ -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

View File

@ -1,7 +0,0 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
IF(UNIX)
ADD_DEFINITIONS(-fPIC)
ENDIF(UNIX)
ADD_SUBDIRECTORY(azone2)

View File

@ -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)

View File

@ -0,0 +1,2 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AdjustSpecialProcPerMinute', 'false', 'Allow PPM for special abilities HeadShot, Assassinate, Decap ect.');
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AvgSpecialProcsPerMinute', '2.0', 'Set PPM for special abilities HeadShot, Assassinate, Decap ect. (Unknown what value live uses) .');

View File

@ -0,0 +1,34 @@
-- AA MGB update
UPDATE altadv_vars SET spellid = 5228 WHERE skill_id = 128;
UPDATE aa_actions SET spell_id = 5228, nonspell_action = 0 WHERE aaid = 128;
-- AA Project Illusion update
UPDATE altadv_vars SET spellid = 5227 WHERE skill_id = 643;
UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643;
-- AA Improved Reclaim Energy
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('180', '1', '241', '95', '0');
-- AA Headshot
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0');
-- AA Anatomy (Rogue Assassinate)
INSERT INTO `altadv_vars` (`skill_id`, `name`, `cost`, `max_level`, `hotkey_sid`, `hotkey_sid2`, `title_sid`, `desc_sid`, `type`, `spellid`, `prereq_skill`, `prereq_minpoints`, `spell_type`, `spell_refresh`, `classes`, `berserker`, `class_type`, `cost_inc`, `aa_expansion`, `special_category`, `sof_type`, `sof_cost_inc`, `sof_max_level`, `sof_next_skill`, `clientver`, `account_time_required`, `sof_current_level`,`sof_next_id`,`level_inc`) VALUES ('1604', 'Anatomy', '5', '3', '4294967295', '4294967295', '1604', '1604', '1', '4294967295', '0', '0', '0', '0', '512', '0', '60', '1', '10', '4294967295', '3', '0', '3', '1604', '1', '0', '0', '0', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '2', '345', '48', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0');
-- AA Finishing Blow Fix
DELETE FROM aa_effects WHERE aaid = 199 AND slot = 2;
DELETE FROM aa_effects WHERE aaid = 200 AND slot = 2;
DELETE FROM aa_effects WHERE aaid = 201 AND slot = 2;
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '2', '440', '50', '200');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '2', '440', '52', '200');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '2', '440', '54', '200');

View File

@ -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

View File

@ -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;

View File

@ -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();

127
world/socket_server.cpp Normal file
View File

@ -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 <key>STRING</key> element to your <world> 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);
}

23
world/socket_server.h Normal file
View File

@ -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_*/

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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){

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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]){

View File

@ -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)); }

View File

@ -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<long long>(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<uint32> 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),

View File

@ -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)

View File

@ -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);

View File

@ -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<void*> *extra_pointers, luabind::object *l_func) {
std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func) {
std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func) {
std::string data, uint32 extra_data, std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func) {
std::vector<void*> *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");

View File

@ -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<void*> *extra_pointers, luabind::object *l_func = nullptr);
std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func = nullptr);
std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func = nullptr);
uint32 extra_data, std::vector<void*> *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<void*> *extra_pointers, luabind::object *l_func = nullptr);
std::vector<void*> *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<void*> *extra_pointers);

View File

@ -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<Client*>(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<void*> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(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<long long>(i + 1));
Lua_ItemInst l_inst = reinterpret_cast<ItemInst*>(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<void*> *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<void*> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(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<void*> *extra_pointers) {
Lua_NPC l_npc(reinterpret_cast<NPC*>(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<void*> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(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<void*> *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<void*> *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<void*> *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<void*> *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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<void*> *extra_pointers) {
Lua_Object l_object(reinterpret_cast<Object*>(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<void*> *extra_pointers) {
Lua_Door l_door(reinterpret_cast<Doors*>(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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<void*> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(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<void*> *extra_pointers) {
Lua_Client l_client(reinterpret_cast<Client*>(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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<Corpse*>(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<void*> *extra_pointers) {
Lua_NPC l_npc(reinterpret_cast<NPC*>(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<void*> *extra_pointers) {
Lua_Packet l_packet(reinterpret_cast<EQApplicationPacket*>(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<void*> *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<void*> *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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<void*> *extra_pointers) {
Lua_ItemInst l_item(reinterpret_cast<ItemInst*>(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<void*> *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<void*> *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<void*> *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<void*> *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);
}

View File

@ -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.
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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; }

View File

@ -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){

View File

@ -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);

View File

@ -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<float>(weapon_speed) *
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
ProcBonus += static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25);
ProcChance += ProcChance * ProcBonus / 100.0f;
} else {
/*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.”
Kayen: Most reports suggest a ~ 6% chance to Headshot which consistent with above.*/
ProcChance = (static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25))/100.0f;
}
return ProcChance;
}
uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime) {
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() &&
(skillInUse == SkillBackstab || skillInUse == SkillThrowing)) {
uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1];
uint8 Assassinate_Level = 0; //Get Highest Headshot Level
Assassinate_Level = aabonuses.AssassinateLevel;
if (Assassinate_Level < spellbonuses.AssassinateLevel)
Assassinate_Level = spellbonuses.AssassinateLevel;
else if (Assassinate_Level < itembonuses.AssassinateLevel)
Assassinate_Level = itembonuses.AssassinateLevel;
if (GetLevel() >= 60){ //Innate Assassinate Ability if client as no bonuses.
if (!Assassinate_Level)
Assassinate_Level = 45;
if (!Assassinate_Dmg)
Assassinate_Dmg = 32000;
}
if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){
float ProcChance = 0.0f;
if (skillInUse == SkillThrowing)
ProcChance = GetSpecialProcChances(11);
else
ProcChance = GetAssassinateProcChances(ReuseTime);
if(ProcChance > MakeRandomFloat(0,1))
return Assassinate_Dmg;
}
}
return 0;
}
float Mob::GetAssassinateProcChances(uint16 ReuseTime)
{
int mydex = GetDEX();
if (mydex > 255)
mydex = 255;
float ProcChance = 0.0f;
float ProcBonus = 0.0f;
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
ProcChance = (static_cast<float>(ReuseTime*1000) *
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
ProcBonus += (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
ProcChance += ProcChance * ProcBonus / 100.0f;
} else {
/*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/
ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
}
return ProcChance;
}
void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte)
@ -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;

View File

@ -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;

View File

@ -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