[11964] Implement new conditions system

Tree-like design idea by Faramir118, thanks for that!

* Add `conditions` table to store conditions.
* REPLACE current handling of conditions for the *_loot_template tables
  Convert the old conditions in *_loot_template to the new system by SQL-Queries
* ADD support for new conditions to gossip_menu and gossip_menu_option.
  If for these tables no condition_id (new system) is provided, the old conditions will still be used
* Add a small helper python script to contrib/convertConditions, see README there for details
* Add new command to reload the `conditions` table (.reload conditions)
* Add two Meta-Condition types CONDITION_AND (-1) and CONDITION_OR (-2) which are used as:
  value1 (as condition_entry) AND / OR value2 (as condition_entry)

  With these meta-conditions it is possible to create tree like and very complicated combined conditions (like HasAura && (HasItem || HasQuest))

NOTE about conversion:
For easier convertion all the old table data is still preserved, but will be removed eventually (within a circle of the moon approximately)
The python script will not create an optimal initial fill of the `conditions` table. You might want to tweak it manually or suggest some optimized algorithm :)

Signed-off-by: Schmoozerd <schmoozerd@scriptdev2.com>
This commit is contained in:
Schmoozerd 2012-04-15 22:40:13 +02:00
parent f3b5e1e4bc
commit 8c29893310
18 changed files with 729 additions and 132 deletions

View file

@ -97,8 +97,8 @@ void LootStore::LoadLootTable()
sLog.outString( "%s :", GetName());
// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, lootcondition, condition_value1, condition_value2 FROM %s",GetName());
// 0 1 2 3 4 5 6
QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, ChanceOrQuestChance, groupid, mincountOrRef, maxcount, condition_id FROM %s",GetName());
if (result)
{
@ -115,9 +115,7 @@ void LootStore::LoadLootTable()
uint8 group = fields[3].GetUInt8();
int32 mincountOrRef = fields[4].GetInt32();
uint32 maxcount = fields[5].GetUInt32();
ConditionType condition = (ConditionType)fields[6].GetUInt8();
uint32 cond_value1 = fields[7].GetUInt32();
uint32 cond_value2 = fields[8].GetUInt32();
uint16 conditionId = fields[6].GetUInt16();
if (maxcount > std::numeric_limits<uint8>::max())
{
@ -125,21 +123,22 @@ void LootStore::LoadLootTable()
continue; // error already printed to log/console.
}
if (mincountOrRef < 0 && condition != CONDITION_NONE)
if (mincountOrRef < 0 && conditionId)
{
sLog.outErrorDb("Table '%s' entry %u mincountOrRef %i < 0 and not allowed has condition, skipped", GetName(), entry, mincountOrRef);
continue;
}
if (!PlayerCondition::IsValid(condition,cond_value1, cond_value2))
if (conditionId)
{
sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item);
continue; // error already printed to log/console.
const PlayerCondition* condition = sConditionStorage.LookupEntry<PlayerCondition>(conditionId);
if (!condition)
{
sLog.outErrorDb("Table `%s` for entry %u, item %u has condition_id %u that does not exist in `conditions`, ignoring", GetName(), entry,item, conditionId);
conditionId = 0;
}
}
// (condition + cond_value1/2) are converted into single conditionId
uint16 conditionId = sObjectMgr.GetConditionId(condition, cond_value1, cond_value2);
LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, group, conditionId, mincountOrRef, maxcount);
if (!storeitem.IsValid(*this,entry)) // Validity checks
@ -363,7 +362,7 @@ LootItem::LootItem(uint32 itemid_, uint32 count_, uint32 randomSuffix_, int32 ra
bool LootItem::AllowedForPlayer(Player const * player) const
{
// DB conditions check
if (!sObjectMgr.IsPlayerMeetToCondition(player,conditionId))
if (conditionId && !sObjectMgr.IsPlayerMeetToNEWCondition(player, conditionId))
return false;
ItemPrototype const *pProto = ObjectMgr::GetItemPrototype(itemid);
@ -396,7 +395,7 @@ bool LootItem::AllowedForPlayer(Player const * player) const
LootSlotType LootItem::GetSlotTypeForSharedLoot(PermissionTypes permission, Player* viewer, bool condition_ok /*= false*/) const
{
// ignore looted, FFA (each player get own copy) and not allowed items
if (is_looted || freeforall || conditionId && !condition_ok || !AllowedForPlayer(viewer))
if (is_looted || freeforall || (conditionId && !condition_ok) || !AllowedForPlayer(viewer))
return MAX_LOOT_SLOT_TYPE;
switch (permission)
@ -697,7 +696,7 @@ LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, QuestItem **qite
}
}
}
else if(item->conditionId)
else if (item->conditionId)
{
QuestItemMap::const_iterator itr = m_playerNonQuestNonFFAConditionalItems.find(player->GetGUIDLow());
if (itr != m_playerNonQuestNonFFAConditionalItems.end())