aboutsummaryrefslogtreecommitdiff
path: root/src/game
diff options
context:
space:
mode:
authorRat <none@none>2010-06-04 23:24:48 +0200
committerRat <none@none>2010-06-04 23:24:48 +0200
commit1426c2970f42a2d065198806f750bf5dd28d580b (patch)
treee3247fb0f1770ab214e412e0f2d6edc5b91ec8f4 /src/game
parent5ca00bc14d38c5ad49f0ab4500af52e645133826 (diff)
HIGHLY EXPERIMENTAL - USE AT YOUR OWN RISK
implemented Condition System all systems should work like before after applying the sql converter you won't be able to apply any Updatepacks (<=up30) so do updates before this this revesion is not threated as stable! --HG-- branch : trunk
Diffstat (limited to 'src/game')
-rw-r--r--src/game/CMakeLists.txt2
-rw-r--r--src/game/Chat.cpp3
-rw-r--r--src/game/Chat.h3
-rw-r--r--src/game/CombatAI.cpp64
-rw-r--r--src/game/CombatAI.h12
-rw-r--r--src/game/ConditionMgr.cpp1145
-rw-r--r--src/game/ConditionMgr.h167
-rw-r--r--src/game/CreatureEventAI.cpp9
-rw-r--r--src/game/CreatureEventAIMgr.cpp15
-rw-r--r--src/game/Item.cpp14
-rw-r--r--src/game/Level3.cpp58
-rw-r--r--src/game/LootMgr.cpp150
-rw-r--r--src/game/LootMgr.h17
-rw-r--r--src/game/ObjectMgr.cpp408
-rw-r--r--src/game/ObjectMgr.h82
-rw-r--r--src/game/Player.cpp19
-rw-r--r--src/game/Player.h2
-rw-r--r--src/game/Spell.cpp55
-rw-r--r--src/game/SpellMgr.cpp168
-rw-r--r--src/game/SpellMgr.h11
-rw-r--r--src/game/World.cpp10
21 files changed, 1657 insertions, 757 deletions
diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt
index c425517f6cb..1ec450e9468 100644
--- a/src/game/CMakeLists.txt
+++ b/src/game/CMakeLists.txt
@@ -70,6 +70,8 @@ SET(game_STAT_SRCS
Chat.h
ChatHandler.cpp
CombatHandler.cpp
+ ConditionMgr.cpp
+ ConditionMgr.h
ConfusedMovementGenerator.cpp
ConfusedMovementGenerator.h
Corpse.cpp
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 76a5f688d37..d3d6e63a232 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -451,6 +451,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "areatrigger_teleport", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAreaTriggerTeleportCommand, "", NULL },
{ "autobroadcast", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadAutobroadcastCommand, "", NULL },
{ "command", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCommandCommand, "", NULL },
+ { "conditions", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadConditions, "", NULL },
{ "creature_ai_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAIScriptsCommand, "", NULL },
{ "creature_ai_summons", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAISummonsCommand, "", NULL },
{ "creature_ai_texts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventAITextsCommand, "", NULL },
@@ -473,7 +474,6 @@ ChatCommand * ChatHandler::getCommandTable()
{ "gossip_menu_option", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGossipMenuOptionCommand, "", NULL },
{ "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
- { "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL },
{ "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL },
{ "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
{ "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
@@ -512,7 +512,6 @@ ChatCommand * ChatHandler::getCommandTable()
{ "spell_linked_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLinkedSpellCommand, "", NULL },
{ "spell_pet_auras", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellPetAurasCommand, "", NULL },
{ "spell_proc_event", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellProcEventCommand, "", NULL },
- { "spell_script_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptTargetCommand, "", NULL },
{ "spell_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellScriptsCommand, "", NULL },
{ "spell_target_position", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellTargetPositionCommand, "", NULL },
{ "spell_threats", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellThreatsCommand, "", NULL },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index 9545588db7c..e05c5b23190 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -374,7 +374,6 @@ class ChatHandler
bool HandleReloadGOQuestRelationsCommand(const char* args);
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
bool HandleReloadItemEnchantementsCommand(const char* args);
- bool HandleReloadItemRequiredTragetCommand(const char* args);
bool HandleReloadLocalesAchievementRewardCommand(const char* args);
bool HandleReloadLocalesCreatureCommand(const char* args);
bool HandleReloadLocalesGameobjectCommand(const char* args);
@@ -419,7 +418,6 @@ class ChatHandler
bool HandleReloadSpellLinkedSpellCommand(const char* args);
bool HandleReloadSpellProcEventCommand(const char* args);
bool HandleReloadSpellBonusesCommand(const char* args);
- bool HandleReloadSpellScriptTargetCommand(const char* args);
bool HandleReloadSpellScriptsCommand(const char* args);
bool HandleReloadSpellTargetPositionCommand(const char* args);
bool HandleReloadSpellThreatsCommand(const char* args);
@@ -428,6 +426,7 @@ class ChatHandler
bool HandleReloadSpellGroupStackRulesCommand(const char* args);
bool HandleReloadAuctionsCommand(const char* args);
bool HandleReloadWpScriptsCommand(const char* args);
+ bool HandleReloadConditions(const char* args);
bool HandleResetAchievementsCommand(const char * args);
bool HandleResetAllCommand(const char * args);
diff --git a/src/game/CombatAI.cpp b/src/game/CombatAI.cpp
index 56d1e6d6a3d..0d0ff17ffd7 100644
--- a/src/game/CombatAI.cpp
+++ b/src/game/CombatAI.cpp
@@ -292,17 +292,79 @@ void AOEAI::UpdateAI(const uint32 /*diff*/)
//VehicleAI
//////////////
+VehicleAI::VehicleAI(Creature *c) : CreatureAI(c), m_vehicle(c->GetVehicleKit()), m_IsVehicleInUse(false), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
+{
+ LoadConditions();
+ m_DoDismiss = false;
+ m_DismissTimer = VEHICLE_DISMISS_TIME;
+}
+
+
//NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted
-void VehicleAI::UpdateAI(const uint32 /*diff*/)
+void VehicleAI::UpdateAI(const uint32 diff)
{
+ CheckConditions(diff);
+
+ if (m_DoDismiss)
+ {
+ if (m_DismissTimer < diff)
+ {
+ m_DoDismiss = false;
+ me->SetVisibility(VISIBILITY_OFF);
+ me->ForcedDespawn();
+ }else m_DismissTimer -= diff;
+ }
}
void VehicleAI::Reset()
{
+ me->SetVisibility(VISIBILITY_ON);
+
m_vehicle->Reset();
}
void VehicleAI::OnCharmed(bool apply)
{
+ if (m_IsVehicleInUse && !apply && !conditions.empty())//was used and has conditions
+ {
+ m_DoDismiss = true;//needs reset
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
+ me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ else if (apply)
+ m_DoDismiss = false;//in use again
+ m_DismissTimer = VEHICLE_DISMISS_TIME;//reset timer
m_IsVehicleInUse = apply;
+}
+
+void VehicleAI::LoadConditions()
+{
+ conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry());
+ if (!conditions.empty())
+ {
+ sLog.outDebug("VehicleAI::LoadConditions: loaded %u conditions", uint32(conditions.size()));
+ }
+}
+
+void VehicleAI::CheckConditions(const uint32 diff)
+{
+ if(m_ConditionsTimer < diff)
+ {
+ if (!conditions.empty())
+ {
+ for (SeatMap::iterator itr = m_vehicle->m_Seats.begin(); itr != m_vehicle->m_Seats.end(); ++itr)
+ if (Unit *passenger = itr->second.passenger)
+ {
+ if (Player* plr = passenger->ToPlayer())
+ {
+ if (!sConditionMgr.IsPlayerMeetToConditions(plr, conditions))
+ {
+ plr->ExitVehicle();
+ return;//check other pessanger in next tick
+ }
+ }
+ }
+ }
+ m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
+ } else m_ConditionsTimer -= diff;
} \ No newline at end of file
diff --git a/src/game/CombatAI.h b/src/game/CombatAI.h
index 40b4273d647..8626b38dd37 100644
--- a/src/game/CombatAI.h
+++ b/src/game/CombatAI.h
@@ -23,6 +23,7 @@
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
+#include "ConditionMgr.h"
class Creature;
@@ -100,11 +101,12 @@ struct AOEAI : public CreatureAI
static int Permissible(const Creature *);
};
-#define VEHICLE_RESET_TIME 5000
+#define VEHICLE_CONDITION_CHECK_TIME 1000
+#define VEHICLE_DISMISS_TIME 5000
struct VehicleAI : public CreatureAI
{
public:
- explicit VehicleAI(Creature *c) : CreatureAI(c), m_vehicle(c->GetVehicleKit()), m_IsVehicleInUse(false) {}
+ explicit VehicleAI(Creature *c);
void UpdateAI(const uint32 diff);
static int Permissible(const Creature *);
@@ -116,6 +118,12 @@ struct VehicleAI : public CreatureAI
private:
Vehicle* m_vehicle;
bool m_IsVehicleInUse;
+ void LoadConditions();
+ void CheckConditions(const uint32 diff);
+ ConditionList conditions;
+ uint32 m_ConditionsTimer;
+ bool m_DoDismiss;
+ uint32 m_DismissTimer;
};
#endif
diff --git a/src/game/ConditionMgr.cpp b/src/game/ConditionMgr.cpp
new file mode 100644
index 00000000000..8e5a7e5677e
--- /dev/null
+++ b/src/game/ConditionMgr.cpp
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "Policies/SingletonImp.h"
+#include "Player.h"
+#include "SpellAuras.h"
+#include "SpellMgr.h"
+#include "GameEventMgr.h"
+#include "ObjectMgr.h"
+#include "ProgressBar.h"
+#include "InstanceData.h"
+#include "ConditionMgr.h"
+
+INSTANTIATE_SINGLETON_1(ConditionMgr);
+
+// Checks if player meets the condition
+// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI)
+bool Condition::Meets(Player * player, Unit* targetOverride)
+{
+ if (!player)
+ {
+ sLog.outDebug("Condition player not found");
+ return false; // player not present, return false
+ }
+ uint32 refId = 0;
+ bool condMeets = false;
+ bool sendErrorMsg = false;
+ refId = mConditionValue3;//value 3 can be a 'quick' reference
+ switch (mConditionType)
+ {
+ case CONDITION_NONE:
+ condMeets = true; // empty condition, always met
+ break;
+ case CONDITION_AURA:
+ condMeets = player->HasAuraEffect(mConditionValue1, mConditionValue2);
+ break;
+ case CONDITION_ITEM:
+ condMeets = player->HasItemCount(mConditionValue1, mConditionValue2);
+ break;
+ case CONDITION_ITEM_EQUIPPED:
+ condMeets = player->HasItemOrGemWithIdEquipped(mConditionValue1,1);
+ break;
+ case CONDITION_ZONEID:
+ condMeets = player->GetZoneId() == mConditionValue1;
+ break;
+ case CONDITION_REPUTATION_RANK:
+ {
+ FactionEntry const* faction = sFactionStore.LookupEntry(mConditionValue1);
+ condMeets = faction && uint32(player->GetReputationMgr().GetRank(faction)) >= int32(mConditionValue2);
+ break;
+ }
+ case CONDITION_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(mConditionValue1);
+ condMeets = player->GetAchievementMgr().HasAchieved(achievement);
+ break;
+ }
+ case CONDITION_TEAM:
+ condMeets = player->GetTeam() == mConditionValue1;
+ break;
+ case CONDITION_CLASS:
+ condMeets = player->getClass() == mConditionValue1;
+ break;
+ case CONDITION_RACE:
+ condMeets = player->getRace() == mConditionValue1;
+ break;
+ case CONDITION_SKILL:
+ condMeets = player->HasSkill(mConditionValue1) && player->GetBaseSkillValue(mConditionValue1) >= mConditionValue2;
+ break;
+ case CONDITION_QUESTREWARDED:
+ condMeets = player->GetQuestRewardStatus(mConditionValue1);
+ break;
+ case CONDITION_QUESTTAKEN:
+ {
+ QuestStatus status = player->GetQuestStatus(mConditionValue1);
+ condMeets = (status == QUEST_STATUS_INCOMPLETE);
+ break;
+ }
+ case CONDITION_QUEST_NONE:
+ {
+ QuestStatus status = player->GetQuestStatus(mConditionValue1);
+ condMeets = (status == QUEST_STATUS_NONE);
+ break;
+ }
+ case CONDITION_AD_COMMISSION_AURA:
+ {
+ Unit::AuraApplicationMap const& auras = player->GetAppliedAuras();
+ for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ if ((itr->second->GetBase()->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetBase()->GetSpellProto()->SpellVisual[0] == 3580)
+ {
+ condMeets = true;
+ break;
+ }
+ condMeets = false;
+ break;
+ }
+ case CONDITION_NO_AURA:
+ condMeets = !player->HasAuraEffect(mConditionValue1, mConditionValue2);
+ break;
+ case CONDITION_ACTIVE_EVENT:
+ condMeets = gameeventmgr.IsActiveEvent(mConditionValue1);
+ break;
+ case CONDITION_INSTANCE_DATA:
+ {
+ Map *map = player->GetMap();
+ if (map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
+ condMeets = ((InstanceMap*)map)->GetInstanceData()->GetData(mConditionValue1) == mConditionValue2;
+ break;
+ }
+ case CONDITION_SPELL_SCRIPT_TARGET:
+ condMeets = true;//spell target condition is handled in spellsystem, here it is always true
+ refId = 0;//cant have references! use CONDITION_SOURCE_TYPE_SPELL for it
+ break;
+ case CONDITION_CREATURE_TARGET:
+ {
+ Unit* target = player->GetSelectedUnit();
+ if (targetOverride)
+ target = targetOverride;
+ if (target)
+ if (Creature* cTarget = target->ToCreature())
+ if (cTarget->GetEntry() == mConditionValue1)
+ condMeets = true;
+ break;
+ }
+ case CONDITION_TARGET_HEALTH_BELOW_PCT:
+ {
+ Unit* target = player->GetSelectedUnit();
+ if (targetOverride)
+ target = targetOverride;
+ if (target)
+ if ((target->GetHealth()*100 / target->GetMaxHealth()) <= mConditionValue1)
+ condMeets = true;
+ break;
+ }
+ case CONDITION_TARGET_RANGE:
+ {
+ if (Unit* target = player->GetSelectedUnit())
+ if (player->GetDistance(target) >= mConditionValue1 && (!mConditionValue2 || player->GetDistance(target) <= mConditionValue2))
+ condMeets = true;
+ break;
+ }
+ case CONDITION_MAPID:
+ condMeets = player->GetMapId() == mConditionValue1;
+ break;
+ case CONDITION_AREAID:
+ condMeets = player->GetAreaId() == mConditionValue1;
+ break;
+ case CONDITION_ITEM_TARGET:
+ {
+ condMeets = true;//handled in Item::IsTargetValidForItemUse
+ refId = 0;//cant have references for now
+ break;
+ }
+ default:
+ condMeets = false;
+ refId = 0;
+ break;
+ }
+ switch (mSourceType)
+ {
+ case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET:
+ case CONDITION_SOURCE_TYPE_SPELL:
+ sendErrorMsg = true;
+ break;
+ }
+
+ bool refMeets = false;
+ if (condMeets && refId)//only have to check references if 'this' is met
+ {
+ ConditionList ref = sConditionMgr.GetConditionReferences(refId);
+ refMeets = sConditionMgr.IsPlayerMeetToConditions(player, ref);
+ }else refMeets = true;
+
+ if (sendErrorMsg && ErrorTextd && (!condMeets || !refMeets))//send special error from DB
+ player->m_ConditionErrorMsgId = ErrorTextd;
+
+ return condMeets && refMeets;
+}
+
+ConditionMgr::ConditionMgr()
+{
+}
+
+ConditionMgr::~ConditionMgr()
+{
+}
+
+ConditionList ConditionMgr::GetConditionReferences(uint32 refId)
+{
+ ConditionList conditions;
+ ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find(refId);
+ if (ref != m_ConditionReferenceMap.end())
+ conditions = (*ref).second;
+ return conditions;
+}
+
+bool ConditionMgr::IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride)
+{
+ std::map<uint32, bool>ElseGroupMap;
+ for (ConditionList::const_iterator i = conditions.begin(); i != conditions.end(); ++i)
+ {
+ sLog.outDebug("ConditionMgr::IsPlayerMeetToConditionList condType: %u val1: %u",(*i)->mConditionType,(*i)->mConditionValue1);
+ if ((*i)->isLoaded())
+ {
+ std::map<uint32, bool>::const_iterator itr = ElseGroupMap.find((*i)->mElseGroup);
+ if (itr == ElseGroupMap.end())
+ ElseGroupMap[(*i)->mElseGroup] = true;
+ else if (!(*itr).second)
+ continue;
+
+ if ((*i)->mReferenceId)//handle reference
+ {
+ ConditionReferenceMap::const_iterator ref = m_ConditionReferenceMap.find((*i)->mReferenceId);
+ if (ref != m_ConditionReferenceMap.end())
+ {
+ 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//handle normal condition
+ {
+ if (!(*i)->Meets(player, targetOverride))
+ ElseGroupMap[(*i)->mElseGroup] = false;
+ }
+ }
+ }
+ for (std::map<uint32, bool>::const_iterator i = ElseGroupMap.begin(); i != ElseGroupMap.end(); ++i)
+ if (i->second)
+ return true;
+ return false;
+}
+
+bool ConditionMgr::IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride)
+{
+ if (conditions.empty())
+ return true;
+ if(player)
+ player->m_ConditionErrorMsgId = 0;
+
+ sLog.outDebug("ConditionMgr::IsPlayerMeetToConditions");
+ bool result = IsPlayerMeetToConditionList(player, conditions, targetOverride);
+
+ if (player && player->m_ConditionErrorMsgId && player->GetSession())
+ player->GetSession()->SendNotification(player->m_ConditionErrorMsgId);//m_ConditionErrorMsgId is set only if a condition was not met
+
+ return result;
+}
+
+ConditionList ConditionMgr::GetConditionsForNotGroupedEntry(ConditionSourceType sType, uint32 uEntry)
+{
+ ConditionList spellCond;
+ if (sType > CONDITION_SOURCE_TYPE_NONE && sType < MAX_CONDITIONSOURCETYPE)
+ {
+ ConditionMap::const_iterator itr = m_ConditionMap.find(sType);
+ if (itr != m_ConditionMap.end())
+ {
+ ConditionTypeMap::const_iterator i = (*itr).second.find(uEntry);
+ if (i != (*itr).second.end())
+ {
+ spellCond = (*i).second;
+ sLog.outDebug("GetConditionsForNotGroupedEntry: found conditions for type %u and entry %u", uint32(sType), uEntry);
+ }
+ }
+ }
+ return spellCond;
+}
+
+void ConditionMgr::LoadConditions(bool isReload)
+{
+ m_ConditionMap.clear(); // for reload case
+ m_ConditionReferenceMap.clear(); // for reload case
+ //must clear all custom handled cases (groupped types) before reload
+ if (isReload)
+ {
+ sLog.outString("Reseting Loot Conditions...");
+ LootTemplates_Creature.ResetConditions();
+ LootTemplates_Fishing.ResetConditions();
+ LootTemplates_Gameobject.ResetConditions();
+ LootTemplates_Item.ResetConditions();
+ LootTemplates_Mail.ResetConditions();
+ LootTemplates_Milling.ResetConditions();
+ LootTemplates_Pickpocketing.ResetConditions();
+ LootTemplates_Reference.ResetConditions();
+ LootTemplates_Skinning.ResetConditions();
+ LootTemplates_Disenchant.ResetConditions();
+ LootTemplates_Prospecting.ResetConditions();
+ LootTemplates_Spell.ResetConditions();
+
+ sLog.outString("Re-Loading `gossip_menu` Table for Conditions!");
+ objmgr.LoadGossipMenu();
+
+ sLog.outString("Re-Loading `gossip_menu_option` Table for Conditions!");
+ objmgr.LoadGossipMenuItems();
+ }
+
+ uint32 count = 0;
+ QueryResult_AutoPtr result = WorldDatabase.Query("SELECT SourceTypeOrReferenceId, SourceGroup, SourceEntry, ElseGroup, ConditionTypeOrReference, ConditionValue1, ConditionValue2, ConditionValue3, ErrorTextId FROM conditions");
+
+ if (!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `conditions`, table is empty!");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ Condition* cond = new Condition();
+ int32 iSourceTypeOrReferenceId = fields[0].GetInt32();
+ cond->mSourceGroup = fields[1].GetUInt32();
+ cond->mSourceEntry = fields[2].GetUInt32();
+ cond->mElseGroup = fields[3].GetUInt32();
+ int32 iConditionTypeOrReference = fields[4].GetInt32();
+ cond->mConditionValue1 = fields[5].GetUInt32();
+ cond->mConditionValue2 = fields[6].GetUInt32();
+ cond->mConditionValue3 = fields[7].GetUInt32();
+ cond->ErrorTextd = fields[8].GetUInt32();
+
+ if (iConditionTypeOrReference >= 0)
+ cond->mConditionType = ConditionType(iConditionTypeOrReference);
+
+ if (iConditionTypeOrReference < 0)//it has a reference
+ {
+ if (iConditionTypeOrReference == iSourceTypeOrReferenceId)//self referencing, skipp
+ {
+ sLog.outErrorDb("Condition reference %i is referencing self, skipped", iSourceTypeOrReferenceId);
+ continue;
+ }
+ cond->mReferenceId = uint32(abs(iConditionTypeOrReference));
+
+ const char* rowType = "reference template";
+ if (iSourceTypeOrReferenceId >= 0)
+ rowType = "reference";
+ //check for useless data
+ if (cond->mConditionValue1)
+ sLog.outErrorDb("Condition %s %i has useless data in value1 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue1);
+ if (cond->mConditionValue2)
+ sLog.outErrorDb("Condition %s %i has useless data in value2 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue2);
+ if (cond->mConditionValue3)
+ sLog.outErrorDb("Condition %s %i has useless data in value3 (%u)!", rowType, iSourceTypeOrReferenceId, cond->mConditionValue3);
+ if (cond->mSourceGroup && iSourceTypeOrReferenceId < 0)
+ 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
+ continue;
+
+
+ if (iSourceTypeOrReferenceId < 0)//it is a reference template
+ {
+ uint32 uRefId = abs(iSourceTypeOrReferenceId);
+ if (m_ConditionReferenceMap.find(uRefId) == m_ConditionReferenceMap.end())//make sure we have a list for our conditions, based on reference id
+ {
+ ConditionList mCondList;
+ m_ConditionReferenceMap[uRefId] = mCondList;
+ }
+ m_ConditionReferenceMap[uRefId].push_back(cond);//add to reference storage
+ count++;
+ continue;
+ }//end of reference templates
+
+ cond->mSourceType = ConditionSourceType(iSourceTypeOrReferenceId);
+
+ //if not a reference and SourceType is invalid, skip
+ if (iConditionTypeOrReference >= 0 && !isSourceTypeValid(cond))
+ continue;
+
+ //Grouping is only allowed for some types (loot templates, gossip menus, gossip items)
+ if (cond->mSourceGroup && !isGroupable(cond->mSourceType))
+ {
+ sLog.outErrorDb("Condition type %u has not allowed grouping %u!", uint32(cond->mSourceType), cond->mSourceGroup);
+ continue;
+ }else if (cond->mSourceGroup)
+ {
+ bool bIsDone = false;
+ //handle grouped conditions
+ switch (cond->mSourceType)
+ {
+ case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Creature.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Disenchant.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Fishing.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Gameobject.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Item.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Mail.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Milling.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Pickpocketing.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Prospecting.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Reference.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Skinning.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE:
+ bIsDone = addToLootTemplate(cond, LootTemplates_Spell.GetLootForConditionFill(cond->mSourceGroup));
+ break;
+ case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
+ bIsDone = addToGossipMenus(cond);
+ break;
+ case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
+ bIsDone = addToGossipMenuItems(cond);
+ break;
+ }
+ if (!bIsDone)
+ sLog.outErrorDb("Not handled grouped condition, SourceGroup %u", cond->mSourceGroup);
+ else
+ ++count;
+ continue;
+ }
+
+ //handle not grouped conditions
+ //make sure we have a storage list for our SourceType
+ if (m_ConditionMap.find(cond->mSourceType) == m_ConditionMap.end())
+ {
+ ConditionTypeMap mTypeMap;
+ m_ConditionMap[cond->mSourceType] = mTypeMap;//add new empty list for SourceType
+ }
+
+ //make sure we have a condition list for our SourceType's entry
+ if (m_ConditionMap[cond->mSourceType].find(cond->mSourceEntry) == m_ConditionMap[cond->mSourceType].end())
+ {
+ ConditionList mCondList;
+ m_ConditionMap[cond->mSourceType][cond->mSourceEntry] = mCondList;
+ }
+
+ //add new Condition to storage based on Type/Entry
+ m_ConditionMap[cond->mSourceType][cond->mSourceEntry].push_back(cond);
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u conditions", count);
+}
+
+bool ConditionMgr::addToLootTemplate(Condition* cond, LootTemplate* loot)
+{
+ if (!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;
+}
+
+bool ConditionMgr::addToGossipMenus(Condition* cond)
+{
+ GossipMenusMapBoundsNonConst pMenuBounds = objmgr.GetGossipMenusMapBoundsNonConst(cond->mSourceGroup);
+
+ if (pMenuBounds.first != pMenuBounds.second)
+ {
+ for (GossipMenusMap::iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
+ {
+ if ((*itr).second.entry == cond->mSourceGroup && (*itr).second.text_id == cond->mSourceEntry)
+ {
+ (*itr).second.conditions.push_back(cond);
+ sLog.outDebug("addToGossipMenus: entry %u textId %u", cond->mSourceGroup, cond->mSourceEntry);
+ return true;
+ }
+ }
+ }
+ sLog.outErrorDb("addToGossipMenus: GossipMenu %u not found", cond->mSourceGroup);
+ return false;
+}
+
+bool ConditionMgr::addToGossipMenuItems(Condition* cond)
+{
+ GossipMenuItemsMapBoundsNonConst pMenuItemBounds = objmgr.GetGossipMenuItemsMapBoundsNonConst(cond->mSourceGroup);
+ if (pMenuItemBounds.first != pMenuItemBounds.second)
+ {
+ for (GossipMenuItemsMap::iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr)
+ {
+ if ((*itr).second.menu_id == cond->mSourceGroup && (*itr).second.id == cond->mSourceEntry)
+ {
+ (*itr).second.conditions.push_back(cond);
+ //sLog.outDebug("addToGossipMenuItems: menuId %u id %u", cond->mSourceGroup, cond->mSourceEntry);
+ return true;
+ }
+ }
+ }
+ sLog.outErrorDb("addToGossipMenuItems: GossipMenuIt %u Item %u not found", cond->mSourceGroup, cond->mSourceEntry);
+ return false;
+}
+
+bool ConditionMgr::isSourceTypeValid(Condition* cond)
+{
+ if (cond->mSourceType == CONDITION_SOURCE_TYPE_NONE || cond->mSourceType >= MAX_CONDITIONSOURCETYPE)
+ {
+ sLog.outErrorDb("Invalid ConditionSourceType %u in `condition` table, ignoring.", uint32(cond->mSourceType));
+ return false;
+ }
+ switch (cond->mSourceType)
+ {
+ case CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Creature.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Disenchant.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Fishing.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Gameobject.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Item.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Mail.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Milling.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Pickpocketing.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Prospecting.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Reference.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Skinning.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE:
+ {
+ if (!LootTemplates_Spell.HaveLootFor(cond->mSourceGroup))
+ {
+ 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))
+ {
+ sLog.outErrorDb("SourceType %u, SourceEntry %u in `condition` table, does not exist in `item_template`, ignoring.", cond->mSourceType, cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET:
+ {
+ if (cond->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
+ {
+ 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);
+
+ if (!spellProto)
+ {
+ sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `spell.dbc`, ignoring.", cond->mSourceEntry);
+ return false;
+ }
+
+ bool targetfound = false;
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ if (spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_SRC ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_SRC ||
+ spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_DST ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_DST ||
+ spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetA[i] == TARGET_DST_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_DST_NEARBY_ENTRY ||
+ spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_CONE_ENTRY ||
+ spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_CONE_ENTRY)
+ {
+ targetfound = true;
+ break;
+ }
+ }
+ if (!targetfound)
+ {
+ sLog.outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\
+ ,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)",cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE:
+ {
+ if (!sCreatureStorage.LookupEntry<CreatureInfo>(cond->mSourceEntry))
+ {
+ sLog.outErrorDb("SourceEntry %u in `condition` table, does not exist in `creature_template`, ignoring.", cond->mSourceEntry);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_SPELL:
+ {
+ 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);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET:
+ {
+ if (cond->mConditionType != CONDITION_ITEM_TARGET)
+ {
+ 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)
+ {
+ if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId))
+ {
+ if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
+ pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
+ {
+ ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, pSpellInfo->Id);//script loading is done before item target loading
+ if (!conditions.empty())
+ break;
+
+ for (int j = 0; j < 3; ++j)
+ {
+ if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY ||
+ pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ENEMY ||
+ pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY ||
+ pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ANY)
+ {
+ bIsItemSpellValid = true;
+ break;
+ }
+ }
+ if (bIsItemSpellValid)
+ break;
+ }
+ }
+ }
+
+ if (!bIsItemSpellValid)
+ {
+ sLog.outErrorDb("Conditions:ITEM_REQUIRED_TARGET used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in scriptTargets or doesn't have item spelltrigger.", cond->mSourceEntry);
+ break;
+ }
+ break;
+ }
+ case CONDITION_SOURCE_TYPE_GOSSIP_MENU:
+ case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION:
+ case CONDITION_SOURCE_TYPE_NONE:
+ break;
+ }
+ return true;
+}
+bool ConditionMgr::isConditionTypeValid(Condition* cond)
+{
+ if (cond->mConditionType == CONDITION_NONE || cond->mConditionType >= MAX_CONDITION)
+ {
+ 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:
+ {
+ if (!sSpellStore.LookupEntry(cond->mConditionValue1))
+ {
+ 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);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ITEM:
+ {
+ ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1);
+ if (!proto)
+ {
+ 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);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ITEM_EQUIPPED:
+ {
+ ItemPrototype const *proto = objmgr.GetItemPrototype(cond->mConditionValue1);
+ if (!proto)
+ {
+ 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;
+ }
+ case CONDITION_ZONEID:
+ {
+ AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->mConditionValue1);
+ if (!areaEntry)
+ {
+ 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;
+ }
+ case CONDITION_REPUTATION_RANK:
+ {
+ FactionEntry const* factionEntry = sFactionStore.LookupEntry(cond->mConditionValue1);
+ if (!factionEntry)
+ {
+ sLog.outErrorDb("Reputation condition has non existing faction (%u), skipped", cond->mConditionValue1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_TEAM:
+ {
+ if (cond->mConditionValue1 != ALLIANCE && cond->mConditionValue1 != HORDE)
+ {
+ 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;
+ }
+ case CONDITION_SKILL:
+ {
+ SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(cond->mConditionValue1);
+ if (!pSkill)
+ {
+ 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);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_QUESTREWARDED:
+ case CONDITION_QUESTTAKEN:
+ case CONDITION_QUEST_NONE:
+ {
+ Quest const *Quest = objmgr.GetQuestTemplate(cond->mConditionValue1);
+ if (!Quest)
+ {
+ 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;
+ }
+ case CONDITION_AD_COMMISSION_AURA:
+ {
+ 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;
+ }
+ case CONDITION_NO_AURA:
+ {
+ if (!sSpellStore.LookupEntry(cond->mConditionValue1))
+ {
+ 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);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ACTIVE_EVENT:
+ {
+ GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ if (cond->mConditionValue1 >=events.size() || !events[cond->mConditionValue1].isValid())
+ {
+ 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;
+ }
+ case CONDITION_ACHIEVEMENT:
+ {
+ AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(cond->mConditionValue1);
+ if (!achievement)
+ {
+ 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;
+ }
+ case CONDITION_CLASS:
+ {
+ if (cond->mConditionValue1 >= MAX_CLASSES)
+ {
+ 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;
+ }
+ case CONDITION_RACE:
+ {
+ if (cond->mConditionValue1 >= MAX_RACES)
+ {
+ 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;
+ }
+ case CONDITION_SPELL_SCRIPT_TARGET:
+ {
+ if (cond->mConditionValue1 >= MAX_SPELL_TARGET_TYPE)
+ {
+ sLog.outErrorDb("SpellTarget condition has non existing spell target type (%u), skipped", cond->mConditionValue1);
+ return false;
+ }
+ switch(cond->mConditionValue1)
+ {
+ case SPELL_TARGET_TYPE_GAMEOBJECT:
+ {
+ if (cond->mConditionValue2 && !sGOStorage.LookupEntry<GameObjectInfo>(cond->mConditionValue2))
+ {
+ sLog.outErrorDb("SpellTarget condition has non existing gameobject (%u) as target, skipped", cond->mConditionValue2);
+ return false;
+ }
+ break;
+ }
+ case SPELL_TARGET_TYPE_CONTROLLED:
+ case SPELL_TARGET_TYPE_CREATURE:
+ case SPELL_TARGET_TYPE_DEAD:
+ {
+ if (cond->mConditionValue2 && !sCreatureStorage.LookupEntry<CreatureInfo>(cond->mConditionValue2))
+ {
+ 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);
+
+ 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);
+ return false;
+ }
+ break;
+ }
+ }
+ if (cond->mConditionValue3)
+ sLog.outErrorDb("SpellTarget condition has useless data in value3 (%u)!", cond->mConditionValue3);
+ break;
+ }
+ case CONDITION_CREATURE_TARGET:
+ {
+ if (!cond->mConditionValue1 && !sCreatureStorage.LookupEntry<CreatureInfo>(cond->mConditionValue1))
+ {
+ 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;
+ }
+ case CONDITION_TARGET_HEALTH_BELOW_PCT:
+ {
+ if (cond->mConditionValue1 > 100)
+ {
+ 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;
+ }
+ case CONDITION_TARGET_RANGE:
+ {
+ if (cond->mConditionValue2 && cond->mConditionValue2 < cond->mConditionValue1)//maxDist can be 0 for infinit max range
+ {
+ sLog.outErrorDb("TargetRange condition has max distance closer then min distance, skipped");
+ return false;
+ }
+ break;
+ }
+ case CONDITION_MAPID:
+ {
+ MapEntry const * me = sMapStore.LookupEntry(cond->mConditionValue1);
+ if (!me)
+ {
+ 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;
+ }
+ case CONDITION_ITEM_TARGET:
+ {
+ if (!cond->mConditionValue1 || cond->mConditionValue1 > MAX_ITEM_REQ_TARGET_TYPE)
+ {
+ 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;
+ }
+ case CONDITION_AREAID:
+ case CONDITION_INSTANCE_DATA:
+ break;
+ }
+ return true;
+}
diff --git a/src/game/ConditionMgr.h b/src/game/ConditionMgr.h
new file mode 100644
index 00000000000..ebb7d2bb0a6
--- /dev/null
+++ b/src/game/ConditionMgr.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TRINITY_CONDITIONMGR_H
+#define TRINITY_CONDITIONMGR_H
+
+#include "LootMgr.h"
+
+class Player;
+class Unit;
+class LootTemplate;
+
+enum ConditionType
+{ // value1 value2 value3
+ CONDITION_NONE = 0, // 0 0 0 always true
+ CONDITION_AURA = 1, // spell_id effindex +referenceID true if has aura of spell_id with effect effindex
+ CONDITION_ITEM = 2, // item_id count +referenceID true if has #count of item_ids
+ CONDITION_ITEM_EQUIPPED = 3, // item_id 0 +referenceID true if has item_id equipped
+ CONDITION_ZONEID = 4, // zone_id 0 +referenceID true if in zone_id
+ CONDITION_REPUTATION_RANK = 5, // faction_id min_rank +referenceID true if has min_rank for faction_id
+ CONDITION_TEAM = 6, // player_team 0, +referenceID 469 - Alliance, 67 - Horde)
+ CONDITION_SKILL = 7, // skill_id skill_value +referenceID true if has skill_value for skill_id
+ CONDITION_QUESTREWARDED = 8, // quest_id 0 +referenceID true if quest_id was rewarded before
+ CONDITION_QUESTTAKEN = 9, // quest_id 0, +referenceID true while quest active
+ CONDITION_AD_COMMISSION_AURA = 10, // 0 0, +referenceID true while one from AD commission aura active
+ CONDITION_NO_AURA = 11, // spell_id effindex +referenceID true if does not have aura of spell_id with effect effindex
+ CONDITION_ACTIVE_EVENT = 12, // event_id 0 +referenceID true if event is active
+ CONDITION_INSTANCE_DATA = 13, // entry data +referenceID true if data is set in current instance
+ CONDITION_QUEST_NONE = 14, // quest_id 0 +referenceID true if doesn't have quest saved
+ CONDITION_CLASS = 15, // class 0 +referenceID true if player's class is equal to class
+ CONDITION_RACE = 16, // race 0 +referenceID true if player's race is equal to race
+ CONDITION_ACHIEVEMENT = 17, // achievement_id 0 +referenceID true if achievement is complete
+ CONDITION_SPELL_SCRIPT_TARGET = 18, // SpellScriptTargetType, TargetEntry, 0
+ CONDITION_CREATURE_TARGET = 19, // creature entry 0 +referenceID true if current target is creature with value1 entry
+ CONDITION_TARGET_HEALTH_BELOW_PCT = 20, // 0-100 0 +referenceID true if target's health is below value1 percent, false if over or no target
+ CONDITION_TARGET_RANGE = 21, // minDistance maxDist +referenceID true if target is closer then minDist and further then maxDist or if max is 0 then max dist is infinit
+ CONDITION_MAPID = 22, // map_id 0 +referenceID true if in map_id
+ CONDITION_AREAID = 23, // area_id 0 +referenceID true if in area_id
+ CONDITION_ITEM_TARGET = 24 // ItemRequiredTargetType, TargetEntry, 0
+};
+
+#define MAX_CONDITION 25 // maximum value in ConditionType enum
+
+enum ConditionSourceType
+{
+ CONDITION_SOURCE_TYPE_NONE = 0,//DONE
+ CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE = 1,//DONE
+ CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE = 2,//DONE
+ CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE = 3,//DONE
+ CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE = 4,//DONE
+ CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE = 5,//DONE
+ CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE = 6,//DONE
+ CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE = 7,//DONE
+ CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE = 8,//DONE
+ CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE = 9,//DONE
+ CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE = 10,//DONE
+ CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE = 11,//DONE
+ CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE = 12,//DONE
+ CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET = 13,//DONE
+ CONDITION_SOURCE_TYPE_GOSSIP_MENU = 14,//DONE
+ CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION = 15,//DONE
+ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE = 16,//DONE
+ CONDITION_SOURCE_TYPE_SPELL = 17,//DONE
+ CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET = 18//DONE
+};
+
+#define MAX_CONDITIONSOURCETYPE 19
+
+struct Condition
+{
+ ConditionSourceType mSourceType; //SourceTypeOrReferenceId
+ uint32 mSourceGroup;
+ uint32 mSourceEntry;
+ uint32 mElseGroup;
+ ConditionType mConditionType; //ConditionTypeOrReference
+ uint32 mConditionValue1;
+ uint32 mConditionValue2;
+ uint32 mConditionValue3;
+ uint32 ErrorTextd;
+ uint32 mReferenceId;
+
+ Condition()
+ {
+ mSourceType = CONDITION_SOURCE_TYPE_NONE;
+ mSourceGroup = 0;
+ mSourceEntry = 0;
+ mElseGroup = 0;
+ mConditionType = CONDITION_NONE;
+ mConditionValue1 = 0;
+ mConditionValue2 = 0;
+ mConditionValue3 = 0;
+ mReferenceId = 0;
+ ErrorTextd = 0;
+ }
+ bool Meets(Player * player, Unit* targetOverride = NULL);
+ bool isLoaded() { return mConditionType > CONDITION_SOURCE_TYPE_NONE || mReferenceId; }
+};
+
+typedef std::list<Condition*> ConditionList;
+typedef std::map<uint32, ConditionList > ConditionTypeMap;
+typedef std::map<ConditionSourceType, ConditionTypeMap > ConditionMap;//used for all conditions, except references
+
+typedef std::map<uint32, ConditionList > ConditionReferenceMap;//only used for references
+
+class ConditionMgr
+{
+ public:
+ ConditionMgr();
+ ~ConditionMgr();
+
+ void LoadConditions(bool isReload = false);
+ bool isConditionTypeValid(Condition* cond);
+ ConditionList GetConditionReferences(uint32 refId);
+
+ bool IsPlayerMeetToConditions(Player* player, ConditionList conditions, Unit* targetOverride = NULL);
+ 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);
+ bool addToGossipMenuItems(Condition* cond);
+ bool IsPlayerMeetToConditionList(Player* player,const ConditionList& conditions, Unit* targetOverride = NULL);
+
+ bool isGroupable(ConditionSourceType sourceType)
+ {
+ return (sourceType == CONDITION_SOURCE_TYPE_CREATURE_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_DISENCHANT_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_FISHING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_GAMEOBJECT_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_ITEM_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_MAIL_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_MILLING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_PICKPOCKETING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_PROSPECTING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_REFERENCE_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_SKINNING_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_SPELL_LOOT_TEMPLATE ||
+ sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU ||
+ sourceType == CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION);
+ }
+};
+
+#define sConditionMgr Trinity::Singleton<ConditionMgr>::Instance()
+
+#endif
diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp
index bbb1dde36e7..47c8e9e6ad8 100644
--- a/src/game/CreatureEventAI.cpp
+++ b/src/game/CreatureEventAI.cpp
@@ -32,6 +32,7 @@
#include "InstanceData.h"
#include "SpellMgr.h"
#include "CreatureAIImpl.h"
+#include "ConditionMgr.h"
bool CreatureEventAIHolder::UpdateRepeatTimer(Creature* creature, uint32 repeatMin, uint32 repeatMax)
{
@@ -1330,8 +1331,12 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
if ((*itr).Event.receive_emote.emoteId != text_emote)
return;
- PlayerCondition pcon((*itr).Event.receive_emote.condition,(*itr).Event.receive_emote.conditionValue1,(*itr).Event.receive_emote.conditionValue2);
- if (pcon.Meets(pPlayer))
+ Condition* cond = new Condition();
+ cond->mConditionType = ConditionType((*itr).Event.receive_emote.condition);
+ cond->mConditionValue1 = (*itr).Event.receive_emote.conditionValue1;
+ cond->mConditionValue2 = (*itr).Event.receive_emote.conditionValue2;
+
+ if (cond->Meets(pPlayer))
{
sLog.outDebug("CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing");
ProcessEvent(*itr, pPlayer);
diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp
index 4fa7517d848..83d62ca74dc 100644
--- a/src/game/CreatureEventAIMgr.cpp
+++ b/src/game/CreatureEventAIMgr.cpp
@@ -26,6 +26,7 @@
#include "Policies/SingletonImp.h"
#include "ObjectDefines.h"
#include "GridDefines.h"
+#include "ConditionMgr.h"
INSTANTIATE_SINGLETON_1(CreatureEventAIMgr);
@@ -359,11 +360,17 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param1 (EmoteTextId: %u) are not valid.",temp.creature_id, i, temp.receive_emote.emoteId);
continue;
}
-
- if (!PlayerCondition::IsValid(ConditionType(temp.receive_emote.condition), temp.receive_emote.conditionValue1, temp.receive_emote.conditionValue2))
+ if (temp.receive_emote.condition)
{
- sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp.creature_id, i, temp.receive_emote.condition);
- continue;
+ Condition* cond = new Condition();
+ cond->mConditionType = ConditionType(temp.receive_emote.condition);
+ cond->mConditionValue1 = temp.receive_emote.conditionValue1;
+ cond->mConditionValue2 = temp.receive_emote.conditionValue2;
+ if (!sConditionMgr.isConditionTypeValid(cond))
+ {
+ sLog.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp.creature_id, i, temp.receive_emote.condition);
+ continue;
+ }
}
if (!(temp.event_flags & EFLAG_REPEATABLE))
diff --git a/src/game/Item.cpp b/src/game/Item.cpp
index 4cfd9484f9f..5c2d94d399b 100644
--- a/src/game/Item.cpp
+++ b/src/game/Item.cpp
@@ -26,6 +26,7 @@
#include "ItemEnchantmentMgr.h"
#include "SpellMgr.h"
#include "ScriptMgr.h"
+#include "ConditionMgr.h"
void AddItemsSetItem(Player*player,Item *item)
{
@@ -824,18 +825,19 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
bool Item::IsTargetValidForItemUse(Unit* pUnitTarget)
{
- ItemRequiredTargetMapBounds bounds = objmgr.GetItemRequiredTargetMapBounds(GetProto()->ItemId);
-
- if (bounds.first == bounds.second)
+ ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_ITEM_REQUIRED_TARGET, GetProto()->ItemId);
+ if (conditions.empty())
return true;
if (!pUnitTarget)
return false;
- for (ItemRequiredTargetMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
- if (itr->second.IsFitToRequirements(pUnitTarget))
+ for (ConditionList::const_iterator itr = conditions.begin(); itr != conditions.end(); ++itr)
+ {
+ ItemRequiredTarget *irt = new ItemRequiredTarget((ItemRequiredTargetType)(*itr)->mConditionValue1, (*itr)->mConditionValue2);
+ if (irt->IsFitToRequirements(pUnitTarget))
return true;
-
+ }
return false;
}
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index fe61046897d..49efbe7fde7 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -55,6 +55,7 @@
#include "CreatureEventAIMgr.h"
#include "SpellAuraEffects.h"
#include "DBCEnums.h"
+#include "ConditionMgr.h"
bool ChatHandler::HandleAHBotOptionsCommand(const char *args)
{
@@ -591,6 +592,7 @@ bool ChatHandler::HandleReloadAllLootCommand(const char*)
sLog.outString("Re-Loading Loot Tables...");
LoadLootTables();
SendGlobalGMSysMessage("DB tables `*_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -655,7 +657,6 @@ bool ChatHandler::HandleReloadAllSpellCommand(const char*)
HandleReloadSpellLinkedSpellCommand("a");
HandleReloadSpellProcEventCommand("a");
HandleReloadSpellBonusesCommand("a");
- HandleReloadSpellScriptTargetCommand("a");
HandleReloadSpellTargetPositionCommand("a");
HandleReloadSpellThreatsCommand("a");
HandleReloadSpellGroupStackRulesCommand("a");
@@ -668,7 +669,6 @@ bool ChatHandler::HandleReloadAllItemCommand(const char*)
{
HandleReloadPageTextsCommand("a");
HandleReloadItemEnchantementsCommand("a");
- HandleReloadItemRequiredTragetCommand("a");
return true;
}
@@ -923,6 +923,7 @@ bool ChatHandler::HandleReloadGossipMenuCommand(const char*)
sLog.outString("Re-Loading `gossip_menu` Table!");
objmgr.LoadGossipMenu();
SendGlobalGMSysMessage("DB table `gossip_menu` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -931,6 +932,7 @@ bool ChatHandler::HandleReloadGossipMenuOptionCommand(const char*)
sLog.outString("Re-Loading `gossip_menu_option` Table!");
objmgr.LoadGossipMenuItems();
SendGlobalGMSysMessage("DB table `gossip_menu_option` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -977,6 +979,7 @@ bool ChatHandler::HandleReloadLootTemplatesCreatureCommand(const char*)
LoadLootTemplates_Creature();
LootTemplates_Creature.CheckLootRefs();
SendGlobalGMSysMessage("DB table `creature_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -986,6 +989,7 @@ bool ChatHandler::HandleReloadLootTemplatesDisenchantCommand(const char*)
LoadLootTemplates_Disenchant();
LootTemplates_Disenchant.CheckLootRefs();
SendGlobalGMSysMessage("DB table `disenchant_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -995,6 +999,7 @@ bool ChatHandler::HandleReloadLootTemplatesFishingCommand(const char*)
LoadLootTemplates_Fishing();
LootTemplates_Fishing.CheckLootRefs();
SendGlobalGMSysMessage("DB table `fishing_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1004,6 +1009,7 @@ bool ChatHandler::HandleReloadLootTemplatesGameobjectCommand(const char*)
LoadLootTemplates_Gameobject();
LootTemplates_Gameobject.CheckLootRefs();
SendGlobalGMSysMessage("DB table `gameobject_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1013,6 +1019,7 @@ bool ChatHandler::HandleReloadLootTemplatesItemCommand(const char*)
LoadLootTemplates_Item();
LootTemplates_Item.CheckLootRefs();
SendGlobalGMSysMessage("DB table `item_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1022,6 +1029,7 @@ bool ChatHandler::HandleReloadLootTemplatesMillingCommand(const char*)
LoadLootTemplates_Milling();
LootTemplates_Milling.CheckLootRefs();
SendGlobalGMSysMessage("DB table `milling_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1031,6 +1039,7 @@ bool ChatHandler::HandleReloadLootTemplatesPickpocketingCommand(const char*)
LoadLootTemplates_Pickpocketing();
LootTemplates_Pickpocketing.CheckLootRefs();
SendGlobalGMSysMessage("DB table `pickpocketing_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1040,6 +1049,7 @@ bool ChatHandler::HandleReloadLootTemplatesProspectingCommand(const char*)
LoadLootTemplates_Prospecting();
LootTemplates_Prospecting.CheckLootRefs();
SendGlobalGMSysMessage("DB table `prospecting_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1049,6 +1059,7 @@ bool ChatHandler::HandleReloadLootTemplatesMailCommand(const char*)
LoadLootTemplates_Mail();
LootTemplates_Mail.CheckLootRefs();
SendGlobalGMSysMessage("DB table `mail_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1057,6 +1068,7 @@ bool ChatHandler::HandleReloadLootTemplatesReferenceCommand(const char*)
sLog.outString("Re-Loading Loot Tables... (`reference_loot_template`)");
LoadLootTemplates_Reference();
SendGlobalGMSysMessage("DB table `reference_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1066,6 +1078,7 @@ bool ChatHandler::HandleReloadLootTemplatesSkinningCommand(const char*)
LoadLootTemplates_Skinning();
LootTemplates_Skinning.CheckLootRefs();
SendGlobalGMSysMessage("DB table `skinning_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1075,6 +1088,7 @@ bool ChatHandler::HandleReloadLootTemplatesSpellCommand(const char*)
LoadLootTemplates_Spell();
LootTemplates_Spell.CheckLootRefs();
SendGlobalGMSysMessage("DB table `spell_loot_template` reloaded.");
+ sConditionMgr.LoadConditions(true);
return true;
}
@@ -1214,14 +1228,6 @@ bool ChatHandler::HandleReloadSpellBonusesCommand(const char*)
return true;
}
-bool ChatHandler::HandleReloadSpellScriptTargetCommand(const char*)
-{
- sLog.outString("Re-Loading SpellsScriptTarget...");
- spellmgr.LoadSpellScriptTarget();
- SendGlobalGMSysMessage("DB table `spell_script_target` (spell targets selection in case specific creature/GO requirements) reloaded.");
- return true;
-}
-
bool ChatHandler::HandleReloadSpellTargetPositionCommand(const char*)
{
sLog.outString("Re-Loading Spell target coordinates...");
@@ -1270,14 +1276,6 @@ bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*)
return true;
}
-bool ChatHandler::HandleReloadItemRequiredTragetCommand(const char*)
-{
- sLog.outString("Re-Loading Item Required Targets Table...");
- objmgr.LoadItemRequiredTarget();
- SendGlobalGMSysMessage("DB table `item_required_target` reloaded.");
- return true;
-}
-
bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg)
{
if (sWorld.IsScriptScheduled())
@@ -1546,6 +1544,14 @@ bool ChatHandler::HandleReloadAuctionsCommand(const char * /*args*/)
return true;
}
+bool ChatHandler::HandleReloadConditions(const char* args)
+{
+ sLog.outString("Re-Loading Conditions...");
+ sConditionMgr.LoadConditions(true);
+ SendGlobalGMSysMessage("Conditions reloaded.");
+ return true;
+}
+
bool ChatHandler::HandleAccountSetGmLevelCommand(const char *args)
{
if (!*args)
@@ -6687,7 +6693,11 @@ bool ChatHandler::HandleCastCommand(const char *args)
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
if (!spellInfo)
+ {
+ PSendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ SetSentErrorMessage(true);
return false;
+ }
if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer()))
{
@@ -6726,7 +6736,11 @@ bool ChatHandler::HandleCastBackCommand(const char *args)
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
uint32 spell = extractSpellIdFromLink((char*)args);
if (!spell || !sSpellStore.LookupEntry(spell))
+ {
+ PSendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ SetSentErrorMessage(true);
return false;
+ }
char* trig_str = strtok(NULL, " ");
if (trig_str)
@@ -6757,7 +6771,11 @@ bool ChatHandler::HandleCastDistCommand(const char *args)
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
if (!spellInfo)
+ {
+ PSendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ SetSentErrorMessage(true);
return false;
+ }
if (!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer()))
{
@@ -6811,7 +6829,11 @@ bool ChatHandler::HandleCastTargetCommand(const char *args)
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
uint32 spell = extractSpellIdFromLink((char*)args);
if (!spell || !sSpellStore.LookupEntry(spell))
+ {
+ PSendSysMessage(LANG_COMMAND_NOSPELLFOUND);
+ SetSentErrorMessage(true);
return false;
+ }
char* trig_str = strtok(NULL, " ");
if (trig_str)
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp
index dcbb376208b..2137c8872b5 100644
--- a/src/game/LootMgr.cpp
+++ b/src/game/LootMgr.cpp
@@ -64,6 +64,9 @@ class LootTemplate::LootGroup // A set of loot def
void Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const;
void CollectLootIds(LootIdSet& set) const;
void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
+ LootStoreItemList * GetExplicitlyChancedItemList() { return &ExplicitlyChanced; }
+ LootStoreItemList * GetEqualChancedItemList() { return &EqualChanced; }
+ void CopyConditions(ConditionList conditions);
private:
LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB
LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance
@@ -99,8 +102,8 @@ void LootStore::LoadLootTable()
sLog.outString("%s :", GetName());
- // 0 1 2 3 4 5 6 7 8 9
- QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
+ // 0 1 2 3 4 5 6
+ QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, lootmode, groupid, mincountOrRef, maxcount FROM %s",GetName());
if (result)
{
@@ -118,9 +121,6 @@ void LootStore::LoadLootTable()
uint8 group = fields[4].GetUInt8();
int32 mincountOrRef = fields[5].GetInt32();
int32 maxcount = fields[6].GetInt32();
- ConditionType condition = (ConditionType)fields[7].GetUInt8();
- uint32 cond_value1 = fields[8].GetUInt32();
- uint32 cond_value2 = fields[9].GetUInt32();
if (maxcount > std::numeric_limits<uint8>::max())
{
@@ -128,16 +128,7 @@ void LootStore::LoadLootTable()
continue; // error already printed to log/console.
}
- if (!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
- {
- sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
- continue; // error already printed to log/console.
- }
-
- // (condition + cond_value1/2) are converted into single conditionId
- uint16 conditionId = objmgr.GetConditionId(condition, cond_value1, cond_value2);
-
- LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, conditionId, mincountOrRef, maxcount);
+ LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount);
if (!storeitem.IsValid(*this,entry)) // Validity checks
continue;
@@ -195,6 +186,16 @@ bool LootStore::HaveQuestLootForPlayer(uint32 loot_id,Player* player) const
return false;
}
+void LootStore::ResetConditions()
+{
+ LootTemplateMap m_LootTemplates;
+ for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr)
+ {
+ ConditionList empty;
+ (*itr).second->CopyConditions(empty);
+ }
+}
+
LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
{
LootTemplateMap::const_iterator tab = m_LootTemplates.find(loot_id);
@@ -205,6 +206,16 @@ LootTemplate const* LootStore::GetLootFor(uint32 loot_id) const
return tab->second;
}
+LootTemplate* LootStore::GetLootForConditionFill(uint32 loot_id)
+{
+ LootTemplateMap::iterator tab = m_LootTemplates.find(loot_id);
+
+ if (tab == m_LootTemplates.end())
+ return NULL;
+
+ return tab->second;
+}
+
void LootStore::LoadAndCollectLootIds(LootIdSet& ids_set)
{
LoadLootTable();
@@ -316,9 +327,9 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
// Constructor, copies most fields from LootStoreItem and generates random count
LootItem::LootItem(LootStoreItem const& li)
{
- itemid = li.itemid;
- conditionId = li.conditionId;
-
+ itemid = li.itemid;
+ conditions = li.conditions;
+
ItemPrototype const* proto = objmgr.GetItemPrototype(itemid);
freeforall = proto && (proto->Flags & ITEM_FLAGS_PARTY_LOOT);
@@ -336,8 +347,8 @@ LootItem::LootItem(LootStoreItem const& li)
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool LootItem::AllowedForPlayer(Player const * player) const
{
- // DB conditions check
- if (!objmgr.IsPlayerMeetToCondition(player,conditionId))
+ // DB conditions check
+ if (!sConditionMgr.IsPlayerMeetToConditions(const_cast<Player*>(player), conditions))
return false;
if (needs_quest)
@@ -368,7 +379,7 @@ void Loot::AddItem(LootStoreItem const & item)
{
if (quest_items.size() < MAX_NR_QUEST_ITEMS)
quest_items.push_back(LootItem(item));
- }
+ }
else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop
{
items.push_back(LootItem(item));
@@ -376,7 +387,7 @@ void Loot::AddItem(LootStoreItem const & item)
// non-conditional one-player only items are counted here,
// free for all items are counted in FillFFALoot(),
// non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot()
- if (!item.conditionId)
+ if (item.conditions.empty())
{
ItemPrototype const* proto = objmgr.GetItemPrototype(item.itemid);
if (!proto || (proto->Flags & ITEM_FLAGS_PARTY_LOOT) == 0)
@@ -512,7 +523,7 @@ QuestItemList* Loot::FillNonQuestNonFFAConditionalLoot(Player* player)
for (uint8 i = 0; i < items.size(); ++i)
{
LootItem &item = items[i];
- if (!item.is_looted && !item.freeforall && item.conditionId && item.AllowedForPlayer(player))
+ if (!item.is_looted && !item.freeforall && !item.conditions.empty() && item.AllowedForPlayer(player))
{
ql->push_back(QuestItem(i));
if (!item.is_counted)
@@ -649,7 +660,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qite
}
}
}
- else if (item->conditionId)
+ else if (!item->conditions.empty())
{
QuestItemMap::const_iterator itr = PlayerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
if (itr != PlayerNonQuestNonFFAConditionalItems.end())
@@ -776,7 +787,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
// blocked rolled items and quest items, and !ffa items
for (uint8 i = 0; i < l.items.size(); ++i)
{
- if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
+ if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
{
uint8 slot_type;
@@ -804,7 +815,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
{
for (uint8 i = 0; i < l.items.size(); ++i)
{
- if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
+ if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
{
if (l.roundRobinPlayer != 0 && lv.viewer->GetGUID() != l.roundRobinPlayer)
// item shall not be displayed.
@@ -823,7 +834,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
uint8 slot_type = (lv.permission == MASTER_PERMISSION) ? LOOT_SLOT_TYPE_MASTER : LOOT_SLOT_TYPE_ALLOW_LOOT;
for (uint8 i = 0; i < l.items.size(); ++i)
{
- if (!l.items[i].is_looted && !l.items[i].freeforall && !l.items[i].conditionId && l.items[i].AllowedForPlayer(lv.viewer))
+ if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer))
{
b << uint8(i) << l.items[i];
b << uint8(slot_type);
@@ -954,6 +965,18 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const
return false;
}
+void LootTemplate::LootGroup::CopyConditions(ConditionList conditions)
+{
+ for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i)
+ {
+ i->conditions = conditions;
+ }
+ for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i)
+ {
+ i->conditions = conditions;
+ }
+}
+
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const
{
@@ -1078,7 +1101,7 @@ void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint
}
}
-void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, LootIdSet* ref_set) const
+void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const
{
for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr)
{
@@ -1120,6 +1143,15 @@ void LootTemplate::AddEntry(LootStoreItem& item)
Entries.push_back(item);
}
+void LootTemplate::CopyConditions(ConditionList conditions)
+{
+ for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
+ i->conditions = conditions;
+
+ for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i)
+ i->CopyConditions(conditions);
+}
+
// Rolls for every item in the template and adds the rolled items the the loot
void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId) const
{
@@ -1165,6 +1197,8 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, bool rate, uint16
if (!Referenced)
continue; // Error message already printed at loading stage
+ const_cast<LootTemplate*>(Referenced)->CopyConditions(i->conditions);//copy conditions from referer template
+
for (uint32 loop = 0; loop < i->maxcount; ++loop) // Ref multiplicator
Referenced->Process(loot, store, rate, lootMode, i->group);
}
@@ -1268,6 +1302,66 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se
for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr)
grItr->CheckLootRefs(store,ref_set);
}
+bool LootTemplate::addConditionItem(Condition* cond)
+{
+ if (!cond || !cond->isLoaded())//should never happen, checked at loading
+ {
+ sLog.outError("LootTemplate::addConditionItem: condition is null");
+ return false;
+ }
+ if (!Entries.empty())
+ {
+ for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i)
+ {
+ if (i->itemid == cond->mSourceEntry)
+ {
+ i->conditions.push_back(cond);
+ return true;
+ }
+ }
+ }
+ if (!Groups.empty())
+ {
+ for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr)
+ {
+ LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList();
+ if (!itemList->empty())
+ {
+ for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
+ {
+ if ((*i).itemid == cond->mSourceEntry)
+ {
+ (*i).conditions.push_back(cond);
+ return true;
+ }
+ }
+ }
+ itemList = (*groupItr).GetEqualChancedItemList();
+ if (!itemList->empty())
+ {
+ for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i)
+ {
+ if ((*i).itemid == cond->mSourceEntry)
+ {
+ (*i).conditions.push_back(cond);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool LootTemplate::isReference(uint32 id)
+{
+ for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr)
+ {
+ if (ieItr->itemid == id && ieItr->mincountOrRef < 0)
+ return true;
+ }
+ return false;//not found or not reference
+}
void LoadLootTemplates_Creature()
{
diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h
index 1f443f47fb9..65fe3de22e1 100644
--- a/src/game/LootMgr.h
+++ b/src/game/LootMgr.h
@@ -25,6 +25,7 @@
#include "ByteBuffer.h"
#include "Utilities/LinkedReference/RefManager.h"
#include "SharedDefines.h"
+#include "ConditionMgr.h"
#include <map>
#include <vector>
@@ -98,6 +99,7 @@ enum LootSlotType
class Player;
class LootStore;
+class ConditionMgr;
struct LootStoreItem
{
@@ -108,13 +110,13 @@ struct LootStoreItem
uint8 group :7;
bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB)
uint8 maxcount :8; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative)
- uint16 conditionId :16; // additional loot condition Id
+ ConditionList conditions; // additional loot condition
// Constructor, converting ChanceOrQuestChance -> (chance, needs_quest)
// displayid is filled in IsValid() which must be called after
- LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, uint16 _lootmode, uint8 _group, uint8 _conditionId, int32 _mincountOrRef, uint8 _maxcount)
+ LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, uint16 _lootmode, uint8 _group, int32 _mincountOrRef, uint8 _maxcount)
: itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), lootmode(_lootmode),
- group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId)
+ group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount)
{}
bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation)
@@ -127,7 +129,7 @@ struct LootItem
uint32 itemid;
uint32 randomSuffix;
int32 randomPropertyId;
- uint16 conditionId :16; // allow compiler pack structure
+ ConditionList conditions; // additional loot condition
uint8 count : 8;
bool is_looted : 1;
bool is_blocked : 1;
@@ -186,6 +188,8 @@ class LootStore
bool HaveQuestLootForPlayer(uint32 loot_id,Player* player) const;
LootTemplate const* GetLootFor(uint32 loot_id) const;
+ void ResetConditions();
+ LootTemplate* GetLootForConditionFill(uint32 loot_id);
char const* GetName() const { return m_name; }
char const* GetEntryName() const { return m_entryName; }
@@ -210,6 +214,7 @@ class LootTemplate
void AddEntry(LootStoreItem& item);
// Rolls for every item in the template and adds the rolled items the the loot
void Process(Loot& loot, LootStore const& store, bool rate, uint16 lootMode, uint8 groupId = 0) const;
+ void CopyConditions(ConditionList conditions);
// True if template includes at least 1 quest drop entry
bool HasQuestDrop(LootTemplateMap const& store, uint8 groupId = 0) const;
@@ -219,6 +224,9 @@ class LootTemplate
// Checks integrity of the template
void Verify(LootStore const& store, uint32 Id) const;
void CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const;
+ bool addConditionItem(Condition* cond);
+ bool isReference(uint32 id);
+
private:
LootStoreItemList Entries; // not grouped only
LootGroups Groups; // groups have own (optimised) processing, grouped entries go there
@@ -355,6 +363,7 @@ extern LootStore LootTemplates_Item;
extern LootStore LootTemplates_Mail;
extern LootStore LootTemplates_Milling;
extern LootStore LootTemplates_Pickpocketing;
+extern LootStore LootTemplates_Reference;
extern LootStore LootTemplates_Skinning;
extern LootStore LootTemplates_Disenchant;
extern LootStore LootTemplates_Prospecting;
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index c826c0ea441..ce86c2a4e77 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -44,7 +44,6 @@
#include "SpellAuras.h"
#include "Util.h"
#include "WaypointManager.h"
-#include "InstanceData.h" //for condition_instance_data
#include "GossipDef.h"
#include "Vehicle.h"
#include "AchievementMgr.h"
@@ -182,9 +181,6 @@ ObjectMgr::ObjectMgr()
m_guildId = 1;
m_arenaTeamId = 1;
m_auctionid = 1;
-
- // Only zero condition left, others will be added while loading DB tables
- mConditions.resize(1);
}
ObjectMgr::~ObjectMgr()
@@ -2427,107 +2423,6 @@ void ObjectMgr::LoadVehicleAccessories()
sLog.outString(">> Loaded %u Vehicle Accessories", count);
}
-void ObjectMgr::LoadItemRequiredTarget()
-{
- m_ItemRequiredTarget.clear(); // needed for reload case
-
- uint32 count = 0;
-
- QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM item_required_target");
-
- if (!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 ItemRequiredTarget. DB table `item_required_target` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 uiItemId = fields[0].GetUInt32();
- uint32 uiType = fields[1].GetUInt32();
- uint32 uiTargetEntry = fields[2].GetUInt32();
-
- ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(uiItemId);
-
- if (!pItemProto)
- {
- sLog.outErrorDb("Table `item_required_target`: Entry %u listed for TargetEntry %u does not exist in `item_template`.",uiItemId,uiTargetEntry);
- continue;
- }
-
- bool bIsItemSpellValid = false;
-
- for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
- {
- if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId))
- {
- if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
- pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
- {
- SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(pSpellInfo->Id);
- if (bounds.first != bounds.second)
- break;
-
- for (int j = 0; j < 3; ++j)
- {
- if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ENEMY ||
- pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ENEMY ||
- pSpellInfo->EffectImplicitTargetA[i] == TARGET_UNIT_TARGET_ANY ||
- pSpellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_TARGET_ANY)
- {
- bIsItemSpellValid = true;
- break;
- }
- }
- if (bIsItemSpellValid)
- break;
- }
- }
- }
-
- if (!bIsItemSpellValid)
- {
- sLog.outErrorDb("Table `item_required_target`: Spell used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in `spell_script_target` or doesn't have item spelltrigger.",uiItemId);
- continue;
- }
-
- if (!uiType || uiType > MAX_ITEM_REQ_TARGET_TYPE)
- {
- sLog.outErrorDb("Table `item_required_target`: Type %u for TargetEntry %u is incorrect.",uiType,uiTargetEntry);
- continue;
- }
-
- if (!uiTargetEntry)
- {
- sLog.outErrorDb("Table `item_required_target`: TargetEntry == 0 for Type (%u).",uiType);
- continue;
- }
-
- if (!sCreatureStorage.LookupEntry<CreatureInfo>(uiTargetEntry))
- {
- sLog.outErrorDb("Table `item_required_target`: creature template entry %u does not exist.",uiTargetEntry);
- continue;
- }
-
- m_ItemRequiredTarget.insert(ItemRequiredTargetMap::value_type(uiItemId,ItemRequiredTarget(ItemRequiredTargetType(uiType),uiTargetEntry)));
-
- ++count;
- } while (result->NextRow());
-
- sLog.outString();
- sLog.outString(">> Loaded %u Item required targets", count);
-}
-
void ObjectMgr::LoadPetLevelInfo()
{
// Loading levels data
@@ -7631,28 +7526,6 @@ void ObjectMgr::LoadFishingBaseSkillLevel()
sLog.outString(">> Loaded %u areas for fishing base skill level", count);
}
-// Searches for the same condition already in Conditions store
-// Returns Id if found, else adds it to Conditions and returns Id
-uint16 ObjectMgr::GetConditionId(ConditionType condition, uint32 value1, uint32 value2)
-{
- PlayerCondition lc = PlayerCondition(condition, value1, value2);
- for (uint16 i=0; i < mConditions.size(); ++i)
- {
- if (lc == mConditions[i])
- return i;
- }
-
- mConditions.push_back(lc);
-
- if (mConditions.size() > 0xFFFF)
- {
- sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!");
- return 0;
- }
-
- return mConditions.size() - 1;
-}
-
bool ObjectMgr::CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names)
{
for (uint8 i =0; i < MAX_DECLINED_NAME_CASES; ++i)
@@ -7675,225 +7548,6 @@ uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id)
return 0;
}
-// Checks if player meets the condition
-bool PlayerCondition::Meets(Player const * player) const
-{
- if (!player)
- return false; // player not present, return false
-
- switch (condition)
- {
- case CONDITION_NONE:
- return true; // empty condition, always met
- case CONDITION_AURA:
- return player->HasAuraEffect(value1, value2);
- case CONDITION_ITEM:
- return player->HasItemCount(value1, value2);
- case CONDITION_ITEM_EQUIPPED:
- return player->HasItemOrGemWithIdEquipped(value1,1);
- case CONDITION_ZONEID:
- return player->GetZoneId() == value1;
- case CONDITION_REPUTATION_RANK:
- {
- FactionEntry const* faction = sFactionStore.LookupEntry(value1);
- return faction && uint32(player->GetReputationMgr().GetRank(faction)) >= int32(value2);
- }
- case CONDITION_ACHIEVEMENT:
- {
- AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(value1);
- return player->GetAchievementMgr().HasAchieved(achievement);
- }
- case CONDITION_TEAM:
- return player->GetTeam() == value1;
- case CONDITION_CLASS:
- return player->getClass() == value1;
- case CONDITION_RACE:
- return player->getRace() == value1;
- case CONDITION_SKILL:
- return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2;
- case CONDITION_QUESTREWARDED:
- return player->GetQuestRewardStatus(value1);
- case CONDITION_QUESTTAKEN:
- {
- QuestStatus status = player->GetQuestStatus(value1);
- return (status == QUEST_STATUS_INCOMPLETE);
- }
- case CONDITION_QUEST_NONE:
- {
- QuestStatus status = player->GetQuestStatus(value1);
- return (status == QUEST_STATUS_NONE);
- }
- case CONDITION_AD_COMMISSION_AURA:
- {
- Unit::AuraApplicationMap const& auras = player->GetAppliedAuras();
- for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if ((itr->second->GetBase()->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetBase()->GetSpellProto()->SpellVisual[0] == 3580)
- return true;
- return false;
- }
- case CONDITION_NO_AURA:
- return !player->HasAuraEffect(value1, value2);
- case CONDITION_ACTIVE_EVENT:
- return gameeventmgr.IsActiveEvent(value1);
- case CONDITION_INSTANCE_DATA:
- {
- Map *map = player->GetMap();
- if (map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
- return ((InstanceMap*)map)->GetInstanceData()->GetData(value1) == value2;
- }
- default:
- return false;
- }
-}
-
-// Verification of condition values validity
-bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2)
-{
- if (condition >= MAX_CONDITION) // Wrong condition type
- {
- sLog.outErrorDb("Condition has bad type of %u, skipped ", condition);
- return false;
- }
-
- switch (condition)
- {
- case CONDITION_AURA:
- {
- if (!sSpellStore.LookupEntry(value1))
- {
- sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
- return false;
- }
- if (value2 > 2)
- {
- sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_ITEM:
- {
- ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
- if (!proto)
- {
- sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_ITEM_EQUIPPED:
- {
- ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
- if (!proto)
- {
- sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_ZONEID:
- {
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1);
- if (!areaEntry)
- {
- sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1);
- return false;
- }
- if (areaEntry->zone != 0)
- {
- sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_REPUTATION_RANK:
- {
- FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1);
- if (!factionEntry)
- {
- sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_TEAM:
- {
- if (value1 != ALLIANCE && value1 != HORDE)
- {
- sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_SKILL:
- {
- SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1);
- if (!pSkill)
- {
- sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1);
- return false;
- }
- if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue())
- {
- sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_QUESTREWARDED:
- case CONDITION_QUESTTAKEN:
- {
- Quest const *Quest = objmgr.GetQuestTemplate(value1);
- if (!Quest)
- {
- sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1);
- return false;
- }
- if (value2)
- sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
- break;
- }
- case CONDITION_AD_COMMISSION_AURA:
- {
- if (value1)
- sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1);
- if (value2)
- sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
- break;
- }
- case CONDITION_NO_AURA:
- {
- if (!sSpellStore.LookupEntry(value1))
- {
- sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
- return false;
- }
- if (value2 > 2)
- {
- sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_ACTIVE_EVENT:
- {
- GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- if (value1 >=events.size() || !events[value1].isValid())
- {
- sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_INSTANCE_DATA:
- //TODO: need some check
- break;
- case CONDITION_NONE:
- break;
- }
- return true;
-}
-
SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
{
switch(pSkill->categoryId)
@@ -8423,8 +8077,7 @@ void ObjectMgr::LoadGossipMenu()
{
m_mGossipMenusMap.clear();
- QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, text_id, "
- "cond_1, cond_1_val_1, cond_1_val_2, cond_2, cond_2_val_1, cond_2_val_2 FROM gossip_menu");
+ QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, text_id FROM gossip_menu");
if (!result)
{
@@ -8450,14 +8103,7 @@ void ObjectMgr::LoadGossipMenu()
GossipMenus gMenu;
gMenu.entry = fields[0].GetUInt32();
- gMenu.text_id = fields[1].GetUInt32();
-
- ConditionType cond_1 = (ConditionType)fields[2].GetUInt32();
- uint32 cond_1_val_1 = fields[3].GetUInt32();
- uint32 cond_1_val_2 = fields[4].GetUInt32();
- ConditionType cond_2 = (ConditionType)fields[5].GetUInt32();
- uint32 cond_2_val_1 = fields[6].GetUInt32();
- uint32 cond_2_val_2 = fields[7].GetUInt32();
+ gMenu.text_id = fields[1].GetUInt32();
if (!GetGossipText(gMenu.text_id))
{
@@ -8465,21 +8111,6 @@ void ObjectMgr::LoadGossipMenu()
continue;
}
- if (!PlayerCondition::IsValid(cond_1, cond_1_val_1, cond_1_val_2))
- {
- sLog.outErrorDb("Table gossip_menu entry %u, invalid condition 1 for id %u", gMenu.entry, gMenu.text_id);
- continue;
- }
-
- if (!PlayerCondition::IsValid(cond_2, cond_2_val_1, cond_2_val_2))
- {
- sLog.outErrorDb("Table gossip_menu entry %u, invalid condition 2 for id %u", gMenu.entry, gMenu.text_id);
- continue;
- }
-
- gMenu.cond_1 = GetConditionId(cond_1, cond_1_val_1, cond_1_val_2);
- gMenu.cond_2 = GetConditionId(cond_2, cond_2_val_1, cond_2_val_2);
-
m_mGossipMenusMap.insert(GossipMenusMap::value_type(gMenu.entry, gMenu));
++count;
@@ -8496,10 +8127,7 @@ void ObjectMgr::LoadGossipMenuItems()
QueryResult_AutoPtr result = WorldDatabase.Query(
"SELECT menu_id, id, option_icon, option_text, option_id, npc_option_npcflag, "
- "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text, "
- "cond_1, cond_1_val_1, cond_1_val_2, "
- "cond_2, cond_2_val_1, cond_2_val_2, "
- "cond_3, cond_3_val_1, cond_3_val_2 "
+ "action_menu_id, action_poi_id, action_script_id, box_coded, box_money, box_text "
"FROM gossip_menu_option");
if (!result)
@@ -8543,32 +8171,6 @@ void ObjectMgr::LoadGossipMenuItems()
gMenuItem.box_money = fields[10].GetUInt32();
gMenuItem.box_text = fields[11].GetCppString();
- ConditionType cond_1 = (ConditionType)fields[12].GetUInt32();
- uint32 cond_1_val_1 = fields[13].GetUInt32();
- uint32 cond_1_val_2 = fields[14].GetUInt32();
- ConditionType cond_2 = (ConditionType)fields[15].GetUInt32();
- uint32 cond_2_val_1 = fields[16].GetUInt32();
- uint32 cond_2_val_2 = fields[17].GetUInt32();
- ConditionType cond_3 = (ConditionType)fields[18].GetUInt32();
- uint32 cond_3_val_1 = fields[19].GetUInt32();
- uint32 cond_3_val_2 = fields[20].GetUInt32();
-
- if (!PlayerCondition::IsValid(cond_1, cond_1_val_1, cond_1_val_2))
- {
- sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 1 for id %u", gMenuItem.menu_id, gMenuItem.id);
- continue;
- }
- if (!PlayerCondition::IsValid(cond_2, cond_2_val_1, cond_2_val_2))
- {
- sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 2 for id %u", gMenuItem.menu_id, gMenuItem.id);
- continue;
- }
- if (!PlayerCondition::IsValid(cond_3, cond_3_val_1, cond_3_val_2))
- {
- sLog.outErrorDb("Table gossip_menu_option menu %u, invalid condition 3 for id %u", gMenuItem.menu_id, gMenuItem.id);
- continue;
- }
-
if (gMenuItem.option_icon >= GOSSIP_ICON_MAX)
{
sLog.outErrorDb("Table gossip_menu_option for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.menu_id, gMenuItem.id, gMenuItem.option_icon);
@@ -8601,10 +8203,6 @@ void ObjectMgr::LoadGossipMenuItems()
gossipScriptSet.erase(gMenuItem.action_script_id);
}
- gMenuItem.cond_1 = GetConditionId(cond_1, cond_1_val_1, cond_1_val_2);
- gMenuItem.cond_2 = GetConditionId(cond_2, cond_2_val_1, cond_2_val_2);
- gMenuItem.cond_3 = GetConditionId(cond_3, cond_3_val_1, cond_3_val_2);
-
m_mGossipMenuItemsMap.insert(GossipMenuItemsMap::value_type(gMenuItem.menu_id, gMenuItem));
++count;
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 2586d987a05..79b6ffdd0eb 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -41,10 +41,11 @@
#include "Policies/Singleton.h"
#include "Database/SQLStorage.h"
#include "Vehicle.h"
-
+#include "ObjectMgr.h"
#include <string>
#include <map>
#include <limits>
+#include "ConditionMgr.h"
extern SQLStorage sCreatureStorage;
extern SQLStorage sCreatureDataAddonStorage;
@@ -235,23 +236,22 @@ struct GossipMenuItems
bool box_coded;
uint32 box_money;
std::string box_text;
- uint16 cond_1;
- uint16 cond_2;
- uint16 cond_3;
+ ConditionList conditions;
};
struct GossipMenus
{
uint32 entry;
uint32 text_id;
- uint16 cond_1;
- uint16 cond_2;
+ ConditionList conditions;
};
typedef std::multimap<uint32,GossipMenus> GossipMenusMap;
typedef std::pair<GossipMenusMap::const_iterator, GossipMenusMap::const_iterator> GossipMenusMapBounds;
+typedef std::pair<GossipMenusMap::iterator, GossipMenusMap::iterator> GossipMenusMapBoundsNonConst;
typedef std::multimap<uint32,GossipMenuItems> GossipMenuItemsMap;
typedef std::pair<GossipMenuItemsMap::const_iterator, GossipMenuItemsMap::const_iterator> GossipMenuItemsMapBounds;
+typedef std::pair<GossipMenuItemsMap::iterator, GossipMenuItemsMap::iterator> GossipMenuItemsMapBoundsNonConst;
struct QuestPOIPoint
{
@@ -300,48 +300,6 @@ struct GraveYardData
};
typedef std::multimap<uint32,GraveYardData> GraveYardMap;
-enum ConditionType
-{ // value1 value2 for the Condition enumed
- CONDITION_NONE = 0, // 0 0
- CONDITION_AURA = 1, // spell_id effindex
- CONDITION_ITEM = 2, // item_id count
- CONDITION_ITEM_EQUIPPED = 3, // item_id 0
- CONDITION_ZONEID = 4, // zone_id 0
- CONDITION_REPUTATION_RANK = 5, // faction_id min_rank
- CONDITION_TEAM = 6, // player_team 0, (469 - Alliance 67 - Horde)
- CONDITION_SKILL = 7, // skill_id skill_value
- CONDITION_QUESTREWARDED = 8, // quest_id 0
- CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
- CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD commission aura active
- CONDITION_NO_AURA = 11, // spell_id effindex
- CONDITION_ACTIVE_EVENT = 12, // event_id
- CONDITION_INSTANCE_DATA = 13, // entry data
- CONDITION_QUEST_NONE = 14, // quest_id 0
- CONDITION_CLASS = 15, // class 0
- CONDITION_RACE = 16, // race 0
- CONDITION_ACHIEVEMENT = 17 // achievement_id 0
-};
-
-#define MAX_CONDITION 18 // maximum value in ConditionType enum
-
-struct PlayerCondition
-{
- ConditionType condition; // additional condition type
- uint32 value1; // data for the condition - see ConditionType definition
- uint32 value2;
-
- PlayerCondition(uint8 _condition = 0, uint32 _value1 = 0, uint32 _value2 = 0)
- : condition(ConditionType(_condition)), value1(_value1), value2(_value2) {}
-
- static bool IsValid(ConditionType condition, uint32 value1, uint32 value2);
- // Checks correctness of values
- bool Meets(Player const * APlayer) const; // Checks if the player meets the condition
- bool operator == (PlayerCondition const& lc) const
- {
- return (lc.condition == condition && lc.value1 == value1 && lc.value2 == value2);
- }
-};
-
// NPC gossip text id
typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap;
@@ -648,7 +606,6 @@ class ObjectMgr
void LoadGameobjects();
void LoadGameobjectRespawnTimes();
void LoadItemPrototypes();
- void LoadItemRequiredTarget();
void LoadItemLocales();
void LoadQuestLocales();
void LoadNpcTextLocales();
@@ -880,15 +837,6 @@ class ObjectMgr
int GetIndexForLocale(LocaleConstant loc);
LocaleConstant GetLocaleForIndex(int i);
- uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2);
- bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const
- {
- if (condition_id >= mConditions.size())
- return false;
-
- return mConditions[condition_id].Meets(player);
- }
-
GameTele const* GetGameTele(uint32 id) const
{
GameTeleMap::const_iterator itr = m_GameTeleMap.find(id);
@@ -942,11 +890,6 @@ class ObjectMgr
return SpellClickInfoMapBounds(mSpellClickInfoMap.lower_bound(creature_id),mSpellClickInfoMap.upper_bound(creature_id));
}
- ItemRequiredTargetMapBounds GetItemRequiredTargetMapBounds(uint32 uiItemEntry) const
- {
- return ItemRequiredTargetMapBounds(m_ItemRequiredTarget.lower_bound(uiItemEntry),m_ItemRequiredTarget.upper_bound(uiItemEntry));
- }
-
GM_Ticket *GetGMTicket(uint64 ticketGuid)
{
for (GmTicketList::const_iterator i = m_GMTicketList.begin(); i != m_GMTicketList.end(); ++i)
@@ -969,10 +912,19 @@ class ObjectMgr
return GossipMenusMapBounds(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId));
}
+ GossipMenusMapBoundsNonConst GetGossipMenusMapBoundsNonConst(uint32 uiMenuId)
+ {
+ return GossipMenusMapBoundsNonConst(m_mGossipMenusMap.lower_bound(uiMenuId),m_mGossipMenusMap.upper_bound(uiMenuId));
+ }
+
GossipMenuItemsMapBounds GetGossipMenuItemsMapBounds(uint32 uiMenuId) const
{
return GossipMenuItemsMapBounds(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId));
}
+ GossipMenuItemsMapBoundsNonConst GetGossipMenuItemsMapBoundsNonConst(uint32 uiMenuId)
+ {
+ return GossipMenuItemsMapBoundsNonConst(m_mGossipMenuItemsMap.lower_bound(uiMenuId),m_mGossipMenuItemsMap.upper_bound(uiMenuId));
+ }
void AddOrUpdateGMTicket(GM_Ticket &ticket, bool create = false);
void _AddOrUpdateGMTicket(GM_Ticket &ticket);
@@ -1109,10 +1061,6 @@ class ObjectMgr
RespawnTimes mCreatureRespawnTimes;
RespawnTimes mGORespawnTimes;
- // Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required)
- typedef std::vector<PlayerCondition> ConditionStore;
- ConditionStore mConditions;
-
CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap;
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index c2ee45e73d1..43965f5646a 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -66,7 +66,7 @@
#include "AchievementMgr.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
-
+#include "ConditionMgr.h"
#include <cmath>
#define ZONE_UPDATE_INTERVAL (1*IN_MILISECONDS)
@@ -503,6 +503,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_powerFraction[i] = 0;
m_globalCooldowns.clear();
+
+ m_ConditionErrorMsgId = 0;
}
Player::~Player ()
@@ -13302,14 +13304,7 @@ void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId, bool showQue
for (GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr)
{
bool bCanTalk = true;
-
- if (itr->second.cond_1 && !objmgr.IsPlayerMeetToCondition(this, itr->second.cond_1))
- continue;
-
- if (itr->second.cond_2 && !objmgr.IsPlayerMeetToCondition(this, itr->second.cond_2))
- continue;
-
- if (itr->second.cond_3 && !objmgr.IsPlayerMeetToCondition(this, itr->second.cond_3))
+ if (!sConditionMgr.IsPlayerMeetToConditions(this, itr->second.conditions))
continue;
if (pSource->GetTypeId() == TYPEID_UNIT)
@@ -13643,7 +13638,7 @@ uint32 Player::GetGossipTextId(uint32 menuId)
for (GossipMenusMap::const_iterator itr = pMenuBounds.first; itr != pMenuBounds.second; ++itr)
{
- if (objmgr.IsPlayerMeetToCondition(this, itr->second.cond_1) && objmgr.IsPlayerMeetToCondition(this, itr->second.cond_2))
+ if (sConditionMgr.IsPlayerMeetToConditions(this, itr->second.conditions))
textId = itr->second.text_id;
}
@@ -17439,8 +17434,8 @@ bool Player::CheckInstanceLoginValid()
if (GetMap()->IsRaid())
{
- // cannot be in raid instance without a raid group
- if (!GetGroup() || !GetGroup()->isRaidGroup())
+ // cannot be in raid instance without a group
+ if (!GetGroup())
return false;
}
else
diff --git a/src/game/Player.h b/src/game/Player.h
index 0166eb2b23d..af8c5fb971d 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -2135,6 +2135,8 @@ class Player : public Unit, public GridObject<Player>
void SetHomebind(WorldLocation const& loc, uint32 area_id);
+ uint32 m_ConditionErrorMsgId;
+
// Homebind coordinates
uint32 m_homebindMapId;
uint16 m_homebindAreaId;
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 303cfc5ffc7..b039767c463 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -51,6 +51,7 @@
#include "Vehicle.h"
#include "SpellAuraEffects.h"
#include "ScriptMgr.h"
+#include "ConditionMgr.h"
#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILISECONDS)
@@ -1683,10 +1684,10 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
{
case SPELL_TARGETS_ENTRY:
{
- SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(m_spellInfo->Id);
- if (bounds.first == bounds.second)
+ ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
+ if (conditions.empty())
{
- sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
+ sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `conditions` for spell script target (ConditionSourceType 14)", m_spellInfo->Id, m_caster->GetEntry());
if (IsPositiveSpell(m_spellInfo->Id))
return SearchNearbyTarget(range, SPELL_TARGETS_ALLY);
else
@@ -1696,13 +1697,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
Creature* creatureScriptTarget = NULL;
GameObject* goScriptTarget = NULL;
- for (SpellScriptTarget::const_iterator i_spellST = bounds.first; i_spellST != bounds.second; ++i_spellST)
+ for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
{
- switch(i_spellST->second.type)
+ if ((*i_spellST)->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
+ continue;
+ switch((*i_spellST)->mConditionValue1)
{
case SPELL_TARGET_TYPE_CONTROLLED:
for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
- if ((*itr)->GetEntry() == i_spellST->second.targetEntry && (*itr)->IsWithinDistInMap(m_caster, range))
+ if ((*itr)->GetEntry() == (*i_spellST)->mConditionValue2 && (*itr)->IsWithinDistInMap(m_caster, range))
{
goScriptTarget = NULL;
creatureScriptTarget = (*itr)->ToCreature();
@@ -1710,9 +1713,9 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
}
break;
case SPELL_TARGET_TYPE_GAMEOBJECT:
- if (i_spellST->second.targetEntry)
+ if ((*i_spellST)->mConditionValue2)
{
- if (GameObject *go = m_caster->FindNearestGameObject(i_spellST->second.targetEntry, range))
+ if (GameObject *go = m_caster->FindNearestGameObject((*i_spellST)->mConditionValue2, range))
{
// remember found target and range, next attempt will find more near target with another entry
goScriptTarget = go;
@@ -1732,11 +1735,11 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
}
break;
case SPELL_TARGET_TYPE_CREATURE:
- if (m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == i_spellST->second.targetEntry)
+ if (m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == (*i_spellST)->mConditionValue2)
return m_targets.getUnitTarget();
case SPELL_TARGET_TYPE_DEAD:
default:
- if (Creature *cre = m_caster->FindNearestCreature(i_spellST->second.targetEntry, range, i_spellST->second.type != SPELL_TARGET_TYPE_DEAD))
+ if (Creature *cre = m_caster->FindNearestCreature((*i_spellST)->mConditionValue2, range, (*i_spellST)->mConditionValue1 != SPELL_TARGET_TYPE_DEAD))
{
creatureScriptTarget = cre;
goScriptTarget = NULL;
@@ -2249,8 +2252,8 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
std::list<Unit*> unitList;
if (targetType == SPELL_TARGETS_ENTRY)
{
- SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(m_spellInfo->Id);
- if (bounds.first == bounds.second)
+ ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
+ if (conditions.empty())
{
// Custom entries
// TODO: move these to sql
@@ -2321,14 +2324,16 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
// let it be done in one check?
else
{
- for (SpellScriptTarget::const_iterator i_spellST = bounds.first; i_spellST != bounds.second; ++i_spellST)
+ for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
{
- if (i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE)
- SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry);
- else if (i_spellST->second.type == SPELL_TARGET_TYPE_CONTROLLED)
+ if ((*i_spellST)->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
+ continue;
+ if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CREATURE)
+ SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, (*i_spellST)->mConditionValue2);
+ else if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED)
{
for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
- if ((*itr)->GetEntry() == i_spellST->second.targetEntry &&
+ if ((*itr)->GetEntry() == (*i_spellST)->mConditionValue2 &&
/*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
unitList.push_back(*itr);
}
@@ -2545,7 +2550,20 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere
return;
}
}
-
+ if (m_caster->ToPlayer())
+ {
+ //check for special spell conditions
+ ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id);
+ if (!conditions.empty())
+ {
+ if (!sConditionMgr.IsPlayerMeetToConditions(m_caster->ToPlayer(), conditions))
+ {
+ SendCastResult(SPELL_FAILED_DONT_REPORT);
+ finish(false);
+ return;
+ }
+ }
+ }
if (!m_targets.HasSrc() && m_spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
m_targets.setSrc(m_caster);
@@ -2607,7 +2625,6 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere
finish(false);
return;
}
-
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
if (objmgr.IsPlayerSpellDisabled(m_spellInfo->Id))
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 0feac0ef110..510fdccb98a 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -1972,174 +1972,6 @@ void SpellMgr::LoadSpellLearnSpells()
sLog.outString(">> Loaded %u spell learn spells + %u found in DBC", count, dbc_count);
}
-void SpellMgr::LoadSpellScriptTarget()
-{
- mSpellScriptTarget.clear(); // need for reload case
-
- uint32 count = 0;
-
- QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM spell_script_target");
-
- if (!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 SpellScriptTarget. DB table `spell_script_target` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 spellId = fields[0].GetUInt32();
- uint32 type = fields[1].GetUInt32();
- uint32 targetEntry = fields[2].GetUInt32();
-
- SpellEntry const* spellProto = sSpellStore.LookupEntry(spellId);
-
- if (!spellProto)
- {
- sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not exist.",spellId,targetEntry);
- continue;
- }
-
- bool targetfound = false;
- for (uint8 i = 0; i < 3; ++i)
- {
- if (spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_SRC ||
- spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_SRC ||
- spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_AREA_ENTRY_DST ||
- spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ENTRY_DST ||
- spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetA[i] == TARGET_DST_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetB[i] == TARGET_DST_NEARBY_ENTRY ||
- spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_CONE_ENTRY ||
- spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_CONE_ENTRY)
- {
- targetfound = true;
- break;
- }
- }
- if (!targetfound)
- {
- sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\
- ,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)",spellId,targetEntry);
- continue;
- }
-
- if (type >= MAX_SPELL_TARGET_TYPE)
- {
- sLog.outErrorDb("Table `spell_script_target`: target type %u for TargetEntry %u is incorrect.",type,targetEntry);
- continue;
- }
-
- switch(type)
- {
- case SPELL_TARGET_TYPE_GAMEOBJECT:
- {
- if (targetEntry == 0)
- break;
-
- if (!sGOStorage.LookupEntry<GameObjectInfo>(targetEntry))
- {
- sLog.outErrorDb("Table `spell_script_target`: gameobject template entry %u does not exist.", targetEntry);
- continue;
- }
- break;
- }
- case SPELL_TARGET_TYPE_CONTROLLED:
- if (targetEntry == 0)
- sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.", targetEntry);
- default:
- {
- //players
- /*if (targetEntry == 0)
- {
- sLog.outErrorDb("Table `spell_script_target`: target entry == 0 for not GO target type (%u).",type);
- continue;
- }*/
- if (targetEntry && !sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry))
- {
- sLog.outErrorDb("Table `spell_script_target`: creature template entry %u does not exist.", targetEntry);
- continue;
- }
- const CreatureInfo* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(targetEntry);
-
- if (spellId == 30427 && !cInfo->SkinLootId)
- {
- sLog.outErrorDb("Table `spell_script_target` has creature %u as a target of spellid 30427, but this creature has no skinlootid. Gas extraction will not work!", cInfo->Entry);
- continue;
- }
- break;
- }
- }
-
- mSpellScriptTarget.insert(SpellScriptTarget::value_type(spellId, SpellTargetEntry(SpellScriptTargetType(type), targetEntry)));
-
- ++count;
- } while (result->NextRow());
-
- // Check all spells
- for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
- {
- SpellEntry const * spellInfo = sSpellStore.LookupEntry(i);
- if (!spellInfo)
- continue;
-
- bool found = false;
- for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
- {
- switch (spellInfo->EffectImplicitTargetA[j])
- {
- case TARGET_UNIT_AREA_ENTRY_SRC:
- case TARGET_UNIT_AREA_ENTRY_DST:
- case TARGET_UNIT_NEARBY_ENTRY:
- case TARGET_GAMEOBJECT_NEARBY_ENTRY:
- case TARGET_DST_NEARBY_ENTRY:
- case TARGET_UNIT_CONE_ENTRY:
- found = true;
- break;
- }
- if (found)
- break;
-
- switch (spellInfo->EffectImplicitTargetB[j])
- {
- case TARGET_UNIT_AREA_ENTRY_SRC:
- case TARGET_UNIT_AREA_ENTRY_DST:
- case TARGET_UNIT_NEARBY_ENTRY:
- case TARGET_GAMEOBJECT_NEARBY_ENTRY:
- case TARGET_DST_NEARBY_ENTRY:
- case TARGET_UNIT_CONE_ENTRY:
- found = true;
- break;
- }
-
- if (found)
- break;
- }
- if (found)
- {
- SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(i);
- //if (bounds.first == bounds.second)
- //sLog.outDebug("Spell (ID: %u) does not have record in `spell_script_target`", i);
- }
- }
-
- sLog.outString();
- sLog.outString(">> Loaded %u Spell Script Targets", count);
-}
-
void SpellMgr::LoadSpellPetAuras()
{
mSpellPetAuraMap.clear(); // need for reload case
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 94121d4610d..224760029e7 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -685,9 +685,6 @@ struct SpellTargetEntry
uint32 targetEntry;
};
-typedef std::multimap<uint32,SpellTargetEntry> SpellScriptTarget;
-typedef std::pair<SpellScriptTarget::const_iterator,SpellScriptTarget::const_iterator> SpellScriptTargetBounds;
-
// coordinates for spells (accessed using SpellMgr functions)
struct SpellTargetPosition
{
@@ -1216,12 +1213,6 @@ class SpellMgr
bool IsSkillBonusSpell(uint32 spellId) const;
bool IsSkillTypeSpell(uint32 spellId, SkillType type) const;
- // Spell script targets
- SpellScriptTargetBounds GetSpellScriptTargetBounds(uint32 spell_id) const
- {
- return SpellScriptTargetBounds(mSpellScriptTarget.lower_bound(spell_id),mSpellScriptTarget.upper_bound(spell_id));
- }
-
// Spell correctess for client using
static bool IsSpellValid(SpellEntry const * spellInfo, Player* pl = NULL, bool msg = true);
@@ -1356,7 +1347,6 @@ class SpellMgr
void LoadSpellRequired();
void LoadSpellLearnSkills();
void LoadSpellLearnSpells();
- void LoadSpellScriptTarget();
void LoadSpellGroups();
void LoadSpellProcEvents();
void LoadSpellBonusess();
@@ -1377,7 +1367,6 @@ class SpellMgr
bool _isPositiveSpell(uint32 spellId, bool deep) const;
bool _isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) const;
- SpellScriptTarget mSpellScriptTarget;
SpellChainMap mSpellChains;
SpellsRequiringSpellMap mSpellsReqSpell;
SpellRequiredMap mSpellReq;
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 04f0c46a7d5..1629aa61af9 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -70,6 +70,7 @@
#include "ScriptMgr.h"
#include "AddonMgr.h"
#include "LFGMgr.h"
+#include "ConditionMgr.h"
INSTANTIATE_SINGLETON_1(World);
@@ -1380,12 +1381,6 @@ void World::SetInitialWorldSettings()
sLog.outString("Loading Creature templates...");
objmgr.LoadCreatureTemplates();
- sLog.outString("Loading SpellsScriptTarget...");
- spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
-
- sLog.outString("Loading ItemRequiredTarget...");
- objmgr.LoadItemRequiredTarget();
-
sLog.outString("Loading Creature Reputation OnKill Data...");
objmgr.LoadReputationOnKill();
@@ -1578,6 +1573,9 @@ void World::SetInitialWorldSettings()
sLog.outString("Loading Creature Formations...");
formation_mgr.LoadCreatureFormations();
+ sLog.outString("Loading Conditions...");
+ sConditionMgr.LoadConditions();
+
sLog.outString("Loading GM tickets...");
objmgr.LoadGMTickets();