mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/DataStores: Implemented checking PlayerCondition for future use
This commit is contained in:
160
sql/updates/hotfixes/2016_01_03_00_hotfixes.sql
Normal file
160
sql/updates/hotfixes/2016_01_03_00_hotfixes.sql
Normal file
@@ -0,0 +1,160 @@
|
||||
--
|
||||
-- Table structure for table `player_condition`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `player_condition`;
|
||||
CREATE TABLE `player_condition` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Flags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`RaceMask` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ClassMask` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Gender` int(11) NOT NULL DEFAULT '0',
|
||||
`NativeGender` int(11) NOT NULL DEFAULT '0',
|
||||
`SkillID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SkillID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SkillID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SkillID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinSkill1` int(11) NOT NULL DEFAULT '0',
|
||||
`MinSkill2` int(11) NOT NULL DEFAULT '0',
|
||||
`MinSkill3` int(11) NOT NULL DEFAULT '0',
|
||||
`MinSkill4` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxSkill1` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxSkill2` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxSkill3` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxSkill4` int(11) NOT NULL DEFAULT '0',
|
||||
`SkillLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LanguageID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinLanguage` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxLanguage` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinFactionID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinFactionID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinFactionID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxFactionID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinReputation1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinReputation2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinReputation3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxReputation` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ReputationLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Unknown1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinPVPRank` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxPVPRank` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PvpMedal` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PrevQuestLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PrevQuestID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PrevQuestID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PrevQuestID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PrevQuestID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrQuestLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrQuestID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrQuestID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrQuestID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrQuestID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrentCompletedQuestLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrentCompletedQuestID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrentCompletedQuestID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrentCompletedQuestID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrentCompletedQuestID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SpellLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SpellID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SpellID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SpellID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`SpellID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemCount1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemCount2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemCount3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemCount4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ItemFlags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Explored1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Explored2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Time1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Time2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AuraSpellLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AuraSpellID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AuraSpellID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AuraSpellID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AuraSpellID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`WorldStateExpressionID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`WeatherID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PartyStatus` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LifetimeMaxPVPRank` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AchievementLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Achievement1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Achievement2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Achievement3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`Achievement4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgStatus1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgStatus2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgStatus3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgStatus4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgCompare1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgCompare2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgCompare3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgCompare4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgValue1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgValue2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgValue3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`LfgValue4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AreaLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AreaID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AreaID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AreaID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`AreaID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyID1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyID2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyID3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyID4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyCount1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyCount2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyCount3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`CurrencyCount4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillLogic` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillMonster1` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillMonster2` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillMonster3` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`QuestKillMonster4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinExpansionLevel` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxExpansionLevel` int(11) NOT NULL DEFAULT '0',
|
||||
`MinExpansionTier` int(11) NOT NULL DEFAULT '0',
|
||||
`MaxExpansionTier` int(11) NOT NULL DEFAULT '0',
|
||||
`MinGuildLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxGuildLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PhaseUseFlags` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PhaseID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`PhaseGroupID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinAvgItemLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxAvgItemLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MinAvgEquippedItemLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`MaxAvgEquippedItemLevel` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`ChrSpecializationIndex` int(11) NOT NULL DEFAULT '0',
|
||||
`ChrSpecializationRole` int(11) NOT NULL DEFAULT '0',
|
||||
`FailureDescription` text,
|
||||
`PowerType` int(11) NOT NULL DEFAULT '0',
|
||||
`PowerTypeComp` int(11) NOT NULL DEFAULT '0',
|
||||
`PowerTypeValue` int(11) NOT NULL DEFAULT '0',
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
--
|
||||
-- Table structure for table `player_condition_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `player_condition_locale`;
|
||||
CREATE TABLE `player_condition_locale` (
|
||||
`ID` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`locale` varchar(4) NOT NULL,
|
||||
`FailureDescription_lang` text,
|
||||
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`ID`,`locale`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
@@ -346,6 +346,24 @@ void HotfixDatabaseConnection::DoPrepareStatements()
|
||||
// PhaseXPhaseGroup.db2
|
||||
PrepareStatement(HOTFIX_SEL_PHASE_X_PHASE_GROUP, "SELECT ID, PhaseID, PhaseGroupID FROM phase_group ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
|
||||
// PlayerCondition.db2
|
||||
PrepareStatement(HOTFIX_SEL_PLAYER_CONDITION, "SELECT ID, Flags, MinLevel, MaxLevel, RaceMask, ClassMask, Gender, NativeGender, SkillID1, "
|
||||
"SkillID2, SkillID3, SkillID4, MinSkill1, MinSkill2, MinSkill3, MinSkill4, MaxSkill1, MaxSkill2, MaxSkill3, MaxSkill4, SkillLogic, "
|
||||
"LanguageID, MinLanguage, MaxLanguage, MinFactionID1, MinFactionID2, MinFactionID3, MaxFactionID, MinReputation1, MinReputation2, "
|
||||
"MinReputation3, MaxReputation, ReputationLogic, Unknown1, MinPVPRank, MaxPVPRank, PvpMedal, PrevQuestLogic, PrevQuestID1, PrevQuestID2, "
|
||||
"PrevQuestID3, PrevQuestID4, CurrQuestLogic, CurrQuestID1, CurrQuestID2, CurrQuestID3, CurrQuestID4, CurrentCompletedQuestLogic, "
|
||||
"CurrentCompletedQuestID1, CurrentCompletedQuestID2, CurrentCompletedQuestID3, CurrentCompletedQuestID4, SpellLogic, SpellID1, SpellID2, "
|
||||
"SpellID3, SpellID4, ItemLogic, ItemID1, ItemID2, ItemID3, ItemID4, ItemCount1, ItemCount2, ItemCount3, ItemCount4, ItemFlags, Explored1, "
|
||||
"Explored2, Time1, Time2, AuraSpellLogic, AuraSpellID1, AuraSpellID2, AuraSpellID3, AuraSpellID4, WorldStateExpressionID, WeatherID, "
|
||||
"PartyStatus, LifetimeMaxPVPRank, AchievementLogic, Achievement1, Achievement2, Achievement3, Achievement4, LfgLogic, LfgStatus1, LfgStatus2, "
|
||||
"LfgStatus3, LfgStatus4, LfgCompare1, LfgCompare2, LfgCompare3, LfgCompare4, LfgValue1, LfgValue2, LfgValue3, LfgValue4, AreaLogic, AreaID1, "
|
||||
"AreaID2, AreaID3, AreaID4, CurrencyLogic, CurrencyID1, CurrencyID2, CurrencyID3, CurrencyID4, CurrencyCount1, CurrencyCount2, "
|
||||
"CurrencyCount3, CurrencyCount4, QuestKillID, QuestKillLogic, QuestKillMonster1, QuestKillMonster2, QuestKillMonster3, QuestKillMonster4, "
|
||||
"MinExpansionLevel, MaxExpansionLevel, MinExpansionTier, MaxExpansionTier, MinGuildLevel, MaxGuildLevel, PhaseUseFlags, PhaseID, "
|
||||
"PhaseGroupID, MinAvgItemLevel, MaxAvgItemLevel, MinAvgEquippedItemLevel, MaxAvgEquippedItemLevel, ChrSpecializationIndex, "
|
||||
"ChrSpecializationRole, FailureDescription, PowerType, PowerTypeComp, PowerTypeValue FROM player_condition ORDER BY ID DESC", CONNECTION_SYNCH);
|
||||
PREPARE_LOCALE_STMT(HOTFIX_SEL_PLAYER_CONDITION, "SELECT ID, FailureDescription_lang FROM player_condition_locale WHERE locale = ?", CONNECTION_SYNCH);
|
||||
|
||||
// QuestMoneyReward.db2
|
||||
PrepareStatement(HOTFIX_SEL_QUEST_MONEY_REWARD, "SELECT Level, Money1, Money2, Money3, Money4, Money5, Money6, Money7, Money8, Money9, Money10"
|
||||
" FROM quest_money_reward ORDER BY Level DESC", CONNECTION_SYNCH);
|
||||
|
||||
@@ -202,6 +202,9 @@ enum HotfixDatabaseStatements
|
||||
|
||||
HOTFIX_SEL_PHASE_X_PHASE_GROUP,
|
||||
|
||||
HOTFIX_SEL_PLAYER_CONDITION,
|
||||
HOTFIX_SEL_PLAYER_CONDITION_LOCALE,
|
||||
|
||||
HOTFIX_SEL_QUEST_MONEY_REWARD,
|
||||
|
||||
HOTFIX_SEL_QUEST_PACKAGE_ITEM,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ConditionMgr.h"
|
||||
#include "AchievementMgr.h"
|
||||
#include "GameEventMgr.h"
|
||||
#include "Group.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
@@ -2300,3 +2301,419 @@ void ConditionMgr::Clean()
|
||||
|
||||
AllocatedMemoryStore.clear();
|
||||
}
|
||||
|
||||
inline bool PlayerConditionCompare(int32 comparisonType, int32 value1, int32 value2)
|
||||
{
|
||||
switch (comparisonType)
|
||||
{
|
||||
case 1:
|
||||
return value1 == value2;
|
||||
case 2:
|
||||
return value1 != value2;
|
||||
case 3:
|
||||
return value1 > value2;
|
||||
case 4:
|
||||
return value1 >= value2;
|
||||
case 5:
|
||||
return value1 < value2;
|
||||
case 6:
|
||||
return value1 <= value2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
inline bool PlayerConditionLogic(uint32 logic, std::array<bool, N>& results)
|
||||
{
|
||||
static_assert(N < 16, "Logic array size must be equal to or less than 16");
|
||||
|
||||
for (std::size_t i = 0; i < results.size(); ++i)
|
||||
if ((logic >> (16 + i)) & 1)
|
||||
results[i] ^= true;
|
||||
|
||||
bool result = results[0];
|
||||
for (std::size_t i = 1; i < results.size(); ++i)
|
||||
{
|
||||
switch ((logic >> (2 * (i - 1))) & 3)
|
||||
{
|
||||
case 1:
|
||||
result = result && results[i];
|
||||
break;
|
||||
case 2:
|
||||
result = result || results[i];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConditionMgr::IsPlayerMeetingCondition(Player* player, PlayerConditionEntry const* condition)
|
||||
{
|
||||
if (condition->MinLevel && player->getLevel() < condition->MinLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MaxLevel && player->getLevel() > condition->MaxLevel)
|
||||
return false;
|
||||
|
||||
if (condition->RaceMask && !(player->getRaceMask() & condition->RaceMask))
|
||||
return false;
|
||||
|
||||
if (condition->ClassMask && !(player->getClassMask() & condition->ClassMask))
|
||||
return false;
|
||||
|
||||
if (condition->Gender >= 0 && player->getGender() != condition->Gender)
|
||||
return false;
|
||||
|
||||
if (condition->NativeGender >= 0 && player->GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER) != condition->NativeGender)
|
||||
return false;
|
||||
|
||||
if (condition->PowerType != -1 && condition->PowerTypeComp)
|
||||
{
|
||||
int32 requiredPowerValue = condition->Flags & 4 ? player->GetMaxPower(Powers(condition->PowerType)) : condition->PowerTypeValue;
|
||||
if (!PlayerConditionCompare(condition->PowerTypeComp, player->GetPower(Powers(condition->PowerType)), requiredPowerValue))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->ChrSpecializationIndex >= 0 || condition->ChrSpecializationRole >= 0)
|
||||
{
|
||||
if (ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(player->GetSpecId(player->GetActiveTalentGroup())))
|
||||
{
|
||||
if (condition->ChrSpecializationIndex >= 0 && spec->OrderIndex != condition->ChrSpecializationIndex)
|
||||
return false;
|
||||
|
||||
if (condition->ChrSpecializationRole >= 0 && spec->Role != condition->ChrSpecializationRole)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->SkillID[0] || condition->SkillID[1] || condition->SkillID[2] || condition->SkillID[3])
|
||||
{
|
||||
using SkillCount = std::extent<decltype(condition->SkillID)>;
|
||||
|
||||
std::array<bool, SkillCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < SkillCount::value; ++i)
|
||||
{
|
||||
if (condition->SkillID[i])
|
||||
{
|
||||
uint16 skillValue = player->GetSkillValue(condition->SkillID[i]);
|
||||
results[i] = skillValue != 0 && skillValue > condition->MinSkill[i] && skillValue < condition->MaxSkill[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerConditionLogic(condition->SkillLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->LanguageID)
|
||||
{
|
||||
if (LanguageDesc const* lang = GetLanguageDescByID(condition->LanguageID))
|
||||
{
|
||||
uint32 languageSkill = player->GetSkillValue(lang->skill_id);
|
||||
if (!languageSkill && player->HasAuraTypeWithMiscvalue(SPELL_AURA_COMPREHEND_LANGUAGE, condition->LanguageID))
|
||||
languageSkill = 300;
|
||||
|
||||
if (condition->MinLanguage && languageSkill < condition->MinLanguage)
|
||||
return false;
|
||||
|
||||
if (condition->MaxLanguage && languageSkill > condition->MaxLanguage)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->MinFactionID[0] && condition->MinFactionID[1] && condition->MinFactionID[2] && condition->MaxFactionID)
|
||||
{
|
||||
if (!condition->MinFactionID[0] && !condition->MinFactionID[1] && !condition->MinFactionID[2])
|
||||
{
|
||||
if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
|
||||
{
|
||||
if (*forcedRank > condition->MaxReputation)
|
||||
return false;
|
||||
}
|
||||
else if (player->GetReputationRank(condition->MaxFactionID) > condition->MaxReputation)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
using FactionCount = std::extent<decltype(condition->MinFactionID)>;
|
||||
|
||||
std::array<bool, FactionCount::value + 1> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < FactionCount::value; ++i)
|
||||
{
|
||||
if (condition->MinFactionID[i])
|
||||
{
|
||||
if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MinFactionID[i]))
|
||||
results[i] = *forcedRank >= condition->MinReputation[i];
|
||||
else
|
||||
results[i] = player->GetReputationRank(condition->MinFactionID[i]) >= condition->MinReputation[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ReputationRank const* forcedRank = player->GetReputationMgr().GetForcedRankIfAny(condition->MaxFactionID))
|
||||
results[3] = *forcedRank <= condition->MaxReputation;
|
||||
else
|
||||
results[3] = player->GetReputationRank(condition->MaxFactionID) <= condition->MaxReputation;
|
||||
|
||||
if (!PlayerConditionLogic(condition->ReputationLogic, results))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->PvpMedal && !((1 << (condition->PvpMedal - 1)) & player->GetUInt32Value(PLAYER_FIELD_PVP_MEDALS)))
|
||||
return false;
|
||||
|
||||
if (condition->LifetimeMaxPVPRank && player->GetByteValue(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTES_OFFSET_LIFETIME_MAX_PVP_RANK) != condition->LifetimeMaxPVPRank)
|
||||
return false;
|
||||
|
||||
if (condition->PartyStatus)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
switch (condition->PartyStatus)
|
||||
{
|
||||
case 1:
|
||||
if (group)
|
||||
return false;
|
||||
break;
|
||||
case 2:
|
||||
if (!group)
|
||||
return false;
|
||||
break;
|
||||
case 3:
|
||||
if (!group || group->isRaidGroup())
|
||||
return false;
|
||||
break;
|
||||
case 4:
|
||||
if (!group || !group->isRaidGroup())
|
||||
return false;
|
||||
break;
|
||||
case 5:
|
||||
if (group && group->isRaidGroup())
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->PrevQuestID[0])
|
||||
{
|
||||
using PrevQuestCount = std::extent<decltype(condition->PrevQuestID)>;
|
||||
|
||||
std::array<bool, PrevQuestCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < PrevQuestCount::value; ++i)
|
||||
if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(condition->PrevQuestID[i]))
|
||||
results[i] = (player->GetUInt32Value(PLAYER_FIELD_QUEST_COMPLETED + (questBit - 1) >> 5) & (1 << ((questBit - 1) & 31))) != 0;
|
||||
|
||||
if (!PlayerConditionLogic(condition->PrevQuestLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->CurrQuestID[0])
|
||||
{
|
||||
using CurrQuestCount = std::extent<decltype(condition->CurrQuestID)>;
|
||||
|
||||
std::array<bool, CurrQuestCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < CurrQuestCount::value; ++i)
|
||||
if (condition->CurrQuestID[i])
|
||||
results[i] = player->FindQuestSlot(condition->CurrQuestID[i]) != MAX_QUEST_LOG_SIZE;
|
||||
|
||||
if (!PlayerConditionLogic(condition->CurrQuestLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->CurrentCompletedQuestID[0])
|
||||
{
|
||||
using CurrentCompletedQuestCount = std::extent<decltype(condition->CurrentCompletedQuestID)>;
|
||||
|
||||
std::array<bool, CurrentCompletedQuestCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < CurrentCompletedQuestCount::value; ++i)
|
||||
if (condition->CurrentCompletedQuestID[i])
|
||||
results[i] = player->GetQuestStatus(condition->CurrentCompletedQuestID[i]) == QUEST_STATUS_COMPLETE;
|
||||
|
||||
if (!PlayerConditionLogic(condition->CurrentCompletedQuestLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (condition->SpellID[0])
|
||||
{
|
||||
using SpellCount = std::extent<decltype(condition->SpellID)>;
|
||||
|
||||
std::array<bool, SpellCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < SpellCount::value; ++i)
|
||||
if (condition->SpellID[i])
|
||||
results[i] = player->HasSpell(condition->SpellID[i]);
|
||||
|
||||
if (!PlayerConditionLogic(condition->SpellLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->ItemID[0])
|
||||
{
|
||||
using ItemCount = std::extent<decltype(condition->ItemID)>;
|
||||
|
||||
std::array<bool, ItemCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < ItemCount::value; ++i)
|
||||
if (condition->ItemID[i])
|
||||
results[i] = player->GetItemCount(condition->ItemID[i], condition->ItemFlags != 0) >= condition->ItemCount[i];
|
||||
|
||||
if (!PlayerConditionLogic(condition->ItemLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->CurrencyID[0])
|
||||
{
|
||||
using CurrencyCount = std::extent<decltype(condition->CurrencyID)>;
|
||||
|
||||
std::array<bool, CurrencyCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < CurrencyCount::value; ++i)
|
||||
if (condition->CurrencyID[i])
|
||||
results[i] = player->GetCurrency(condition->CurrencyID[i]) >= condition->CurrencyCount[i];
|
||||
|
||||
if (!PlayerConditionLogic(condition->CurrencyLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->Explored[0] || condition->Explored[1])
|
||||
{
|
||||
using ExploredCount = std::extent<decltype(condition->Explored)>;
|
||||
|
||||
for (std::size_t i = 0; i < ExploredCount::value; ++i)
|
||||
{
|
||||
if (condition->Explored[i])
|
||||
{
|
||||
int32 exploreFlag = GetAreaFlagByAreaID(condition->Explored[i]);
|
||||
if (exploreFlag != -1 && !(player->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + exploreFlag / 32) & (1 << (uint32(exploreFlag) % 32))))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->AuraSpellID[0])
|
||||
{
|
||||
using AuraCount = std::extent<decltype(condition->AuraSpellID)>;
|
||||
|
||||
std::array<bool, AuraCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < AuraCount::value; ++i)
|
||||
if (condition->AuraSpellID[i])
|
||||
results[i] = player->HasAura(condition->AuraSpellID[i]);
|
||||
|
||||
if (!PlayerConditionLogic(condition->AuraSpellLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: time condition
|
||||
// TODO (or not): world state expression condition
|
||||
// TODO: weather condition
|
||||
|
||||
if (condition->Achievement[0])
|
||||
{
|
||||
using AchievementCount = std::extent<decltype(condition->Achievement)>;
|
||||
|
||||
std::array<bool, AchievementCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < AchievementCount::value; ++i)
|
||||
{
|
||||
if (condition->Achievement[i])
|
||||
{
|
||||
// if (condition->Flags & 2) { any character on account completed it } else { current character only }
|
||||
// TODO: part of accountwide achievements
|
||||
results[i] = player->HasAchieved(condition->Achievement[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerConditionLogic(condition->AchievementLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: research lfg status for player conditions
|
||||
|
||||
if (condition->AreaID[0])
|
||||
{
|
||||
using AreaCount = std::extent<decltype(condition->AreaID)>;
|
||||
|
||||
std::array<bool, AreaCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < AreaCount::value; ++i)
|
||||
if (condition->AreaID[i])
|
||||
results[i] = player->GetAreaId() == condition->AreaID[i] || player->GetZoneId() == condition->AreaID[i];
|
||||
|
||||
if (!PlayerConditionLogic(condition->AreaLogic, results))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->MinExpansionLevel != -1 && player->GetSession()->GetExpansion() < condition->MinExpansionLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MaxExpansionLevel != -1 && player->GetSession()->GetExpansion() > condition->MaxExpansionLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MinExpansionLevel != -1 && condition->MinExpansionTier != -1 && !player->IsGameMaster()
|
||||
&& (condition->MinExpansionLevel == sWorld->getIntConfig(CONFIG_EXPANSION) && condition->MinExpansionTier > 0 /*TODO: implement tier*/
|
||||
|| condition->MinExpansionLevel > sWorld->getIntConfig(CONFIG_EXPANSION)))
|
||||
return false;
|
||||
|
||||
if (condition->PhaseID && !player->IsInPhase(condition->PhaseID))
|
||||
return false;
|
||||
|
||||
if (condition->PhaseGroupID)
|
||||
{
|
||||
std::set<uint32> phases = sDB2Manager.GetPhasesForGroup(condition->PhaseGroupID);
|
||||
if (!Trinity::Containers::Intersects(phases.begin(), phases.end(), player->GetPhases().begin(), player->GetPhases().end()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (condition->QuestKillID)
|
||||
{
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(condition->QuestKillID);
|
||||
if (quest && player->GetQuestStatus(condition->QuestKillID) != QUEST_STATUS_COMPLETE)
|
||||
{
|
||||
using QuestKillCount = std::extent<decltype(condition->QuestKillMonster)>;
|
||||
|
||||
std::array<bool, QuestKillCount::value> results;
|
||||
results.fill(true);
|
||||
for (std::size_t i = 0; i < QuestKillCount::value; ++i)
|
||||
{
|
||||
if (condition->QuestKillMonster[i])
|
||||
{
|
||||
auto objectiveItr = std::find_if(quest->GetObjectives().begin(), quest->GetObjectives().end(), [condition, i](QuestObjective const& objective) -> bool
|
||||
{
|
||||
return objective.Type == QUEST_OBJECTIVE_MONSTER && uint32(objective.ObjectID) == condition->QuestKillMonster[i];
|
||||
});
|
||||
if (objectiveItr != quest->GetObjectives().end())
|
||||
results[i] = player->GetQuestObjectiveData(quest, objectiveItr->StorageIndex) >= objectiveItr->Amount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerConditionLogic(condition->QuestKillLogic, results))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (condition->MinAvgItemLevel && uint32(std::floor(player->GetFloatValue(PLAYER_FIELD_AVG_ITEM_LEVEL))) < condition->MinAvgItemLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MaxAvgItemLevel && uint32(std::floor(player->GetFloatValue(PLAYER_FIELD_AVG_ITEM_LEVEL))) > condition->MaxAvgItemLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MinAvgEquippedItemLevel && uint32(std::floor(player->GetFloatValue(PLAYER_FIELD_AVG_ITEM_LEVEL + 1))) < condition->MinAvgEquippedItemLevel)
|
||||
return false;
|
||||
|
||||
if (condition->MaxAvgEquippedItemLevel && uint32(std::floor(player->GetFloatValue(PLAYER_FIELD_AVG_ITEM_LEVEL + 1))) > condition->MaxAvgEquippedItemLevel)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class Unit;
|
||||
class WorldObject;
|
||||
class LootTemplate;
|
||||
struct Condition;
|
||||
struct PlayerConditionEntry;
|
||||
|
||||
/*! Documentation on implementing a new ConditionType:
|
||||
Step 1: Check for the lowest free ID. Look for CONDITION_UNUSED_XX in the enum.
|
||||
@@ -273,6 +274,8 @@ class ConditionMgr
|
||||
bool IsObjectMeetingSmartEventConditions(int64 entryOrGuid, uint32 eventId, uint32 sourceType, Unit* unit, WorldObject* baseObject) const;
|
||||
bool IsObjectMeetingVendorItemConditions(uint32 creatureId, uint32 itemId, Player* player, Creature* vendor) const;
|
||||
|
||||
static bool IsPlayerMeetingCondition(Player* player, PlayerConditionEntry const* condition);
|
||||
|
||||
struct ConditionTypeInfo
|
||||
{
|
||||
char const* Name;
|
||||
|
||||
@@ -97,6 +97,7 @@ DB2Storage<NamesReservedEntry> sNamesReservedStore("NamesReserv
|
||||
DB2Storage<NamesReservedLocaleEntry> sNamesReservedLocaleStore("NamesReservedLocale.db2", NamesReservedLocaleFormat, HOTFIX_SEL_NAMES_RESERVED_LOCALE);
|
||||
DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore("OverrideSpellData.db2", OverrideSpellDataFormat, HOTFIX_SEL_OVERRIDE_SPELL_DATA);
|
||||
DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPhaseGroup.db2", PhaseXPhaseGroupFormat, HOTFIX_SEL_PHASE_X_PHASE_GROUP);
|
||||
DB2Storage<PlayerConditionEntry> sPlayerConditionStore("PlayerCondition.db2", PlayerConditionFormat, HOTFIX_SEL_PLAYER_CONDITION);
|
||||
DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardFormat, HOTFIX_SEL_QUEST_MONEY_REWARD);
|
||||
DB2Storage<QuestPackageItemEntry> sQuestPackageItemStore("QuestPackageItem.db2", QuestPackageItemfmt, HOTFIX_SEL_QUEST_PACKAGE_ITEM);
|
||||
DB2Storage<QuestSortEntry> sQuestSortStore("QuestSort.db2", QuestSortFormat, HOTFIX_SEL_QUEST_SORT);
|
||||
@@ -271,6 +272,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
|
||||
LOAD_DB2(sNamesReservedLocaleStore);
|
||||
LOAD_DB2(sOverrideSpellDataStore);
|
||||
LOAD_DB2(sPhaseXPhaseGroupStore);
|
||||
LOAD_DB2(sPlayerConditionStore);
|
||||
LOAD_DB2(sQuestMoneyRewardStore);
|
||||
LOAD_DB2(sQuestPackageItemStore);
|
||||
LOAD_DB2(sQuestSortStore);
|
||||
|
||||
@@ -80,6 +80,7 @@ extern DB2Storage<MailTemplateEntry> sMailTemplateStore;
|
||||
extern DB2Storage<ModifierTreeEntry> sModifierTreeStore;
|
||||
extern DB2Storage<MountCapabilityEntry> sMountCapabilityStore;
|
||||
extern DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore;
|
||||
extern DB2Storage<PlayerConditionEntry> sPlayerConditionStore;
|
||||
extern DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore;
|
||||
extern DB2Storage<QuestSortEntry> sQuestSortStore;
|
||||
extern DB2Storage<QuestXPEntry> sQuestXPStore;
|
||||
|
||||
@@ -994,6 +994,87 @@ struct PhaseXPhaseGroupEntry
|
||||
uint32 PhaseGroupID;
|
||||
};
|
||||
|
||||
struct PlayerConditionEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 Flags; // 1
|
||||
uint32 MinLevel; // 2
|
||||
uint32 MaxLevel; // 3
|
||||
uint32 RaceMask; // 4
|
||||
uint32 ClassMask; // 5
|
||||
int32 Gender; // 6
|
||||
int32 NativeGender; // 7
|
||||
uint32 SkillID[4]; // 8-11
|
||||
int32 MinSkill[4]; // 12-15
|
||||
int32 MaxSkill[4]; // 16-19
|
||||
uint32 SkillLogic; // 20
|
||||
uint32 LanguageID; // 21
|
||||
uint32 MinLanguage; // 22
|
||||
uint32 MaxLanguage; // 23
|
||||
uint32 MinFactionID[3]; // 24-26
|
||||
uint32 MaxFactionID; // 27
|
||||
uint32 MinReputation[3]; // 28-30
|
||||
uint32 MaxReputation; // 31
|
||||
uint32 ReputationLogic; // 32
|
||||
uint32 Unknown1; // 33
|
||||
uint32 MinPVPRank; // 34
|
||||
uint32 MaxPVPRank; // 35
|
||||
uint32 PvpMedal; // 36
|
||||
uint32 PrevQuestLogic; // 37
|
||||
uint32 PrevQuestID[4]; // 38-41
|
||||
uint32 CurrQuestLogic; // 42
|
||||
uint32 CurrQuestID[4]; // 43-46
|
||||
uint32 CurrentCompletedQuestLogic; // 47
|
||||
uint32 CurrentCompletedQuestID[4]; // 48-51
|
||||
uint32 SpellLogic; // 52
|
||||
uint32 SpellID[4]; // 53-56
|
||||
uint32 ItemLogic; // 57
|
||||
uint32 ItemID[4]; // 58-61
|
||||
uint32 ItemCount[4]; // 62-65
|
||||
uint32 ItemFlags; // 66
|
||||
uint32 Explored[2]; // 67-68
|
||||
uint32 Time[2]; // 69-70
|
||||
uint32 AuraSpellLogic; // 71
|
||||
uint32 AuraSpellID[4]; // 72-75
|
||||
uint32 WorldStateExpressionID; // 76
|
||||
uint32 WeatherID; // 77
|
||||
uint32 PartyStatus; // 78
|
||||
uint32 LifetimeMaxPVPRank; // 79
|
||||
uint32 AchievementLogic; // 80
|
||||
uint32 Achievement[4]; // 81-84
|
||||
uint32 LfgLogic; // 85
|
||||
uint32 LfgStatus[4]; // 86-89
|
||||
uint32 LfgCompare[4]; // 90-93
|
||||
uint32 LfgValue[4]; // 94-97
|
||||
uint32 AreaLogic; // 98
|
||||
uint32 AreaID[4]; // 99-102
|
||||
uint32 CurrencyLogic; // 103
|
||||
uint32 CurrencyID[4]; // 104-107
|
||||
uint32 CurrencyCount[4]; // 108-111
|
||||
uint32 QuestKillID; // 112
|
||||
uint32 QuestKillLogic; // 113
|
||||
uint32 QuestKillMonster[4]; // 114-117
|
||||
int32 MinExpansionLevel; // 118
|
||||
int32 MaxExpansionLevel; // 119
|
||||
int32 MinExpansionTier; // 120
|
||||
int32 MaxExpansionTier; // 121
|
||||
uint32 MinGuildLevel; // 122
|
||||
uint32 MaxGuildLevel; // 123
|
||||
uint32 PhaseUseFlags; // 124
|
||||
uint32 PhaseID; // 125
|
||||
uint32 PhaseGroupID; // 126
|
||||
uint32 MinAvgItemLevel; // 127
|
||||
uint32 MaxAvgItemLevel; // 128
|
||||
uint32 MinAvgEquippedItemLevel; // 129
|
||||
uint32 MaxAvgEquippedItemLevel; // 130
|
||||
int32 ChrSpecializationIndex; // 131
|
||||
int32 ChrSpecializationRole; // 132
|
||||
LocalizedString* FailureDescription_lang; // 133
|
||||
int32 PowerType; // 134
|
||||
int32 PowerTypeComp; // 135
|
||||
int32 PowerTypeValue; // 136
|
||||
};
|
||||
|
||||
struct QuestMoneyRewardEntry
|
||||
{
|
||||
uint32 Level; // 0
|
||||
|
||||
@@ -91,6 +91,7 @@ char const NamesReservedFormat[] = "nS";
|
||||
char const NamesReservedLocaleFormat[] = "nSi";
|
||||
char const OverrideSpellDataFormat[] = "niiiiiiiiiiii";
|
||||
char const PhaseXPhaseGroupFormat[] = "nii";
|
||||
char const PlayerConditionFormat[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisiii";
|
||||
char const QuestMoneyRewardFormat[] = "niiiiiiiiii";
|
||||
char const QuestPackageItemfmt[] = "niiii";
|
||||
char const QuestSortFormat[] = "ns";
|
||||
|
||||
@@ -111,7 +111,12 @@ class ReputationMgr
|
||||
|
||||
ReputationRank const* GetForcedRankIfAny(FactionTemplateEntry const* factionTemplateEntry) const
|
||||
{
|
||||
ForcedReactions::const_iterator forceItr = _forcedReactions.find(factionTemplateEntry->Faction);
|
||||
return GetForcedRankIfAny(factionTemplateEntry->Faction);
|
||||
}
|
||||
|
||||
ReputationRank const* GetForcedRankIfAny(uint32 factionId) const
|
||||
{
|
||||
ForcedReactions::const_iterator forceItr = _forcedReactions.find(factionId);
|
||||
return forceItr != _forcedReactions.end() ? &forceItr->second : NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user