aboutsummaryrefslogtreecommitdiff
path: root/src/game/Player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Player.cpp')
-rw-r--r--src/game/Player.cpp388
1 files changed, 387 insertions, 1 deletions
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index a9b0b95307c..329e605ec0e 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -12730,6 +12730,392 @@ void Player::SendNewItem(Item *item, uint32 count, bool received, bool created,
}
/*********************************************************/
+/*** GOSSIP SYSTEM ***/
+/*********************************************************/
+
+void Player::PrepareGossipMenu(WorldObject *pSource, uint32 menuId)
+{
+ PlayerMenu* pMenu = PlayerTalkClass;
+ pMenu->ClearMenus();
+
+ pMenu->GetGossipMenu().SetMenuId(menuId);
+
+ GossipMenuItemsMapBounds pMenuItemBounds = objmgr.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 = objmgr.GetGossipMenuItemsMapBounds(0);
+
+ 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))
+ continue;
+
+ if (pSource->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature *pCreature = (Creature*)pSource;
+
+ uint32 npcflags = pCreature->GetUInt32Value(UNIT_NPC_FLAGS);
+
+ if (!(itr->second.npc_option_npcflag & npcflags))
+ continue;
+
+ switch(itr->second.option_id)
+ {
+ case GOSSIP_OPTION_QUESTGIVER:
+ PrepareQuestMenu(pSource->GetGUID());
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_ARMORER:
+ bCanTalk = false; // added in special mode
+ break;
+ case GOSSIP_OPTION_SPIRITHEALER:
+ if (!isDead())
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_VENDOR:
+ {
+ VendorItemData const* vItems = pCreature->GetVendorItems();
+ if (!vItems || vItems->Empty())
+ {
+ sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", pCreature->GetGUIDLow(), pCreature->GetEntry());
+ bCanTalk = false;
+ }
+ break;
+ }
+ case GOSSIP_OPTION_TRAINER:
+ if (!pCreature->isCanTrainingOf(this, false))
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_LEARNDUALSPEC:
+ if(!(GetSpecsCount() == 1 && pCreature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld.getConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_UNLEARNTALENTS:
+ if (!pCreature->isCanTrainingAndResetTalentsOf(this))
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_UNLEARNPETSKILLS:
+ 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;
+ break;
+ case GOSSIP_OPTION_TAXIVENDOR:
+ if (GetSession()->SendLearnNewTaxiNode(pCreature))
+ return;
+ break;
+ case GOSSIP_OPTION_BATTLEFIELD:
+ if (!pCreature->isCanInteractWithBattleMaster(this, false))
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_STABLEPET:
+ if (getClass() != CLASS_HUNTER)
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_GOSSIP:
+ case GOSSIP_OPTION_SPIRITGUIDE:
+ case GOSSIP_OPTION_INNKEEPER:
+ case GOSSIP_OPTION_BANKER:
+ case GOSSIP_OPTION_PETITIONER:
+ case GOSSIP_OPTION_TABARDDESIGNER:
+ case GOSSIP_OPTION_AUCTIONEER:
+ break; // no checks
+ case GOSSIP_OPTION_OUTDOORPVP:
+ if (!sOutdoorPvPMgr.CanTalkTo(this, pCreature, itr->second))
+ bCanTalk = 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;
+ break;
+ }
+ }
+ else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
+ {
+ GameObject *pGo = (GameObject*)pSource;
+
+ switch(itr->second.option_id)
+ {
+ case GOSSIP_OPTION_QUESTGIVER:
+ if (pGo->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
+ PrepareQuestMenu(pSource->GetGUID());
+ bCanTalk = false;
+ break;
+ case GOSSIP_OPTION_GOSSIP:
+ if (pGo->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && pGo->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
+ bCanTalk = false;
+ break;
+ default:
+ bCanTalk = false;
+ break;
+ }
+ }
+
+ if (bCanTalk)
+ {
+ std::string strOptionText = itr->second.option_text;
+ std::string strBoxText = itr->second.box_text;
+
+ int loc_idx = GetSession()->GetSessionDbLocaleIndex();
+
+ if (loc_idx >= 0)
+ {
+ uint32 idxEntry = MAKE_PAIR32(menuId, itr->second.id);
+
+ if (GossipMenuItemsLocale const *no = objmgr.GetGossipMenuItemsLocale(idxEntry))
+ {
+ if (no->OptionText.size() > (size_t)loc_idx && !no->OptionText[loc_idx].empty())
+ strOptionText = no->OptionText[loc_idx];
+
+ if (no->BoxText.size() > (size_t)loc_idx && !no->BoxText[loc_idx].empty())
+ strBoxText = no->BoxText[loc_idx];
+ }
+ }
+
+ 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);
+ }
+ }
+
+ // some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-)
+ /*if (pMenu->Empty())
+ {
+ if (pCreature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER))
+ {
+ // output error message if need
+ pCreature->isCanTrainingOf(this, true);
+ }
+
+ if (pCreature->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_BATTLEMASTER))
+ {
+ // output error message if need
+ pCreature->isCanInteractWithBattleMaster(this, true);
+ }
+ }*/
+}
+
+void Player::SendPreparedGossip(WorldObject *pSource)
+{
+ if (!pSource)
+ return;
+
+ if (pSource->GetTypeId() == TYPEID_UNIT)
+ {
+ // in case no gossip flag and quest menu not empty, open quest menu (client expect gossip menu with this flag)
+ if (!((Creature*)pSource)->HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_GOSSIP) && !PlayerTalkClass->GetQuestMenu().Empty())
+ {
+ SendPreparedQuest(pSource->GetGUID());
+ return;
+ }
+ }
+ else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
+ {
+ // probably need to find a better way here
+ if (!PlayerTalkClass->GetGossipMenu().GetMenuId() && !PlayerTalkClass->GetQuestMenu().Empty())
+ {
+ SendPreparedQuest(pSource->GetGUID());
+ return;
+ }
+ }
+
+ // 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);
+
+ if (uint32 menuId = PlayerTalkClass->GetGossipMenu().GetMenuId())
+ textId = GetGossipTextId(menuId);
+
+ PlayerTalkClass->SendGossipMenu(textId, pSource->GetGUID());
+}
+
+void Player::OnGossipSelect(WorldObject* pSource, uint32 gossipListId, uint32 menuId)
+{
+ GossipMenu& gossipmenu = PlayerTalkClass->GetGossipMenu();
+
+ if (gossipListId >= gossipmenu.MenuItemCount())
+ 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();
+
+ if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
+ {
+ if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER)
+ {
+ sLog.outError("Player guid %u request invalid gossip option for GameObject entry %u", GetGUIDLow(), pSource->GetEntry());
+ return;
+ }
+ }
+
+ GossipMenuItemData pMenuData = gossipmenu.GetItemData(gossipListId);
+
+ switch(gossipOptionId)
+ {
+ case GOSSIP_OPTION_GOSSIP:
+ {
+ if (pMenuData.m_gAction_menu)
+ {
+ PrepareGossipMenu(pSource, pMenuData.m_gAction_menu);
+ SendPreparedGossip(pSource);
+ }
+
+ if (pMenuData.m_gAction_poi)
+ PlayerTalkClass->SendPointOfInterest(pMenuData.m_gAction_poi);
+
+ if (pMenuData.m_gAction_script)
+ {
+ 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);
+ }
+ break;
+ }
+ case GOSSIP_OPTION_OUTDOORPVP:
+ sOutdoorPvPMgr.HandleGossipOption(this, pSource->GetGUID(), gossipListId);
+ break;
+ case GOSSIP_OPTION_SPIRITHEALER:
+ if (isDead())
+ ((Creature*)pSource)->CastSpell(((Creature*)pSource),17251,true,NULL,NULL,GetGUID());
+ break;
+ case GOSSIP_OPTION_QUESTGIVER:
+ PrepareQuestMenu(guid);
+ SendPreparedQuest(guid);
+ break;
+ case GOSSIP_OPTION_VENDOR:
+ case GOSSIP_OPTION_ARMORER:
+ GetSession()->SendListInventory(guid);
+ break;
+ case GOSSIP_OPTION_STABLEPET:
+ GetSession()->SendStablePet(guid);
+ break;
+ case GOSSIP_OPTION_TRAINER:
+ GetSession()->SendTrainerList(guid);
+ break;
+ case GOSSIP_OPTION_LEARNDUALSPEC:
+ if(GetSpecsCount() == 1 && !(getLevel() < sWorld.getConfig(CONFIG_MIN_DUALSPEC_LEVEL)))
+ {
+ if (GetMoney() < 10000000)
+ {
+ SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
+ PlayerTalkClass->CloseGossip();
+ break;
+ }
+ else
+ {
+ ModifyMoney(-10000000);
+
+ // Cast spells that teach dual spec
+ // Both are also ImplicitTarget self and must be cast by player
+ this->CastSpell(this, 63680, true, NULL, NULL, this->GetGUID());
+ this->CastSpell(this, 63624, true, NULL, NULL, this->GetGUID());
+
+ // Should show another Gossip text with "Congratulations..."
+ PlayerTalkClass->CloseGossip();
+ }
+ }
+ break;
+ case GOSSIP_OPTION_UNLEARNTALENTS:
+ PlayerTalkClass->CloseGossip();
+ SendTalentWipeConfirm(guid);
+ break;
+ case GOSSIP_OPTION_UNLEARNPETSKILLS:
+ PlayerTalkClass->CloseGossip();
+ SendPetSkillWipeConfirm();
+ break;
+ case GOSSIP_OPTION_TAXIVENDOR:
+ GetSession()->SendTaxiMenu(((Creature*)pSource));
+ break;
+ case GOSSIP_OPTION_INNKEEPER:
+ PlayerTalkClass->CloseGossip();
+ SetBindPoint(guid);
+ break;
+ case GOSSIP_OPTION_BANKER:
+ GetSession()->SendShowBank(guid);
+ break;
+ case GOSSIP_OPTION_PETITIONER:
+ PlayerTalkClass->CloseGossip();
+ GetSession()->SendPetitionShowList(guid);
+ break;
+ case GOSSIP_OPTION_TABARDDESIGNER:
+ PlayerTalkClass->CloseGossip();
+ GetSession()->SendTabardVendorActivate(guid);
+ break;
+ case GOSSIP_OPTION_AUCTIONEER:
+ GetSession()->SendAuctionHello(guid, ((Creature*)pSource));
+ break;
+ case GOSSIP_OPTION_SPIRITGUIDE:
+ PrepareGossipMenu(pSource);
+ SendPreparedGossip(pSource);
+ break;
+ case GOSSIP_OPTION_BATTLEFIELD:
+ {
+ BattleGroundTypeId bgTypeId = sBattleGroundMgr.GetBattleMasterBG(pSource->GetEntry());
+
+ if (bgTypeId == BATTLEGROUND_TYPE_NONE)
+ {
+ sLog.outError("a user (guid %u) requested battlegroundlist from a npc who is no battlemaster", GetGUIDLow());
+ return;
+ }
+
+ GetSession()->SendBattlegGroundList(guid, bgTypeId);
+ break;
+ }
+ }
+}
+
+uint32 Player::GetGossipTextId(WorldObject *pSource)
+{
+ if (!pSource || pSource->GetTypeId() != TYPEID_UNIT || !((Creature*)pSource)->GetDBTableGUIDLow())
+ return DEFAULT_GOSSIP_MESSAGE;
+
+ if (uint32 pos = objmgr.GetNpcGossip(((Creature*)pSource)->GetDBTableGUIDLow()))
+ return pos;
+
+ return DEFAULT_GOSSIP_MESSAGE;
+}
+
+uint32 Player::GetGossipTextId(uint32 menuId)
+{
+ uint32 textId = DEFAULT_GOSSIP_MESSAGE;
+
+ if (!menuId)
+ return textId;
+
+ GossipMenusMapBounds pMenuBounds = objmgr.GetGossipMenusMapBounds(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))
+ textId = itr->second.text_id;
+ }
+
+ return textId;
+}
+
+uint32 Player::GetDefaultGossipMenuForSource(WorldObject *pSource)
+{
+ if (pSource->GetTypeId() == TYPEID_UNIT)
+ return ((Creature*)pSource)->GetCreatureInfo()->GossipMenuId;
+ else if (pSource->GetTypeId() == TYPEID_GAMEOBJECT)
+ return((GameObject*)pSource)->GetGOInfo()->GetGossipMenuId();
+
+ return 0;
+}
+
+/*********************************************************/
/*** QUEST SYSTEM ***/
/*********************************************************/
@@ -12837,7 +13223,7 @@ void Player::SendPreparedQuest(uint64 guid)
Creature *pCreature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this,guid);
if (pCreature)
{
- uint32 textid = pCreature->GetNpcTextId();
+ uint32 textid = GetGossipTextId(pCreature);
GossipText const* gossiptext = objmgr.GetGossipText(textid);
if (!gossiptext)
{