diff options
48 files changed, 2303 insertions, 1122 deletions
diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index 67e3e42f2ae..c2677953027 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -40,7 +40,7 @@ namespace FactorySelector //scriptname in db if (!ai_factory) - if (CreatureAI* scriptedAI = sScriptMgr.GetAI(creature)) + if (CreatureAI* scriptedAI = sScriptMgr.GetCreatureAI(creature)) return scriptedAI; // AIname in db diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 9ab9e06b624..c3b132026a1 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -16,7 +16,7 @@ struct TSpellSummary { uint8 Targets; // set of enum SelectTarget uint8 Effects; // set of enum SelectEffect -} *SpellSummary; +} extern *SpellSummary; void SummonList::DoZoneInCombat(uint32 entry) { @@ -309,91 +309,6 @@ bool ScriptedAI::CanCast(Unit* pTarget, SpellEntry const* pSpell, bool bTriggere return true; } -void FillSpellSummary() -{ - SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()]; - - SpellEntry const* pTempSpell; - - for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) - { - SpellSummary[i].Effects = 0; - SpellSummary[i].Targets = 0; - - pTempSpell = GetSpellStore()->LookupEntry(i); - //This spell doesn't exist - if (!pTempSpell) - continue; - - for (uint32 j = 0; j < 3; ++j) - { - //Spell targets self - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); - - //Spell targets a single enemy - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); - - //Spell targets AoE at enemy - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); - - //Spell targets an enemy - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); - - //Spell targets a single friend(or self) - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); - - //Spell targets aoe friends - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); - - //Spell targets any friend(or self) - if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || - pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || - pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) - SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); - - //Make sure that this spell includes a damage effect - if (pTempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || - pTempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || - pTempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || - pTempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); - - //Make sure that this spell includes a healing effect (or an apply aura with a periodic heal) - if (pTempSpell->Effect[j] == SPELL_EFFECT_HEAL || - pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || - pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || - (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && pTempSpell->EffectApplyAuraName[j] == 8)) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); - - //Make sure that this spell applies an aura - if (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) - SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); - } - } -} - void ScriptedAI::DoResetThreat() { if (!me->CanHaveThreatList() || me->getThreatManager().isThreatListEmpty()) @@ -702,25 +617,6 @@ void BossAI::SummonedCreatureDespawn(Creature *summon) summons.Despawn(summon); } -#define GOBJECT(x) (const_cast<GameObjectInfo*>(GetGameObjectInfo(x))) - -void LoadOverridenSQLData() -{ - GameObjectInfo *goInfo; - - // Sunwell Plateau : Kalecgos : Spectral Rift - goInfo = GOBJECT(187055); - if (goInfo) - if (goInfo->type == GAMEOBJECT_TYPE_GOOBER) - goInfo->goober.lockId = 57; // need LOCKTYPE_QUICK_OPEN - - // Naxxramas : Sapphiron Birth - goInfo = GOBJECT(181356); - if (goInfo) - if (goInfo->type == GAMEOBJECT_TYPE_TRAP) - goInfo->trap.radius = 50; -} - // SD2 grid searchers. Creature *GetClosestCreatureWithEntry(WorldObject *pSource, uint32 uiEntry, float fMaxSearchRange, bool bAlive) { diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index 9b27504c1b7..b4cd3f3eb9e 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -394,7 +394,7 @@ void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 Wait void npc_escortAI::FillPointMovementListForCreature() { - std::vector<ScriptPointMove> const &pPointsEntries = pSystemMgr.GetPointMoveList(me->GetEntry()); + std::vector<ScriptPointMove> const &pPointsEntries = sScriptSystemMgr.GetPointMoveList(me->GetEntry()); if (pPointsEntries.empty()) return; diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 112f1e25d3b..f50076554f1 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -24,9 +24,8 @@ #include "WorldSession.h" #include "DatabaseEnv.h" #include "SQLStorage.h" - #include "DBCStores.h" - +#include "ScriptMgr.h" #include "AccountMgr.h" #include "AuctionHouseMgr.h" #include "Item.h" @@ -231,7 +230,8 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry * auction) //does not clear ram void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry * auction) -{ //return an item in auction to its owner by mail +{ + //return an item in auction to its owner by mail Item *pItem = GetAItem(auction->item_guidlow); if (!pItem) return; @@ -476,6 +476,7 @@ AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTem void AuctionHouseObject::AddAuction(AuctionEntry *ah) { ASSERT(ah); + AuctionsMap[ah->Id] = ah; } @@ -483,10 +484,12 @@ bool AuctionHouseObject::RemoveAuction(AuctionEntry *auction, uint32 item_templa { bool wasInMap = AuctionsMap.erase(auction->Id) ? true : false; + sScriptMgr.OnRemoveAuction(this, auction); + // we need to delete the entry, it is not referenced any more delete auction; return wasInMap; - } +} void AuctionHouseObject::Update() { @@ -511,7 +514,8 @@ void AuctionHouseObject::Update() { uint32 tmpdata = result->Fetch()->GetUInt32(); expiredAuctions.push_back(tmpdata); - } while (result->NextRow()); + } + while (result->NextRow()); while (!expiredAuctions.empty()) { @@ -528,7 +532,10 @@ void AuctionHouseObject::Update() ///- Either cancel the auction if there was no bidder if (auction->bidder == 0) + { auctionmgr.SendAuctionExpiredMail(auction); + sScriptMgr.OnAuctionExpire(this, auction); + } ///- Or perform the transaction else { @@ -537,6 +544,7 @@ void AuctionHouseObject::Update() //we send the money to the seller auctionmgr.SendAuctionSuccessfulMail(auction); auctionmgr.SendAuctionWonMail(auction); + sScriptMgr.OnAuctionSuccessful(this, auction); } ///- In any case clear the auction diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index bce8644ffd8..26e07ab62c3 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -35,6 +35,7 @@ #include "Player.h" #include "UpdateMask.h" #include "SpellMgr.h" +#include "ScriptMgr.h" // Supported shift-links (client generated and server side) // |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r @@ -958,6 +959,15 @@ void ChatHandler::PSendSysMessage(const char *format, ...) SendSysMessage(str); } +bool ChatHandler::ExecuteCommandInTables(std::vector<ChatCommand*>& tables, const char* text, const std::string& fullcmd) +{ + for (std::vector<ChatCommand*>::iterator it = tables.begin(); it != tables.end(); ++it) + if (ExecuteCommandInTable((*it), text, fullcmd)) + return true; + + return false; +} + bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcmd) { char const* oldtext = text; @@ -1091,10 +1101,7 @@ int ChatHandler::ParseCommands(const char* text) std::string fullcmd = text; if (m_session && m_session->GetSecurity() <= SEC_PLAYER && sWorld.getConfig(CONFIG_ALLOW_PLAYER_COMMANDS) == 0) - return 0; - - if (m_session && !m_session->HandleOnPlayerChat(text)) - return 0; + return 0; /// chat case (.command or !command format) if (m_session) @@ -1118,9 +1125,13 @@ int ChatHandler::ParseCommands(const char* text) if (!ExecuteCommandInTable(getCommandTable(), text, fullcmd)) { - if (m_session && m_session->GetSecurity() == SEC_PLAYER) - return 0; - SendSysMessage(LANG_NO_CMD); + if (!ExecuteCommandInTables(sScriptMgr.GetChatCommands(), text, fullcmd)) + { + if (m_session && m_session->GetSecurity() == SEC_PLAYER) + return 0; + + SendSysMessage(LANG_NO_CMD); + } } return 1; } diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 39f3eb416c1..cf3ef686f3e 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -23,6 +23,8 @@ #include "SharedDefines.h" +#include <vector> + class ChatHandler; class WorldSession; class Creature; @@ -96,7 +98,8 @@ class ChatHandler void SendGlobalGMSysMessage(const char *str); static bool SetDataForCommandInTable(ChatCommand *table, const char* text, uint32 security, std::string const& help, std::string const& fullcommand); - bool ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcommand); + bool ExecuteCommandInTables(std::vector<ChatCommand*>& tables, const char* text, const std::string& fullcmd); + bool ExecuteCommandInTable(ChatCommand *table, const char* text, const std::string& fullcmd); bool ShowHelpForCommand(ChatCommand *table, const char* cmd); bool ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd); diff --git a/src/server/game/Chat/Commands/Debugcmds.cpp b/src/server/game/Chat/Commands/Debugcmds.cpp index 64fa3efdcba..97a3777d73d 100644 --- a/src/server/game/Chat/Commands/Debugcmds.cpp +++ b/src/server/game/Chat/Commands/Debugcmds.cpp @@ -896,8 +896,8 @@ bool ChatHandler::HandleDebugItemExpireCommand(const char* args) if (!i) return false; - m_session->GetPlayer()->DestroyItem(i->GetBagSlot(),i->GetSlot(), true); - sScriptMgr.ItemExpire(m_session->GetPlayer(),i->GetProto()); + m_session->GetPlayer()->DestroyItem(i->GetBagSlot(), i->GetSlot(), true); + sScriptMgr.OnItemExpire(m_session->GetPlayer(), i->GetProto()); return true; } diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 2ce666bede5..30dedf793de 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -28,6 +28,7 @@ #include "ProgressBar.h" #include "InstanceData.h" #include "ConditionMgr.h" +#include "ScriptMgr.h" // Checks if player meets the condition // Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI) @@ -38,10 +39,9 @@ bool Condition::Meets(Player * player, Unit* targetOverride) sLog.outDebug("Condition player not found"); return false; // player not present, return false } - uint32 refId = 0; + uint32 refId = mConditionValue3;//value 3 can be a 'quick' reference bool condMeets = false; bool sendErrorMsg = false; - refId = mConditionValue3;//value 3 can be a 'quick' reference switch (mConditionType) { case CONDITION_NONE: @@ -185,12 +185,15 @@ bool Condition::Meets(Player * player, Unit* targetOverride) { ConditionList ref = sConditionMgr.GetConditionReferences(refId); refMeets = sConditionMgr.IsPlayerMeetToConditions(player, ref); - }else refMeets = true; + } + else + refMeets = true; if (sendErrorMsg && ErrorTextd && (!condMeets || !refMeets))//send special error from DB player->m_ConditionErrorMsgId = ErrorTextd; - return condMeets && refMeets; + bool script = sScriptMgr.OnConditionCheck(this, player, targetOverride); // Returns true by default. + return condMeets && refMeets && script; } ConditionMgr::ConditionMgr() @@ -232,11 +235,15 @@ bool ConditionMgr::IsPlayerMeetToConditionList(Player* player,const ConditionLis { if(!IsPlayerMeetToConditionList(player, (*ref).second, targetOverride)) ElseGroupMap[(*i)->mElseGroup] = false; - }else{ - sLog.outDebug("IsPlayerMeetToConditionList: Reference template -%u not found", (*i)->mReferenceId);//checked at loading, should never happen + } + else + { + sLog.outDebug("IsPlayerMeetToConditionList: Reference template -%u not found", + (*i)->mReferenceId);//checked at loading, should never happen } - } else//handle normal condition + } + else //handle normal condition { if (!(*i)->Meets(player, targetOverride)) ElseGroupMap[(*i)->mElseGroup] = false; @@ -246,6 +253,7 @@ bool ConditionMgr::IsPlayerMeetToConditionList(Player* player,const ConditionLis for (std::map<uint32, bool>::const_iterator i = ElseGroupMap.begin(); i != ElseGroupMap.end(); ++i) if (i->second) return true; + return false; } @@ -253,6 +261,7 @@ bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList condit { if (conditions.empty()) return true; + if(player) player->m_ConditionErrorMsgId = 0; @@ -373,7 +382,8 @@ void ConditionMgr::LoadConditions(bool isReload) sLog.outErrorDb("Condition %s %i has useless data in SourceGroup (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceGroup); if (cond->mSourceEntry && iSourceTypeOrReferenceId < 0) sLog.outErrorDb("Condition %s %i has useless data in SourceEntry (%u)!", rowType, iSourceTypeOrReferenceId, cond->mSourceEntry); - }else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType + } + else if (!isConditionTypeValid(cond))//doesn't have reference, validate ConditionType { delete cond; continue; @@ -407,7 +417,8 @@ void ConditionMgr::LoadConditions(bool isReload) sLog.outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->mSourceType), cond->mSourceGroup); delete cond; continue; - }else if (cond->mSourceGroup) + } + else if (cond->mSourceGroup) { bool bIsDone = false; //handle grouped conditions @@ -456,6 +467,7 @@ void ConditionMgr::LoadConditions(bool isReload) bIsDone = addToGossipMenuItems(cond); break; } + if (!bIsDone) { sLog.outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup); @@ -501,8 +513,10 @@ bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot) sLog.outErrorDb("ConditionMgr: LootTemplate %u not found", cond->mSourceGroup); return false; } + if (loot->addConditionItem(cond)) return true; + sLog.outErrorDb("ConditionMgr: Item %u not found in LootTemplate %u", cond->mSourceEntry, cond->mSourceGroup); return false; } @@ -522,6 +536,7 @@ bool ConditionMgr::addToGossipMenus(Condition* cond) } } } + sLog.outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->mSourceGroup); return false; } @@ -540,6 +555,7 @@ bool ConditionMgr::addToGossipMenuItems(Condition* cond) } } } + sLog.outErrorDb("addToGossipMenuItems: GossipMenuId %u Item %u not found", cond->mSourceGroup, cond->mSourceEntry); return false; } @@ -551,6 +567,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->mSourceType)); return false; } + switch (cond->mSourceType) { case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE: @@ -560,6 +577,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `creature_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -576,6 +594,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `disenchant_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -592,6 +611,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `fishing_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -608,6 +628,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `gameobject_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -624,6 +645,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `item_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -640,6 +662,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `mail_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -656,6 +679,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `milling_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -672,6 +696,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `pickpocketing_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -688,6 +713,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `prospecting_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -704,6 +730,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `reference_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -720,6 +747,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `skinning_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -736,6 +764,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceGroup %u in `condition` table, does not exist in `spell_loot_template`, ignoring.", cond->mSourceGroup); return false; } + LootTemplate* loot = LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup); ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(cond->mSourceEntry); if (!pItemProto && !loot->isReference(cond->mSourceEntry)) @@ -752,8 +781,8 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_SPELL_SCRIPT_TARGET(18) is valid for CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET(14), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); return false; } - SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); + SpellEntry const* spellProto = sSpellStore.LookupEntry(cond->mSourceEntry); if (!spellProto) { sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry); @@ -819,12 +848,14 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) sLog.outErrorDb("SourceEntry %u in `condition` table, has ConditionType %u. Only CONDITION_ITEM_TARGET(24) is valid for CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET(18), ignoring.", cond->mSourceEntry, uint32(cond->mConditionType)); return false; } + ItemPrototype const *pItemProto = objmgr.GetItemPrototype(cond->mSourceEntry); if (!pItemProto) { sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `item_tamplate`, ignoring.", cond->mSourceEntry); return false; } + bool bIsItemSpellValid = false; for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) { @@ -848,6 +879,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) break; } } + if (bIsItemSpellValid) break; } @@ -867,6 +899,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) case CONDITION_SOURCE_TYPE_NONE: break; } + return true; } bool ConditionMgr::isConditionTypeValid(Condition* cond) @@ -876,6 +909,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Invalid ConditionType %u at SourceEntry %u in `condition` table, ignoring.", uint32(cond->mConditionType),cond->mSourceEntry); return false; } + switch (cond->mConditionType) { case CONDITION_AURA: @@ -885,6 +919,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2 > 2) { sLog.outErrorDb("Aura condition has non existing effect index (%u) (must be 0..2), skipped", cond->mConditionValue2); @@ -900,6 +935,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Item condition has non existing item (%u), skipped", cond->mConditionValue1); return false; } + if (!cond->mConditionValue2) { sLog.outErrorDb("Item condition has 0 set for item count in value2 (%u), skipped", cond->mConditionValue2); @@ -915,6 +951,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("ItemEquipped condition has non existing item (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("ItemEquipped condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -927,11 +964,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Zone condition has non existing area (%u), skipped", cond->mConditionValue1); return false; } + if (areaEntry->zone != 0) { sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Zone condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -953,6 +992,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Team condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -965,6 +1005,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2 < 1 || cond->mConditionValue2 > sWorld.GetConfigMaxSkillValue()) { sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", cond->mConditionValue2); @@ -982,6 +1023,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -990,6 +1032,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->mConditionValue1) sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", cond->mConditionValue1); + if (cond->mConditionValue2) sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1001,6 +1044,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Aura condition has non existing spell (Id: %d), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2 > 2) { sLog.outErrorDb("Aura condition has non existing effect index (%u) in value2 (must be 0..2), skipped", cond->mConditionValue2); @@ -1016,6 +1060,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Active event condition has non existing event id (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Active event condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1028,6 +1073,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Achivemen condition has non existing achivement id (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Achivemen condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1039,6 +1085,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Class condition has non existing class (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Class condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1050,6 +1097,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Race condition has non existing race (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Race condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1061,6 +1109,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->mConditionValue1); return false; } + switch(cond->mConditionValue1) { case SPELL_TARGET_TYPE_GAMEOBJECT: @@ -1081,8 +1130,8 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("SpellTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); return false; } - const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(cond->mConditionValue2); + const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(cond->mConditionValue2); if (cond->mSourceEntry == 30427 && !cInfo->SkinLootId) { sLog.outErrorDb("SpellTarget condition has creature entry %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!, skipped", cond->mConditionValue2); @@ -1091,6 +1140,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) break; } } + if (cond->mConditionValue3) sLog.outErrorDb("SpellTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); break; @@ -1102,6 +1152,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("CreatureTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("CreatureTarget condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1113,6 +1164,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("TargetHealthBelowPct condition has invalid data in value1 (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("TargetHealthBelowPct condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1134,6 +1186,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("Map condition has non existing map (%u), skipped", cond->mConditionValue1); return false; } + if (cond->mConditionValue2) sLog.outErrorDb("Map condition has useless data in value2 (%u)!", cond->mConditionValue2); break; @@ -1145,11 +1198,13 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) sLog.outErrorDb("ItemTarget condition has incorrect target type (%u), skipped", cond->mConditionValue1); return false; } + if (!cond->mConditionValue2 && !sCreatureStorage.LookupEntry<CreatureInfo>(cond->mConditionValue2)) { sLog.outErrorDb("ItemTarget condition has non existing creature template entry (%u) as target, skipped", cond->mConditionValue2); return false; } + if (cond->mConditionValue3) sLog.outErrorDb("ItemTarget condition has useless data in value3 (%u)!", cond->mConditionValue3); break; @@ -1169,6 +1224,7 @@ void ConditionMgr::Clean() delete *it; itr->second.clear(); } + m_ConditionReferenceMap.clear(); for (ConditionMap::iterator itr = m_ConditionMap.begin(); itr != m_ConditionMap.end(); ++itr) @@ -1181,10 +1237,12 @@ void ConditionMgr::Clean() } itr->second.clear(); } + m_ConditionMap.clear(); // this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;) for (std::list<Condition*>::const_iterator itr = m_AllocatedMemory.begin(); itr != m_AllocatedMemory.end(); ++itr) delete *itr; + m_AllocatedMemory.clear(); } diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 11c148783ea..aec59b32da1 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -111,6 +111,7 @@ struct Condition ErrorTextd = 0; mScriptId = 0; } + bool Meets(Player * player, Unit* targetOverride = NULL); bool isLoaded() { return mConditionType > CONDITION_NONE || mReferenceId; } }; @@ -125,9 +126,9 @@ class ConditionMgr { friend class ACE_Singleton<ConditionMgr, ACE_Null_Mutex>; ConditionMgr(); + ~ConditionMgr(); public: - ~ConditionMgr(); void LoadConditions(bool isReload = false); bool isConditionTypeValid(Condition* cond); @@ -137,10 +138,12 @@ class ConditionMgr ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry); protected: + ConditionMap m_ConditionMap; ConditionReferenceMap m_ConditionReferenceMap; private: + bool isSourceTypeValid(Condition* cond); bool addToLootTemplate(Condition* cond, LootTemplate* loot); bool addToGossipMenus(Condition* cond); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 57802f058c4..0d0542b37aa 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -588,6 +588,8 @@ void Creature::Update(uint32 diff) default: break; } + + sScriptMgr.OnCreatureUpdate(this, diff); } void Creature::RegenerateMana() diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 529710eda90..f83b3e5ecc7 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -27,6 +27,7 @@ #include "GridNotifiers.h" #include "CellImpl.h" #include "GridNotifiersImpl.h" +#include "ScriptMgr.h" DynamicObject::DynamicObject() : WorldObject() { @@ -143,6 +144,8 @@ void DynamicObject::Update(uint32 p_time) caster->RemoveDynObjectWithGUID(GetGUID()); Delete(); } + else + sScriptMgr.OnDynamicObjectUpdate(this, p_time); } void DynamicObject::Delete() diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 026dd8b1a32..32f26a3dc52 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -526,6 +526,8 @@ void GameObject::Update(uint32 diff) break; } } + + sScriptMgr.OnGameObjectUpdate(this, diff); } void GameObject::Refresh() @@ -1602,7 +1604,7 @@ void GameObject::TakenDamage(uint32 damage, Unit *who) if (BattleGround* bg = pwho->GetBattleGround()) bg->DestroyGate(pwho, this, m_goInfo->building.destroyedEvent); hitType = BG_OBJECT_DMG_HIT_TYPE_JUST_DESTROYED; - sScriptMgr.GODestroyed(pwho, this, m_goInfo->building.destroyedEvent); + sScriptMgr.OnGameObjectDestroyed(pwho, this, m_goInfo->building.destroyedEvent); } if (pwho) if (BattleGround* bg = pwho->GetBattleGround()) diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 6efc320d3d2..2b4e751b80a 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -292,7 +292,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff) if (GetUInt32Value(ITEM_FIELD_DURATION) <= diff) { - sScriptMgr.ItemExpire(owner, GetProto()); + sScriptMgr.OnItemExpire(owner, GetProto()); owner->DestroyItem(GetBagSlot(), GetSlot(), true); return; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d4e7196a16e..7abb307bd33 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2642,7 +2642,7 @@ void Player::GiveXP(uint32 xp, Unit* victim) level = getLevel(); nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); } - newXP = GetSession()->HandleOnGetXP(newXP); + SetUInt32Value(PLAYER_XP, newXP); } @@ -6363,10 +6363,7 @@ void Player::CheckAreaExploreAndOutdoor() if (!m_AreaID) m_AreaID = GetAreaId(); if (m_AreaID != GetAreaId()) - { m_AreaID = GetAreaId(); - GetSession()->HandleOnAreaChange(GetAreaEntryByAreaID(m_AreaID)); - } bool isOutdoor; uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(),GetPositionY(),GetPositionZ(), &isOutdoor); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2d6690bd817..e8dd8f8fc0c 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1443,7 +1443,6 @@ class Player : public Unit, public GridObject<Player> uint32 GetMoney() { return GetUInt32Value (PLAYER_FIELD_COINAGE); } void ModifyMoney(int32 d) { - d = GetSession()->HandleOnGetMoney(d); if (d < 0) SetMoney (GetMoney() > uint32(-d) ? GetMoney() + d : 0); else diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index d4bccbc2979..5e5eecea068 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -19,16 +19,14 @@ */ #include "Common.h" - #include "Transport.h" #include "MapManager.h" #include "ObjectMgr.h" #include "Path.h" - +#include "ScriptMgr.h" #include "WorldPacket.h" #include "DBCStores.h" #include "ProgressBar.h" - #include "World.h" void MapManager::LoadTransports() @@ -115,7 +113,8 @@ void MapManager::LoadTransports() } ++count; - } while (result->NextRow()); + } + while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u transports", count); @@ -529,6 +528,8 @@ bool Transport::AddPassenger(Player* passenger) { if (m_passengers.insert(passenger).second) sLog.outDetail("Player %s boarded transport %s.", passenger->GetName(), GetName()); + + sScriptMgr.OnAddPassenger(this, passenger); return true; } @@ -536,10 +537,12 @@ bool Transport::RemovePassenger(Player* passenger) { if (m_passengers.erase(passenger)) sLog.outDetail("Player %s removed from transport %s.", passenger->GetName(), GetName()); + + sScriptMgr.OnRemovePassenger(this, passenger); return true; } -void Transport::Update(uint32 /*p_time*/) +void Transport::Update(uint32 p_diff) { if (m_WayPoints.size() <= 1) return; @@ -572,6 +575,8 @@ void Transport::Update(uint32 /*p_time*/) if ((sLog.getLogFilter() & LOG_FILTER_TRANSPORT_MOVES) == 0) sLog.outDetail("%s moved to %d %f %f %f %d", this->m_name.c_str(), m_curr->second.id, m_curr->second.x, m_curr->second.y, m_curr->second.z, m_curr->second.mapid); + + sScriptMgr.OnTransportUpdate(this, p_diff); } } @@ -676,6 +681,7 @@ uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, currenttguid = std::max(tguid,currenttguid); pCreature->SetGUIDTransport(tguid); + sScriptMgr.OnAddCreaturePassenger(this, pCreature); return tguid; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f361d1ba95a..002f456bb77 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -724,13 +724,11 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa { Player *killer = this->ToPlayer(); Player *killed = pVictim->ToPlayer(); - killer->GetSession()->HandleOnPVPKill(killed); } if (pVictim->GetTypeId() == TYPEID_UNIT && this->GetTypeId() == TYPEID_PLAYER) { Player *killer = this->ToPlayer(); Creature *pCreature = (pVictim->ToCreature()); - killer->GetSession()->HandleOnCreatureKill(pCreature); } } else // if (health <= damage) diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 818cbd67904..e92e488de3d 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -23,7 +23,7 @@ #include "Unit.h" #include "Util.h" #include "WorldPacket.h" - +#include "ScriptMgr.h" #include "CreatureAI.h" #include "ZoneScript.h" @@ -108,6 +108,8 @@ void Vehicle::Install() } Reset(); + + sScriptMgr.OnInstall(this); } void Vehicle::InstallAllAccessories() @@ -127,7 +129,10 @@ void Vehicle::Uninstall() if (Unit *passenger = itr->second.passenger) if (passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY)) passenger->ToTempSummon()->UnSummon(); + RemoveAllPassengers(); + + sScriptMgr.OnUninstall(this); } void Vehicle::Die() @@ -137,7 +142,10 @@ void Vehicle::Die() if (Unit *passenger = itr->second.passenger) if (passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY)) passenger->setDeathState(JUST_DIED); + RemoveAllPassengers(); + + sScriptMgr.OnDie(this); } void Vehicle::Reset() @@ -154,6 +162,8 @@ void Vehicle::Reset() if (m_usableSeatNum) me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); } + + sScriptMgr.OnReset(this); } void Vehicle::RemoveAllPassengers() @@ -237,6 +247,8 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion) accessory->EnterVehicle(this, seatId); // This is not good, we have to send update twice accessory->SendMovementFlagUpdate(); + + sScriptMgr.OnInstallAccessory(this, accessory); } } @@ -317,9 +329,7 @@ bool Vehicle::AddPassenger(Unit *unit, int8 seatId) } } - //if (unit->GetTypeId() == TYPEID_PLAYER) - // unit->ToPlayer()->SendTeleportAckPacket(); - //unit->SendMovementFlagUpdate(); + sScriptMgr.OnAddPassenger(this, unit, seatId); return true; } @@ -366,6 +376,8 @@ void Vehicle::RemovePassenger(Unit *unit) // only for flyable vehicles if (unit->HasUnitMovementFlag(MOVEMENTFLAG_FLYING)) me->CastSpell(unit, 45472, true); // Parachute + + sScriptMgr.OnRemovePassenger(this, unit); } void Vehicle::RelocatePassengers(float x, float y, float z, float ang) diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 5b811d54fe2..5bc83ee4e5f 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -8765,8 +8765,6 @@ void ObjectMgr::LoadScriptNames() barGoLink bar(result->GetRowCount()); - //OnEvent Changes - m_scriptNames.push_back("scripted_on_events"); uint32 count = 1; do diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index eed56efd026..6a4e02a9d1b 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -41,7 +41,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "GossipDef.h" - +#include "ScriptMgr.h" #include "MapInstanced.h" #include "InstanceSaveMgr.h" #include "VMapFactory.h" @@ -62,6 +62,9 @@ struct ScriptAction Map::~Map() { + if (!Instanceable()) + sScriptMgr.OnDestroyMap(this); + UnloadAll(); while (!i_worldObjects.empty()) @@ -169,6 +172,8 @@ void Map::LoadMap(int gx,int gy, bool reload) sLog.outDetail("Unloading previously loaded map %u before reloading.",GetId()); delete (GridMaps[gx][gy]); GridMaps[gx][gy]=NULL; + + sScriptMgr.OnUnloadGridMap(this, gx, gy); } // map file name @@ -184,6 +189,8 @@ void Map::LoadMap(int gx,int gy, bool reload) sLog.outError("Error loading map file: \n %s\n", tmp); } delete [] tmp; + + sScriptMgr.OnLoadGridMap(this, gx, gy); } void Map::LoadMapAndVMap(int gx,int gy) @@ -229,6 +236,9 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par //lets initialize visibility distance for map Map::InitVisibilityDistance(); + + if (!Instanceable()) + sScriptMgr.OnCreateMap(this); } void Map::InitVisibilityDistance() @@ -437,6 +447,7 @@ bool Map::Add(Player *player) player->m_clientGUIDs.clear(); player->UpdateObjectVisibility(true); + sScriptMgr.OnPlayerEnter(this, player); return true; } @@ -480,102 +491,6 @@ Map::Add(T *obj) obj->UpdateObjectVisibility(true); } -/* -void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self) -{ - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::MessageDeliverer post_man(*player, msg, to_self); - TypeContainerVisitor<Trinity::MessageDeliverer, WorldTypeMapContainer > message(post_man); - CellLock<ReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *player, GetVisibilityDistance()); -} - -void Map::MessageBroadcast(WorldObject *obj, WorldPacket *msg) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - //TODO: currently on continents when Visibility.Distance.InFlight > Visibility.Distance.Continents - //we have alot of blinking mobs because monster move packet send is broken... - Trinity::ObjectMessageDeliverer post_man(*obj,msg); - TypeContainerVisitor<Trinity::ObjectMessageDeliverer, WorldTypeMapContainer > message(post_man); - CellLock<ReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *obj, GetVisibilityDistance()); -} - -void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, bool to_self, bool own_team_only) -{ - CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Player (GUID: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", player->GetGUIDLow(), player->GetPositionX(), player->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only); - TypeContainerVisitor<Trinity::MessageDistDeliverer , WorldTypeMapContainer > message(post_man); - CellLock<ReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *player, dist); -} - -void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist) -{ - CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - - if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - { - sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord); - return; - } - - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y))) - return; - - Trinity::ObjectMessageDistDeliverer post_man(*obj, msg, dist); - TypeContainerVisitor<Trinity::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man); - CellLock<ReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *this, *obj, dist); -} -*/ - bool Map::loaded(const GridPair &p) const { return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); @@ -704,6 +619,8 @@ void Map::Update(const uint32 &t_diff) if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty()) ProcessRelocationNotifies(t_diff); + + sScriptMgr.OnMapUpdate(this, t_diff); } struct ResetNotifier @@ -821,6 +738,8 @@ void Map::Remove(Player *player, bool remove) if (remove) DeleteFromWorld(player); + + sScriptMgr.OnPlayerLeave(this, player); } template<class T> @@ -1993,32 +1912,6 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpai // send data notifier.SendToSelf(); } -/* -void Map::PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair) -{ - Trinity::PlayerRelocationNotifier relocationNotifier(*player); - cell.data.Part.reserved = ALL_DISTRICT; - - TypeContainerVisitor<Trinity::PlayerRelocationNotifier, GridTypeMapContainer > p2grid_relocation(relocationNotifier); - TypeContainerVisitor<Trinity::PlayerRelocationNotifier, WorldTypeMapContainer > p2world_relocation(relocationNotifier); - - cell.Visit(cellpair, p2grid_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); - cell.Visit(cellpair, p2world_relocation, *this, *player, MAX_CREATURE_ATTACK_RADIUS); -} - -void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair) -{ - Trinity::CreatureRelocationNotifier relocationNotifier(*creature); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); // not trigger load unloaded grids at notifier call - - TypeContainerVisitor<Trinity::CreatureRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocationNotifier); - TypeContainerVisitor<Trinity::CreatureRelocationNotifier, GridTypeMapContainer > c2grid_relocation(relocationNotifier); - - cell.Visit(cellpair, c2world_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); - cell.Visit(cellpair, c2grid_relocation, *this, *creature, MAX_CREATURE_ATTACK_RADIUS); -} -*/ void Map::SendInitSelf(Player * player) { diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 0d34244ad5f..251415b2d97 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -248,6 +248,8 @@ class Map : public GridRefManager<NGridType> Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); virtual ~Map(); + MapEntry const* GetEntry() const { return i_mapEntry; } + // currently unused for normal maps bool CanUnload(uint32 diff) { @@ -264,13 +266,6 @@ class Map : public GridRefManager<NGridType> virtual void Update(const uint32&); - /* - void MessageBroadcast(Player *, WorldPacket *, bool to_self); - void MessageBroadcast(WorldObject *, WorldPacket *); - void MessageDistBroadcast(Player *, WorldPacket *, float dist, bool to_self, bool own_team_only = false); - void MessageDistBroadcast(WorldObject *, WorldPacket *, float dist); - */ - float GetVisibilityDistance() const { return m_VisibleDistance; } //function for setting up visibility distance for maps on per-type/per-Id basis virtual void InitVisibilityDistance(); @@ -369,7 +364,6 @@ class Map : public GridRefManager<NGridType> MapDifficulty const* GetMapDifficulty() const; bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); } - // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } bool IsNonRaidDungeon() const { return i_mapEntry && i_mapEntry->IsNonRaidDungeon(); } bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h index 8244e344275..bd73326852e 100644 --- a/src/server/game/Miscellaneous/Formulas.h +++ b/src/server/game/Miscellaneous/Formulas.h @@ -22,6 +22,8 @@ #define TRINITY_FORMULAS_H #include "World.h" +#include "SharedDefines.h" +#include "ScriptMgr.h" namespace Trinity { @@ -29,71 +31,108 @@ namespace Trinity { inline float hk_honor_at_level_f(uint8 level, uint32 count = 1) { - return count * level * 1.55f; + float honor = count * level * 1.55f; + sScriptMgr.OnHonorCalculation(honor, level, count); + return honor; } inline uint32 hk_honor_at_level(uint8 level, uint32 count = 1) { - return ceil(hk_honor_at_level_f(level, count)); + uint32 honor = ceil(hk_honor_at_level_f(level, count)); + sScriptMgr.OnHonorCalculation(honor, level, count); + return honor; } } namespace XP { - enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY }; - inline uint8 GetGrayLevel(uint8 pl_level) { + uint8 level; + if (pl_level <= 5) - return 0; + level = 0; else if (pl_level <= 39) - return pl_level - 5 - pl_level/10; + level = pl_level - 5 - pl_level / 10; else if (pl_level <= 59) - return pl_level - 1 - pl_level/5; + level = pl_level - 1 - pl_level / 5; else - return pl_level - 9; + level = pl_level - 9; + + sScriptMgr.OnGetGrayLevel(level, pl_level); + return level; } inline XPColorChar GetColorCode(uint8 pl_level, uint8 mob_level) { + XPColorChar color; + if (mob_level >= pl_level + 5) - return RED; + color = XP_RED; else if (mob_level >= pl_level + 3) - return ORANGE; + color = XP_ORANGE; else if (mob_level >= pl_level - 2) - return YELLOW; + color = XP_YELLOW; else if (mob_level > GetGrayLevel(pl_level)) - return GREEN; + color = XP_GREEN; else - return GRAY; + color = XP_GRAY; + + sScriptMgr.OnGetColorCode(color, pl_level, mob_level); + return color; } inline uint8 GetZeroDifference(uint8 pl_level) { - if (pl_level < 8) return 5; - if (pl_level < 10) return 6; - if (pl_level < 12) return 7; - if (pl_level < 16) return 8; - if (pl_level < 20) return 9; - if (pl_level < 30) return 11; - if (pl_level < 40) return 12; - if (pl_level < 45) return 13; - if (pl_level < 50) return 14; - if (pl_level < 55) return 15; - if (pl_level < 60) return 16; - return 17; + uint8 diff; + + if (pl_level < 8) + diff = 5; + else if (pl_level < 10) + diff = 6; + else if (pl_level < 12) + diff = 7; + else if (pl_level < 16) + diff = 8; + else if (pl_level < 20) + diff = 9; + else if (pl_level < 30) + diff = 11; + else if (pl_level < 40) + diff = 12; + else if (pl_level < 45) + diff = 13; + else if (pl_level < 50) + diff = 14; + else if (pl_level < 55) + diff = 15; + else if (pl_level < 60) + diff = 16; + else + diff = 17; + + return diff; } inline uint32 BaseGain(uint8 pl_level, uint8 mob_level, ContentLevels content) { + uint32 baseGain; uint32 nBaseExp; + switch (content) { - case CONTENT_1_60: nBaseExp = 45; break; - case CONTENT_61_70: nBaseExp = 235; break; - case CONTENT_71_80: nBaseExp = 580; break; + case CONTENT_1_60: + nBaseExp = 45; + break; + case CONTENT_61_70: + nBaseExp = 235; + break; + case CONTENT_71_80: + nBaseExp = 580; + break; default: sLog.outError("BaseGain: Unsupported content level %u",content); - nBaseExp = 45; break; + nBaseExp = 45; + break; } if (mob_level >= pl_level) @@ -101,7 +140,8 @@ namespace Trinity uint8 nLevelDiff = mob_level - pl_level; if (nLevelDiff > 4) nLevelDiff = 4; - return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2; + + baseGain = ((pl_level * 5 + nBaseExp) * (20 + nLevelDiff) / 10 + 1) / 2; } else { @@ -109,41 +149,51 @@ namespace Trinity if (mob_level > gray_level) { uint8 ZD = GetZeroDifference(pl_level); - return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD; + baseGain = (pl_level * 5 + nBaseExp) * (ZD + mob_level - pl_level) / ZD; } - return 0; + else + baseGain = 0; } + + sScriptMgr.OnGetBaseGain(baseGain, pl_level, mob_level, content); + return baseGain; } inline uint32 Gain(Player *pl, Unit *u) { - if (u->GetTypeId() == TYPEID_UNIT && ( - ((Creature*)u)->isTotem() || ((Creature*)u)->isPet() || - (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) - return 0; - - uint32 xp_gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(),u->GetZoneId())); - if (xp_gain == 0) - return 0; + uint32 gain; - //elites in instances have a 2.75x xp bonus instead of the regular 2x world bonus - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isElite()) + if (u->GetTypeId() == TYPEID_UNIT && + (((Creature*)u)->isTotem() || ((Creature*)u)->isPet() || + (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) + gain = 0; + else { - if(u->GetMap() && u->GetMap()->IsDungeon()) - xp_gain *= 2.75; - else - xp_gain *= 2; + gain = BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(), u->GetZoneId())); + + if (gain != 0 && u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isElite()) + { + // Elites in instances have a 2.75x XP bonus instead of the regular 2x world bonus. + if (u->GetMap() && u->GetMap()->IsDungeon()) + gain *= 2.75; + else + gain *= 2; + } } - return uint32(xp_gain*sWorld.getRate(RATE_XP_KILL)); + gain *= sWorld.getRate(RATE_XP_KILL); + sScriptMgr.OnGetGain(gain, pl, u); + return gain; } inline float xp_in_group_rate(uint32 count, bool isRaid) { + float rate; + if (isRaid) { - // FIX ME: must apply decrease modifiers dependent from raid size - return 1.0f; + // FIXME: Must apply decrease modifiers depending on raid size. + rate = 1.0f; } else { @@ -152,18 +202,21 @@ namespace Trinity case 0: case 1: case 2: - return 1.0f; + rate = 1.0f; case 3: - return 1.166f; + rate = 1.166f; case 4: - return 1.3f; + rate = 1.3f; case 5: default: - return 1.4f; + rate = 1.4f; } } + + sScriptMgr.OnGetGroupRate(rate, count, isRaid); + return rate; } } } -#endif +#endif diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 07694a57577..c5e3594ed4c 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -2812,4 +2812,13 @@ enum TradeStatus TRADE_STATUS_ONLY_CONJURED = 22 // You can only trade conjured items... (cross realm BG related). }; +enum XPColorChar +{ + XP_RED, + XP_ORANGE, + XP_YELLOW, + XP_GREEN, + XP_GRAY +}; + #endif diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h index 530bb647903..e15880176f9 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.h +++ b/src/server/game/OutdoorPvP/OutdoorPvP.h @@ -33,10 +33,9 @@ enum OutdoorPvPTypes OUTDOOR_PVP_ZM = 4, OUTDOOR_PVP_SI = 5, OUTDOOR_PVP_EP = 6, - OUTDOOR_PVP_NR = 7, }; -#define MAX_OUTDOORPVP_TYPES 8 +#define MAX_OUTDOORPVP_TYPES 7 const uint8 CapturePointArtKit[3] = {2, 1, 21}; diff --git a/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp b/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp index ba2df92bed9..89f2ce0c754 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvPMgr.cpp @@ -27,6 +27,7 @@ #include "Player.h" #include "ProgressBar.h" #include "DisableMgr.h" +#include "ScriptMgr.h" OutdoorPvPMgr::OutdoorPvPMgr() { @@ -40,91 +41,39 @@ OutdoorPvPMgr::~OutdoorPvPMgr() for (OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr) delete *itr; - for (OutdoorPvPDataSet::iterator itr = m_OutdoorPvPDatas.begin(); itr != m_OutdoorPvPDatas.end(); ++itr) - delete *itr; + for (OutdoorPvPDataMap::iterator itr = m_OutdoorPvPDatas.begin(); itr != m_OutdoorPvPDatas.end(); ++itr) + delete itr->second; } void OutdoorPvPMgr::InitOutdoorPvP() { LoadTemplates(); - // create new opvp - OutdoorPvP * pOP = new OutdoorPvPHP; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : HP init failed."); - delete pOP; - } - else - { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : HP successfully initiated."); - } - - pOP = new OutdoorPvPNA; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : NA init failed."); - delete pOP; - } - else - { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : NA successfully initiated."); - } - - pOP = new OutdoorPvPTF; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : TF init failed."); - delete pOP; - } - else + OutdoorPvP* pvp; + for (uint8 i = 0; i < MAX_OUTDOORPVP_TYPES; ++i) { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : TF successfully initiated."); - } + OutdoorPvPDataMap::iterator iter = m_OutdoorPvPDatas.find(OutdoorPvPTypes(i)); + if (iter == m_OutdoorPvPDatas.end()) + { + sLog.outErrorDb("Could not initialize OutdoorPvP object for type ID %u; no entry in database.", uint32(iter->first)); + continue; + } - pOP = new OutdoorPvPZM; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : ZM init failed."); - delete pOP; - } - else - { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : ZM successfully initiated."); - } + pvp = sScriptMgr.CreateOutdoorPvP(iter->second); + if (!pvp) + { + sLog.outError("Could not initialize OutdoorPvP object for type ID %u; got NULL pointer from script.", uint32(iter->first)); + continue; + } - pOP = new OutdoorPvPSI; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : SI init failed."); - delete pOP; - } - else - { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : SI successfully initiated."); - } + if (!pvp->SetupOutdoorPvP()) + { + sLog.outError("Could not initialize OutdoorPvP object for type ID %u; SetupOutdoorPvP failed.", uint32(iter->first)); + delete pvp; + continue; + } - pOP = new OutdoorPvPEP; - // respawn, init variables - if (!pOP->SetupOutdoorPvP()) - { - sLog.outDebug("OutdoorPvP : EP init failed."); - delete pOP; - } - else - { - m_OutdoorPvPSet.push_back(pOP); - sLog.outDebug("OutdoorPvP : EP successfully initiated."); + m_OutdoorPvPSet.push_back(pvp); } } @@ -161,14 +110,15 @@ void OutdoorPvPMgr::LoadTemplates() if (typeId >= MAX_OUTDOORPVP_TYPES) { - sLog.outError("Invalid OutdoorPvPTypes value %u in outdoorpvp_template; skipped.", typeId); + sLog.outErrorDb("Invalid OutdoorPvPTypes value %u in outdoorpvp_template; skipped.", typeId); continue; } OutdoorPvPData data; - data.TypeId = OutdoorPvPTypes(typeId); + OutdoorPvPTypes realTypeId = OutdoorPvPTypes(typeId); + data.TypeId = realTypeId; data.ScriptId = objmgr.GetScriptId(fields[1].GetString()); - m_OutdoorPvPDatas.push_back(&data); + m_OutdoorPvPDatas[realTypeId] = &data; ++count; } diff --git a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h index a1e8e3c9a6b..f140cbe421a 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h +++ b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h @@ -85,7 +85,7 @@ class OutdoorPvPMgr typedef std::vector<OutdoorPvP*> OutdoorPvPSet; typedef std::map<uint32 /* zoneid */, OutdoorPvP*> OutdoorPvPMap; - typedef std::vector<OutdoorPvPData*> OutdoorPvPDataSet; + typedef std::map<OutdoorPvPTypes, OutdoorPvPData*> OutdoorPvPDataMap; private: @@ -98,7 +98,7 @@ class OutdoorPvPMgr OutdoorPvPMap m_OutdoorPvPMap; // Holds the outdoor PvP templates - OutdoorPvPDataSet m_OutdoorPvPDatas; + OutdoorPvPDataMap m_OutdoorPvPDatas; // update interval uint32 m_UpdateTimer; diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 5f6cce4917d..8e660f7116e 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -11,69 +11,34 @@ #include "ScriptLoader.h" #include "ScriptSystem.h" -int num_sc_scripts; -Script *m_scripts[MAX_SCRIPTS]; - -void FillSpellSummary(); -void LoadOverridenSQLData(); - -void ScriptMgr::LoadDatabase() -{ - pSystemMgr.LoadVersion(); - pSystemMgr.LoadScriptTexts(); - pSystemMgr.LoadScriptTextsCustom(); - pSystemMgr.LoadScriptWaypoints(); -} - -struct TSpellSummary { - uint8 Targets; // set of enum SelectTarget - uint8 Effects; // set of enum SelectEffect -}extern *SpellSummary; - -ScriptMgr::ScriptMgr() -{ - -} -ScriptMgr::~ScriptMgr() -{ - -} - -void ScriptMgr::ScriptsInit() -{ - //Trinity Script startup - /*sLog.outString(" _____ _ _ _ ____ _ _"); - sLog.outString("|_ _| __(_)_ __ (_) |_ _ _/ ___| ___ _ __(_)_ __ | |_ "); - sLog.outString(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \'__| | \'_ \\| __|"); - sLog.outString(" | || | | | | | | | |_| |_| |___) | (__| | | | |_) | |_ "); - sLog.outString(" |_||_| |_|_| |_|_|\\__|\\__, |____/ \\___|_| |_| .__/ \\__|"); - sLog.outString(" |___/ |_| "); - sLog.outString(""); - sLog.outString("");*/ - - //Load database (must be called after SD2Config.SetSource). - LoadDatabase(); - - sLog.outString("Loading C++ scripts"); - barGoLink bar(1); - bar.step(); - sLog.outString(""); - - for (uint16 i =0; i<MAX_SCRIPTS; ++i) - m_scripts[i]=NULL; - - FillSpellSummary(); - - AddScripts(); - - sLog.outString(">> Loaded %i C++ Scripts.", num_sc_scripts); - - sLog.outString(">> Load Overriden SQL Data."); - LoadOverridenSQLData(); -} - -//********************************* -//*** Functions used globally *** +// Utility macros to refer to the script registry. +#define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptMap +#define SCR_REG_LST(T) ScriptRegistry<T>::ScriptPointerList + +// Utility macros for looping over scripts. +#define FOR_SCRIPTS(T,C,E) \ + if (SCR_REG_LST(T).empty()) \ + return; \ + for (SCR_REG_MAP(T)::iterator C = SCR_REG_LST(T).begin(); \ + C != SCR_REG_LST(T).end(); ++C) +#define FOR_SCRIPTS_RET(T,C,E,R) \ + if (SCR_REG_LST(T).empty()) \ + return R; \ + for (SCR_REG_MAP(T)::iterator C = SCR_REG_LST(T).begin(); \ + C != SCR_REG_LST(T).end(); ++C) +#define FOREACH_SCRIPT(T) \ + FOR_SCRIPTS(T, itr, end) \ + itr->second + +// Utility macros for finding specific scripts. +#define GET_SCRIPT(T,I,V) \ + T* V = ScriptRegistry<T>::GetScriptById(I); \ + if (!V) \ + return; +#define GET_SCRIPT_RET(T,I,V,R) \ + T* V = ScriptRegistry<T>::GetScriptById(I); \ + if (!V) \ + return R; void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) { @@ -89,7 +54,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) return; } - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); + const StringTextData* pData = sScriptSystemMgr.GetTextData(iTextEntry); if (!pData) { @@ -102,9 +67,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) if (pData->uiSoundId) { if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - { pSource->SendPlaySound(pData->uiSoundId, false); - } else sLog.outError("TSCR: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); } @@ -117,7 +80,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) sLog.outError("TSCR: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId()); } - switch(pData->uiType) + switch (pData->uiType) { case CHAT_TYPE_SAY: pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); @@ -132,437 +95,1122 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0, true); break; case CHAT_TYPE_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); - else - sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); + else + sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + break; + } case CHAT_TYPE_BOSS_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); - else - sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); + else + sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + break; + } case CHAT_TYPE_ZONE_YELL: pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); break; } } -void Script::RegisterSelf() +ScriptMgr::ScriptMgr() +{ +} + +ScriptMgr::~ScriptMgr() +{ + #define SCR_CLEAR(T) \ + FOR_SCRIPTS(T, itr, end) \ + delete itr->second; \ + SCR_REG_LST(T).clear(); + + // Clear scripts for every script type. + SCR_CLEAR(SpellHandlerScript); + SCR_CLEAR(AuraHandlerScript); + SCR_CLEAR(ServerScript); + SCR_CLEAR(WorldScript); + SCR_CLEAR(FormulaScript); + SCR_CLEAR(WorldMapScript); + SCR_CLEAR(InstanceMapScript); + SCR_CLEAR(BattlegroundMapScript); + SCR_CLEAR(ItemScript); + SCR_CLEAR(CreatureScript); + SCR_CLEAR(GameObjectScript); + SCR_CLEAR(AreaTriggerScript); + SCR_CLEAR(BattlegroundScript); + SCR_CLEAR(OutdoorPvPScript); + SCR_CLEAR(CommandScript); + SCR_CLEAR(WeatherScript); + SCR_CLEAR(AuctionHouseScript); + SCR_CLEAR(ConditionScript); + SCR_CLEAR(VehicleScript); + SCR_CLEAR(DynamicObjectScript); + SCR_CLEAR(TransportScript); + + #undef SCR_CLEAR +} + +void ScriptMgr::Initialize() { - // try to find scripts which try to use another script's allocated memory - // that means didn't allocate memory for script - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) + LoadDatabase(); + + sLog.outString("Loading C++ scripts"); + barGoLink bar(1); + bar.step(); + sLog.outString(""); + + FillSpellSummary(); + AddScripts(); + + sLog.outString(">> Loaded %u C++ scripts", GetScriptCount()); +} + +void ScriptMgr::LoadDatabase() +{ + sScriptSystemMgr.LoadVersion(); + sScriptSystemMgr.LoadScriptTexts(); + sScriptSystemMgr.LoadScriptTextsCustom(); + sScriptSystemMgr.LoadScriptWaypoints(); +} + +struct TSpellSummary +{ + uint8 Targets; // set of enum SelectTarget + uint8 Effects; // set of enum SelectEffect +} *SpellSummary; + +void ScriptMgr::FillSpellSummary() +{ + SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()]; + + SpellEntry const* pTempSpell; + + for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) { - // somebody forgot to allocate memory for a script by a method like this: newscript = new Script - if (m_scripts[i] == this) + SpellSummary[i].Effects = 0; + SpellSummary[i].Targets = 0; + + pTempSpell = GetSpellStore()->LookupEntry(i); + //This spell doesn't exist + if (!pTempSpell) + continue; + + for (uint32 j = 0; j < 3; ++j) { - sLog.outError("ScriptName: '%s' - Forgot to allocate memory, so this script and/or the script before that can't work.", Name.c_str()); - // don't register it - // and don't delete it because its memory is used for another script - return; + //Spell targets self + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); + + //Spell targets a single enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); + + //Spell targets AoE at enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); + + //Spell targets an enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); + + //Spell targets a single friend(or self) + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); + + //Spell targets aoe friends + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); + + //Spell targets any friend(or self) + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); + + //Make sure that this spell includes a damage effect + if (pTempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || + pTempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || + pTempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + pTempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); + + //Make sure that this spell includes a healing effect (or an apply aura with a periodic heal) + if (pTempSpell->Effect[j] == SPELL_EFFECT_HEAL || + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || + (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && pTempSpell->EffectApplyAuraName[j] == 8)) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); + + //Make sure that this spell applies an aura + if (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); } } +} - int id = GetScriptId(Name.c_str()); - if (id) +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) { - // try to find the script in assigned scripts - bool IsExist = false; - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) - { - if (m_scripts[i]) - { - // if the assigned script's name and the new script's name is the same - if (m_scripts[i]->Name == Name) - { - IsExist = true; - break; - } - } - } + SpellHandlerScript* tmpscript = ScriptRegistry<SpellHandlerScript>::GetScriptById(itr->second); + if (!tmpscript) + continue; - // if the script doesn't assigned -> assign it! - if (!IsExist) + SpellScript* script = tmpscript->GetSpellScript(); + + if (!script) { - m_scripts[id] = this; - ++num_sc_scripts; + sLog.outError("Spell script %s for spell %u returned a NULL SpellScript pointer!", tmpscript->ToString(), spell_id); + continue; } - // if the script is already assigned -> delete it! - else + + script_vector.push_back(script); + } +} + +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + script_vector.reserve(std::distance(bounds.first, bounds.second)); + + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + SpellHandlerScript* tmpscript = ScriptRegistry<SpellHandlerScript>::GetScriptById(itr->second); + if (!tmpscript) + continue; + + SpellScript* script = tmpscript->GetSpellScript(); + + if (!script) { - // TODO: write a better error message than this one :) - sLog.outError("ScriptName: '%s' already assigned with the same ScriptName, so the script can't work.", Name.c_str()); - delete this; + sLog.outError("Spell script %s for spell %u returned a NULL SpellScript pointer!", tmpscript->ToString(), spell_id); + continue; } + + script_vector.push_back(std::make_pair(script, itr)); } - else - { - if (Name.find("example") == std::string::npos) - sLog.outErrorDb("TrinityScript: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); - delete this; +} + +void ScriptMgr::OnNetworkStart() +{ + FOREACH_SCRIPT(ServerScript)->OnNetworkStart(); +} + +void ScriptMgr::OnNetworkStop() +{ + FOREACH_SCRIPT(ServerScript)->OnNetworkStop(); +} + +void ScriptMgr::OnSocketOpen(WorldSocket* socket) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnSocketOpen(socket); +} + +void ScriptMgr::OnSocketClose(WorldSocket* socket, bool wasNew) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket, wasNew); +} + +void ScriptMgr::OnPacketReceive(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnPacketReceive(socket, packet); +} + +void ScriptMgr::OnPacketSend(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnPacketSend(socket, packet); +} + +void ScriptMgr::OnUnknownPacketReceive(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnUnknownPacketReceive(socket, packet); +} + +void ScriptMgr::OnOpenStateChange(bool open) +{ + FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open); +} + +void ScriptMgr::OnConfigLoad(bool reload) +{ + FOREACH_SCRIPT(WorldScript)->OnConfigLoad(reload); +} + +void ScriptMgr::OnMotdChange(std::string& newMotd) +{ + FOREACH_SCRIPT(WorldScript)->OnMotdChange(newMotd); +} + +void ScriptMgr::OnShutdown(ShutdownExitCode code, ShutdownMask mask) +{ + FOREACH_SCRIPT(WorldScript)->OnShutdown(code, mask); +} + +void ScriptMgr::OnShutdownCancel() +{ + FOREACH_SCRIPT(WorldScript)->OnShutdownCancel(); +} + +void ScriptMgr::OnWorldUpdate(uint32 diff) +{ + FOREACH_SCRIPT(WorldScript)->OnUpdate(NULL, diff); +} + +void ScriptMgr::OnHonorCalculation(float& honor, uint8 level, uint32 count) +{ + FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, count); +} + +void ScriptMgr::OnHonorCalculation(uint32& honor, uint8 level, uint32 count) +{ + FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, count); +} + +void ScriptMgr::OnGetGrayLevel(uint8& grayLevel, uint8 playerLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetGrayLevel(grayLevel, playerLevel); +} + +void ScriptMgr::OnGetColorCode(XPColorChar& color, uint8 playerLevel, uint8 mobLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetColorCode(color, playerLevel, mobLevel); +} + +void ScriptMgr::OnGetZeroDifference(uint8& diff, uint8 playerLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetZeroDifference(diff, playerLevel); +} + +void ScriptMgr::OnGetBaseGain(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetBaseGain(gain, playerLevel, mobLevel, content); +} + +void ScriptMgr::OnGetGain(uint32& gain, Player* player, Unit* unit) +{ + ASSERT(player); + ASSERT(unit); + + FOREACH_SCRIPT(FormulaScript)->OnGetGain(gain, player, unit); +} + +void ScriptMgr::OnGetGroupRate(float& rate, uint32 count, bool isRaid) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetGroupRate(rate, count, isRaid); +} + +#define SCR_MAP_BGN(M,V,I,E,C,T) \ + if (V->GetEntry()->T()) \ + { \ + FOR_SCRIPTS(M, I, E) \ + { \ + MapEntry const* C = I->second->GetEntry(); \ + if (!C) \ + continue; \ + if (entry->MapID == V->GetId()) \ + { + +#define SCR_MAP_END \ + break; \ + } \ + } \ } + +void ScriptMgr::OnCreateMap(Map* map) +{ + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnCreate(map); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnCreate((InstanceMap*)map); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnCreate((BattleGroundMap*)map); + SCR_MAP_END; } -void ScriptMgr::OnLogin(Player *pPlayer) +void ScriptMgr::OnDestroyMap(Map* map) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogin) return; - tmpscript->pOnLogin(pPlayer); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnDestroy(map); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnDestroy((InstanceMap*)map); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnDestroy((BattleGroundMap*)map); + SCR_MAP_END; } -void ScriptMgr::OnLogout(Player *pPlayer) +void ScriptMgr::OnLoadGridMap(Map* map, uint32 gx, uint32 gy) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogout) return; - tmpscript->pOnLogout(pPlayer); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnLoadGridMap(map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnLoadGridMap((InstanceMap*)map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnLoadGridMap((BattleGroundMap*)map, gx, gy); + SCR_MAP_END; } -void ScriptMgr::OnPVPKill(Player *killer, Player *killed) +void ScriptMgr::OnUnloadGridMap(Map* map, uint32 gx, uint32 gy) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPVPKill) return; - tmpscript->pOnPVPKill(killer, killed); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnUnloadGridMap(map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnUnloadGridMap((InstanceMap*)map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnUnloadGridMap((BattleGroundMap*)map, gx, gy); + SCR_MAP_END; } -bool ScriptMgr::OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell) +void ScriptMgr::OnPlayerEnter(Map* map, Player* player) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnSpellCast) return true; - return tmpscript->pOnSpellCast(pUnitTarget,pItemTarget,pGoTarget,i,spell); + ASSERT(map); + ASSERT(player); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnPlayerEnter(map, player); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnPlayerEnter((InstanceMap*)map, player); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnPlayerEnter((BattleGroundMap*)map, player); + SCR_MAP_END; } -uint32 ScriptMgr::OnGetXP(Player *pPlayer, uint32 amount) +void ScriptMgr::OnPlayerLeave(Map* map, Player* player) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetXP) return amount; - return tmpscript->pOnGetXP(pPlayer,amount); + ASSERT(map); + ASSERT(player); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnPlayerLeave(map, player); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnPlayerLeave((InstanceMap*)map, player); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnPlayerLeave((BattleGroundMap*)map, player); + SCR_MAP_END; } -uint32 ScriptMgr::OnGetMoney(Player *pPlayer, int32 amount) +void ScriptMgr::OnMapUpdate(Map* map, uint32 diff) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetMoney) return amount; - return tmpscript->pOnGetMoney(pPlayer,amount); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnUpdate(map, diff); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnUpdate((InstanceMap*)map, diff); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnUpdate((BattleGroundMap*)map, diff); + SCR_MAP_END; } -bool ScriptMgr::OnPlayerChat(Player *pPlayer, const char *text) +#undef SCR_MAP_BGN +#undef SCR_MAP_END + +InstanceData* ScriptMgr::CreateInstanceData(InstanceMap* map) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPlayerChat) return true; - return tmpscript->pOnPlayerChat(pPlayer,text); + ASSERT(map); + + GET_SCRIPT_RET(InstanceMapScript, map->GetScriptId(), tmpscript, NULL); + return tmpscript->OnGetInstanceData(map); } -void ScriptMgr::OnServerStartup() +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerStartup) return; - tmpscript->pOnServerStartup(); + ASSERT(caster); + ASSERT(target); + + GET_SCRIPT_RET(ItemScript, target->GetProto()->ScriptId, tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -void ScriptMgr::OnServerShutdown() +bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerShutdown) return; - tmpscript->pOnServerShutdown(); + ASSERT(player); + ASSERT(item); + ASSERT(quest); + + GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, item, quest); } -void ScriptMgr::OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea) +bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& targets) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnAreaChange) return; - tmpscript->pOnAreaChange(pPlayer, pArea); + ASSERT(player); + ASSERT(item); + + GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false); + return tmpscript->OnUse(player, item, targets); } -bool ScriptMgr::OnItemClick (Player *pPlayer, Item *pItem) +bool ScriptMgr::OnItemExpire(Player* player, ItemPrototype const* proto) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemClick) return true; - return tmpscript->pOnItemClick(pPlayer,pItem); + ASSERT(player); + ASSERT(proto); + + GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false); + return tmpscript->OnExpire(player, proto); } -bool ScriptMgr::OnItemOpen (Player *pPlayer, Item *pItem) +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemOpen) return true; - return tmpscript->pOnItemOpen(pPlayer,pItem); + ASSERT(caster); + ASSERT(target); + + GET_SCRIPT_RET(CreatureScript, target->GetScriptId(), tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -bool ScriptMgr::OnGoClick (Player *pPlayer, GameObject *pGameObject) +bool ScriptMgr::OnGossipHello(Player* player, Creature* creature) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGoClick) return true; - return tmpscript->pOnGoClick(pPlayer,pGameObject); + ASSERT(player); + ASSERT(creature); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipHello(player, creature); } -void ScriptMgr::OnCreatureKill (Player *pPlayer, Creature *pCreature) +bool ScriptMgr::OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnCreatureKill) return; - tmpscript->pOnCreatureKill(pPlayer,pCreature); + ASSERT(player); + ASSERT(creature); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelect(player, creature, sender, action); } -char const* ScriptMgr::ScriptsVersion() +bool ScriptMgr::OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) { - return "Integrated Trinity Scripts"; + ASSERT(player); + ASSERT(creature); + ASSERT(code); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelectCode(player, creature, sender, action, code); } -bool ScriptMgr::GossipHello (Player * pPlayer, Creature* pCreature) +bool ScriptMgr::OnQuestAccept(Player* player, Creature* creature, Quest const* quest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipHello) return false; + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipHello(pPlayer, pCreature); + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, creature, quest); } -bool ScriptMgr::GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool ScriptMgr::OnQuestSelect(Player* player, Creature* creature, Quest const* quest) { - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + ASSERT(player); + ASSERT(creature); + ASSERT(quest); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestSelect(player, creature, quest); +} - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelect) return false; +bool ScriptMgr::OnQuestComplete(Player* player, Creature* creature, Quest const* quest) +{ + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestComplete(player, creature, quest); } -bool ScriptMgr::GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode) +bool ScriptMgr::OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt) { - sLog.outDebug("TSCR: Gossip selection with code, sender: %d, action: %d", uiSender, uiAction); + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false; + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestReward(player, creature, quest, opt); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); +uint32 ScriptMgr::GetDialogStatus(Player* player, Creature* creature) +{ + ASSERT(player); + ASSERT(creature); + + // TODO: 100 is a funny magic number to have hanging around here... + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, 100); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnDialogStatus(player, creature); } -bool ScriptMgr::GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction) +CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) { - if (!pGO) - return false; - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + ASSERT(creature); - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelect) return false; + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, NULL); + return tmpscript->OnGetAI(); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelect(pPlayer, pGO, uiSender, uiAction); +void ScriptMgr::OnCreatureUpdate(Creature* creature, uint32 diff) +{ + ASSERT(creature); + + GET_SCRIPT(CreatureScript, creature->GetScriptId(), tmpscript); + tmpscript->OnUpdate(creature, diff); } -bool ScriptMgr::GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode) +bool ScriptMgr::OnGossipHello(Player* player, GameObject* go) { - if (!pGO) - return false; - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d",uiSender, uiAction); + ASSERT(player); + ASSERT(go); - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelectWithCode) return false; + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipHello(player, go); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelectWithCode(pPlayer, pGO, uiSender ,uiAction, sCode); +bool ScriptMgr::OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) +{ + ASSERT(player); + ASSERT(go); + + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelect(player, go, sender, action); } -bool ScriptMgr::QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestAccept) return false; + ASSERT(player); + ASSERT(go); + ASSERT(code); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestAccept(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelectCode(player, go, sender, action, code); } -bool ScriptMgr::QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnQuestAccept(Player* player, GameObject* go, Quest const* quest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestSelect) return false; + ASSERT(player); + ASSERT(go); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestSelect(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, go, quest); } -bool ScriptMgr::QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestComplete) return false; + ASSERT(player); + ASSERT(go); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestComplete(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestReward(player, go, quest, opt); } -bool ScriptMgr::ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) +uint32 ScriptMgr::GetDialogStatus(Player* player, GameObject* go) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pChooseReward) return false; + ASSERT(player); + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pChooseReward(pPlayer, pCreature, pQuest, opt); + // TODO: 100 is a funny magic number to have hanging around here... + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, 100); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnDialogStatus(player, go); } -uint32 ScriptMgr::NPCDialogStatus(Player* pPlayer, Creature* pCreature) +void ScriptMgr::OnGameObjectDestroyed(Player* player, GameObject* go, uint32 eventId) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100; + ASSERT(player); + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pNPCDialogStatus(pPlayer, pCreature); + GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript); + tmpscript->OnDestroyed(player, go, eventId); } -uint32 ScriptMgr::GODialogStatus(Player* pPlayer, GameObject* pGO) +void ScriptMgr::OnGameObjectUpdate(GameObject* go, uint32 diff) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGODialogStatus) return 100; + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGODialogStatus(pPlayer, pGO); + GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript); + tmpscript->OnUpdate(go, diff); } -bool ScriptMgr::ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest) +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemHello) return false; + ASSERT(caster); + ASSERT(target); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemHello(pPlayer, pItem, pQuest); + GET_SCRIPT_RET(GameObjectScript, target->GetScriptId(), tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -bool ScriptMgr::ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) +bool ScriptMgr::OnTrigger(Player* player, AreaTriggerEntry const* trigger) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemQuestAccept) return false; + ASSERT(player); + ASSERT(trigger); + + GET_SCRIPT_RET(AreaTriggerScript, trigger->id, tmpscript, false); + return tmpscript->OnTrigger(player, trigger); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemQuestAccept(pPlayer, pItem, pQuest); +BattleGround* ScriptMgr::CreateBattleground(BattleGroundTypeId typeId) +{ + // TODO: Implement script-side battlegrounds. + ASSERT(false); + return NULL; } -bool ScriptMgr::GOHello(Player* pPlayer, GameObject* pGO) +OutdoorPvP* ScriptMgr::CreateOutdoorPvP(OutdoorPvPData const* data) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOHello) return false; + ASSERT(data); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOHello(pPlayer, pGO); + GET_SCRIPT_RET(OutdoorPvPScript, data->ScriptId, tmpscript, NULL); + return tmpscript->OnGetOutdoorPvP(); } -bool ScriptMgr::GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest) +std::vector<ChatCommand*> ScriptMgr::GetChatCommands() { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOQuestAccept) return false; + std::vector<ChatCommand*> table; + + FOR_SCRIPTS_RET(CommandScript, itr, end, table) + table.push_back(itr->second->OnGetCommands()); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOQuestAccept(pPlayer, pGO, pQuest); + return table; } -bool ScriptMgr::GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt) +void ScriptMgr::OnWeatherChange(Weather* weather, WeatherState state, float grade) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOChooseReward) return false; + ASSERT(weather); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOChooseReward(pPlayer, pGO, pQuest, opt); + GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript); + tmpscript->OnChange(weather, state, grade); } -void ScriptMgr::GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent) +void ScriptMgr::OnWeatherUpdate(Weather* weather, uint32 diff) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript) return; - tmpscript->pGODestroyed(pPlayer, pGO, destroyedEvent); + ASSERT(weather); + + GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript); + tmpscript->OnUpdate(weather, diff); } -bool ScriptMgr::AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) +void ScriptMgr::OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; - if (!tmpscript || !tmpscript->pAreaTrigger) return false; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pAreaTrigger(pPlayer, atEntry); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, entry); } -CreatureAI* ScriptMgr::GetAI(Creature* pCreature) +void ScriptMgr::OnRemoveAuction(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->GetAI) return NULL; + ASSERT(ah); + ASSERT(entry); - return tmpscript->GetAI(pCreature); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, entry); } -bool ScriptMgr::ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemUse) return false; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pItemUse(pPlayer, pItem, targets); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, entry); } -bool ScriptMgr::ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto) +void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pItemProto->ScriptId]; - if (!tmpscript || !tmpscript->pItemExpire) return true; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pItemExpire(pPlayer, pItemProto); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, entry); } -bool ScriptMgr::EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget) +bool ScriptMgr::OnConditionCheck(Condition* condition, Player* player, Unit* targetOverride) { - Script *tmpscript = m_scripts[crTarget->GetScriptId()]; + ASSERT(condition); + ASSERT(player); + + GET_SCRIPT_RET(ConditionScript, condition->mScriptId, tmpscript, true); + return tmpscript->OnConditionCheck(condition, player, targetOverride); +} - if (!tmpscript || !tmpscript->pEffectDummyCreature) return false; +void ScriptMgr::OnInstall(Vehicle* veh) +{ + ASSERT(veh); - return tmpscript->pEffectDummyCreature(caster, spellId, effIndex, crTarget); + FOREACH_SCRIPT(VehicleScript)->OnInstall(veh); } -bool ScriptMgr::EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget) +void ScriptMgr::OnUninstall(Vehicle* veh) { - Script *tmpscript = m_scripts[gameObjTarget->GetGOInfo()->ScriptId]; + ASSERT(veh); - if (!tmpscript || !tmpscript->pEffectDummyGameObj) return false; + FOREACH_SCRIPT(VehicleScript)->OnUninstall(veh); +} - return tmpscript->pEffectDummyGameObj(caster, spellId, effIndex, gameObjTarget); +void ScriptMgr::OnDie(Vehicle* veh) +{ + ASSERT(veh); + + FOREACH_SCRIPT(VehicleScript)->OnDie(veh); } -bool ScriptMgr::EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget) +void ScriptMgr::OnReset(Vehicle* veh) { - Script *tmpscript = m_scripts[itemTarget->GetProto()->ScriptId]; + ASSERT(veh); + + FOREACH_SCRIPT(VehicleScript)->OnReset(veh); +} - if (!tmpscript || !tmpscript->pEffectDummyItem) return false; +void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory) +{ + ASSERT(veh); + ASSERT(accessory); - return tmpscript->pEffectDummyItem(caster, spellId, effIndex, itemTarget); + FOREACH_SCRIPT(VehicleScript)->OnInstallAccessory(veh, accessory); } -InstanceData* ScriptMgr::CreateInstanceData(Map *map) +void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId) { - if (!map->IsDungeon()) return NULL; + ASSERT(veh); + ASSERT(passenger); - Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; - if (!tmpscript || !tmpscript->GetInstanceData) return NULL; + FOREACH_SCRIPT(VehicleScript)->OnAddPassenger(veh, passenger, seatId); +} - return tmpscript->GetInstanceData(map); +void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger) +{ + ASSERT(veh); + ASSERT(passenger); + + FOREACH_SCRIPT(VehicleScript)->OnRemovePassenger(veh, passenger); } -void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector) +void ScriptMgr::OnDynamicObjectUpdate(DynamicObject* dynobj, uint32 diff) { - SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); - for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) - { - Script *tmpscript = m_scripts[itr->second]; - if (!tmpscript || !tmpscript->GetSpellScript) continue; - script_vector.push_back(tmpscript->GetSpellScript()); - } + ASSERT(dynobj); + + FOR_SCRIPTS(DynamicObjectScript, itr, end) + itr->second->OnUpdate(dynobj, diff); } -void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector) +void ScriptMgr::OnAddPassenger(Transport* transport, Player* player) { - SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); - script_vector.reserve(std::distance(bounds.first, bounds.second)); - for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + ASSERT(transport); + ASSERT(player); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnAddPassenger(transport, player); +} + +void ScriptMgr::OnAddCreaturePassenger(Transport* transport, Creature* creature) +{ + ASSERT(transport); + ASSERT(creature); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnAddCreaturePassenger(transport, creature); +} + +void ScriptMgr::OnRemovePassenger(Transport* transport, Player* player) +{ + ASSERT(transport); + ASSERT(player); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnRemovePassenger(transport, player); +} + +void ScriptMgr::OnTransportUpdate(Transport* transport, uint32 diff) +{ + ASSERT(transport); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnUpdate(transport, diff); +} + +void SpellHandlerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<SpellHandlerScript>::AddScript(this); +} + +void AuraHandlerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AuraHandlerScript>::AddScript(this); +} + +void ServerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ServerScript>::AddScript(this); +} + +void WorldScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WorldScript>::AddScript(this); +} + +void FormulaScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<FormulaScript>::AddScript(this); +} + +void WorldMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WorldMapScript>::AddScript(this); +} + +void InstanceMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<InstanceMapScript>::AddScript(this); +} + +void BattlegroundMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<BattlegroundMapScript>::AddScript(this); +} + +void AreaTriggerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AreaTriggerScript>::AddScript(this); +} + +void ItemScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ItemScript>::AddScript(this); +} + +void CreatureScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<CreatureScript>::AddScript(this); +} + +void GameObjectScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<GameObjectScript>::AddScript(this); +} + +void BattlegroundScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<BattlegroundScript>::AddScript(this); +} + +void OutdoorPvPScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<OutdoorPvPScript>::AddScript(this); +} + +void CommandScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<CommandScript>::AddScript(this); +} + +void WeatherScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WeatherScript>::AddScript(this); +} + +void AuctionHouseScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AuctionHouseScript>::AddScript(this); +} + +void ConditionScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ConditionScript>::AddScript(this); +} + +void VehicleScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<VehicleScript>::AddScript(this); +} + +void DynamicObjectScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<DynamicObjectScript>::AddScript(this); +} + +void TransportScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<TransportScript>::AddScript(this); +} + +template<class TScript> +void ScriptMgr::ScriptRegistry<TScript>::AddScript(TScript* const script) +{ + ASSERT(script); + + // See if the script is using the same memory as another script. If this happens, it means that + // someone forgot to allocate new memory for a script. + for (ScriptMap::iterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) { - Script *tmpscript = m_scripts[itr->second]; - if (!tmpscript || !tmpscript->GetSpellScript) continue; - script_vector.push_back(std::make_pair(tmpscript->GetSpellScript(), itr)); + if (it->second == script) + { + sLog.outError("Script '%s' forgot to allocate memory, so this script and/or the script before that can't work.", + script->ToString()); + + return; + } + } + + // Get an ID for the script. An ID only exists if it's a script that is assigned in the database + // through a script name (or similar). + uint32 id = GetScriptId(script->ToString()); + if (id) + { + // Try to find an existing script. + bool existing = false; + for (ScriptMap::iterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + { + // If the script names match... + if (it->second->GetName() == script->GetName()) + { + // ... It exists. + existing = true; + break; + } + } + + // If the script isn't assigned -> assign it! + if (!existing) + { + ScriptPointerList[id] = script; + sScriptMgr.IncrementScriptCount(); + } + else + { + // If the script is already assigned -> delete it! + sLog.outError("Script '%s' already assigned with the same script name, so the script can't work.", + script->ToString()); + + delete script; + } + } + else if (script->IsDatabaseBound()) + { + // The script uses a script name from database, but isn't assigned to anything. + if (script->GetName().find("example") == std::string::npos) + sLog.outErrorDb("Script named '%s' does not have a script name assigned in database.", + script->ToString()); + + delete script; + } + else + { + // We're dealing with a code-only script; just add it. + ScriptPointerList[_scriptIdCounter++] = script; + sScriptMgr.IncrementScriptCount(); } } + +// Instantiate static members of ScriptMgr::ScriptRegistry. +template<class TScript> std::map<uint32, TScript*> ScriptMgr::ScriptRegistry<TScript>::ScriptPointerList; +template<class TScript> uint32 ScriptMgr::ScriptRegistry<TScript>::_scriptIdCounter; + +// Specialize for each script type class like so: +template class ScriptMgr::ScriptRegistry<SpellHandlerScript>; +template class ScriptMgr::ScriptRegistry<AuraHandlerScript>; +template class ScriptMgr::ScriptRegistry<ServerScript>; +template class ScriptMgr::ScriptRegistry<WorldScript>; +template class ScriptMgr::ScriptRegistry<FormulaScript>; +template class ScriptMgr::ScriptRegistry<WorldMapScript>; +template class ScriptMgr::ScriptRegistry<InstanceMapScript>; +template class ScriptMgr::ScriptRegistry<BattlegroundMapScript>; +template class ScriptMgr::ScriptRegistry<ItemScript>; +template class ScriptMgr::ScriptRegistry<CreatureScript>; +template class ScriptMgr::ScriptRegistry<GameObjectScript>; +template class ScriptMgr::ScriptRegistry<AreaTriggerScript>; +template class ScriptMgr::ScriptRegistry<BattlegroundScript>; +template class ScriptMgr::ScriptRegistry<OutdoorPvPScript>; +template class ScriptMgr::ScriptRegistry<CommandScript>; +template class ScriptMgr::ScriptRegistry<WeatherScript>; +template class ScriptMgr::ScriptRegistry<AuctionHouseScript>; +template class ScriptMgr::ScriptRegistry<ConditionScript>; +template class ScriptMgr::ScriptRegistry<VehicleScript>; +template class ScriptMgr::ScriptRegistry<DynamicObjectScript>; +template class ScriptMgr::ScriptRegistry<TransportScript>; + +// Undefine utility macros. +#undef GET_SCRIPT_RET +#undef GET_SCRIPT +#undef FOREACH_SCRIPT +#undef FOR_SCRIPTS_RET +#undef FOR_SCRIPTS +#undef SCR_REG_LST +#undef SCR_REG_MAP diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 4ce6b403cea..64d8e92abea 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -13,6 +13,15 @@ #include "DBCStructure.h" #include "Config.h" #include "ObjectMgr.h" +#include "BattleGround.h" +#include "OutdoorPvPMgr.h" +#include "SharedDefines.h" +#include "Chat.h" +#include "Weather.h" +#include "AuctionHouseMgr.h" +#include "ConditionMgr.h" +#include "Vehicle.h" +#include "Transport.h" class Player; class Creature; @@ -28,134 +37,893 @@ class Unit; class WorldObject; struct ItemPrototype; class Spell; +class ScriptMgr; +class WorldSocket; -#define MAX_SCRIPTS 5000 //72 bytes each (approx 351kb) #define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid) #define DEFAULT_TEXT "<Trinity Script Text Entry Missing!>" -struct Script -{ - Script() : - pOnLogin(NULL), pOnLogout(NULL), pOnPVPKill(NULL), pOnSpellCast(NULL), pOnGetXP(NULL), - pOnGetMoney(NULL), pOnPlayerChat(NULL), pOnServerStartup(NULL), pOnServerShutdown(NULL), - pOnAreaChange(NULL), pOnItemClick(NULL), pOnItemOpen(NULL), pOnGoClick(NULL), pOnCreatureKill(NULL), - pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL), - pGOSelect(NULL), pGOSelectWithCode(NULL), - pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), - pChooseReward(NULL), pGODestroyed(NULL), pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), - pGOQuestAccept(NULL), pGOChooseReward(NULL),pItemUse(NULL), pItemExpire(NULL), - pEffectDummyCreature(NULL), pEffectDummyGameObj(NULL), pEffectDummyItem(NULL), - GetAI(NULL), GetInstanceData(NULL), GetSpellScript(NULL) - {} - - std::string Name; - - //Methods to be scripted - void (*pOnLogin)(Player*); - void (*pOnLogout)(Player*); - void (*pOnPVPKill)(Player*, Player*); - bool (*pOnSpellCast)(Unit*, Item*, GameObject*, uint32, SpellEntry const*); - uint32 (*pOnGetXP)(Player*, uint32); - int32 (*pOnGetMoney)(Player*, int32); - bool (*pOnPlayerChat)(Player*, const char*); - void (*pOnServerStartup)(); - void (*pOnServerShutdown)(); - void (*pOnAreaChange)(Player*, AreaTableEntry const*); - bool (*pOnItemClick)(Player*, Item*); - bool (*pOnItemOpen)(Player*, Item*); - bool (*pOnGoClick)(Player*, GameObject*); - void (*pOnCreatureKill)(Player*, Creature*); - bool (*pGossipHello)(Player*, Creature*); - bool (*pQuestAccept)(Player*, Creature*, Quest const*); - bool (*pGossipSelect)(Player*, Creature*, uint32 , uint32); - bool (*pGossipSelectWithCode)(Player*, Creature*, uint32 , uint32 , const char*); - bool (*pGOSelect)(Player*, GameObject*, uint32 , uint32); - bool (*pGOSelectWithCode)(Player*, GameObject*, uint32 , uint32 , const char*); - bool (*pQuestSelect)(Player*, Creature*, Quest const*); - bool (*pQuestComplete)(Player*, Creature*, Quest const*); - uint32 (*pNPCDialogStatus)(Player*, Creature*); - uint32 (*pGODialogStatus)(Player*, GameObject * _GO); - bool (*pChooseReward)(Player*, Creature*, Quest const*, uint32); - bool (*pItemHello)(Player*, Item*, Quest const*); - bool (*pGOHello)(Player*, GameObject*); - bool (*pAreaTrigger)(Player*, AreaTriggerEntry const*); - bool (*pItemQuestAccept)(Player*, Item *, Quest const*); - bool (*pGOQuestAccept)(Player*, GameObject*, Quest const*); - bool (*pGOChooseReward)(Player*, GameObject*, Quest const*, uint32); - void (*pGODestroyed)(Player*, GameObject*, uint32); - bool (*pItemUse)(Player*, Item*, SpellCastTargets const&); - bool (*pItemExpire)(Player*, ItemPrototype const *); - bool (*pEffectDummyCreature)(Unit*, uint32, uint32, Creature*); - bool (*pEffectDummyGameObj)(Unit*, uint32, uint32, GameObject*); - bool (*pEffectDummyItem)(Unit*, uint32, uint32, Item*); - - CreatureAI* (*GetAI)(Creature*); - InstanceData* (*GetInstanceData)(Map*); - - SpellScript*(*GetSpellScript)(); - //AuraScript*(*GetAuraScript)(); - - void RegisterSelf(); +// Generic scripting text function. +void DoScriptText(int32 textEntry, WorldObject* pSource, Unit *pTarget = NULL); + +/* + TODO: Add more script type classes. + + ChatScript + MailScript + SessionScript + CollisionScript + GroupScript + ArenaTeamScript + GuildScript + +*/ + +/* + Standard procedure when adding new script type classes: + + First of all, define the actual class, and have it inherit from ScriptObject, like so: + + class MyScriptType : public ScriptObject + { + uint32 _someId; + + protected: + + MyScriptType(const char* name, uint32 someId) + : ScriptObject(name), _someId(someId) + { } + + void RegisterSelf(); + + public: + + // If a virtual function in your script type class is not necessarily + // required to be overridden, just declare it virtual with an empty + // body. If, on the other hand, it's logical only to override it (i.e. + // if it's the only method in the class), make it pure virtual, by adding + // = 0 to it. + virtual void OnSomeEvent(uint32 someArg1, std::string& someArg2) { } + + // This is a pure virtual function: + virtual void OnAnotherEvent(uint32 someArg) = 0; + } + + RegisterSelf() should be defined in ScriptMgr.cpp, and simply registers the script + with ScriptRegistry: + + void MyScriptType::RegisterSelf() + { + ScriptMgr::ScriptRegistry<MyScriptType>::AddScript(this); + } + + Next, you need to add a specialization for ScriptRegistry. Put this in the bottom of + ScriptMgr.cpp: + + template class ScriptMgr::ScriptRegistry<MyScriptType>; + + Now, add a cleanup routine in ScriptMgr::~ScriptMgr: + + SCR_CLEAR(MyScriptType); + + Now your script type is good to go with the script system. What you need to do now + is add functions to ScriptMgr that can be called from the core to actually trigger + certain events. For example, in ScriptMgr.h: + + void OnSomeEvent(uint32 someArg1, std::string& someArg2); + void OnAnotherEvent(uint32 someArg); + + In ScriptMgr.cpp: + + void ScriptMgr::OnSomeEvent(uint32 someArg1, std::string& someArg2) + { + FOREACH_SCRIPT(MyScriptType)->OnSomeEvent(someArg1, someArg2); + } + + void ScriptMgr::OnAnotherEvent(uint32 someArg) + { + FOREACH_SCRIPT(MyScriptType)->OnAnotherEvent(someArg1, someArg2); + } + + Now you simply call these two functions from anywhere in the core to trigger the + event on all registered scripts of that type. +*/ + +class ScriptObject +{ + friend class ScriptMgr; + + public: + + // Called when the script is initialized. Use it to initialize any properties of the script. + virtual void OnInitialize() { } + + // Called when the script is deleted. Use it to free memory, etc. + virtual void OnTeardown() { } + + // Do not override this in scripts; it should be overridden by the various script type classes. It indicates + // whether or not this script type must be assigned in the database. + virtual bool IsDatabaseBound() const { return false; } + + const std::string& GetName() const { return _name; } + + const char* ToString() const { return _name.c_str(); } + + protected: + + // Call this to register the script with ScriptMgr. + virtual void RegisterSelf() = 0; + + ScriptObject(const char* name) + : _name(std::string(name)) + { + // Allow the script to do startup routines. + OnInitialize(); + + // Register with ScriptMgr. + RegisterSelf(); + } + + virtual ~ScriptObject() + { + // Allow the script to do cleanup routines. + OnTeardown(); + } + + private: + + const std::string _name; +}; + +template<class TObject> class UpdatableScript +{ + protected: + + UpdatableScript() + { + } + + public: + + virtual void OnUpdate(TObject* obj, uint32 diff) { } +}; + +class SpellHandlerScript : public ScriptObject +{ + protected: + + SpellHandlerScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Should return a fully valid SpellScript pointer. + virtual SpellScript* GetSpellScript() const = 0; +}; + +class AuraHandlerScript : public ScriptObject +{ + protected: + + AuraHandlerScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Should return a fully valid AuraScript pointer. + // virtual AuraScript* GetAuraScript() const = 0; +}; + +class ServerScript : public ScriptObject +{ + protected: + + ServerScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Called when reactive socket I/O is started (WorldSocketMgr). + virtual void OnNetworkStart() { } + + // Called when reactive I/O is stopped. + virtual void OnNetworkStop() { } + + // Called when a remote socket establishes a connection to the server. Do not store the socket object. + virtual void OnSocketOpen(WorldSocket* socket) { } + + // Called when a socket is closed. Do not store the socket object, and do not rely on the connection + // being open; it is not. + virtual void OnSocketClose(WorldSocket* socket, bool wasNew) { } + + // Called when a packet is sent to a client. The packet object is a copy of the original packet, so reading + // and modifying it is safe. + virtual void OnPacketSend(WorldSocket* socket, WorldPacket& packet) { } + + // Called when a (valid) packet is received by a client. The packet object is a copy of the original packet, so + // reading and modifying it is safe. + virtual void OnPacketReceive(WorldSocket* socket, WorldPacket& packet) { } + + // Called when an invalid (unknown opcode) packet is received by a client. The packet is a reference to the orignal + // packet; not a copy. This allows you to actually handle unknown packets (for whatever purpose). + virtual void OnUnknownPacketReceive(WorldSocket* socket, WorldPacket& packet) { } +}; + +class WorldScript : public ScriptObject, public UpdatableScript<void> +{ + protected: + + WorldScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Called when the open/closed state of the world changes. + virtual void OnOpenStateChange(bool open) { } + + // Called after the world configuration is (re)loaded. + virtual void OnConfigLoad(bool reload) { } + + // Called before the message of the day is changed. + virtual void OnMotdChange(std::string& newMotd) { } + + // Called when a world shutdown is initiated. + virtual void OnShutdown(ShutdownExitCode code, ShutdownMask mask) { } + + // Called when a world shutdown is cancelled. + virtual void OnShutdownCancel() { } + + // Called on every world tick (don't execute too heavy code here). + virtual void OnUpdate(void* null, uint32 diff) { } +}; + +class FormulaScript : public ScriptObject +{ + protected: + + FormulaScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Called after calculating honor. + virtual void OnHonorCalculation(float& honor, uint8 level, uint32 count) { } + + // Called after calculating honor. + virtual void OnHonorCalculation(uint32& honor, uint8 level, uint32 count) { } + + // Called after gray level calculation. + virtual void OnGetGrayLevel(uint8& grayLevel, uint8 playerLevel) { } + + // Called after calculating experience color. + virtual void OnGetColorCode(XPColorChar& color, uint8 playerLevel, uint8 mobLevel) { } + + // Called after calculating zero difference. + virtual void OnGetZeroDifference(uint8& diff, uint8 playerLevel) { } + + // Called after calculating base experience gain. + virtual void OnGetBaseGain(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content) { } + + // Called after calculating experience gain. + virtual void OnGetGain(uint32& gain, Player* player, Unit* unit) { } + + virtual void OnGetGroupRate(float& rate, uint32 count, bool isRaid) { } +}; + +template<class TMap> class MapScript : public UpdatableScript<TMap> +{ + MapEntry const* _mapEntry; + + protected: + + MapScript(uint32 mapId) + : _mapEntry(sMapStore.LookupEntry(mapId)) + { + if (!_mapEntry) + sLog.outError("Invalid MapScript for %u; no such map ID.", mapId); + } + + public: + + // Gets the MapEntry structure associated with this script. Can return NULL. + MapEntry const* GetEntry() { return _mapEntry; } + + // Called when the map is created. + virtual void OnCreate(TMap* map) { } + + // Called just before the map is destroyed. + virtual void OnDestroy(TMap* map) { } + + // Called when a grid map is loaded. + virtual void OnLoadGridMap(TMap* map, uint32 gx, uint32 gy) { } + + // Called when a grid map is unloaded. + virtual void OnUnloadGridMap(TMap* map, uint32 gx, uint32 gy) { } + + // Called when a player enters the map. + virtual void OnPlayerEnter(TMap* map, Player* player) { } + + // Called when a player leaves the map. + virtual void OnPlayerLeave(TMap* map, Player* player) { } + + // Called on every map update tick. + virtual void OnUpdate(TMap* map, uint32 diff) { } +}; + +class WorldMapScript : public ScriptObject, public MapScript<Map> +{ + protected: + + WorldMapScript(const char* name, uint32 mapId) + : ScriptObject(name), MapScript(mapId) + { + if (GetEntry() && !GetEntry()->IsContinent()) + sLog.outError("WorldMapScript for map %u is invalid.", mapId); + } + + void RegisterSelf(); +}; + +class InstanceMapScript : public ScriptObject, public MapScript<InstanceMap> +{ + protected: + + InstanceMapScript(const char* name, uint32 mapId = 0) + : ScriptObject(name), MapScript(mapId) + { + if (GetEntry() && !GetEntry()->IsDungeon()) + sLog.outError("InstanceMapScript for map %u is invalid.", mapId); + } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Gets an InstanceData object for this instance. + virtual InstanceData* OnGetInstanceData(InstanceMap* map) { return NULL; } +}; + +class BattlegroundMapScript : public ScriptObject, public MapScript<BattleGroundMap> +{ + protected: + + BattlegroundMapScript(const char* name, uint32 mapId) + : ScriptObject(name), MapScript(mapId) + { + if (GetEntry() && !GetEntry()->IsBattleGround()) + sLog.outError("BattlegroundMapScript for map %u is invalid.", mapId); + } + + void RegisterSelf(); +}; + +class ItemScript : public ScriptObject +{ + protected: + + ItemScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when a dummy spell effect is triggered on the item. + virtual bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target) { return false; } + + // Called when a player accepts a quest from the item. + virtual bool OnQuestAccept(Player* player, Item* item, Quest const* quest) { return false; } + + // Called when a player uses the item. + virtual bool OnUse(Player* player, Item* item, SpellCastTargets const& targets) { return false; } + + // Called when the item expires (is destroyed). + virtual bool OnExpire(Player* player, ItemPrototype const* proto) { return false; } +}; + +class CreatureScript : public ScriptObject, public UpdatableScript<Creature> +{ + protected: + + CreatureScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when a dummy spell effect is triggered on the creature. + virtual bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target) { return false; } + + // Called when a player opens a gossip dialog with the creature. + virtual bool OnGossipHello(Player* player, Creature* creature) { return false; } + + // Called when a player selects a gossip item in the creature's gossip menu. + virtual bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { return false; } + + // Called when a player selects a gossip with a code in the creature's gossip menu. + virtual bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) { return false; } + + // Called when a player accepts a quest from the creature. + virtual bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) { return false; } + + // Called when a player selects a quest in the creature's quest menu. + virtual bool OnQuestSelect(Player* player, Creature* creature, Quest const* quest) { return false; } + + // Called when a player completes a quest with the creature. + virtual bool OnQuestComplete(Player* player, Creature* creature, Quest const* quest) { return false; } + + // Called when a player selects a quest reward. + virtual bool OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt) { return false; } + + // Called when the dialog status between a player and the creature is requested. + virtual uint32 OnDialogStatus(Player* player, Creature* creature) { return 0; } + + // Called when a CreatureAI object is needed for the creature. + virtual CreatureAI* OnGetAI() { return NULL; } +}; + +class GameObjectScript : public ScriptObject, public UpdatableScript<GameObject> +{ + protected: + + GameObjectScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when a dummy spell effect is triggered on the gameobject. + virtual bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target) { return false; } + + // Called when a player opens a gossip dialog with the gameobject. + virtual bool OnGossipHello(Player* player, GameObject* go) { return false; } + + // Called when a player selects a gossip item in the gameobject's gossip menu. + virtual bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) { return false; } + + // Called when a player selects a gossip with a code in the gameobject's gossip menu. + virtual bool OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code) { return false; } + + // Called when a player accepts a quest from the gameobject. + virtual bool OnQuestAccept(Player* player, GameObject* go, Quest const* quest) { return false; } + + // Called when a player selects a quest reward. + virtual bool OnQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt) { return false; } + + // Called when the dialog status between a player and the gameobject is requested. + virtual uint32 OnDialogStatus(Player* player, GameObject* go) { return 0; } + + // Called when the gameobject is destroyed (destructible buildings only). + virtual void OnDestroyed(Player* player, GameObject* go, uint32 eventId) { } +}; + +class AreaTriggerScript : public ScriptObject +{ + protected: + + AreaTriggerScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when the area trigger is activated by a player. + bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) { return false; } +}; + +class BattlegroundScript : public ScriptObject +{ + protected: + + BattlegroundScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Should return a fully valid BattleGround object for the type ID. + virtual BattleGround* OnGetBattleground() = 0; +}; + +class OutdoorPvPScript : public ScriptObject +{ + protected: + + OutdoorPvPScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Should return a fully valid OutdoorPvP object for the type ID. + virtual OutdoorPvP* OnGetOutdoorPvP() = 0; +}; + +class CommandScript : public ScriptObject +{ + protected: + + CommandScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Should return a pointer to a valid command table (ChatCommand array) to be used by ChatHandler. + virtual ChatCommand* OnGetCommands() = 0; +}; + +class WeatherScript : public ScriptObject, public UpdatableScript<Weather> +{ + protected: + + WeatherScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when the weather changes in the zone this script is associated with. + virtual void OnChange(Weather* weather, WeatherState state, float grade) { } +}; + +class AuctionHouseScript : public ScriptObject +{ + protected: + + AuctionHouseScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Called when an auction is added to an auction house. + void OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry) { } + + // Called when an auction is removed from an auction house. + void OnAuctionRemove(AuctionHouseObject* ah, AuctionEntry* entry) { } + + // Called when an auction was succesfully completed. + void OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry) { } + + // Called when an auction expires. + void OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry) { } }; +class ConditionScript : public ScriptObject +{ + protected: + + ConditionScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when a single condition is checked for a player. + bool OnConditionCheck(Condition* condition, Player* player, Unit* targetOverride) { return true; } +}; + +class VehicleScript : public ScriptObject +{ + protected: + + VehicleScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); + + public: + + // Called after a vehicle is installed. + virtual void OnInstall(Vehicle* veh) { } + + // Called after a vehicle is uninstalled. + virtual void OnUninstall(Vehicle* veh) { } + + // Called after a vehicle dies. + virtual void OnDie(Vehicle* veh) { } + + // Called when a vehicle resets. + virtual void OnReset(Vehicle* veh) { } + + // Called after an accessory is installed in a vehicle. + virtual void OnInstallAccessory(Vehicle* veh, Creature* accessory) { } + + // Called after a passenger is added to a vehicle. + virtual void OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId) { } + + // Called after a passenger is removed from a vehicle. + virtual void OnRemovePassenger(Vehicle* veh, Unit* passenger) { } +}; + +class DynamicObjectScript : public ScriptObject, public UpdatableScript<DynamicObject> +{ + protected: + + DynamicObjectScript(const char* name) + : ScriptObject(name) + { } + + void RegisterSelf(); +}; + +class TransportScript : public ScriptObject, public UpdatableScript<Transport> +{ + protected: + + TransportScript(const char* name) + : ScriptObject(name) + { + } + + void RegisterSelf(); + + public: + + bool IsDatabaseBound() const { return true; } + + // Called when a player boards the transport. + virtual void OnAddPassenger(Transport* transport, Player* player) { } + + // Called when a creature boards the transport. + virtual void OnAddCreaturePassenger(Transport* transport, Creature* creature) { } + + // Called when a player exits the transport. + virtual void OnRemovePassenger(Transport* transport, Player* player) { } +}; + +// Placed here due to ScriptRegistry::AddScript dependency. +#define sScriptMgr (*ACE_Singleton<ScriptMgr, ACE_Null_Mutex>::instance()) + +// Manages registration, loading, and execution of scripts. class ScriptMgr { friend class ACE_Singleton<ScriptMgr, ACE_Null_Mutex>; + friend class ScriptObject; + ScriptMgr(); - public: - ~ScriptMgr(); - - void ScriptsInit(); - void LoadDatabase(); - char const* ScriptsVersion(); - - //event handlers - void OnLogin(Player *pPlayer); - void OnLogout(Player *pPlayer); - void OnPVPKill(Player *killer, Player *killed); - bool OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell); - uint32 OnGetXP(Player *pPlayer, uint32 amount); - uint32 OnGetMoney(Player *pPlayer, int32 amount); - bool OnPlayerChat(Player *pPlayer, const char *text); - void OnServerStartup(); - void OnServerShutdown(); - void OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea); - bool OnItemClick (Player *pPlayer, Item *pItem); - bool OnItemOpen (Player *pPlayer, Item *pItem); - bool OnGoClick (Player *pPlayer, GameObject *pGameObject); - void OnCreatureKill (Player *pPlayer, Creature *pCreature); - bool GossipHello (Player * pPlayer, Creature* pCreature); - bool GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction); - bool GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode); - bool GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction); - bool GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode); - bool QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest); - bool ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt); - uint32 NPCDialogStatus(Player* pPlayer, Creature* pCreature); - uint32 GODialogStatus(Player* pPlayer, GameObject* pGO); - bool ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest); - bool ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest); - bool GOHello(Player* pPlayer, GameObject* pGO); - bool GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest); - bool GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt); - void GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent); - bool AreaTrigger(Player* pPlayer,AreaTriggerEntry const* atEntry); - CreatureAI* GetAI(Creature* pCreature); - bool ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); - bool ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto); - bool EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget); - bool EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget); - bool EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget); - InstanceData* CreateInstanceData(Map *map); - void CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector); - void CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector); -}; - -//Generic scripting text function -void DoScriptText(int32 textEntry, WorldObject* pSource, Unit *pTarget = NULL); + ~ScriptMgr(); -#define sScriptMgr (*ACE_Singleton<ScriptMgr, ACE_Null_Mutex>::instance()) -#endif + uint32 _scriptCount; + + void LoadDatabase(); + void FillSpellSummary(); + + public: /* Initialization */ + + void Initialize(); + const char* ScriptsVersion() const { return "Integrated Trinity Scripts"; } + + void IncrementScriptCount() { ++_scriptCount; } + uint32 GetScriptCount() const { return _scriptCount; } + + public: /* SpellHandlerScript */ + + void CreateSpellScripts(uint32 spell_id, std::list<SpellScript*>& script_vector); + void CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript*, SpellScriptsMap::iterator> >& script_vector); + + public: /* AuraHandlerScript */ + + // void CreateAuraScripts(uint32 spell_id, std::list<AuraScript*>& script_vector); + // void CreateAuraScripts(uint32 spell_id, std::vector<std::pair<AuraScript*, SpellScriptsMap::iterator> >& script_vector); + + public: /* ServerScript */ + + void OnNetworkStart(); + void OnNetworkStop(); + void OnSocketOpen(WorldSocket* socket); + void OnSocketClose(WorldSocket* socket, bool wasNew); + void OnPacketReceive(WorldSocket* socket, WorldPacket& packet); + void OnPacketSend(WorldSocket* socket, WorldPacket& packet); + void OnUnknownPacketReceive(WorldSocket* socket, WorldPacket& packet); + + public: /* WorldScript */ + + void OnOpenStateChange(bool open); + void OnConfigLoad(bool reload); + void OnMotdChange(std::string& newMotd); + void OnShutdown(ShutdownExitCode code, ShutdownMask mask); + void OnShutdownCancel(); + void OnWorldUpdate(uint32 diff); + + public: /* FormulaScript */ + void OnHonorCalculation(float& honor, uint8 level, uint32 count); + void OnHonorCalculation(uint32& honor, uint8 level, uint32 count); + void OnGetGrayLevel(uint8& grayLevel, uint8 playerLevel); + void OnGetColorCode(XPColorChar& color, uint8 playerLevel, uint8 mobLevel); + void OnGetZeroDifference(uint8& diff, uint8 playerLevel); + void OnGetBaseGain(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content); + void OnGetGain(uint32& gain, Player* player, Unit* unit); + void OnGetGroupRate(float& rate, uint32 count, bool isRaid); + + public: /* MapScript */ + + void OnCreateMap(Map* map); + void OnDestroyMap(Map* map); + void OnLoadGridMap(Map* map, uint32 gx, uint32 gy); + void OnUnloadGridMap(Map* map, uint32 gx, uint32 gy); + void OnPlayerEnter(Map* map, Player* player); + void OnPlayerLeave(Map* map, Player* player); + void OnMapUpdate(Map* map, uint32 diff); + + public: /* InstanceMapScript */ + + InstanceData* CreateInstanceData(InstanceMap* map); + + public: /* ItemScript */ + + bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target); + bool OnQuestAccept(Player* player, Item* item, Quest const* quest); + bool OnItemUse(Player* player, Item* item, SpellCastTargets const& targets); + bool OnItemExpire(Player* player, ItemPrototype const* proto); + + public: /* CreatureScript */ + + bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target); + bool OnGossipHello(Player* player, Creature* creature); + bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action); + bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code); + bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest); + bool OnQuestSelect(Player* player, Creature* creature, Quest const* quest); + bool OnQuestComplete(Player* player, Creature* creature, Quest const* quest); + bool OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt); + uint32 GetDialogStatus(Player* player, Creature* creature); + CreatureAI* GetCreatureAI(Creature* creature); + void OnCreatureUpdate(Creature* creature, uint32 diff); + + public: /* GameObjectScript */ + + bool OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target); + bool OnGossipHello(Player* player, GameObject* go); + bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action); + bool OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code); + bool OnQuestAccept(Player* player, GameObject* go, Quest const* quest); + bool OnQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt); + uint32 GetDialogStatus(Player* player, GameObject* go); + void OnGameObjectDestroyed(Player* player, GameObject* go, uint32 eventId); + void OnGameObjectUpdate(GameObject* go, uint32 diff); + + public: /* AreaTriggerScript */ + + bool OnTrigger(Player* player, AreaTriggerEntry const* trigger); + + public: /* BattlegroundScript */ + + BattleGround* CreateBattleground(BattleGroundTypeId typeId); + + public: /* OutdoorPvPScript */ + + OutdoorPvP* CreateOutdoorPvP(OutdoorPvPData const* data); + + public: /* CommandScript */ + + std::vector<ChatCommand*> GetChatCommands(); + + public: /* WeatherScript */ + + void OnWeatherChange(Weather* weather, WeatherState state, float grade); + void OnWeatherUpdate(Weather* weather, uint32 diff); + + public: /* AuctionHouseScript */ + + void OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry); + void OnRemoveAuction(AuctionHouseObject* ah, AuctionEntry* entry); + void OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry); + void OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry); + + public: /* ConditionScript */ + + bool OnConditionCheck(Condition* condition, Player* player, Unit* targetOverride); + + public: /* VehicleScript */ + + void OnInstall(Vehicle* veh); + void OnUninstall(Vehicle* veh); + void OnDie(Vehicle* veh); + void OnReset(Vehicle* veh); + void OnInstallAccessory(Vehicle* veh, Creature* accessory); + void OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId); + void OnRemovePassenger(Vehicle* veh, Unit* passenger); + + public: /* DynamicObjectScript */ + + void OnDynamicObjectUpdate(DynamicObject* dynobj, uint32 diff); + + public: /* TransportScript */ + + void OnAddPassenger(Transport* transport, Player* player); + void OnAddCreaturePassenger(Transport* transport, Creature* creature); + void OnRemovePassenger(Transport* transport, Player* player); + void OnTransportUpdate(Transport* transport, uint32 diff); + + public: /* ScriptRegistry */ + + // This is the global static registry of scripts. + template<class TScript> class ScriptRegistry + { + // Counter used for code-only scripts. + static uint32 _scriptIdCounter; + + public: + + typedef std::map<uint32, TScript*> ScriptMap; + + // The actual list of scripts. This will be accessed concurrently, so it must not be modified + // after server startup. + static ScriptMap ScriptPointerList; + + // Gets a script by its ID (assigned by ObjectMgr). + static TScript* GetScriptById(uint32 id) + { + for (ScriptMap::iterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + if (it->first == id) + return it->second; + + return NULL; + } + + // Attempts to add a new script to the list. + static void AddScript(TScript* const script); + }; +}; + +#endif diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h index 7102e4a43e1..52401502c83 100644 --- a/src/server/game/Scripting/ScriptSystem.h +++ b/src/server/game/Scripting/ScriptSystem.h @@ -97,6 +97,6 @@ class SystemMgr PointMoveMap m_mPointMoveMap; //coordinates for waypoints }; -#define pSystemMgr SystemMgr::Instance() +#define sScriptSystemMgr SystemMgr::Instance() #endif diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 94afaee6f0f..45a41dc099d 100644 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -806,8 +806,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) m_playerLoading = false; - //Hook for OnLogin Event - sScriptMgr.OnLogin(pCurrChar); delete holder; } @@ -1360,48 +1358,3 @@ void WorldSession::HandleEquipmentSetUse(WorldPacket &recv_data) data << uint8(0); // 4 - equipment swap failed - inventory is full SendPacket(&data); } - -void WorldSession::HandleOnPVPKill(Player *killed) -{ - sScriptMgr.OnPVPKill(GetPlayer(), killed); -} - -bool WorldSession::HandleOnPlayerChat(const char *text) -{ - return sScriptMgr.OnPlayerChat(GetPlayer(), text); -} - -uint32 WorldSession::HandleOnGetXP(uint32 amount) -{ - return sScriptMgr.OnGetXP(GetPlayer(), amount); -} - -int32 WorldSession::HandleOnGetMoney(int32 amount) -{ - return sScriptMgr.OnGetMoney(GetPlayer(), amount); -} - -void WorldSession::HandleOnAreaChange(AreaTableEntry const *pArea) -{ - sScriptMgr.OnAreaChange(GetPlayer(), pArea); -} - -bool WorldSession::HandleOnItemClick(Item *pItem) -{ - return sScriptMgr.OnItemClick(GetPlayer(), pItem); -} - -bool WorldSession::HandleOnItemOpen(Item *pItem) -{ - return sScriptMgr.OnItemOpen(GetPlayer(), pItem); -} - -bool WorldSession::HandleOnGoClick(GameObject *pGameObject) -{ - return sScriptMgr.OnGoClick(GetPlayer(), pGameObject); -} - -void WorldSession::HandleOnCreatureKill(Creature *pCreature) -{ - sScriptMgr.OnCreatureKill(GetPlayer(), pCreature); -} diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp index b7aa9b66979..264f48b7265 100644 --- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp @@ -140,21 +140,21 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) { if (unit) { - if (!sScriptMgr.GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str())) + if (!sScriptMgr.OnGossipSelectCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str())) _player->OnGossipSelect(unit, gossipListId, menuId); } else - sScriptMgr.GOSelectWithCode(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()); + sScriptMgr.OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId), code.c_str()); } else { if (unit) { - if (!sScriptMgr.GossipSelect(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId))) + if (!sScriptMgr.OnGossipSelect(_player, unit, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId))) _player->OnGossipSelect(unit, gossipListId, menuId); } else - sScriptMgr.GOSelect(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)); + sScriptMgr.OnGossipSelect(_player, go, _player->PlayerTalkClass->GossipOptionSender(gossipListId), _player->PlayerTalkClass->GossipOptionAction(gossipListId)); } } @@ -884,7 +884,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) } } - if (sScriptMgr.AreaTrigger(GetPlayer(), atEntry)) + if (sScriptMgr.OnTrigger(GetPlayer(), atEntry)) return; uint32 quest_id = objmgr.GetQuestForAreaTrigger(Trigger_ID); diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp index 935ccf02f96..3caf0db9dac 100644 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp @@ -340,7 +340,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket & recv_data) } } - if (!sScriptMgr.GossipHello(_player, unit)) + if (!sScriptMgr.OnGossipHello(_player, unit)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); _player->PrepareGossipMenu(unit, unit->GetCreatureInfo()->GossipMenuId, true); diff --git a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp b/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp index 8c7b87be79c..7344ad6d272 100644 --- a/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/QuestHandler.cpp @@ -56,7 +56,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) Creature* cr_questgiver=questgiver->ToCreature(); if (!cr_questgiver->IsHostileTo(_player)) // not show quest status to enemies { - questStatus = sScriptMgr.NPCDialogStatus(_player, cr_questgiver); + questStatus = sScriptMgr.GetDialogStatus(_player, cr_questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, cr_questgiver, defstatus); } @@ -66,7 +66,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket & recv_data) { sLog.outDebug("WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject guid = %u",uint32(GUID_LOPART(guid))); GameObject* go_questgiver=(GameObject*)questgiver; - questStatus = sScriptMgr.GODialogStatus(_player, go_questgiver); + questStatus = sScriptMgr.GetDialogStatus(_player, go_questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, go_questgiver, defstatus); break; @@ -101,7 +101,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket & recv_data) // Stop the npc if moving pCreature->StopMoving(); - if (sScriptMgr.GossipHello(_player, pCreature)) + if (sScriptMgr.OnGossipHello(_player, pCreature)) return; _player->PrepareGossipMenu(pCreature, pCreature->GetCreatureInfo()->GossipMenuId, true); @@ -188,12 +188,12 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) switch(pObject->GetTypeId()) { case TYPEID_UNIT: - sScriptMgr.QuestAccept(_player, (pObject->ToCreature()), qInfo); + sScriptMgr.OnQuestAccept(_player, (pObject->ToCreature()), qInfo); break; case TYPEID_ITEM: case TYPEID_CONTAINER: { - sScriptMgr.ItemQuestAccept(_player, ((Item*)pObject), qInfo); + sScriptMgr.OnQuestAccept(_player, ((Item*)pObject), qInfo); // destroy not required for quest finish quest starting item bool destroyItem = true; @@ -212,7 +212,7 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode(WorldPacket & recv_data) break; } case TYPEID_GAMEOBJECT: - sScriptMgr.GOQuestAccept(_player, ((GameObject*)pObject), qInfo); + sScriptMgr.OnQuestAccept(_player, ((GameObject*)pObject), qInfo); break; } _player->PlayerTalkClass->CloseGossip(); @@ -307,7 +307,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) switch(pObject->GetTypeId()) { case TYPEID_UNIT: - if (!(sScriptMgr.ChooseReward(_player, (pObject->ToCreature()), pQuest, reward))) + if (!(sScriptMgr.OnQuestReward(_player, (pObject->ToCreature()), pQuest, reward))) { // Send next quest if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) @@ -315,7 +315,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket & recv_data) } break; case TYPEID_GAMEOBJECT: - if (!sScriptMgr.GOChooseReward(_player, ((GameObject*)pObject), pQuest, reward)) + if (!sScriptMgr.OnQuestReward(_player, ((GameObject*)pObject), pQuest, reward)) { // Send next quest if (Quest const* nextquest = _player->GetNextQuest(guid ,pQuest)) @@ -672,7 +672,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket continue; if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; - questStatus = sScriptMgr.NPCDialogStatus(_player, questgiver); + questStatus = sScriptMgr.GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); @@ -687,7 +687,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket continue; if (questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) continue; - questStatus = sScriptMgr.GODialogStatus(_player, questgiver); + questStatus = sScriptMgr.GetDialogStatus(_player, questgiver); if (questStatus > 6) questStatus = getDialogStatus(_player, questgiver, defstatus); diff --git a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp index 4179474db47..a46d4e336d6 100644 --- a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp @@ -156,7 +156,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) } //Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. - if (!sScriptMgr.ItemUse(pUser,pItem,targets)) + if (!sScriptMgr.OnItemUse(pUser,pItem,targets)) { // no script or script not process request by self pUser->CastItemUseSpell(pItem,targets,cast_count,glyphIndex); @@ -199,9 +199,6 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) return; } - if (!pUser->GetSession()->HandleOnItemOpen(pItem)) - return; - // locked item uint32 lockId = proto->LockID; if (lockId) @@ -266,7 +263,7 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) if (!obj) return; - if (sScriptMgr.GOHello(_player, obj)) + if (sScriptMgr.OnGossipHello(_player, obj)) return; obj->Use(_player); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index cc4644e0434..931e2e6519f 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -196,6 +196,8 @@ bool WorldSession::Update(uint32 diff) sLog.outError("SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); + + sScriptMgr.OnUnknownPacketReceive(m_Socket, WorldPacket(*packet)); } else { @@ -213,6 +215,7 @@ bool WorldSession::Update(uint32 diff) } else if (_player->IsInWorld()) { + sScriptMgr.OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); @@ -227,6 +230,7 @@ bool WorldSession::Update(uint32 diff) else { // not expected _player or must checked in packet hanlder + sScriptMgr.OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); @@ -239,6 +243,7 @@ bool WorldSession::Update(uint32 diff) LogUnexpectedOpcode(packet, "the player is still in world"); else { + sScriptMgr.OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); @@ -256,7 +261,8 @@ bool WorldSession::Update(uint32 diff) // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; - + + sScriptMgr.OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); @@ -471,9 +477,6 @@ void WorldSession::LogoutPlayer(bool Save) sLog.outDebug("SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } - //Hook for OnLogout Event - sScriptMgr.OnLogout(_player); - m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index f88b34d3127..9b5bca8b53f 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -785,15 +785,6 @@ class WorldSession void HandleReadyForAccountDataTimes(WorldPacket& recv_data); void HandleQueryQuestsCompleted(WorldPacket& recv_data); void HandleQuestPOIQuery(WorldPacket& recv_data); - void HandleOnPVPKill(Player *killed); - bool HandleOnPlayerChat(const char *text); - uint32 HandleOnGetXP(uint32 amount); - int32 HandleOnGetMoney(int32 amount); - void HandleOnAreaChange(AreaTableEntry const *pArea); - bool HandleOnItemClick(Item *pItem); - bool HandleOnItemOpen(Item *pItem); - bool HandleOnGoClick(GameObject *pGameObject); - void HandleOnCreatureKill(Creature *pCreature); void HandleEjectPasenger(WorldPacket &data); void HandleEnterPlayerVehicle(WorldPacket &data); private: diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index f7b128fb761..dea11417e23 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -45,6 +45,7 @@ #include "WorldSocketMgr.h" #include "Log.h" #include "WorldLog.h" +#include "ScriptMgr.h" #if defined(__GNUC__) #pragma pack(1) @@ -186,6 +187,9 @@ int WorldSocket::SendPacket (const WorldPacket& pct) sWorldLog.outLog("\n"); } + // Create a copy of the original packet; this is to avoid issues if a hook modifies it. + sScriptMgr.OnPacketSend(this, WorldPacket(pct)); + ServerPktHeader header(pct.size()+2, pct.GetOpcode()); m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); @@ -705,7 +709,8 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct) sWorldLog.outLog ("\n"); } - try { + try + { switch(opcode) { case CMSG_PING: @@ -716,11 +721,12 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct) sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); return -1; } - + + sScriptMgr.OnPacketReceive(this, WorldPacket(*new_pct)); return HandleAuthSession (*new_pct); case CMSG_KEEP_ALIVE: DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size()); - + sScriptMgr.OnPacketReceive(this, WorldPacket(*new_pct)); return 0; default: { @@ -747,7 +753,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct) } } } - catch(ByteBufferException &) + catch (ByteBufferException &) { sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1); diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 192105a5ba3..d4015c47e76 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -45,6 +45,7 @@ #include "Config.h" #include "DatabaseEnv.h" #include "WorldSocket.h" +#include "ScriptMgr.h" /** * This is a helper class to WorldSocketMgr ,that manages @@ -116,6 +117,8 @@ class ReactorRunnable : protected ACE_Task_Base sock->reactor (m_Reactor); m_NewSockets.insert (sock); + sScriptMgr.OnSocketOpen(sock); + return 0; } @@ -139,6 +142,8 @@ class ReactorRunnable : protected ACE_Task_Base if (sock->IsClosed()) { + sScriptMgr.OnSocketClose(sock, true); + sock->RemoveReference(); --m_Connections; } @@ -176,7 +181,11 @@ class ReactorRunnable : protected ACE_Task_Base { t = i; ++i; + (*t)->CloseSocket(); + + sScriptMgr.OnSocketClose((*t), false); + (*t)->RemoveReference(); --m_Connections; m_Sockets.erase (t); @@ -279,6 +288,8 @@ WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) if (StartReactiveIO(port, address) == -1) return -1; + sScriptMgr.OnNetworkStart(); + return 0; } @@ -300,6 +311,8 @@ WorldSocketMgr::StopNetwork() } Wait(); + + sScriptMgr.OnNetworkStop(); } void diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 80b1aacd54d..0af5b043fd7 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2327,7 +2327,7 @@ void AuraEffect::TriggerSpell(Unit * target, Unit * caster) const triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, 0, this); sLog.outDebug("AuraEffect::TriggerSpell: Spell %u Trigger %u",GetId(), triggeredSpellInfo->Id); } - else if (target->GetTypeId() != TYPEID_UNIT || !sScriptMgr.EffectDummyCreature(caster, GetId(), GetEffIndex(), triggerTarget->ToCreature())) + else if (target->GetTypeId() != TYPEID_UNIT || !sScriptMgr.OnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex()), triggerTarget->ToCreature())) sLog.outError("AuraEffect::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex()); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index cad47652544..ca7443fbbcf 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4553,9 +4553,6 @@ void Spell::HandleThreatSpells(uint32 spellId) void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i) { - if (!sScriptMgr.OnSpellCast(pUnitTarget,pItemTarget,pGOTarget,i,m_spellInfo)) - return; - //effect has been handled, skip it if (m_effectMask & (1<<i)) return; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index a42501a8ac5..f7c5b759334 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1936,11 +1936,11 @@ void Spell::EffectDummy(uint32 i) // Script based implementation. Must be used only for not good for implementation in core spell effects // So called only for not proccessed cases if (gameObjTarget) - sScriptMgr.EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget); + sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), gameObjTarget); else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) - sScriptMgr.EffectDummyCreature(m_caster, m_spellInfo->Id, i, unitTarget->ToCreature()); + sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), unitTarget->ToCreature()); else if (itemTarget) - sScriptMgr.EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget); + sScriptMgr.OnDummyEffect(m_caster, m_spellInfo->Id, SpellEffIndex(i), itemTarget); } void Spell::EffectTriggerSpellWithValue(uint32 i) @@ -3128,7 +3128,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) if (gameObjTarget) { - if (sScriptMgr.GOHello(player, gameObjTarget)) + if (sScriptMgr.OnGossipHello(player, gameObjTarget)) return; switch (gameObjTarget->GetGoType()) diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index 5c5779a6506..8c3da68f538 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -29,6 +29,7 @@ #include "Log.h" #include "ObjectMgr.h" #include "Util.h" +#include "ScriptMgr.h" /// Create the Weather object Weather::Weather(uint32 zone, WeatherData const* weatherChances) @@ -46,7 +47,8 @@ bool Weather::Update(uint32 diff) { if (m_timer.GetCurrent() >= 0) m_timer.Update(diff); - else m_timer.SetCurrent(0); + else + m_timer.SetCurrent(0); ///- If the timer has passed, ReGenerate the weather if (m_timer.Passed()) @@ -60,6 +62,8 @@ bool Weather::Update(uint32 diff) return false; } } + + sScriptMgr.OnWeatherUpdate(this, diff); return true; } @@ -266,6 +270,7 @@ bool Weather::UpdateWeather() } sLog.outDetail("Change the weather of zone %u to %s.", m_zone, wthstr); + sScriptMgr.OnWeatherChange(this, state, m_grade); return true; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 5a54f9f85da..0554bf5e5a7 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -70,6 +70,7 @@ #include "ConditionMgr.h" #include "DisableMgr.h" #include "CharacterDatabaseCleaner.h" +#include "ScriptMgr.h" volatile bool World::m_stopEvent = false; uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; @@ -165,6 +166,31 @@ Player* World::FindPlayerInZone(uint32 zone) return NULL; } +bool World::IsClosed() const +{ + return m_isClosed; +} + +void World::SetClosed(bool val) +{ + m_isClosed = val; + + // Invert the value, for simplicity for scripters. + sScriptMgr.OnOpenStateChange(!val); +} + +void World::SetMotd(const std::string& motd) +{ + m_motd = motd; + + sScriptMgr.OnMotdChange(m_motd); +} + +const char* World::GetMotd() const +{ + return m_motd.c_str(); +} + /// Find a session by its id WorldSession* World::FindSession(uint32 id) const { @@ -1223,7 +1249,6 @@ void World::LoadConfigSettings(bool reload) if (m_configs[CONFIG_PVP_TOKEN_COUNT] < 1) m_configs[CONFIG_PVP_TOKEN_COUNT] = 1; - m_configs[CONFIG_NO_RESET_TALENT_COST] = sConfig.GetBoolDefault("NoResetTalentsCost", false); m_configs[CONFIG_SHOW_KICK_IN_WORLD] = sConfig.GetBoolDefault("ShowKickInWorld", false); m_configs[CONFIG_INTERVAL_LOG_UPDATE] = sConfig.GetIntDefault("RecordUpdateTimeDiffInterval", 60000); @@ -1240,6 +1265,8 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_CHATLOG_PUBLIC] = sConfig.GetBoolDefault("ChatLogs.Public", false); m_configs[CONFIG_CHATLOG_ADDON] = sConfig.GetBoolDefault("ChatLogs.Addon", false); m_configs[CONFIG_CHATLOG_BGROUND] = sConfig.GetBoolDefault("ChatLogs.BattleGround", false); + + sScriptMgr.OnConfigLoad(reload); } /// Initialize the World @@ -1624,7 +1651,7 @@ void World::SetInitialWorldSettings() objmgr.LoadSpellScriptNames(); sLog.outString("Initializing Scripts..."); - sScriptMgr.ScriptsInit(); + sScriptMgr.Initialize(); sLog.outString("Validating spell scripts..."); objmgr.ValidateSpellScripts(); @@ -1733,7 +1760,6 @@ void World::SetInitialWorldSettings() else sLog.SetLogDB(false); - sScriptMgr.OnServerStartup(); sLog.outString("WORLD: World initialized"); } @@ -1847,7 +1873,8 @@ void World::LoadAutobroadcasts() /// Update the World ! void World::Update(uint32 diff) { - m_updateTime = uint32(diff); + m_updateTime = diff; + if (m_configs[CONFIG_INTERVAL_LOG_UPDATE]) { if (m_updateTimeSum > m_configs[CONFIG_INTERVAL_LOG_UPDATE]) @@ -1867,7 +1894,8 @@ void World::Update(uint32 diff) for (int i = 0; i < WUPDATE_COUNT; ++i) if (m_timers[i].GetCurrent() >= 0) m_timers[i].Update(diff); - else m_timers[i].SetCurrent(0); + else + m_timers[i].SetCurrent(0); ///- Update the game time and check for shutdown time _UpdateGameTime(); @@ -1928,6 +1956,7 @@ void World::Update(uint32 diff) } } } + /// <li> Update uptime table if (m_timers[WUPDATE_UPTIME].Passed()) { @@ -1956,12 +1985,6 @@ void World::Update(uint32 diff) ///- Update objects when the timer has passed (maps, transport, creatures,...) sMapMgr.Update(diff); // As interval = 0 - /*if (m_timers[WUPDATE_OBJECTS].Passed()) - { - m_timers[WUPDATE_OBJECTS].Reset(); - sMapMgr.DoDelayedMovesAndRemoves(); - }*/ - static uint32 autobroadcaston = 0; autobroadcaston = sConfig.GetIntDefault("AutoBroadcast.On", 0); if (autobroadcaston == 1) @@ -2015,6 +2038,8 @@ void World::Update(uint32 diff) // And last, but not least handle the issued cli commands ProcessCliCommands(); + + sScriptMgr.OnWorldUpdate(diff); } void World::ForceGameEventUpdate() @@ -2361,7 +2386,7 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode) ShutdownMsg(true); } - sScriptMgr.OnServerShutdown(); + sScriptMgr.OnShutdown(ShutdownExitCode(exitcode), ShutdownMask(options)); } /// Display a shutdown message to the user(s) @@ -2409,6 +2434,8 @@ void World::ShutdownCancel() SendServerMessage(msgid); DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown")); + + sScriptMgr.OnShutdownCancel(); } /// Send a server message to the user(s) diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 29bb6f73fc3..5742741db07 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -525,10 +525,10 @@ class World void RemoveWeather(uint32 zone_id); /// Deny clients? - bool IsClosed() { return m_isClosed; } + bool IsClosed() const; /// Close world - void SetClosed(bool val) { m_isClosed = val; } + void SetClosed(bool val); /// Get the active session server limit (or security level limitations) uint32 GetPlayerAmountLimit() const { return m_playerLimit >= 0 ? m_playerLimit : 0; } @@ -553,9 +553,9 @@ class World void SetAllowMovement(bool allow) { m_allowMovement = allow; } /// Set a new Message of the Day - void SetMotd(const std::string& motd) { m_motd = motd; } + void SetMotd(const std::string& motd); /// Get the current Message of the Day - const char* GetMotd() const { return m_motd.c_str(); } + const char* GetMotd() const; /// Set the string for new characters (first login) void SetNewCharString(std::string str) { m_newCharString = str; } @@ -688,11 +688,11 @@ class World void UpdateAreaDependentAuras(); - void ProcessStartEvent(); - void ProcessStopEvent(); - bool GetEventKill() { return isEventKillStart; } + void ProcessStartEvent(); + void ProcessStopEvent(); + bool GetEventKill() { return isEventKillStart; } - bool isEventKillStart; + bool isEventKillStart; protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index eef7b7f65d3..b7cef4d8832 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -31,7 +31,6 @@ set(scripts_STAT_SRCS ${scripts_world} ${scripts_spells} ${scripts_examples} - Custom/on_events.cpp ../game/AI/ScriptedAI/ScriptedEscortAI.cpp ../game/AI/ScriptedAI/ScriptedCreature.cpp ../game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -90,6 +89,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Pet ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Player + ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Transport ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle ${CMAKE_SOURCE_DIR}/src/server/game/Events diff --git a/src/server/scripts/Custom/on_events.cpp b/src/server/scripts/Custom/on_events.cpp deleted file mode 100644 index 58cc8275a3a..00000000000 --- a/src/server/scripts/Custom/on_events.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.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; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. - */ - -#include "ScriptPCH.h" -#include <cstring> - -//This function is called when the player logs in (every login) -void OnLogin(Player * /*pPlayer*/) -{ - -} - -//This function is called when the player logs out -void OnLogout(Player * /*pPlayer*/) -{ - -} - -//This function is called when the player kills another player -void OnPVPKill(Player * /*killer*/, Player * /*killed*/) -{ - -} - -//This function is called when a players AreaID changes -void OnAreaChange(Player * /*pPlayer*/, AreaTableEntry const * /*pArea*/) -{ - -} - -//This is called when a player kills a creature (non pvp) -void OnCreatureKill(Player * /*pPlayer*/, Creature * /*pCreature*/) -{ - -} - -//This function is called when a player has a money exchange -int32 OnGetMoney(Player * /*pPlayer*/, int32 amount) -{ - return amount; -} - -//This function is called whenever a player gets XP -uint32 OnGetXP(Player * /*pPlayer*/, uint32 amount) -{ - return amount; -} - -//This function is called when a player clicks a GO Object -bool OnGoClick(Player * /*pPlayer*/, GameObject * /*pGameObject*/) -{ - return true; -} - -//This function is called when a player clicks and item -bool OnItemClick(Player * /*pPlayer*/, Item * /*pItem*/) -{ - return true; -} - -//This function is called when a player opens an item (like a clam) -bool OnItemOpen(Player * /*pPlayer*/, Item * /*pItem*/) -{ - return true; -} - -//This function is called when a player sends a chat message -bool OnPlayerChat(Player * /*pPlayer*/, const char * /*text*/) -{ - return true; -} - -//this function is called when the server starts -void OnServerStartup() -{ - -} -//this function is called when the server shuts down -void OnServerShutdown() -{ - -} - -//this function is called when a player casts a spell -bool OnSpellCast(Unit * /*pUnitTarget*/, Item * /*pItemTarget*/, GameObject * /*pGoTarget*/, uint32 /*i*/, SpellEntry const * /*spell*/) -{ - return true; -} - - void AddSC_onevents() -{ - Script *newscript; - newscript = new Script; - newscript->Name = "scripted_on_events"; - newscript->pOnLogin = &OnLogin; - newscript->pOnLogout = &OnLogout; - newscript->pOnPVPKill = &OnPVPKill; - newscript->pOnAreaChange = &OnAreaChange; - newscript->pOnCreatureKill = &OnCreatureKill; - newscript->pOnGetMoney = &OnGetMoney; - newscript->pOnGetXP = &OnGetXP; - newscript->pOnGoClick = &OnGoClick; - newscript->pOnItemClick = &OnItemClick; - newscript->pOnItemOpen = &OnItemOpen; - newscript->pOnPlayerChat = &OnPlayerChat; - newscript->pOnServerShutdown = &OnServerShutdown; - newscript->pOnServerStartup = &OnServerStartup; - newscript->pOnSpellCast = &OnSpellCast; - - newscript->RegisterSelf(); -} diff --git a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.h b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.h index 2fdd536b698..375e586f13b 100644 --- a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.h +++ b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.h @@ -5,32 +5,32 @@ #ifndef DEF_ZF_H #define DEF_ZF_H - enum zfEntries - { - ENTRY_ZUMRAH = 7271, - ENTRY_BLY = 7604, - ENTRY_RAVEN = 7605, - ENTRY_ORO = 7606, - ENTRY_WEEGLI = 7607, - ENTRY_MURTA = 7608, +enum zfEntries +{ + ENTRY_ZUMRAH = 7271, + ENTRY_BLY = 7604, + ENTRY_RAVEN = 7605, + ENTRY_ORO = 7606, + ENTRY_WEEGLI = 7607, + ENTRY_MURTA = 7608, - GO_END_DOOR = 146084, + GO_END_DOOR = 146084, - EVENT_PYRAMID = 1, - EVENT_GAHZRILLA - }; + EVENT_PYRAMID = 1, + EVENT_GAHZRILLA +}; - enum zfPyramidPhases - { - PYRAMID_NOT_STARTED, //default - PYRAMID_CAGES_OPEN, //happens in GO hello for cages - PYRAMID_ARRIVED_AT_STAIR , //happens in Weegli's movementinform - PYRAMID_WAVE_1, - PYRAMID_PRE_WAVE_2, - PYRAMID_WAVE_2, - PYRAMID_PRE_WAVE_3, - PYRAMID_WAVE_3, - PYRAMID_KILLED_ALL_TROLLS, - }; +enum zfPyramidPhases +{ + PYRAMID_NOT_STARTED, //default + PYRAMID_CAGES_OPEN, //happens in GO hello for cages + PYRAMID_ARRIVED_AT_STAIR , //happens in Weegli's movementinform + PYRAMID_WAVE_1, + PYRAMID_PRE_WAVE_2, + PYRAMID_WAVE_2, + PYRAMID_PRE_WAVE_3, + PYRAMID_WAVE_3, + PYRAMID_KILLED_ALL_TROLLS, +}; #endif
\ No newline at end of file diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index c158b9be3fb..3edf0c50c61 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -330,6 +330,10 @@ class HookList m_list.remove(t); return *this; } + size_t size() + { + return m_list.size(); + } ListIterator begin() { return m_list.begin(); |