Core/Gossip: Gossip menu items will now have constant index, allowing to properly define scripts relying on that index when mixed with conditions. Script-created menus via ADD_GOSSIP_ITEM will still have the index generated dynamically

This commit is contained in:
Shauren
2011-05-26 23:57:17 +02:00
parent f91136b949
commit 0ad14aeafd
16 changed files with 587 additions and 653 deletions
+112 -106
View File
@@ -13932,90 +13932,90 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
/*** GOSSIP SYSTEM ***/
/*********************************************************/
void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId, bool showQuests)
void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool showQuests /*= false*/)
{
PlayerMenu* pMenu = PlayerTalkClass;
pMenu->ClearMenus();
PlayerMenu* menu = PlayerTalkClass;
menu->ClearMenus();
pMenu->GetGossipMenu().SetMenuId(menuId);
menu->GetGossipMenu().SetMenuId(menuId);
GossipMenuItemsMapBounds pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId);
GossipMenuItemsMapBounds menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId);
// if default menuId and no menu options exist for this, use options from default options
if (pMenuItemBounds.first == pMenuItemBounds.second && menuId == GetDefaultGossipMenuForSource(pSource))
pMenuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(0);
if (menuItemBounds.first == menuItemBounds.second && menuId == GetDefaultGossipMenuForSource(source))
menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(0);
uint32 npcflags = 0;
Creature *pCreature = NULL;
Creature* creature = NULL;
if (pSource->GetTypeId() == TYPEID_UNIT)
if (source->GetTypeId() == TYPEID_UNIT)
{
pCreature = pSource->ToCreature();
npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
creature = source->ToCreature();
npcflags = creature->GetUInt32Value(UNIT_NPC_FLAGS);
if (npcflags & UNIT_NPC_FLAG_QUESTGIVER && showQuests)
PrepareQuestMenu(pSource->GetGUID());
PrepareQuestMenu(source->GetGUID());
}
for (GossipMenuItemsMap::const_iterator itr = pMenuItemBounds.first; itr != pMenuItemBounds.second; ++itr)
for (GossipMenuItemsMap::const_iterator itr = menuItemBounds.first; itr != menuItemBounds.second; ++itr)
{
bool bCanTalk = true;
if (!sConditionMgr->IsPlayerMeetToConditions(this, itr->second.conditions))
bool canTalk = true;
if (!sConditionMgr->IsPlayerMeetToConditions(this, itr->second.Conditions))
continue;
if (pSource->GetTypeId() == TYPEID_UNIT)
if (source->GetTypeId() == TYPEID_UNIT)
{
if (!(itr->second.npc_option_npcflag & npcflags))
if (!(itr->second.OptionNpcflag & npcflags))
continue;
switch(itr->second.option_id)
switch (itr->second.OptionType)
{
case GOSSIP_OPTION_ARMORER:
bCanTalk = false; // added in special mode
canTalk = false; // added in special mode
break;
case GOSSIP_OPTION_SPIRITHEALER:
if (!isDead())
bCanTalk = false;
canTalk = false;
break;
case GOSSIP_OPTION_VENDOR:
{
VendorItemData const* vItems = pCreature->GetVendorItems();
if (!vItems || vItems->Empty())
VendorItemData const* vendorItems = creature->GetVendorItems();
if (!vendorItems || vendorItems->Empty())
{
sLog->outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", pCreature->GetGUIDLow(), pCreature->GetEntry());
bCanTalk = false;
sLog->outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
canTalk = false;
}
break;
}
case GOSSIP_OPTION_TRAINER:
if (!pCreature->isCanTrainingOf(this, false))
bCanTalk = false;
if (!creature->isCanTrainingOf(this, false))
canTalk = false;
break;
case GOSSIP_OPTION_LEARNDUALSPEC:
if (!(GetSpecsCount() == 1 && pCreature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
bCanTalk = false;
if (!(GetSpecsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
canTalk = false;
break;
case GOSSIP_OPTION_UNLEARNTALENTS:
if (!pCreature->isCanTrainingAndResetTalentsOf(this))
bCanTalk = false;
if (!creature->isCanTrainingAndResetTalentsOf(this))
canTalk = false;
break;
case GOSSIP_OPTION_UNLEARNPETTALENTS:
if (!GetPet() || GetPet()->getPetType() != HUNTER_PET || GetPet()->m_spells.size() <= 1 || pCreature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || pCreature->GetCreatureInfo()->trainer_class != CLASS_HUNTER)
bCanTalk = false;
if (!GetPet() || GetPet()->getPetType() != HUNTER_PET || GetPet()->m_spells.size() <= 1 || creature->GetCreatureInfo()->trainer_type != TRAINER_TYPE_PETS || creature->GetCreatureInfo()->trainer_class != CLASS_HUNTER)
canTalk = false;
break;
case GOSSIP_OPTION_TAXIVENDOR:
if (GetSession()->SendLearnNewTaxiNode(pCreature))
if (GetSession()->SendLearnNewTaxiNode(creature))
return;
break;
case GOSSIP_OPTION_BATTLEFIELD:
if (!pCreature->isCanInteractWithBattleMaster(this, false))
bCanTalk = false;
if (!creature->isCanInteractWithBattleMaster(this, false))
canTalk = false;
break;
case GOSSIP_OPTION_STABLEPET:
if (getClass() != CLASS_HUNTER)
bCanTalk = false;
canTalk = false;
break;
case GOSSIP_OPTION_QUESTGIVER:
bCanTalk = false;
canTalk = false;
break;
case GOSSIP_OPTION_GOSSIP:
case GOSSIP_OPTION_SPIRITGUIDE:
@@ -14026,78 +14026,78 @@ void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId, bool showQue
case GOSSIP_OPTION_AUCTIONEER:
break; // no checks
case GOSSIP_OPTION_OUTDOORPVP:
if (!sOutdoorPvPMgr->CanTalkTo(this, pCreature, itr->second))
bCanTalk = false;
if (!sOutdoorPvPMgr->CanTalkTo(this, creature, itr->second))
canTalk = false;
break;
default:
sLog->outErrorDb("Creature entry %u have unknown gossip option %u for menu %u", pCreature->GetEntry(), itr->second.option_id, itr->second.menu_id);
bCanTalk = false;
sLog->outErrorDb("Creature entry %u have unknown gossip option %u for menu %u", creature->GetEntry(), itr->second.OptionType, itr->second.MenuId);
canTalk = false;
break;
}
}
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
{
GameObject *pGo = (GameObject*)pSource;
GameObject *go = source->ToGameObject();
switch(itr->second.option_id)
switch (itr->second.OptionType)
{
case GOSSIP_OPTION_QUESTGIVER:
if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
PrepareQuestMenu(pSource->GetGUID());
bCanTalk = false;
if (go->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
PrepareQuestMenu(source->GetGUID());
canTalk = false;
break;
case GOSSIP_OPTION_GOSSIP:
if (pGo->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && pGo->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
bCanTalk = false;
if (go->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && go->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
canTalk = false;
break;
default:
bCanTalk = false;
canTalk = false;
break;
}
}
if (bCanTalk)
if (canTalk)
{
std::string strOptionText = itr->second.option_text;
std::string strBoxText = itr->second.box_text;
std::string strOptionText = itr->second.OptionText;
std::string strBoxText = itr->second.BoxText;
int loc_idx = GetSession()->GetSessionDbLocaleIndex();
if (loc_idx >= 0)
int32 locale = GetSession()->GetSessionDbLocaleIndex();
if (locale >= 0)
{
uint32 idxEntry = MAKE_PAIR32(menuId, itr->second.id);
uint32 idxEntry = MAKE_PAIR32(menuId, itr->second.OptionIndex);
if (GossipMenuItemsLocale const *no = sObjectMgr->GetGossipMenuItemsLocale(idxEntry))
{
sObjectMgr->GetLocaleString(no->OptionText, loc_idx, strOptionText);
sObjectMgr->GetLocaleString(no->BoxText, loc_idx, strBoxText);
sObjectMgr->GetLocaleString(no->OptionText, locale, strOptionText);
sObjectMgr->GetLocaleString(no->BoxText, locale, strBoxText);
}
}
pMenu->GetGossipMenu().AddMenuItem(itr->second.option_icon, strOptionText, 0, itr->second.option_id, strBoxText, itr->second.box_money, itr->second.box_coded);
pMenu->GetGossipMenu().AddGossipMenuItemData(itr->second.action_menu_id, itr->second.action_poi_id, itr->second.action_script_id);
menu->GetGossipMenu().AddMenuItem(itr->second.OptionIndex, itr->second.OptionIcon, strOptionText, 0, itr->second.OptionType, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded);
menu->GetGossipMenu().AddGossipMenuItemData(itr->second.OptionIndex, itr->second.ActionMenuId, itr->second.ActionPoiId, itr->second.ActionScriptId);
}
}
}
void Player::SendPreparedGossip(WorldObject *pSource)
void Player::SendPreparedGossip(WorldObject* source)
{
if (!pSource)
if (!source)
return;
if (pSource->GetTypeId() == TYPEID_UNIT)
if (source->GetTypeId() == TYPEID_UNIT)
{
// in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
if (!pSource->ToCreature()->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
if (!source->ToCreature()->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
{
SendPreparedQuest(pSource->GetGUID());
SendPreparedQuest(source->GetGUID());
return;
}
}
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
{
// probably need to find a better way here
if (!PlayerTalkClass->GetGossipMenu().GetMenuId() && !PlayerTalkClass->GetQuestMenu().Empty())
{
SendPreparedQuest(pSource->GetGUID());
SendPreparedQuest(source->GetGUID());
return;
}
}
@@ -14105,67 +14105,73 @@ void Player::SendPreparedGossip(WorldObject *pSource)
// in case non empty gossip menu (that not included quests list size) show it
// (quest entries from quest menu will be included in list)
uint32 textId = GetGossipTextId(pSource);
uint32 textId = GetGossipTextId(source);
if (uint32 menuId = PlayerTalkClass->GetGossipMenu().GetMenuId())
textId = GetGossipTextId(menuId);
PlayerTalkClass->SendGossipMenu(textId, pSource->GetGUID());
PlayerTalkClass->SendGossipMenu(textId, source->GetGUID());
}
void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 menuId)
void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 menuId)
{
GossipMenu& gossipmenu = PlayerTalkClass->GetGossipMenu();
if (gossipListId >= gossipmenu.MenuItemCount())
if (gossipListId >= gossipmenu.GetMenuItemCount())
return;
// if not same, then something funky is going on
if (menuId != gossipmenu.GetMenuId())
return;
uint32 gossipOptionId = gossipmenu.GetItem(gossipListId).m_gOptionId;
uint64 guid = pSource->GetGUID();
GossipMenuItem const* item = gossipmenu.GetItem(gossipListId);
if (!item)
return;
if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
uint32 gossipOptionId = item->OptionType;
uint64 guid = source->GetGUID();
if (source->GetTypeId() == TYPEID_GAMEOBJECT)
{
if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER)
{
sLog->outError("Player guid %u request invalid gossip option for GameObject entry %u", GetGUIDLow(), pSource->GetEntry());
sLog->outError("Player guid %u request invalid gossip option for GameObject entry %u", GetGUIDLow(), source->GetEntry());
return;
}
}
GossipMenuItemData pMenuData = gossipmenu.GetItemData(gossipListId);
GossipMenuItemData const* menuItemData = gossipmenu.GetItemData(gossipListId);
if (menuItemData)
return;
switch(gossipOptionId)
switch (gossipOptionId)
{
case GOSSIP_OPTION_GOSSIP:
{
if (pMenuData.m_gAction_menu)
if (menuItemData->GossipActionMenuId)
{
PrepareGossipMenu(pSource, pMenuData.m_gAction_menu);
SendPreparedGossip(pSource);
PrepareGossipMenu(source, menuItemData->GossipActionMenuId);
SendPreparedGossip(source);
}
if (pMenuData.m_gAction_poi)
PlayerTalkClass->SendPointOfInterest(pMenuData.m_gAction_poi);
if (menuItemData->GossipActionPoi)
PlayerTalkClass->SendPointOfInterest(menuItemData->GossipActionPoi);
if (pMenuData.m_gAction_script)
if (menuItemData->GossipActionScript)
{
if (pSource->GetTypeId() == TYPEID_UNIT)
GetMap()->ScriptsStart(sGossipScripts, pMenuData.m_gAction_script, this, pSource);
else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
GetMap()->ScriptsStart(sGossipScripts, pMenuData.m_gAction_script, pSource, this);
if (source->GetTypeId() == TYPEID_UNIT)
GetMap()->ScriptsStart(sGossipScripts, menuItemData->GossipActionScript, this, source);
else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
GetMap()->ScriptsStart(sGossipScripts, menuItemData->GossipActionScript, source, this);
}
break;
}
case GOSSIP_OPTION_OUTDOORPVP:
sOutdoorPvPMgr->HandleGossipOption(this, pSource->GetGUID(), gossipListId);
sOutdoorPvPMgr->HandleGossipOption(this, source->GetGUID(), gossipListId);
break;
case GOSSIP_OPTION_SPIRITHEALER:
if (isDead())
pSource->ToCreature()->CastSpell((pSource->ToCreature()), 17251, true, NULL, NULL, GetGUID());
source->ToCreature()->CastSpell((source->ToCreature()), 17251, true, NULL, NULL, GetGUID());
break;
case GOSSIP_OPTION_QUESTGIVER:
PrepareQuestMenu(guid);
@@ -14187,7 +14193,7 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 me
if (!HasEnoughMoney(10000000))
{
SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
break;
}
else
@@ -14200,46 +14206,46 @@ void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 me
CastSpell(this, 63624, true, NULL, NULL, GetGUID());
// Should show another Gossip text with "Congratulations..."
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
}
}
break;
case GOSSIP_OPTION_UNLEARNTALENTS:
PlayerTalkClass->CloseGossip();
pSource->ToCreature()->CastSpell(this, 46331, true); // Trainer: Untrain Talents
PlayerTalkClass->SendCloseGossip();
source->ToCreature()->CastSpell(this, 46331, true); // Trainer: Untrain Talents
break;
case GOSSIP_OPTION_UNLEARNPETTALENTS:
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
ResetPetTalents();
break;
case GOSSIP_OPTION_TAXIVENDOR:
GetSession()->SendTaxiMenu((pSource->ToCreature()));
GetSession()->SendTaxiMenu((source->ToCreature()));
break;
case GOSSIP_OPTION_INNKEEPER:
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
SetBindPoint(guid);
break;
case GOSSIP_OPTION_BANKER:
GetSession()->SendShowBank(guid);
break;
case GOSSIP_OPTION_PETITIONER:
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
GetSession()->SendPetitionShowList(guid);
break;
case GOSSIP_OPTION_TABARDDESIGNER:
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
GetSession()->SendTabardVendorActivate(guid);
break;
case GOSSIP_OPTION_AUCTIONEER:
GetSession()->SendAuctionHello(guid, (pSource->ToCreature()));
GetSession()->SendAuctionHello(guid, (source->ToCreature()));
break;
case GOSSIP_OPTION_SPIRITGUIDE:
PrepareGossipMenu(pSource);
SendPreparedGossip(pSource);
PrepareGossipMenu(source);
SendPreparedGossip(source);
break;
case GOSSIP_OPTION_BATTLEFIELD:
{
BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(pSource->GetEntry());
BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(source->GetEntry());
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
@@ -14364,13 +14370,13 @@ void Player::SendPreparedQuest(uint64 guid)
QuestMenuItem const& qmi0 = questMenu.GetItem(0);
uint32 icon = qmi0.m_qIcon;
uint32 icon = qmi0.QuestIcon;
// single element case
if (questMenu.MenuItemCount() == 1)
if (questMenu.GetMenuItemCount() == 1)
{
// Auto open -- maybe also should verify there is no greeting
uint32 quest_id = qmi0.m_qId;
uint32 quest_id = qmi0.QuestId;
Quest const* pQuest = sObjectMgr->GetQuestTemplate(quest_id);
if (pQuest)
@@ -14386,7 +14392,7 @@ void Player::SendPreparedQuest(uint64 guid)
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT|TYPEMASK_ITEM);
if (!pObject || (!pObject->hasQuest(quest_id) && !pObject->hasInvolvedQuest(quest_id)))
{
PlayerTalkClass->CloseGossip();
PlayerTalkClass->SendCloseGossip();
return;
}
+3 -3
View File
@@ -1333,9 +1333,9 @@ class Player : public Unit, public GridObject<Player>
/*** GOSSIP SYSTEM ***/
/*********************************************************/
void PrepareGossipMenu(WorldObject *pSource, uint32 menuId = 0, bool showQuests = false);
void SendPreparedGossip(WorldObject *pSource);
void OnGossipSelect(WorldObject *pSource, uint32 gossipListId, uint32 menuId);
void PrepareGossipMenu(WorldObject* source, uint32 menuId = 0, bool showQuests = false);
void SendPreparedGossip(WorldObject* source);
void OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 menuId);
uint32 GetGossipTextId(uint32 menuId);
uint32 GetGossipTextId(WorldObject *pSource);