Core/SpellAreas: Changed the way quest_start and quest_end works.

They now follow this rule:
The player's quest status of quest_start must have the mask defined in quest_start_status in order for the spell to be applied/kept.
The player's quest status of quest_end must _NOT_ have the mask defined in quest_end_status in order for the spell to be removed
To generate the mask:
Take the QuestStatus enum in QuestDef.h, use (1 << theValueYouWant) to obtain a mask and you can use | to combine masks.
This expands the usage of the spell_area table, making possible to give a player an aura while he has a quest, but remove it as soon as the quest is completed (not rewarded).
Feature request by @Svannon
This commit is contained in:
Subv
2012-10-16 21:44:28 -05:00
parent 6abc6253a6
commit 27f091806a
4 changed files with 46 additions and 72 deletions
@@ -0,0 +1,4 @@
ALTER TABLE `spell_area` ADD COLUMN `quest_start_status` INT(11) NOT NULL DEFAULT 64; -- default is QUEST_STATUS_REWARDED
ALTER TABLE `spell_area` ADD COLUMN `quest_end_status` INT(11) NOT NULL DEFAULT 11; -- default is QUEST_STATUS_COMPLETE | QUEST_STATUS_NONE | QUEST_STATUS_INCOMPLETE
UPDATE spell_area SET `quest_start_status` = (1 << 6) | (1 << 3) | (1 << 1) WHERE `quest_start_active` = 1;
ALTER TABLE spell_area DROP COLUMN `quest_start_active`;
+24 -40
View File
@@ -14980,19 +14980,6 @@ void Player::AddQuest(Quest const* quest, Object* questGiver)
if (questGiver && quest->GetQuestStartScript() != 0) if (questGiver && quest->GetQuestStartScript() != 0)
GetMap()->ScriptsStart(sQuestStartScripts, quest->GetQuestStartScript(), questGiver, this); GetMap()->ScriptsStart(sQuestStartScripts, quest->GetQuestStartScript(), questGiver, this);
// Some spells applied at quest activation
SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestMapBounds(quest_id, true);
if (saBounds.first != saBounds.second)
{
uint32 zone, area;
GetZoneAndAreaId(zone, area);
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if (itr->second->autocast && itr->second->IsFitToRequirements(this, zone, area))
if (!HasAura(itr->second->spellId))
CastSpell(this, itr->second->spellId, true);
}
UpdateForQuestWorldObjects(); UpdateForQuestWorldObjects();
} }
@@ -15181,33 +15168,6 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId()); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId());
uint32 zone = 0;
uint32 area = 0;
// remove auras from spells with quest reward state limitations
SpellAreaForQuestMapBounds saEndBounds = sSpellMgr->GetSpellAreaForQuestEndMapBounds(quest_id);
if (saEndBounds.first != saEndBounds.second)
{
GetZoneAndAreaId(zone, area);
for (SpellAreaForAreaMap::const_iterator itr = saEndBounds.first; itr != saEndBounds.second; ++itr)
if (!itr->second->IsFitToRequirements(this, zone, area))
RemoveAurasDueToSpell(itr->second->spellId);
}
// Some spells applied at quest reward
SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestMapBounds(quest_id, false);
if (saBounds.first != saBounds.second)
{
if (!zone || !area)
GetZoneAndAreaId(zone, area);
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if (itr->second->autocast && itr->second->IsFitToRequirements(this, zone, area))
if (!HasAura(itr->second->spellId))
CastSpell(this, itr->second->spellId, true);
}
//lets remove flag for delayed teleports //lets remove flag for delayed teleports
SetCanDelayTeleport(false); SetCanDelayTeleport(false);
} }
@@ -15750,6 +15710,30 @@ void Player::SetQuestStatus(uint32 quest_id, QuestStatus status)
m_QuestStatusSave[quest_id] = true; m_QuestStatusSave[quest_id] = true;
} }
uint32 zone = 0, area = 0;
SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestMapBounds(quest_id);
if (saBounds.first != saBounds.second)
{
GetZoneAndAreaId(zone, area);
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if (itr->second->autocast && itr->second->IsFitToRequirements(this, zone, area))
if (!HasAura(itr->second->spellId))
CastSpell(this, itr->second->spellId, true);
}
saBounds = sSpellMgr->GetSpellAreaForQuestEndMapBounds(quest_id);
if (saBounds.first != saBounds.second)
{
if (!zone || !area)
GetZoneAndAreaId(zone, area);
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if (!itr->second->IsFitToRequirements(this, zone, area))
RemoveAurasDueToSpell(itr->second->spellId);
}
UpdateForQuestWorldObjects(); UpdateForQuestWorldObjects();
} }
+13 -27
View File
@@ -1061,11 +1061,8 @@ SpellAreaMapBounds SpellMgr::GetSpellAreaMapBounds(uint32 spell_id) const
return SpellAreaMapBounds(mSpellAreaMap.lower_bound(spell_id), mSpellAreaMap.upper_bound(spell_id)); return SpellAreaMapBounds(mSpellAreaMap.lower_bound(spell_id), mSpellAreaMap.upper_bound(spell_id));
} }
SpellAreaForQuestMapBounds SpellMgr::GetSpellAreaForQuestMapBounds(uint32 quest_id, bool active) const SpellAreaForQuestMapBounds SpellMgr::GetSpellAreaForQuestMapBounds(uint32 quest_id) const
{ {
if (active)
return SpellAreaForQuestMapBounds(mSpellAreaForActiveQuestMap.lower_bound(quest_id), mSpellAreaForActiveQuestMap.upper_bound(quest_id));
else
return SpellAreaForQuestMapBounds(mSpellAreaForQuestMap.lower_bound(quest_id), mSpellAreaForQuestMap.upper_bound(quest_id)); return SpellAreaForQuestMapBounds(mSpellAreaForQuestMap.lower_bound(quest_id), mSpellAreaForQuestMap.upper_bound(quest_id));
} }
@@ -1099,11 +1096,11 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
return false; return false;
if (questStart) // not in expected required quest state if (questStart) // not in expected required quest state
if (!player || ((!questStartCanActive || !player->IsActiveQuest(questStart)) && !player->GetQuestRewardStatus(questStart))) if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0))
return false; return false;
if (questEnd) // not in expected forbidden quest state if (questEnd) // not in expected forbidden quest state
if (!player || player->GetQuestRewardStatus(questEnd)) if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0))
return false; return false;
if (auraSpell) // not have expected aura if (auraSpell) // not have expected aura
@@ -2433,12 +2430,11 @@ void SpellMgr::LoadSpellAreas()
mSpellAreaMap.clear(); // need for reload case mSpellAreaMap.clear(); // need for reload case
mSpellAreaForQuestMap.clear(); mSpellAreaForQuestMap.clear();
mSpellAreaForActiveQuestMap.clear();
mSpellAreaForQuestEndMap.clear(); mSpellAreaForQuestEndMap.clear();
mSpellAreaForAuraMap.clear(); mSpellAreaForAuraMap.clear();
// 0 1 2 3 4 5 6 7 8 // 0 1 2 3 4 5 6 7 8 9
QueryResult result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area"); QueryResult result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_status, quest_end_status, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
if (!result) if (!result)
{ {
@@ -2457,12 +2453,13 @@ void SpellMgr::LoadSpellAreas()
spellArea.spellId = spell; spellArea.spellId = spell;
spellArea.areaId = fields[1].GetUInt32(); spellArea.areaId = fields[1].GetUInt32();
spellArea.questStart = fields[2].GetUInt32(); spellArea.questStart = fields[2].GetUInt32();
spellArea.questStartCanActive = fields[3].GetBool(); spellArea.questStartStatus = fields[3].GetUInt32();
spellArea.questEnd = fields[4].GetUInt32(); spellArea.questEndStatus = fields[4].GetUInt32();
spellArea.auraSpell = fields[5].GetInt32(); spellArea.questEnd = fields[5].GetUInt32();
spellArea.raceMask = fields[6].GetUInt32(); spellArea.auraSpell = fields[6].GetInt32();
spellArea.gender = Gender(fields[7].GetUInt8()); spellArea.raceMask = fields[7].GetUInt32();
spellArea.autocast = fields[8].GetBool(); spellArea.gender = Gender(fields[8].GetUInt8());
spellArea.autocast = fields[9].GetBool();
if (SpellInfo const* spellInfo = GetSpellInfo(spell)) if (SpellInfo const* spellInfo = GetSpellInfo(spell))
{ {
@@ -2494,7 +2491,7 @@ void SpellMgr::LoadSpellAreas()
continue; continue;
// duplicate by requirements // duplicate by requirements
ok =false; ok = false;
break; break;
} }
@@ -2524,12 +2521,6 @@ void SpellMgr::LoadSpellAreas()
sLog->outError(LOG_FILTER_SQL, "Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell, spellArea.questEnd); sLog->outError(LOG_FILTER_SQL, "Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell, spellArea.questEnd);
continue; continue;
} }
if (spellArea.questEnd == spellArea.questStart && !spellArea.questStartCanActive)
{
sLog->outError(LOG_FILTER_SQL, "Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time", spell, spellArea.questEnd);
continue;
}
} }
if (spellArea.auraSpell) if (spellArea.auraSpell)
@@ -2605,12 +2596,7 @@ void SpellMgr::LoadSpellAreas()
// for search at quest start/reward // for search at quest start/reward
if (spellArea.questStart) if (spellArea.questStart)
{
if (spellArea.questStartCanActive)
mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
else
mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa)); mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
}
// for search at quest start/reward // for search at quest start/reward
if (spellArea.questEnd) if (spellArea.questEnd)
+3 -3
View File
@@ -495,7 +495,8 @@ struct SpellArea
int32 auraSpell; // spell aura must be applied for spell apply)if possitive) and it must not be applied in other case int32 auraSpell; // spell aura must be applied for spell apply)if possitive) and it must not be applied in other case
uint32 raceMask; // can be applied only to races uint32 raceMask; // can be applied only to races
Gender gender; // can be applied only to gender Gender gender; // can be applied only to gender
bool questStartCanActive; // if true then quest start can be active (not only rewarded) uint32 questStartStatus; // QuestStatus that quest_start must have in order to keep the spell
uint32 questEndStatus; // QuestStatus that the quest_end must have in order to keep the spell (if the quest_end's status is different than this, the spell will be dropped)
bool autocast; // if true then auto applied at area enter, in other case just allowed to cast bool autocast; // if true then auto applied at area enter, in other case just allowed to cast
// helpers // helpers
@@ -681,7 +682,7 @@ class SpellMgr
// Spell area // Spell area
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const; SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const;
SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id, bool active) const; SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id) const;
SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const; SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const;
SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const; SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const;
SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const; SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const;
@@ -740,7 +741,6 @@ class SpellMgr
EnchantCustomAttribute mEnchantCustomAttr; EnchantCustomAttribute mEnchantCustomAttr;
SpellAreaMap mSpellAreaMap; SpellAreaMap mSpellAreaMap;
SpellAreaForQuestMap mSpellAreaForQuestMap; SpellAreaForQuestMap mSpellAreaForQuestMap;
SpellAreaForQuestMap mSpellAreaForActiveQuestMap;
SpellAreaForQuestMap mSpellAreaForQuestEndMap; SpellAreaForQuestMap mSpellAreaForQuestEndMap;
SpellAreaForAuraMap mSpellAreaForAuraMap; SpellAreaForAuraMap mSpellAreaForAuraMap;
SpellAreaForAreaMap mSpellAreaForAreaMap; SpellAreaForAreaMap mSpellAreaForAreaMap;